summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407 (patch)
treedf5a6539447324de36e95b057d6b9f0361b7a250
downloadframeworks_native-7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407.zip
frameworks_native-7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407.tar.gz
frameworks_native-7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407.tar.bz2
Initial Contribution
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--NOTICE222
-rw-r--r--awt/Android.mk31
-rw-r--r--awt/com/android/internal/awt/AndroidGraphics2D.java1354
-rw-r--r--awt/com/android/internal/awt/AndroidGraphicsConfiguration.java96
-rw-r--r--awt/com/android/internal/awt/AndroidGraphicsFactory.java87
-rw-r--r--awt/com/android/internal/awt/AndroidImageDecoder.java274
-rw-r--r--awt/com/android/internal/awt/AndroidJavaBlitter.java536
-rw-r--r--awt/com/android/internal/awt/AndroidNativeEventQueue.java75
-rw-r--r--awt/com/android/internal/awt/AndroidWTK.java88
-rw-r--r--awt/com/android/internal/awt/AwtFactory.java52
-rw-r--r--awt/com/android/internal/awt/ImageOutputStreamWrapper.java66
-rw-r--r--awt/java/awt/AWTEvent.java618
-rw-r--r--awt/java/awt/AWTException.java43
-rw-r--r--awt/java/awt/AWTKeyStroke.java678
-rw-r--r--awt/java/awt/AWTListenerList.java47
-rw-r--r--awt/java/awt/AWTPermission.java54
-rw-r--r--awt/java/awt/ActiveEvent.java36
-rw-r--r--awt/java/awt/Adjustable.java156
-rw-r--r--awt/java/awt/AlphaComposite.java315
-rw-r--r--awt/java/awt/BasicStroke.java2204
-rw-r--r--awt/java/awt/BufferCapabilities.java185
-rw-r--r--awt/java/awt/Color.java881
-rw-r--r--awt/java/awt/Component.java6408
-rw-r--r--awt/java/awt/ComponentBehavior.java56
-rw-r--r--awt/java/awt/ComponentOrientation.java140
-rw-r--r--awt/java/awt/Composite.java47
-rw-r--r--awt/java/awt/CompositeContext.java49
-rw-r--r--awt/java/awt/Cursor.java372
-rw-r--r--awt/java/awt/Dimension.java185
-rw-r--r--awt/java/awt/Dispatcher.java723
-rw-r--r--awt/java/awt/DisplayMode.java147
-rw-r--r--awt/java/awt/Event.java479
-rw-r--r--awt/java/awt/EventDispatchThread.java118
-rw-r--r--awt/java/awt/EventQueue.java310
-rw-r--r--awt/java/awt/EventQueueCore.java253
-rw-r--r--awt/java/awt/Font.java1500
-rw-r--r--awt/java/awt/FontFormatException.java41
-rw-r--r--awt/java/awt/FontMetrics.java456
-rw-r--r--awt/java/awt/GradientPaint.java219
-rw-r--r--awt/java/awt/GradientPaintContext.java204
-rw-r--r--awt/java/awt/Graphics.java737
-rw-r--r--awt/java/awt/Graphics2D.java456
-rw-r--r--awt/java/awt/GraphicsConfiguration.java217
-rw-r--r--awt/java/awt/GraphicsDevice.java199
-rw-r--r--awt/java/awt/GraphicsEnvironment.java209
-rw-r--r--awt/java/awt/HeadlessException.java48
-rw-r--r--awt/java/awt/HeadlessGraphicsEnvironment.java69
-rw-r--r--awt/java/awt/HeadlessToolkit.java301
-rw-r--r--awt/java/awt/IllegalComponentStateException.java51
-rw-r--r--awt/java/awt/Image.java203
-rw-r--r--awt/java/awt/ImageCapabilities.java74
-rw-r--r--awt/java/awt/Insets.java165
-rw-r--r--awt/java/awt/ItemSelectable.java53
-rw-r--r--awt/java/awt/MenuComponent.java1041
-rw-r--r--awt/java/awt/MenuContainer.java56
-rw-r--r--awt/java/awt/ModalContext.java64
-rw-r--r--awt/java/awt/MouseDispatcher.java418
-rw-r--r--awt/java/awt/Paint.java52
-rw-r--r--awt/java/awt/PaintContext.java64
-rw-r--r--awt/java/awt/Point.java195
-rw-r--r--awt/java/awt/Polygon.java494
-rw-r--r--awt/java/awt/Rectangle.java686
-rw-r--r--awt/java/awt/RenderingHints.java601
-rw-r--r--awt/java/awt/Shape.java162
-rw-r--r--awt/java/awt/Stroke.java47
-rw-r--r--awt/java/awt/Toolkit.java1338
-rw-r--r--awt/java/awt/ToolkitImpl.java255
-rw-r--r--awt/java/awt/Transparency.java51
-rw-r--r--awt/java/awt/color/CMMException.java40
-rw-r--r--awt/java/awt/color/ColorSpace.java340
-rw-r--r--awt/java/awt/color/ICC_ColorSpace.java379
-rw-r--r--awt/java/awt/color/ICC_Profile.java1231
-rw-r--r--awt/java/awt/color/ICC_ProfileGray.java68
-rw-r--r--awt/java/awt/color/ICC_ProfileRGB.java122
-rw-r--r--awt/java/awt/color/ICC_ProfileStub.java173
-rw-r--r--awt/java/awt/color/ProfileDataException.java42
-rw-r--r--awt/java/awt/event/AWTEventListener.java30
-rw-r--r--awt/java/awt/event/AWTEventListenerProxy.java52
-rw-r--r--awt/java/awt/event/ActionEvent.java108
-rw-r--r--awt/java/awt/event/ActionListener.java29
-rw-r--r--awt/java/awt/event/AdjustmentEvent.java117
-rw-r--r--awt/java/awt/event/AdjustmentListener.java29
-rw-r--r--awt/java/awt/event/ComponentAdapter.java40
-rw-r--r--awt/java/awt/event/ComponentEvent.java82
-rw-r--r--awt/java/awt/event/ComponentListener.java35
-rw-r--r--awt/java/awt/event/ContainerAdapter.java34
-rw-r--r--awt/java/awt/event/ContainerEvent.java83
-rw-r--r--awt/java/awt/event/ContainerListener.java31
-rw-r--r--awt/java/awt/event/FocusAdapter.java34
-rw-r--r--awt/java/awt/event/FocusEvent.java90
-rw-r--r--awt/java/awt/event/FocusListener.java31
-rw-r--r--awt/java/awt/event/HierarchyBoundsAdapter.java34
-rw-r--r--awt/java/awt/event/HierarchyBoundsListener.java31
-rw-r--r--awt/java/awt/event/HierarchyEvent.java148
-rw-r--r--awt/java/awt/event/HierarchyListener.java29
-rw-r--r--awt/java/awt/event/InputEvent.java184
-rw-r--r--awt/java/awt/event/InputMethodEvent.java150
-rw-r--r--awt/java/awt/event/InputMethodListener.java31
-rw-r--r--awt/java/awt/event/InvocationEvent.java132
-rw-r--r--awt/java/awt/event/ItemEvent.java90
-rw-r--r--awt/java/awt/event/ItemListener.java29
-rw-r--r--awt/java/awt/event/KeyAdapter.java37
-rw-r--r--awt/java/awt/event/KeyEvent.java681
-rw-r--r--awt/java/awt/event/KeyListener.java33
-rw-r--r--awt/java/awt/event/MouseAdapter.java43
-rw-r--r--awt/java/awt/event/MouseEvent.java226
-rw-r--r--awt/java/awt/event/MouseListener.java37
-rw-r--r--awt/java/awt/event/MouseMotionAdapter.java34
-rw-r--r--awt/java/awt/event/MouseMotionListener.java31
-rw-r--r--awt/java/awt/event/MouseWheelEvent.java97
-rw-r--r--awt/java/awt/event/MouseWheelListener.java29
-rw-r--r--awt/java/awt/event/PaintEvent.java80
-rw-r--r--awt/java/awt/event/TextEvent.java53
-rw-r--r--awt/java/awt/event/TextListener.java30
-rw-r--r--awt/java/awt/event/WindowAdapter.java58
-rw-r--r--awt/java/awt/event/WindowEvent.java162
-rw-r--r--awt/java/awt/event/WindowFocusListener.java31
-rw-r--r--awt/java/awt/event/WindowListener.java41
-rw-r--r--awt/java/awt/event/WindowStateListener.java30
-rw-r--r--awt/java/awt/font/FontRenderContext.java168
-rw-r--r--awt/java/awt/font/GlyphJustificationInfo.java185
-rw-r--r--awt/java/awt/font/GlyphMetrics.java248
-rw-r--r--awt/java/awt/font/GlyphVector.java394
-rw-r--r--awt/java/awt/font/GraphicAttribute.java196
-rw-r--r--awt/java/awt/font/ImageGraphicAttribute.java179
-rw-r--r--awt/java/awt/font/LineBreakMeasurer.java231
-rw-r--r--awt/java/awt/font/LineMetrics.java115
-rw-r--r--awt/java/awt/font/MultipleMaster.java86
-rw-r--r--awt/java/awt/font/OpenType.java410
-rw-r--r--awt/java/awt/font/ShapeGraphicAttribute.java195
-rw-r--r--awt/java/awt/font/TextHitInfo.java216
-rw-r--r--awt/java/awt/font/TextLayout.java916
-rw-r--r--awt/java/awt/font/TextMeasurer.java167
-rw-r--r--awt/java/awt/font/TransformAttribute.java80
-rw-r--r--awt/java/awt/geom/AffineTransform.java1158
-rw-r--r--awt/java/awt/geom/Arc2D.java1028
-rw-r--r--awt/java/awt/geom/Area.java317
-rw-r--r--awt/java/awt/geom/CubicCurve2D.java945
-rw-r--r--awt/java/awt/geom/Dimension2D.java78
-rw-r--r--awt/java/awt/geom/Ellipse2D.java403
-rw-r--r--awt/java/awt/geom/FlatteningPathIterator.java326
-rw-r--r--awt/java/awt/geom/GeneralPath.java566
-rw-r--r--awt/java/awt/geom/IllegalPathStateException.java50
-rw-r--r--awt/java/awt/geom/Line2D.java871
-rw-r--r--awt/java/awt/geom/NoninvertibleTransformException.java43
-rw-r--r--awt/java/awt/geom/PathIterator.java132
-rw-r--r--awt/java/awt/geom/Point2D.java288
-rw-r--r--awt/java/awt/geom/QuadCurve2D.java824
-rw-r--r--awt/java/awt/geom/Rectangle2D.java761
-rw-r--r--awt/java/awt/geom/RectangularShape.java276
-rw-r--r--awt/java/awt/geom/RoundRectangle2D.java552
-rw-r--r--awt/java/awt/im/InputContext.java77
-rw-r--r--awt/java/awt/im/InputMethodHighlight.java89
-rw-r--r--awt/java/awt/im/InputMethodRequests.java43
-rw-r--r--awt/java/awt/im/InputSubset.java53
-rw-r--r--awt/java/awt/im/spi/InputMethod.java61
-rw-r--r--awt/java/awt/im/spi/InputMethodContext.java40
-rw-r--r--awt/java/awt/im/spi/InputMethodDescriptor.java40
-rw-r--r--awt/java/awt/image/AffineTransformOp.java617
-rw-r--r--awt/java/awt/image/AreaAveragingScaleFilter.java253
-rw-r--r--awt/java/awt/image/AwtImageBackdoorAccessorImpl.java153
-rw-r--r--awt/java/awt/image/BandCombineOp.java610
-rw-r--r--awt/java/awt/image/BandedSampleModel.java426
-rw-r--r--awt/java/awt/image/BufferStrategy.java72
-rw-r--r--awt/java/awt/image/BufferedImage.java931
-rw-r--r--awt/java/awt/image/BufferedImageFilter.java375
-rw-r--r--awt/java/awt/image/BufferedImageOp.java86
-rw-r--r--awt/java/awt/image/ByteLookupTable.java134
-rw-r--r--awt/java/awt/image/ColorConvertOp.java711
-rw-r--r--awt/java/awt/image/ColorModel.java911
-rw-r--r--awt/java/awt/image/ComponentColorModel.java1471
-rw-r--r--awt/java/awt/image/ComponentSampleModel.java690
-rw-r--r--awt/java/awt/image/ConvolveOp.java545
-rw-r--r--awt/java/awt/image/CropImageFilter.java193
-rw-r--r--awt/java/awt/image/DataBuffer.java442
-rw-r--r--awt/java/awt/image/DataBufferByte.java171
-rw-r--r--awt/java/awt/image/DataBufferDouble.java214
-rw-r--r--awt/java/awt/image/DataBufferFloat.java214
-rw-r--r--awt/java/awt/image/DataBufferInt.java170
-rw-r--r--awt/java/awt/image/DataBufferShort.java172
-rw-r--r--awt/java/awt/image/DataBufferUShort.java182
-rw-r--r--awt/java/awt/image/DirectColorModel.java862
-rw-r--r--awt/java/awt/image/FilteredImageSource.java88
-rw-r--r--awt/java/awt/image/ImageConsumer.java165
-rw-r--r--awt/java/awt/image/ImageFilter.java129
-rw-r--r--awt/java/awt/image/ImageObserver.java99
-rw-r--r--awt/java/awt/image/ImageProducer.java74
-rw-r--r--awt/java/awt/image/ImagingOpException.java44
-rw-r--r--awt/java/awt/image/IndexColorModel.java1020
-rw-r--r--awt/java/awt/image/Kernel.java138
-rw-r--r--awt/java/awt/image/LookupOp.java647
-rw-r--r--awt/java/awt/image/LookupTable.java93
-rw-r--r--awt/java/awt/image/MemoryImageSource.java512
-rw-r--r--awt/java/awt/image/MultiPixelPackedSampleModel.java454
-rw-r--r--awt/java/awt/image/PackedColorModel.java383
-rw-r--r--awt/java/awt/image/PixelGrabber.java408
-rw-r--r--awt/java/awt/image/PixelInterleavedSampleModel.java124
-rw-r--r--awt/java/awt/image/RGBImageFilter.java190
-rw-r--r--awt/java/awt/image/Raster.java1412
-rw-r--r--awt/java/awt/image/RasterFormatException.java45
-rw-r--r--awt/java/awt/image/RasterOp.java83
-rw-r--r--awt/java/awt/image/RenderedImage.java198
-rw-r--r--awt/java/awt/image/ReplicateScaleFilter.java213
-rw-r--r--awt/java/awt/image/RescaleOp.java659
-rw-r--r--awt/java/awt/image/SampleModel.java1053
-rw-r--r--awt/java/awt/image/ShortLookupTable.java132
-rw-r--r--awt/java/awt/image/SinglePixelPackedSampleModel.java508
-rw-r--r--awt/java/awt/image/TileObserver.java44
-rw-r--r--awt/java/awt/image/VolatileImage.java144
-rw-r--r--awt/java/awt/image/WritableRaster.java516
-rw-r--r--awt/java/awt/image/WritableRenderedImage.java101
-rw-r--r--awt/java/awt/image/renderable/ContextualRenderedImageFactory.java89
-rw-r--r--awt/java/awt/image/renderable/ParameterBlock.java548
-rw-r--r--awt/java/awt/image/renderable/RenderContext.java196
-rw-r--r--awt/java/awt/image/renderable/RenderableImage.java132
-rw-r--r--awt/java/awt/image/renderable/RenderableImageOp.java182
-rw-r--r--awt/java/awt/image/renderable/RenderableImageProducer.java141
-rw-r--r--awt/java/awt/image/renderable/RenderedImageFactory.java43
-rw-r--r--awt/java/awt/peer/ButtonPeer.java25
-rw-r--r--awt/java/awt/peer/CanvasPeer.java25
-rw-r--r--awt/java/awt/peer/CheckboxMenuItemPeer.java25
-rw-r--r--awt/java/awt/peer/CheckboxPeer.java25
-rw-r--r--awt/java/awt/peer/ChoicePeer.java25
-rw-r--r--awt/java/awt/peer/ComponentPeer.java25
-rw-r--r--awt/java/awt/peer/DialogPeer.java25
-rw-r--r--awt/java/awt/peer/FileDialogPeer.java25
-rw-r--r--awt/java/awt/peer/FontPeer.java25
-rw-r--r--awt/java/awt/peer/FramePeer.java25
-rw-r--r--awt/java/awt/peer/LabelPeer.java25
-rw-r--r--awt/java/awt/peer/LightweightPeer.java25
-rw-r--r--awt/java/awt/peer/ListPeer.java25
-rw-r--r--awt/java/awt/peer/MenuBarPeer.java25
-rw-r--r--awt/java/awt/peer/MenuComponentPeer.java25
-rw-r--r--awt/java/awt/peer/MenuItemPeer.java25
-rw-r--r--awt/java/awt/peer/MenuPeer.java25
-rw-r--r--awt/java/awt/peer/MouseInfoPeer.java25
-rw-r--r--awt/java/awt/peer/PanelPeer.java25
-rw-r--r--awt/java/awt/peer/PopupMenuPeer.java25
-rw-r--r--awt/java/awt/peer/ScrollPanePeer.java25
-rw-r--r--awt/java/awt/peer/ScrollbarPeer.java25
-rw-r--r--awt/java/awt/peer/TextAreaPeer.java25
-rw-r--r--awt/java/awt/peer/TextFieldPeer.java25
-rw-r--r--awt/java/awt/peer/WindowPeer.java25
-rw-r--r--awt/java/beans/FeatureDescriptor.java234
-rw-r--r--awt/java/beans/IndexedPropertyChangeEvent.java66
-rw-r--r--awt/java/beans/IndexedPropertyDescriptor.java227
-rw-r--r--awt/java/beans/IntrospectionException.java27
-rw-r--r--awt/java/beans/PropertyChangeEvent.java62
-rw-r--r--awt/java/beans/PropertyChangeListener.java25
-rw-r--r--awt/java/beans/PropertyChangeListenerProxy.java41
-rw-r--r--awt/java/beans/PropertyChangeSupport.java351
-rw-r--r--awt/java/beans/PropertyDescriptor.java300
-rw-r--r--awt/java/beans/PropertyEditor.java49
-rw-r--r--awt/java/beans/PropertyEditorManager.java114
-rw-r--r--awt/java/beans/PropertyEditorSupport.java129
-rw-r--r--awt/java/beans/PropertyVetoException.java54
-rw-r--r--awt/javax/imageio/IIOException.java52
-rw-r--r--awt/javax/imageio/IIOImage.java203
-rw-r--r--awt/javax/imageio/IIOParam.java316
-rw-r--r--awt/javax/imageio/IIOParamController.java43
-rw-r--r--awt/javax/imageio/ImageIO.java777
-rw-r--r--awt/javax/imageio/ImageReadParam.java193
-rw-r--r--awt/javax/imageio/ImageReader.java1100
-rw-r--r--awt/javax/imageio/ImageTranscoder.java60
-rw-r--r--awt/javax/imageio/ImageTypeSpecifier.java339
-rw-r--r--awt/javax/imageio/ImageWriteParam.java633
-rw-r--r--awt/javax/imageio/ImageWriter.java951
-rw-r--r--awt/javax/imageio/event/IIOReadProgressListener.java103
-rw-r--r--awt/javax/imageio/event/IIOReadUpdateListener.java138
-rw-r--r--awt/javax/imageio/event/IIOReadWarningListener.java46
-rw-r--r--awt/javax/imageio/event/IIOWriteProgressListener.java86
-rw-r--r--awt/javax/imageio/event/IIOWriteWarningListener.java40
-rw-r--r--awt/javax/imageio/metadata/IIOInvalidTreeException.java67
-rw-r--r--awt/javax/imageio/metadata/IIOMetadata.java371
-rw-r--r--awt/javax/imageio/metadata/IIOMetadataController.java45
-rw-r--r--awt/javax/imageio/metadata/IIOMetadataFormat.java347
-rw-r--r--awt/javax/imageio/metadata/IIOMetadataFormatImpl.java939
-rw-r--r--awt/javax/imageio/metadata/IIOMetadataNode.java675
-rw-r--r--awt/javax/imageio/metadata/IIOStandardMetadataFormat.java316
-rw-r--r--awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties133
-rw-r--r--awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java75
-rw-r--r--awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java213
-rw-r--r--awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java116
-rw-r--r--awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java193
-rw-r--r--awt/javax/imageio/plugins/jpeg/JPEGQTable.java162
-rw-r--r--awt/javax/imageio/spi/IIORegistry.java110
-rw-r--r--awt/javax/imageio/spi/IIOServiceProvider.java97
-rw-r--r--awt/javax/imageio/spi/ImageInputStreamSpi.java126
-rw-r--r--awt/javax/imageio/spi/ImageOutputStreamSpi.java126
-rw-r--r--awt/javax/imageio/spi/ImageReaderSpi.java186
-rw-r--r--awt/javax/imageio/spi/ImageReaderWriterSpi.java315
-rw-r--r--awt/javax/imageio/spi/ImageTranscoderSpi.java74
-rw-r--r--awt/javax/imageio/spi/ImageWriterSpi.java209
-rw-r--r--awt/javax/imageio/spi/RegisterableService.java50
-rw-r--r--awt/javax/imageio/spi/ServiceRegistry.java516
-rw-r--r--awt/javax/imageio/stream/FileCacheImageInputStream.java131
-rw-r--r--awt/javax/imageio/stream/FileCacheImageOutputStream.java184
-rw-r--r--awt/javax/imageio/stream/FileImageInputStream.java115
-rw-r--r--awt/javax/imageio/stream/FileImageOutputStream.java123
-rw-r--r--awt/javax/imageio/stream/IIOByteBuffer.java111
-rw-r--r--awt/javax/imageio/stream/ImageInputStream.java485
-rw-r--r--awt/javax/imageio/stream/ImageInputStreamImpl.java394
-rw-r--r--awt/javax/imageio/stream/ImageOutputStream.java270
-rw-r--r--awt/javax/imageio/stream/ImageOutputStreamImpl.java169
-rw-r--r--awt/javax/imageio/stream/MemoryCacheImageInputStream.java113
-rw-r--r--awt/javax/imageio/stream/MemoryCacheImageOutputStream.java130
-rw-r--r--awt/org/apache/harmony/awt/ChoiceStyle.java33
-rw-r--r--awt/org/apache/harmony/awt/ClipRegion.java84
-rw-r--r--awt/org/apache/harmony/awt/ComponentInternals.java212
-rw-r--r--awt/org/apache/harmony/awt/ContextStorage.java154
-rw-r--r--awt/org/apache/harmony/awt/ContextThreadGroup.java34
-rw-r--r--awt/org/apache/harmony/awt/ListenerList.java194
-rw-r--r--awt/org/apache/harmony/awt/ReadOnlyIterator.java53
-rw-r--r--awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java65
-rw-r--r--awt/org/apache/harmony/awt/gl/CommonGraphics2D.java1132
-rw-r--r--awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java78
-rw-r--r--awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java67
-rw-r--r--awt/org/apache/harmony/awt/gl/Crossing.java889
-rw-r--r--awt/org/apache/harmony/awt/gl/GLVolatileImage.java30
-rw-r--r--awt/org/apache/harmony/awt/gl/ICompositeContext.java90
-rw-r--r--awt/org/apache/harmony/awt/gl/ImageSurface.java323
-rw-r--r--awt/org/apache/harmony/awt/gl/MultiRectArea.java836
-rw-r--r--awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java837
-rw-r--r--awt/org/apache/harmony/awt/gl/Surface.java309
-rw-r--r--awt/org/apache/harmony/awt/gl/TextRenderer.java59
-rw-r--r--awt/org/apache/harmony/awt/gl/XORComposite.java48
-rw-r--r--awt/org/apache/harmony/awt/gl/color/ColorConverter.java257
-rw-r--r--awt/org/apache/harmony/awt/gl/color/ColorScaler.java355
-rw-r--r--awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java82
-rw-r--r--awt/org/apache/harmony/awt/gl/color/ICC_Transform.java156
-rw-r--r--awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java148
-rw-r--r--awt/org/apache/harmony/awt/gl/color/NativeCMM.java92
-rw-r--r--awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java642
-rw-r--r--awt/org/apache/harmony/awt/gl/font/AndroidFont.java254
-rw-r--r--awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java277
-rw-r--r--awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java81
-rw-r--r--awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java219
-rw-r--r--awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java120
-rw-r--r--awt/org/apache/harmony/awt/gl/font/BasicMetrics.java134
-rw-r--r--awt/org/apache/harmony/awt/gl/font/CaretManager.java530
-rw-r--r--awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java954
-rw-r--r--awt/org/apache/harmony/awt/gl/font/CompositeFont.java486
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java145
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontFinder.java121
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontManager.java819
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java282
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java499
-rw-r--r--awt/org/apache/harmony/awt/gl/font/FontProperty.java106
-rw-r--r--awt/org/apache/harmony/awt/gl/font/Glyph.java236
-rw-r--r--awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java412
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextDecorator.java433
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java209
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java861
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextRunSegment.java165
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java979
-rw-r--r--awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java79
-rw-r--r--awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java136
-rw-r--r--awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java62
-rw-r--r--awt/org/apache/harmony/awt/gl/image/DataBufferListener.java31
-rw-r--r--awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java261
-rw-r--r--awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java68
-rw-r--r--awt/org/apache/harmony/awt/gl/image/GifDecoder.java692
-rw-r--r--awt/org/apache/harmony/awt/gl/image/ImageDecoder.java258
-rw-r--r--awt/org/apache/harmony/awt/gl/image/ImageLoader.java208
-rw-r--r--awt/org/apache/harmony/awt/gl/image/JpegDecoder.java231
-rw-r--r--awt/org/apache/harmony/awt/gl/image/OffscreenImage.java532
-rw-r--r--awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java153
-rw-r--r--awt/org/apache/harmony/awt/gl/image/PngDecoder.java270
-rw-r--r--awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java282
-rw-r--r--awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java77
-rw-r--r--awt/org/apache/harmony/awt/gl/render/Blitter.java53
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java502
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaBlitter.java611
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java760
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java475
-rw-r--r--awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java263
-rw-r--r--awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java218
-rw-r--r--awt/org/apache/harmony/awt/gl/render/NullBlitter.java56
-rw-r--r--awt/org/apache/harmony/awt/im/InputMethodContext.java563
-rw-r--r--awt/org/apache/harmony/awt/internal/nls/Messages.java143
-rw-r--r--awt/org/apache/harmony/awt/internal/nls/MsgHelp.java86
-rw-r--r--awt/org/apache/harmony/awt/state/MenuItemState.java51
-rw-r--r--awt/org/apache/harmony/awt/state/MenuState.java46
-rw-r--r--awt/org/apache/harmony/awt/state/State.java55
-rw-r--r--awt/org/apache/harmony/awt/wtk/CreationParams.java133
-rw-r--r--awt/org/apache/harmony/awt/wtk/CursorFactory.java85
-rw-r--r--awt/org/apache/harmony/awt/wtk/GraphicsFactory.java82
-rw-r--r--awt/org/apache/harmony/awt/wtk/KeyInfo.java53
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeCursor.java45
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeEvent.java268
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeEventQueue.java117
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeEventThread.java78
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeIM.java130
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java42
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeRobot.java75
-rw-r--r--awt/org/apache/harmony/awt/wtk/NativeWindow.java220
-rw-r--r--awt/org/apache/harmony/awt/wtk/ShutdownThread.java83
-rw-r--r--awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java86
-rw-r--r--awt/org/apache/harmony/awt/wtk/Synchronizer.java200
-rw-r--r--awt/org/apache/harmony/awt/wtk/SystemProperties.java59
-rw-r--r--awt/org/apache/harmony/awt/wtk/WTK.java61
-rw-r--r--awt/org/apache/harmony/awt/wtk/WindowFactory.java85
-rw-r--r--awt/org/apache/harmony/beans/internal/nls/Messages.java132
-rw-r--r--awt/org/apache/harmony/beans/internal/nls/messages.properties103
-rw-r--r--awt/org/apache/harmony/x/imageio/internal/nls/Messages.java124
-rw-r--r--awt/org/apache/harmony/x/imageio/internal/nls/messages.properties18
-rw-r--r--awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java94
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java115
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java44
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java126
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java86
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java402
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java56
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java57
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java106
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java88
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java247
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java41
-rw-r--r--awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java113
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java53
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java52
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java59
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java60
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java54
-rw-r--r--awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java53
-rw-r--r--awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java226
-rw-r--r--awt/resources/org/apache/harmony/awt/internal/nls/messages.properties495
-rw-r--r--camera/libcameraservice/Android.mk58
-rw-r--r--camera/libcameraservice/CameraHardwareStub.cpp357
-rw-r--r--camera/libcameraservice/CameraHardwareStub.h115
-rw-r--r--camera/libcameraservice/CameraService.cpp757
-rw-r--r--camera/libcameraservice/CameraService.h160
-rw-r--r--camera/libcameraservice/CannedJpeg.h1546
-rw-r--r--camera/libcameraservice/FakeCamera.cpp404
-rw-r--r--camera/libcameraservice/FakeCamera.h51
-rw-r--r--cmds/runtime/Android.mk29
-rw-r--r--cmds/runtime/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/runtime/NOTICE190
-rw-r--r--cmds/runtime/ServiceManager.cpp74
-rw-r--r--cmds/runtime/ServiceManager.h38
-rw-r--r--cmds/runtime/SignalHandler.cpp249
-rw-r--r--cmds/runtime/SignalHandler.h137
-rw-r--r--cmds/runtime/main_runtime.cpp514
-rw-r--r--cmds/surfaceflinger/Android.mk16
-rw-r--r--cmds/surfaceflinger/main_surfaceflinger.cpp18
-rw-r--r--include/GLES/egl.h268
-rw-r--r--include/GLES/eglnatives.h276
-rw-r--r--include/GLES/egltypes.h47
-rw-r--r--include/GLES/gl.h639
-rw-r--r--include/pim/EventRecurrence.h82
-rw-r--r--include/private/opengles/gl_context.h624
-rw-r--r--include/private/ui/LayerState.h75
-rw-r--r--include/private/ui/SharedState.h168
-rw-r--r--include/private/ui/SurfaceFlingerSynchro.h76
-rw-r--r--include/private/utils/Static.h58
-rw-r--r--include/private/utils/binder_module.h148
-rw-r--r--include/private/utils/futex_synchro.h60
-rw-r--r--include/ui/BlitHardware.h143
-rw-r--r--include/ui/Camera.h125
-rw-r--r--include/ui/CameraHardwareInterface.h156
-rw-r--r--include/ui/CameraParameters.h70
-rw-r--r--include/ui/DisplayInfo.h43
-rw-r--r--include/ui/EGLDisplaySurface.h82
-rw-r--r--include/ui/EGLNativeSurface.h64
-rw-r--r--include/ui/EGLNativeWindowSurface.h60
-rw-r--r--include/ui/EventHub.h142
-rw-r--r--include/ui/ICamera.h75
-rw-r--r--include/ui/ICameraClient.h54
-rw-r--r--include/ui/ICameraService.h55
-rw-r--r--include/ui/ISurface.h62
-rw-r--r--include/ui/ISurfaceComposer.h181
-rw-r--r--include/ui/ISurfaceFlingerClient.h91
-rw-r--r--include/ui/KeyCharacterMap.h72
-rw-r--r--include/ui/KeycodeLabels.h222
-rw-r--r--include/ui/PixelFormat.h106
-rw-r--r--include/ui/Point.h88
-rw-r--r--include/ui/Rect.h152
-rw-r--r--include/ui/Region.h174
-rw-r--r--include/ui/Surface.h137
-rw-r--r--include/ui/SurfaceComposerClient.h179
-rw-r--r--include/utils.h33
-rw-r--r--include/utils/AndroidUnicode.h255
-rw-r--r--include/utils/Asset.h311
-rw-r--r--include/utils/AssetDir.h145
-rw-r--r--include/utils/AssetManager.h323
-rw-r--r--include/utils/Atomic.h22
-rw-r--r--include/utils/Binder.h103
-rw-r--r--include/utils/BpBinder.h122
-rw-r--r--include/utils/Buffer.h107
-rw-r--r--include/utils/BufferedTextOutput.h67
-rw-r--r--include/utils/ByteOrder.h69
-rw-r--r--include/utils/CallStack.h76
-rw-r--r--include/utils/Debug.h45
-rw-r--r--include/utils/Endian.h40
-rw-r--r--include/utils/Errors.h87
-rw-r--r--include/utils/FileMap.h134
-rw-r--r--include/utils/IBinder.h159
-rw-r--r--include/utils/IInterface.h135
-rw-r--r--include/utils/IMemory.h94
-rw-r--r--include/utils/IPCThreadState.h107
-rw-r--r--include/utils/IPermissionController.h56
-rw-r--r--include/utils/IServiceManager.h98
-rw-r--r--include/utils/KeyedVector.h201
-rw-r--r--include/utils/List.h280
-rw-r--r--include/utils/Log.h33
-rw-r--r--include/utils/LogSocket.h20
-rw-r--r--include/utils/MemoryBase.h51
-rw-r--r--include/utils/MemoryDealer.h238
-rw-r--r--include/utils/MemoryHeapBase.h95
-rw-r--r--include/utils/MemoryHeapPmem.h65
-rw-r--r--include/utils/Parcel.h196
-rw-r--r--include/utils/Pipe.h108
-rw-r--r--include/utils/ProcessState.h117
-rw-r--r--include/utils/RefBase.h526
-rw-r--r--include/utils/ResourceTypes.h1685
-rw-r--r--include/utils/SharedBuffer.h146
-rw-r--r--include/utils/Socket.h80
-rw-r--r--include/utils/SortedVector.h282
-rw-r--r--include/utils/StopWatch.h62
-rw-r--r--include/utils/String16.h260
-rw-r--r--include/utils/String8.h353
-rw-r--r--include/utils/SystemClock.h32
-rw-r--r--include/utils/TextOutput.h190
-rw-r--r--include/utils/TimeUtils.h88
-rw-r--r--include/utils/TimerProbe.h72
-rw-r--r--include/utils/Timers.h137
-rw-r--r--include/utils/TypeHelpers.h254
-rw-r--r--include/utils/Vector.h359
-rw-r--r--include/utils/VectorImpl.h199
-rw-r--r--include/utils/ZipEntry.h345
-rw-r--r--include/utils/ZipFile.h269
-rw-r--r--include/utils/ZipFileCRO.h59
-rw-r--r--include/utils/ZipFileRO.h222
-rw-r--r--include/utils/ZipUtils.h67
-rw-r--r--include/utils/ashmem.h41
-rw-r--r--include/utils/executablepath.h28
-rw-r--r--include/utils/inet_address.h103
-rw-r--r--include/utils/logger.h46
-rw-r--r--include/utils/misc.h93
-rw-r--r--include/utils/ported.h50
-rw-r--r--include/utils/string_array.h122
-rw-r--r--include/utils/threads.h347
-rw-r--r--libs/audioflinger/Android.mk53
-rw-r--r--libs/audioflinger/AudioBufferProvider.h47
-rw-r--r--libs/audioflinger/AudioDumpInterface.cpp94
-rw-r--r--libs/audioflinger/AudioDumpInterface.h101
-rw-r--r--libs/audioflinger/AudioFlinger.cpp1450
-rw-r--r--libs/audioflinger/AudioFlinger.h490
-rw-r--r--libs/audioflinger/AudioHardwareGeneric.cpp293
-rw-r--r--libs/audioflinger/AudioHardwareGeneric.h135
-rw-r--r--libs/audioflinger/AudioHardwareInterface.cpp240
-rw-r--r--libs/audioflinger/AudioHardwareStub.cpp175
-rw-r--r--libs/audioflinger/AudioHardwareStub.h95
-rw-r--r--libs/audioflinger/AudioMixer.cpp857
-rw-r--r--libs/audioflinger/AudioMixer.h192
-rw-r--r--libs/audioflinger/AudioResampler.cpp297
-rw-r--r--libs/audioflinger/AudioResampler.h93
-rw-r--r--libs/audioflinger/AudioResamplerCubic.cpp178
-rw-r--r--libs/audioflinger/AudioResamplerCubic.h68
-rw-r--r--libs/audioflinger/AudioResamplerSinc.cpp320
-rw-r--r--libs/audioflinger/AudioResamplerSinc.h87
-rw-r--r--libs/surfaceflinger/Android.mk47
-rw-r--r--libs/surfaceflinger/Barrier.h59
-rw-r--r--libs/surfaceflinger/BlurFilter.cpp326
-rw-r--r--libs/surfaceflinger/BlurFilter.h35
-rw-r--r--libs/surfaceflinger/BootAnimation.cpp424
-rw-r--r--libs/surfaceflinger/BootAnimation.h84
-rw-r--r--libs/surfaceflinger/CPUGauge.cpp171
-rw-r--r--libs/surfaceflinger/CPUGauge.h74
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp335
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.h105
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp395
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h96
-rw-r--r--libs/surfaceflinger/GPUHardware/GPUHardware.cpp557
-rw-r--r--libs/surfaceflinger/GPUHardware/GPUHardware.h116
-rw-r--r--libs/surfaceflinger/Layer.cpp565
-rw-r--r--libs/surfaceflinger/Layer.h120
-rw-r--r--libs/surfaceflinger/LayerBase.cpp700
-rw-r--r--libs/surfaceflinger/LayerBase.h271
-rw-r--r--libs/surfaceflinger/LayerBitmap.cpp188
-rw-r--r--libs/surfaceflinger/LayerBitmap.h87
-rw-r--r--libs/surfaceflinger/LayerBlur.cpp229
-rw-r--r--libs/surfaceflinger/LayerBlur.h65
-rw-r--r--libs/surfaceflinger/LayerBuffer.cpp366
-rw-r--r--libs/surfaceflinger/LayerBuffer.h145
-rw-r--r--libs/surfaceflinger/LayerDim.cpp113
-rw-r--r--libs/surfaceflinger/LayerDim.h57
-rw-r--r--libs/surfaceflinger/LayerScreenshot.cpp110
-rw-r--r--libs/surfaceflinger/LayerScreenshot.h57
-rw-r--r--libs/surfaceflinger/MODULE_LICENSE_APACHE20
-rw-r--r--libs/surfaceflinger/RFBServer.cpp722
-rw-r--r--libs/surfaceflinger/RFBServer.h316
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.cpp1895
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.h433
-rw-r--r--libs/surfaceflinger/Tokenizer.cpp172
-rw-r--r--libs/surfaceflinger/Tokenizer.h57
-rw-r--r--libs/surfaceflinger/Transform.cpp204
-rw-r--r--libs/surfaceflinger/Transform.h87
-rw-r--r--libs/surfaceflinger/VRamHeap.cpp161
-rw-r--r--libs/surfaceflinger/VRamHeap.h86
-rw-r--r--libs/surfaceflinger/clz.cpp37
-rw-r--r--libs/surfaceflinger/clz.h37
-rw-r--r--libs/ui/Android.mk39
-rw-r--r--libs/ui/BlitHardware.cpp446
-rw-r--r--libs/ui/Camera.cpp249
-rw-r--r--libs/ui/CameraParameters.cpp253
-rw-r--r--libs/ui/EGLDisplaySurface.cpp471
-rw-r--r--libs/ui/EGLNativeWindowSurface.cpp181
-rw-r--r--libs/ui/EventHub.cpp743
-rw-r--r--libs/ui/EventRecurrence.cpp484
-rw-r--r--libs/ui/ICamera.cpp204
-rw-r--r--libs/ui/ICameraClient.cpp153
-rw-r--r--libs/ui/ICameraService.cpp77
-rw-r--r--libs/ui/ISurface.cpp117
-rw-r--r--libs/ui/ISurfaceComposer.cpp277
-rw-r--r--libs/ui/ISurfaceFlingerClient.cpp210
-rw-r--r--libs/ui/KeyCharacterMap.cpp263
-rw-r--r--libs/ui/KeyLayoutMap.cpp235
-rw-r--r--libs/ui/KeyLayoutMap.h31
-rw-r--r--libs/ui/LayerState.cpp53
-rw-r--r--libs/ui/MODULE_LICENSE_APACHE20
-rw-r--r--libs/ui/NOTICE190
-rw-r--r--libs/ui/PixelFormat.cpp66
-rw-r--r--libs/ui/Point.cpp11
-rw-r--r--libs/ui/Rect.cpp86
-rw-r--r--libs/ui/Region.cpp315
-rw-r--r--libs/ui/Surface.cpp261
-rw-r--r--libs/ui/SurfaceComposerClient.cpp1026
-rw-r--r--libs/ui/SurfaceFlingerSynchro.cpp123
-rw-r--r--libs/ui/Time.cpp199
-rw-r--r--libs/utils/Android.mk148
-rw-r--r--libs/utils/Asset.cpp813
-rw-r--r--libs/utils/AssetDir.cpp66
-rw-r--r--libs/utils/AssetManager.cpp1637
-rw-r--r--libs/utils/Binder.cpp242
-rw-r--r--libs/utils/BpBinder.cpp348
-rw-r--r--libs/utils/BufferedTextOutput.cpp279
-rw-r--r--libs/utils/CallStack.cpp335
-rw-r--r--libs/utils/Debug.cpp318
-rw-r--r--libs/utils/FileMap.cpp222
-rw-r--r--libs/utils/IDataConnection.cpp89
-rw-r--r--libs/utils/IInterface.cpp35
-rw-r--r--libs/utils/IMemory.cpp486
-rw-r--r--libs/utils/IPCThreadState.cpp1007
-rw-r--r--libs/utils/IPermissionController.cpp86
-rw-r--r--libs/utils/IServiceManager.cpp230
-rw-r--r--libs/utils/InetAddress.cpp236
-rw-r--r--libs/utils/LogSocket.cpp129
-rw-r--r--libs/utils/MODULE_LICENSE_APACHE20
-rw-r--r--libs/utils/MemoryBase.cpp46
-rw-r--r--libs/utils/MemoryDealer.cpp407
-rw-r--r--libs/utils/MemoryHeapBase.cpp178
-rw-r--r--libs/utils/MemoryHeapPmem.cpp226
-rw-r--r--libs/utils/NOTICE190
-rw-r--r--libs/utils/Parcel.cpp1311
-rw-r--r--libs/utils/Pipe.cpp465
-rw-r--r--libs/utils/ProcessState.cpp398
-rw-r--r--libs/utils/README14
-rw-r--r--libs/utils/RefBase.cpp534
-rw-r--r--libs/utils/ResourceTypes.cpp3969
-rw-r--r--libs/utils/SharedBuffer.cpp113
-rw-r--r--libs/utils/Socket.cpp388
-rw-r--r--libs/utils/Static.cpp120
-rw-r--r--libs/utils/StopWatch.cpp79
-rw-r--r--libs/utils/String16.cpp609
-rw-r--r--libs/utils/String8.cpp602
-rw-r--r--libs/utils/SystemClock.cpp139
-rw-r--r--libs/utils/TextOutput.cpp146
-rw-r--r--libs/utils/Threads.cpp1126
-rw-r--r--libs/utils/TimerProbe.cpp131
-rw-r--r--libs/utils/Timers.cpp240
-rw-r--r--libs/utils/Unicode.cpp193
-rw-r--r--libs/utils/VectorImpl.cpp611
-rw-r--r--libs/utils/ZipEntry.cpp696
-rw-r--r--libs/utils/ZipFile.cpp1296
-rw-r--r--libs/utils/ZipFileCRO.cpp54
-rw-r--r--libs/utils/ZipFileRO.cpp724
-rw-r--r--libs/utils/ZipUtils.cpp344
-rw-r--r--libs/utils/characterData.h730
-rw-r--r--libs/utils/executablepath_darwin.cpp31
-rw-r--r--libs/utils/executablepath_linux.cpp30
-rw-r--r--libs/utils/futex_synchro.c175
-rw-r--r--libs/utils/misc.cpp185
-rw-r--r--libs/utils/ported.cpp106
-rw-r--r--opengl/libGLES_CM/Android.mk22
-rw-r--r--opengl/libGLES_CM/egl_entries.cpp46
-rw-r--r--opengl/libGLES_CM/enumextract.sh32
-rw-r--r--opengl/libGLES_CM/gl_api.cpp606
-rw-r--r--opengl/libGLES_CM/gl_entries.cpp159
-rw-r--r--opengl/libGLES_CM/gl_enums.in261
-rw-r--r--opengl/libGLES_CM/gl_logger.cpp1059
-rw-r--r--opengl/libGLES_CM/gl_logger.h26
-rw-r--r--opengl/libGLES_CM/gl_wrapper.cpp1663
-rw-r--r--opengl/libagl/Android.mk34
-rw-r--r--opengl/libagl/BufferObjectManager.cpp103
-rw-r--r--opengl/libagl/BufferObjectManager.h85
-rw-r--r--opengl/libagl/TextureObjectManager.cpp309
-rw-r--r--opengl/libagl/TextureObjectManager.h140
-rw-r--r--opengl/libagl/TokenManager.cpp62
-rw-r--r--opengl/libagl/TokenManager.h53
-rw-r--r--opengl/libagl/Tokenizer.cpp173
-rw-r--r--opengl/libagl/Tokenizer.h59
-rw-r--r--opengl/libagl/array.cpp1557
-rw-r--r--opengl/libagl/array.h37
-rw-r--r--opengl/libagl/context.h20
-rw-r--r--opengl/libagl/dxt.cpp636
-rw-r--r--opengl/libagl/dxt.h33
-rw-r--r--opengl/libagl/egl.cpp1513
-rw-r--r--opengl/libagl/fixed_asm.S65
-rw-r--r--opengl/libagl/fp.cpp87
-rw-r--r--opengl/libagl/fp.h243
-rw-r--r--opengl/libagl/iterators.S88
-rw-r--r--opengl/libagl/light.cpp852
-rw-r--r--opengl/libagl/light.h38
-rw-r--r--opengl/libagl/matrix.cpp1144
-rw-r--r--opengl/libagl/matrix.h355
-rw-r--r--opengl/libagl/mipmap.cpp192
-rw-r--r--opengl/libagl/primitives.cpp1095
-rw-r--r--opengl/libagl/primitives.h37
-rw-r--r--opengl/libagl/state.cpp592
-rw-r--r--opengl/libagl/state.h54
-rw-r--r--opengl/libagl/texture.cpp1423
-rw-r--r--opengl/libagl/texture.h45
-rw-r--r--opengl/libagl/vertex.cpp247
-rw-r--r--opengl/libagl/vertex.h48
-rw-r--r--services/Android.mk17
727 files changed, 192150 insertions, 0 deletions
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..267a6aa
--- /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 0000000..c7480f5
--- /dev/null
+++ b/awt/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_RESOURCE_DIRS := resources
+
+LOCAL_JAVA_LIBRARIES := core framework
+
+LOCAL_MODULE:= android.awt
+
+LOCAL_DX_FLAGS := --core-library
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/awt/com/android/internal/awt/AndroidGraphics2D.java b/awt/com/android/internal/awt/AndroidGraphics2D.java
new file mode 100644
index 0000000..9a8ae02
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidGraphics2D.java
@@ -0,0 +1,1354 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import com.android.internal.awt.AndroidGraphicsConfiguration;
+import com.android.internal.graphics.NativeUtils;
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.PathIterator;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.font.AndroidGlyphVector;
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.graphics.Typeface;
+import android.graphics.PixelXorXfermode;
+import android.view.Display;
+import android.view.WindowManager;
+import android.content.Context;
+
+public class AndroidGraphics2D extends Graphics2D {
+
+ private int displayWidth, displayHeight;
+
+ protected Surface dstSurf = null;
+ protected MultiRectArea clip = null;
+
+ protected Composite composite = AlphaComposite.SrcOver;
+ protected AffineTransform transform = new AffineTransform();
+
+ private static AndroidGraphics2D mAg;
+ private static Canvas mC;
+
+ // Android Paint
+ public static Paint mP;
+
+ private static java.awt.Font mFnt;
+
+ // Cached Matrix
+ public static Matrix mM;
+ private static FontMetrics mFm;
+ private static RenderingHints mRh;
+ private static Color mBc;
+
+ private Area mCurrClip;
+
+ public final static double RAD_360 = Math.PI / 180 * 360;
+
+ // Image drawing
+ private AndroidJavaBlitter blitter;
+ private DirectColorModel cm;
+ private SinglePixelPackedSampleModel sm;
+ private WritableRaster wr;
+
+
+ public static AndroidGraphics2D getInstance() {
+ if (mAg == null) {
+ throw new RuntimeException("AndroidGraphics2D not instantiated!");
+ }
+ return mAg;
+ }
+
+ public static AndroidGraphics2D getInstance(Context ctx, Canvas c, Paint p) {
+ if (c == null || ctx == null) {
+ throw new RuntimeException(
+ "Illegal argument, Canvas cannot be null!");
+ }
+ mAg = new AndroidGraphics2D(ctx, c, p);
+ return mAg;
+ }
+
+ private AndroidGraphics2D(Context ctx, Canvas c, Paint p) {
+ super();
+ mC = c;
+ mP = p;
+ mM = new Matrix();
+ mM.reset();
+ mM = mC.getMatrix();
+ Rect r = mC.getClipBounds();
+ int cl[] = {-1, r.top, r.left, -2, r.top, r.right, -2, r.bottom, r.right, -2, r.bottom, r.left};
+ mCurrClip = new Area(createShape(cl));
+ if(ctx != null) {
+ WindowManager wm = (WindowManager)ctx.getSystemService(Context.WINDOW_SERVICE);
+ Display d = wm.getDefaultDisplay();
+ displayWidth = d.getWidth();
+ displayHeight = d.getHeight();
+ }
+ blitter = new AndroidJavaBlitter(c);
+ cm = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000);
+ sm = new SinglePixelPackedSampleModel(
+ DataBuffer.TYPE_INT, displayWidth, displayHeight, cm.getMasks());
+ wr = Raster.createWritableRaster(sm, null);
+ dstSurf = new ImageSurface(cm, wr);
+ }
+
+ @Override
+ public void addRenderingHints(Map<?, ?> hints) {
+ if (mRh == null) {
+ mRh = (RenderingHints) hints;
+ }
+ mRh.add((RenderingHints) hints);
+ }
+
+ public float[] getMatrix() {
+ float[] f = new float[9];
+ mC.getMatrix().getValues(f);
+ return f;
+ }
+
+ /**
+ *
+ * @return a Matrix in Android format
+ */
+ public float[] getInverseMatrix() {
+ AffineTransform af = new AffineTransform(createAWTMatrix(getMatrix()));
+ try {
+ af = af.createInverse();
+ } catch (NoninvertibleTransformException e) {
+ }
+ return createMatrix(af);
+ }
+
+ private Path getPath(Shape s) {
+ Path path = new Path();
+ PathIterator pi = s.getPathIterator(null);
+ while (pi.isDone() == false) {
+ getCurrentSegment(pi, path);
+ pi.next();
+ }
+ return path;
+ }
+
+ private void getCurrentSegment(PathIterator pi, Path path) {
+ float[] coordinates = new float[6];
+ int type = pi.currentSegment(coordinates);
+ switch (type) {
+ case PathIterator.SEG_MOVETO:
+ path.moveTo(coordinates[0], coordinates[1]);
+ break;
+ case PathIterator.SEG_LINETO:
+ path.lineTo(coordinates[0], coordinates[1]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ path.quadTo(coordinates[0], coordinates[1], coordinates[2],
+ coordinates[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ path.cubicTo(coordinates[0], coordinates[1], coordinates[2],
+ coordinates[3], coordinates[4], coordinates[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ path.close();
+ break;
+ default:
+ break;
+ }
+ }
+
+ private Shape createShape(int[] arr) {
+ Shape s = new GeneralPath();
+ for(int i = 0; i < arr.length; i++) {
+ int type = arr[i];
+ switch (type) {
+ case -1:
+ //MOVETO
+ ((GeneralPath)s).moveTo(arr[++i], arr[++i]);
+ break;
+ case -2:
+ //LINETO
+ ((GeneralPath)s).lineTo(arr[++i], arr[++i]);
+ break;
+ case -3:
+ //QUADTO
+ ((GeneralPath)s).quadTo(arr[++i], arr[++i], arr[++i],
+ arr[++i]);
+ break;
+ case -4:
+ //CUBICTO
+ ((GeneralPath)s).curveTo(arr[++i], arr[++i], arr[++i],
+ arr[++i], arr[++i], arr[++i]);
+ break;
+ case -5:
+ //CLOSE
+ return s;
+ default:
+ break;
+ }
+ }
+ return s;
+ }
+ /*
+ public int[] getPixels() {
+ return mC.getPixels();
+ }*/
+
+ public static float getRadian(float degree) {
+ return (float) ((Math.PI / 180) * degree);
+ }
+
+ private Shape getShape() {
+ return null;
+ }
+
+ public static float getDegree(float radian) {
+ return (float) ((180 / Math.PI) * radian);
+ }
+
+ /*
+ * Degree in radian
+ */
+ public static float getEllipsisX(float degree, float princAxis) {
+ return (float) Math.cos(degree) * princAxis;
+ }
+
+ public static float getEllipsisY(float degree, float conAxis) {
+ return (float) Math.sin(degree) * conAxis;
+ }
+
+ @Override
+ public void clip(Shape s) {
+ mC.clipPath(getPath(s));
+ }
+
+ public void setCanvas(Canvas c) {
+ mC = c;
+ }
+
+ @Override
+ public void draw(Shape s) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.STROKE);
+ mC.drawPath(getPath(s), mP);
+ mP.setStyle(tmp);
+ }
+/*
+ private ArrayList getSegments(Shape s) {
+ ArrayList arr = new ArrayList();
+ PathIterator pi = s.getPathIterator(null);
+ while (pi.isDone() == false) {
+ getCurrentSegment(pi, arr);
+ pi.next();
+ }
+ return arr;
+ }
+
+ private void getCurrentSegment(PathIterator pi, ArrayList arr) {
+ float[] coordinates = new float[6];
+ int type = pi.currentSegment(coordinates);
+ switch (type) {
+ case PathIterator.SEG_MOVETO:
+ arr.add(new Integer(-1));
+ break;
+ case PathIterator.SEG_LINETO:
+ arr.add(new Integer(-2));
+ break;
+ case PathIterator.SEG_QUADTO:
+ arr.add(new Integer(-3));
+ break;
+ case PathIterator.SEG_CUBICTO:
+ arr.add(new Integer(-4));
+ break;
+ case PathIterator.SEG_CLOSE:
+ arr.add(new Integer(-5));
+ break;
+ default:
+ break;
+ }
+ }
+*/
+ /*
+ * Convenience method, not standard AWT
+ */
+ public void draw(Path s) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.STROKE);
+ s.transform(mM);
+ mC.drawPath(s, mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void drawGlyphVector(GlyphVector g, float x, float y) {
+ // TODO draw at x, y
+ // draw(g.getOutline());
+ /*
+ Matrix matrix = new Matrix();
+ matrix.setTranslate(x, y);
+ Path pth = getPath(g.getOutline());
+ pth.transform(matrix);
+ draw(pth);
+ */
+ Path path = new Path();
+ char[] c = ((AndroidGlyphVector)g).getGlyphs();
+ mP.getTextPath(c, 0, c.length, x, y, path);
+ mC.drawPath(path, mP);
+ }
+
+ @Override
+ public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, float x,
+ float y) {
+ throw new RuntimeException("AttributedCharacterIterator not supported!");
+
+ }
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+ throw new RuntimeException("AttributedCharacterIterator not supported!");
+
+ }
+
+ @Override
+ public void drawString(String s, float x, float y) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+
+ mP.setStyle(Paint.Style.FILL);
+ Path pth = new Path();
+ mP.getTextPath(s, 0, s.length(), x, y, pth);
+ mC.drawPath(pth, mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void drawString(String str, int x, int y) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStrokeWidth(0);
+
+ mC.drawText(str.toCharArray(), 0, str.toCharArray().length, x, y,
+ mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void fill(Shape s) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.FILL);
+ mC.drawPath(getPath(s), mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public Color getBackground() {
+ return mBc;
+ }
+
+ @Override
+ public Composite getComposite() {
+ throw new RuntimeException("Composite not implemented!");
+ }
+
+ @Override
+ public GraphicsConfiguration getDeviceConfiguration() {
+ return new AndroidGraphicsConfiguration();
+ }
+
+ @Override
+ public FontRenderContext getFontRenderContext() {
+ return new FontRenderContext(getTransform(), mP.isAntiAlias(), true);
+ }
+
+ @Override
+ public java.awt.Paint getPaint() {
+ throw new RuntimeException("AWT Paint not implemented in Android!");
+ }
+
+ public static Canvas getAndroidCanvas() {
+ return mC;
+ }
+
+ public static Paint getAndroidPaint() {
+ return mP;
+ }
+
+ @Override
+ public RenderingHints getRenderingHints() {
+ return mRh;
+ }
+
+ @Override
+ public Stroke getStroke() {
+ if (mP != null) {
+ return new BasicStroke(mP.getStrokeWidth(), mP.getStrokeCap()
+ .ordinal(), mP.getStrokeJoin().ordinal());
+ }
+ return null;
+ }
+
+ @Override
+ public AffineTransform getTransform() {
+ return new AffineTransform(createAWTMatrix(getMatrix()));
+ }
+
+ @Override
+ public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+ // ???AWT TODO check if on stroke
+ return s.intersects(rect.getX(), rect.getY(), rect.getWidth(), rect
+ .getHeight());
+ }
+
+ @Override
+ public void rotate(double theta) {
+ mM.preRotate((float) AndroidGraphics2D
+ .getDegree((float) (RAD_360 - theta)));
+ mC.concat(mM);
+ }
+
+ @Override
+ public void rotate(double theta, double x, double y) {
+ mM.preRotate((float) AndroidGraphics2D.getDegree((float) theta),
+ (float) x, (float) y);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void scale(double sx, double sy) {
+ mM.setScale((float) sx, (float) sy);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void setBackground(Color color) {
+ mBc = color;
+ mC.clipRect(new Rect(0, 0, mC.getWidth(), mC.getHeight()));
+ // TODO don't limit to current clip
+ mC.drawARGB(color.getAlpha(), color.getRed(), color.getGreen(), color
+ .getBlue());
+ }
+
+ @Override
+ public void setComposite(Composite comp) {
+ throw new RuntimeException("Composite not implemented!");
+ }
+
+ public void setSpaint(Paint paint) {
+ mP = paint;
+ }
+
+ @Override
+ public void setPaint(java.awt.Paint paint) {
+ setColor((Color)paint);
+ }
+
+ @Override
+ public Object getRenderingHint(RenderingHints.Key key) {
+ if (mRh == null) {
+ return null;
+ }
+ return mRh.get(key);
+ }
+
+ @Override
+ public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) {
+ if (mRh == null) {
+ mRh = new RenderingHints(hintKey, hintValue);
+ } else {
+ mRh.put(hintKey, hintValue);
+ }
+ applyHints();
+ }
+
+ @Override
+ public void setRenderingHints(Map<?, ?> hints) {
+ mRh = (RenderingHints) hints;
+ applyHints();
+ }
+
+ private void applyHints() {
+ Object o;
+
+ // TODO do something like this:
+ /*
+ * Set s = mRh.keySet(); Iterator it = s.iterator(); while(it.hasNext()) {
+ * o = it.next(); }
+ */
+
+ // /////////////////////////////////////////////////////////////////////
+ // not supported in skia
+ /*
+ * o = mRh.get(RenderingHints.KEY_ALPHA_INTERPOLATION); if
+ * (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) { } else
+ * if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) { }
+ * else if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_COLOR_RENDERING); if
+ * (o.equals(RenderingHints.VALUE_COLOR_RENDER_DEFAULT)) { } else if
+ * (o.equals(RenderingHints.VALUE_COLOR_RENDER_QUALITY)) { } else if
+ * (o.equals(RenderingHints.VALUE_COLOR_RENDER_SPEED)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_DITHERING); if
+ * (o.equals(RenderingHints.VALUE_DITHER_DEFAULT)) { } else if
+ * (o.equals(RenderingHints.VALUE_DITHER_DISABLE)) { } else if
+ * (o.equals(RenderingHints.VALUE_DITHER_ENABLE)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_FRACTIONALMETRICS); if
+ * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT)) { } else
+ * if (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_OFF)) { } else if
+ * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_ON)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_INTERPOLATION); if
+ * (o.equals(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) { } else if
+ * (o.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) { } else if
+ * (o .equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_RENDERING); if
+ * (o.equals(RenderingHints.VALUE_RENDER_DEFAULT)) { } else if
+ * (o.equals(RenderingHints.VALUE_RENDER_QUALITY)) { } else if
+ * (o.equals(RenderingHints.VALUE_RENDER_SPEED)) { }
+ *
+ * o = mRh.get(RenderingHints.KEY_STROKE_CONTROL); if
+ * (o.equals(RenderingHints.VALUE_STROKE_DEFAULT)) { } else if
+ * (o.equals(RenderingHints.VALUE_STROKE_NORMALIZE)) { } else if
+ * (o.equals(RenderingHints.VALUE_STROKE_PURE)) { }
+ */
+
+ o = mRh.get(RenderingHints.KEY_ANTIALIASING);
+ if (o != null) {
+ if (o.equals(RenderingHints.VALUE_ANTIALIAS_DEFAULT)) {
+ mP.setAntiAlias(false);
+ } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_OFF)) {
+ mP.setAntiAlias(false);
+ } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_ON)) {
+ mP.setAntiAlias(true);
+ }
+ }
+
+ o = mRh.get(RenderingHints.KEY_TEXT_ANTIALIASING);
+ if (o != null) {
+ if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT)) {
+ mP.setAntiAlias(false);
+ } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)) {
+ mP.setAntiAlias(false);
+ } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_ON)) {
+ mP.setAntiAlias(true);
+ }
+ }
+ }
+
+ @Override
+ public void setStroke(Stroke s) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ BasicStroke bs = (BasicStroke) s;
+ mP.setStyle(Paint.Style.STROKE);
+ mP.setStrokeWidth(bs.getLineWidth());
+
+ int cap = bs.getEndCap();
+ if (cap == 0) {
+ mP.setStrokeCap(Paint.Cap.BUTT);
+ } else if (cap == 1) {
+ mP.setStrokeCap(Paint.Cap.ROUND);
+ } else if (cap == 2) {
+ mP.setStrokeCap(Paint.Cap.SQUARE);
+ }
+
+ int join = bs.getLineJoin();
+ if (join == 0) {
+ mP.setStrokeJoin(Paint.Join.MITER);
+ } else if (join == 1) {
+ mP.setStrokeJoin(Paint.Join.ROUND);
+ } else if (join == 2) {
+ mP.setStrokeJoin(Paint.Join.BEVEL);
+ }
+ }
+
+ public static float[] createMatrix(AffineTransform Tx) {
+ double[] at = new double[9];
+ Tx.getMatrix(at);
+ float[] f = new float[at.length];
+ f[0] = (float) at[0];
+ f[1] = (float) at[2];
+ f[2] = (float) at[4];
+ f[3] = (float) at[1];
+ f[4] = (float) at[3];
+ f[5] = (float) at[5];
+ f[6] = 0;
+ f[7] = 0;
+ f[8] = 1;
+ return f;
+ }
+
+ private float[] createAWTMatrix(float[] matrix) {
+ float[] at = new float[9];
+ at[0] = matrix[0];
+ at[1] = matrix[3];
+ at[2] = matrix[1];
+ at[3] = matrix[4];
+ at[4] = matrix[2];
+ at[5] = matrix[5];
+ at[6] = 0;
+ at[7] = 0;
+ at[8] = 1;
+ return at;
+ }
+
+ public static Matrix createMatrixObj(AffineTransform Tx) {
+ Matrix m = new Matrix();
+ m.reset();
+ m.setValues(createMatrix(Tx));
+ return m;
+ }
+
+ @Override
+ public void setTransform(AffineTransform Tx) {
+ mM.reset();
+ /*
+ * if(Tx.isIdentity()) { mM = new Matrix(); }
+ */
+ mM.setValues(createMatrix(Tx));
+ Matrix m = new Matrix();
+ m.setValues(getInverseMatrix());
+ mC.concat(m);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void shear(double shx, double shy) {
+ mM.setSkew((float) shx, (float) shy);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void transform(AffineTransform Tx) {
+ Matrix m = new Matrix();
+ m.setValues(createMatrix(Tx));
+ mC.concat(m);
+ }
+
+ @Override
+ public void translate(double tx, double ty) {
+ mM.setTranslate((float) tx, (float) ty);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void translate(int x, int y) {
+ mM.setTranslate((float) x, (float) y);
+ mC.concat(mM);
+ }
+
+ @Override
+ public void clearRect(int x, int y, int width, int height) {
+ mC.clipRect(x, y, x + width, y + height);
+ if (mBc != null) {
+ mC.drawARGB(mBc.getAlpha(), mBc.getBlue(), mBc.getGreen(), mBc
+ .getRed());
+ } else {
+ mC.drawARGB(0xff, 0xff, 0xff, 0xff);
+ }
+ }
+
+ @Override
+ public void clipRect(int x, int y, int width, int height) {
+ int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y};
+ Shape shp = createShape(cl);
+ mCurrClip.intersect(new Area(shp));
+ mC.clipRect(new Rect(x, y, x + width, y + height), Region.Op.INTERSECT);
+ }
+
+ @Override
+ public void copyArea(int sx, int sy, int width, int height, int dx, int dy) {
+ copyArea(mC, sx, sy, width + dx, height + dy, dx, dy);
+ }
+
+ @Override
+ public Graphics create() {
+ return this;
+ }
+
+ @Override
+ public void dispose() {
+ mC = null;
+ mP = null;
+ }
+
+ @Override
+ public void drawArc(int x, int y, int width, int height, int sa, int ea) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setStrokeWidth(0);
+ mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (ea + sa),
+ ea, true, mP);
+ }
+
+
+ // ???AWT: only used for debuging, delete in final version
+ public void drawBitmap(Bitmap bm, float x, float y, Paint p) {
+ mC.drawBitmap(bm, x, y, null);
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, Color bgcolor,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) {
+ return drawImage(image, x, y, null, imageObserver);
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, int width, int height,
+ Color bgcolor, ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(width == 0 || height == 0) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ if(w == width && h == height){
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }else{
+ AffineTransform xform = new AffineTransform();
+ xform.setToScale((float)width / w, (float)height / h);
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ xform, composite, bgcolor, clip);
+ }
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, int width, int height,
+ ImageObserver imageObserver) {
+ return drawImage(image, x, y, width, height, null, imageObserver);
+ }
+
+ @Override
+ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2, Color bgcolor,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+
+ int dstX = dx1;
+ int dstY = dy1;
+ int srcX = sx1;
+ int srcY = sy1;
+
+ int dstW = dx2 - dx1;
+ int dstH = dy2 - dy1;
+ int srcW = sx2 - sx1;
+ int srcH = sy2 - sy1;
+
+ if(srcW == dstW && srcH == dstH){
+ blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+ (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }else{
+ AffineTransform xform = new AffineTransform();
+ xform.setToScale((float)dstW / srcW, (float)dstH / srcH);
+ blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+ (AffineTransform) transform.clone(),
+ xform, composite, bgcolor, clip);
+ }
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) {
+
+ return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
+ imageObserver);
+ }
+
+ @Override
+ public void drawImage(BufferedImage bufImage, BufferedImageOp op,
+ int x, int y) {
+
+ if(bufImage == null) {
+ return;
+ }
+
+ if(op == null) {
+ drawImage(bufImage, x, y, null);
+ } else if(op instanceof AffineTransformOp){
+ AffineTransformOp atop = (AffineTransformOp) op;
+ AffineTransform xform = atop.getTransform();
+ Surface srcSurf = Surface.getImageSurface(bufImage);
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(), xform,
+ composite, null, clip);
+ } else {
+ bufImage = op.filter(bufImage, null);
+ Surface srcSurf = Surface.getImageSurface(bufImage);
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ composite, null, clip);
+ }
+ }
+
+ @Override
+ public boolean drawImage(Image image, AffineTransform trans,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(trans == null || trans.isIdentity()) {
+ return drawImage(image, 0, 0, imageObserver);
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ AffineTransform xform = (AffineTransform) transform.clone();
+ xform.concatenate(trans);
+ blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite,
+ null, clip);
+ }
+ return done;
+ }
+
+ @Override
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mC.drawLine(x1, y1, x2, y2, mP);
+ }
+
+ @Override
+ public void drawOval(int x, int y, int width, int height) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setStyle(Paint.Style.STROKE);
+ mC.drawOval(new RectF(x, y, x + width, y + height), mP);
+ }
+
+ @Override
+ public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mC.drawLine(xpoints[npoints - 1], ypoints[npoints - 1], xpoints[0],
+ ypoints[0], mP);
+ for (int i = 0; i < npoints - 1; i++) {
+ mC.drawLine(xpoints[i], ypoints[i], xpoints[i + 1],
+ ypoints[i + 1], mP);
+ }
+ }
+
+ @Override
+ public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) {
+ for (int i = 0; i < npoints - 1; i++) {
+ drawLine(xpoints[i], ypoints[i], xpoints[i + 1], ypoints[i + 1]);
+ }
+
+ }
+
+ @Override
+ public void drawRoundRect(int x, int y, int width, int height,
+ int arcWidth, int arcHeight) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mC.drawRoundRect(new RectF(x, y, width, height), arcWidth,
+ arcHeight, mP);
+ }
+
+ @Override
+ public void fillArc(int x, int y, int width, int height, int sa, int ea) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.FILL_AND_STROKE);
+ mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (sa + ea),
+ ea, true, mP);
+
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void fillOval(int x, int y, int width, int height) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.FILL);
+ mC.drawOval(new RectF(x, y, x + width, y + height), mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mC.save(Canvas.CLIP_SAVE_FLAG);
+
+ mP.setStyle(Paint.Style.FILL);
+
+ GeneralPath filledPolygon = new GeneralPath(
+ GeneralPath.WIND_EVEN_ODD, npoints);
+ filledPolygon.moveTo(xpoints[0], ypoints[0]);
+ for (int index = 1; index < xpoints.length; index++) {
+ filledPolygon.lineTo(xpoints[index], ypoints[index]);
+ }
+ filledPolygon.closePath();
+ Path path = getPath(filledPolygon);
+ mC.clipPath(path);
+ mC.drawPath(path, mP);
+
+ mP.setStyle(tmp);
+ mC.restore();
+ }
+
+ @Override
+ public void fillRect(int x, int y, int width, int height) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ Paint.Style tmp = mP.getStyle();
+ mP.setStyle(Paint.Style.FILL);
+ mC.drawRect(new Rect(x, y, x + width, y + height), mP);
+ mP.setStyle(tmp);
+ }
+
+ @Override
+ public void drawRect(int x, int y, int width, int height) {
+ int[] xpoints = { x, x, x + width, x + width };
+ int[] ypoints = { y, y + height, y + height, y };
+ drawPolygon(xpoints, ypoints, 4);
+ }
+
+ @Override
+ public void fillRoundRect(int x, int y, int width, int height,
+ int arcWidth, int arcHeight) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setStyle(Paint.Style.FILL);
+ mC.drawRoundRect(new RectF(x, y, x + width, y + height), arcWidth,
+ arcHeight, mP);
+ }
+
+ @Override
+ public Shape getClip() {
+ return mCurrClip;
+ }
+
+ @Override
+ public Rectangle getClipBounds() {
+ Rect r = mC.getClipBounds();
+ return new Rectangle(r.left, r.top, r.width(), r.height());
+ }
+
+ @Override
+ public Color getColor() {
+ if (mP != null) {
+ return new Color(mP.getColor());
+ }
+ return null;
+ }
+
+ @Override
+ public Font getFont() {
+ return mFnt;
+ }
+
+ @Override
+ public FontMetrics getFontMetrics(Font font) {
+ mFm = new FontMetricsImpl(font);
+ return mFm;
+ }
+
+ @Override
+ public void setClip(int x, int y, int width, int height) {
+ int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y};
+ mCurrClip = new Area(createShape(cl));
+ mC.clipRect(x, y, x + width, y + height, Region.Op.REPLACE);
+
+ }
+
+ @Override
+ public void setClip(Shape clip) {
+ mCurrClip = new Area(clip);
+ mC.clipPath(getPath(clip), Region.Op.REPLACE);
+ }
+
+ @Override
+ public void setColor(Color c) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setColor(c.getRGB());
+ }
+
+ /**
+ * Font mapping:
+ *
+ * Family:
+ *
+ * Android AWT
+ * -------------------------------------
+ * serif Serif / TimesRoman
+ * sans-serif SansSerif / Helvetica
+ * monospace Monospaced / Courier
+ *
+ * Style:
+ *
+ * Android AWT
+ * -------------------------------------
+ * normal Plain
+ * bold bold
+ * italic italic
+ *
+ */
+ @Override
+ public void setFont(Font font) {
+ if (font == null) {
+ return;
+ }
+ if (mP == null) {
+ mP = new Paint();
+ }
+
+ mFnt = font;
+ Typeface tf = null;
+ int sty = font.getStyle();
+ String nam = font.getName();
+ String aF = "";
+ if (nam != null) {
+ if (nam.equalsIgnoreCase("Serif")
+ || nam.equalsIgnoreCase("TimesRoman")) {
+ aF = "serif";
+ } else if (nam.equalsIgnoreCase("SansSerif")
+ || nam.equalsIgnoreCase("Helvetica")) {
+ aF = "sans-serif";
+ } else if (nam.equalsIgnoreCase("Monospaced")
+ || nam.equalsIgnoreCase("Courier")) {
+ aF = "monospace";
+ }
+ }
+
+ switch (sty) {
+ case Font.PLAIN:
+ tf = Typeface.create(aF, Typeface.NORMAL);
+ break;
+ case Font.BOLD:
+ tf = Typeface.create(aF, Typeface.BOLD);
+ break;
+ case Font.ITALIC:
+ tf = Typeface.create(aF, Typeface.ITALIC);
+ break;
+ case Font.BOLD | Font.ITALIC:
+ tf = Typeface.create(aF, Typeface.BOLD_ITALIC);
+ break;
+ default:
+ tf = Typeface.DEFAULT;
+ }
+
+ mP.setTextSize(font.getSize());
+ mP.setTypeface(tf);
+ }
+
+ @Override
+ public void drawBytes(byte[] data, int offset, int length, int x, int y) {
+ drawString(new String(data, offset, length), x, y);
+ }
+
+ @Override
+ public void drawPolygon(Polygon p) {
+ drawPolygon(p.xpoints, p.ypoints, p.npoints);
+ }
+
+ @Override
+ public void fillPolygon(Polygon p) {
+ fillPolygon(p.xpoints, p.ypoints, p.npoints);
+ }
+
+ @Override
+ public Rectangle getClipBounds(Rectangle r) {
+ Shape clip = getClip();
+ if (clip != null) {
+ Rectangle b = clip.getBounds();
+ r.x = b.x;
+ r.y = b.y;
+ r.width = b.width;
+ r.height = b.height;
+ }
+ return r;
+ }
+
+ @Override
+ public boolean hitClip(int x, int y, int width, int height) {
+ return getClipBounds().intersects(new Rectangle(x, y, width, height));
+ }
+
+ @Override
+ public void drawChars(char[] data, int offset, int length, int x, int y) {
+ mC.drawText(data, offset, length, x, y, mP);
+ }
+
+ @Override
+ public void setPaintMode() {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setXfermode(null);
+ }
+
+ @Override
+ public void setXORMode(Color color) {
+ if (mP == null) {
+ mP = new Paint();
+ }
+ mP.setXfermode(new PixelXorXfermode(color.getRGB()));
+ }
+
+ @Override
+ public void fill3DRect(int x, int y, int width, int height, boolean raised) {
+ Color color = getColor();
+ Color colorUp, colorDown;
+ if (raised) {
+ colorUp = color.brighter();
+ colorDown = color.darker();
+ setColor(color);
+ } else {
+ colorUp = color.darker();
+ colorDown = color.brighter();
+ setColor(colorUp);
+ }
+
+ width--;
+ height--;
+ fillRect(x+1, y+1, width-1, height-1);
+
+ setColor(colorUp);
+ fillRect(x, y, width, 1);
+ fillRect(x, y+1, 1, height);
+
+ setColor(colorDown);
+ fillRect(x+width, y, 1, height);
+ fillRect(x+1, y+height, width, 1);
+ }
+
+ @Override
+ public void draw3DRect(int x, int y, int width, int height, boolean raised) {
+ Color color = getColor();
+ Color colorUp, colorDown;
+ if (raised) {
+ colorUp = color.brighter();
+ colorDown = color.darker();
+ } else {
+ colorUp = color.darker();
+ colorDown = color.brighter();
+ }
+
+ setColor(colorUp);
+ fillRect(x, y, width, 1);
+ fillRect(x, y+1, 1, height);
+
+ setColor(colorDown);
+ fillRect(x+width, y, 1, height);
+ fillRect(x+1, y+height, width, 1);
+ }
+
+ public void copyArea(Canvas canvas, int sx, int sy, int width, int height, int dx, int dy) {
+ sx += getTransform().getTranslateX();
+ sy += getTransform().getTranslateY();
+
+ NativeUtils.nativeScrollRect(canvas,
+ new Rect(sx, sy, sx + width, sy + height),
+ dx, dy);
+ }
+}
diff --git a/awt/com/android/internal/awt/AndroidGraphicsConfiguration.java b/awt/com/android/internal/awt/AndroidGraphicsConfiguration.java
new file mode 100644
index 0000000..0c888cd
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidGraphicsConfiguration.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.VolatileImage;
+
+import android.graphics.Canvas;
+
+public class AndroidGraphicsConfiguration extends GraphicsConfiguration {
+
+ @Override
+ public BufferedImage createCompatibleImage(int width, int height) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BufferedImage createCompatibleImage(int width, int height,
+ int transparency) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public VolatileImage createCompatibleVolatileImage(int width, int height) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public VolatileImage createCompatibleVolatileImage(int width, int height,
+ int transparency) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Rectangle getBounds() {
+ Canvas c = AndroidGraphics2D.getAndroidCanvas();
+ if(c != null)
+ return new Rectangle(0, 0, c.getWidth(), c.getHeight());
+ return null;
+ }
+
+ @Override
+ public ColorModel getColorModel() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ColorModel getColorModel(int transparency) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public AffineTransform getDefaultTransform() {
+ return new AffineTransform();
+ }
+
+ @Override
+ public GraphicsDevice getDevice() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public AffineTransform getNormalizingTransform() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidGraphicsFactory.java b/awt/com/android/internal/awt/AndroidGraphicsFactory.java
new file mode 100644
index 0000000..ca255b5
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidGraphicsFactory.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.peer.FontPeer;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.font.AndroidFont;
+import org.apache.harmony.awt.gl.font.FontManager;
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.gl.font.AndroidFontManager;
+import org.apache.harmony.awt.wtk.NativeWindow;
+import org.apache.harmony.awt.wtk.WindowFactory;
+import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.content.Context;
+
+public class AndroidGraphicsFactory extends CommonGraphics2DFactory {
+
+ public GraphicsEnvironment createGraphicsEnvironment(WindowFactory wf) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Font embedFont(String fontFilePath) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public FontManager getFontManager() {
+ return AndroidFontManager.inst;
+ }
+
+ public FontMetrics getFontMetrics(Font font) {
+ return new FontMetricsImpl(font);
+ }
+
+ public FontPeer getFontPeer(Font font) {
+ //return getFontManager().getFontPeer(font.getName(), font.getStyle(), font.getSize());
+ return new AndroidFont(font.getName(), font.getStyle(), font.getSize());
+ }
+
+ public Graphics2D getGraphics2D(NativeWindow win, int translateX,
+ int translateY, MultiRectArea clip) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Graphics2D getGraphics2D(NativeWindow win, int translateX,
+ int translateY, int width, int height) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Graphics2D getGraphics2D(Context ctx, Canvas c, Paint p) {
+ return AndroidGraphics2D.getInstance(ctx, c, p);
+ }
+
+ public Graphics2D getGraphics2D(Canvas c, Paint p) {
+ throw new RuntimeException("Not supported!");
+ }
+
+ public Graphics2D getGraphics2D() {
+ return AndroidGraphics2D.getInstance();
+ }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidImageDecoder.java b/awt/com/android/internal/awt/AndroidImageDecoder.java
new file mode 100644
index 0000000..81b2e1a
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidImageDecoder.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.awt;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+//import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.IndexColorModel;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+import org.apache.harmony.awt.gl.image.ImageDecoder;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class AndroidImageDecoder extends ImageDecoder {
+
+ private static final int hintflags =
+ ImageConsumer.SINGLEFRAME | // PNG is a static image
+ ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible
+ ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines
+
+ // Each pixel is a grayscale sample.
+ private static final int PNG_COLOR_TYPE_GRAY = 0;
+ // Each pixel is an R,G,B triple.
+ private static final int PNG_COLOR_TYPE_RGB = 2;
+ // Each pixel is a palette index, a PLTE chunk must appear.
+ private static final int PNG_COLOR_TYPE_PLTE = 3;
+ // Each pixel is a grayscale sample, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4;
+ // Each pixel is an R,G,B triple, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_RGBA = 6;
+
+ private static final int NB_OF_LINES_PER_CHUNK = 1; // 0 = full image
+
+ Bitmap bm; // The image as decoded by Android
+
+ // Header information
+ int imageWidth; // Image size
+ int imageHeight;
+ int colorType; // One of the PNG_ constants from above
+ int bitDepth; // Number of bits per color
+ byte cmap[]; // The color palette for index color models
+ ColorModel model; // The corresponding AWT color model
+
+ boolean transferInts; // Is transfer of type int or byte?
+ int dataElementsPerPixel;
+
+ // Buffers for decoded image data
+ byte byteOut[];
+ int intOut[];
+
+
+ public AndroidImageDecoder(DecodingImageSource src, InputStream is) {
+ super(src, is);
+ dataElementsPerPixel = 1;
+ }
+
+ @Override
+ /**
+ * All the decoding is done in Android
+ *
+ * AWT???: Method returns only once the image is completly
+ * decoded; decoding is not done asynchronously
+ */
+ public void decodeImage() throws IOException {
+ try {
+ bm = BitmapFactory.decodeStream(inputStream);
+ if (bm == null) {
+ throw new IOException("Input stream empty and no image cached");
+ }
+
+ // Check size
+ imageWidth = bm.getWidth();
+ imageHeight = bm.getHeight();
+ if (imageWidth < 0 || imageHeight < 0 ) {
+ throw new RuntimeException("Illegal image size: "
+ + imageWidth + ", " + imageHeight);
+ }
+
+ // We got the image fully decoded; now send all image data to AWT
+ setDimensions(imageWidth, imageHeight);
+ model = createColorModel();
+ setColorModel(model);
+ setHints(hintflags);
+ setProperties(new Hashtable<Object, Object>()); // Empty
+ sendPixels(NB_OF_LINES_PER_CHUNK != 0 ? NB_OF_LINES_PER_CHUNK : imageHeight);
+ imageComplete(ImageConsumer.STATICIMAGEDONE);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ imageComplete(ImageConsumer.IMAGEERROR);
+ throw e;
+ } finally {
+ closeStream();
+ }
+ }
+
+ /**
+ * Create the AWT color model
+ *
+ * ???AWT: Android Bitmaps are always of type: ARGB-8888-Direct color model
+ *
+ * However, we leave the code here for a more powerfull decoder
+ * that returns a native model, and the conversion is then handled
+ * in AWT. With such a decoder, we would need to get the colorType,
+ * the bitDepth, (and the color palette for an index color model)
+ * from the image and construct the correct color model here.
+ */
+ private ColorModel createColorModel() {
+ ColorModel cm = null;
+ int bmModel = 5; // TODO This doesn't exist: bm.getColorModel();
+ cmap = null;
+
+ switch (bmModel) {
+ // A1_MODEL
+ case 1:
+ colorType = PNG_COLOR_TYPE_GRAY;
+ bitDepth = 1;
+ break;
+
+ // A8_MODEL
+ case 2:
+ colorType = PNG_COLOR_TYPE_GRAY_ALPHA;
+ bitDepth = 8;
+ break;
+
+ // INDEX8_MODEL
+ // RGB_565_MODEL
+ // ARGB_8888_MODEL
+ case 3:
+ case 4:
+ case 5:
+ colorType = bm.hasAlpha() ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB;
+ bitDepth = 8;
+ break;
+
+ default:
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ switch (colorType) {
+
+ case PNG_COLOR_TYPE_GRAY: {
+ if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ // Create gray color model
+ int numEntries = 1 << bitDepth;
+ int scaleFactor = 255 / (numEntries-1);
+ byte comps[] = new byte[numEntries];
+ for (int i = 0; i < numEntries; i++) {
+ comps[i] = (byte) (i * scaleFactor);
+ }
+ cm = new IndexColorModel(bitDepth, numEntries, comps, comps, comps);
+
+ transferInts = false;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_RGB: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = new DirectColorModel(24, 0xff0000, 0xFF00, 0xFF);
+
+ transferInts = true;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_PLTE: {
+ if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ if (cmap == null) {
+ throw new IllegalStateException("Palette color type is not supported");
+ }
+
+ cm = new IndexColorModel(bitDepth, cmap.length / 3, cmap, 0, false);
+
+ transferInts = false;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_GRAY_ALPHA: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ true, false,
+ Transparency.TRANSLUCENT,
+ DataBuffer.TYPE_BYTE);
+
+ transferInts = false;
+ dataElementsPerPixel = 2;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_RGBA: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = ColorModel.getRGBdefault();
+
+ transferInts = true;
+ break;
+ }
+ default:
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ return cm;
+ }
+
+ private void sendPixels(int nbOfLinesPerChunk) {
+ int w = imageWidth;
+ int h = imageHeight;
+ int n = 1;
+ if (nbOfLinesPerChunk > 0 && nbOfLinesPerChunk <= h) {
+ n = nbOfLinesPerChunk;
+ }
+
+ if (transferInts) {
+ // Create output buffer
+ intOut = new int[w * n];
+ for (int yi = 0; yi < h; yi += n) {
+ // Last chunk might contain less liness
+ if (n > 1 && h - yi < n ) {
+ n = h - yi;
+ }
+ bm.getPixels(intOut, 0, w, 0, yi, w, n);
+ setPixels(0, yi, w, n, model, intOut, 0, w);
+ }
+ } else {
+ // Android bitmaps always store ints (ARGB-8888 direct model)
+ throw new RuntimeException("Byte transfer not supported");
+ }
+ }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidJavaBlitter.java b/awt/com/android/internal/awt/AndroidJavaBlitter.java
new file mode 100644
index 0000000..423b534
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidJavaBlitter.java
@@ -0,0 +1,536 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.XORComposite;
+import org.apache.harmony.awt.gl.render.Blitter;
+
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+public class AndroidJavaBlitter implements Blitter {
+
+ private Canvas canvas;
+ private Paint paint;
+ private int colorCache;
+
+ public AndroidJavaBlitter(Canvas c) {
+ this.canvas = c;
+ this.paint = new Paint();
+ this.paint.setStrokeWidth(1);
+ }
+
+ /**
+ * Instead of multiplication and division we are using values from
+ * Lookup tables.
+ */
+ static byte mulLUT[][]; // Lookup table for multiplication
+ static byte divLUT[][]; // Lookup table for division
+
+ static{
+ mulLUT = new byte[256][256];
+ for(int i = 0; i < 256; i++){
+ for(int j = 0; j < 256; j++){
+ mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f);
+ }
+ }
+ divLUT = new byte[256][256];
+ for(int i = 1; i < 256; i++){
+ for(int j = 0; j < i; j++){
+ divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f);
+ }
+ for(int j = i; j < 256; j++){
+ divLUT[i][j] = (byte)255;
+ }
+ }
+ }
+
+ final static int AlphaCompositeMode = 1;
+ final static int XORMode = 2;
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ AffineTransform xform, Composite comp, Color bgcolor,
+ MultiRectArea clip) {
+
+ if(xform == null){
+ blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }else{
+ double scaleX = xform.getScaleX();
+ double scaleY = xform.getScaleY();
+ double scaledX = dstX / scaleX;
+ double scaledY = dstY / scaleY;
+ AffineTransform at = new AffineTransform();
+ at.setToTranslation(scaledX, scaledY);
+ xform.concatenate(at);
+ sysxform.concatenate(xform);
+ blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }
+
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ Composite comp, Color bgcolor, MultiRectArea clip) {
+
+ if(sysxform == null) {
+ sysxform = new AffineTransform();
+ }
+ int type = sysxform.getType();
+ switch(type){
+ case AffineTransform.TYPE_TRANSLATION:
+ dstX += sysxform.getTranslateX();
+ dstY += sysxform.getTranslateY();
+ case AffineTransform.TYPE_IDENTITY:
+ simpleBlit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
+ width, height, comp, bgcolor, clip);
+ break;
+ default:
+ int srcW = srcSurf.getWidth();
+ int srcH = srcSurf.getHeight();
+
+ int w = srcX + width < srcW ? width : srcW - srcX;
+ int h = srcY + height < srcH ? height : srcH - srcY;
+
+ ColorModel srcCM = srcSurf.getColorModel();
+ Raster srcR = srcSurf.getRaster().createChild(srcX, srcY,
+ w, h, 0, 0, null);
+
+ ColorModel dstCM = dstSurf.getColorModel();
+ WritableRaster dstR = dstSurf.getRaster();
+
+ transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h,
+ sysxform, comp, bgcolor, clip);
+
+ }
+ }
+
+ public void simpleBlit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+
+ // TODO It's possible, though unlikely that we might encounter non-int[]
+ // data buffers. In this case the following code needs to have several
+ // branches that take this into account.
+ data = (DataBufferInt)srcSurf.getRaster().getDataBuffer();
+ int[] pixels = data.getData();
+ if (!srcSurf.getColorModel().hasAlpha()) {
+ // This wouldn't be necessary if Android supported RGB_888.
+ for (int i = 0; i < pixels.length; i++) {
+ pixels[i] = pixels[i] | 0xff000000;
+ }
+ }
+ bmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
+ canvas.drawBitmap(bmap, dstX, dstY, paint);
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+
+ javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(),
+ srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY,
+ dstSurf.getWidth(), dstSurf.getHeight(),
+ dstSurf.getColorModel(), dstSurf.getRaster(),
+ width, height, comp, bgcolor, clip);
+
+ }
+
+ public void javaBlt(int srcX, int srcY, int srcW, int srcH,
+ ColorModel srcCM, Raster srcRast, int dstX, int dstY,
+ int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, Composite comp, Color bgcolor,
+ MultiRectArea clip){
+
+ int srcX2 = srcW - 1;
+ int srcY2 = srcH - 1;
+ int dstX2 = dstW - 1;
+ int dstY2 = dstH - 1;
+
+ if(srcX < 0){
+ width += srcX;
+ srcX = 0;
+ }
+ if(srcY < 0){
+ height += srcY;
+ srcY = 0;
+ }
+
+ if(dstX < 0){
+ width += dstX;
+ srcX -= dstX;
+ dstX = 0;
+ }
+ if(dstY < 0){
+ height += dstY;
+ srcY -= dstY;
+ dstY = 0;
+ }
+
+ if(srcX > srcX2 || srcY > srcY2) {
+ return;
+ }
+ if(dstX > dstX2 || dstY > dstY2) {
+ return;
+ }
+
+ if(srcX + width > srcX2) {
+ width = srcX2 - srcX + 1;
+ }
+ if(srcY + height > srcY2) {
+ height = srcY2 - srcY + 1;
+ }
+ if(dstX + width > dstX2) {
+ width = dstX2 - dstX + 1;
+ }
+ if(dstY + height > dstY2) {
+ height = dstY2 - dstY + 1;
+ }
+
+ if(width <= 0 || height <= 0) {
+ return;
+ }
+
+ int clipRects[];
+ if(clip != null) {
+ clipRects = clip.rect;
+ } else {
+ clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1};
+ }
+
+ boolean isAlphaComp = false;
+ int rule = 0;
+ float alpha = 0;
+ boolean isXORComp = false;
+ Color xorcolor = null;
+ CompositeContext cont = null;
+
+ if(comp instanceof AlphaComposite){
+ isAlphaComp = true;
+ AlphaComposite ac = (AlphaComposite) comp;
+ rule = ac.getRule();
+ alpha = ac.getAlpha();
+ }else if(comp instanceof XORComposite){
+ isXORComp = true;
+ XORComposite xcomp = (XORComposite) comp;
+ xorcolor = xcomp.getXORColor();
+ }else{
+ cont = comp.createContext(srcCM, dstCM, null);
+ }
+
+ for(int i = 1; i < clipRects[0]; i += 4){
+ int _sx = srcX;
+ int _sy = srcY;
+
+ int _dx = dstX;
+ int _dy = dstY;
+
+ int _w = width;
+ int _h = height;
+
+ int cx = clipRects[i]; // Clipping left top X
+ int cy = clipRects[i + 1]; // Clipping left top Y
+ int cx2 = clipRects[i + 2]; // Clipping right bottom X
+ int cy2 = clipRects[i + 3]; // Clipping right bottom Y
+
+ if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) {
+ continue;
+ }
+
+ if(cx > _dx){
+ int shx = cx - _dx;
+ _w -= shx;
+ _dx = cx;
+ _sx += shx;
+ }
+
+ if(cy > _dy){
+ int shy = cy - _dy;
+ _h -= shy;
+ _dy = cy;
+ _sy += shy;
+ }
+
+ if(_dx + _w > cx2 + 1){
+ _w = cx2 - _dx + 1;
+ }
+
+ if(_dy + _h > cy2 + 1){
+ _h = cy2 - _dy + 1;
+ }
+
+ if(_sx > srcX2 || _sy > srcY2) {
+ continue;
+ }
+
+ if(isAlphaComp){
+ alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+ dstCM, dstRast, _w, _h, rule, alpha, bgcolor);
+ }else if(isXORComp){
+ xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+ dstCM, dstRast, _w, _h, xorcolor);
+ }else{
+ Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null);
+ WritableRaster dr = dstRast.createWritableChild(_dx, _dy,
+ _w, _h, 0, 0, null);
+ cont.compose(sr, dr, dr);
+ }
+ }
+
+ }
+
+ DataBufferInt data;
+ Bitmap bmap, bmp;
+
+ void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+ int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, int rule, float alpha, Color bgcolor){
+
+ Object srcPixel = getTransferArray(srcRast, 1);
+ data = (DataBufferInt)srcRast.getDataBuffer();
+ int pix[] = data.getData();
+ bmap = Bitmap.createBitmap(pix, width, height, Bitmap.Config.RGB_565);
+ canvas.drawBitmap(bmap, dstX, dstY, paint);
+ }
+
+ void render(int[] img, int x, int y, int width, int height) {
+ canvas.drawBitmap(Bitmap.createBitmap(img, width, height, Bitmap.Config.ARGB_8888), x, y, paint);
+ }
+
+ void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+ int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, Color xorcolor){
+
+ data = (DataBufferInt)srcRast.getDataBuffer();
+ int pix[] = data.getData();
+ bmap = Bitmap.createBitmap(pix, width, height, Bitmap.Config.RGB_565);
+ canvas.drawBitmap(bmap, dstX, dstY, paint);
+ }
+
+ private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY,
+ ColorModel dstCM, WritableRaster dstR, int dstX, int dstY,
+ int width, int height, AffineTransform at, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+
+ data = (DataBufferInt)srcR.getDataBuffer();
+ int[] pixels = data.getData();
+ if (!srcCM.hasAlpha()) {
+ // This wouldn't be necessary if Android supported RGB_888.
+ for (int i = 0; i < pixels.length; i++) {
+ pixels[i] = pixels[i] | 0xff000000;
+ }
+ }
+ bmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
+
+ Matrix tm = new Matrix();
+ tm.setConcat(canvas.getMatrix(), AndroidGraphics2D.createMatrixObj(at));
+ if(at.getType() > 1) {
+ bmp = Bitmap.createBitmap(bmap, 0, 0, width, height, tm, true);
+ } else {
+ bmp = Bitmap.createBitmap(bmap, 0, 0, width, height, tm, false);
+ }
+ canvas.drawBitmap(bmp, dstX + (float)at.getTranslateX(), dstY + (float)at.getTranslateY(), paint);
+ }
+
+ private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) {
+ int x = r.x;
+ int y = r.y;
+ int width = r.width;
+ int height = r.height;
+
+ float[] corners = {
+ x, y,
+ x + width, y,
+ x + width, y + height,
+ x, y + height
+ };
+
+ at.transform(corners, 0, corners, 0, 4);
+
+ Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0);
+ bounds.add(corners[2], corners[3]);
+ bounds.add(corners[4], corners[5]);
+ bounds.add(corners[6], corners[7]);
+
+ return bounds;
+ }
+
+ private int compose(int srcRGB, boolean isSrcAlphaPre,
+ int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre,
+ int rule, int srcConstAlpha){
+
+ int sa, sr, sg, sb, da, dr, dg, db;
+
+ sa = (srcRGB >> 24) & 0xff;
+ sr = (srcRGB >> 16) & 0xff;
+ sg = (srcRGB >> 8) & 0xff;
+ sb = srcRGB & 0xff;
+
+ if(isSrcAlphaPre){
+ sa = mulLUT[srcConstAlpha][sa] & 0xff;
+ sr = mulLUT[srcConstAlpha][sr] & 0xff;
+ sg = mulLUT[srcConstAlpha][sg] & 0xff;
+ sb = mulLUT[srcConstAlpha][sb] & 0xff;
+ }else{
+ sa = mulLUT[srcConstAlpha][sa] & 0xff;
+ sr = mulLUT[sa][sr] & 0xff;
+ sg = mulLUT[sa][sg] & 0xff;
+ sb = mulLUT[sa][sb] & 0xff;
+ }
+
+ da = (dstRGB >> 24) & 0xff;
+ dr = (dstRGB >> 16) & 0xff;
+ dg = (dstRGB >> 8) & 0xff;
+ db = dstRGB & 0xff;
+
+ if(!isDstAlphaPre){
+ dr = mulLUT[da][dr] & 0xff;
+ dg = mulLUT[da][dg] & 0xff;
+ db = mulLUT[da][db] & 0xff;
+ }
+
+ int Fs = 0;
+ int Fd = 0;
+ switch(rule){
+ case AlphaComposite.CLEAR:
+ break;
+
+ case AlphaComposite.DST:
+ Fd = 255;
+ break;
+
+ case AlphaComposite.DST_ATOP:
+ Fs = 255 - da;
+ Fd = sa;
+ break;
+
+ case AlphaComposite.DST_IN:
+ Fd = sa;
+ break;
+
+ case AlphaComposite.DST_OUT:
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.DST_OVER:
+ Fs = 255 - da;
+ Fd = 255;
+ break;
+
+ case AlphaComposite.SRC:
+ Fs = 255;
+ break;
+
+ case AlphaComposite.SRC_ATOP:
+ Fs = da;
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.SRC_IN:
+ Fs = da;
+ break;
+
+ case AlphaComposite.SRC_OUT:
+ Fs = 255 - da;
+ break;
+
+ case AlphaComposite.SRC_OVER:
+ Fs = 255;
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.XOR:
+ Fs = 255 - da;
+ Fd = 255 - sa;
+ break;
+ }
+ dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff);
+ dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff);
+ db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff);
+
+ da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff);
+
+ if(!isDstAlphaPre){
+ if(da != 255){
+ dr = divLUT[da][dr] & 0xff;
+ dg = divLUT[da][dg] & 0xff;
+ db = divLUT[da][db] & 0xff;
+ }
+ }
+ if(!dstHasAlpha) {
+ da = 0xff;
+ }
+ dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db;
+
+ return dstRGB;
+
+ }
+
+ /**
+ * Allocate an array that can be use to store the result for a
+ * Raster.getDataElements call.
+ * @param raster Raster (type) where the getDataElements call will be made.
+ * @param nbPixels How many pixels to store in the array at most
+ * @return the result array or null
+ */
+ private Object getTransferArray(Raster raster, int nbPixels) {
+ int transferType = raster.getTransferType();
+ int nbDataElements = raster.getSampleModel().getNumDataElements();
+ int n = nbDataElements * nbPixels;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ return new byte[n];
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ return new short[n];
+ case DataBuffer.TYPE_INT:
+ return new int[n];
+ case DataBuffer.TYPE_FLOAT:
+ return new float[n];
+ case DataBuffer.TYPE_DOUBLE:
+ return new double[n];
+ case DataBuffer.TYPE_UNDEFINED:
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Draw a pixel
+ */
+ private void dot(int x, int y, int clr) {
+ if (colorCache != clr) {
+ paint.setColor(clr);
+ colorCache = clr;
+ }
+ canvas.drawLine(x, y, x + 1, y + 1, paint);
+ }
+}
diff --git a/awt/com/android/internal/awt/AndroidNativeEventQueue.java b/awt/com/android/internal/awt/AndroidNativeEventQueue.java
new file mode 100644
index 0000000..fc30614
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidNativeEventQueue.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+
+public class AndroidNativeEventQueue extends NativeEventQueue {
+
+ private Object eventMonitor;
+
+ public AndroidNativeEventQueue() {
+ super();
+ eventMonitor = getEventMonitor();
+ }
+
+ @Override
+ public void awake() {
+ synchronized (eventMonitor) {
+ eventMonitor.notify();
+ }
+ }
+
+ @Override
+ public void dispatchEvent() {
+ //???AWT
+ System.out.println(getClass()+": empty method called");
+ }
+
+ @Override
+ public long getJavaWindow() {
+ //???AWT
+ System.out.println(getClass()+": empty method called");
+ return 0;
+ }
+
+ @Override
+ public void performLater(Task task) {
+ //???AWT
+ System.out.println(getClass()+": empty method called");
+ }
+
+ @Override
+ public void performTask(Task task) {
+ //???AWT
+ System.out.println(getClass()+": empty method called");
+ }
+
+ @Override
+ public boolean waitEvent() {
+ while (isEmpty() ) {
+ synchronized (eventMonitor) {
+ try {
+ eventMonitor.wait(1000);
+ } catch (InterruptedException ignore) {
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/awt/com/android/internal/awt/AndroidWTK.java b/awt/com/android/internal/awt/AndroidWTK.java
new file mode 100644
index 0000000..1609d11
--- /dev/null
+++ b/awt/com/android/internal/awt/AndroidWTK.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import java.awt.GraphicsDevice;
+
+import org.apache.harmony.awt.wtk.CursorFactory;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+import org.apache.harmony.awt.wtk.NativeIM;
+import org.apache.harmony.awt.wtk.NativeMouseInfo;
+import org.apache.harmony.awt.wtk.NativeRobot;
+import org.apache.harmony.awt.wtk.SystemProperties;
+import org.apache.harmony.awt.wtk.WTK;
+import org.apache.harmony.awt.wtk.WindowFactory;
+
+public class AndroidWTK extends WTK {
+
+ private AndroidGraphicsFactory mAgf;
+ private AndroidNativeEventQueue mAneq;
+
+ @Override
+ public CursorFactory getCursorFactory() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public GraphicsFactory getGraphicsFactory() {
+ if(mAgf == null) {
+ mAgf = new AndroidGraphicsFactory();
+ }
+ return mAgf;
+ }
+
+ @Override
+ public NativeEventQueue getNativeEventQueue() {
+ if(mAneq == null) {
+ mAneq = new AndroidNativeEventQueue();
+ }
+ return mAneq;
+ }
+
+ @Override
+ public NativeIM getNativeIM() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public NativeMouseInfo getNativeMouseInfo() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public NativeRobot getNativeRobot(GraphicsDevice screen) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SystemProperties getSystemProperties() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public WindowFactory getWindowFactory() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/awt/com/android/internal/awt/AwtFactory.java b/awt/com/android/internal/awt/AwtFactory.java
new file mode 100644
index 0000000..6e667b2
--- /dev/null
+++ b/awt/com/android/internal/awt/AwtFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import java.awt.Graphics2D;
+import java.awt.Toolkit;
+
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+public class AwtFactory {
+
+ private static GraphicsFactory gf;
+
+ /**
+ * Use this method to get acces to AWT drawing primitives and to
+ * render into the surface area of a Android widget. Origin and
+ * clip of the returned graphics object are the same as in the
+ * corresponding Android widget.
+ *
+ * @param c Canvas of the android widget to draw into
+ * @param p The default drawing parameters such as font,
+ * stroke, foreground and background colors, etc.
+ * @return The AWT Graphics object that makes all AWT
+ * drawing primitives available in the androind world.
+ */
+ public static Graphics2D getAwtGraphics(Canvas c, Paint p) {
+ // AWT?? TODO: test it!
+ if (null == gf) {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ gf = tk.getGraphicsFactory();
+ }
+ return gf.getGraphics2D(c, p);
+ }
+
+}
diff --git a/awt/com/android/internal/awt/ImageOutputStreamWrapper.java b/awt/com/android/internal/awt/ImageOutputStreamWrapper.java
new file mode 100644
index 0000000..92185fd
--- /dev/null
+++ b/awt/com/android/internal/awt/ImageOutputStreamWrapper.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.awt;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.imageio.stream.ImageOutputStream;
+
+public class ImageOutputStreamWrapper extends OutputStream {
+
+ protected ImageOutputStream mIos;
+
+ private byte[] mBuff;
+
+ public ImageOutputStreamWrapper(ImageOutputStream ios) {
+ if (null == ios) {
+ throw new IllegalArgumentException("ImageOutputStream must not be null");
+ }
+ this.mIos = ios;
+ this.mBuff = new byte[1];
+ }
+
+ public ImageOutputStream getImageOutputStream() {
+ return mIos;
+ }
+
+ @Override
+ public void write(int oneByte) throws IOException {
+ mBuff[0] = (byte)oneByte;
+ mIos.write(mBuff, 0, 1);
+ }
+
+ public void write(byte[] b) throws IOException {
+ mIos.write(b, 0, b.length);
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ mIos.write(b, off, len);
+ }
+
+ public void flush() throws IOException {
+ mIos.flush();
+ }
+
+ public void close() throws IOException {
+ if (mIos == null) {
+ throw new IOException("Stream already closed");
+ }
+ mIos = null;
+ }
+}
diff --git a/awt/java/awt/AWTEvent.java b/awt/java/awt/AWTEvent.java
new file mode 100644
index 0000000..1ed9a37
--- /dev/null
+++ b/awt/java/awt/AWTEvent.java
@@ -0,0 +1,618 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev, Michael Danilov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.util.EventObject;
+import java.util.Hashtable;
+import java.util.EventListener;
+
+import java.awt.event.*;
+
+/**
+ * The abstract AWT events is base class for all AWT events.
+ * This class and its subclasses supercede the original java.awt.Event class.
+ */
+public abstract class AWTEvent extends EventObject {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -1825314779160409405L;
+
+ /** The Constant COMPONENT_EVENT_MASK indicates the event relates to a component. */
+ public static final long COMPONENT_EVENT_MASK = 1;
+
+ /** The Constant CONTAINER_EVENT_MASK indicates the event relates to a container. */
+ public static final long CONTAINER_EVENT_MASK = 2;
+
+ /** The Constant FOCUS_EVENT_MASK indicates the event relates to the focus. */
+ public static final long FOCUS_EVENT_MASK = 4;
+
+ /** The Constant KEY_EVENT_MASK indicates the event relates to a key. */
+ public static final long KEY_EVENT_MASK = 8;
+
+ /** The Constant MOUSE_EVENT_MASK indicates the event relates to the mouse. */
+ public static final long MOUSE_EVENT_MASK = 16;
+
+ /** The Constant MOUSE_MOTION_EVENT_MASK indicates the event relates to a mouse motion. */
+ public static final long MOUSE_MOTION_EVENT_MASK = 32;
+
+ /** The Constant WINDOW_EVENT_MASK indicates the event relates to a window. */
+ public static final long WINDOW_EVENT_MASK = 64;
+
+ /** The Constant ACTION_EVENT_MASK indicates the event relates to an action. */
+ public static final long ACTION_EVENT_MASK = 128;
+
+ /** The Constant ADJUSTMENT_EVENT_MASK indicates the event relates to an adjustment. */
+ public static final long ADJUSTMENT_EVENT_MASK = 256;
+
+ /** The Constant ITEM_EVENT_MASK indicates the event relates to an item. */
+ public static final long ITEM_EVENT_MASK = 512;
+
+ /** The Constant TEXT_EVENT_MASK indicates the event relates to text. */
+ public static final long TEXT_EVENT_MASK = 1024;
+
+ /** The Constant INPUT_METHOD_EVENT_MASK indicates the event relates to an input method. */
+ public static final long INPUT_METHOD_EVENT_MASK = 2048;
+
+ /** The Constant PAINT_EVENT_MASK indicates the event relates to a paint method. */
+ public static final long PAINT_EVENT_MASK = 8192;
+
+ /** The Constant INVOCATION_EVENT_MASK indicates the event relates to a method invocation. */
+ public static final long INVOCATION_EVENT_MASK = 16384;
+
+ /** The Constant HIERARCHY_EVENT_MASK indicates the event relates to a hierarchy. */
+ public static final long HIERARCHY_EVENT_MASK = 32768;
+
+ /**
+ * The Constant HIERARCHY_BOUNDS_EVENT_MASK indicates the event relates to hierarchy bounds.
+ */
+ public static final long HIERARCHY_BOUNDS_EVENT_MASK = 65536;
+
+ /** The Constant MOUSE_WHEEL_EVENT_MASK indicates the event relates to the mouse wheel. */
+ public static final long MOUSE_WHEEL_EVENT_MASK = 131072;
+
+ /** The Constant WINDOW_STATE_EVENT_MASK indicates the event relates to a window state. */
+ public static final long WINDOW_STATE_EVENT_MASK = 262144;
+
+ /** The Constant WINDOW_FOCUS_EVENT_MASK indicates the event relates to a window focus. */
+ public static final long WINDOW_FOCUS_EVENT_MASK = 524288;
+
+ /** The Constant RESERVED_ID_MAX indicates the maximum value for reserved
+ * AWT event IDs.
+ */
+ public static final int RESERVED_ID_MAX = 1999;
+
+ /** The Constant eventsMap. */
+ private static final Hashtable<Integer, EventDescriptor> eventsMap = new Hashtable<Integer, EventDescriptor>();
+
+ /** The converter. */
+ private static EventConverter converter;
+
+ /** The ID of the event. */
+ protected int id;
+
+ /**
+ * The consumed indicates whether or not the event is sent back down to
+ * the peer once the source has processed it (false means it's sent to the peer,
+ * true means it's not).
+ */
+ protected boolean consumed;
+
+ /** The dispatched by kfm. */
+ boolean dispatchedByKFM;
+
+ /** The is posted. */
+ transient boolean isPosted;
+
+ static {
+ eventsMap.put(new Integer(KeyEvent.KEY_TYPED),
+ new EventDescriptor(KEY_EVENT_MASK, KeyListener.class));
+ eventsMap.put(new Integer(KeyEvent.KEY_PRESSED),
+ new EventDescriptor(KEY_EVENT_MASK, KeyListener.class));
+ eventsMap.put(new Integer(KeyEvent.KEY_RELEASED),
+ new EventDescriptor(KEY_EVENT_MASK, KeyListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_CLICKED),
+ new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_PRESSED),
+ new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_RELEASED),
+ new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_MOVED),
+ new EventDescriptor(MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_ENTERED),
+ new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_EXITED),
+ new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_DRAGGED),
+ new EventDescriptor(MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class));
+ eventsMap.put(new Integer(MouseEvent.MOUSE_WHEEL),
+ new EventDescriptor(MOUSE_WHEEL_EVENT_MASK, MouseWheelListener.class));
+ eventsMap.put(new Integer(ComponentEvent.COMPONENT_MOVED),
+ new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class));
+ eventsMap.put(new Integer(ComponentEvent.COMPONENT_RESIZED),
+ new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class));
+ eventsMap.put(new Integer(ComponentEvent.COMPONENT_SHOWN),
+ new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class));
+ eventsMap.put(new Integer(ComponentEvent.COMPONENT_HIDDEN),
+ new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class));
+ eventsMap.put(new Integer(FocusEvent.FOCUS_GAINED),
+ new EventDescriptor(FOCUS_EVENT_MASK, FocusListener.class));
+ eventsMap.put(new Integer(FocusEvent.FOCUS_LOST),
+ new EventDescriptor(FOCUS_EVENT_MASK, FocusListener.class));
+ eventsMap.put(new Integer(PaintEvent.PAINT),
+ new EventDescriptor(PAINT_EVENT_MASK, null));
+ eventsMap.put(new Integer(PaintEvent.UPDATE),
+ new EventDescriptor(PAINT_EVENT_MASK, null));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_OPENED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSING),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_DEICONIFIED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_ICONIFIED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_STATE_CHANGED),
+ new EventDescriptor(WINDOW_STATE_EVENT_MASK, WindowStateListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_LOST_FOCUS),
+ new EventDescriptor(WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_GAINED_FOCUS),
+ new EventDescriptor(WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_DEACTIVATED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(WindowEvent.WINDOW_ACTIVATED),
+ new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class));
+ eventsMap.put(new Integer(HierarchyEvent.HIERARCHY_CHANGED),
+ new EventDescriptor(HIERARCHY_EVENT_MASK, HierarchyListener.class));
+ eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_MOVED),
+ new EventDescriptor(HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class));
+ eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_RESIZED),
+ new EventDescriptor(HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class));
+ eventsMap.put(new Integer(ContainerEvent.COMPONENT_ADDED),
+ new EventDescriptor(CONTAINER_EVENT_MASK, ContainerListener.class));
+ eventsMap.put(new Integer(ContainerEvent.COMPONENT_REMOVED),
+ new EventDescriptor(CONTAINER_EVENT_MASK, ContainerListener.class));
+ eventsMap.put(new Integer(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED),
+ new EventDescriptor(INPUT_METHOD_EVENT_MASK, InputMethodListener.class));
+ eventsMap.put(new Integer(InputMethodEvent.CARET_POSITION_CHANGED),
+ new EventDescriptor(INPUT_METHOD_EVENT_MASK, InputMethodListener.class));
+ eventsMap.put(new Integer(InvocationEvent.INVOCATION_DEFAULT),
+ new EventDescriptor(INVOCATION_EVENT_MASK, null));
+ eventsMap.put(new Integer(ItemEvent.ITEM_STATE_CHANGED),
+ new EventDescriptor(ITEM_EVENT_MASK, ItemListener.class));
+ eventsMap.put(new Integer(TextEvent.TEXT_VALUE_CHANGED),
+ new EventDescriptor(TEXT_EVENT_MASK, TextListener.class));
+ eventsMap.put(new Integer(ActionEvent.ACTION_PERFORMED),
+ new EventDescriptor(ACTION_EVENT_MASK, ActionListener.class));
+ eventsMap.put(new Integer(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED),
+ new EventDescriptor(ADJUSTMENT_EVENT_MASK, AdjustmentListener.class));
+ converter = new EventConverter();
+ }
+
+ /**
+ * Instantiates a new AWT event from the specified Event object.
+ *
+ * @param event the Event object.
+ */
+ public AWTEvent(Event event) {
+ this(event.target, event.id);
+ }
+
+ /**
+ * Instantiates a new AWT event with the specified object and type.
+ *
+ * @param source the source Object.
+ * @param id the event's type.
+ */
+ public AWTEvent(Object source, int id) {
+ super(source);
+ this.id = id;
+ consumed = false;
+ }
+
+ /**
+ * Gets the event's type.
+ *
+ * @return the event type ID.
+ */
+ public int getID() {
+ return id;
+ }
+
+ /**
+ * Sets a new source for the AWTEvent.
+ *
+ * @param newSource the new source Object for the AWTEvent.
+ */
+ public void setSource(Object newSource) {
+ source = newSource;
+ }
+
+ /**
+ * Returns a String representation of the AWTEvent.
+ *
+ * @return the String representation of the AWTEvent.
+ */
+ @Override
+ public String toString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * AWTEvent event = new AWTEvent(new Component(){}, 1){};
+ * System.out.println(event);
+ */
+ String name = ""; //$NON-NLS-1$
+
+ if (source instanceof Component && (source != null)) {
+ Component comp = (Component) getSource();
+ name = comp.getName();
+ if (name == null) {
+ name = ""; //$NON-NLS-1$
+ }
+ }
+
+ return (getClass().getName() + "[" + paramString() + "]" //$NON-NLS-1$ //$NON-NLS-2$
+ + " on " + (name.length() > 0 ? name : source)); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns a string representation of the AWTEvent state.
+ *
+ * @return a string representation of the AWTEvent state.
+ */
+ public String paramString() {
+ //nothing to implement: all event types must override this method
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Checks whether or not this AWTEvent has been consumed.
+ *
+ * @return true, if this AWTEvent has been consumed, false otherwise.
+ */
+ protected boolean isConsumed() {
+ return consumed;
+ }
+
+ /**
+ * Consumes the AWTEvent.
+ */
+ protected void consume() {
+ consumed = true;
+ }
+
+ /**
+ * Convert AWTEvent object to a corresponding (deprecated) Event object.
+ *
+ * @return new Event object which is a converted AWTEvent object or null
+ * if the conversion is not possible
+ */
+ Event getEvent() {
+
+ if (id == ActionEvent.ACTION_PERFORMED) {
+ ActionEvent ae = (ActionEvent) this;
+ return converter.convertActionEvent(ae);
+
+ } else if (id == AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED) {
+ AdjustmentEvent ae = (AdjustmentEvent) this;
+ return converter.convertAdjustmentEvent(ae);
+
+//???AWT
+// } else if (id == ComponentEvent.COMPONENT_MOVED
+// && source instanceof Window) {
+// //the only type of Component events is COMPONENT_MOVED on window
+// ComponentEvent ce = (ComponentEvent) this;
+// return converter.convertComponentEvent(ce);
+
+ } else if (id >= FocusEvent.FOCUS_FIRST && id <= FocusEvent.FOCUS_LAST) {
+ //nothing to convert
+
+//???AWT
+// } else if (id == ItemEvent.ITEM_STATE_CHANGED) {
+// ItemEvent ie = (ItemEvent) this;
+// return converter.convertItemEvent(ie);
+
+ } else if (id == KeyEvent.KEY_PRESSED || id == KeyEvent.KEY_RELEASED) {
+ KeyEvent ke = (KeyEvent) this;
+ return converter.convertKeyEvent(ke);
+ } else if (id >= MouseEvent.MOUSE_FIRST && id <= MouseEvent.MOUSE_LAST) {
+ MouseEvent me = (MouseEvent) this;
+ return converter.convertMouseEvent(me);
+ } else if (id == WindowEvent.WINDOW_CLOSING
+ || id == WindowEvent.WINDOW_ICONIFIED
+ || id == WindowEvent.WINDOW_DEICONIFIED) {
+ //nothing to convert
+ } else {
+ return null;
+ }
+ return new Event(source, id, null);
+ }
+
+
+ /**
+ * The Class EventDescriptor.
+ */
+ static final class EventDescriptor {
+
+ /** The event mask. */
+ final long eventMask;
+
+ /** The listener type. */
+ final Class<? extends EventListener> listenerType;
+
+ /**
+ * Instantiates a new event descriptor.
+ *
+ * @param eventMask the event mask
+ * @param listenerType the listener type
+ */
+ EventDescriptor(long eventMask, Class<? extends EventListener> listenerType) {
+ this.eventMask = eventMask;
+ this.listenerType = listenerType;
+ }
+
+ }
+
+ /**
+ * The Class EventTypeLookup.
+ */
+ static final class EventTypeLookup {
+
+ /** The last event. */
+ private AWTEvent lastEvent = null;
+
+ /** The last event descriptor. */
+ private EventDescriptor lastEventDescriptor = null;
+
+ /**
+ * Gets the event descriptor.
+ *
+ * @param event the event
+ *
+ * @return the event descriptor
+ */
+ EventDescriptor getEventDescriptor(AWTEvent event) {
+ synchronized (this) {
+ if (event != lastEvent) {
+ lastEvent = event;
+ lastEventDescriptor = eventsMap.get(new Integer(event.id));
+ }
+
+ return lastEventDescriptor;
+ }
+ }
+
+ /**
+ * Gets the event mask.
+ *
+ * @param event the event
+ *
+ * @return the event mask
+ */
+ long getEventMask(AWTEvent event) {
+ final EventDescriptor ed = getEventDescriptor(event);
+ return ed == null ? -1 : ed.eventMask;
+ }
+ }
+
+ /**
+ * The Class EventConverter.
+ */
+ static final class EventConverter {
+
+ /** The Constant OLD_MOD_MASK. */
+ static final int OLD_MOD_MASK = Event.ALT_MASK | Event.CTRL_MASK
+ | Event.META_MASK | Event.SHIFT_MASK;
+
+ /**
+ * Convert action event.
+ *
+ * @param ae the ae
+ *
+ * @return the event
+ */
+ Event convertActionEvent(ActionEvent ae) {
+ Event evt = new Event(ae.getSource(), ae.getID(), ae.getActionCommand());
+ evt.when = ae.getWhen();
+ evt.modifiers = ae.getModifiers() & OLD_MOD_MASK;
+
+ /* if (source instanceof Button) {
+ arg = ((Button) source).getLabel();
+ } else if (source instanceof Checkbox) {
+ arg = new Boolean(((Checkbox) source).getState());
+ } else if (source instanceof CheckboxMenuItem) {
+ arg = ((CheckboxMenuItem) source).getLabel();
+ } else if (source instanceof Choice) {
+ arg = ((Choice) source).getSelectedItem();
+ } else if (source instanceof List) {
+ arg = ((List) source).getSelectedItem();
+ } else if (source instanceof MenuItem) {
+ arg = ((MenuItem) source).getLabel();
+ } else if (source instanceof TextField) {
+ arg = ((TextField) source).getText();
+ }
+*/
+ return evt;
+ }
+
+
+ /**
+ * Convert adjustment event.
+ *
+ * @param ae the ae
+ *
+ * @return the event
+ */
+ Event convertAdjustmentEvent(AdjustmentEvent ae) {
+ //TODO: Event.SCROLL_BEGIN/SCROLL_END
+ return new Event(ae.source, ae.id + ae.getAdjustmentType() - 1,
+ new Integer(ae.getValue()));
+ }
+
+ /**
+ * Convert component event.
+ *
+ * @param ce the ce
+ *
+ * @return the event
+ */
+ Event convertComponentEvent(ComponentEvent ce) {
+ Component comp = ce.getComponent();
+ Event evt = new Event(comp, Event.WINDOW_MOVED, null);
+ evt.x = comp.getX();
+ evt.y = comp.getY();
+ return evt;
+ }
+
+ //???AWT
+ /*
+ Event convertItemEvent(ItemEvent ie) {
+ int oldId = ie.id + ie.getStateChange() - 1;
+ Object source = ie.source;
+ int idx = -1;
+ if (source instanceof List) {
+ List list = (List) source;
+ idx = list.getSelectedIndex();
+ }
+ else if (source instanceof Choice) {
+ Choice choice = (Choice) source;
+ idx = choice.getSelectedIndex();
+ }
+ Object arg = idx >= 0 ? new Integer(idx) : null;
+ return new Event(source, oldId, arg);
+ }
+ */
+
+ /**
+ * Convert key event.
+ *
+ * @param ke the ke
+ *
+ * @return the event
+ */
+ Event convertKeyEvent(KeyEvent ke) {
+ int oldId = ke.id;
+ //leave only old Event's modifiers
+
+ int mod = ke.getModifiers() & OLD_MOD_MASK;
+ Component comp = ke.getComponent();
+ char keyChar = ke.getKeyChar();
+ int keyCode = ke.getKeyCode();
+ int key = convertKey(keyChar, keyCode);
+ if (key >= Event.HOME && key <= Event.INSERT) {
+ oldId += 2; //non-ASCII key -> action key
+ }
+ return new Event(comp, ke.getWhen(), oldId, 0, 0, key, mod);
+ }
+
+ /**
+ * Convert mouse event.
+ *
+ * @param me the me
+ *
+ * @return the event
+ */
+ Event convertMouseEvent(MouseEvent me) {
+ int id = me.id;
+ if (id != MouseEvent.MOUSE_CLICKED) {
+ Event evt = new Event(me.source, id, null);
+ evt.x = me.getX();
+ evt.y = me.getY();
+ int mod = me.getModifiers();
+ //in Event modifiers mean button number for mouse events:
+ evt.modifiers = mod & (Event.ALT_MASK | Event.META_MASK);
+ if (id == MouseEvent.MOUSE_PRESSED) {
+ evt.clickCount = me.getClickCount();
+ }
+ return evt;
+ }
+ return null;
+ }
+
+ /**
+ * Convert key.
+ *
+ * @param keyChar the key char
+ * @param keyCode the key code
+ *
+ * @return the int
+ */
+ int convertKey(char keyChar, int keyCode) {
+ int key;
+ //F1 - F12
+ if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) {
+ key = Event.F1 + keyCode - KeyEvent.VK_F1;
+ } else {
+ switch (keyCode) {
+ default: //non-action key
+ key = keyChar;
+ break;
+ //action keys:
+ case KeyEvent.VK_HOME:
+ key = Event.HOME;
+ break;
+ case KeyEvent.VK_END:
+ key = Event.END;
+ break;
+ case KeyEvent.VK_PAGE_UP:
+ key = Event.PGUP;
+ break;
+ case KeyEvent.VK_PAGE_DOWN:
+ key = Event.PGDN;
+ break;
+ case KeyEvent.VK_UP:
+ key = Event.UP;
+ break;
+ case KeyEvent.VK_DOWN:
+ key = Event.DOWN;
+ break;
+ case KeyEvent.VK_LEFT:
+ key = Event.LEFT;
+ break;
+ case KeyEvent.VK_RIGHT:
+ key = Event.RIGHT;
+ break;
+ case KeyEvent.VK_PRINTSCREEN:
+ key = Event.PRINT_SCREEN;
+ break;
+ case KeyEvent.VK_SCROLL_LOCK:
+ key = Event.SCROLL_LOCK;
+ break;
+ case KeyEvent.VK_CAPS_LOCK:
+ key = Event.CAPS_LOCK;
+ break;
+ case KeyEvent.VK_NUM_LOCK:
+ key = Event.NUM_LOCK;
+ break;
+ case KeyEvent.VK_PAUSE:
+ key = Event.PAUSE;
+ break;
+ case KeyEvent.VK_INSERT:
+ key = Event.INSERT;
+ break;
+ }
+ }
+ return key;
+ }
+
+ }
+
+}
diff --git a/awt/java/awt/AWTException.java b/awt/java/awt/AWTException.java
new file mode 100644
index 0000000..70ce6e1
--- /dev/null
+++ b/awt/java/awt/AWTException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt;
+
+
+/**
+ * The AWTException class is used to provide notification and information
+ * about AWT errors.
+ */
+public class AWTException extends Exception {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -1900414231151323879L;
+
+ /**
+ * Instantiates a new AWT exception with the specified message.
+ *
+ * @param msg the specific message for current exception.
+ */
+ public AWTException(String msg) {
+ super(msg);
+ }
+
+}
+
diff --git a/awt/java/awt/AWTKeyStroke.java b/awt/java/awt/AWTKeyStroke.java
new file mode 100644
index 0000000..5e7de4e
--- /dev/null
+++ b/awt/java/awt/AWTKeyStroke.java
@@ -0,0 +1,678 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The AWTKeyStroke holds all of the information for the complete act of
+ * typing a character. This includes the events that are generated when
+ * the key is pressed, released, or typed (pressed and released generating
+ * a unicode character result) which are associated with the event
+ * objects KeyEvent.KEY_PRESSED, KeyEvent.KEY_RELEASED, or KeyEvent.KEY_TYPED.
+ * It also holds information about which modifiers (such as control or
+ * shift) were used in conjunction with the keystroke. The following masks
+ * are available to identify the modifiers:
+ * <ul>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.META_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_MASK</li>
+ * <li>java.awt.event.InputEvent.META_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_MASK</li>
+ * </ul>
+ * <br>
+ * The AWTKeyStroke is unique, and applications should not create their own
+ * instances of AWTKeyStroke. All applications should use getAWTKeyStroke
+ * methods for obtaining instances of AWTKeyStroke.
+ */
+public class AWTKeyStroke implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -6430539691155161871L;
+
+ /** The Constant cache. */
+ private static final Map<AWTKeyStroke, AWTKeyStroke> cache = new HashMap<AWTKeyStroke, AWTKeyStroke>(); //Map<AWTKeyStroke, ? extends AWTKeyStroke>
+
+ /** The Constant keyEventTypesMap. */
+ private static final Map<Integer, String> keyEventTypesMap = new HashMap<Integer, String>(); //Map<int, String>
+
+ private static Constructor<?> subConstructor;
+
+ static {
+ keyEventTypesMap.put(new Integer(KeyEvent.KEY_PRESSED), "pressed"); //$NON-NLS-1$
+ keyEventTypesMap.put(new Integer(KeyEvent.KEY_RELEASED), "released"); //$NON-NLS-1$
+ keyEventTypesMap.put(new Integer(KeyEvent.KEY_TYPED), "typed"); //$NON-NLS-1$
+ }
+
+ /** The key char. */
+ private char keyChar;
+
+ /** The key code. */
+ private int keyCode;
+
+ /** The modifiers. */
+ private int modifiers;
+
+ /** The on key release. */
+ private boolean onKeyRelease;
+
+ /**
+ * Instantiates a new AWTKeyStroke.
+ * getAWTKeyStroke method should be used by applications code.
+ *
+ * @param keyChar the key char
+ * @param keyCode the key code
+ * @param modifiers the modifiers
+ * @param onKeyRelease true if AWTKeyStroke is for a key release, overwise false.
+ */
+ protected AWTKeyStroke(char keyChar, int keyCode, int modifiers,
+ boolean onKeyRelease)
+ {
+ setAWTKeyStroke(keyChar, keyCode, modifiers, onKeyRelease);
+ }
+
+ /** Sets the awt key stroke.
+ *
+ * @param keyChar the key char
+ * @param keyCode the key code
+ * @param modifiers the modifiers
+ * @param onKeyRelease the on key release
+ */
+ private void setAWTKeyStroke( char keyChar, int keyCode, int modifiers,
+ boolean onKeyRelease)
+ {
+ this.keyChar = keyChar;
+ this.keyCode = keyCode;
+ this.modifiers = modifiers;
+ this.onKeyRelease = onKeyRelease;
+ }
+
+ /**
+ * Instantiates a new AWTKeyStroke with default parameters:
+ * KeyEvent.CHAR_UNDEFINED key char, KeyEvent.VK_UNDEFINED key code,
+ * without modifiers and false key realised value.
+ */
+ protected AWTKeyStroke() {
+ this(KeyEvent.CHAR_UNDEFINED, KeyEvent.VK_UNDEFINED, 0, false);
+ }
+
+ /**
+ * Returns the unique number value for AWTKeyStroke object.
+ *
+ * @return the int unique value of the AWTKeyStroke object.
+ */
+ @Override
+ public int hashCode() {
+ return modifiers + ( keyCode != KeyEvent.VK_UNDEFINED ?
+ keyCode : keyChar) + (onKeyRelease ? -1 : 0);
+ }
+
+ /**
+ * Gets the set of modifiers for the AWTKeyStroke object.
+ *
+ * @return the int value which contains modifiers.
+ */
+ public final int getModifiers() {
+ return modifiers;
+ }
+
+ /**
+ * Compares the AWTKeyStroke object to the specified object.
+ *
+ * @return true, if objects are identical, overwise false.
+ */
+ @Override
+ public final boolean equals(Object anObject) {
+ if (anObject instanceof AWTKeyStroke) {
+ AWTKeyStroke key = (AWTKeyStroke)anObject;
+ return ((key.keyCode == keyCode) && (key.keyChar == keyChar) &&
+ (key.modifiers == modifiers) &&
+ (key.onKeyRelease == onKeyRelease));
+ }
+ return false;
+ }
+
+ /**
+ * Returns the string representation of the AWTKeyStroke.
+ * This string should contain key stroke properties.
+ *
+ * @return the string representation of the AWTKeyStroke.
+ */
+ @Override
+ public String toString() {
+ int type = getKeyEventType();
+ return InputEvent.getModifiersExText(getModifiers()) + " " + //$NON-NLS-1$
+ keyEventTypesMap.get(new Integer(type)) + " " + //$NON-NLS-1$
+ (type == KeyEvent.KEY_TYPED ? new String(new char[] {keyChar}) :
+ KeyEvent.getKeyText(keyCode));
+ }
+
+ /**
+ * Gets the key code for the AWTKeyStroke object.
+ *
+ * @return the key code for the AWTKeyStroke object.
+ */
+ public final int getKeyCode() {
+ return keyCode;
+ }
+
+ /**
+ * Gets the key character for the AWTKeyStroke object.
+ *
+ * @return the key character for the AWTKeyStroke object.
+ */
+ public final char getKeyChar() {
+ return keyChar;
+ }
+
+ /**
+ * Gets the AWT key stroke.
+ *
+ * @param keyChar the key char
+ * @param keyCode the key code
+ * @param modifiers the modifiers
+ * @param onKeyRelease the on key release
+ *
+ * @return the AWT key stroke
+ */
+ private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode,
+ int modifiers,
+ boolean onKeyRelease) {
+ AWTKeyStroke key = newInstance(keyChar, keyCode, modifiers, onKeyRelease);
+
+ AWTKeyStroke value = cache.get(key);
+ if (value == null) {
+ value = key;
+ cache.put(key, value);
+ }
+ return value;
+ }
+
+ /**
+ * New instance.
+ *
+ * @param keyChar the key char
+ * @param keyCode the key code
+ * @param modifiers the modifiers
+ * @param onKeyRelease the on key release
+ *
+ * @return the AWT key stroke
+ */
+ private static AWTKeyStroke newInstance(char keyChar, int keyCode,
+ int modifiers,
+ boolean onKeyRelease) {
+ AWTKeyStroke key;
+ //???AWT
+// if (subConstructor == null) {
+ key = new AWTKeyStroke();
+ //???AWT
+// } else {
+// try {
+// key = (AWTKeyStroke) subConstructor.newInstance();
+// } catch (Exception e) {
+// throw new RuntimeException(e);
+// }
+// }
+ int allModifiers = getAllModifiers(modifiers);
+ key.setAWTKeyStroke(keyChar, keyCode, allModifiers, onKeyRelease);
+ return key;
+ }
+
+ /**
+ * Adds the mask.
+ *
+ * @param mod the mod
+ * @param mask the mask
+ *
+ * @return the int
+ */
+ private static int addMask(int mod, int mask) {
+ return ((mod & mask) != 0) ? (mod | mask) : mod;
+ }
+
+ /**
+ * return all (old & new) modifiers corresponding to.
+ *
+ * @param mod old or new modifiers
+ *
+ * @return old and new modifiers together
+ */
+ static int getAllModifiers(int mod) {
+ int allMod = mod;
+ int shift = (InputEvent.SHIFT_MASK | InputEvent.SHIFT_DOWN_MASK);
+ int ctrl = (InputEvent.CTRL_MASK | InputEvent.CTRL_DOWN_MASK);
+ int meta = (InputEvent.META_MASK | InputEvent.META_DOWN_MASK);
+ int alt = (InputEvent.ALT_MASK | InputEvent.ALT_DOWN_MASK);
+ int altGr = (InputEvent.ALT_GRAPH_MASK | InputEvent.ALT_GRAPH_DOWN_MASK);
+ // button modifiers are not converted between old & new
+
+ allMod = addMask(allMod, shift);
+ allMod = addMask(allMod, ctrl);
+ allMod = addMask(allMod, meta);
+ allMod = addMask(allMod, alt);
+ allMod = addMask(allMod, altGr);
+
+ return allMod;
+ }
+
+ /**
+ * Returns an instance of AWTKeyStroke for parsed string.
+ *
+ * The string must have the following syntax:
+ *<p>
+ * &lt;modifiers&gt;* (&lt;typedID&gt; | &lt;pressedReleasedID&gt;)
+ *<p>
+ * modifiers := shift | control | ctrl | meta | alt | altGraph
+ * <br>
+ * typedID := typed <typedKey>
+ * <br>
+ * typedKey := string of length 1 giving the Unicode character.
+ * <br>
+ * pressedReleasedID := (pressed | released) <key>
+ * <br>
+ * key := KeyEvent key code name, i.e. the name following "VK_".
+ * <p>
+ * @param s the String which contains key stroke parameters.
+ *
+ * @return the AWTKeyStroke for string.
+ *
+ * @throws IllegalArgumentException if string has incorrect format or null.
+ */
+ public static AWTKeyStroke getAWTKeyStroke(String s) {
+ if (s == null) {
+ // awt.65=null argument
+ throw new IllegalArgumentException(Messages.getString("awt.65")); //$NON-NLS-1$
+ }
+
+ StringTokenizer tokenizer = new StringTokenizer(s);
+
+ Boolean release = null;
+ int modifiers = 0;
+ int keyCode = KeyEvent.VK_UNDEFINED;
+ char keyChar = KeyEvent.CHAR_UNDEFINED;
+ boolean typed = false;
+ long modifier = 0;
+ String token = null;
+ do {
+ token = getNextToken(tokenizer);
+ modifier = parseModifier(token);
+ modifiers |= modifier;
+ } while (modifier > 0);
+
+ typed = parseTypedID(token);
+
+ if (typed) {
+ token = getNextToken(tokenizer);
+ keyChar = parseTypedKey(token);
+
+ }
+ if (keyChar == KeyEvent.CHAR_UNDEFINED) {
+ release = parsePressedReleasedID(token);
+ if (release != null) {
+ token = getNextToken(tokenizer);
+ }
+ keyCode = parseKey(token);
+ }
+ if (tokenizer.hasMoreTokens()) {
+ // awt.66=Invalid format
+ throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+ }
+
+ return getAWTKeyStroke(keyChar, keyCode, modifiers,
+ release == Boolean.TRUE);
+ }
+
+ /**
+ * Gets the next token.
+ *
+ * @param tokenizer the tokenizer
+ *
+ * @return the next token
+ */
+ private static String getNextToken(StringTokenizer tokenizer) {
+ try {
+ return tokenizer.nextToken();
+ } catch (NoSuchElementException exception) {
+ // awt.66=Invalid format
+ throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Gets the key code.
+ *
+ * @param s the s
+ *
+ * @return the key code
+ */
+ static int getKeyCode(String s) {
+ try {
+ Field vk = KeyEvent.class.getField("VK_" + s); //$NON-NLS-1$
+ return vk.getInt(null);
+ } catch (Exception e) {
+ if (s.length() != 1) {
+ // awt.66=Invalid format
+ throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+ }
+ return KeyEvent.VK_UNDEFINED;
+ }
+ }
+
+ /**
+ * Gets an instance of the AWTKeyStroke for specified character.
+ *
+ * @param keyChar the keyboard character value.
+ *
+ * @return a AWTKeyStroke for specified character.
+ */
+ public static AWTKeyStroke getAWTKeyStroke(char keyChar) {
+ return getAWTKeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false);
+ }
+
+ /**
+ * Returns an instance of AWTKeyStroke for a given key code, set
+ * of modifiers, and specified key released flag value.
+ * The key codes are defined in java.awt.event.KeyEvent class.
+ * The set of modifiers is given as a bitwise combination
+ * of masks taken from the following list:
+ * <ul>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.META_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_MASK</li>
+ * <li>java.awt.event.InputEvent.META_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_MASK</li>
+ * </ul>
+ * <br>
+ *
+ * @param keyCode the specified key code of keyboard.
+ * @param modifiers the bit set of modifiers.
+ *
+ * @return the AWTKeyStroke.
+ */
+ public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers,
+ boolean onKeyRelease) {
+ return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,
+ onKeyRelease);
+ }
+
+ /**
+ * Returns AWTKeyStroke for a specified character and set of modifiers.
+ * The set of modifiers is given as a bitwise combination
+ * of masks taken from the following list:
+ * <ul>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.META_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_MASK</li>
+ * <li>java.awt.event.InputEvent.META_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_MASK</li>
+ * </ul>
+ *
+ * @param keyChar the Character object which represents keyboard character value.
+ * @param modifiers the bit set of modifiers.
+ *
+ * @return the AWTKeyStroke object.
+ *
+ * @throws IllegalArgumentException if keyChar value is null.
+ */
+ public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers) {
+ if (keyChar == null) {
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "keyChar")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return getAWTKeyStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED,
+ modifiers, false);
+ }
+
+ /**
+ * Returns an instance of AWTKeyStroke for a specified key code and
+ * set of modifiers.
+ * The key codes are defined in java.awt.event.KeyEvent class.
+ * The set of modifiers is given as a bitwise combination
+ * of masks taken from the following list:
+ * <ul>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.META_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK</li>
+ * <li>java.awt.event.InputEvent.ALT_MASK</li>
+ * <li>java.awt.event.InputEvent.CTRL_MASK</li>
+ * <li>java.awt.event.InputEvent.META_MASK</li>
+ * <li>java.awt.event.InputEvent.SHIFT_MASK</li>
+ * </ul>
+ *
+ * @param keyCode the specified key code of keyboard.
+ * @param modifiers the bit set of modifiers.
+ *
+ * @return the AWTKeyStroke
+ */
+ public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) {
+ return getAWTKeyStroke(keyCode, modifiers, false);
+ }
+
+ /**
+ * Gets the AWTKeyStroke for a key event. This method obtains the key char
+ * and key code from the specified key event.
+ *
+ * @param anEvent the key event which identifies the desired AWTKeyStroke.
+ *
+ * @return the AWTKeyStroke for the key event.
+ */
+ public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) {
+ int id = anEvent.getID();
+ char undef = KeyEvent.CHAR_UNDEFINED;
+ char keyChar = (id == KeyEvent.KEY_TYPED ? anEvent.getKeyChar() :
+ undef);
+ int keyCode = (keyChar == undef ? anEvent.getKeyCode() :
+ KeyEvent.VK_UNDEFINED);
+ return getAWTKeyStroke(keyChar, keyCode, anEvent.getModifiersEx(),
+ id == KeyEvent.KEY_RELEASED);
+ }
+
+ /**
+ * Gets the key event type for the AWTKeyStroke object.
+ *
+ * @return the key event type: KeyEvent.KEY_PRESSED, KeyEvent.KEY_TYPED, or KeyEvent.KEY_RELEASED
+ */
+ public final int getKeyEventType() {
+ if (keyCode == KeyEvent.VK_UNDEFINED) {
+ return KeyEvent.KEY_TYPED;
+ }
+ return (onKeyRelease ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED);
+ }
+
+ /**
+ * Retuns true if the key event is associated with the AWTKeyStroke is
+ * KEY_RELEASED, overwise false.
+ *
+ * @return true, if if the key event associated with the AWTKeyStroke is
+ * KEY_RELEASED, overwise false.
+ */
+ public final boolean isOnKeyRelease() {
+ return onKeyRelease;
+ }
+
+ /**
+ * Read resolve.
+ *
+ * @return the object
+ *
+ * @throws ObjectStreamException the object stream exception
+ */
+ protected Object readResolve() throws ObjectStreamException {
+ return getAWTKeyStroke(this.keyChar, this.keyCode,
+ this.modifiers, this.onKeyRelease);
+ }
+
+ /**
+ * Register subclass.
+ *
+ * @param subclass the subclass
+ */
+ protected static void registerSubclass(Class<?> subclass) {
+ //???AWT
+ /*
+ if (subclass == null) {
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "subclass")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (! AWTKeyStroke.class.isAssignableFrom(subclass)) {
+ // awt.67=subclass is not derived from AWTKeyStroke
+ throw new ClassCastException(Messages.getString("awt.67")); //$NON-NLS-1$
+ }
+ try {
+ subConstructor = subclass.getDeclaredConstructor();
+ subConstructor.setAccessible(true);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ // awt.68=subclass could not be instantiated
+ throw new IllegalArgumentException(Messages.getString("awt.68")); //$NON-NLS-1$
+ }
+ cache.clear(); //flush the cache
+ */
+ }
+
+ /**
+ * Parses the modifier.
+ *
+ * @param strMod the str mod
+ *
+ * @return the long
+ */
+ private static long parseModifier(String strMod) {
+ long modifiers = 0l;
+ if (strMod.equals("shift")) { //$NON-NLS-1$
+ modifiers |= InputEvent.SHIFT_DOWN_MASK;
+ } else if (strMod.equals("control") || strMod.equals("ctrl")) { //$NON-NLS-1$ //$NON-NLS-2$
+ modifiers |= InputEvent.CTRL_DOWN_MASK;
+ } else if (strMod.equals("meta")) { //$NON-NLS-1$
+ modifiers |= InputEvent.META_DOWN_MASK;
+ } else if (strMod.equals("alt")) { //$NON-NLS-1$
+ modifiers |= InputEvent.ALT_DOWN_MASK;
+ } else if (strMod.equals("altGraph")) { //$NON-NLS-1$
+ modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
+ } else if (strMod.equals("button1")) { //$NON-NLS-1$
+ modifiers |= InputEvent.BUTTON1_DOWN_MASK;
+ } else if (strMod.equals("button2")) { //$NON-NLS-1$
+ modifiers |= InputEvent.BUTTON2_DOWN_MASK;
+ } else if (strMod.equals("button3")) { //$NON-NLS-1$
+ modifiers |= InputEvent.BUTTON3_DOWN_MASK;
+ }
+ return modifiers;
+ }
+
+ /**
+ * Parses the typed id.
+ *
+ * @param strTyped the str typed
+ *
+ * @return true, if successful
+ */
+ private static boolean parseTypedID(String strTyped) {
+ if (strTyped.equals("typed")) { //$NON-NLS-1$
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Parses the typed key.
+ *
+ * @param strChar the str char
+ *
+ * @return the char
+ */
+ private static char parseTypedKey(String strChar) {
+ char keyChar = KeyEvent.CHAR_UNDEFINED;
+
+ if (strChar.length() != 1) {
+ // awt.66=Invalid format
+ throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+ }
+ keyChar = strChar.charAt(0);
+ return keyChar;
+ }
+
+ /**
+ * Parses the pressed released id.
+ *
+ * @param str the str
+ *
+ * @return the boolean
+ */
+ private static Boolean parsePressedReleasedID(String str) {
+
+ if (str.equals("pressed")) { //$NON-NLS-1$
+ return Boolean.FALSE;
+ } else if (str.equals("released")) { //$NON-NLS-1$
+ return Boolean.TRUE;
+ }
+ return null;
+ }
+
+ /**
+ * Parses the key.
+ *
+ * @param strCode the str code
+ *
+ * @return the int
+ */
+ private static int parseKey(String strCode) {
+ int keyCode = KeyEvent.VK_UNDEFINED;
+
+ keyCode = getKeyCode(strCode);
+
+ if (keyCode == KeyEvent.VK_UNDEFINED) {
+ // awt.66=Invalid format
+ throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$
+ }
+ return keyCode;
+ }
+}
+
diff --git a/awt/java/awt/AWTListenerList.java b/awt/java/awt/AWTListenerList.java
new file mode 100644
index 0000000..3327d63
--- /dev/null
+++ b/awt/java/awt/AWTListenerList.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.util.EventListener;
+
+import org.apache.harmony.awt.ListenerList;
+
+final class AWTListenerList<T extends EventListener> extends ListenerList<T> {
+ private static final long serialVersionUID = -2622077171532840953L;
+
+ private final Component owner;
+
+ AWTListenerList() {
+ super();
+ this.owner = null;
+ }
+
+ AWTListenerList(Component owner) {
+ super();
+ this.owner = owner;
+ }
+
+ @Override
+ public void addUserListener(T listener) {
+ super.addUserListener(listener);
+
+ if (owner != null) {
+ owner.deprecatedEventHandler = false;
+ }
+ }
+}
diff --git a/awt/java/awt/AWTPermission.java b/awt/java/awt/AWTPermission.java
new file mode 100644
index 0000000..25326ab
--- /dev/null
+++ b/awt/java/awt/AWTPermission.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.security.BasicPermission;
+
+/**
+ * The AWTPermission specifies the name of the permission and the
+ * corresponding action list.
+ */
+public final class AWTPermission extends BasicPermission {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 8890392402588814465L;
+
+ /**
+ * Instantiates a new AWTPermission with defined name and actions.
+ *
+ * @param name the name of a new AWTPermission.
+ * @param actions the actions of a new AWTPermission.
+ */
+ public AWTPermission(String name, String actions) {
+ super(name, actions);
+ }
+
+ /**
+ * Instantiates a new AWT permission with the defined name.
+ *
+ * @param name the name of a new AWTPermission.
+ */
+ public AWTPermission(String name) {
+ super(name);
+ }
+
+}
+
diff --git a/awt/java/awt/ActiveEvent.java b/awt/java/awt/ActiveEvent.java
new file mode 100644
index 0000000..4133752
--- /dev/null
+++ b/awt/java/awt/ActiveEvent.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * This interface defines events that know how to dispatch themselves.
+ * Such event can be placed upon the event queue and its dispatch method
+ * will be called when the event is dispatched.
+ */
+public interface ActiveEvent {
+
+ /**
+ * Dispatches the event to the listeners of the event's source,
+ * or does whatever it is this event is supposed to do.
+ */
+ public void dispatch();
+
+}
diff --git a/awt/java/awt/Adjustable.java b/awt/java/awt/Adjustable.java
new file mode 100644
index 0000000..3241cad
--- /dev/null
+++ b/awt/java/awt/Adjustable.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.AdjustmentListener;
+
+/**
+ * The Adjustable interface represents an adjustable numeric value
+ * contained within a bounded range of values, such as the current
+ * location in scrollable region or the value of a gauge.
+ */
+public interface Adjustable {
+
+ /**
+ * The Constant HORIZONTAL indicates that the Adjustable's orientation
+ * is horizontal.
+ */
+ public static final int HORIZONTAL = 0;
+
+ /**
+ * The Constant VERTICAL indicates that the Adjustable's orientation
+ * is vertical.
+ */
+ public static final int VERTICAL = 1;
+
+ /**
+ * The Constant NO_ORIENTATION indicates that the Adjustable
+ * has no orientation.
+ */
+ public static final int NO_ORIENTATION = 2;
+
+ /**
+ * Gets the value of the Adjustable.
+ *
+ * @return the current value of the Adjustable.
+ */
+ public int getValue();
+
+ /**
+ * Sets the value to the Adjustable object.
+ *
+ * @param a0 the new value of the Adjustable object.
+ */
+ public void setValue(int a0);
+
+ /**
+ * Adds the AdjustmentListener to current Adjustment.
+ *
+ * @param a0 the AdjustmentListener object.
+ */
+ public void addAdjustmentListener(AdjustmentListener a0);
+
+ /**
+ * Gets the block increment of the Adjustable.
+ *
+ * @return the block increment of the Adjustable.
+ */
+ public int getBlockIncrement();
+
+ /**
+ * Gets the maximum value of the Adjustable.
+ *
+ * @return the maximum value of the Adjustable.
+ */
+ public int getMaximum();
+
+ /**
+ * Gets the minimum value of the Adjustable.
+ *
+ * @return the minimum value of the Adjustable.
+ */
+ public int getMinimum();
+
+ /**
+ * Gets the orientation of the Adjustable.
+ *
+ * @return the orientation of the Adjustable.
+ */
+ public int getOrientation();
+
+ /**
+ * Gets the unit increment of the Adjustable.
+ *
+ * @return the unit increment of the Adjustable.
+ */
+ public int getUnitIncrement();
+
+ /**
+ * Gets the visible amount of the Adjustable.
+ *
+ * @return the visible amount of the Adjustable.
+ */
+ public int getVisibleAmount();
+
+ /**
+ * Removes the adjustment listener of the Adjustable.
+ *
+ * @param a0 the specified AdjustmentListener to be removed.
+ */
+ public void removeAdjustmentListener(AdjustmentListener a0);
+
+ /**
+ * Sets the block increment for the Adjustable.
+ *
+ * @param a0 the new block increment.
+ */
+ public void setBlockIncrement(int a0);
+
+ /**
+ * Sets the maximum value of the Adjustable.
+ *
+ * @param a0 the new maximum of the Adjustable.
+ */
+ public void setMaximum(int a0);
+
+ /**
+ * Sets the minimum value of the Adjustable.
+ *
+ * @param a0 the new minimum of the Adjustable.
+ */
+ public void setMinimum(int a0);
+
+ /**
+ * Sets the unit increment of the Adjustable.
+ *
+ * @param a0 the new unit increment of the Adjustable.
+ */
+ public void setUnitIncrement(int a0);
+
+ /**
+ * Sets the visible amount of the Adjustable.
+ *
+ * @param a0 the new visible amount of the Adjustable.
+ */
+ public void setVisibleAmount(int a0);
+
+}
+
diff --git a/awt/java/awt/AlphaComposite.java b/awt/java/awt/AlphaComposite.java
new file mode 100644
index 0000000..d26753c
--- /dev/null
+++ b/awt/java/awt/AlphaComposite.java
@@ -0,0 +1,315 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.RenderingHints;
+import java.awt.image.ColorModel;
+
+import org.apache.harmony.awt.gl.ICompositeContext;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * The AlphaComposite class defines a basic alpha compositing rules for
+ * combining source and destination colors to achieve blending and
+ * transparency effects with graphics and images.
+ */
+public final class AlphaComposite implements Composite {
+
+ /**
+ * The Constant CLEAR indicates that both the color and the alpha of
+ * the destination are cleared (Porter-Duff Clear rule).
+ */
+ public static final int CLEAR = 1;
+
+ /**
+ * The Constant SRC indicates that the source is copied to the destination
+ * (Porter-Duff Source rule).
+ */
+ public static final int SRC = 2;
+
+ /** The Constant DST indicates that the destination is left untouched
+ * (Porter-Duff Destination rule).
+ */
+ public static final int DST = 9;
+
+ /**
+ * The Constant SRC_OVER indicates that the source is composited over
+ * the destination (Porter-Duff Source Over Destination rule).
+ */
+ public static final int SRC_OVER = 3;
+
+ /**
+ * The Constant DST_OVER indicates that The destination is composited over
+ * the source and the result replaces the destination
+ * (Porter-Duff Destination Over Source rule).
+ */
+ public static final int DST_OVER = 4;
+
+ /**
+ * The Constant SRC_IN indicates that the part of the source lying
+ * inside of the destination replaces the destination (Porter-Duff
+ * Source In Destination rule).
+ */
+ public static final int SRC_IN = 5;
+
+ /**
+ * The Constant DST_IN indicates that the part of the destination
+ * lying inside of the source replaces the destination
+ * (Porter-Duff Destination In Source rule).
+ */
+ public static final int DST_IN = 6;
+
+ /**
+ * The Constant SRC_OUT indicates that the part of the source lying
+ * outside of the destination replaces the destination (Porter-Duff
+ * Source Held Out By Destination rule).
+ */
+ public static final int SRC_OUT = 7;
+
+ /**
+ * The Constant DST_OUT indicates that the part of the destination
+ * lying outside of the source replaces the destination (Porter-Duff
+ * Destination Held Out By Source rule).
+ */
+ public static final int DST_OUT = 8;
+
+ /**
+ * The Constant SRC_ATOP indicates that the part of the source lying
+ * inside of the destination is composited onto the destination
+ * (Porter-Duff Source Atop Destination rule).
+ */
+ public static final int SRC_ATOP = 10;
+
+ /**
+ * The Constant DST_ATOP indicates that the part of the destination
+ * lying inside of the source is composited over the source and replaces
+ * the destination (Porter-Duff Destination Atop Source rule).
+ */
+ public static final int DST_ATOP = 11;
+
+ /**
+ * The Constant XOR indicates that the part of the source that lies
+ * outside of the destination is combined with the part of the destination
+ * that lies outside of the source (Porter-Duff Source Xor Destination rule).
+ */
+ public static final int XOR = 12;
+
+ /** AlphaComposite object with the opaque CLEAR rule and an alpha of 1.0f. */
+ public static final AlphaComposite Clear = new AlphaComposite(CLEAR);
+
+ /** AlphaComposite object with the opaque SRC rule and an alpha of 1.0f. */
+ public static final AlphaComposite Src = new AlphaComposite(SRC);
+
+ /** AlphaComposite object with the opaque DST rule and an alpha of 1.0f. */
+ public static final AlphaComposite Dst = new AlphaComposite(DST);
+
+ /** AlphaComposite object with the opaque SRC_OVER rule and an alpha of 1.0f. */
+ public static final AlphaComposite SrcOver = new AlphaComposite(SRC_OVER);
+
+ /** AlphaComposite object with the opaque DST_OVER rule and an alpha of 1.0f. */
+ public static final AlphaComposite DstOver = new AlphaComposite(DST_OVER);
+
+ /** AlphaComposite object with the opaque SRC_IN rule and an alpha of 1.0f. */
+ public static final AlphaComposite SrcIn = new AlphaComposite(SRC_IN);
+
+ /** AlphaComposite object with the opaque DST_IN rule and an alpha of 1.0f. */
+ public static final AlphaComposite DstIn = new AlphaComposite(DST_IN);
+
+ /** AlphaComposite object with the opaque SRC_OUT rule and an alpha of 1.0f. */
+ public static final AlphaComposite SrcOut = new AlphaComposite(SRC_OUT);
+
+ /** AlphaComposite object with the opaque DST_OUT rule and an alpha of 1.0f. */
+ public static final AlphaComposite DstOut = new AlphaComposite(DST_OUT);
+
+ /** AlphaComposite object with the opaque SRC_ATOP rule and an alpha of 1.0f. */
+ public static final AlphaComposite SrcAtop = new AlphaComposite(SRC_ATOP);
+
+ /** AlphaComposite object with the opaque DST_ATOP rule and an alpha of 1.0f. */
+ public static final AlphaComposite DstAtop = new AlphaComposite(DST_ATOP);
+
+ /** AlphaComposite object with the opaque XOR rule and an alpha of 1.0f. */
+ public static final AlphaComposite Xor = new AlphaComposite(XOR);
+
+ /** The rule. */
+ private int rule;
+
+ /** The alpha. */
+ private float alpha;
+
+ /**
+ * Instantiates a new alpha composite.
+ * Creates a context for the compositing operation. The context contains state that is used in performing the compositing operation.
+ *
+ * @param rule the rule
+ * @param alpha the alpha
+ */
+ private AlphaComposite(int rule, float alpha){
+ if(rule < CLEAR || rule > XOR) {
+ // awt.11D=Unknown rule
+ throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$
+ }
+ if(alpha < 0.0f || alpha > 1.0f) {
+ // awt.11E=Wrong alpha value
+ throw new IllegalArgumentException(Messages.getString("awt.11E")); //$NON-NLS-1$
+ }
+
+ this.rule = rule;
+ this.alpha = alpha;
+ }
+
+ /**
+ * Instantiates a new alpha composite.
+ *
+ * @param rule the rule
+ */
+ private AlphaComposite(int rule){
+ this(rule, 1.0f);
+ }
+
+ /**
+ * Creates a CompositeContext object with the specified source ColorModel,
+ * destination ColorModel and RenderingHints parameters for a composing
+ * operation.
+ *
+ * @param srcColorModel the source's ColorModel.
+ * @param dstColorModel the destination's ColorModel.
+ * @param hints the RenderingHints object.
+ *
+ * @return the CompositeContext object.
+ *
+ * @see java.awt.Composite#createContext(java.awt.image.ColorModel, java.awt.image.ColorModel, java.awt.RenderingHints)
+ */
+ public CompositeContext createContext(ColorModel srcColorModel,
+ ColorModel dstColorModel, RenderingHints hints) {
+ return new ICompositeContext(this, srcColorModel, dstColorModel);
+ }
+
+ /**
+ * Compares the AlphaComposite object with the specified object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the AlphaComposite object is equal to the specified
+ * object.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if(!(obj instanceof AlphaComposite)) {
+ return false;
+ }
+ AlphaComposite other = (AlphaComposite)obj;
+ return (this.rule == other.getRule() && this.alpha == other.getAlpha());
+ }
+
+ /**
+ * Returns the hash code of the AlphaComposite object.
+ *
+ * @return the hash code of the AlphaComposite object.
+ */
+ @Override
+ public int hashCode() {
+ int hash = Float.floatToIntBits(alpha);
+ int tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= rule;
+ return hash;
+ }
+
+ /**
+ * Gets the compositing rule of this AlphaComposite object.
+ *
+ * @return the compositing rule of this AlphaComposite object.
+ */
+ public int getRule() {
+ return rule;
+ }
+
+ /**
+ * Gets the alpha value of this AlphaComposite object; returns 1.0 if
+ * this AlphaComposite object doesn't have alpha value.
+ *
+ * @return the alpha value of this AlphaComposite object or 1.0 if
+ * this AlphaComposite object doesn't have alpha value.
+ */
+ public float getAlpha() {
+ return alpha;
+ }
+
+ /**
+ * Gets the AlphaComposite instance with the specified rule and alpha value.
+ *
+ * @param rule the compositing rule.
+ * @param alpha the alpha value.
+ *
+ * @return AlphaComposite instance.
+ */
+ public static AlphaComposite getInstance(int rule, float alpha) {
+ if(alpha == 1.0f) {
+ return getInstance(rule);
+ }
+ return new AlphaComposite(rule, alpha);
+ }
+
+ /**
+ * Gets the AlphaComposite instance with the specified rule.
+ *
+ * @param rule the compositing rule.
+ *
+ * @return AlphaComposite instance.
+ */
+ public static AlphaComposite getInstance(int rule) {
+ switch(rule){
+ case CLEAR:
+ return Clear;
+ case SRC:
+ return Src;
+ case DST:
+ return Dst;
+ case SRC_OVER:
+ return SrcOver;
+ case DST_OVER:
+ return DstOver;
+ case SRC_IN:
+ return SrcIn;
+ case DST_IN:
+ return DstIn;
+ case SRC_OUT:
+ return SrcOut;
+ case DST_OUT:
+ return DstOut;
+ case SRC_ATOP:
+ return SrcAtop;
+ case DST_ATOP:
+ return DstAtop;
+ case XOR:
+ return Xor;
+ default:
+ // awt.11D=Unknown rule
+ throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/BasicStroke.java b/awt/java/awt/BasicStroke.java
new file mode 100644
index 0000000..955dc6b
--- /dev/null
+++ b/awt/java/awt/BasicStroke.java
@@ -0,0 +1,2204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.GeneralPath;
+import java.awt.geom.PathIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The BasicStroke class specifies a set of rendering attributes for the outlines
+ * of graphics primitives. The BasicStroke attributes describe the shape of the
+ * pen which draws the outline of a Shape and the decorations applied at the ends
+ * and joins of path segments of the Shape. The BasicStroke has the following
+ * rendering attributes:
+ * <p>
+ * <ul>
+ * <li> line width -the pen width which draws the outlines.</li>
+ * <li> end caps - indicates the decoration applied to the ends of unclosed
+ * subpaths and dash segments. The BasicStroke defines three different decorations:
+ * CAP_BUTT, CAP_ROUND, and CAP_SQUARE.</li>
+ * <li>line joins - indicates the decoration applied at the intersection of
+ * two path segments and at the intersection of the endpoints of a subpath.
+ * The BasicStroke defines three decorations: JOIN_BEVEL, JOIN_MITER,
+ * and JOIN_ROUND.</li>
+ * <li>miter limit - the limit to trim a line join that has a JOIN_MITER
+ * decoration.</li>
+ * <li>dash attributes - the definition of how to make a dash pattern by
+ * alternating between opaque and transparent sections </li>
+ * </ul>
+ */
+public class BasicStroke implements Stroke {
+
+ /**
+ * The Constant CAP_BUTT indicates the ends of unclosed subpaths
+ * and dash segments have no added decoration.
+ */
+ public static final int CAP_BUTT = 0;
+
+ /**
+ * The Constant CAP_ROUND indicates the ends of unclosed subpaths
+ * and dash segments have a round decoration.
+ */
+ public static final int CAP_ROUND = 1;
+
+ /**
+ * The Constant CAP_SQUARE indicates the ends of unclosed subpaths
+ * and dash segments have a square projection.
+ */
+ public static final int CAP_SQUARE = 2;
+
+ /**
+ * The Constant JOIN_MITER indicates that path segments are joined by
+ * extending their outside edges until they meet.
+ */
+ public static final int JOIN_MITER = 0;
+
+ /**
+ * The Constant JOIN_ROUND indicates that path segments are joined by
+ * rounding off the corner at a radius of half the line width.
+ */
+ public static final int JOIN_ROUND = 1;
+
+ /**
+ * The Constant JOIN_BEVEL indicates that path segments are joined by
+ * connecting the outer corners of their wide outlines with
+ * a straight segment.
+ */
+ public static final int JOIN_BEVEL = 2;
+
+ /** Constants for calculating. */
+ static final int MAX_LEVEL = 20; // Maximal deepness of curve subdivision
+
+ /** The Constant CURVE_DELTA. */
+ static final double CURVE_DELTA = 2.0; // Width tolerance
+
+ /** The Constant CORNER_ANGLE. */
+ static final double CORNER_ANGLE = 4.0; // Minimum corner angle
+
+ /** The Constant CORNER_ZERO. */
+ static final double CORNER_ZERO = 0.01; // Zero angle
+
+ /** The Constant CUBIC_ARC. */
+ static final double CUBIC_ARC = 4.0 / 3.0 * (Math.sqrt(2.0) - 1);
+
+ /** Stroke width. */
+ float width;
+
+ /** Stroke cap type. */
+ int cap;
+
+ /** Stroke join type. */
+ int join;
+
+ /** Stroke miter limit. */
+ float miterLimit;
+
+ /** Stroke dashes array. */
+ float dash[];
+
+ /** Stroke dash phase. */
+ float dashPhase;
+
+ /** The temporary pre-calculated values. */
+ double curveDelta;
+
+ /** The corner delta. */
+ double cornerDelta;
+
+ /** The zero delta. */
+ double zeroDelta;
+
+ /** The w2. */
+ double w2;
+
+ /** The fmy. */
+ double fmx, fmy;
+
+ /** The smy. */
+ double scx, scy, smx, smy;
+
+ /** The cy. */
+ double mx, my, cx, cy;
+
+ /** The temporary indicators. */
+ boolean isMove;
+
+ /** The is first. */
+ boolean isFirst;
+
+ /** The check move. */
+ boolean checkMove;
+
+ /** The temporary and destination work paths. */
+ BufferedPath dst, lp, rp, sp;
+
+ /** Stroke dasher class. */
+ Dasher dasher;
+
+ /**
+ * Instantiates a new BasicStroke with default width, cap, join, limit,
+ * dash attributes parameters. The default parameters are a solid line of
+ * width 1.0, CAP_SQUARE, JOIN_MITER, a miter limit of 10.0, null dash attributes,
+ * and a dash phase of 0.0f.
+ */
+ public BasicStroke() {
+ this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
+ }
+
+ /**
+ * Instantiates a new BasicStroke with the specified width,
+ * caps, joins, limit, dash attributes, dash phase parameters.
+ *
+ * @param width the width of BasikStroke.
+ * @param cap the end decoration of BasikStroke.
+ * @param join the join segments decoration.
+ * @param miterLimit the limit to trim the miter join.
+ * @param dash the array with the dashing pattern.
+ * @param dashPhase the offset to start the dashing pattern.
+ */
+ public BasicStroke(float width, int cap, int join, float miterLimit, float[] dash, float dashPhase) {
+ if (width < 0.0f) {
+ // awt.133=Negative width
+ throw new IllegalArgumentException(Messages.getString("awt.133")); //$NON-NLS-1$
+ }
+ if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) {
+ // awt.134=Illegal cap
+ throw new IllegalArgumentException(Messages.getString("awt.134")); //$NON-NLS-1$
+ }
+ if (join != JOIN_MITER && join != JOIN_ROUND && join != JOIN_BEVEL) {
+ // awt.135=Illegal join
+ throw new IllegalArgumentException(Messages.getString("awt.135")); //$NON-NLS-1$
+ }
+ if (join == JOIN_MITER && miterLimit < 1.0f) {
+ // awt.136=miterLimit less than 1.0f
+ throw new IllegalArgumentException(Messages.getString("awt.136")); //$NON-NLS-1$
+ }
+ if (dash != null) {
+ if (dashPhase < 0.0f) {
+ // awt.137=Negative dashPhase
+ throw new IllegalArgumentException(Messages.getString("awt.137")); //$NON-NLS-1$
+ }
+ if (dash.length == 0) {
+ // awt.138=Zero dash length
+ throw new IllegalArgumentException(Messages.getString("awt.138")); //$NON-NLS-1$
+ }
+ ZERO: {
+ for(int i = 0; i < dash.length; i++) {
+ if (dash[i] < 0.0) {
+ // awt.139=Negative dash[{0}]
+ throw new IllegalArgumentException(Messages.getString("awt.139", i)); //$NON-NLS-1$
+ }
+ if (dash[i] > 0.0) {
+ break ZERO;
+ }
+ }
+ // awt.13A=All dash lengths zero
+ throw new IllegalArgumentException(Messages.getString("awt.13A")); //$NON-NLS-1$
+ }
+ }
+ this.width = width;
+ this.cap = cap;
+ this.join = join;
+ this.miterLimit = miterLimit;
+ this.dash = dash;
+ this.dashPhase = dashPhase;
+ }
+
+ /**
+ * Instantiates a new BasicStroke with specified width, cap, join, limit
+ * and default dash attributes parameters.
+ *
+ * @param width the width of BasikStroke.
+ * @param cap the end decoration of BasikStroke.
+ * @param join the join segments decoration.
+ * @param miterLimit the limit to trim the miter join.
+ */
+ public BasicStroke(float width, int cap, int join, float miterLimit) {
+ this(width, cap, join, miterLimit, null, 0.0f);
+ }
+
+ /**
+ * Instantiates a new BasicStroke with specified width, cap, join
+ * and default limit and dash attributes parameters.
+ *
+ * @param width the width of BasikStroke.
+ * @param cap the end decoration of BasikStroke.
+ * @param join the join segments decoration.
+ */
+ public BasicStroke(float width, int cap, int join) {
+ this(width, cap, join, 10.0f, null, 0.0f);
+ }
+
+ /**
+ * Instantiates a new BasicStroke with specified width and default cap, join,
+ * limit, dash attributes parameters.
+ *
+ * @param width the width of BasicStroke.
+ */
+ public BasicStroke(float width) {
+ this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
+ }
+
+ /**
+ * Gets the line width of the BasicStroke.
+ *
+ * @return the line width of the BasicStroke.
+ */
+ public float getLineWidth() {
+ return width;
+ }
+
+ /**
+ * Gets the end cap style of the BasicStroke.
+ *
+ * @return the end cap style of the BasicStroke.
+ */
+ public int getEndCap() {
+ return cap;
+ }
+
+ /**
+ * Gets the line join style of the BasicStroke.
+ *
+ * @return the line join style of the BasicStroke.
+ */
+ public int getLineJoin() {
+ return join;
+ }
+
+ /**
+ * Gets the miter limit of the BasicStroke (the limit to trim the miter join).
+ *
+ * @return the miter limit of the BasicStroke.
+ */
+ public float getMiterLimit() {
+ return miterLimit;
+ }
+
+ /**
+ * Gets the dash attributes array of the BasicStroke.
+ *
+ * @return the dash attributes array of the BasicStroke.
+ */
+ public float[] getDashArray() {
+ return dash;
+ }
+
+ /**
+ * Gets the dash phase of the BasicStroke.
+ *
+ * @return the dash phase of the BasicStroke.
+ */
+ public float getDashPhase() {
+ return dashPhase;
+ }
+
+ /**
+ * Returns hash code of this BasicStroke.
+ *
+ * @return the hash code of this BasicStroke.
+ */
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(width);
+ hash.append(cap);
+ hash.append(join);
+ hash.append(miterLimit);
+ if (dash != null) {
+ hash.append(dashPhase);
+ for (float element : dash) {
+ hash.append(element);
+ }
+ }
+ return hash.hashCode();
+ }
+
+ /**
+ * Compares this BasicStroke object with the specified Object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the Object is a BasicStroke with the same data
+ * values as this BasicStroke; false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof BasicStroke) {
+ BasicStroke bs = (BasicStroke)obj;
+ return
+ bs.width == width &&
+ bs.cap == cap &&
+ bs.join == join &&
+ bs.miterLimit == miterLimit &&
+ bs.dashPhase == dashPhase &&
+ java.util.Arrays.equals(bs.dash, dash);
+ }
+ return false;
+ }
+
+ /**
+ * Calculates allowable curve derivation.
+ *
+ * @param width the width
+ *
+ * @return the curve delta
+ */
+ double getCurveDelta(double width) {
+ double a = width + CURVE_DELTA;
+ double cos = 1.0 - 2.0 * width * width / (a * a);
+ double sin = Math.sqrt(1.0 - cos * cos);
+ return Math.abs(sin / cos);
+ }
+
+ /**
+ * Calculates the value to detect a small angle.
+ *
+ * @param width the width
+ *
+ * @return the corner delta
+ */
+ double getCornerDelta(double width) {
+ return width * width * Math.sin(Math.PI * CORNER_ANGLE / 180.0);
+ }
+
+ /**
+ * Calculates value to detect a zero angle.
+ *
+ * @param width the width
+ *
+ * @return the zero delta
+ */
+ double getZeroDelta(double width) {
+ return width * width * Math.sin(Math.PI * CORNER_ZERO / 180.0);
+ }
+
+ /**
+ * Creates a Shape from the outline of the specified shape
+ * drawn with this BasicStroke.
+ *
+ * @param s the specified Shape to be stroked.
+ *
+ * @return the Shape of the stroked outline.
+ *
+ * @see java.awt.Stroke#createStrokedShape(java.awt.Shape)
+ */
+ public Shape createStrokedShape(Shape s) {
+ w2 = width / 2.0;
+ curveDelta = getCurveDelta(w2);
+ cornerDelta = getCornerDelta(w2);
+ zeroDelta = getZeroDelta(w2);
+
+ dst = new BufferedPath();
+ lp = new BufferedPath();
+ rp = new BufferedPath();
+
+ if (dash == null) {
+ createSolidShape(s.getPathIterator(null));
+ } else {
+ createDashedShape(s.getPathIterator(null));
+ }
+
+ return dst.createGeneralPath();
+ }
+
+ /**
+ * Generates a shape with a solid (not dashed) outline.
+ *
+ * @param p - the PathIterator of source shape
+ */
+ void createSolidShape(PathIterator p) {
+ double coords[] = new double[6];
+ mx = my = cx = cy = 0.0;
+ isMove = false;
+ isFirst = false;
+ checkMove = true;
+ boolean isClosed = true;
+
+ while(!p.isDone()) {
+ switch(p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (!isClosed) {
+ closeSolidShape();
+ }
+ rp.clean();
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ isMove = true;
+ isClosed = false;
+ break;
+ case PathIterator.SEG_LINETO:
+ addLine(cx, cy, cx = coords[0], cy = coords[1], true);
+ break;
+ case PathIterator.SEG_QUADTO:
+ addQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ addCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ addLine(cx, cy, mx, my, false);
+ addJoin(lp, mx, my, lp.xMove, lp.yMove, true);
+ addJoin(rp, mx, my, rp.xMove, rp.yMove, false);
+ lp.closePath();
+ rp.closePath();
+ lp.appendReverse(rp);
+ isClosed = true;
+ break;
+ }
+ p.next();
+ }
+ if (!isClosed) {
+ closeSolidShape();
+ }
+
+ dst = lp;
+ }
+
+ /**
+ * Closes solid shape path.
+ */
+ void closeSolidShape() {
+ addCap(lp, cx, cy, rp.xLast, rp.yLast);
+ lp.combine(rp);
+ addCap(lp, mx, my, lp.xMove, lp.yMove);
+ lp.closePath();
+ }
+
+ /**
+ * Generates dashed stroked shape.
+ *
+ * @param p - the PathIterator of source shape
+ */
+ void createDashedShape(PathIterator p) {
+ double coords[] = new double[6];
+ mx = my = cx = cy = 0.0;
+ smx = smy = scx = scy = 0.0;
+ isMove = false;
+ checkMove = false;
+ boolean isClosed = true;
+
+ while(!p.isDone()) {
+ switch(p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+
+ if (!isClosed) {
+ closeDashedShape();
+ }
+
+ dasher = new Dasher(dash, dashPhase);
+ lp.clean();
+ rp.clean();
+ sp = null;
+ isFirst = true;
+ isMove = true;
+ isClosed = false;
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ break;
+ case PathIterator.SEG_LINETO:
+ addDashLine(cx, cy, cx = coords[0], cy = coords[1]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ addDashQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ addDashCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ addDashLine(cx, cy, cx = mx, cy = my);
+
+ if (dasher.isConnected()) {
+ // Connect current and head segments
+ addJoin(lp, fmx, fmy, sp.xMove, sp.yMove, true);
+ lp.join(sp);
+ addJoin(lp, fmx, fmy, rp.xLast, rp.yLast, true);
+ lp.combine(rp);
+ addCap(lp, smx, smy, lp.xMove, lp.yMove);
+ lp.closePath();
+ dst.append(lp);
+ sp = null;
+ } else {
+ closeDashedShape();
+ }
+
+ isClosed = true;
+ break;
+ }
+ p.next();
+ }
+
+ if (!isClosed) {
+ closeDashedShape();
+ }
+
+ }
+
+ /**
+ * Closes dashed shape path.
+ */
+ void closeDashedShape() {
+ // Add head segment
+ if (sp != null) {
+ addCap(sp, fmx, fmy, sp.xMove, sp.yMove);
+ sp.closePath();
+ dst.append(sp);
+ }
+ if (lp.typeSize > 0) {
+ // Close current segment
+ if (!dasher.isClosed()) {
+ addCap(lp, scx, scy, rp.xLast, rp.yLast);
+ lp.combine(rp);
+ addCap(lp, smx, smy, lp.xMove, lp.yMove);
+ lp.closePath();
+ }
+ dst.append(lp);
+ }
+ }
+
+ /**
+ * Adds cap to the work path.
+ *
+ * @param p - the BufferedPath object of work path
+ * @param x0 - the x coordinate of the source path
+ * @param y0 - the y coordinate on the source path
+ * @param x2 - the x coordinate of the next point on the work path
+ * @param y2 - the y coordinate of the next point on the work path
+ */
+ void addCap(BufferedPath p, double x0, double y0, double x2, double y2) {
+ double x1 = p.xLast;
+ double y1 = p.yLast;
+ double x10 = x1 - x0;
+ double y10 = y1 - y0;
+ double x20 = x2 - x0;
+ double y20 = y2 - y0;
+
+ switch(cap) {
+ case CAP_BUTT:
+ p.lineTo(x2, y2);
+ break;
+ case CAP_ROUND:
+ double mx = x10 * CUBIC_ARC;
+ double my = y10 * CUBIC_ARC;
+
+ double x3 = x0 + y10;
+ double y3 = y0 - x10;
+
+ x10 *= CUBIC_ARC;
+ y10 *= CUBIC_ARC;
+ x20 *= CUBIC_ARC;
+ y20 *= CUBIC_ARC;
+
+ p.cubicTo(x1 + y10, y1 - x10, x3 + mx, y3 + my, x3, y3);
+ p.cubicTo(x3 - mx, y3 - my, x2 - y20, y2 + x20, x2, y2);
+ break;
+ case CAP_SQUARE:
+ p.lineTo(x1 + y10, y1 - x10);
+ p.lineTo(x2 - y20, y2 + x20);
+ p.lineTo(x2, y2);
+ break;
+ }
+ }
+
+ /**
+ * Adds bevel and miter join to the work path.
+ *
+ * @param p - the BufferedPath object of work path
+ * @param x0 - the x coordinate of the source path
+ * @param y0 - the y coordinate on the source path
+ * @param x2 - the x coordinate of the next point on the work path
+ * @param y2 - the y coordinate of the next point on the work path
+ * @param isLeft - the orientation of work path, true if work path lies to the left from source path, false otherwise
+ */
+ void addJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) {
+ double x1 = p.xLast;
+ double y1 = p.yLast;
+ double x10 = x1 - x0;
+ double y10 = y1 - y0;
+ double x20 = x2 - x0;
+ double y20 = y2 - y0;
+ double sin0 = x10 * y20 - y10 * x20;
+
+ // Small corner
+ if (-cornerDelta < sin0 && sin0 < cornerDelta) {
+ double cos0 = x10 * x20 + y10 * y20;
+ if (cos0 > 0.0) {
+ // if zero corner do nothing
+ if (-zeroDelta > sin0 || sin0 > zeroDelta) {
+ double x3 = x0 + w2 * w2 * (y20 - y10) / sin0;
+ double y3 = y0 + w2 * w2 * (x10 - x20) / sin0;
+ p.setLast(x3, y3);
+ }
+ return;
+ }
+ // Zero corner
+ if (-zeroDelta < sin0 && sin0 < zeroDelta) {
+ p.lineTo(x2, y2);
+ }
+ return;
+ }
+
+ if (isLeft ^ (sin0 < 0.0)) {
+ // Twisted corner
+ p.lineTo(x0, y0);
+ p.lineTo(x2, y2);
+ } else {
+ switch(join) {
+ case JOIN_BEVEL:
+ p.lineTo(x2, y2);
+ break;
+ case JOIN_MITER:
+ double s1 = x1 * x10 + y1 * y10;
+ double s2 = x2 * x20 + y2 * y20;
+ double x3 = (s1 * y20 - s2 * y10) / sin0;
+ double y3 = (s2 * x10 - s1 * x20) / sin0;
+ double x30 = x3 - x0;
+ double y30 = y3 - y0;
+ double miterLength = Math.sqrt(x30 * x30 + y30 * y30);
+ if (miterLength < miterLimit * w2) {
+ p.lineTo(x3, y3);
+ }
+ p.lineTo(x2, y2);
+ break;
+ case JOIN_ROUND:
+ addRoundJoin(p, x0, y0, x2, y2, isLeft);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Adds round join to the work path.
+ *
+ * @param p - the BufferedPath object of work path
+ * @param x0 - the x coordinate of the source path
+ * @param y0 - the y coordinate on the source path
+ * @param x2 - the x coordinate of the next point on the work path
+ * @param y2 - the y coordinate of the next point on the work path
+ * @param isLeft - the orientation of work path, true if work path lies to the left from source path, false otherwise
+ */
+ void addRoundJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) {
+ double x1 = p.xLast;
+ double y1 = p.yLast;
+ double x10 = x1 - x0;
+ double y10 = y1 - y0;
+ double x20 = x2 - x0;
+ double y20 = y2 - y0;
+
+ double x30 = x10 + x20;
+ double y30 = y10 + y20;
+
+ double l30 = Math.sqrt(x30 * x30 + y30 * y30);
+
+ if (l30 < 1E-5) {
+ p.lineTo(x2, y2);
+ return;
+ }
+
+ double w = w2 / l30;
+
+ x30 *= w;
+ y30 *= w;
+
+ double x3 = x0 + x30;
+ double y3 = y0 + y30;
+
+ double cos = x10 * x20 + y10 * y20;
+ double a = Math.acos(cos / (w2 * w2));
+ if (cos >= 0.0) {
+ double k = 4.0 / 3.0 * Math.tan(a / 4.0);
+ if (isLeft) {
+ k = -k;
+ }
+
+ x10 *= k;
+ y10 *= k;
+ x20 *= k;
+ y20 *= k;
+
+ p.cubicTo(x1 - y10, y1 + x10, x2 + y20, y2 - x20, x2, y2);
+ } else {
+ double k = 4.0 / 3.0 * Math.tan(a / 8.0);
+ if (isLeft) {
+ k = -k;
+ }
+
+ x10 *= k;
+ y10 *= k;
+ x20 *= k;
+ y20 *= k;
+ x30 *= k;
+ y30 *= k;
+
+ p.cubicTo(x1 - y10, y1 + x10, x3 + y30, y3 - x30, x3, y3);
+ p.cubicTo(x3 - y30, y3 + x30, x2 + y20, y2 - x20, x2, y2);
+ }
+
+ }
+
+ /**
+ * Adds solid line segment to the work path.
+ *
+ * @param x1 - the x coordinate of the start line point
+ * @param y1 - the y coordinate of the start line point
+ * @param x2 - the x coordinate of the end line point
+ * @param y2 - the y coordinate of the end line point
+ * @param zero - if true it's allowable to add zero length line segment
+ */
+ void addLine(double x1, double y1, double x2, double y2, boolean zero) {
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+
+ if (dx == 0.0 && dy == 0.0) {
+ if (!zero) {
+ return;
+ }
+ dx = w2;
+ dy = 0;
+ } else {
+ double w = w2 / Math.sqrt(dx * dx + dy * dy);
+ dx *= w;
+ dy *= w;
+ }
+
+ double lx1 = x1 - dy;
+ double ly1 = y1 + dx;
+ double rx1 = x1 + dy;
+ double ry1 = y1 - dx;
+
+ if (checkMove) {
+ if (isMove) {
+ isMove = false;
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ }
+
+ lp.lineTo(x2 - dy, y2 + dx);
+ rp.lineTo(x2 + dy, y2 - dx);
+ }
+
+ /**
+ * Adds solid quad segment to the work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ */
+ void addQuad(double x1, double y1, double x2, double y2, double x3, double y3) {
+ double x21 = x2 - x1;
+ double y21 = y2 - y1;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+
+ double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+
+ if (l21 == 0.0 && l23 == 0.0) {
+ addLine(x1, y1, x3, y3, false);
+ return;
+ }
+
+ if (l21 == 0.0) {
+ addLine(x2, y2, x3, y3, false);
+ return;
+ }
+
+ if (l23 == 0.0) {
+ addLine(x1, y1, x2, y2, false);
+ return;
+ }
+
+ double w;
+ w = w2 / l21;
+ double mx1 = - y21 * w;
+ double my1 = x21 * w;
+ w = w2 / l23;
+ double mx3 = y23 * w;
+ double my3 = - x23 * w;
+
+ double lx1 = x1 + mx1;
+ double ly1 = y1 + my1;
+ double rx1 = x1 - mx1;
+ double ry1 = y1 - my1;
+
+ if (checkMove) {
+ if (isMove) {
+ isMove = false;
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ }
+
+ if (x21 * y23 - y21 * x23 == 0.0) {
+ // On line curve
+ if (x21 * x23 + y21 * y23 > 0.0) {
+ // Twisted curve
+ if (l21 == l23) {
+ double px = x1 + (x21 + x23) / 4.0;
+ double py = y1 + (y21 + y23) / 4.0;
+ lp.lineTo(px + mx1, py + my1);
+ rp.lineTo(px - mx1, py - my1);
+ lp.lineTo(px - mx1, py - my1);
+ rp.lineTo(px + mx1, py + my1);
+ lp.lineTo(x3 - mx1, y3 - my1);
+ rp.lineTo(x3 + mx1, y3 + my1);
+ } else {
+ double px1, py1;
+ double k = l21 / (l21 + l23);
+ double px = x1 + (x21 + x23) * k * k;
+ double py = y1 + (y21 + y23) * k * k;
+ px1 = (x1 + px) / 2.0;
+ py1 = (y1 + py) / 2.0;
+ lp.quadTo(px1 + mx1, py1 + my1, px + mx1, py + my1);
+ rp.quadTo(px1 - mx1, py1 - my1, px - mx1, py - my1);
+ lp.lineTo(px - mx1, py - my1);
+ rp.lineTo(px + mx1, py + my1);
+ px1 = (x3 + px) / 2.0;
+ py1 = (y3 + py) / 2.0;
+ lp.quadTo(px1 - mx1, py1 - my1, x3 - mx1, y3 - my1);
+ rp.quadTo(px1 + mx1, py1 + my1, x3 + mx1, y3 + my1);
+ }
+ } else {
+ // Simple curve
+ lp.quadTo(x2 + mx1, y2 + my1, x3 + mx3, y3 + my3);
+ rp.quadTo(x2 - mx1, y2 - my1, x3 - mx3, y3 - my3);
+ }
+ } else {
+ addSubQuad(x1, y1, x2, y2, x3, y3, 0);
+ }
+ }
+
+ /**
+ * Subdivides solid quad curve to make outline for source quad segment and adds it to work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ * @param level - the maximum level of subdivision deepness
+ */
+ void addSubQuad(double x1, double y1, double x2, double y2, double x3, double y3, int level) {
+ double x21 = x2 - x1;
+ double y21 = y2 - y1;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+
+ double cos = x21 * x23 + y21 * y23;
+ double sin = x21 * y23 - y21 * x23;
+
+ if (level < MAX_LEVEL && (cos >= 0.0 || (Math.abs(sin / cos) > curveDelta))) {
+ double c1x = (x2 + x1) / 2.0;
+ double c1y = (y2 + y1) / 2.0;
+ double c2x = (x2 + x3) / 2.0;
+ double c2y = (y2 + y3) / 2.0;
+ double c3x = (c1x + c2x) / 2.0;
+ double c3y = (c1y + c2y) / 2.0;
+ addSubQuad(x1, y1, c1x, c1y, c3x, c3y, level + 1);
+ addSubQuad(c3x, c3y, c2x, c2y, x3, y3, level + 1);
+ } else {
+ double w;
+ double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+ w = w2 / sin;
+ double mx2 = (x21 * l23 + x23 * l21) * w;
+ double my2 = (y21 * l23 + y23 * l21) * w;
+ w = w2 / l23;
+ double mx3 = y23 * w;
+ double my3 = - x23 * w;
+ lp.quadTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3);
+ rp.quadTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3);
+ }
+ }
+
+ /**
+ * Adds solid cubic segment to the work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ * @param x4 - the x coordinate of the fours control point
+ * @param y4 - the y coordinate of the fours control point
+ */
+ void addCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
+ double x12 = x1 - x2;
+ double y12 = y1 - y2;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+ double x34 = x3 - x4;
+ double y34 = y3 - y4;
+
+ double l12 = Math.sqrt(x12 * x12 + y12 * y12);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+ double l34 = Math.sqrt(x34 * x34 + y34 * y34);
+
+ // All edges are zero
+ if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) {
+ addLine(x1, y1, x4, y4, false);
+ return;
+ }
+
+ // One zero edge
+ if (l12 == 0.0 && l23 == 0.0) {
+ addLine(x3, y3, x4, y4, false);
+ return;
+ }
+
+ if (l23 == 0.0 && l34 == 0.0) {
+ addLine(x1, y1, x2, y2, false);
+ return;
+ }
+
+ if (l12 == 0.0 && l34 == 0.0) {
+ addLine(x2, y2, x3, y3, false);
+ return;
+ }
+
+ double w, mx1, my1, mx4, my4;
+ boolean onLine;
+
+ if (l12 == 0.0) {
+ w = w2 / l23;
+ mx1 = y23 * w;
+ my1 = - x23 * w;
+ w = w2 / l34;
+ mx4 = y34 * w;
+ my4 = - x34 * w;
+ onLine = - x23 * y34 + y23 * x34 == 0.0; // sin3
+ } else
+ if (l34 == 0.0) {
+ w = w2 / l12;
+ mx1 = y12 * w;
+ my1 = - x12 * w;
+ w = w2 / l23;
+ mx4 = y23 * w;
+ my4 = - x23 * w;
+ onLine = - x12 * y23 + y12 * x23 == 0.0; // sin2
+ } else {
+ w = w2 / l12;
+ mx1 = y12 * w;
+ my1 = - x12 * w;
+ w = w2 / l34;
+ mx4 = y34 * w;
+ my4 = - x34 * w;
+ if (l23 == 0.0) {
+ onLine = - x12 * y34 + y12 * x34 == 0.0;
+ } else {
+ onLine =
+ - x12 * y34 + y12 * x34 == 0.0 &&
+ - x12 * y23 + y12 * x23 == 0.0 && // sin2
+ - x23 * y34 + y23 * x34 == 0.0; // sin3
+ }
+ }
+
+ double lx1 = x1 + mx1;
+ double ly1 = y1 + my1;
+ double rx1 = x1 - mx1;
+ double ry1 = y1 - my1;
+
+ if (checkMove) {
+ if (isMove) {
+ isMove = false;
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ }
+
+ if (onLine) {
+ if ((x1 == x2 && y1 < y2) || x1 < x2) {
+ l12 = -l12;
+ }
+ if ((x2 == x3 && y2 < y3) || x2 < x3) {
+ l23 = -l23;
+ }
+ if ((x3 == x4 && y3 < y4) || x3 < x4) {
+ l34 = -l34;
+ }
+ double d = l23 * l23 - l12 * l34;
+ double roots[] = new double[3];
+ int rc = 0;
+ if (d == 0.0) {
+ double t = (l12 - l23) / (l12 + l34 - l23 - l23);
+ if (0.0 < t && t < 1.0) {
+ roots[rc++] = t;
+ }
+ } else
+ if (d > 0.0) {
+ d = Math.sqrt(d);
+ double z = l12 + l34 - l23 - l23;
+ double t;
+ t = (l12 - l23 + d) / z;
+ if (0.0 < t && t < 1.0) {
+ roots[rc++] = t;
+ }
+ t = (l12 - l23 - d) / z;
+ if (0.0 < t && t < 1.0) {
+ roots[rc++] = t;
+ }
+ }
+
+ if (rc > 0) {
+ // Sort roots
+ if (rc == 2 && roots[0] > roots[1]) {
+ double tmp = roots[0];
+ roots[0] = roots[1];
+ roots[1] = tmp;
+ }
+ roots[rc++] = 1.0;
+
+ double ax = - x34 - x12 + x23 + x23;
+ double ay = - y34 - y12 + y23 + y23;
+ double bx = 3.0 * (- x23 + x12);
+ double by = 3.0 * (- y23 + y12);
+ double cx = 3.0 * (- x12);
+ double cy = 3.0 * (- y12);
+ double xPrev = x1;
+ double yPrev = y1;
+ for(int i = 0; i < rc; i++) {
+ double t = roots[i];
+ double px = t * (t * (t * ax + bx) + cx) + x1;
+ double py = t * (t * (t * ay + by) + cy) + y1;
+ double px1 = (xPrev + px) / 2.0;
+ double py1 = (yPrev + py) / 2.0;
+ lp.cubicTo(px1 + mx1, py1 + my1, px1 + mx1, py1 + my1, px + mx1, py + my1);
+ rp.cubicTo(px1 - mx1, py1 - my1, px1 - mx1, py1 - my1, px - mx1, py - my1);
+ if (i < rc - 1) {
+ lp.lineTo(px - mx1, py - my1);
+ rp.lineTo(px + mx1, py + my1);
+ }
+ xPrev = px;
+ yPrev = py;
+ mx1 = - mx1;
+ my1 = - my1;
+ }
+ } else {
+ lp.cubicTo(x2 + mx1, y2 + my1, x3 + mx4, y3 + my4, x4 + mx4, y4 + my4);
+ rp.cubicTo(x2 - mx1, y2 - my1, x3 - mx4, y3 - my4, x4 - mx4, y4 - my4);
+ }
+ } else {
+ addSubCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0);
+ }
+ }
+
+ /**
+ * Subdivides solid cubic curve to make outline for source quad segment and adds it to work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ * @param x4 - the x coordinate of the fours control point
+ * @param y4 - the y coordinate of the fours control point
+ * @param level - the maximum level of subdivision deepness
+ */
+ void addSubCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, int level) {
+ double x12 = x1 - x2;
+ double y12 = y1 - y2;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+ double x34 = x3 - x4;
+ double y34 = y3 - y4;
+
+ double cos2 = - x12 * x23 - y12 * y23;
+ double cos3 = - x23 * x34 - y23 * y34;
+ double sin2 = - x12 * y23 + y12 * x23;
+ double sin3 = - x23 * y34 + y23 * x34;
+ double sin0 = - x12 * y34 + y12 * x34;
+ double cos0 = - x12 * x34 - y12 * y34;
+
+ if (level < MAX_LEVEL && (sin2 != 0.0 || sin3 != 0.0 || sin0 != 0.0) &&
+ (cos2 >= 0.0 || cos3 >= 0.0 || cos0 >= 0.0 ||
+ (Math.abs(sin2 / cos2) > curveDelta) ||
+ (Math.abs(sin3 / cos3) > curveDelta) ||
+ (Math.abs(sin0 / cos0) > curveDelta)))
+ {
+ double cx = (x2 + x3) / 2.0;
+ double cy = (y2 + y3) / 2.0;
+ double lx2 = (x2 + x1) / 2.0;
+ double ly2 = (y2 + y1) / 2.0;
+ double rx3 = (x3 + x4) / 2.0;
+ double ry3 = (y3 + y4) / 2.0;
+ double lx3 = (cx + lx2) / 2.0;
+ double ly3 = (cy + ly2) / 2.0;
+ double rx2 = (cx + rx3) / 2.0;
+ double ry2 = (cy + ry3) / 2.0;
+ cx = (lx3 + rx2) / 2.0;
+ cy = (ly3 + ry2) / 2.0;
+ addSubCubic(x1, y1, lx2, ly2, lx3, ly3, cx, cy, level + 1);
+ addSubCubic(cx, cy, rx2, ry2, rx3, ry3, x4, y4, level + 1);
+ } else {
+ double w, mx1, my1, mx2, my2, mx3, my3, mx4, my4;
+ double l12 = Math.sqrt(x12 * x12 + y12 * y12);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+ double l34 = Math.sqrt(x34 * x34 + y34 * y34);
+
+ if (l12 == 0.0) {
+ w = w2 / l23;
+ mx1 = y23 * w;
+ my1 = - x23 * w;
+ w = w2 / l34;
+ mx4 = y34 * w;
+ my4 = - x34 * w;
+ } else
+ if (l34 == 0.0) {
+ w = w2 / l12;
+ mx1 = y12 * w;
+ my1 = - x12 * w;
+ w = w2 / l23;
+ mx4 = y23 * w;
+ my4 = - x23 * w;
+ } else {
+ // Common case
+ w = w2 / l12;
+ mx1 = y12 * w;
+ my1 = - x12 * w;
+ w = w2 / l34;
+ mx4 = y34 * w;
+ my4 = - x34 * w;
+ }
+
+ if (sin2 == 0.0) {
+ mx2 = mx1;
+ my2 = my1;
+ } else {
+ w = w2 / sin2;
+ mx2 = -(x12 * l23 - x23 * l12) * w;
+ my2 = -(y12 * l23 - y23 * l12) * w;
+ }
+ if (sin3 == 0.0) {
+ mx3 = mx4;
+ my3 = my4;
+ } else {
+ w = w2 / sin3;
+ mx3 = -(x23 * l34 - x34 * l23) * w;
+ my3 = -(y23 * l34 - y34 * l23) * w;
+ }
+
+ lp.cubicTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3, x4 + mx4, y4 + my4);
+ rp.cubicTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3, x4 - mx4, y4 - my4);
+ }
+ }
+
+ /**
+ * Adds dashed line segment to the work path.
+ *
+ * @param x1 - the x coordinate of the start line point
+ * @param y1 - the y coordinate of the start line point
+ * @param x2 - the x coordinate of the end line point
+ * @param y2 - the y coordinate of the end line point
+ */
+ void addDashLine(double x1, double y1, double x2, double y2) {
+ double x21 = x2 - x1;
+ double y21 = y2 - y1;
+
+ double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+
+ if (l21 == 0.0) {
+ return;
+ }
+
+ double px1, py1;
+ px1 = py1 = 0.0;
+ double w = w2 / l21;
+ double mx = - y21 * w;
+ double my = x21 * w;
+
+ dasher.init(new DashIterator.Line(l21));
+
+ while(!dasher.eof()) {
+ double t = dasher.getValue();
+ scx = x1 + t * x21;
+ scy = y1 + t * y21;
+
+ if (dasher.isOpen()) {
+ px1 = scx;
+ py1 = scy;
+ double lx1 = px1 + mx;
+ double ly1 = py1 + my;
+ double rx1 = px1 - mx;
+ double ry1 = py1 - my;
+ if (isMove) {
+ isMove = false;
+ smx = px1;
+ smy = py1;
+ rp.clean();
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ } else
+ if (dasher.isContinue()) {
+ double px2 = scx;
+ double py2 = scy;
+ lp.lineTo(px2 + mx, py2 + my);
+ rp.lineTo(px2 - mx, py2 - my);
+ if (dasher.close) {
+ addCap(lp, px2, py2, rp.xLast, rp.yLast);
+ lp.combine(rp);
+ if (isFirst) {
+ isFirst = false;
+ fmx = smx;
+ fmy = smy;
+ sp = lp;
+ lp = new BufferedPath();
+ } else {
+ addCap(lp, smx, smy, lp.xMove, lp.yMove);
+ lp.closePath();
+ }
+ isMove = true;
+ }
+ }
+
+ dasher.next();
+ }
+ }
+
+ /**
+ * Adds dashed quad segment to the work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ */
+ void addDashQuad(double x1, double y1, double x2, double y2, double x3, double y3) {
+
+ double x21 = x2 - x1;
+ double y21 = y2 - y1;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+
+ double l21 = Math.sqrt(x21 * x21 + y21 * y21);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+
+ if (l21 == 0.0 && l23 == 0.0) {
+ return;
+ }
+
+ if (l21 == 0.0) {
+ addDashLine(x2, y2, x3, y3);
+ return;
+ }
+
+ if (l23 == 0.0) {
+ addDashLine(x1, y1, x2, y2);
+ return;
+ }
+
+ double ax = x1 + x3 - x2 - x2;
+ double ay = y1 + y3 - y2 - y2;
+ double bx = x2 - x1;
+ double by = y2 - y1;
+ double cx = x1;
+ double cy = y1;
+
+ double px1, py1, dx1, dy1;
+ px1 = py1 = dx1 = dy1 = 0.0;
+ double prev = 0.0;
+
+ dasher.init(new DashIterator.Quad(x1, y1, x2, y2, x3, y3));
+
+ while(!dasher.eof()) {
+ double t = dasher.getValue();
+ double dx = t * ax + bx;
+ double dy = t * ay + by;
+ scx = t * (dx + bx) + cx; // t^2 * ax + 2.0 * t * bx + cx
+ scy = t * (dy + by) + cy; // t^2 * ay + 2.0 * t * by + cy
+ if (dasher.isOpen()) {
+ px1 = scx;
+ py1 = scy;
+ dx1 = dx;
+ dy1 = dy;
+ double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1);
+ double mx1 = - dy1 * w;
+ double my1 = dx1 * w;
+ double lx1 = px1 + mx1;
+ double ly1 = py1 + my1;
+ double rx1 = px1 - mx1;
+ double ry1 = py1 - my1;
+ if (isMove) {
+ isMove = false;
+ smx = px1;
+ smy = py1;
+ rp.clean();
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ } else
+ if (dasher.isContinue()) {
+ double px3 = scx;
+ double py3 = scy;
+ double sx = x2 - x23 * prev;
+ double sy = y2 - y23 * prev;
+ double t2 = (t - prev) / (1 - prev);
+ double px2 = px1 + (sx - px1) * t2;
+ double py2 = py1 + (sy - py1) * t2;
+
+ addQuad(px1, py1, px2, py2, px3, py3);
+ if (dasher.isClosed()) {
+ addCap(lp, px3, py3, rp.xLast, rp.yLast);
+ lp.combine(rp);
+ if (isFirst) {
+ isFirst = false;
+ fmx = smx;
+ fmy = smy;
+ sp = lp;
+ lp = new BufferedPath();
+ } else {
+ addCap(lp, smx, smy, lp.xMove, lp.yMove);
+ lp.closePath();
+ }
+ isMove = true;
+ }
+ }
+
+ prev = t;
+ dasher.next();
+ }
+ }
+
+ /**
+ * Adds dashed cubic segment to the work path.
+ *
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param x3 - the x coordinate of the third control point
+ * @param y3 - the y coordinate of the third control point
+ * @param x4 - the x coordinate of the fours control point
+ * @param y4 - the y coordinate of the fours control point
+ */
+ void addDashCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
+
+ double x12 = x1 - x2;
+ double y12 = y1 - y2;
+ double x23 = x2 - x3;
+ double y23 = y2 - y3;
+ double x34 = x3 - x4;
+ double y34 = y3 - y4;
+
+ double l12 = Math.sqrt(x12 * x12 + y12 * y12);
+ double l23 = Math.sqrt(x23 * x23 + y23 * y23);
+ double l34 = Math.sqrt(x34 * x34 + y34 * y34);
+
+ // All edges are zero
+ if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) {
+ // NOTHING
+ return;
+ }
+
+ // One zero edge
+ if (l12 == 0.0 && l23 == 0.0) {
+ addDashLine(x3, y3, x4, y4);
+ return;
+ }
+
+ if (l23 == 0.0 && l34 == 0.0) {
+ addDashLine(x1, y1, x2, y2);
+ return;
+ }
+
+ if (l12 == 0.0 && l34 == 0.0) {
+ addDashLine(x2, y2, x3, y3);
+ return;
+ }
+
+ double ax = x4 - x1 + 3.0 * (x2 - x3);
+ double ay = y4 - y1 + 3.0 * (y2 - y3);
+ double bx = 3.0 * (x1 + x3 - x2 - x2);
+ double by = 3.0 * (y1 + y3 - y2 - y2);
+ double cx = 3.0 * (x2 - x1);
+ double cy = 3.0 * (y2 - y1);
+ double dx = x1;
+ double dy = y1;
+
+ double px1 = 0.0;
+ double py1 = 0.0;
+ double prev = 0.0;
+
+ dasher.init(new DashIterator.Cubic(x1, y1, x2, y2, x3, y3, x4, y4));
+
+ while(!dasher.eof()) {
+
+ double t = dasher.getValue();
+ scx = t * (t * (t * ax + bx) + cx) + dx;
+ scy = t * (t * (t * ay + by) + cy) + dy;
+ if (dasher.isOpen()) {
+ px1 = scx;
+ py1 = scy;
+ double dx1 = t * (t * (ax + ax + ax) + bx + bx) + cx;
+ double dy1 = t * (t * (ay + ay + ay) + by + by) + cy;
+ double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1);
+ double mx1 = - dy1 * w;
+ double my1 = dx1 * w;
+ double lx1 = px1 + mx1;
+ double ly1 = py1 + my1;
+ double rx1 = px1 - mx1;
+ double ry1 = py1 - my1;
+ if (isMove) {
+ isMove = false;
+ smx = px1;
+ smy = py1;
+ rp.clean();
+ lp.moveTo(lx1, ly1);
+ rp.moveTo(rx1, ry1);
+ } else {
+ addJoin(lp, x1, y1, lx1, ly1, true);
+ addJoin(rp, x1, y1, rx1, ry1, false);
+ }
+ } else
+ if (dasher.isContinue()) {
+ double sx1 = x2 - x23 * prev;
+ double sy1 = y2 - y23 * prev;
+ double sx2 = x3 - x34 * prev;
+ double sy2 = y3 - y34 * prev;
+ double sx3 = sx1 + (sx2 - sx1) * prev;
+ double sy3 = sy1 + (sy2 - sy1) * prev;
+ double t2 = (t - prev) / (1 - prev);
+ double sx4 = sx3 + (sx2 - sx3) * t2;
+ double sy4 = sy3 + (sy2 - sy3) * t2;
+
+ double px4 = scx;
+ double py4 = scy;
+ double px2 = px1 + (sx3 - px1) * t2;
+ double py2 = py1 + (sy3 - py1) * t2;
+ double px3 = px2 + (sx4 - px2) * t2;
+ double py3 = py2 + (sy4 - py2) * t2;
+
+ addCubic(px1, py1, px2, py2, px3, py3, px4, py4);
+ if (dasher.isClosed()) {
+ addCap(lp, px4, py4, rp.xLast, rp.yLast);
+ lp.combine(rp);
+ if (isFirst) {
+ isFirst = false;
+ fmx = smx;
+ fmy = smy;
+ sp = lp;
+ lp = new BufferedPath();
+ } else {
+ addCap(lp, smx, smy, lp.xMove, lp.yMove);
+ lp.closePath();
+ }
+ isMove = true;
+ }
+ }
+
+ prev = t;
+ dasher.next();
+ }
+ }
+
+ /**
+ * Dasher class provides dashing for particular dash style.
+ */
+ class Dasher {
+
+ /** The pos. */
+ double pos;
+
+ /** The first. */
+ boolean close, visible, first;
+
+ /** The dash. */
+ float dash[];
+
+ /** The phase. */
+ float phase;
+
+ /** The index. */
+ int index;
+
+ /** The iter. */
+ DashIterator iter;
+
+ /**
+ * Instantiates a new dasher.
+ *
+ * @param dash the dash
+ * @param phase the phase
+ */
+ Dasher(float dash[], float phase) {
+ this.dash = dash;
+ this.phase = phase;
+ index = 0;
+ pos = phase;
+ visible = true;
+ while (pos >= dash[index]) {
+ visible = !visible;
+ pos -= dash[index];
+ index = (index + 1) % dash.length;
+ }
+ pos = -pos;
+ first = visible;
+ }
+
+ /**
+ * Inits the.
+ *
+ * @param iter the iter
+ */
+ void init(DashIterator iter) {
+ this.iter = iter;
+ close = true;
+ }
+
+ /**
+ * Checks if is open.
+ *
+ * @return true, if is open
+ */
+ boolean isOpen() {
+ return visible && pos < iter.length;
+ }
+
+ /**
+ * Checks if is continue.
+ *
+ * @return true, if is continue
+ */
+ boolean isContinue() {
+ return !visible && pos > 0;
+ }
+
+ /**
+ * Checks if is closed.
+ *
+ * @return true, if is closed
+ */
+ boolean isClosed() {
+ return close;
+ }
+
+ /**
+ * Checks if is connected.
+ *
+ * @return true, if is connected
+ */
+ boolean isConnected() {
+ return first && !close;
+ }
+
+ /**
+ * Eof.
+ *
+ * @return true, if successful
+ */
+ boolean eof() {
+ if (!close) {
+ pos -= iter.length;
+ return true;
+ }
+ if (pos >= iter.length) {
+ if (visible) {
+ pos -= iter.length;
+ return true;
+ }
+ close = pos == iter.length;
+ }
+ return false;
+ }
+
+ /**
+ * Next.
+ */
+ void next() {
+ if (close) {
+ pos += dash[index];
+ index = (index + 1) % dash.length;
+ } else {
+ // Go back
+ index = (index + dash.length - 1) % dash.length;
+ pos -= dash[index];
+ }
+ visible = !visible;
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value
+ */
+ double getValue() {
+ double t = iter.getNext(pos);
+ return t < 0 ? 0 : (t > 1 ? 1 : t);
+ }
+
+ }
+
+ /**
+ * DashIterator class provides dashing for particular segment type.
+ */
+ static abstract class DashIterator {
+
+ /** The Constant FLATNESS. */
+ static final double FLATNESS = 1.0;
+
+ /**
+ * The Class Line.
+ */
+ static class Line extends DashIterator {
+
+ /**
+ * Instantiates a new line.
+ *
+ * @param len the len
+ */
+ Line(double len) {
+ length = len;
+ }
+
+ @Override
+ double getNext(double dashPos) {
+ return dashPos / length;
+ }
+
+ }
+
+ /**
+ * The Class Quad.
+ */
+ static class Quad extends DashIterator {
+
+ /** The val size. */
+ int valSize;
+
+ /** The val pos. */
+ int valPos;
+
+ /** The cur len. */
+ double curLen;
+
+ /** The prev len. */
+ double prevLen;
+
+ /** The last len. */
+ double lastLen;
+
+ /** The values. */
+ double[] values;
+
+ /** The step. */
+ double step;
+
+ /**
+ * Instantiates a new quad.
+ *
+ * @param x1 the x1
+ * @param y1 the y1
+ * @param x2 the x2
+ * @param y2 the y2
+ * @param x3 the x3
+ * @param y3 the y3
+ */
+ Quad(double x1, double y1, double x2, double y2, double x3, double y3) {
+
+ double nx = x1 + x3 - x2 - x2;
+ double ny = y1 + y3 - y2 - y2;
+
+ int n = (int)(1 + Math.sqrt(0.75 * (Math.abs(nx) + Math.abs(ny)) * FLATNESS));
+ step = 1.0 / n;
+
+ double ax = x1 + x3 - x2 - x2;
+ double ay = y1 + y3 - y2 - y2;
+ double bx = 2.0 * (x2 - x1);
+ double by = 2.0 * (y2 - y1);
+
+ double dx1 = step * (step * ax + bx);
+ double dy1 = step * (step * ay + by);
+ double dx2 = step * (step * ax * 2.0);
+ double dy2 = step * (step * ay * 2.0);
+ double vx = x1;
+ double vy = y1;
+
+ valSize = n;
+ values = new double[valSize];
+ double pvx = vx;
+ double pvy = vy;
+ length = 0.0;
+ for(int i = 0; i < n; i++) {
+ vx += dx1;
+ vy += dy1;
+ dx1 += dx2;
+ dy1 += dy2;
+ double lx = vx - pvx;
+ double ly = vy - pvy;
+ values[i] = Math.sqrt(lx * lx + ly * ly);
+ length += values[i];
+ pvx = vx;
+ pvy = vy;
+ }
+
+ valPos = 0;
+ curLen = 0.0;
+ prevLen = 0.0;
+ }
+
+ @Override
+ double getNext(double dashPos) {
+ double t = 2.0;
+ while (curLen <= dashPos && valPos < valSize) {
+ prevLen = curLen;
+ curLen += lastLen = values[valPos++];
+ }
+ if (curLen > dashPos) {
+ t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step;
+ }
+ return t;
+ }
+
+ }
+
+ /**
+ * The Class Cubic.
+ */
+ static class Cubic extends DashIterator {
+
+ /** The val size. */
+ int valSize;
+
+ /** The val pos. */
+ int valPos;
+
+ /** The cur len. */
+ double curLen;
+
+ /** The prev len. */
+ double prevLen;
+
+ /** The last len. */
+ double lastLen;
+
+ /** The values. */
+ double[] values;
+
+ /** The step. */
+ double step;
+
+ /**
+ * Instantiates a new cubic.
+ *
+ * @param x1 the x1
+ * @param y1 the y1
+ * @param x2 the x2
+ * @param y2 the y2
+ * @param x3 the x3
+ * @param y3 the y3
+ * @param x4 the x4
+ * @param y4 the y4
+ */
+ Cubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
+
+ double nx1 = x1 + x3 - x2 - x2;
+ double ny1 = y1 + y3 - y2 - y2;
+ double nx2 = x2 + x4 - x3 - x3;
+ double ny2 = y2 + y4 - y3 - y3;
+
+ double max = Math.max(Math.abs(nx1) + Math.abs(ny1), Math.abs(nx2) + Math.abs(ny2));
+ int n = (int)(1 + Math.sqrt(0.75 * max) * FLATNESS);
+ step = 1.0 / n;
+
+ double ax = x4 - x1 + 3.0 * (x2 - x3);
+ double ay = y4 - y1 + 3.0 * (y2 - y3);
+ double bx = 3.0 * (x1 + x3 - x2 - x2);
+ double by = 3.0 * (y1 + y3 - y2 - y2);
+ double cx = 3.0 * (x2 - x1);
+ double cy = 3.0 * (y2 - y1);
+
+ double dx1 = step * (step * (step * ax + bx) + cx);
+ double dy1 = step * (step * (step * ay + by) + cy);
+ double dx2 = step * (step * (step * ax * 6.0 + bx * 2.0));
+ double dy2 = step * (step * (step * ay * 6.0 + by * 2.0));
+ double dx3 = step * (step * (step * ax * 6.0));
+ double dy3 = step * (step * (step * ay * 6.0));
+ double vx = x1;
+ double vy = y1;
+
+ valSize = n;
+ values = new double[valSize];
+ double pvx = vx;
+ double pvy = vy;
+ length = 0.0;
+ for(int i = 0; i < n; i++) {
+ vx += dx1;
+ vy += dy1;
+ dx1 += dx2;
+ dy1 += dy2;
+ dx2 += dx3;
+ dy2 += dy3;
+ double lx = vx - pvx;
+ double ly = vy - pvy;
+ values[i] = Math.sqrt(lx * lx + ly * ly);
+ length += values[i];
+ pvx = vx;
+ pvy = vy;
+ }
+
+ valPos = 0;
+ curLen = 0.0;
+ prevLen = 0.0;
+ }
+
+ @Override
+ double getNext(double dashPos) {
+ double t = 2.0;
+ while (curLen <= dashPos && valPos < valSize) {
+ prevLen = curLen;
+ curLen += lastLen = values[valPos++];
+ }
+ if (curLen > dashPos) {
+ t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step;
+ }
+ return t;
+ }
+
+ }
+
+ /** The length. */
+ double length;
+
+ /**
+ * Gets the next.
+ *
+ * @param dashPos the dash pos
+ *
+ * @return the next
+ */
+ abstract double getNext(double dashPos);
+
+ }
+
+ /**
+ * BufferedPath class provides work path storing and processing.
+ */
+ static class BufferedPath {
+
+ /** The Constant bufCapacity. */
+ private static final int bufCapacity = 10;
+
+ /** The point shift. */
+ static int pointShift[] = {
+ 2, // MOVETO
+ 2, // LINETO
+ 4, // QUADTO
+ 6, // CUBICTO
+ 0}; // CLOSE
+
+ /** The types. */
+ byte[] types;
+
+ /** The points. */
+ float[] points;
+
+ /** The type size. */
+ int typeSize;
+
+ /** The point size. */
+ int pointSize;
+
+ /** The x last. */
+ float xLast;
+
+ /** The y last. */
+ float yLast;
+
+ /** The x move. */
+ float xMove;
+
+ /** The y move. */
+ float yMove;
+
+ /**
+ * Instantiates a new buffered path.
+ */
+ public BufferedPath() {
+ types = new byte[bufCapacity];
+ points = new float[bufCapacity * 2];
+ }
+
+ /**
+ * Check buf.
+ *
+ * @param typeCount the type count
+ * @param pointCount the point count
+ */
+ void checkBuf(int typeCount, int pointCount) {
+ if (typeSize + typeCount > types.length) {
+ byte tmp[] = new byte[typeSize + Math.max(bufCapacity, typeCount)];
+ System.arraycopy(types, 0, tmp, 0, typeSize);
+ types = tmp;
+ }
+ if (pointSize + pointCount > points.length) {
+ float tmp[] = new float[pointSize + Math.max(bufCapacity * 2, pointCount)];
+ System.arraycopy(points, 0, tmp, 0, pointSize);
+ points = tmp;
+ }
+ }
+
+ /**
+ * Checks if is empty.
+ *
+ * @return true, if is empty
+ */
+ boolean isEmpty() {
+ return typeSize == 0;
+ }
+
+ /**
+ * Clean.
+ */
+ void clean() {
+ typeSize = 0;
+ pointSize = 0;
+ }
+
+ /**
+ * Move to.
+ *
+ * @param x the x
+ * @param y the y
+ */
+ void moveTo(double x, double y) {
+ checkBuf(1, 2);
+ types[typeSize++] = PathIterator.SEG_MOVETO;
+ points[pointSize++] = xMove = (float)x;
+ points[pointSize++] = yMove = (float)y;
+ }
+
+ /**
+ * Line to.
+ *
+ * @param x the x
+ * @param y the y
+ */
+ void lineTo(double x, double y) {
+ checkBuf(1, 2);
+ types[typeSize++] = PathIterator.SEG_LINETO;
+ points[pointSize++] = xLast = (float)x;
+ points[pointSize++] = yLast = (float)y;
+ }
+
+ /**
+ * Quad to.
+ *
+ * @param x1 the x1
+ * @param y1 the y1
+ * @param x2 the x2
+ * @param y2 the y2
+ */
+ void quadTo(double x1, double y1, double x2, double y2) {
+ checkBuf(1, 4);
+ types[typeSize++] = PathIterator.SEG_QUADTO;
+ points[pointSize++] = (float)x1;
+ points[pointSize++] = (float)y1;
+ points[pointSize++] = xLast = (float)x2;
+ points[pointSize++] = yLast = (float)y2;
+ }
+
+ /**
+ * Cubic to.
+ *
+ * @param x1 the x1
+ * @param y1 the y1
+ * @param x2 the x2
+ * @param y2 the y2
+ * @param x3 the x3
+ * @param y3 the y3
+ */
+ void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) {
+ checkBuf(1, 6);
+ types[typeSize++] = PathIterator.SEG_CUBICTO;
+ points[pointSize++] = (float)x1;
+ points[pointSize++] = (float)y1;
+ points[pointSize++] = (float)x2;
+ points[pointSize++] = (float)y2;
+ points[pointSize++] = xLast = (float)x3;
+ points[pointSize++] = yLast = (float)y3;
+ }
+
+ /**
+ * Close path.
+ */
+ void closePath() {
+ checkBuf(1, 0);
+ types[typeSize++] = PathIterator.SEG_CLOSE;
+ }
+
+ /**
+ * Sets the last.
+ *
+ * @param x the x
+ * @param y the y
+ */
+ void setLast(double x, double y) {
+ points[pointSize - 2] = xLast = (float)x;
+ points[pointSize - 1] = yLast = (float)y;
+ }
+
+ /**
+ * Append.
+ *
+ * @param p the p
+ */
+ void append(BufferedPath p) {
+ checkBuf(p.typeSize, p.pointSize);
+ System.arraycopy(p.points, 0, points, pointSize, p.pointSize);
+ System.arraycopy(p.types, 0, types, typeSize, p.typeSize);
+ pointSize += p.pointSize;
+ typeSize += p.typeSize;
+ xLast = points[pointSize - 2];
+ yLast = points[pointSize - 1];
+ }
+
+ /**
+ * Append reverse.
+ *
+ * @param p the p
+ */
+ void appendReverse(BufferedPath p) {
+ checkBuf(p.typeSize, p.pointSize);
+ // Skip last point, beacause it's the first point of the second path
+ for(int i = p.pointSize - 2; i >= 0; i -= 2) {
+ points[pointSize++] = p.points[i + 0];
+ points[pointSize++] = p.points[i + 1];
+ }
+ // Skip first type, beacuse it's always MOVETO
+ int closeIndex = 0;
+ for(int i = p.typeSize - 1; i >= 0; i--) {
+ byte type = p.types[i];
+ if (type == PathIterator.SEG_MOVETO) {
+ types[closeIndex] = PathIterator.SEG_MOVETO;
+ types[typeSize++] = PathIterator.SEG_CLOSE;
+ } else {
+ if (type == PathIterator.SEG_CLOSE) {
+ closeIndex = typeSize;
+ }
+ types[typeSize++] = type;
+ }
+ }
+ xLast = points[pointSize - 2];
+ yLast = points[pointSize - 1];
+ }
+
+ /**
+ * Join.
+ *
+ * @param p the p
+ */
+ void join(BufferedPath p) {
+ // Skip MOVETO
+ checkBuf(p.typeSize - 1, p.pointSize - 2);
+ System.arraycopy(p.points, 2, points, pointSize, p.pointSize - 2);
+ System.arraycopy(p.types, 1, types, typeSize, p.typeSize - 1);
+ pointSize += p.pointSize - 2;
+ typeSize += p.typeSize - 1;
+ xLast = points[pointSize - 2];
+ yLast = points[pointSize - 1];
+ }
+
+ /**
+ * Combine.
+ *
+ * @param p the p
+ */
+ void combine(BufferedPath p) {
+ checkBuf(p.typeSize - 1, p.pointSize - 2);
+ // Skip last point, beacause it's the first point of the second path
+ for(int i = p.pointSize - 4; i >= 0; i -= 2) {
+ points[pointSize++] = p.points[i + 0];
+ points[pointSize++] = p.points[i + 1];
+ }
+ // Skip first type, beacuse it's always MOVETO
+ for(int i = p.typeSize - 1; i >= 1; i--) {
+ types[typeSize++] = p.types[i];
+ }
+ xLast = points[pointSize - 2];
+ yLast = points[pointSize - 1];
+ }
+
+ /**
+ * Creates the general path.
+ *
+ * @return the general path
+ */
+ GeneralPath createGeneralPath() {
+ GeneralPath p = new GeneralPath();
+ int j = 0;
+ for(int i = 0; i < typeSize; i++) {
+ int type = types[i];
+ switch(type){
+ case PathIterator.SEG_MOVETO:
+ p.moveTo(points[j], points[j + 1]);
+ break;
+ case PathIterator.SEG_LINETO:
+ p.lineTo(points[j], points[j + 1]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ p.quadTo(points[j], points[j + 1], points[j + 2], points[j + 3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ p.curveTo(points[j], points[j + 1], points[j + 2], points[j + 3], points[j + 4], points[j + 5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ p.closePath();
+ break;
+ }
+ j += pointShift[type];
+ }
+ return p;
+ }
+
+ }
+
+}
+
diff --git a/awt/java/awt/BufferCapabilities.java b/awt/java/awt/BufferCapabilities.java
new file mode 100644
index 0000000..80e8add
--- /dev/null
+++ b/awt/java/awt/BufferCapabilities.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+
+/**
+ * The BufferCapabilities class represents the capabilities
+ * and other properties of the image buffers.
+ */
+public class BufferCapabilities implements Cloneable {
+
+ /** The front buffer capabilities. */
+ private final ImageCapabilities frontBufferCapabilities;
+
+ /** The back buffer capabilities. */
+ private final ImageCapabilities backBufferCapabilities;
+
+ /** The flip contents. */
+ private final FlipContents flipContents;
+
+ /**
+ * Instantiates a new BufferCapabilities object.
+ *
+ * @param frontBufferCapabilities the front buffer capabilities,
+ * can not be null.
+ * @param backBufferCapabilities the the back and intermediate
+ * buffers capabilities, can not be null.
+ * @param flipContents the back buffer contents after page flipping,
+ * null if page flipping is not used.
+ */
+ public BufferCapabilities(ImageCapabilities frontBufferCapabilities,
+ ImageCapabilities backBufferCapabilities, FlipContents flipContents) {
+ if (frontBufferCapabilities == null || backBufferCapabilities == null) {
+ throw new IllegalArgumentException();
+ }
+
+ this.frontBufferCapabilities = frontBufferCapabilities;
+ this.backBufferCapabilities = backBufferCapabilities;
+ this.flipContents = flipContents;
+ }
+
+ /**
+ * Returns a copy of the BufferCapabilities object.
+ *
+ * @return a copy of the BufferCapabilities object.
+ */
+ @Override
+ public Object clone() {
+ return new BufferCapabilities(frontBufferCapabilities, backBufferCapabilities, flipContents);
+ }
+
+ /**
+ * Gets the image capabilities of the front buffer.
+ *
+ * @return the ImageCapabilities object represented capabilities
+ * of the front buffer.
+ */
+ public ImageCapabilities getFrontBufferCapabilities() {
+ return frontBufferCapabilities;
+ }
+
+ /**
+ * Gets the image capabilities of the back buffer.
+ *
+ * @return the ImageCapabilities object represented capabilities
+ * of the back buffer.
+ */
+ public ImageCapabilities getBackBufferCapabilities() {
+ return backBufferCapabilities;
+ }
+
+ /**
+ * Gets the flip contents of the back buffer after page-flipping.
+ *
+ * @return the FlipContents of the back buffer after page-flipping.
+ */
+ public FlipContents getFlipContents() {
+ return flipContents;
+ }
+
+ /**
+ * Checks if the buffer strategy uses page flipping.
+ *
+ * @return true, if the buffer strategy uses page flipping,
+ * false otherwise.
+ */
+ public boolean isPageFlipping() {
+ return flipContents != null;
+ }
+
+ /**
+ * Checks if page flipping is only available in full-screen mode.
+ *
+ * @return true, if page flipping is only available in full-screen mode,
+ * false otherwise.
+ */
+ public boolean isFullScreenRequired() {
+ return false;
+ }
+
+ /**
+ * Checks if page flipping can be performed using more than two buffers.
+ *
+ * @return true, if page flipping can be performed using more than two buffers,
+ * false otherwise.
+ */
+ public boolean isMultiBufferAvailable() {
+ return false;
+ }
+
+ /**
+ * The FlipContents class represents a set of possible back buffer contents
+ * after page-flipping.
+ */
+ public static final class FlipContents {
+
+ /**
+ * The back buffered contents are cleared with the background color
+ * after flipping.
+ */
+ public static final FlipContents BACKGROUND = new FlipContents();
+
+ /**
+ * The back buffered contents are copied to the front buffer before
+ * flipping.
+ */
+ public static final FlipContents COPIED = new FlipContents();
+
+ /**
+ * The back buffer contents are the prior contents of the
+ * front buffer.
+ */
+ public static final FlipContents PRIOR = new FlipContents();
+
+ /**
+ * The back buffer contents are undefined after flipping
+ */
+ public static final FlipContents UNDEFINED = new FlipContents();
+
+ /**
+ * Instantiates a new flip contents.
+ */
+ private FlipContents() {
+
+ }
+
+ /**
+ * Returns the hash code of the FlipContents object.
+ *
+ * @return the hash code of the FlipContents object.
+ */
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ /**
+ * Returns the String representation of the FlipContents object.
+ *
+ * @return the string
+ */
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+ }
+}
diff --git a/awt/java/awt/Color.java b/awt/java/awt/Color.java
new file mode 100644
index 0000000..e1e4178
--- /dev/null
+++ b/awt/java/awt/Color.java
@@ -0,0 +1,881 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.io.Serializable;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Color class defines colors in the default sRGB color
+ * space or in the specified ColorSpace. Every Color contains alpha value.
+ * The alpha value defines the transparency of a color and can be represented
+ * by a float value in the range 0.0 - 1.0 or 0 - 255.
+ */
+public class Color implements Paint, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 118526816881161077L;
+
+ /*
+ * The values of the following colors are based on 1.5 release behavior which
+ * can be revealed using the following or similar code:
+ * Color c = Color.white;
+ * System.out.println(c);
+ */
+
+ /** The color white. */
+ public static final Color white = new Color(255, 255, 255);
+
+ /** The color white. */
+ public static final Color WHITE = white;
+
+ /** The color light gray. */
+ public static final Color lightGray = new Color(192, 192, 192);
+
+ /** The color light gray. */
+ public static final Color LIGHT_GRAY = lightGray;
+
+ /** The color gray. */
+ public static final Color gray = new Color(128, 128, 128);
+
+ /** The color gray. */
+ public static final Color GRAY = gray;
+
+ /** The color dark gray. */
+ public static final Color darkGray = new Color(64, 64, 64);
+
+ /** The color dark gray. */
+ public static final Color DARK_GRAY = darkGray;
+
+ /** The color black. */
+ public static final Color black = new Color(0, 0, 0);
+
+ /** The color black. */
+ public static final Color BLACK = black;
+
+ /** The color red. */
+ public static final Color red = new Color(255, 0, 0);
+
+ /** The color red. */
+ public static final Color RED = red;
+
+ /** The color pink. */
+ public static final Color pink = new Color(255, 175, 175);
+
+ /** The color pink. */
+ public static final Color PINK = pink;
+
+ /** The color orange. */
+ public static final Color orange = new Color(255, 200, 0);
+
+ /** The color orange. */
+ public static final Color ORANGE = orange;
+
+ /** The color yellow. */
+ public static final Color yellow = new Color(255, 255, 0);
+
+ /** The color yellow. */
+ public static final Color YELLOW = yellow;
+
+ /** The color green. */
+ public static final Color green = new Color(0, 255, 0);
+
+ /** The color green. */
+ public static final Color GREEN = green;
+
+ /** The color magenta. */
+ public static final Color magenta = new Color(255, 0, 255);
+
+ /** The color magenta. */
+ public static final Color MAGENTA = magenta;
+
+ /** The color cyan. */
+ public static final Color cyan = new Color(0, 255, 255);
+
+ /** The color cyan. */
+ public static final Color CYAN = cyan;
+
+ /** The color blue. */
+ public static final Color blue = new Color(0, 0, 255);
+
+ /** The color blue. */
+ public static final Color BLUE = blue;
+
+ /** integer RGB value. */
+ int value;
+
+ /** Float sRGB value. */
+ private float[] frgbvalue;
+
+ /** Color in an arbitrary color space with <code>float</code> components. If null, other value should be used. */
+ private float fvalue[];
+
+ /** Float alpha value. If frgbvalue is null, this is not valid data. */
+ private float falpha;
+
+ /** The color's color space if applicable. */
+ private ColorSpace cs;
+
+ /*
+ * The value of the SCALE_FACTOR is based on 1.5 release behavior which
+ * can be revealed using the following code:
+ * Color c = new Color(100, 100, 100);
+ * Color bc = c.brighter();
+ * System.out.println("Brighter factor: " + ((float)c.getRed())/((float)bc.getRed()));
+ * Color dc = c.darker();
+ * System.out.println("Darker factor: " + ((float)dc.getRed())/((float)c.getRed()));
+ * The result is the same for brighter and darker methods, so we need only
+ * one scale factor for both.
+ */
+ /** The Constant SCALE_FACTOR. */
+ private static final double SCALE_FACTOR = 0.7;
+
+ /** The Constant MIN_SCALABLE. */
+ private static final int MIN_SCALABLE = 3; // should increase when multiplied by SCALE_FACTOR
+
+ /** The current paint context. */
+ transient private PaintContext currentPaintContext;
+
+ /**
+ * Creates a color in the specified ColorSpace, the specified color
+ * components and the specified alpha.
+ *
+ * @param cspace the ColorSpace to be used to define the components.
+ * @param components the components.
+ * @param alpha the alpha.
+ */
+ public Color(ColorSpace cspace, float[] components, float alpha) {
+ int nComps = cspace.getNumComponents();
+ float comp;
+ fvalue = new float[nComps];
+
+ for(int i=0 ; i<nComps; i++) {
+ comp = components[i];
+ if(comp < 0.0f || comp > 1.0f) {
+ // awt.107=Color parameter outside of expected range: component {0}.
+ throw new IllegalArgumentException(
+ Messages.getString("awt.107", i)); //$NON-NLS-1$
+ }
+ fvalue[i] = components[i];
+ }
+
+ if (alpha < 0.0f || alpha > 1.0f) {
+ // awt.108=Alpha value outside of expected range.
+ throw new IllegalArgumentException(Messages.getString("awt.108")); //$NON-NLS-1$
+ }
+ falpha = alpha;
+
+ cs = cspace;
+
+ frgbvalue = cs.toRGB(fvalue);
+
+ value = ((int)(frgbvalue[2]*255 + 0.5)) |
+ (((int)(frgbvalue[1]*255 + 0.5)) << 8 ) |
+ (((int)(frgbvalue[0]*255 + 0.5)) << 16 ) |
+ (((int)(falpha*255 + 0.5)) << 24 );
+ }
+
+ /**
+ * Instantiates a new sRGB color with the specified combined
+ * RGBA value consisting of the alpha component in bits 24-31,
+ * the red component in bits 16-23, the green component in bits 8-15,
+ * and the blue component in bits 0-7. If the hasalpha argument is
+ * false, the alpha has default value - 255.
+ *
+ * @param rgba the RGBA components.
+ * @param hasAlpha alpha parameter is true if alpha bits are valid,
+ * false otherwise.
+ */
+ public Color(int rgba, boolean hasAlpha) {
+ if (!hasAlpha) {
+ value = rgba | 0xFF000000;
+ } else {
+ value = rgba;
+ }
+ }
+
+ /**
+ * Instantiates a new color with the specified red, green, blue and alpha
+ * components.
+ *
+ * @param r the red component.
+ * @param g the green component.
+ * @param b the blue component.
+ * @param a the alpha component.
+ */
+ public Color(int r, int g, int b, int a) {
+ if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b || (a & 0xFF) != a) {
+ // awt.109=Color parameter outside of expected range.
+ throw new IllegalArgumentException(Messages.getString("awt.109")); //$NON-NLS-1$
+ }
+ value = b | (g << 8) | (r << 16) | (a << 24);
+ }
+
+ /**
+ * Instantiates a new opaque sRGB color with the specified red, green,
+ * and blue values. The Alpha component is set to the default - 1.0.
+ *
+ * @param r the red component.
+ * @param g the green component.
+ * @param b the blue component.
+ */
+ public Color(int r, int g, int b) {
+ if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b) {
+ // awt.109=Color parameter outside of expected range.
+ throw new IllegalArgumentException(Messages.getString("awt.109")); //$NON-NLS-1$
+ }
+ // 0xFF for alpha channel
+ value = b | (g << 8) | (r << 16) | 0xFF000000;
+ }
+
+ /**
+ * Instantiates a new sRGB color with the specified
+ * RGB value consisting of the red component in bits 16-23,
+ * the green component in bits 8-15, and the blue component
+ * in bits 0-7. Alpha has default value - 255.
+ *
+ * @param rgb the RGB components.
+ */
+ public Color(int rgb) {
+ value = rgb | 0xFF000000;
+ }
+
+ /**
+ * Instantiates a new color with the specified red, green, blue and alpha
+ * components.
+ *
+ * @param r the red component.
+ * @param g the green component.
+ * @param b the blue component.
+ * @param a the alpha component.
+ */
+ public Color(float r, float g, float b, float a) {
+ this((int)(r*255+0.5),
+ (int)(g*255+0.5),
+ (int)(b*255+0.5),
+ (int)(a*255+0.5));
+ falpha = a;
+ fvalue = new float[3];
+ fvalue[0] = r;
+ fvalue[1] = g;
+ fvalue[2] = b;
+ frgbvalue = fvalue;
+ }
+
+ /**
+ * Instantiates a new color with the specified red, green, and blue
+ * components and default alfa value - 1.0.
+ *
+ * @param r the red component.
+ * @param g the green component.
+ * @param b the blue component.
+ */
+ public Color(float r, float g, float b) {
+ this(r, g, b, 1.0f);
+ }
+
+ public PaintContext createContext(
+ ColorModel cm,
+ Rectangle r,
+ Rectangle2D r2d,
+ AffineTransform xform,
+ RenderingHints rhs
+ ) {
+ if(currentPaintContext != null) {
+ return currentPaintContext;
+ }
+ currentPaintContext = new Color.ColorPaintContext(value);
+ return currentPaintContext;
+ }
+
+ /**
+ * Returns a string representation of the Color object.
+ *
+ * @return the string representation of the Color object.
+ */
+ @Override
+ public String toString() {
+ /*
+ The format of the string is based on 1.5 release behavior which
+ can be revealed using the following code:
+
+ Color c = new Color(1, 2, 3);
+ System.out.println(c);
+ */
+
+ return getClass().getName() +
+ "[r=" + getRed() + //$NON-NLS-1$
+ ",g=" + getGreen() + //$NON-NLS-1$
+ ",b=" + getBlue() + //$NON-NLS-1$
+ "]"; //$NON-NLS-1$
+ }
+
+ /**
+ * Compares the specified Object to the Color.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified Object is a Color whose
+ * value is equal to this Color, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if(obj instanceof Color) {
+ return ((Color)obj).value == this.value;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a float array containing the color and alpha components of
+ * the Color in the specified ColorSpace.
+ *
+ * @param colorSpace the specified ColorSpace.
+ * @param components the results of this method will be written to
+ * this float array. If null, a float array will be created.
+ *
+ * @return the color and alpha components in a float array.
+ */
+ public float[] getComponents(ColorSpace colorSpace, float[] components) {
+ int nComps = colorSpace.getNumComponents();
+ if(components == null) {
+ components = new float[nComps+1];
+ }
+
+ getColorComponents(colorSpace, components);
+
+ if(frgbvalue != null) {
+ components[nComps] = falpha;
+ } else {
+ components[nComps] = getAlpha()/255f;
+ }
+
+ return components;
+ }
+
+ /**
+ * Returns a float array containing the color components of
+ * the Color in the specified ColorSpace.
+ *
+ * @param colorSpace the specified ColorSpace.
+ * @param components the results of this method will be written to
+ * this float array. If null, a float array will be created.
+ *
+ * @return the color components in a float array.
+ */
+ public float[] getColorComponents(ColorSpace colorSpace, float[] components) {
+ float[] cieXYZComponents = getColorSpace().toCIEXYZ(getColorComponents(null));
+ float[] csComponents = colorSpace.fromCIEXYZ(cieXYZComponents);
+
+ if(components == null) {
+ return csComponents;
+ }
+
+ for(int i=0; i<csComponents.length; i++) {
+ components[i] = csComponents[i];
+ }
+
+ return components;
+ }
+
+ /**
+ * Gets the ColorSpace of this Color.
+ *
+ * @return the ColorSpace object.
+ */
+ public ColorSpace getColorSpace() {
+ if (cs == null) {
+ cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+ }
+
+ return cs;
+ }
+
+ /**
+ * Creates a new Color which is a darker than this Color
+ * according to a fixed scale factor.
+ *
+ * @return the darker Color.
+ */
+ public Color darker() {
+ return new Color(
+ (int)(getRed()*SCALE_FACTOR),
+ (int)(getGreen()*SCALE_FACTOR),
+ (int)(getBlue()*SCALE_FACTOR));
+ }
+
+ /**
+ * Creates a new Color which is a brighter than this Color.
+ *
+ * @return the brighter Color.
+ */
+ public Color brighter() {
+
+ int r = getRed();
+ int b = getBlue();
+ int g = getGreen();
+
+ if(r == 0 && b == 0 && g == 0) {
+ return new Color(MIN_SCALABLE, MIN_SCALABLE, MIN_SCALABLE);
+ }
+
+ if(r < MIN_SCALABLE && r != 0) {
+ r = MIN_SCALABLE;
+ } else {
+ r = (int) (r/SCALE_FACTOR);
+ r = (r > 255) ? 255 : r;
+ }
+
+ if(b < MIN_SCALABLE && b != 0) {
+ b = MIN_SCALABLE;
+ } else {
+ b = (int) (b/SCALE_FACTOR);
+ b = (b > 255) ? 255 : b;
+ }
+
+ if(g < MIN_SCALABLE && g != 0) {
+ g = MIN_SCALABLE;
+ } else {
+ g = (int) (g/SCALE_FACTOR);
+ g = (g > 255) ? 255 : g;
+ }
+
+ return new Color(r, g, b);
+ }
+
+ /**
+ * Returns a float array containing the color and alpha components of
+ * the Color in the default sRGB color space.
+ *
+ * @param components the results of this method will be written to
+ * this float array. A new float array will be created if this
+ * argument is null.
+ *
+ * @return the RGB color and alpha components in a float array.
+ */
+ public float[] getRGBComponents(float[] components) {
+ if(components == null) {
+ components = new float[4];
+ }
+
+ if(frgbvalue != null) {
+ components[3] = falpha;
+ } else {
+ components[3] = getAlpha()/255f;
+ }
+
+ getRGBColorComponents(components);
+
+ return components;
+ }
+
+ /**
+ * Returns a float array containing the color components of
+ * the Color in the default sRGB color space.
+ *
+ * @param components the results of this method will be written to
+ * this float array. A new float array will be created if this
+ * argument is null.
+ *
+ * @return the RGB color components in a float array.
+ */
+ public float[] getRGBColorComponents(float[] components) {
+ if(components == null) {
+ components = new float[3];
+ }
+
+ if(frgbvalue != null) {
+ components[2] = frgbvalue[2];
+ components[1] = frgbvalue[1];
+ components[0] = frgbvalue[0];
+ } else {
+ components[2] = getBlue()/255f;
+ components[1] = getGreen()/255f;
+ components[0] = getRed()/255f;
+ }
+
+ return components;
+ }
+
+ /**
+ * Returns a float array which contains the color and alpha components of
+ * the Color in the ColorSpace of the Color.
+ *
+ * @param components the results of this method will be written to
+ * this float array. A new float array will be created if this
+ * argument is null.
+ *
+ * @return the color and alpha components in a float array.
+ */
+ public float[] getComponents(float[] components) {
+ if(fvalue == null) {
+ return getRGBComponents(components);
+ }
+
+ int nColorComps = fvalue.length;
+
+ if(components == null) {
+ components = new float[nColorComps+1];
+ }
+
+ getColorComponents(components);
+
+ components[nColorComps] = falpha;
+
+ return components;
+ }
+
+ /**
+ * Returns a float array which contains the color components of
+ * the Color in the ColorSpace of the Color.
+ *
+ * @param components the results of this method will be written to
+ * this float array. A new float array will be created if this
+ * argument is null.
+ *
+ * @return the color components in a float array.
+ */
+ public float[] getColorComponents(float[] components) {
+ if(fvalue == null) {
+ return getRGBColorComponents(components);
+ }
+
+ if(components == null) {
+ components = new float[fvalue.length];
+ }
+
+ for(int i=0; i<fvalue.length; i++) {
+ components[i] = fvalue[i];
+ }
+
+ return components;
+ }
+
+ /**
+ * Returns a hash code of this Color object.
+ *
+ * @return a hash code of this Color object.
+ */
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ public int getTransparency() {
+ switch(getAlpha()) {
+ case 0xff:
+ return Transparency.OPAQUE;
+ case 0:
+ return Transparency.BITMASK;
+ default:
+ return Transparency.TRANSLUCENT;
+ }
+ }
+
+ /**
+ * Gets the red component of the Color in the range 0-255.
+ *
+ * @return the red component of the Color.
+ */
+ public int getRed() {
+ return (value >> 16) & 0xFF;
+ }
+
+ /**
+ * Gets the RGB value that represents the color in the default sRGB ColorModel.
+ *
+ * @return the RGB color value in the default sRGB ColorModel.
+ */
+ public int getRGB() {
+ return value;
+ }
+
+ /**
+ * Gets the green component of the Color in the range 0-255.
+ *
+ * @return the green component of the Color.
+ */
+ public int getGreen() {
+ return (value >> 8) & 0xFF;
+ }
+
+ /**
+ * Gets the blue component of the Color in the range 0-255.
+ *
+ * @return the blue component of the Color.
+ */
+ public int getBlue() {
+ return value & 0xFF;
+ }
+
+ /**
+ * Gets the alpha component of the Color in the range 0-255.
+ *
+ * @return the alpha component of the Color.
+ */
+ public int getAlpha() {
+ return (value >> 24) & 0xFF;
+ }
+
+ /**
+ * Gets the Color from the specified string, or returns the Color
+ * specified by the second parameter.
+ *
+ * @param nm the specified string.
+ * @param def the default Color.
+ *
+ * @return the color from the specified string, or the Color
+ * specified by the second parameter.
+ */
+ public static Color getColor(String nm, Color def) {
+ Integer integer = Integer.getInteger(nm);
+
+ if (integer == null) {
+ return def;
+ }
+
+ return new Color(integer.intValue());
+ }
+
+ /**
+ * Gets the Color from the specified string, or returns the Color converted
+ * from the second parameter.
+ *
+ * @param nm the specified string.
+ * @param def the default Color.
+ *
+ * @return the color from the specified string, or the Color
+ * converted from the second parameter.
+ */
+ public static Color getColor(String nm, int def) {
+ Integer integer = Integer.getInteger(nm);
+
+ if (integer == null) {
+ return new Color(def);
+ }
+
+ return new Color(integer.intValue());
+ }
+
+ /**
+ * Gets the Color from the specified String.
+ *
+ * @param nm the specified string.
+ *
+ * @return the Color object, or null.
+ */
+ public static Color getColor(String nm) {
+ Integer integer = Integer.getInteger(nm);
+
+ if (integer == null) {
+ return null;
+ }
+
+ return new Color(integer.intValue());
+ }
+
+ /**
+ * Decodes a String to an integer and returns the specified opaque Color.
+ *
+ * @param nm a String which represents an opaque color as a 24-bit integer.
+ *
+ * @throws NumberFormatException if the specified string can not be
+ * converted to an integer.
+ */
+ public static Color decode(String nm) throws NumberFormatException {
+ Integer integer = Integer.decode(nm);
+ return new Color(integer.intValue());
+ }
+
+ /**
+ * Gets a Color object using the specified values of the HSB color model.
+ *
+ * @param h the hue component of the Color.
+ * @param s the saturation of the Color.
+ * @param b the brightness of the Color.
+ *
+ * @return a color object with the specified hue, saturation and
+ * brightness values.
+ */
+ public static Color getHSBColor(float h, float s, float b) {
+ return new Color(HSBtoRGB(h, s, b));
+ }
+
+ /**
+ * Converts the Color specified by the RGB model to an equivalent
+ * color in the HSB model.
+ *
+ * @param r the red component.
+ * @param g the green component.
+ * @param b the blue component.
+ * @param hsbvals the array of result hue, saturation, brightness
+ * values or null.
+ *
+ * @return the float array of hue, saturation, brightness values.
+ */
+ public static float[] RGBtoHSB(int r, int g, int b, float[] hsbvals) {
+ if(hsbvals == null) {
+ hsbvals = new float[3];
+ }
+
+ int V = Math.max(b, Math.max(r, g));
+ int temp = Math.min(b, Math.min(r, g));
+
+ float H, S, B;
+
+ B = V/255.f;
+
+ if(V == temp) {
+ H = S = 0;
+ } else {
+ S = (V - temp)/((float)V);
+
+ float Cr = (V - r) / (float)(V - temp);
+ float Cg = (V - g) / (float)(V - temp);
+ float Cb = (V - b) / (float)(V - temp);
+
+ if (r == V) {
+ H = Cb - Cg;
+ } else if (g == V) {
+ H = 2 + Cr - Cb;
+ } else {
+ H = 4 + Cg - Cr;
+ }
+
+ H /= 6.f;
+ if(H < 0) {
+ H++;
+ }
+ }
+
+ hsbvals[0] = H;
+ hsbvals[1] = S;
+ hsbvals[2] = B;
+
+ return hsbvals;
+ }
+
+ /**
+ * Converts the Color specified by the HSB model to an equivalent
+ * color in the default RGB model.
+ *
+ * @param hue the hue component of the Color.
+ * @param saturation the saturation of the Color.
+ * @param brightness the brightness of the Color.
+ *
+ * @return the RGB value of the color with the specified hue,
+ * saturation and brightness.
+ */
+ public static int HSBtoRGB(float hue, float saturation, float brightness) {
+ float fr, fg, fb;
+
+ if(saturation == 0) {
+ fr = fg = fb = brightness;
+ } else {
+ float H = (hue - (float)Math.floor(hue)) * 6;
+ int I = (int) Math.floor(H);
+ float F = H - I;
+ float M = brightness * (1 - saturation);
+ float N = brightness * (1 - saturation * F);
+ float K = brightness * (1 - saturation * (1 - F));
+
+ switch(I) {
+ case 0:
+ fr = brightness; fg = K; fb = M; break;
+ case 1:
+ fr = N; fg = brightness; fb = M; break;
+ case 2:
+ fr = M; fg = brightness; fb = K; break;
+ case 3:
+ fr = M; fg = N; fb = brightness; break;
+ case 4:
+ fr = K; fg = M; fb = brightness; break;
+ case 5:
+ fr = brightness; fg = M; fb = N; break;
+ default:
+ fr = fb = fg = 0; // impossible, to supress compiler error
+ }
+ }
+
+ int r = (int) (fr * 255. + 0.5);
+ int g = (int) (fg * 255. + 0.5);
+ int b = (int) (fb * 255. + 0.5);
+
+ return (r << 16) | (g << 8) | b | 0xFF000000;
+ }
+
+ /**
+ * The Class ColorPaintContext.
+ */
+ class ColorPaintContext implements PaintContext {
+
+ /** The rgb value. */
+ int rgbValue;
+
+ /** The saved raster. */
+ WritableRaster savedRaster = null;
+
+ /**
+ * Instantiates a new color paint context.
+ *
+ * @param rgb the rgb
+ */
+ protected ColorPaintContext(int rgb) {
+ rgbValue = rgb;
+ }
+
+ public void dispose() {
+ savedRaster = null;
+ }
+
+ public ColorModel getColorModel() {
+ return ColorModel.getRGBdefault();
+ }
+
+ public Raster getRaster(int x, int y, int w, int h) {
+ if (savedRaster == null ||
+ w != savedRaster.getWidth() ||
+ h != savedRaster.getHeight()) {
+ savedRaster =
+ getColorModel().createCompatibleWritableRaster(w, h);
+
+ // Suppose we have here simple INT/RGB color/sample model
+ DataBufferInt intBuffer =
+ (DataBufferInt) savedRaster.getDataBuffer();
+ int rgbValues[] = intBuffer.getData();
+ int rgbFillValue = rgbValue;
+ Arrays.fill(rgbValues, rgbFillValue);
+ }
+
+ return savedRaster;
+ }
+ }
+}
+
diff --git a/awt/java/awt/Component.java b/awt/java/awt/Component.java
new file mode 100644
index 0000000..f19d285
--- /dev/null
+++ b/awt/java/awt/Component.java
@@ -0,0 +1,6408 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+//import java.awt.dnd.DropTarget;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.HierarchyBoundsListener;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.InputMethodListener;
+import java.awt.event.InvocationEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.event.PaintEvent;
+import java.awt.event.WindowEvent;
+import java.awt.im.InputContext;
+import java.awt.im.InputMethodRequests;
+import java.awt.image.BufferStrategy;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.VolatileImage;
+import java.awt.image.WritableRaster;
+import java.awt.peer.ComponentPeer;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+//???AWT
+//import javax.accessibility.Accessible;
+//import javax.accessibility.AccessibleComponent;
+//import javax.accessibility.AccessibleContext;
+//import javax.accessibility.AccessibleRole;
+//import javax.accessibility.AccessibleState;
+//import javax.accessibility.AccessibleStateSet;
+
+import org.apache.harmony.awt.ClipRegion;
+//import org.apache.harmony.awt.FieldsAccessor;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.state.State;
+//import org.apache.harmony.awt.text.TextFieldKit;
+//import org.apache.harmony.awt.text.TextKit;
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+/**
+ * The abstract Component class specifies an object with a graphical
+ * representation that can be displayed on the screen and that can
+ * interact with the user (for example: scrollbars, buttons, checkboxes).
+ */
+public abstract class Component implements ImageObserver, MenuContainer, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -7644114512714619750L;
+
+ /** The Constant TOP_ALIGNMENT indicates the top alignment of the component. */
+ public static final float TOP_ALIGNMENT = 0.0f;
+
+ /** The Constant CENTER_ALIGNMENT indicates the center alignment of the component. */
+ public static final float CENTER_ALIGNMENT = 0.5f;
+
+ /** The Constant BOTTOM_ALIGNMENT indicates the bottom alignment of the component. */
+ public static final float BOTTOM_ALIGNMENT = 1.0f;
+
+ /** The Constant LEFT_ALIGNMENT indicates the left alignment of the component. */
+ public static final float LEFT_ALIGNMENT = 0.0f;
+
+ /** The Constant RIGHT_ALIGNMENT indicates the right alignment of the component. */
+ public static final float RIGHT_ALIGNMENT = 1.0f;
+
+ /** The Constant childClassesFlags. */
+ private static final Hashtable<Class<?>, Boolean> childClassesFlags = new Hashtable<Class<?>, Boolean>();
+
+ /** The Constant peer. */
+ private static final ComponentPeer peer = new ComponentPeer() {
+ };
+
+ /** The Constant incrementalImageUpdate. */
+ private static final boolean incrementalImageUpdate;
+
+ /** The toolkit. */
+ final transient Toolkit toolkit = Toolkit.getDefaultToolkit();
+
+ //???AWT
+ /*
+ protected abstract class AccessibleAWTComponent extends AccessibleContext implements
+ Serializable, AccessibleComponent {
+ private static final long serialVersionUID = 642321655757800191L;
+
+ protected class AccessibleAWTComponentHandler implements ComponentListener {
+ protected AccessibleAWTComponentHandler() {
+ }
+
+ public void componentHidden(ComponentEvent e) {
+ if (behaviour.isLightweight()) {
+ return;
+ }
+ firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
+ AccessibleState.VISIBLE, null);
+ }
+
+ public void componentMoved(ComponentEvent e) {
+ }
+
+ public void componentResized(ComponentEvent e) {
+ }
+
+ public void componentShown(ComponentEvent e) {
+ if (behaviour.isLightweight()) {
+ return;
+ }
+ firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null,
+ AccessibleState.VISIBLE);
+ }
+ }
+
+ protected class AccessibleAWTFocusHandler implements FocusListener {
+ public void focusGained(FocusEvent e) {
+ if (behaviour.isLightweight()) {
+ return;
+ }
+ firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null,
+ AccessibleState.FOCUSED);
+ }
+
+ public void focusLost(FocusEvent e) {
+ if (behaviour.isLightweight()) {
+ return;
+ }
+ firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
+ AccessibleState.FOCUSED, null);
+ }
+ }
+
+ protected ComponentListener accessibleAWTComponentHandler;
+
+ protected FocusListener accessibleAWTFocusHandler;
+ */
+ /*
+ * Number of registered property change listeners.
+ */
+ /*
+ int listenersCount;
+
+ public void addFocusListener(FocusListener l) {
+ Component.this.addFocusListener(l);
+ }
+
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ toolkit.lockAWT();
+ try {
+ super.addPropertyChangeListener(listener);
+ listenersCount++;
+ if (accessibleAWTComponentHandler == null) {
+ accessibleAWTComponentHandler = new AccessibleAWTComponentHandler();
+ Component.this.addComponentListener(accessibleAWTComponentHandler);
+ }
+ if (accessibleAWTFocusHandler == null) {
+ accessibleAWTFocusHandler = new AccessibleAWTFocusHandler();
+ Component.this.addFocusListener(accessibleAWTFocusHandler);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean contains(Point p) {
+ toolkit.lockAWT();
+ try {
+ return Component.this.contains(p);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Accessible getAccessibleAt(Point arg0) {
+ toolkit.lockAWT();
+ try {
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Color getBackground() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getBackground();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Rectangle getBounds() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getBounds();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Cursor getCursor() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getCursor();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Font getFont() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getFont();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public FontMetrics getFontMetrics(Font f) {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getFontMetrics(f);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Color getForeground() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getForeground();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Point getLocation() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getLocation();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Point getLocationOnScreen() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getLocationOnScreen();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Dimension getSize() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getSize();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean isEnabled() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.isEnabled();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean isFocusTraversable() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.isFocusTraversable();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean isShowing() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.isShowing();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean isVisible() {
+ toolkit.lockAWT();
+ try {
+ return Component.this.isVisible();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void removeFocusListener(FocusListener l) {
+ Component.this.removeFocusListener(l);
+ }
+
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ toolkit.lockAWT();
+ try {
+ super.removePropertyChangeListener(listener);
+ listenersCount--;
+ if (listenersCount > 0) {
+ return;
+ }
+ // if there are no more listeners, remove handlers:
+ Component.this.removeFocusListener(accessibleAWTFocusHandler);
+ Component.this.removeComponentListener(accessibleAWTComponentHandler);
+ accessibleAWTComponentHandler = null;
+ accessibleAWTFocusHandler = null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void requestFocus() {
+ toolkit.lockAWT();
+ try {
+ Component.this.requestFocus();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setBackground(Color color) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setBackground(color);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setBounds(Rectangle r) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setBounds(r);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setCursor(Cursor cursor) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setCursor(cursor);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setEnabled(boolean enabled) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setEnabled(enabled);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setFont(Font f) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setFont(f);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setForeground(Color color) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setForeground(color);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setLocation(Point p) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setLocation(p);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setSize(Dimension size) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setSize(size);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void setVisible(boolean visible) {
+ toolkit.lockAWT();
+ try {
+ Component.this.setVisible(visible);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public Accessible getAccessibleParent() {
+ toolkit.lockAWT();
+ try {
+ Accessible aParent = super.getAccessibleParent();
+ if (aParent != null) {
+ return aParent;
+ }
+ Container parent = getParent();
+ return (parent instanceof Accessible ? (Accessible) parent : null);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public Accessible getAccessibleChild(int i) {
+ toolkit.lockAWT();
+ try {
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public int getAccessibleChildrenCount() {
+ toolkit.lockAWT();
+ try {
+ return 0;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public AccessibleComponent getAccessibleComponent() {
+ return this;
+ }
+
+ @Override
+ public String getAccessibleDescription() {
+ return super.getAccessibleDescription(); // why override?
+ }
+
+ @Override
+ public int getAccessibleIndexInParent() {
+ toolkit.lockAWT();
+ try {
+ if (getAccessibleParent() == null) {
+ return -1;
+ }
+ int count = 0;
+ Container parent = getParent();
+ for (int i = 0; i < parent.getComponentCount(); i++) {
+ Component aComp = parent.getComponent(i);
+ if (aComp instanceof Accessible) {
+ if (aComp == Component.this) {
+ return count;
+ }
+ ++count;
+ }
+ }
+ return -1;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public AccessibleRole getAccessibleRole() {
+ toolkit.lockAWT();
+ try {
+ return AccessibleRole.AWT_COMPONENT;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public AccessibleStateSet getAccessibleStateSet() {
+ toolkit.lockAWT();
+ try {
+ AccessibleStateSet set = new AccessibleStateSet();
+ if (isEnabled()) {
+ set.add(AccessibleState.ENABLED);
+ }
+ if (isFocusable()) {
+ set.add(AccessibleState.FOCUSABLE);
+ }
+ if (hasFocus()) {
+ set.add(AccessibleState.FOCUSED);
+ }
+ if (isOpaque()) {
+ set.add(AccessibleState.OPAQUE);
+ }
+ if (isShowing()) {
+ set.add(AccessibleState.SHOWING);
+ }
+ if (isVisible()) {
+ set.add(AccessibleState.VISIBLE);
+ }
+ return set;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public Locale getLocale() throws IllegalComponentStateException {
+ toolkit.lockAWT();
+ try {
+ return Component.this.getLocale();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ }
+ */
+ /**
+ * The BltBufferStrategy class provides opportunity of blitting
+ * offscreen surfaces to a component. For more information on
+ * blitting, see <a href="http://en.wikipedia.org/wiki/Bit_blit">Bit blit</a>.
+ */
+ protected class BltBufferStrategy extends BufferStrategy {
+
+ /** The back buffers. */
+ protected VolatileImage[] backBuffers;
+
+ /** The caps. */
+ protected BufferCapabilities caps;
+
+ /** The width. */
+ protected int width;
+
+ /** The height. */
+ protected int height;
+
+ /** The validated contents. */
+ protected boolean validatedContents;
+
+ /**
+ * Instantiates a new BltBufferStrategy buffer strategy.
+ *
+ * @param numBuffers the number of buffers.
+ * @param caps the BufferCapabilities.
+ *
+ * @throws NotImplementedException the not implemented exception.
+ */
+ protected BltBufferStrategy(int numBuffers, BufferCapabilities caps) throws org.apache.harmony.luni.util.NotImplementedException {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns true if the drawing buffer has been lost since the last call
+ * to getDrawGraphics.
+ *
+ * @return true if the drawing buffer has been lost since the last call
+ * to getDrawGraphics, false otherwise.
+ *
+ * @see java.awt.image.BufferStrategy#contentsLost()
+ */
+ @Override
+ public boolean contentsLost() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the drawing buffer has been restored from a lost
+ * state and reinitialized to the default background color.
+ *
+ * @return true if the drawing buffer has been restored from a lost
+ * state and reinitialized to the default background color,
+ * false otherwise.
+ *
+ * @see java.awt.image.BufferStrategy#contentsRestored()
+ */
+ @Override
+ public boolean contentsRestored() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return false;
+ }
+
+ /**
+ * Creates the back buffers.
+ *
+ * @param numBuffers the number of buffers.
+ */
+ protected void createBackBuffers(int numBuffers) {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the BufferCapabilities of the buffer strategy.
+ *
+ * @return the BufferCapabilities.
+ *
+ * @see java.awt.image.BufferStrategy#getCapabilities()
+ */
+ @Override
+ public BufferCapabilities getCapabilities() {
+ return (BufferCapabilities) caps.clone();
+ }
+
+ /**
+ * Gets Graphics of current buffer strategy.
+ *
+ * @return the Graphics of current buffer strategy.
+ *
+ * @see java.awt.image.BufferStrategy#getDrawGraphics()
+ */
+ @Override
+ public Graphics getDrawGraphics() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Revalidates the lost drawing buffer.
+ */
+ protected void revalidate() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Shows the next available buffer.
+ *
+ * @see java.awt.image.BufferStrategy#show()
+ */
+ @Override
+ public void show() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * The FlipBufferStrategy class is for flipping buffers on a component.
+ */
+ protected class FlipBufferStrategy extends BufferStrategy {
+
+ /** The Buffer Capabilities. */
+ protected BufferCapabilities caps;
+
+ /** The drawing buffer. */
+ protected Image drawBuffer;
+
+ /** The drawing VolatileImage buffer. */
+ protected VolatileImage drawVBuffer;
+
+ /** The number of buffers. */
+ protected int numBuffers;
+
+ /** The validated contents indicates if the drawing buffer is restored from
+ * lost state. */
+ protected boolean validatedContents;
+
+ /**
+ * Instantiates a new flip buffer strategy.
+ *
+ * @param numBuffers the number of buffers.
+ * @param caps the BufferCapabilities.
+ *
+ * @throws AWTException if the capabilities supplied could not
+ * be supported or met.
+ */
+ protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps)
+ throws AWTException {
+ //???AWT
+ /*
+ if (!(Component.this instanceof Window) && !(Component.this instanceof Canvas)) {
+ // awt.14B=Only Canvas or Window is allowed
+ throw new ClassCastException(Messages.getString("awt.14B")); //$NON-NLS-1$
+ }
+ */
+ // TODO: throw new AWTException("Capabilities are not supported");
+ this.numBuffers = numBuffers;
+ this.caps = (BufferCapabilities) caps.clone();
+ }
+
+ /**
+ * Returns true if the drawing buffer has been lost since the last call
+ * to getDrawGraphics.
+ *
+ * @return true if the drawing buffer has been lost since the last call
+ * to getDrawGraphics, false otherwise.
+ *
+ * @see java.awt.image.BufferStrategy#contentsLost()
+ */
+ @Override
+ public boolean contentsLost() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the drawing buffer has been restored from a lost
+ * state and reinitialized to the default background color.
+ *
+ * @return true if the drawing buffer has been restored from a lost
+ * state and reinitialized to the default background color,
+ * false otherwise.
+ *
+ * @see java.awt.image.BufferStrategy#contentsRestored()
+ */
+ @Override
+ public boolean contentsRestored() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return false;
+ }
+
+ /**
+ * Creates flipping buffers with the specified buffer capabilities.
+ *
+ * @param numBuffers the number of buffers.
+ * @param caps the BufferCapabilities.
+ *
+ * @throws AWTException if the capabilities could not be
+ * supported or met.
+ */
+ protected void createBuffers(int numBuffers, BufferCapabilities caps)
+ throws AWTException {
+ if (numBuffers < 2) {
+ // awt.14C=Number of buffers must be greater than one
+ throw new IllegalArgumentException(Messages.getString("awt.14C")); //$NON-NLS-1$
+ }
+ if (!caps.isPageFlipping()) {
+ // awt.14D=Buffer capabilities should support flipping
+ throw new IllegalArgumentException(Messages.getString("awt.14D")); //$NON-NLS-1$
+ }
+ if (!Component.this.behaviour.isDisplayable()) {
+ // awt.14E=Component should be displayable
+ throw new IllegalStateException(Messages.getString("awt.14E")); //$NON-NLS-1$
+ }
+ // TODO: throw new AWTException("Capabilities are not supported");
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Destroy buffers.
+ */
+ protected void destroyBuffers() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Flips the contents of the back buffer to the front buffer.
+ *
+ * @param flipAction the flip action.
+ */
+ protected void flip(BufferCapabilities.FlipContents flipAction) {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Gets the back buffer as Image.
+ *
+ * @return the back buffer as Image.
+ */
+ protected Image getBackBuffer() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Returns the BufferCapabilities of the buffer strategy.
+ *
+ * @return the BufferCapabilities.
+ *
+ * @see java.awt.image.BufferStrategy#getCapabilities()
+ */
+ @Override
+ public BufferCapabilities getCapabilities() {
+ return (BufferCapabilities) caps.clone();
+ }
+
+ /**
+ * Gets Graphics of current buffer strategy.
+ *
+ * @return the Graphics of current buffer strategy.
+ *
+ * @see java.awt.image.BufferStrategy#getDrawGraphics()
+ */
+ @Override
+ public Graphics getDrawGraphics() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Revalidates the lost drawing buffer.
+ */
+ protected void revalidate() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Shows the next available buffer.
+ *
+ * @see java.awt.image.BufferStrategy#show()
+ */
+ @Override
+ public void show() {
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * The internal component's state utilized by the visual theme.
+ */
+ class ComponentState implements State {
+
+ /** The default minimum size. */
+ private Dimension defaultMinimumSize = new Dimension();
+
+ /**
+ * Checks if the component is enabled.
+ *
+ * @return true, if the component is enabled
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Checks if the component is visible.
+ *
+ * @return true, if the component is visible
+ */
+ public boolean isVisible() {
+ return visible;
+ }
+
+ /**
+ * Checks if is focused.
+ *
+ * @return true, if is focused
+ */
+ public boolean isFocused() {
+ //???AWT: return isFocusOwner();
+ return false;
+ }
+
+ /**
+ * Gets the font.
+ *
+ * @return the font
+ */
+ public Font getFont() {
+ return Component.this.getFont();
+ }
+
+ /**
+ * Checks if the font has been set.
+ *
+ * @return true, if the font has been set
+ */
+ public boolean isFontSet() {
+ return font != null;
+ }
+
+ /**
+ * Gets the background color.
+ *
+ * @return the background color
+ */
+ public Color getBackground() {
+ Color c = Component.this.getBackground();
+ return (c != null) ? c : getDefaultBackground();
+ }
+
+ /**
+ * Checks if the background is set.
+ *
+ * @return true, if the background is set
+ */
+ public boolean isBackgroundSet() {
+ return backColor != null;
+ }
+
+ /**
+ * Gets the text color.
+ *
+ * @return the text color
+ */
+ public Color getTextColor() {
+ Color c = getForeground();
+ return (c != null) ? c : getDefaultForeground();
+ }
+
+ /**
+ * Checks if the text color is set.
+ *
+ * @return true, if the text color is set
+ */
+ public boolean isTextColorSet() {
+ return foreColor != null;
+ }
+
+ /**
+ * Gets the font metrics.
+ *
+ * @return the font metrics
+ */
+ @SuppressWarnings("deprecation")
+ public FontMetrics getFontMetrics() {
+ return toolkit.getFontMetrics(Component.this.getFont());
+ }
+
+ /**
+ * Gets the bounding rectangle.
+ *
+ * @return the bounding rectangle
+ */
+ public Rectangle getBounds() {
+ return new Rectangle(x, y, w, h);
+ }
+
+ /**
+ * Gets the size of the bounding rectangle.
+ *
+ * @return the size of the bounding rectangle
+ */
+ public Dimension getSize() {
+ return new Dimension(w, h);
+ }
+
+ /**
+ * Gets the window id.
+ *
+ * @return the window id
+ */
+ public long getWindowId() {
+ NativeWindow win = getNativeWindow();
+ return (win != null) ? win.getId() : 0;
+ }
+
+ /**
+ * Gets the default minimum size.
+ *
+ * @return the default minimum size
+ */
+ public Dimension getDefaultMinimumSize() {
+ if (defaultMinimumSize == null) {
+ calculate();
+ }
+ return defaultMinimumSize;
+ }
+
+ /**
+ * Sets the default minimum size.
+ *
+ * @param size the new default minimum size
+ */
+ public void setDefaultMinimumSize(Dimension size) {
+ defaultMinimumSize = size;
+ }
+
+ /**
+ * Reset the default minimum size to null.
+ */
+ public void reset() {
+ defaultMinimumSize = null;
+ }
+
+ /**
+ * Calculate the default minimum size: to be overridden.
+ */
+ public void calculate() {
+ // to be overridden
+ }
+ }
+
+ //???AWT: private transient AccessibleContext accessibleContext;
+
+ /** The behaviour. */
+ final transient ComponentBehavior behaviour;
+
+ //???AWT: Container parent;
+
+ /** The name. */
+ private String name;
+
+ /** The auto name. */
+ private boolean autoName = true;
+
+ /** The font. */
+ private Font font;
+
+ /** The back color. */
+ private Color backColor;
+
+ /** The fore color. */
+ private Color foreColor;
+
+ /** The deprecated event handler. */
+ boolean deprecatedEventHandler = true;
+
+ /** The enabled events. */
+ private long enabledEvents;
+
+ /** The enabled awt events. */
+ private long enabledAWTEvents;
+
+ /** The component listeners. */
+ private final AWTListenerList<ComponentListener> componentListeners = new AWTListenerList<ComponentListener>(
+ this);
+
+ /** The focus listeners. */
+ private final AWTListenerList<FocusListener> focusListeners = new AWTListenerList<FocusListener>(
+ this);
+
+ /** The hierarchy listeners. */
+ private final AWTListenerList<HierarchyListener> hierarchyListeners = new AWTListenerList<HierarchyListener>(
+ this);
+
+ /** The hierarchy bounds listeners. */
+ private final AWTListenerList<HierarchyBoundsListener> hierarchyBoundsListeners = new AWTListenerList<HierarchyBoundsListener>(
+ this);
+
+ /** The key listeners. */
+ private final AWTListenerList<KeyListener> keyListeners = new AWTListenerList<KeyListener>(
+ this);
+
+ /** The mouse listeners. */
+ private final AWTListenerList<MouseListener> mouseListeners = new AWTListenerList<MouseListener>(
+ this);
+
+ /** The mouse motion listeners. */
+ private final AWTListenerList<MouseMotionListener> mouseMotionListeners = new AWTListenerList<MouseMotionListener>(
+ this);
+
+ /** The mouse wheel listeners. */
+ private final AWTListenerList<MouseWheelListener> mouseWheelListeners = new AWTListenerList<MouseWheelListener>(
+ this);
+
+ /** The input method listeners. */
+ private final AWTListenerList<InputMethodListener> inputMethodListeners = new AWTListenerList<InputMethodListener>(
+ this);
+
+ /** The x. */
+ int x;
+
+ /** The y. */
+ int y;
+
+ /** The w. */
+ int w;
+
+ /** The h. */
+ int h;
+
+ /** The maximum size. */
+ private Dimension maximumSize;
+
+ /** The minimum size. */
+ private Dimension minimumSize;
+
+ /** The preferred size. */
+ private Dimension preferredSize;
+
+ /** The bounds mask param. */
+ private int boundsMaskParam;
+
+ /** The ignore repaint. */
+ private boolean ignoreRepaint;
+
+ /** The enabled. */
+ private boolean enabled = true;
+
+ /** The input methods enabled. */
+ private boolean inputMethodsEnabled = true;
+
+ /** The dispatch to im. */
+ transient boolean dispatchToIM = true;
+
+ /** The focusable. */
+ private boolean focusable = true; // By default, all Components return
+
+ // true from isFocusable() method
+ /** The visible. */
+ boolean visible = true;
+
+ /** The called set focusable. */
+ private boolean calledSetFocusable;
+
+ /** The overriden is focusable. */
+ private boolean overridenIsFocusable = true;
+
+ /** The focus traversal keys enabled. */
+ private boolean focusTraversalKeysEnabled = true;
+
+ /** Possible keys are: FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, UP_CYCLE_TRAVERSAL_KEYS. */
+ private final Map<Integer, Set<? extends AWTKeyStroke>> traversalKeys = new HashMap<Integer, Set<? extends AWTKeyStroke>>();
+
+ /** The traversal i ds. */
+ int[] traversalIDs;
+
+ /** The locale. */
+ private Locale locale;
+
+ /** The orientation. */
+ private ComponentOrientation orientation;
+
+ /** The property change support. */
+ private PropertyChangeSupport propertyChangeSupport;
+
+ //???AWT: private ArrayList<PopupMenu> popups;
+
+ /** The coalescer. */
+ private boolean coalescer;
+
+ /** The events table. */
+ private Hashtable<Integer, LinkedList<AWTEvent>> eventsTable;
+
+ /** Cashed reference used during EventQueue.postEvent() */
+ private LinkedList<AWTEvent> eventsList;
+
+ /** The hierarchy changing counter. */
+ private int hierarchyChangingCounter;
+
+ /** The was showing. */
+ private boolean wasShowing;
+
+ /** The was displayable. */
+ private boolean wasDisplayable;
+
+ /** The cursor. */
+ Cursor cursor;
+
+ //???AWT: DropTarget dropTarget;
+
+ /** The mouse exited expected. */
+ private boolean mouseExitedExpected;
+
+ /** The repaint region. */
+ transient MultiRectArea repaintRegion;
+
+ //???AWT: transient RedrawManager redrawManager;
+ /** The redraw manager. */
+ transient Object redrawManager;
+
+ /** The valid. */
+ private boolean valid;
+
+ /** The updated images. */
+ private HashMap<Image, ImageParameters> updatedImages;
+
+ /**
+ * The lock object for private component's data which don't affect the
+ * component hierarchy.
+ */
+ private class ComponentLock {
+ }
+
+ /** The component lock. */
+ private final transient Object componentLock = new ComponentLock();
+ static {
+ PrivilegedAction<String[]> action = new PrivilegedAction<String[]>() {
+ public String[] run() {
+ String properties[] = new String[2];
+ properties[0] = System.getProperty("awt.image.redrawrate", "100"); //$NON-NLS-1$ //$NON-NLS-2$
+ properties[1] = System.getProperty("awt.image.incrementaldraw", "true"); //$NON-NLS-1$ //$NON-NLS-2$
+ return properties;
+ }
+ };
+ String properties[] = AccessController.doPrivileged(action);
+ // FIXME: rate is never used, can this code and the get property above
+ // be removed?
+ // int rate;
+ //
+ // try {
+ // rate = Integer.decode(properties[0]).intValue();
+ // } catch (NumberFormatException e) {
+ // rate = 100;
+ // }
+ incrementalImageUpdate = properties[1].equals("true"); //$NON-NLS-1$
+ }
+
+ /**
+ * Instantiates a new component.
+ */
+ protected Component() {
+ toolkit.lockAWT();
+ try {
+ orientation = ComponentOrientation.UNKNOWN;
+ redrawManager = null;
+ //???AWT
+ /*
+ traversalIDs = this instanceof Container ? KeyboardFocusManager.contTraversalIDs
+ : KeyboardFocusManager.compTraversalIDs;
+ for (int element : traversalIDs) {
+ traversalKeys.put(new Integer(element), null);
+ }
+ behaviour = createBehavior();
+ */
+ behaviour = null;
+
+ deriveCoalescerFlag();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Determine that the class inherited from Component declares the method
+ * coalesceEvents(), and put the results to the childClassesFlags map.
+ */
+ private void deriveCoalescerFlag() {
+ Class<?> thisClass = getClass();
+ boolean flag = true;
+ synchronized (childClassesFlags) {
+ Boolean flagWrapper = childClassesFlags.get(thisClass);
+ if (flagWrapper == null) {
+ Method coalesceMethod = null;
+ for (Class<?> c = thisClass; c != Component.class; c = c.getSuperclass()) {
+ try {
+ coalesceMethod = c.getDeclaredMethod("coalesceEvents", new Class[] { //$NON-NLS-1$
+ Class.forName("java.awt.AWTEvent"), //$NON-NLS-1$
+ Class.forName("java.awt.AWTEvent") }); //$NON-NLS-1$
+ } catch (Exception e) {
+ }
+ if (coalesceMethod != null) {
+ break;
+ }
+ }
+ flag = (coalesceMethod != null);
+ childClassesFlags.put(thisClass, Boolean.valueOf(flag));
+ } else {
+ flag = flagWrapper.booleanValue();
+ }
+ }
+ coalescer = flag;
+ if (flag) {
+ eventsTable = new Hashtable<Integer, LinkedList<AWTEvent>>();
+ } else {
+ eventsTable = null;
+ }
+ }
+
+ /**
+ * Sets the name of the Component.
+ *
+ * @param name the new name of the Component.
+ */
+ public void setName(String name) {
+ String oldName;
+ toolkit.lockAWT();
+ try {
+ autoName = false;
+ oldName = this.name;
+ this.name = name;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("name", oldName, name); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the name of this Component.
+ *
+ * @return the name of this Component.
+ */
+ public String getName() {
+ toolkit.lockAWT();
+ try {
+ if ((name == null) && autoName) {
+ name = autoName();
+ }
+ return name;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Auto name.
+ *
+ * @return the string
+ */
+ String autoName() {
+ String name = getClass().getName();
+ if (name.indexOf("$") != -1) { //$NON-NLS-1$
+ return null;
+ }
+ //???AWT
+ //int number = toolkit.autoNumber.nextComponent++;
+ int number = 0;
+ name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$
+ return name;
+ }
+
+ /**
+ * Returns the string representation of the Component.
+ *
+ * @return the string representation of the Component.
+ */
+ @Override
+ public String toString() {
+ /*
+ * The format is based on 1.5 release behavior which can be revealed by
+ * the following code:
+ *
+ * Component c = new Component(){}; c.setVisible(false);
+ * System.out.println(c);
+ */
+ toolkit.lockAWT();
+ try {
+ return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ public void add(PopupMenu popup) {
+ toolkit.lockAWT();
+ try {
+ if (popup.getParent() == this) {
+ return;
+ }
+ if (popups == null) {
+ popups = new ArrayList<PopupMenu>();
+ }
+ popup.setParent(this);
+ popups.add(popup);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Returns true, if the component contains the specified Point.
+ *
+ * @param p the Point.
+ *
+ * @return true, if the component contains the specified Point,
+ * false otherwise.
+ */
+ public boolean contains(Point p) {
+ toolkit.lockAWT();
+ try {
+ return contains(p.x, p.y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns true, if the component contains the point with
+ * the specified coordinates.
+ *
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if the component contains the point with
+ * the specified coordinates, false otherwise.
+ */
+ public boolean contains(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ return inside(x, y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by replaced by getSize() method.
+ *
+ * @return the dimension.
+ *
+ * @deprecated Replaced by getSize() method.
+ */
+ @Deprecated
+ public Dimension size() {
+ toolkit.lockAWT();
+ try {
+ return new Dimension(w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ public Container getParent() {
+ toolkit.lockAWT();
+ try {
+ return parent;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * List.
+ *
+ * @param out the out
+ * @param indent the indent
+ *
+ * @return the nearest heavyweight ancestor in hierarchy or
+ * <code>null</code> if not found
+ */
+ //???AWT
+ /*
+ Component getHWAncestor() {
+ return (parent != null ? parent.getHWSurface() : null);
+ }
+ */
+
+ /**
+ * @return heavyweight component that is equal to or is a nearest
+ * heavyweight container of the current component, or
+ * <code>null</code> if not found
+ */
+ //???AWT
+ /*
+ Component getHWSurface() {
+ Component parent;
+ for (parent = this; (parent != null) && (parent.isLightweight()); parent = parent
+ .getParent()) {
+ ;
+ }
+ return parent;
+ }
+
+ Window getWindowAncestor() {
+ Component par;
+ for (par = this; par != null && !(par instanceof Window); par = par.getParent()) {
+ ;
+ }
+ return (Window) par;
+ }
+ */
+
+ /** To be called by container */
+ //???AWT
+ /*
+ void setParent(Container parent) {
+ this.parent = parent;
+ setRedrawManager();
+ }
+
+ void setRedrawManager() {
+ redrawManager = getRedrawManager();
+ }
+
+ public void remove(MenuComponent menu) {
+ toolkit.lockAWT();
+ try {
+ if (menu.getParent() == this) {
+ menu.setParent(null);
+ popups.remove(menu);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+ /**
+ * Prints a list of this component with the specified number of
+ * leading whitespace characters to the specified PrintStream.
+ *
+ * @param out the output PrintStream object.
+ * @param indent how many leading whitespace characters to prepend
+ */
+ public void list(PrintStream out, int indent) {
+ toolkit.lockAWT();
+ try {
+ out.println(getIndentStr(indent) + this);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prints a list of this component to the specified PrintWriter.
+ *
+ * @param out the output PrintWriter object.
+ */
+ public void list(PrintWriter out) {
+ toolkit.lockAWT();
+ try {
+ list(out, 1);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prints a list of this component with the specified number of
+ * leading whitespace characters to the specified PrintWriter.
+ *
+ * @param out the output PrintWriter object.
+ * @param indent how many leading whitespace characters to prepend
+ */
+ public void list(PrintWriter out, int indent) {
+ toolkit.lockAWT();
+ try {
+ out.println(getIndentStr(indent) + this);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets a string composed of the desired number of
+ * whitespace characters.
+ *
+ * @param indent the length of the String to return
+ *
+ * @return the string composed of the desired number of
+ * whitespace characters
+ */
+ String getIndentStr(int indent) {
+ char[] ind = new char[indent];
+ for (int i = 0; i < indent; ind[i++] = ' ') {
+ ;
+ }
+ return new String(ind);
+ }
+
+ /**
+ * Prints a list of this component to the specified PrintStream
+ *
+ * @param out the output PrintStream object.
+ */
+ public void list(PrintStream out) {
+ toolkit.lockAWT();
+ try {
+ // default indent = 1
+ list(out, 1);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prints a list of this component to the standard system
+ * output stream.
+ */
+ public void list() {
+ toolkit.lockAWT();
+ try {
+ list(System.out);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prints this component.
+ *
+ * @param g the Graphics to be used for painting.
+ */
+ public void print(Graphics g) {
+ toolkit.lockAWT();
+ try {
+ paint(g);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prints the component and all of its subcomponents.
+ *
+ * @param g the Graphics to be used for painting.
+ */
+ public void printAll(Graphics g) {
+ toolkit.lockAWT();
+ try {
+ paintAll(g);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the size of the Component specified by width and height
+ * parameters.
+ *
+ * @param width the width of the Component.
+ * @param height the height of the Component.
+ */
+ public void setSize(int width, int height) {
+ toolkit.lockAWT();
+ try {
+ resize(width, height);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the size of the Component specified by Dimension object.
+ *
+ * @param d the new size of the Component.
+ */
+ public void setSize(Dimension d) {
+ toolkit.lockAWT();
+ try {
+ resize(d);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by setSize(int, int) method.
+ *
+ * @param width the width.
+ * @param height the height.
+ *
+ * @deprecated Replaced by setSize(int, int) method.
+ */
+ @Deprecated
+ public void resize(int width, int height) {
+ toolkit.lockAWT();
+ try {
+ boundsMaskParam = NativeWindow.BOUNDS_NOMOVE;
+ setBounds(x, y, width, height);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by setSize(int, int) method.
+ *
+ * @param size the size.
+ *
+ * @deprecated Replaced by setSize(int, int) method.
+ */
+ @Deprecated
+ public void resize(Dimension size) {
+ toolkit.lockAWT();
+ try {
+ setSize(size.width, size.height);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not this component is completely opaque.
+ *
+ * @return true, if this component is completely opaque,
+ * false by default.
+ */
+ public boolean isOpaque() {
+ toolkit.lockAWT();
+ try {
+ return behaviour.isOpaque();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Disables.
+ *
+ * @deprecated Replaced by setEnabled(boolean) method.
+ */
+ @Deprecated
+ public void disable() {
+ toolkit.lockAWT();
+ try {
+ setEnabledImpl(false);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ //???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, false);
+ }
+
+ /**
+ * Enables this component.
+ *
+ * @deprecated Replaced by setEnabled(boolean) method.
+ */
+ @Deprecated
+ public void enable() {
+ toolkit.lockAWT();
+ try {
+ setEnabledImpl(true);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ //???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, true);
+ }
+
+ /**
+ * Enables or disable this component.
+ *
+ * @param b the boolean parameter.
+ *
+ * @deprecated Replaced by setEnabled(boolean) method.
+ */
+ @Deprecated
+ public void enable(boolean b) {
+ toolkit.lockAWT();
+ try {
+ if (b) {
+ enable();
+ } else {
+ disable();
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Stores the location of this component to the specified Point object;
+ * returns the point of the component's top-left corner.
+ *
+ * @param rv the Point object where the component's top-left corner
+ * position will be stored.
+ *
+ * @return the Point which specifies the component's top-left corner.
+ */
+ public Point getLocation(Point rv) {
+ toolkit.lockAWT();
+ try {
+ if (rv == null) {
+ rv = new Point();
+ }
+ rv.setLocation(getX(), getY());
+ return rv;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the location of this component on the form;
+ * returns the point of the component's top-left corner.
+ *
+ * @return the Point which specifies the component's top-left corner.
+ */
+ public Point getLocation() {
+ toolkit.lockAWT();
+ try {
+ return location();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the size of this Component.
+ *
+ * @return the size of this Component.
+ */
+ public Dimension getSize() {
+ toolkit.lockAWT();
+ try {
+ return size();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Stores the size of this Component to the specified Dimension
+ * object.
+ *
+ * @param rv the Dimension object where the size of the Component
+ * will be stored.
+ *
+ * @return the Dimension of this Component.
+ */
+ public Dimension getSize(Dimension rv) {
+ toolkit.lockAWT();
+ try {
+ if (rv == null) {
+ rv = new Dimension();
+ }
+ rv.setSize(getWidth(), getHeight());
+ return rv;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not this Component is valid. A component is valid
+ * if it is correctly sized and positioned within its parent container
+ * and all its children are also valid.
+ *
+ * @return true, if the Component is valid, false otherwise.
+ */
+ public boolean isValid() {
+ toolkit.lockAWT();
+ try {
+ return valid && behaviour.isDisplayable();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by getComponentAt(int, int) method.
+ *
+ * @return the Point.
+ *
+ * @deprecated Replaced by getComponentAt(int, int) method.
+ */
+ @Deprecated
+ public Point location() {
+ toolkit.lockAWT();
+ try {
+ return new Point(x, y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Connects this Component to a native screen resource and makes it
+ * displayable. This method not be called directly by user applications.
+ */
+ public void addNotify() {
+ toolkit.lockAWT();
+ try {
+ prepare4HierarchyChange();
+ behaviour.addNotify();
+ //???AWT
+// finishHierarchyChange(this, parent, 0);
+// if (dropTarget != null) {
+// dropTarget.addNotify(peer);
+// }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Map to display.
+ *
+ * @param b the b
+ */
+ void mapToDisplay(boolean b) {
+ //???AWT
+ /*
+ if (b && !isDisplayable()) {
+ if ((this instanceof Window) || ((parent != null) && parent.isDisplayable())) {
+ addNotify();
+ }
+ } else if (!b && isDisplayable()) {
+ removeNotify();
+ }
+ */
+ }
+
+ /**
+ * Gets the toolkit.
+ *
+ * @return accessible context specific for particular component
+ */
+ //???AWT
+ /*
+ AccessibleContext createAccessibleContext() {
+ return null;
+ }
+
+ public AccessibleContext getAccessibleContext() {
+ toolkit.lockAWT();
+ try {
+ if (accessibleContext == null) {
+ accessibleContext = createAccessibleContext();
+ }
+ return accessibleContext;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Gets Toolkit for the current Component.
+ *
+ * @return the Toolkit of this Component.
+ */
+ public Toolkit getToolkit() {
+ return toolkit;
+ }
+
+ /**
+ * Gets this component's locking object for AWT component tree
+ * and layout operations.
+ *
+ * @return the tree locking object.
+ */
+ public final Object getTreeLock() {
+ return toolkit.awtTreeLock;
+ }
+
+ /**
+ * @param evt the Event.
+ * @param what the event's key.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Use ActionListener class for registering event listener.
+ */
+ @Deprecated
+ public boolean action(Event evt, Object what) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+
+ /**
+ * Gets the property change support.
+ *
+ * @return the property change support
+ */
+ private PropertyChangeSupport getPropertyChangeSupport() {
+ synchronized (componentLock) {
+ if (propertyChangeSupport == null) {
+ propertyChangeSupport = new PropertyChangeSupport(this);
+ }
+ return propertyChangeSupport;
+ }
+ }
+
+ //???AWT
+ /*
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ getPropertyChangeSupport().addPropertyChangeListener(listener);
+ }
+
+ public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+ getPropertyChangeSupport().addPropertyChangeListener(propertyName, listener);
+ }
+
+ public void applyComponentOrientation(ComponentOrientation orientation) {
+ toolkit.lockAWT();
+ try {
+ setComponentOrientation(orientation);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Returns true if the set of focus traversal keys for the given focus
+ * traversal operation has been explicitly defined for this Component.
+ *
+ * @param id the ID of traversal key.
+ *
+ * @return true, if the set of focus traversal keys for the given focus
+ * traversal operation has been explicitly defined for this Component,
+ * false otherwise.
+ */
+ public boolean areFocusTraversalKeysSet(int id) {
+ toolkit.lockAWT();
+ try {
+ Integer Id = new Integer(id);
+ if (traversalKeys.containsKey(Id)) {
+ return traversalKeys.get(Id) != null;
+ }
+ // awt.14F=invalid focus traversal key identifier
+ throw new IllegalArgumentException(Messages.getString("awt.14F")); //$NON-NLS-1$
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the bounds of the Component.
+ *
+ * @return the rectangle bounds of the Component.
+ *
+ * @deprecated Use getBounds() methood.
+ */
+ @Deprecated
+ public Rectangle bounds() {
+ toolkit.lockAWT();
+ try {
+ return new Rectangle(x, y, w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the construction status of a specified image
+ * with the specified width and height that is being created.
+ *
+ *
+ * @param image the image to be checked.
+ * @param width the width of scaled image which status is being checked, or -1.
+ * @param height the height of scaled image which status is being checked, or -1.
+ * @param observer the ImageObserver object to be notified while
+ * the image is being prepared.
+ *
+ * @return the ImageObserver flags of the current state of the image data.
+ */
+ public int checkImage(Image image, int width, int height, ImageObserver observer) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.checkImage(image, width, height, observer);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the construction status of a specified image that is being created.
+ *
+ *
+ * @param image the image to be checked.
+ * @param observer the ImageObserver object to be notified while
+ * the image is being prepared.
+ *
+ * @return the ImageObserver flags of the current state of the image data.
+ */
+ public int checkImage(Image image, ImageObserver observer) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.checkImage(image, -1, -1, observer);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Coalesces the existed event with new event.
+ *
+ * @param existingEvent the existing event in the EventQueue.
+ * @param newEvent the new event to be posted to the EventQueue.
+ *
+ * @return the coalesced AWTEvent, or null if there is no coalescing done.
+ */
+ protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) {
+ toolkit.lockAWT();
+ try {
+ // Nothing to do:
+ // 1. Mouse events coalesced at WTK level
+ // 2. Paint events handled by RedrawManager
+ // This method is for overriding only
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if this Component is a coalescer.
+ *
+ * @return true, if is coalescer
+ */
+ boolean isCoalescer() {
+ return coalescer;
+ }
+
+ /**
+ * Gets the relative event.
+ *
+ * @param id the id
+ *
+ * @return the relative event
+ */
+ AWTEvent getRelativeEvent(int id) {
+ Integer idWrapper = new Integer(id);
+ eventsList = eventsTable.get(idWrapper);
+ if (eventsList == null) {
+ eventsList = new LinkedList<AWTEvent>();
+ eventsTable.put(idWrapper, eventsList);
+ return null;
+ }
+ if (eventsList.isEmpty()) {
+ return null;
+ }
+ return eventsList.getLast();
+ }
+
+ /**
+ * Adds the new event.
+ *
+ * @param event the event
+ */
+ void addNewEvent(AWTEvent event) {
+ eventsList.addLast(event);
+ }
+
+ /**
+ * Removes the relative event.
+ */
+ void removeRelativeEvent() {
+ eventsList.removeLast();
+ }
+
+ /**
+ * Removes the next event.
+ *
+ * @param id the id
+ */
+ void removeNextEvent(int id) {
+ eventsTable.get(new Integer(id)).removeFirst();
+ }
+
+ /**
+ * Creates the image with the specified ImageProducer.
+ *
+ * @param producer the ImageProducer to be used for image creation.
+ *
+ * @return the image with the specified ImageProducer.
+ */
+ public Image createImage(ImageProducer producer) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.createImage(producer);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Creates an off-screen drawable image to be used for double buffering.
+ *
+ * @param width the width of the image.
+ * @param height the height of the image.
+ *
+ * @return the off-screen drawable image or null if the component is not
+ * displayable or GraphicsEnvironment.isHeadless() method returns true.
+ */
+ public Image createImage(int width, int height) {
+ toolkit.lockAWT();
+ try {
+ if (!isDisplayable()) {
+ return null;
+ }
+ GraphicsConfiguration gc = getGraphicsConfiguration();
+ if (gc == null) {
+ return null;
+ }
+ ColorModel cm = gc.getColorModel(Transparency.OPAQUE);
+ WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
+ Image image = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), null);
+ fillImageBackground(image, width, height);
+ return image;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Creates an off-screen drawable image with the specified width,
+ * height and ImageCapabilities.
+ *
+ * @param width the width
+ * @param height the height
+ * @param caps the ImageCapabilities.
+ *
+ * @return the volatile image
+ *
+ * @throws AWTException if an image with the specified capabilities
+ * cannot be created.
+ */
+ public VolatileImage createVolatileImage(int width, int height, ImageCapabilities caps)
+ throws AWTException {
+ toolkit.lockAWT();
+ try {
+ if (!isDisplayable()) {
+ return null;
+ }
+ GraphicsConfiguration gc = getGraphicsConfiguration();
+ if (gc == null) {
+ return null;
+ }
+ VolatileImage image = gc.createCompatibleVolatileImage(width, height, caps);
+ fillImageBackground(image, width, height);
+ return image;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Creates a volatile off-screen drawable image which is used
+ * for double buffering.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ *
+ * @return the volatile image a volatile off-screen drawable image
+ * which is used for double buffering or null if the component
+ * is not displayable, or GraphicsEnvironment.isHeadless() method
+ * returns true.
+ */
+ public VolatileImage createVolatileImage(int width, int height) {
+ toolkit.lockAWT();
+ try {
+ if (!isDisplayable()) {
+ return null;
+ }
+ GraphicsConfiguration gc = getGraphicsConfiguration();
+ if (gc == null) {
+ return null;
+ }
+ VolatileImage image = gc.createCompatibleVolatileImage(width, height);
+ fillImageBackground(image, width, height);
+ return image;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Fill the image being created by createImage() or createVolatileImage()
+ * with the component's background color to prepare it for double-buffered
+ * painting.
+ *
+ * @param image the image
+ * @param width the width
+ * @param height the height
+ */
+ private void fillImageBackground(Image image, int width, int height) {
+ Graphics gr = image.getGraphics();
+ gr.setColor(getBackground());
+ gr.fillRect(0, 0, width, height);
+ gr.dispose();
+ }
+
+ /**
+ * Delivers event.
+ *
+ * @param evt the event.
+ *
+ * @deprecated Replaced by dispatchEvent(AWTEvent e) method.
+ */
+ @Deprecated
+ public void deliverEvent(Event evt) {
+ postEvent(evt);
+ }
+
+ /**
+ * Prompts the layout manager to lay out this component.
+ */
+ public void doLayout() {
+ toolkit.lockAWT();
+ try {
+ layout();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ // Implemented in Container
+ }
+
+ /**
+ * Fire property change impl.
+ *
+ * @param propertyName the property name
+ * @param oldValue the old value
+ * @param newValue the new value
+ */
+ private void firePropertyChangeImpl(String propertyName, Object oldValue, Object newValue) {
+ PropertyChangeSupport pcs;
+ synchronized (componentLock) {
+ if (propertyChangeSupport == null) {
+ return;
+ }
+ pcs = propertyChangeSupport;
+ }
+ pcs.firePropertyChange(propertyName, oldValue, newValue);
+ }
+
+ /**
+ * Reports a bound property changes for int properties.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ protected void firePropertyChange(String propertyName, int oldValue, int newValue) {
+ firePropertyChangeImpl(propertyName, new Integer(oldValue), new Integer(newValue));
+ }
+
+ /**
+ * Report a bound property change for a boolean-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the property's old value.
+ * @param newValue the property's new value.
+ */
+ protected void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
+ firePropertyChangeImpl(propertyName, Boolean.valueOf(oldValue), Boolean
+ .valueOf(newValue));
+ }
+
+ /**
+ * Reports a bound property change for an Object-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the property's old value
+ * @param newValue the property's new value
+ */
+ protected void firePropertyChange(final String propertyName, final Object oldValue,
+ final Object newValue) {
+ firePropertyChangeImpl(propertyName, oldValue, newValue);
+ }
+
+ /**
+ * Report a bound property change for a byte-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the property's old value.
+ * @param newValue the property's new value.
+ */
+ public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {
+ firePropertyChangeImpl(propertyName, new Byte(oldValue), new Byte(newValue));
+ }
+
+ /**
+ * Report a bound property change for a char-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ public void firePropertyChange(String propertyName, char oldValue, char newValue) {
+ firePropertyChangeImpl(propertyName, new Character(oldValue), new Character(newValue));
+ }
+
+ /**
+ * Report a bound property change for a short-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ public void firePropertyChange(String propertyName, short oldValue, short newValue) {
+ firePropertyChangeImpl(propertyName, new Short(oldValue), new Short(newValue));
+ }
+
+ /**
+ * Report a bound property change for a long-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ public void firePropertyChange(String propertyName, long oldValue, long newValue) {
+ firePropertyChangeImpl(propertyName, new Long(oldValue), new Long(newValue));
+ }
+
+ /**
+ * Report a bound property change for a float-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ public void firePropertyChange(String propertyName, float oldValue, float newValue) {
+ firePropertyChangeImpl(propertyName, new Float(oldValue), new Float(newValue));
+ }
+
+ /**
+ * Report a bound property change for a double-valued property.
+ *
+ * @param propertyName the property name.
+ * @param oldValue the old property's value.
+ * @param newValue the new property's value.
+ */
+ public void firePropertyChange(String propertyName, double oldValue, double newValue) {
+ firePropertyChangeImpl(propertyName, new Double(oldValue), new Double(newValue));
+ }
+
+ /**
+ * Gets the alignment along the x axis.
+ *
+ * @return the alignment along the x axis.
+ */
+ public float getAlignmentX() {
+ toolkit.lockAWT();
+ try {
+ return CENTER_ALIGNMENT;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the alignment along the y axis.
+ *
+ * @return the alignment along y axis.
+ */
+ public float getAlignmentY() {
+ toolkit.lockAWT();
+ try {
+ return CENTER_ALIGNMENT;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the background color for this component.
+ *
+ * @return the background color for this component.
+ */
+ public Color getBackground() {
+ toolkit.lockAWT();
+ try {
+ //???AWT
+ /*
+ if ((backColor == null) && (parent != null)) {
+ return parent.getBackground();
+ }
+ */
+ return backColor;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the bounding rectangle of this component.
+ *
+ * @return the bounding rectangle of this component.
+ */
+ public Rectangle getBounds() {
+ toolkit.lockAWT();
+ try {
+ return bounds();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Writes the data of the bounding rectangle to the specified
+ * Rectangle object.
+ *
+ * @param rv the Rectangle object where the bounding rectangle's data is stored.
+ *
+ * @return the bounding rectangle.
+ */
+ public Rectangle getBounds(Rectangle rv) {
+ toolkit.lockAWT();
+ try {
+ if (rv == null) {
+ rv = new Rectangle();
+ }
+ rv.setBounds(x, y, w, h);
+ return rv;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the color model of the Component.
+ *
+ * @return the color model of the Component.
+ */
+ public ColorModel getColorModel() {
+ toolkit.lockAWT();
+ try {
+ return getToolkit().getColorModel();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the Component which contains the specified Point.
+ *
+ * @param p the Point.
+ *
+ * @return the Component which contains the specified Point.
+ */
+ public Component getComponentAt(Point p) {
+ toolkit.lockAWT();
+ try {
+ return getComponentAt(p.x, p.y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the Component which contains the point with the
+ * specified coordinates.
+ *
+ * @param x the x coordinate of the point.
+ * @param y the y coordinate of the point.
+ *
+ * @return the Component which contains the point with the
+ * specified coordinates.
+ */
+ public Component getComponentAt(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ return locate(x, y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the component's orientation.
+ *
+ * @return the component's orientation.
+ */
+ public ComponentOrientation getComponentOrientation() {
+ toolkit.lockAWT();
+ try {
+ return orientation;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the cursor of the Component.
+ *
+ * @return the Cursor.
+ */
+ public Cursor getCursor() {
+ toolkit.lockAWT();
+ try {
+ if (cursor != null) {
+ return cursor;
+ //???AWT
+ /*
+ } else if (parent != null) {
+ return parent.getCursor();
+ */
+ }
+ return Cursor.getDefaultCursor();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ public DropTarget getDropTarget() {
+ toolkit.lockAWT();
+ try {
+ return dropTarget;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public Container getFocusCycleRootAncestor() {
+ toolkit.lockAWT();
+ try {
+ for (Container c = parent; c != null; c = c.getParent()) {
+ if (c.isFocusCycleRoot()) {
+ return c;
+ }
+ }
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public Set<AWTKeyStroke> getFocusTraversalKeys(int id) {
+ toolkit.lockAWT();
+ try {
+ Integer kId = new Integer(id);
+ KeyboardFocusManager.checkTraversalKeysID(traversalKeys, kId);
+ Set<? extends AWTKeyStroke> keys = traversalKeys.get(kId);
+ if (keys == null && parent != null) {
+ keys = parent.getFocusTraversalKeys(id);
+ }
+ if (keys == null) {
+ keys = KeyboardFocusManager.getCurrentKeyboardFocusManager()
+ .getDefaultFocusTraversalKeys(id);
+ }
+ return (Set<AWTKeyStroke>) keys;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Checks if the the focus traversal keys are enabled for this component.
+ *
+ * @return true, if the the focus traversal keys are enabled for
+ * this component, false otherwise.
+ */
+ public boolean getFocusTraversalKeysEnabled() {
+ toolkit.lockAWT();
+ try {
+ return focusTraversalKeysEnabled;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the font metrics of the specified Font.
+ *
+ * @param f the Font.
+ *
+ * @return the FontMetrics of the specified Font.
+ */
+ @SuppressWarnings("deprecation")
+ public FontMetrics getFontMetrics(Font f) {
+ return toolkit.getFontMetrics(f);
+ }
+
+ /**
+ * Gets the foreground color of the Component.
+ *
+ * @return the foreground color of the Component.
+ */
+ public Color getForeground() {
+ toolkit.lockAWT();
+ try {
+ //???AWT
+ /*
+ if (foreColor == null && parent != null) {
+ return parent.getForeground();
+ }
+ */
+ return foreColor;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the Graphics of the Component or null if this Component
+ * is not displayable.
+ *
+ * @return the Graphics of the Component or null if this Component
+ * is not displayable.
+ */
+ public Graphics getGraphics() {
+ toolkit.lockAWT();
+ try {
+ if (!isDisplayable()) {
+ return null;
+ }
+ Graphics g = behaviour.getGraphics(0, 0, w, h);
+ g.setColor(foreColor);
+ g.setFont(font);
+ return g;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+
+ /**
+ * Gets the GraphicsConfiguration associated with this Component.
+ *
+ * @return the GraphicsConfiguration associated with this Component.
+ */
+ public GraphicsConfiguration getGraphicsConfiguration() {
+ //???AWT
+ /*
+ toolkit.lockAWT();
+ try {
+ Window win = getWindowAncestor();
+ if (win == null) {
+ return null;
+ }
+ return win.getGraphicsConfiguration();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ */
+ return null;
+ }
+
+ /**
+ * Gets the height of the Component.
+ *
+ * @return the height of the Component.
+ */
+ public int getHeight() {
+ toolkit.lockAWT();
+ try {
+ return h;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns true if paint messages received from the operating system
+ * should be ignored.
+ *
+ * @return true if paint messages received from the operating system
+ * should be ignored, false otherwise.
+ */
+ public boolean getIgnoreRepaint() {
+ toolkit.lockAWT();
+ try {
+ return ignoreRepaint;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the input context of this component for handling
+ * the communication with input methods when text is entered
+ * in this component.
+ *
+ * @return the InputContext used by this Component or
+ * null if no context is specifined.
+ */
+ public InputContext getInputContext() {
+ toolkit.lockAWT();
+ try {
+ //???AWT
+ /*
+ Container parent = getParent();
+ if (parent != null) {
+ return parent.getInputContext();
+ }
+ */
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the input method request handler which supports requests
+ * from input methods for this component, or null for default.
+ *
+ * @return the input method request handler which supports requests
+ * from input methods for this component, or null for default.
+ */
+ public InputMethodRequests getInputMethodRequests() {
+ return null;
+ }
+
+ /**
+ * Gets the locale of this Component.
+ *
+ * @return the locale of this Component.
+ */
+ public Locale getLocale() {
+ toolkit.lockAWT();
+ try {
+ //???AWT
+ /*
+ if (locale == null) {
+ if (parent == null) {
+ if (this instanceof Window) {
+ return Locale.getDefault();
+ }
+ // awt.150=no parent
+ throw new IllegalComponentStateException(Messages.getString("awt.150")); //$NON-NLS-1$
+ }
+ return getParent().getLocale();
+ }
+ */
+ return locale;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the location of this component in the form of a point
+ * specifying the component's top-left corner in the
+ * screen's coordinate space.
+ *
+ * @return the Point giving the component's location in the
+ * screen's coordinate space.
+ *
+ * @throws IllegalComponentStateException if the component is
+ * not shown on the screen.
+ */
+ public Point getLocationOnScreen() throws IllegalComponentStateException {
+ toolkit.lockAWT();
+ try {
+ Point p = new Point();
+ if (isShowing()) {
+ //???AWT
+ /*
+ Component comp;
+ for (comp = this; comp != null && !(comp instanceof Window); comp = comp
+ .getParent()) {
+ p.translate(comp.getX(), comp.getY());
+ }
+ if (comp instanceof Window) {
+ p.translate(comp.getX(), comp.getY());
+ }
+ */
+ return p;
+ }
+ // awt.151=component must be showing on the screen to determine its location
+ throw new IllegalComponentStateException(Messages.getString("awt.151")); //$NON-NLS-1$
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the peer. This method should not be called directly by
+ * user applications.
+ *
+ * @return the ComponentPeer.
+ *
+ * @deprecated Replaced by isDisplayable().
+ */
+ @Deprecated
+ public ComponentPeer getPeer() {
+ toolkit.lockAWT();
+ try {
+ if (behaviour.isDisplayable()) {
+ return peer;
+ }
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets an array of the property change listeners registered to
+ * this Component.
+ *
+ * @return an array of the PropertyChangeListeners registered to
+ * this Component.
+ */
+ public PropertyChangeListener[] getPropertyChangeListeners() {
+ return getPropertyChangeSupport().getPropertyChangeListeners();
+ }
+
+ /**
+ * Gets an array of PropertyChangeListener objects registered
+ * to this Component for the specified property.
+ *
+ * @param propertyName the property name.
+ *
+ * @return an array of PropertyChangeListener objects registered
+ * to this Component for the specified property.
+ */
+ public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
+ return getPropertyChangeSupport().getPropertyChangeListeners(propertyName);
+ }
+
+ /**
+ * Gets the width of the Component.
+ *
+ * @return the width of the Component.
+ */
+ public int getWidth() {
+ toolkit.lockAWT();
+ try {
+ return w;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the x coordinate of the component's top-left corner.
+ *
+ * @return the x coordinate of the component's top-left corner.
+ */
+ public int getX() {
+ toolkit.lockAWT();
+ try {
+ return x;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the y coordinate of the component's top-left corner.
+ *
+ * @return the y coordinate of the component's top-left corner.
+ */
+ public int getY() {
+ toolkit.lockAWT();
+ try {
+ return y;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Got the focus.
+ *
+ * @param evt the Event.
+ * @param what the Object.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processFocusEvent(FocusEvent) method.
+ */
+ @Deprecated
+ public boolean gotFocus(Event evt, Object what) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Handles event.
+ *
+ * @param evt the Event.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processEvent(AWTEvent) method.
+ */
+ @Deprecated
+ public boolean handleEvent(Event evt) {
+ switch (evt.id) {
+ case Event.ACTION_EVENT:
+ return action(evt, evt.arg);
+ case Event.GOT_FOCUS:
+ return gotFocus(evt, null);
+ case Event.LOST_FOCUS:
+ return lostFocus(evt, null);
+ case Event.MOUSE_DOWN:
+ return mouseDown(evt, evt.x, evt.y);
+ case Event.MOUSE_DRAG:
+ return mouseDrag(evt, evt.x, evt.y);
+ case Event.MOUSE_ENTER:
+ return mouseEnter(evt, evt.x, evt.y);
+ case Event.MOUSE_EXIT:
+ return mouseExit(evt, evt.x, evt.y);
+ case Event.MOUSE_MOVE:
+ return mouseMove(evt, evt.x, evt.y);
+ case Event.MOUSE_UP:
+ return mouseUp(evt, evt.x, evt.y);
+ case Event.KEY_ACTION:
+ case Event.KEY_PRESS:
+ return keyDown(evt, evt.key);
+ case Event.KEY_ACTION_RELEASE:
+ case Event.KEY_RELEASE:
+ return keyUp(evt, evt.key);
+ }
+ return false;// event not handled
+ }
+
+ /**
+ * Checks whether the Component is the focus owner or not.
+ *
+ * @return true, if the Component is the focus owner, false otherwise.
+ */
+ public boolean hasFocus() {
+ toolkit.lockAWT();
+ try {
+ //???AWT: return isFocusOwner();
+ return false;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Hides the Component.
+ *
+ * @deprecated Replaced by setVisible(boolean) method.
+ */
+ @Deprecated
+ public void hide() {
+ toolkit.lockAWT();
+ try {
+ if (!visible) {
+ return;
+ }
+ prepare4HierarchyChange();
+ visible = false;
+ moveFocusOnHide();
+ behaviour.setVisible(false);
+ postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_HIDDEN));
+ //???AWT: finishHierarchyChange(this, parent, 0);
+ notifyInputMethod(null);
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not the point with the specified coordinates
+ * belongs to the Commponent.
+ *
+ * @param x the x coordinate of the Point.
+ * @param y the y coordinate of the Point.
+ *
+ * @return true, if the point with the specified coordinates
+ * belongs to the Commponent, false otherwise.
+ *
+ * @deprecated Replaced by contains(int, int) method.
+ */
+ @Deprecated
+ public boolean inside(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Invalidates the component, this component and all parents
+ * above it are marked as needing to be laid out.
+ */
+ public void invalidate() {
+ toolkit.lockAWT();
+ try {
+ valid = false;
+ resetDefaultSize();
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not the background color is set to this Component.
+ *
+ * @return true, if the background color is set to this Component,
+ * false otherwise.
+ */
+ public boolean isBackgroundSet() {
+ toolkit.lockAWT();
+ try {
+ return backColor != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not a cursor is set for the Component.
+ *
+ * @return true, if a cursor is set for the Component,
+ * false otherwise.
+ */
+ public boolean isCursorSet() {
+ toolkit.lockAWT();
+ try {
+ return cursor != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not this Component is displayable.
+ *
+ * @return true, if this Component is displayable, false otherwise.
+ */
+ public boolean isDisplayable() {
+ toolkit.lockAWT();
+ try {
+ return behaviour.isDisplayable();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not this component is painted to an buffer
+ * which is copied to the screen later.
+ *
+ * @return true, if this component is painted to an buffer
+ * which is copied to the screen later, false otherwise.
+ */
+ public boolean isDoubleBuffered() {
+ toolkit.lockAWT();
+ try {
+ // false by default
+ return false;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not this Component is enabled.
+ *
+ * @return true, if this Component is enabled, false otherwise.
+ */
+ public boolean isEnabled() {
+ toolkit.lockAWT();
+ try {
+ return enabled;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * "Recursive" isEnabled().
+ *
+ * @return true if not only component itself is enabled but its heavyweight
+ * parent is also "indirectly" enabled
+ */
+ boolean isIndirectlyEnabled() {
+ Component comp = this;
+ while (comp != null) {
+ if (!comp.isLightweight() && !comp.isEnabled()) {
+ return false;
+ }
+ //???AWT: comp = comp.getRealParent();
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the component is key enabled.
+ *
+ * @return true, if the component is enabled and indirectly enabled
+ */
+ boolean isKeyEnabled() {
+ if (!isEnabled()) {
+ return false;
+ }
+ return isIndirectlyEnabled();
+ }
+
+ /**
+ * Gets only parent of a child component, but not owner of a window.
+ *
+ * @return parent of child component, null if component is a top-level
+ * (Window instance)
+ */
+ //???AWT
+ /*
+ Container getRealParent() {
+ return (!(this instanceof Window) ? getParent() : null);
+ }
+
+ public boolean isFocusCycleRoot(Container container) {
+ toolkit.lockAWT();
+ try {
+ return getFocusCycleRootAncestor() == container;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public boolean isFocusOwner() {
+ toolkit.lockAWT();
+ try {
+ return KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == this;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Checks whether or not this Component can be focusable.
+ *
+ * @return true, if this Component can be focusable, false otherwise.
+ *
+ * @deprecated Replaced by isFocusable().
+ */
+ @Deprecated
+ public boolean isFocusTraversable() {
+ toolkit.lockAWT();
+ try {
+ overridenIsFocusable = false;
+ return focusable; // a Component must either be both focusable and
+ // focus traversable, or neither
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if this Component can be focusable or not.
+ *
+ * @return true, if this Component can be focusable, false otherwise.
+ */
+ public boolean isFocusable() {
+ toolkit.lockAWT();
+ try {
+ return isFocusTraversable();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if the Font is set for this Component or not.
+ *
+ * @return true, if the Font is set, false otherwise.
+ */
+ public boolean isFontSet() {
+ toolkit.lockAWT();
+ try {
+ return font != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if foreground color is set for the Component or not.
+ *
+ * @return true, if is foreground color is set for the Component,
+ * false otherwise.
+ */
+ public boolean isForegroundSet() {
+ toolkit.lockAWT();
+ try {
+ return foreColor != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns true if this component has a lightweight peer.
+ *
+ * @return true, if this component has a lightweight peer,
+ * false if it has a native peer or no peer.
+ */
+ public boolean isLightweight() {
+ toolkit.lockAWT();
+ try {
+ return behaviour.isLightweight();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+
+ /**
+ * Checks whether or not this Component is shown.
+ *
+ * @return true, if this Component is shown, false otherwise.
+ */
+ public boolean isShowing() {
+ //???AWT
+ /*
+ toolkit.lockAWT();
+ try {
+ return (isVisible() && isDisplayable() && (parent != null) && parent.isShowing());
+ } finally {
+ toolkit.unlockAWT();
+ }
+ */
+ return false;
+ }
+
+ /**
+ * Checks whether or not this Component is visible.
+ *
+ * @return true, if the Component is visible, false otherwise.
+ */
+ public boolean isVisible() {
+ toolkit.lockAWT();
+ try {
+ return visible;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by processKeyEvent(KeyEvent) method.
+ *
+ * @param evt the Event.
+ * @param key the key code.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by replaced by processKeyEvent(KeyEvent) method.
+ */
+ @Deprecated
+ public boolean keyDown(Event evt, int key) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Deprecated: replaced by processKeyEvent(KeyEvent) method.
+ *
+ * @param evt the Event.
+ * @param key the key code.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processKeyEvent(KeyEvent) method.
+ */
+ @Deprecated
+ public boolean keyUp(Event evt, int key) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Deprecated: Replaced by doLayout() method.
+ *
+ * @deprecated Replaced by doLayout() method.
+ */
+ @Deprecated
+ public void layout() {
+ toolkit.lockAWT();
+ try {
+ // Implemented in Container
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by getComponentAt(int, int) method.
+ *
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return The component.
+ *
+ * @deprecated Replaced by getComponentAt(int, int) method.
+ */
+ @Deprecated
+ public Component locate(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ if (contains(x, y)) {
+ return this;
+ }
+ return null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by processFocusEvent(FocusEvent).
+ *
+ * @param evt the Event.
+ * @param what the Object.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processFocusEvent(FocusEvent).
+ */
+ @Deprecated
+ public boolean lostFocus(Event evt, Object what) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Deprecated: replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @param evt the MouseEvent.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+ */
+ @Deprecated
+ public boolean mouseDown(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Deprecated: replaced by getMinimumSize() method.
+ *
+ * @param evt the Event.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by getMinimumSize() method.
+ */
+ @Deprecated
+ public boolean mouseDrag(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @param evt the Event.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated replaced by processMouseEvent(MouseEvent) method.
+ */
+ @Deprecated
+ public boolean mouseEnter(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @param evt the Event.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+ */
+ @Deprecated
+ public boolean mouseExit(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @param evt the Event.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @return true, if successful.
+ */
+ @Deprecated
+ public boolean mouseMove(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Replaced by processMouseEvent(MouseEvent) method.
+ *
+ * @param evt the Event.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ *
+ * @return true, if successful.
+ *
+ * @deprecated Replaced by processMouseEvent(MouseEvent) method.
+ */
+ @Deprecated
+ public boolean mouseUp(Event evt, int x, int y) {
+ // to be overridden: do nothing,
+ // just return false to propagate event up to the parent container
+ return false;
+ }
+
+ /**
+ * Deprecated: replaced by setLocation(int, int) method.
+ *
+ * @param x the x coordinates.
+ * @param y the y coordinates.
+ *
+ * @deprecated Replaced by setLocation(int, int) method.
+ */
+ @Deprecated
+ public void move(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ boundsMaskParam = NativeWindow.BOUNDS_NOSIZE;
+ setBounds(x, y, w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ @Deprecated
+ public void nextFocus() {
+ toolkit.lockAWT();
+ try {
+ transferFocus(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Returns a string representation of the component's state.
+ *
+ * @return the string representation of the component's state.
+ */
+ protected String paramString() {
+ /*
+ * The format is based on 1.5 release behavior which can be revealed by
+ * the following code:
+ *
+ * Component c = new Component(){}; c.setVisible(false);
+ * System.out.println(c);
+ */
+ toolkit.lockAWT();
+ try {
+ return getName() + "," + getX() + "," + getY() + "," + getWidth() + "x" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ + getHeight() + (!isVisible() ? ",hidden" : ""); //$NON-NLS-1$ //$NON-NLS-2$
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ public boolean postEvent(Event evt) {
+ boolean handled = handleEvent(evt);
+ if (handled) {
+ return true;
+ }
+ //???AWT
+ /*
+
+ // propagate non-handled events up to parent
+ Component par = parent;
+ // try to call postEvent only on components which
+ // override any of deprecated method handlers
+ // while (par != null && !par.deprecatedEventHandler) {
+ // par = par.parent;
+ // }
+ // translate event coordinates before posting it to parent
+ if (par != null) {
+ evt.translate(x, y);
+ par.postEvent(evt);
+ }
+
+ */
+ return false;
+ }
+
+ /**
+ * Prepares an image for rendering on the Component.
+ *
+ * @param image the Image to be prepared.
+ * @param observer the ImageObserver object to be notified as soon as
+ * the image is prepared.
+ *
+ * @return true if the image has been fully prepared,
+ * false otherwise.
+ */
+ public boolean prepareImage(Image image, ImageObserver observer) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.prepareImage(image, -1, -1, observer);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prepares an image for rendering on the Component with the
+ * specified width, height, and ImageObserver.
+ *
+ * @param image the Image to be prepared.
+ * @param width the width of scaled image.
+ * @param height the height of scaled height.
+ * @param observer the ImageObserver object to be notified as soon as
+ * the image is prepared.
+ *
+ * @return true if the image is been fully prepared,
+ * false otherwise.
+ */
+ public boolean prepareImage(Image image, int width, int height, ImageObserver observer) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.prepareImage(image, width, height, observer);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Makes this Component undisplayable.
+ */
+ public void removeNotify() {
+ toolkit.lockAWT();
+ try {
+ //???AWT
+ /*
+ if (dropTarget != null) {
+ dropTarget.removeNotify(peer);
+ }
+ */
+ prepare4HierarchyChange();
+ ///???AWT: moveFocus();
+ behaviour.removeNotify();
+ //???AWT: finishHierarchyChange(this, parent, 0);
+ removeNotifyInputContext();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Calls InputContext.removeNotify
+ */
+ private void removeNotifyInputContext() {
+ if (!inputMethodsEnabled) {
+ return;
+ }
+ InputContext ic = getInputContext();
+ if (ic != null) {
+ //???AWT: ic.removeNotify(this);
+ }
+ }
+
+ /**
+ * This method is called when some property of a component changes, making
+ * it unfocusable, e. g. hide(), removeNotify(), setEnabled(false),
+ * setFocusable(false) is called, and therefore automatic forward focus
+ * traversal is necessary
+ */
+ //???AWT
+ /*
+ void moveFocus() {
+ // don't use transferFocus(), but query focus traversal policy directly
+ // and if it returns null, transfer focus up cycle
+ // and find next focusable component there
+ KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ Container root = kfm.getCurrentFocusCycleRoot();
+ Component nextComp = this;
+ boolean success = !isFocusOwner();
+ while (!success) {
+ if (root != nextComp.getFocusCycleRootAncestor()) {
+ // component was probably removed from container
+ // so focus will be lost in some time
+ return;
+ }
+ nextComp = root.getFocusTraversalPolicy().getComponentAfter(root, nextComp);
+ if (nextComp == this) {
+ nextComp = null; // avoid looping
+ }
+ if (nextComp != null) {
+ success = nextComp.requestFocusInWindow();
+ } else {
+ nextComp = root;
+ root = root.getFocusCycleRootAncestor();
+ // if no acceptable component is found at all - clear global
+ // focus owner
+ if (root == null) {
+ if (nextComp instanceof Window) {
+ Window wnd = (Window) nextComp;
+ wnd.setFocusOwner(null);
+ wnd.setRequestedFocus(null);
+ }
+ kfm.clearGlobalFocusOwner();
+ return;
+ }
+ }
+ }
+ }
+ */
+
+ /**
+ * For Container there's a difference between moving focus when being made
+ * invisible or made unfocusable in some other way, because when container
+ * is made invisible, component still remains visible, i. e. its hide() or
+ * setVisible() is not called.
+ */
+ void moveFocusOnHide() {
+ //???AWT: moveFocus();
+ }
+
+ /**
+ * Removes the property change listener registered for this component.
+ *
+ * @param listener the PropertyChangeListener.
+ */
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ getPropertyChangeSupport().removePropertyChangeListener(listener);
+ }
+
+ /**
+ * Removes the property change listener registered fot this component
+ * for the specified propertyy.
+ *
+ * @param propertyName the property name.
+ * @param listener the PropertyChangeListener.
+ */
+ public void removePropertyChangeListener(String propertyName,
+ PropertyChangeListener listener) {
+ getPropertyChangeSupport().removePropertyChangeListener(propertyName, listener);
+ }
+
+
+ /**
+ * Repaints the specified rectangle of this component within
+ * tm milliseconds.
+ *
+ * @param tm the time in milliseconds before updating.
+ * @param x the x coordinate of Rectangle.
+ * @param y the y coordinate of Rectangle.
+ * @param width the width of Rectangle.
+ * @param height the height of Rectangle.
+ */
+ public void repaint(long tm, int x, int y, int width, int height) {
+ //???AWT
+ /*
+ toolkit.lockAWT();
+ try {
+ if (width <= 0 || height <= 0 || (redrawManager == null) || !isShowing()) {
+ return;
+ }
+ if (behaviour instanceof LWBehavior) {
+ if (parent == null || !parent.visible || !parent.behaviour.isDisplayable()) {
+ return;
+ }
+ if (repaintRegion == null) {
+ repaintRegion = new MultiRectArea(new Rectangle(x, y, width, height));
+ }
+ repaintRegion.intersect(new Rectangle(0, 0, this.w, this.h));
+ repaintRegion.translate(this.x, this.y);
+ parent.repaintRegion = repaintRegion;
+ repaintRegion = null;
+ parent.repaint(tm, x + this.x, y + this.y, width, height);
+ } else {
+ if (repaintRegion != null) {
+ redrawManager.addUpdateRegion(this, repaintRegion);
+ repaintRegion = null;
+ } else {
+ redrawManager.addUpdateRegion(this, new Rectangle(x, y, width, height));
+ }
+ toolkit.getSystemEventQueueCore().notifyEventMonitor(toolkit);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ */
+ }
+
+ /**
+ * Post event.
+ *
+ * @param e the e
+ */
+ void postEvent(AWTEvent e) {
+ getToolkit().getSystemEventQueueImpl().postEvent(e);
+ }
+
+ /**
+ * Repaints the specified Rectangle of this Component.
+ *
+ * @param x the x coordinate of Rectangle.
+ * @param y the y coordinate of Rectangle.
+ * @param width the width of Rectangle.
+ * @param height the height of Rectangle.
+ */
+ public void repaint(int x, int y, int width, int height) {
+ toolkit.lockAWT();
+ try {
+ repaint(0, x, y, width, height);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Repaints this component.
+ */
+ public void repaint() {
+ toolkit.lockAWT();
+ try {
+ if (w > 0 && h > 0) {
+ repaint(0, 0, 0, w, h);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Repaints the component within tm milliseconds.
+ *
+ * @param tm the time in milliseconds before updating.
+ */
+ public void repaint(long tm) {
+ toolkit.lockAWT();
+ try {
+ repaint(tm, 0, 0, w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Requests that this Component get the input focus temporarily.
+ * This component must be displayable, visible, and focusable.
+ *
+ * @param temporary this parameter is true if the focus change
+ * is temporary, when the window loses the focus.
+ *
+ * @return true if the focus change request is succeeded,
+ * false otherwise.
+ */
+ protected boolean requestFocus(boolean temporary) {
+ toolkit.lockAWT();
+ try {
+ //???AWT: return requestFocusImpl(temporary, true, false);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ //???AWT
+ return false;
+ }
+
+ /**
+ * Requests that this Component get the input focus.
+ * This component must be displayable, visible, and focusable.
+ */
+ public void requestFocus() {
+ toolkit.lockAWT();
+ try {
+ requestFocus(false);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ protected boolean requestFocusInWindow(boolean temporary) {
+ toolkit.lockAWT();
+ try {
+ Window wnd = getWindowAncestor();
+ if ((wnd == null) || !wnd.isFocused()) {
+ return false;
+ }
+ return requestFocusImpl(temporary, false, false);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ boolean requestFocusImpl(boolean temporary, boolean crossWindow, boolean rejectionRecovery) {
+ if (!rejectionRecovery && isFocusOwner()) {
+ return true;
+ }
+ Window wnd = getWindowAncestor();
+ Container par = getRealParent();
+ if ((par != null) && par.isRemoved) {
+ return false;
+ }
+ if (!isShowing() || !isFocusable() || !wnd.isFocusableWindow()) {
+ return false;
+ }
+ return KeyboardFocusManager.getCurrentKeyboardFocusManager().requestFocus(this,
+ temporary, crossWindow, true);
+ }
+
+ public boolean requestFocusInWindow() {
+ toolkit.lockAWT();
+ try {
+ return requestFocusInWindow(false);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Deprecated: replaced by setBounds(int, int, int, int) method.
+ *
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ * @param w the width.
+ * @param h the height.
+ *
+ * @deprecated Replaced by setBounds(int, int, int, int) method.
+ */
+ @Deprecated
+ public void reshape(int x, int y, int w, int h) {
+ toolkit.lockAWT();
+ try {
+ setBounds(x, y, w, h, boundsMaskParam, true);
+ boundsMaskParam = 0;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets rectangle for this Component to be the rectangle with the specified
+ * x,y coordinates of the top-left corner and the width and height.
+ *
+ * @param x the x coordinate of the rectangle's top-left corner.
+ * @param y the y coordinate of the rectangle's top-left corner.
+ * @param w the width of rectangle.
+ * @param h the height of rectangle.
+ */
+ public void setBounds(int x, int y, int w, int h) {
+ toolkit.lockAWT();
+ try {
+ reshape(x, y, w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets rectangle for this Component to be the rectangle with the specified
+ * x,y coordinates of the top-left corner and the width and height
+ * and posts the appropriate events.
+ *
+ * @param x the x coordinate of the rectangle's top-left corner.
+ * @param y the y coordinate of the rectangle's top-left corner.
+ * @param w the width of rectangle.
+ * @param h the height of rectangle.
+ * @param bMask the bitmask of bounds options
+ * @param updateBehavior the whether to update the behavoir's bounds as well
+ */
+ void setBounds(int x, int y, int w, int h, int bMask, boolean updateBehavior) {
+ int oldX = this.x;
+ int oldY = this.y;
+ int oldW = this.w;
+ int oldH = this.h;
+ setBoundsFields(x, y, w, h, bMask);
+ // Moved
+ if ((oldX != this.x) || (oldY != this.y)) {
+ //???AWT: invalidateRealParent();
+ postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_MOVED));
+ spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_MOVED);
+ }
+ // Resized
+ if ((oldW != this.w) || (oldH != this.h)) {
+ invalidate();
+ postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED));
+ spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_RESIZED);
+ }
+ if (updateBehavior) {
+ behaviour.setBounds(this.x, this.y, this.w, this.h, bMask);
+ }
+ notifyInputMethod(new Rectangle(x, y, w, h));
+ }
+
+ /**
+ * Calls InputContextImpl.notifyClientWindowChanged.
+ *
+ * @param bounds the bounds
+ */
+ void notifyInputMethod(Rectangle bounds) {
+ // only Window actually notifies IM of bounds change
+ }
+
+ /**
+ * Sets the bounds fields.
+ *
+ * @param x the x
+ * @param y the y
+ * @param w the w
+ * @param h the h
+ * @param bMask the b mask
+ */
+ private void setBoundsFields(int x, int y, int w, int h, int bMask) {
+ if ((bMask & NativeWindow.BOUNDS_NOSIZE) == 0) {
+ this.w = w;
+ this.h = h;
+ }
+ if ((bMask & NativeWindow.BOUNDS_NOMOVE) == 0) {
+ this.x = x;
+ this.y = y;
+ }
+ }
+
+ /**
+ * Gets the native insets.
+ *
+ * @return the native insets
+ */
+ Insets getNativeInsets() {
+ return new Insets(0, 0, 0, 0);
+ }
+
+ /**
+ * Gets the insets.
+ *
+ * @return the insets
+ */
+ Insets getInsets() {
+ return new Insets(0, 0, 0, 0);
+ }
+
+ /**
+ * Checks if is mouse exited expected.
+ *
+ * @return true, if is mouse exited expected
+ */
+ boolean isMouseExitedExpected() {
+ return mouseExitedExpected;
+ }
+
+ /**
+ * Sets the mouse exited expected.
+ *
+ * @param expected the new mouse exited expected
+ */
+ void setMouseExitedExpected(boolean expected) {
+ mouseExitedExpected = expected;
+ }
+
+ /**
+ * Sets the new bounding rectangle for this Component.
+ *
+ * @param r the new bounding rectangle.
+ */
+ public void setBounds(Rectangle r) {
+ toolkit.lockAWT();
+ try {
+ setBounds(r.x, r.y, r.width, r.height);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the component orientation which affects the component's
+ * elements and text within this component.
+ *
+ * @param o the ComponentOrientation object.
+ */
+ public void setComponentOrientation(ComponentOrientation o) {
+ ComponentOrientation oldOrientation;
+ toolkit.lockAWT();
+ try {
+ oldOrientation = orientation;
+ orientation = o;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("componentOrientation", oldOrientation, orientation); //$NON-NLS-1$
+ invalidate();
+ }
+
+ /**
+ * Sets the specified cursor for this Component.
+ *
+ * @param cursor the new Cursor.
+ */
+ public void setCursor(Cursor cursor) {
+ toolkit.lockAWT();
+ try {
+ this.cursor = cursor;
+ setCursor();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Set current cursor shape to Component's Cursor.
+ */
+ void setCursor() {
+ if (isDisplayable() && isShowing()) {
+ Rectangle absRect = new Rectangle(getLocationOnScreen(), getSize());
+ Point absPointerPos = toolkit.dispatcher.mouseDispatcher.getPointerPos();
+ //???AWT
+ /*
+ if (absRect.contains(absPointerPos)) {
+ // set Cursor only on top-level Windows(on X11)
+ Window topLevelWnd = getWindowAncestor();
+ if (topLevelWnd != null) {
+ Point pointerPos = MouseDispatcher.convertPoint(null, absPointerPos,
+ topLevelWnd);
+ Component compUnderCursor = topLevelWnd.findComponentAt(pointerPos);
+ // if (compUnderCursor == this ||
+ // compUnderCursor.getCursorAncestor() == this) {
+ NativeWindow wnd = topLevelWnd.getNativeWindow();
+ if (compUnderCursor != null && wnd != null) {
+ compUnderCursor.getRealCursor().getNativeCursor()
+ .setCursor(wnd.getId());
+ }
+ // }
+ }
+ }
+ */
+ }
+ }
+
+ /**
+ * Gets the ancestor Cursor if Component is disabled (directly or via an
+ * ancestor) even if Cursor is explicitly set.
+ *
+ * @param value the value
+ *
+ * @return actual Cursor to be displayed
+ */
+ //???AWT
+ /*
+ Cursor getRealCursor() {
+ Component cursorAncestor = getCursorAncestor();
+ return cursorAncestor != null ? cursorAncestor.getCursor() : Cursor.getDefaultCursor();
+ }
+ */
+
+ /**
+ * Gets the ancestor(or component itself) whose cursor is set when pointer
+ * is inside component
+ *
+ * @return actual Cursor to be displayed
+ */
+ //???AWT
+ /*
+ Component getCursorAncestor() {
+ Component comp;
+ for (comp = this; comp != null; comp = comp.getParent()) {
+ if (comp instanceof Window || comp.isCursorSet() && comp.isKeyEnabled()) {
+ return comp;
+ }
+ }
+ return null;
+ }
+
+ public void setDropTarget(DropTarget dt) {
+ toolkit.lockAWT();
+ try {
+ if (dropTarget == dt) {
+ return;
+ }
+ DropTarget oldDropTarget = dropTarget;
+ dropTarget = dt;
+ if (oldDropTarget != null) {
+ if (behaviour.isDisplayable()) {
+ oldDropTarget.removeNotify(peer);
+ }
+ oldDropTarget.setComponent(null);
+ }
+ if (dt != null) {
+ dt.setComponent(this);
+ if (behaviour.isDisplayable()) {
+ dt.addNotify(peer);
+ }
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Sets this component to the "enabled" or "disabled" state depending
+ * on the specified boolean parameter.
+ *
+ * @param value true if this component should be enabled; false
+ * if this component should be disabled.
+ */
+ public void setEnabled(boolean value) {
+ toolkit.lockAWT();
+ try {
+ enable(value);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the enabled impl.
+ *
+ * @param value the new enabled impl
+ */
+ void setEnabledImpl(boolean value) {
+ if (enabled != value) {
+ enabled = value;
+ setCursor();
+ if (!enabled) {
+ moveFocusOnHide();
+ }
+ behaviour.setEnabled(value);
+ }
+ }
+
+ //???AWT
+ /*
+ private void fireAccessibleStateChange(AccessibleState state, boolean value) {
+ if (behaviour.isLightweight()) {
+ return;
+ }
+ AccessibleContext ac = getAccessibleContext();
+ if (ac != null) {
+ AccessibleState oldValue = null;
+ AccessibleState newValue = null;
+ if (value) {
+ newValue = state;
+ } else {
+ oldValue = state;
+ }
+ ac.firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, oldValue,
+ newValue);
+ }
+ }
+ */
+
+ //???AWT
+ /*
+ public void setFocusTraversalKeys(int id, Set<? extends AWTKeyStroke> keystrokes) {
+ Set<? extends AWTKeyStroke> oldTraversalKeys;
+ String propName = "FocusTraversalKeys"; //$NON-NLS-1$
+ toolkit.lockAWT();
+ try {
+ Integer kId = new Integer(id);
+ KeyboardFocusManager.checkTraversalKeysID(traversalKeys, kId);
+ Map<Integer, Set<? extends AWTKeyStroke>> keys = new HashMap<Integer, Set<? extends AWTKeyStroke>>();
+ for (int kid : traversalIDs) {
+ Integer key = new Integer(kid);
+ keys.put(key, getFocusTraversalKeys(kid));
+ }
+ KeyboardFocusManager.checkKeyStrokes(traversalIDs, keys, kId, keystrokes);
+ oldTraversalKeys = traversalKeys.get(new Integer(id));
+ // put a copy of keystrokes object into map:
+ Set<? extends AWTKeyStroke> newKeys = keystrokes;
+ if (keystrokes != null) {
+ newKeys = new HashSet<AWTKeyStroke>(keystrokes);
+ }
+ traversalKeys.put(kId, newKeys);
+ String direction = ""; //$NON-NLS-1$
+ switch (id) {
+ case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS:
+ direction = "forward"; //$NON-NLS-1$
+ break;
+ case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS:
+ direction = "backward"; //$NON-NLS-1$
+ break;
+ case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS:
+ direction = "upCycle"; //$NON-NLS-1$
+ break;
+ case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS:
+ direction = "downCycle"; //$NON-NLS-1$
+ break;
+ }
+ propName = direction + propName;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange(propName, oldTraversalKeys, keystrokes);
+ }
+ */
+
+ /**
+ * Sets the focus traversal keys state for this component.
+ *
+ * @param value true if the focus traversal keys state is enabled,
+ * false if the focus traversal keys state is disabled.
+ */
+ public void setFocusTraversalKeysEnabled(boolean value) {
+ boolean oldFocusTraversalKeysEnabled;
+ toolkit.lockAWT();
+ try {
+ oldFocusTraversalKeysEnabled = focusTraversalKeysEnabled;
+ focusTraversalKeysEnabled = value;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("focusTraversalKeysEnabled", oldFocusTraversalKeysEnabled, //$NON-NLS-1$
+ focusTraversalKeysEnabled);
+ }
+
+ //???AWT
+ /*
+ public void setFocusable(boolean focusable) {
+ boolean oldFocusable;
+ toolkit.lockAWT();
+ try {
+ calledSetFocusable = true;
+ oldFocusable = this.focusable;
+ this.focusable = focusable;
+ if (!focusable) {
+ moveFocus();
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("focusable", oldFocusable, focusable); //$NON-NLS-1$
+ }
+
+ public Font getFont() {
+ toolkit.lockAWT();
+ try {
+ return (font == null) && (parent != null) ? parent.getFont() : font;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Sets the font for this Component.
+ *
+ * @param f the new font of the Component.
+ */
+ public void setFont(Font f) {
+ Font oldFont;
+ toolkit.lockAWT();
+ try {
+ oldFont = font;
+ setFontImpl(f);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("font", oldFont, font); //$NON-NLS-1$
+ }
+
+ /**
+ * Sets the font impl.
+ *
+ * @param f the new font impl
+ */
+ void setFontImpl(Font f) {
+ font = f;
+ invalidate();
+ if (isShowing()) {
+ repaint();
+ }
+ }
+
+
+ /**
+ * Invalidate the component if it inherits the font from the parent. This
+ * method is overridden in Container.
+ *
+ * @return true if the component was invalidated, false otherwise
+ */
+ boolean propagateFont() {
+ if (font == null) {
+ invalidate();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets the foreground color for this Component.
+ *
+ * @param c the new foreground color.
+ */
+ public void setForeground(Color c) {
+ Color oldFgColor;
+ toolkit.lockAWT();
+ try {
+ oldFgColor = foreColor;
+ foreColor = c;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("foreground", oldFgColor, foreColor); //$NON-NLS-1$
+ repaint();
+ }
+
+ /**
+ * Sets the background color for the Component.
+ *
+ * @param c the new background color for this component.
+ */
+ public void setBackground(Color c) {
+ Color oldBkColor;
+ toolkit.lockAWT();
+ try {
+ oldBkColor = backColor;
+ backColor = c;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("background", oldBkColor, backColor); //$NON-NLS-1$
+ repaint();
+ }
+
+ /**
+ * Sets the flag for whether paint messages received from the operating
+ * system should be ignored or not.
+ *
+ * @param value true if paint messages received from the operating
+ * system should be ignored, false otherwise.
+ */
+ public void setIgnoreRepaint(boolean value) {
+ toolkit.lockAWT();
+ try {
+ ignoreRepaint = value;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the locale of the component.
+ *
+ * @param locale the new Locale.
+ */
+ public void setLocale(Locale locale) {
+ Locale oldLocale;
+ toolkit.lockAWT();
+ try {
+ oldLocale = this.locale;
+ this.locale = locale;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("locale", oldLocale, locale); //$NON-NLS-1$
+ }
+
+ /**
+ * Sets the location of the Component to the specified point.
+ *
+ * @param p the new location of the Component
+ */
+ public void setLocation(Point p) {
+ toolkit.lockAWT();
+ try {
+ setLocation(p.x, p.y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the location of the Component to the specified x, y coordinates.
+ *
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ */
+ public void setLocation(int x, int y) {
+ toolkit.lockAWT();
+ try {
+ move(x, y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the visibility state of the component.
+ *
+ * @param b true if the component is visible, false if the component
+ * is not shown.
+ */
+ public void setVisible(boolean b) {
+ // show() & hide() are not deprecated for Window,
+ // so have to call them from setVisible()
+ show(b);
+ }
+
+ /**
+ * Deprecated: replaced by setVisible(boolean) method.
+ *
+ * @deprecated Replaced by setVisible(boolean) method.
+ */
+ @Deprecated
+ public void show() {
+ toolkit.lockAWT();
+ try {
+ if (visible) {
+ return;
+ }
+ prepare4HierarchyChange();
+ mapToDisplay(true);
+ validate();
+ visible = true;
+ behaviour.setVisible(true);
+ postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_SHOWN));
+ //???AWT: finishHierarchyChange(this, parent, 0);
+ notifyInputMethod(new Rectangle(x, y, w, h));
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by setVisible(boolean) method.
+ *
+ * @param b the visibility's state.
+ *
+ * @deprecated Replaced by setVisible(boolean) method.
+ */
+ @Deprecated
+ public void show(boolean b) {
+ if (b) {
+ show();
+ } else {
+ hide();
+ }
+ }
+
+ //???AWT
+ /*
+ void transferFocus(int dir) {
+ Container root = null;
+ if (this instanceof Container) {
+ Container cont = (Container) this;
+ if (cont.isFocusCycleRoot()) {
+ root = cont.getFocusTraversalRoot();
+ }
+ }
+ if (root == null) {
+ root = getFocusCycleRootAncestor();
+ }
+ // transfer focus up cycle if root is unreachable
+ Component comp = this;
+ while ((root != null)
+ && !(root.isFocusCycleRoot() && root.isShowing() && root.isEnabled() && root
+ .isFocusable())) {
+ comp = root;
+ root = root.getFocusCycleRootAncestor();
+ }
+ if (root == null) {
+ return;
+ }
+ FocusTraversalPolicy policy = root.getFocusTraversalPolicy();
+ Component nextComp = null;
+ switch (dir) {
+ case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS:
+ nextComp = policy.getComponentAfter(root, comp);
+ break;
+ case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS:
+ nextComp = policy.getComponentBefore(root, comp);
+ break;
+ }
+ if (nextComp != null) {
+ nextComp.requestFocus(false);
+ }
+ }
+
+ public void transferFocus() {
+ toolkit.lockAWT();
+ try {
+ nextFocus();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void transferFocusBackward() {
+ toolkit.lockAWT();
+ try {
+ transferFocus(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ public void transferFocusUpCycle() {
+ toolkit.lockAWT();
+ try {
+ KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ Container root = kfm.getCurrentFocusCycleRoot();
+
+ if(root == null) {
+ return;
+ }
+
+ boolean success = false;
+ Component nextComp = null;
+ Container newRoot = root;
+ do {
+ nextComp = newRoot instanceof Window ? newRoot.getFocusTraversalPolicy()
+ .getDefaultComponent(newRoot) : newRoot;
+ newRoot = newRoot.getFocusCycleRootAncestor();
+ if (nextComp == null) {
+ break;
+ }
+ success = nextComp.requestFocusInWindow();
+ if (newRoot == null) {
+ break;
+ }
+ kfm.setGlobalCurrentFocusCycleRoot(newRoot);
+ } while (!success);
+ if (!success && root != newRoot) {
+ kfm.setGlobalCurrentFocusCycleRoot(root);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Validates that this component has a valid layout.
+ */
+ public void validate() {
+ toolkit.lockAWT();
+ try {
+ if (!behaviour.isDisplayable()) {
+ return;
+ }
+ validateImpl();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Validate impl.
+ */
+ void validateImpl() {
+ valid = true;
+ }
+
+ /**
+ * Gets the native window.
+ *
+ * @return the native window
+ */
+ NativeWindow getNativeWindow() {
+ return behaviour.getNativeWindow();
+ }
+
+ /**
+ * Checks whether or not a maximum size is set for the Component.
+ *
+ * @return true, if the maximum size is set for the Component,
+ * false otherwise.
+ */
+ public boolean isMaximumSizeSet() {
+ toolkit.lockAWT();
+ try {
+ return maximumSize != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not the minimum size is set for the component.
+ *
+ * @return true, if the minimum size is set for the component,
+ * false otherwise.
+ */
+ public boolean isMinimumSizeSet() {
+ toolkit.lockAWT();
+ try {
+ return minimumSize != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks whether or not the preferred size is set for the Component.
+ *
+ * @return true, if the preferred size is set for the Component,
+ * false otherwise.
+ */
+ public boolean isPreferredSizeSet() {
+ toolkit.lockAWT();
+ try {
+ return preferredSize != null;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the maximum size of the Component.
+ *
+ * @return the maximum size of the Component.
+ */
+ public Dimension getMaximumSize() {
+ toolkit.lockAWT();
+ try {
+ return isMaximumSizeSet() ? new Dimension(maximumSize) : new Dimension(
+ Short.MAX_VALUE, Short.MAX_VALUE);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the minimum size of the Component.
+ *
+ * @return the minimum size of the Component.
+ */
+ public Dimension getMinimumSize() {
+ toolkit.lockAWT();
+ try {
+ return minimumSize();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by getMinimumSize() method.
+ *
+ * @return the Dimension.
+ *
+ * @deprecated Replaced by getMinimumSize() method.
+ */
+ @Deprecated
+ public Dimension minimumSize() {
+ toolkit.lockAWT();
+ try {
+ if (isMinimumSizeSet()) {
+ return (Dimension)minimumSize.clone();
+ }
+ Dimension defSize = getDefaultMinimumSize();
+ if (defSize != null) {
+ return (Dimension)defSize.clone();
+ }
+ return isDisplayable()? new Dimension(1, 1) : new Dimension(w, h);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the preferred size of the Component.
+ *
+ * @return the preferred size of the Component.
+ */
+ public Dimension getPreferredSize() {
+ toolkit.lockAWT();
+ try {
+ return preferredSize();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Deprecated: replaced by getPreferredSize() method.
+ *
+ * @return the Dimension.
+ *
+ * @deprecated Replaced by getPreferredSize() method.
+ */
+ @Deprecated
+ public Dimension preferredSize() {
+ toolkit.lockAWT();
+ try {
+ if (isPreferredSizeSet()) {
+ return new Dimension(preferredSize);
+ }
+ Dimension defSize = getDefaultPreferredSize();
+ if (defSize != null) {
+ return new Dimension(defSize);
+ }
+ return new Dimension(getMinimumSize());
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the maximum size of the Component.
+ *
+ * @param maximumSize the new maximum size of the Component.
+ */
+ public void setMaximumSize(Dimension maximumSize) {
+ Dimension oldMaximumSize;
+ toolkit.lockAWT();
+ try {
+ oldMaximumSize = this.maximumSize;
+ if (oldMaximumSize != null) {
+ oldMaximumSize = oldMaximumSize.getSize();
+ }
+ if (this.maximumSize == null) {
+ if (maximumSize != null) {
+ this.maximumSize = new Dimension(maximumSize);
+ }
+ } else {
+ if (maximumSize != null) {
+ this.maximumSize.setSize(maximumSize);
+ } else {
+ this.maximumSize = null;
+ }
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("maximumSize", oldMaximumSize, this.maximumSize); //$NON-NLS-1$
+ toolkit.lockAWT();
+ try {
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the minimum size of the Component.
+ *
+ * @param minimumSize the new minimum size of the Component.
+ */
+ public void setMinimumSize(Dimension minimumSize) {
+ Dimension oldMinimumSize;
+ toolkit.lockAWT();
+ try {
+ oldMinimumSize = this.minimumSize;
+ if (oldMinimumSize != null) {
+ oldMinimumSize = oldMinimumSize.getSize();
+ }
+ if (this.minimumSize == null) {
+ if (minimumSize != null) {
+ this.minimumSize = new Dimension(minimumSize);
+ }
+ } else {
+ if (minimumSize != null) {
+ this.minimumSize.setSize(minimumSize);
+ } else {
+ this.minimumSize = null;
+ }
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("minimumSize", oldMinimumSize, this.minimumSize); //$NON-NLS-1$
+ toolkit.lockAWT();
+ try {
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the preferred size of the Component.
+ *
+ * @param preferredSize the new preferred size of the Component.
+ */
+ public void setPreferredSize(Dimension preferredSize) {
+ Dimension oldPreferredSize;
+ toolkit.lockAWT();
+ try {
+ oldPreferredSize = this.preferredSize;
+ if (oldPreferredSize != null) {
+ oldPreferredSize = oldPreferredSize.getSize();
+ }
+ if (this.preferredSize == null) {
+ if (preferredSize != null) {
+ this.preferredSize = new Dimension(preferredSize);
+ }
+ } else {
+ if (preferredSize != null) {
+ this.preferredSize.setSize(preferredSize);
+ } else {
+ this.preferredSize = null;
+ }
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ firePropertyChange("preferredSize", oldPreferredSize, this.preferredSize); //$NON-NLS-1$
+ toolkit.lockAWT();
+ try {
+ //???AWT: invalidateRealParent();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ RedrawManager getRedrawManager() {
+ if (parent == null) {
+ return null;
+ }
+ return parent.getRedrawManager();
+ }
+ */
+
+ /**
+ * Checks if is focusability explicitly set.
+ *
+ * @return true if component has a focusable peer
+ */
+ //???AWT
+ /*
+ boolean isPeerFocusable() {
+ // The recommendations for Windows and Unix are that
+ // Canvases, Labels, Panels, Scrollbars, ScrollPanes, Windows,
+ // and lightweight Components have non-focusable peers,
+ // and all other Components have focusable peers.
+ if (this instanceof Canvas || this instanceof Label || this instanceof Panel
+ || this instanceof Scrollbar || this instanceof ScrollPane
+ || this instanceof Window || isLightweight()) {
+ return false;
+ }
+ return true;
+ }
+ */
+
+ /**
+ * @return true if focusability was explicitly set via a call to
+ * setFocusable() or via overriding isFocusable() or
+ * isFocusTraversable()
+ */
+ boolean isFocusabilityExplicitlySet() {
+ return calledSetFocusable || overridenIsFocusable;
+ }
+
+ /**
+ * Paints the component and all of its subcomponents.
+ *
+ * @param g the Graphics to be used for painting.
+ */
+ public void paintAll(Graphics g) {
+ toolkit.lockAWT();
+ try {
+ paint(g);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Updates this Component.
+ *
+ * @param g the Graphics to be used for updating.
+ */
+ public void update(Graphics g) {
+ toolkit.lockAWT();
+ try {
+ if (!isLightweight() && !isPrepainter()) {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, w, h);
+ g.setColor(getForeground());
+ }
+ paint(g);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Paints this component.
+ *
+ * @param g the Graphics to be used for painting.
+ */
+ public void paint(Graphics g) {
+ toolkit.lockAWT();
+ try {
+ // Just to nothing
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Prepares the component to be painted.
+ *
+ * @param g the Graphics to be used for painting.
+ */
+ void prepaint(Graphics g) {
+ // Just to nothing. For overriding.
+ }
+
+ /**
+ * Checks if is prepainter.
+ *
+ * @return true, if is prepainter
+ */
+ boolean isPrepainter() {
+ return false;
+ }
+
+ /**
+ * Prepare4 hierarchy change.
+ */
+ void prepare4HierarchyChange() {
+ if (hierarchyChangingCounter++ == 0) {
+ wasShowing = isShowing();
+ wasDisplayable = isDisplayable();
+ prepareChildren4HierarchyChange();
+ }
+ }
+
+ /**
+ * Prepare children4 hierarchy change.
+ */
+ void prepareChildren4HierarchyChange() {
+ // To be inherited by Container
+ }
+
+ //???AWT
+ /*
+ void finishHierarchyChange(Component changed, Container changedParent, int ancestorFlags) {
+ if (--hierarchyChangingCounter == 0) {
+ int changeFlags = ancestorFlags;
+ if (wasShowing != isShowing()) {
+ changeFlags |= HierarchyEvent.SHOWING_CHANGED;
+ }
+ if (wasDisplayable != isDisplayable()) {
+ changeFlags |= HierarchyEvent.DISPLAYABILITY_CHANGED;
+ }
+ if (changeFlags > 0) {
+ postEvent(new HierarchyEvent(this, HierarchyEvent.HIERARCHY_CHANGED, changed,
+ changedParent, changeFlags));
+ }
+ finishChildrenHierarchyChange(changed, changedParent, ancestorFlags);
+ }
+ }
+
+
+ void finishChildrenHierarchyChange(Component changed, Container changedParent,
+ int ancestorFlags) {
+ // To be inherited by Container
+ }
+
+ void postHierarchyBoundsEvents(Component changed, int id) {
+ postEvent(new HierarchyEvent(this, id, changed, null, 0));
+ }
+ */
+
+ /**
+ * Spread hierarchy bounds events.
+ *
+ * @param changed the changed
+ * @param id the id
+ */
+ void spreadHierarchyBoundsEvents(Component changed, int id) {
+ // To be inherited by Container
+ }
+
+ /**
+ * Dispatches an event to this component.
+ *
+ * @param e the Event.
+ */
+ public final void dispatchEvent(AWTEvent e) {
+ //???AWT
+ /*
+ if (e.isConsumed()) {
+ return;
+ }
+ if (e instanceof PaintEvent) {
+ toolkit.dispatchAWTEvent(e);
+ processPaintEvent((PaintEvent) e);
+ return;
+ }
+ KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ if (!e.dispatchedByKFM && kfm.dispatchEvent(e)) {
+ return;
+ }
+ if (e instanceof KeyEvent) {
+ KeyEvent ke = (KeyEvent) e;
+ // consumes KeyEvent which represents a focus traversal key
+ if (getFocusTraversalKeysEnabled()) {
+ kfm.processKeyEvent(this, ke);
+ if (ke.isConsumed()) {
+ return;
+ }
+ }
+ }
+ if (inputMethodsEnabled && dispatchToIM && e.isPosted && dispatchEventToIM(e)) {
+ return;
+ }
+ if (e.getID() == WindowEvent.WINDOW_ICONIFIED) {
+ notifyInputMethod(null);
+ }
+ AWTEvent.EventDescriptor descriptor = toolkit.eventTypeLookup.getEventDescriptor(e);
+ toolkit.dispatchAWTEvent(e);
+ if (descriptor != null) {
+ if (isEventEnabled(descriptor.eventMask)
+ || (getListeners(descriptor.listenerType).length > 0)) {
+ processEvent(e);
+ }
+ // input events can be consumed by user listeners:
+ if (!e.isConsumed() && ((enabledAWTEvents & descriptor.eventMask) != 0)) {
+ postprocessEvent(e, descriptor.eventMask);
+ }
+ }
+ postDeprecatedEvent(e);
+ */
+ }
+
+ /**
+ * Post deprecated event.
+ *
+ * @param e the e
+ */
+ private void postDeprecatedEvent(AWTEvent e) {
+ if (deprecatedEventHandler) {
+ Event evt = e.getEvent();
+ if (evt != null) {
+ postEvent(evt);
+ }
+ }
+ }
+
+ /**
+ * Postprocess event.
+ *
+ * @param e the e
+ * @param eventMask the event mask
+ */
+ void postprocessEvent(AWTEvent e, long eventMask) {
+ toolkit.lockAWT();
+ try {
+ // call system listeners under AWT lock
+ if (eventMask == AWTEvent.FOCUS_EVENT_MASK) {
+ preprocessFocusEvent((FocusEvent) e);
+ } else if (eventMask == AWTEvent.KEY_EVENT_MASK) {
+ preprocessKeyEvent((KeyEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) {
+ preprocessMouseEvent((MouseEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) {
+ preprocessMouseMotionEvent((MouseEvent) e);
+ } else if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) {
+ preprocessComponentEvent((ComponentEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) {
+ preprocessMouseWheelEvent((MouseWheelEvent) e);
+ } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) {
+ preprocessInputMethodEvent((InputMethodEvent) e);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Preprocess input method event.
+ *
+ * @param e the e
+ */
+ private void preprocessInputMethodEvent(InputMethodEvent e) {
+ processInputMethodEventImpl(e, inputMethodListeners.getSystemListeners());
+ }
+
+ /**
+ * Preprocess mouse wheel event.
+ *
+ * @param e the e
+ */
+ private void preprocessMouseWheelEvent(MouseWheelEvent e) {
+ processMouseWheelEventImpl(e, mouseWheelListeners.getSystemListeners());
+ }
+
+ /**
+ * Process mouse wheel event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processMouseWheelEventImpl(MouseWheelEvent e, Collection<MouseWheelListener> c) {
+ for (MouseWheelListener listener : c) {
+ switch (e.getID()) {
+ case MouseEvent.MOUSE_WHEEL:
+ listener.mouseWheelMoved(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Preprocess component event.
+ *
+ * @param e the e
+ */
+ private void preprocessComponentEvent(ComponentEvent e) {
+ processComponentEventImpl(e, componentListeners.getSystemListeners());
+ }
+
+ /**
+ * Preprocess mouse motion event.
+ *
+ * @param e the e
+ */
+ void preprocessMouseMotionEvent(MouseEvent e) {
+ processMouseMotionEventImpl(e, mouseMotionListeners.getSystemListeners());
+ }
+
+ /**
+ * Preprocess mouse event.
+ *
+ * @param e the e
+ */
+ void preprocessMouseEvent(MouseEvent e) {
+ processMouseEventImpl(e, mouseListeners.getSystemListeners());
+ }
+
+ /**
+ * Preprocess key event.
+ *
+ * @param e the e
+ */
+ void preprocessKeyEvent(KeyEvent e) {
+ processKeyEventImpl(e, keyListeners.getSystemListeners());
+ }
+
+ /**
+ * Preprocess focus event.
+ *
+ * @param e the e
+ */
+ void preprocessFocusEvent(FocusEvent e) {
+ processFocusEventImpl(e, focusListeners.getSystemListeners());
+ }
+
+ /**
+ * Processes AWTEvent occurred on this component.
+ *
+ * @param e the AWTEvent.
+ */
+ protected void processEvent(AWTEvent e) {
+ long eventMask = toolkit.eventTypeLookup.getEventMask(e);
+ if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) {
+ processComponentEvent((ComponentEvent) e);
+ } else if (eventMask == AWTEvent.FOCUS_EVENT_MASK) {
+ processFocusEvent((FocusEvent) e);
+ } else if (eventMask == AWTEvent.KEY_EVENT_MASK) {
+ processKeyEvent((KeyEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) {
+ processMouseEvent((MouseEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) {
+ processMouseWheelEvent((MouseWheelEvent) e);
+ } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) {
+ processMouseMotionEvent((MouseEvent) e);
+ } else if (eventMask == AWTEvent.HIERARCHY_EVENT_MASK) {
+ processHierarchyEvent((HierarchyEvent) e);
+ } else if (eventMask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) {
+ processHierarchyBoundsEvent((HierarchyEvent) e);
+ } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) {
+ processInputMethodEvent((InputMethodEvent) e);
+ }
+ }
+
+ /**
+ * Gets an array of all listener's objects based on the specified
+ * listener type and registered to this Component.
+ *
+ * @param listenerType the listener type.
+ *
+ * @return an array of all listener's objects based on the specified
+ * listener type and registered to this Component.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
+ if (ComponentListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getComponentListeners();
+ } else if (FocusListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getFocusListeners();
+ } else if (HierarchyBoundsListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getHierarchyBoundsListeners();
+ } else if (HierarchyListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getHierarchyListeners();
+ } else if (InputMethodListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getInputMethodListeners();
+ } else if (KeyListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getKeyListeners();
+ } else if (MouseWheelListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getMouseWheelListeners();
+ } else if (MouseMotionListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getMouseMotionListeners();
+ } else if (MouseListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getMouseListeners();
+ } else if (PropertyChangeListener.class.isAssignableFrom(listenerType)) {
+ return (T[]) getPropertyChangeListeners();
+ }
+ return (T[]) Array.newInstance(listenerType, 0);
+ }
+
+ /**
+ * Process paint event.
+ *
+ * @param event the event
+ */
+ private void processPaintEvent(PaintEvent event) {
+ if (redrawManager == null) {
+ return;
+ }
+ Rectangle clipRect = event.getUpdateRect();
+ if ((clipRect.width <= 0) || (clipRect.height <= 0)) {
+ return;
+ }
+ Graphics g = getGraphics();
+ if (g == null) {
+ return;
+ }
+ initGraphics(g, event);
+ if (!getIgnoreRepaint()) {
+ if (event.getID() == PaintEvent.PAINT) {
+ paint(g);
+ } else {
+ update(g);
+ }
+ }
+ g.dispose();
+ }
+
+ /**
+ * Inits the graphics.
+ *
+ * @param g the g
+ * @param e the e
+ */
+ void initGraphics(Graphics g, PaintEvent e) {
+ Rectangle clip = e.getUpdateRect();
+ if (clip instanceof ClipRegion) {
+ g.setClip(((ClipRegion) clip).getClip());
+ } else {
+ g.setClip(clip);
+ }
+ if (isPrepainter()) {
+ prepaint(g);
+ } else if (!isLightweight() && (e.getID() == PaintEvent.PAINT)) {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, w, h);
+ }
+ g.setFont(getFont());
+ g.setColor(getForeground());
+ }
+
+ /**
+ * Enables the events with the specified event mask to be delivered to
+ * this component.
+ *
+ * @param eventsToEnable the events mask which specifies the types
+ * of events to enable.
+ */
+ protected final void enableEvents(long eventsToEnable) {
+ toolkit.lockAWT();
+ try {
+ enabledEvents |= eventsToEnable;
+ deprecatedEventHandler = false;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Enable awt events.
+ *
+ * @param eventsToEnable the events to enable
+ */
+ private void enableAWTEvents(long eventsToEnable) {
+ enabledAWTEvents |= eventsToEnable;
+ }
+
+ /**
+ * Disables the events with types specified by the specified event mask
+ * from being delivered to this component.
+ *
+ * @param eventsToDisable the event mask specifying the event types.
+ */
+ protected final void disableEvents(long eventsToDisable) {
+ toolkit.lockAWT();
+ try {
+ enabledEvents &= ~eventsToDisable;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /*
+ * For use in MouseDispatcher only. Really it checks not only mouse events.
+ */
+ /**
+ * Checks if is mouse event enabled.
+ *
+ * @param eventMask the event mask
+ *
+ * @return true, if is mouse event enabled
+ */
+ boolean isMouseEventEnabled(long eventMask) {
+ return (isEventEnabled(eventMask) || (enabledAWTEvents & eventMask) != 0);
+ }
+
+ /**
+ * Checks if is event enabled.
+ *
+ * @param eventMask the event mask
+ *
+ * @return true, if is event enabled
+ */
+ boolean isEventEnabled(long eventMask) {
+ return ((enabledEvents & eventMask) != 0);
+ }
+
+ /**
+ * Enables or disables input method support for this component.
+ *
+ * @param enable true to enable input method support, false to disable it.
+ */
+ public void enableInputMethods(boolean enable) {
+ toolkit.lockAWT();
+ try {
+ if (!enable) {
+ removeNotifyInputContext();
+ }
+ inputMethodsEnabled = enable;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets an array of all component's listeners registered for this
+ * component.
+ *
+ * @return an array of all component's listeners registered for this
+ * component.
+ */
+ public ComponentListener[] getComponentListeners() {
+ return componentListeners.getUserListeners(new ComponentListener[0]);
+ }
+
+ /**
+ * Adds the specified component listener to the Component for receiving
+ * component's event.
+ *
+ * @param l the ComponentListener.
+ */
+ public void addComponentListener(ComponentListener l) {
+ componentListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the component listener registered for this Component.
+ *
+ * @param l the ComponentListener.
+ */
+ public void removeComponentListener(ComponentListener l) {
+ componentListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a component event that has occurred on this component
+ * by dispatching them to any registered ComponentListener objects.
+ *
+ * @param e the ComponentEvent.
+ */
+ protected void processComponentEvent(ComponentEvent e) {
+ processComponentEventImpl(e, componentListeners.getUserListeners());
+ }
+
+ /**
+ * Process component event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processComponentEventImpl(ComponentEvent e, Collection<ComponentListener> c) {
+ for (ComponentListener listener : c) {
+ switch (e.getID()) {
+ case ComponentEvent.COMPONENT_HIDDEN:
+ listener.componentHidden(e);
+ break;
+ case ComponentEvent.COMPONENT_MOVED:
+ listener.componentMoved(e);
+ break;
+ case ComponentEvent.COMPONENT_RESIZED:
+ listener.componentResized(e);
+ break;
+ case ComponentEvent.COMPONENT_SHOWN:
+ listener.componentShown(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of focus listeners registered for this Component.
+ *
+ * @return the array of focus listeners registered for this Component.
+ */
+ public FocusListener[] getFocusListeners() {
+ return focusListeners.getUserListeners(new FocusListener[0]);
+ }
+
+ /**
+ * Adds the specified focus listener to the Component for receiving
+ * focus events.
+ *
+ * @param l the FocusListener.
+ */
+ public void addFocusListener(FocusListener l) {
+ focusListeners.addUserListener(l);
+ }
+
+ /**
+ * Adds the awt focus listener.
+ *
+ * @param l the l
+ */
+ void addAWTFocusListener(FocusListener l) {
+ enableAWTEvents(AWTEvent.FOCUS_EVENT_MASK);
+ focusListeners.addSystemListener(l);
+ }
+
+ /**
+ * Removes the focus listener registered for this Component.
+ *
+ * @param l the FocusListener.
+ */
+ public void removeFocusListener(FocusListener l) {
+ focusListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a FocusEvent that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the FocusEvent.
+ */
+ protected void processFocusEvent(FocusEvent e) {
+ processFocusEventImpl(e, focusListeners.getUserListeners());
+ }
+
+ /**
+ * Process focus event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processFocusEventImpl(FocusEvent e, Collection<FocusListener> c) {
+ for (FocusListener listener : c) {
+ switch (e.getID()) {
+ case FocusEvent.FOCUS_GAINED:
+ listener.focusGained(e);
+ break;
+ case FocusEvent.FOCUS_LOST:
+ listener.focusLost(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of registered HierarchyListeners for
+ * this Component.
+ *
+ * @return an array of registered HierarchyListeners for
+ * this Component.
+ */
+ public HierarchyListener[] getHierarchyListeners() {
+ return hierarchyListeners.getUserListeners(new HierarchyListener[0]);
+ }
+
+ /**
+ * Adds the specified hierarchy listener.
+ *
+ * @param l the HierarchyListener.
+ */
+ public void addHierarchyListener(HierarchyListener l) {
+ hierarchyListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the hierarchy listener registered for this component.
+ *
+ * @param l the HierarchyListener.
+ */
+ public void removeHierarchyListener(HierarchyListener l) {
+ hierarchyListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a hierarchy event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the HierarchyEvent.
+ */
+ protected void processHierarchyEvent(HierarchyEvent e) {
+ for (HierarchyListener listener : hierarchyListeners.getUserListeners()) {
+ switch (e.getID()) {
+ case HierarchyEvent.HIERARCHY_CHANGED:
+ listener.hierarchyChanged(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of HierarchyBoundsListener objects registered
+ * to this Component.
+ *
+ * @return an array of HierarchyBoundsListener objects.
+ */
+ public HierarchyBoundsListener[] getHierarchyBoundsListeners() {
+ return hierarchyBoundsListeners.getUserListeners(new HierarchyBoundsListener[0]);
+ }
+
+ /**
+ * Adds the specified hierarchy bounds listener.
+ *
+ * @param l the HierarchyBoundsListener.
+ */
+ public void addHierarchyBoundsListener(HierarchyBoundsListener l) {
+ hierarchyBoundsListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the hierarchy bounds listener registered for this Component.
+ *
+ * @param l the HierarchyBoundsListener.
+ */
+ public void removeHierarchyBoundsListener(HierarchyBoundsListener l) {
+ hierarchyBoundsListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a hierarchy bounds event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the HierarchyBoundsEvent.
+ */
+ protected void processHierarchyBoundsEvent(HierarchyEvent e) {
+ for (HierarchyBoundsListener listener : hierarchyBoundsListeners.getUserListeners()) {
+ switch (e.getID()) {
+ case HierarchyEvent.ANCESTOR_MOVED:
+ listener.ancestorMoved(e);
+ break;
+ case HierarchyEvent.ANCESTOR_RESIZED:
+ listener.ancestorResized(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of the key listeners registered to the Component.
+ *
+ * @return an array of the key listeners registered to the Component.
+ */
+ public KeyListener[] getKeyListeners() {
+ return keyListeners.getUserListeners(new KeyListener[0]);
+ }
+
+ /**
+ * Adds the specified key listener.
+ *
+ * @param l the KeyListener.
+ */
+ public void addKeyListener(KeyListener l) {
+ keyListeners.addUserListener(l);
+ }
+
+ /**
+ * Adds the awt key listener.
+ *
+ * @param l the l
+ */
+ void addAWTKeyListener(KeyListener l) {
+ enableAWTEvents(AWTEvent.KEY_EVENT_MASK);
+ keyListeners.addSystemListener(l);
+ }
+
+ /**
+ * Removes the key listener registered for this Component.
+ *
+ * @param l the KeyListener.
+ */
+ public void removeKeyListener(KeyListener l) {
+ keyListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a key event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the KeyEvent.
+ */
+ protected void processKeyEvent(KeyEvent e) {
+ processKeyEventImpl(e, keyListeners.getUserListeners());
+ }
+
+ /**
+ * Process key event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processKeyEventImpl(KeyEvent e, Collection<KeyListener> c) {
+ for (KeyListener listener : c) {
+ switch (e.getID()) {
+ case KeyEvent.KEY_PRESSED:
+ listener.keyPressed(e);
+ break;
+ case KeyEvent.KEY_RELEASED:
+ listener.keyReleased(e);
+ break;
+ case KeyEvent.KEY_TYPED:
+ listener.keyTyped(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of the mouse listeners registered to the Component.
+ *
+ * @return an array of the mouse listeners registered to the Component.
+ */
+ public MouseListener[] getMouseListeners() {
+ return mouseListeners.getUserListeners(new MouseListener[0]);
+ }
+
+ /**
+ * Adds the specified mouse listener.
+ *
+ * @param l the MouseListener.
+ */
+ public void addMouseListener(MouseListener l) {
+ mouseListeners.addUserListener(l);
+ }
+
+ /**
+ * Adds the awt mouse listener.
+ *
+ * @param l the l
+ */
+ void addAWTMouseListener(MouseListener l) {
+ enableAWTEvents(AWTEvent.MOUSE_EVENT_MASK);
+ mouseListeners.addSystemListener(l);
+ }
+
+ /**
+ * Adds the awt mouse motion listener.
+ *
+ * @param l the l
+ */
+ void addAWTMouseMotionListener(MouseMotionListener l) {
+ enableAWTEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
+ mouseMotionListeners.addSystemListener(l);
+ }
+
+ /**
+ * Adds the awt component listener.
+ *
+ * @param l the l
+ */
+ void addAWTComponentListener(ComponentListener l) {
+ enableAWTEvents(AWTEvent.COMPONENT_EVENT_MASK);
+ componentListeners.addSystemListener(l);
+ }
+
+ /**
+ * Adds the awt input method listener.
+ *
+ * @param l the l
+ */
+ void addAWTInputMethodListener(InputMethodListener l) {
+ enableAWTEvents(AWTEvent.INPUT_METHOD_EVENT_MASK);
+ inputMethodListeners.addSystemListener(l);
+ }
+
+ /**
+ * Adds the awt mouse wheel listener.
+ *
+ * @param l the l
+ */
+ void addAWTMouseWheelListener(MouseWheelListener l) {
+ enableAWTEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK);
+ mouseWheelListeners.addSystemListener(l);
+ }
+
+ /**
+ * Removes the mouse listener registered for this Component.
+ *
+ * @param l the MouseListener.
+ */
+ public void removeMouseListener(MouseListener l) {
+ mouseListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a mouse event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the MouseEvent.
+ */
+ protected void processMouseEvent(MouseEvent e) {
+ processMouseEventImpl(e, mouseListeners.getUserListeners());
+ }
+
+ /**
+ * Process mouse event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processMouseEventImpl(MouseEvent e, Collection<MouseListener> c) {
+ for (MouseListener listener : c) {
+ switch (e.getID()) {
+ case MouseEvent.MOUSE_CLICKED:
+ listener.mouseClicked(e);
+ break;
+ case MouseEvent.MOUSE_ENTERED:
+ listener.mouseEntered(e);
+ break;
+ case MouseEvent.MOUSE_EXITED:
+ listener.mouseExited(e);
+ break;
+ case MouseEvent.MOUSE_PRESSED:
+ listener.mousePressed(e);
+ break;
+ case MouseEvent.MOUSE_RELEASED:
+ listener.mouseReleased(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Process mouse motion event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processMouseMotionEventImpl(MouseEvent e, Collection<MouseMotionListener> c) {
+ for (MouseMotionListener listener : c) {
+ switch (e.getID()) {
+ case MouseEvent.MOUSE_DRAGGED:
+ listener.mouseDragged(e);
+ break;
+ case MouseEvent.MOUSE_MOVED:
+ listener.mouseMoved(e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets an array of the mouse motion listeners registered to
+ * the Component.
+ *
+ * @return an array of the MouseMotionListeners registered to
+ * the Component.
+ */
+ public MouseMotionListener[] getMouseMotionListeners() {
+ return mouseMotionListeners.getUserListeners(new MouseMotionListener[0]);
+ }
+
+ /**
+ * Adds the specified mouse motion listener.
+ *
+ * @param l the MouseMotionListener.
+ */
+ public void addMouseMotionListener(MouseMotionListener l) {
+ mouseMotionListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the mouse motion listener registered for this component.
+ *
+ * @param l the MouseMotionListener.
+ */
+ public void removeMouseMotionListener(MouseMotionListener l) {
+ mouseMotionListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a mouse motion event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the MouseEvent.
+ */
+ protected void processMouseMotionEvent(MouseEvent e) {
+ processMouseMotionEventImpl(e, mouseMotionListeners.getUserListeners());
+ }
+
+ /**
+ * Gets an array of the mouse wheel listeners registered to
+ * the Component.
+ *
+ * @return an array of the MouseWheelListeners registered to
+ * the Component.
+ */
+ public MouseWheelListener[] getMouseWheelListeners() {
+ return mouseWheelListeners.getUserListeners(new MouseWheelListener[0]);
+ }
+
+ /**
+ * Adds the specified mouse wheel listener.
+ *
+ * @param l the MouseWheelListener.
+ */
+ public void addMouseWheelListener(MouseWheelListener l) {
+ mouseWheelListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the mouse wheel listener registered for this component.
+ *
+ * @param l the MouseWheelListener.
+ */
+ public void removeMouseWheelListener(MouseWheelListener l) {
+ mouseWheelListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes a mouse wheel event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the MouseWheelEvent.
+ */
+ protected void processMouseWheelEvent(MouseWheelEvent e) {
+ processMouseWheelEventImpl(e, mouseWheelListeners.getUserListeners());
+ }
+
+ /**
+ * Gets an array of the InputMethodListener listeners
+ * registered to the Component.
+ *
+ * @return an array of the InputMethodListener listeners
+ * registered to the Component.
+ */
+ public InputMethodListener[] getInputMethodListeners() {
+ return inputMethodListeners.getUserListeners(new InputMethodListener[0]);
+ }
+
+ /**
+ * Adds the specified input method listener.
+ *
+ * @param l the InputMethodListener.
+ */
+ public void addInputMethodListener(InputMethodListener l) {
+ inputMethodListeners.addUserListener(l);
+ }
+
+ /**
+ * Removes the input method listener registered for this component.
+ *
+ * @param l the InputMethodListener.
+ */
+ public void removeInputMethodListener(InputMethodListener l) {
+ inputMethodListeners.removeUserListener(l);
+ }
+
+ /**
+ * Processes an input method event that has occurred on this component
+ * by dispatching it to the registered listeners.
+ *
+ * @param e the InputMethodEvent.
+ */
+ protected void processInputMethodEvent(InputMethodEvent e) {
+ processInputMethodEventImpl(e, inputMethodListeners.getUserListeners());
+ }
+
+ /**
+ * Process input method event impl.
+ *
+ * @param e the e
+ * @param c the c
+ */
+ private void processInputMethodEventImpl(InputMethodEvent e,
+ Collection<InputMethodListener> c) {
+ for (InputMethodListener listener : c) {
+ switch (e.getID()) {
+ case InputMethodEvent.CARET_POSITION_CHANGED:
+ listener.caretPositionChanged(e);
+ break;
+ case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED:
+ listener.inputMethodTextChanged(e);
+ break;
+ }
+ }
+ }
+
+ //???AWT
+ /*
+ public Point getMousePosition() throws HeadlessException {
+ Point absPointerPos = MouseInfo.getPointerInfo().getLocation();
+ Window winUnderPtr = toolkit.dispatcher.mouseDispatcher.findWindowAt(absPointerPos);
+ Point pointerPos = MouseDispatcher.convertPoint(null, absPointerPos, winUnderPtr);
+ boolean isUnderPointer = false;
+ if (winUnderPtr == null) {
+ return null;
+ }
+ isUnderPointer = winUnderPtr.isComponentAt(this, pointerPos);
+ if (isUnderPointer) {
+ return MouseDispatcher.convertPoint(null, absPointerPos, this);
+ }
+ return null;
+ }
+ */
+
+ /**
+ * Set native caret at the given position <br>
+ * Note: this method takes AWT lock inside because it walks through the
+ * component hierarchy.
+ *
+ * @param x the x
+ * @param y the y
+ */
+ void setCaretPos(final int x, final int y) {
+ Runnable r = new Runnable() {
+ public void run() {
+ toolkit.lockAWT();
+ try {
+ setCaretPosImpl(x, y);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ };
+ if (Thread.currentThread() instanceof EventDispatchThread) {
+ r.run();
+ } else {
+ toolkit.getSystemEventQueueImpl().postEvent(new InvocationEvent(this, r));
+ }
+ }
+
+ /**
+ * This method should be called only at event dispatch thread.
+ *
+ * @param x the x
+ * @param y the y
+ */
+ void setCaretPosImpl(int x, int y) {
+ Component c = this;
+ while ((c != null) && c.behaviour.isLightweight()) {
+ x += c.x;
+ y += c.y;
+ //???AWT: c = c.getParent();
+ }
+ if (c == null) {
+ return;
+ }
+ //???AWT
+ /*
+ if (c instanceof Window) {
+ Insets insets = c.getNativeInsets();
+ x -= insets.left;
+ y -= insets.top;
+ }
+ toolkit.getWindowFactory().setCaretPosition(x, y);
+ */
+ }
+
+ // to be overridden in standard components such as Button and List
+ /**
+ * Gets the default minimum size.
+ *
+ * @return the default minimum size
+ */
+ Dimension getDefaultMinimumSize() {
+ return null;
+ }
+
+ // to be overridden in standard components such as Button and List
+ /**
+ * Gets the default preferred size.
+ *
+ * @return the default preferred size
+ */
+ Dimension getDefaultPreferredSize() {
+ return null;
+ }
+
+ // to be overridden in standard components such as Button and List
+ /**
+ * Reset default size.
+ */
+ void resetDefaultSize() {
+ }
+
+ //???AWT
+ /*
+ ComponentBehavior createBehavior() {
+ return new LWBehavior(this);
+ }
+ */
+
+ /**
+ * Gets the default background.
+ *
+ * @return the default background
+ */
+ Color getDefaultBackground() {
+ //???AWT: return getWindowAncestor().getDefaultBackground();
+ return getBackground();
+ }
+
+ /**
+ * Gets the default foreground.
+ *
+ * @return the default foreground
+ */
+ Color getDefaultForeground() {
+ //???AWT return getWindowAncestor().getDefaultForeground();
+ return getForeground();
+ }
+
+ /**
+ * Called when native resource for this component is created (for
+ * heavyweights only).
+ *
+ * @param win the win
+ */
+ void nativeWindowCreated(NativeWindow win) {
+ // to be overridden
+ }
+
+ /**
+ * Determine the component's area hidden behind the windows that have higher
+ * Z-order, including windows of other applications.
+ *
+ * @param image the image
+ * @param destLocation the dest location
+ * @param destSize the dest size
+ * @param source the source
+ *
+ * @return the calculated region, or null if it cannot be determined
+ */
+ //???AWT
+ /*
+ MultiRectArea getObscuredRegion(Rectangle part) {
+ if (!visible || parent == null || !parent.visible) {
+ return null;
+ }
+ Rectangle r = new Rectangle(0, 0, w, h);
+ if (part != null) {
+ r = r.intersection(part);
+ }
+ if (r.isEmpty()) {
+ return null;
+ }
+ r.translate(x, y);
+ MultiRectArea ret = parent.getObscuredRegion(r);
+ if (ret != null) {
+ parent.addObscuredRegions(ret, this);
+ ret.translate(-x, -y);
+ ret.intersect(new Rectangle(0, 0, w, h));
+ }
+ return ret;
+ }
+ */
+
+ //???AWT
+ /*
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+ stream.defaultReadObject();
+ FieldsAccessor accessor = new FieldsAccessor(Component.class, this);
+ accessor.set("toolkit", Toolkit.getDefaultToolkit()); //$NON-NLS-1$
+ accessor.set("behaviour", createBehavior()); //$NON-NLS-1$
+ accessor.set("componentLock", new Object()); // $NON-LOCK-1$ //$NON-NLS-1$
+ }
+ */
+
+ final void onDrawImage(Image image, Point destLocation, Dimension destSize, Rectangle source) {
+ ImageParameters imageParams;
+ if (updatedImages == null) {
+ updatedImages = new HashMap<Image, ImageParameters>();
+ }
+ imageParams = updatedImages.get(image);
+ if (imageParams == null) {
+ imageParams = new ImageParameters();
+ updatedImages.put(image, imageParams);
+ }
+ imageParams.addDrawing(destLocation, destSize, source);
+ }
+
+ public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
+ toolkit.lockAWT();
+ try {
+ boolean done = false;
+ if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
+ done = true;
+ } else if ((infoflags & SOMEBITS) != 0 && incrementalImageUpdate) {
+ done = true;
+ }
+ if (done) {
+ repaint();
+ }
+ return (infoflags & (ABORT | ALLBITS)) == 0;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ private void invalidateRealParent() {
+ Container realParent = getRealParent();
+ if ((realParent != null) && realParent.isValid()) {
+ realParent.invalidate();
+ }
+ }
+ */
+
+ /**
+ * The Class ImageParameters.
+ */
+ private class ImageParameters {
+
+ /** The drawing params. */
+ private final LinkedList<DrawingParameters> drawingParams = new LinkedList<DrawingParameters>();
+
+ /** The size. */
+ Dimension size = new Dimension(Component.this.w, Component.this.h);
+
+ /**
+ * Adds the drawing.
+ *
+ * @param destLocation the dest location
+ * @param destSize the dest size
+ * @param source the source
+ */
+ void addDrawing(Point destLocation, Dimension destSize, Rectangle source) {
+ drawingParams.add(new DrawingParameters(destLocation, destSize, source));
+ }
+
+ /**
+ * Drawing parameters iterator.
+ *
+ * @return the iterator< drawing parameters>
+ */
+ Iterator<DrawingParameters> drawingParametersIterator() {
+ return drawingParams.iterator();
+ }
+
+ /**
+ * The Class DrawingParameters.
+ */
+ class DrawingParameters {
+
+ /** The dest location. */
+ Point destLocation;
+
+ /** The dest size. */
+ Dimension destSize;
+
+ /** The source. */
+ Rectangle source;
+
+ /**
+ * Instantiates a new drawing parameters.
+ *
+ * @param destLocation the dest location
+ * @param destSize the dest size
+ * @param source the source
+ */
+ DrawingParameters(Point destLocation, Dimension destSize, Rectangle source) {
+ this.destLocation = new Point(destLocation);
+ if (destSize != null) {
+ this.destSize = new Dimension(destSize);
+ } else {
+ this.destSize = null;
+ }
+ if (source != null) {
+ this.source = new Rectangle(source);
+ } else {
+ this.source = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * TextComponent support.
+ *
+ * @param e the e
+ *
+ * @return true, if dispatch event to im
+ */
+ //???AWT
+ /*
+ private TextKit textKit = null;
+
+ TextKit getTextKit() {
+ return textKit;
+ }
+
+ void setTextKit(TextKit kit) {
+ textKit = kit;
+ }
+ */
+
+ /**
+ * TextField support
+ */
+ //???AWT
+ /*
+ private TextFieldKit textFieldKit = null;
+
+ TextFieldKit getTextFieldKit() {
+ return textFieldKit;
+ }
+
+ void setTextFieldKit(TextFieldKit kit) {
+ textFieldKit = kit;
+ }
+ */
+
+ /**
+ * Dispatches input & focus events to input method
+ * context.
+ * @param e event to pass to InputContext.dispatchEvent()
+ * @return true if event was consumed by IM, false otherwise
+ */
+ private boolean dispatchEventToIM(AWTEvent e) {
+ InputContext ic = getInputContext();
+ if (ic == null) {
+ return false;
+ }
+ int id = e.getID();
+ boolean isInputEvent = ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST))
+ || ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST));
+ if (((id >= FocusEvent.FOCUS_FIRST) && (id <= FocusEvent.FOCUS_LAST)) || isInputEvent) {
+ ic.dispatchEvent(e);
+ }
+ return e.isConsumed();
+ }
+}
diff --git a/awt/java/awt/ComponentBehavior.java b/awt/java/awt/ComponentBehavior.java
new file mode 100644
index 0000000..89c9999
--- /dev/null
+++ b/awt/java/awt/ComponentBehavior.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+/**
+ * The interface of the helper object that encapsulates the difference
+ * between lightweight and heavyweight components.
+ */
+interface ComponentBehavior {
+
+ void addNotify();
+
+ void setBounds(int x, int y, int w, int h, int bMask);
+
+ void setVisible(boolean b);
+
+ Graphics getGraphics(int translationX, int translationY, int width, int height);
+
+ NativeWindow getNativeWindow();
+
+ boolean isLightweight();
+
+ void onMove(int x, int y);
+
+ boolean isOpaque();
+
+ boolean isDisplayable();
+
+ void setEnabled(boolean value);
+
+ void removeNotify();
+
+ void setZOrder(int newIndex, int oldIndex);
+
+ boolean setFocus(boolean focus, Component opposite);
+}
diff --git a/awt/java/awt/ComponentOrientation.java b/awt/java/awt/ComponentOrientation.java
new file mode 100644
index 0000000..ddb118d
--- /dev/null
+++ b/awt/java/awt/ComponentOrientation.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov, Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * The ComponentOrientation class specifies the language-sensitive orientation
+ * of component's elements or text. It is used to reflect the differences in this
+ * ordering between different writting systems. The ComponentOrientation class
+ * indicates the orientation of the elements/text in the horizontal direction
+ * ("left to right" or "right to left") and in the vertical direction
+ * ("top to bottom" or "bottom to top").
+ */
+public final class ComponentOrientation implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -4113291392143563828L;
+
+ /**
+ * The Constant LEFT_TO_RIGHT indicates that items run left to right.
+ */
+ public static final ComponentOrientation LEFT_TO_RIGHT = new ComponentOrientation(true, true);
+
+ /**
+ * The Constant RIGHT_TO_LEFT indicates that items run right to left.
+ */
+ public static final ComponentOrientation RIGHT_TO_LEFT = new ComponentOrientation(true, false);
+
+ /** The Constant UNKNOWN indicates that a component's orientation is not set. */
+ public static final ComponentOrientation UNKNOWN = new ComponentOrientation(true, true);
+
+ /** The Constant rlLangs. */
+ private static final Set<String> rlLangs = new HashSet<String>(); //RIGHT_TO_LEFT languages
+
+ /** The horizontal. */
+ private final boolean horizontal;
+
+ /** The left2right. */
+ private final boolean left2right;
+
+ static {
+ rlLangs.add("ar"); //$NON-NLS-1$
+ rlLangs.add("fa"); //$NON-NLS-1$
+ rlLangs.add("iw"); //$NON-NLS-1$
+ rlLangs.add("ur"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the orientation for the given ResourceBundle's localization.
+ *
+ * @param bdl the ResourceBundle.
+ *
+ * @return the ComponentOrientation.
+ *
+ * @deprecated Use getOrientation(java.util.Locale) method.
+ */
+ @Deprecated
+ public static ComponentOrientation getOrientation(ResourceBundle bdl) {
+ Object obj = null;
+ try {
+ obj = bdl.getObject("Orientation"); //$NON-NLS-1$
+ }
+ catch (MissingResourceException mre) {
+ obj = null;
+ }
+ if (obj instanceof ComponentOrientation) {
+ return (ComponentOrientation) obj;
+ }
+ Locale locale = bdl.getLocale();
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ return getOrientation(locale);
+ }
+
+ /**
+ * Gets the orientation for the specified locale.
+ *
+ * @param locale the specified Locale.
+ *
+ * @return the ComponentOrientation.
+ */
+ public static ComponentOrientation getOrientation(Locale locale) {
+ String lang = locale.getLanguage();
+ return rlLangs.contains(lang) ? RIGHT_TO_LEFT : LEFT_TO_RIGHT;
+ }
+
+ /**
+ * Instantiates a new component orientation.
+ *
+ * @param hor whether the items should be arranged horizontally
+ * @param l2r whether this orientation specifies a left-to-right flow
+ */
+ private ComponentOrientation(boolean hor, boolean l2r) {
+ horizontal = hor;
+ left2right = l2r;
+ }
+
+ /**
+ * Returns true if the text of the of writing systems arranged
+ * horizontally.
+ *
+ * @return true, if the text is written horizontally, false
+ * for a vertical arrangement.
+ */
+ public boolean isHorizontal() {
+ return horizontal;
+ }
+
+ /**
+ * Returns true if the text is arranged from left to right.
+ *
+ * @return true, for writing systems written from left to right;
+ * false for right-to-left.
+ */
+ public boolean isLeftToRight() {
+ return left2right;
+ }
+
+}
diff --git a/awt/java/awt/Composite.java b/awt/java/awt/Composite.java
new file mode 100644
index 0000000..8e5b90a
--- /dev/null
+++ b/awt/java/awt/Composite.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.image.ColorModel;
+
+/**
+ * The Composite interface allows the methods to compose a draw primitive
+ * on the graphics area. The classes implementing this interface provides
+ * the rules and a method to create the context for a particular operation.
+ */
+public interface Composite {
+
+ /**
+ * Creates a CompositeContext which defines the encapsulated and
+ * optimized environment for a compositing operation. Several contexts
+ * can exist for a single Composite object.
+ *
+ * @param srcColorModel the source's ColorModel.
+ * @param dstColorModel the destination's ColorModel.
+ * @param hints the RenderingHints.
+ *
+ * @return the CompositeContext object.
+ */
+ public CompositeContext createContext(ColorModel srcColorModel,
+ ColorModel dstColorModel, RenderingHints hints);
+
+}
+
diff --git a/awt/java/awt/CompositeContext.java b/awt/java/awt/CompositeContext.java
new file mode 100644
index 0000000..c676032
--- /dev/null
+++ b/awt/java/awt/CompositeContext.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+/**
+ * The CompositeContext interface specifies the encapsulated and optimized
+ * environment for a compositing operation.
+ */
+public interface CompositeContext {
+
+ /**
+ * Composes the two source Raster objects and places the result in the
+ * destination WritableRaster.
+ *
+ * @param src the source Raster.
+ * @param dstIn the destination Raster.
+ * @param dstOut the WritableRaster object where the result of
+ * composing operation is stored.
+ */
+ public void compose(Raster src, Raster dstIn, WritableRaster dstOut);
+
+ /**
+ * Releases resources allocated for a context.
+ */
+ public void dispose();
+
+}
+
diff --git a/awt/java/awt/Cursor.java b/awt/java/awt/Cursor.java
new file mode 100644
index 0000000..625686c
--- /dev/null
+++ b/awt/java/awt/Cursor.java
@@ -0,0 +1,372 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.NativeCursor;
+
+/**
+ * The Cursor class represents the bitmap of the mouse cursor.
+ */
+public class Cursor implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 8028237497568985504L;
+
+ /** The Constant DEFAULT_CURSOR indicates the default cursor type. */
+ public static final int DEFAULT_CURSOR = 0;
+
+ /** The Constant CROSSHAIR_CURSOR cursor type. */
+ public static final int CROSSHAIR_CURSOR = 1;
+
+ /** The Constant TEXT_CURSOR cursor type. */
+ public static final int TEXT_CURSOR = 2;
+
+ /** The Constant WAIT_CURSOR cursor type. */
+ public static final int WAIT_CURSOR = 3;
+
+ /** The Constant SW_RESIZE_CURSOR cursor type. */
+ public static final int SW_RESIZE_CURSOR = 4;
+
+ /** The Constant SE_RESIZE_CURSOR cursor type. */
+ public static final int SE_RESIZE_CURSOR = 5;
+
+ /** The Constant NW_RESIZE_CURSOR cursor type. */
+ public static final int NW_RESIZE_CURSOR = 6;
+
+ /** The Constant NE_RESIZE_CURSOR cursor type. */
+ public static final int NE_RESIZE_CURSOR = 7;
+
+ /** The Constant N_RESIZE_CURSOR cursor type. */
+ public static final int N_RESIZE_CURSOR = 8;
+
+ /** The Constant S_RESIZE_CURSOR cursor type. */
+ public static final int S_RESIZE_CURSOR = 9;
+
+ /** The Constant W_RESIZE_CURSOR cursor type. */
+ public static final int W_RESIZE_CURSOR = 10;
+
+ /** The Constant E_RESIZE_CURSOR cursor type. */
+ public static final int E_RESIZE_CURSOR = 11;
+
+ /** The Constant HAND_CURSOR cursor type. */
+ public static final int HAND_CURSOR = 12;
+
+ /** The Constant MOVE_CURSOR cursor type. */
+ public static final int MOVE_CURSOR = 13;
+
+ /** A mapping from names to system custom cursors. */
+ static Map<String, Cursor> systemCustomCursors;
+
+ /** The cursor props. */
+ static Properties cursorProps;
+
+ /** The Constant predefinedNames. */
+ static final String[] predefinedNames = {
+ "Default", "Crosshair", "Text", "Wait", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ "Southwest Resize", "Southeast Resize", //$NON-NLS-1$ //$NON-NLS-2$
+ "Northwest Resize", "Northeast Resize", //$NON-NLS-1$ //$NON-NLS-2$
+ "North Resize", "South Resize", "West Resize", "East Resize", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ "Hand", "Move" //$NON-NLS-1$ //$NON-NLS-2$
+
+ };
+
+ /** The predefined set of cursors. */
+ protected static Cursor[] predefined = {
+ new Cursor(DEFAULT_CURSOR), null, null, null,
+ null, null, null, null,
+ null, null, null, null,
+ null, null
+ };
+
+ /** The Constant CUSTOM_CURSOR is associated with all custom cursor types.
+ * (Those which are not predefined)
+ */
+ public static final int CUSTOM_CURSOR = -1;
+
+ /** The name of the cursor. */
+ protected String name;
+
+ /** The type of the cursor, chosen from the list of cursor type constants. */
+ private final int type;
+
+ /** The native cursor. */
+ private transient NativeCursor nativeCursor;
+
+ /** The exact point on the cursor image that indicates which point
+ * the cursor is selecting (pointing to). The coordinates are given
+ * with respect the origin of the Image (its upper left corner).
+ */
+ private Point hotSpot;
+
+ /** The image to draw on the screen representing the cursor. */
+ private Image image;
+
+ /**
+ * Instantiates a new cursor with the specified name.
+ *
+ * @param name the name of cursor.
+ */
+ protected Cursor(String name) {
+ this(name, null, new Point());
+ }
+
+ /**
+ * Instantiates a new cursor of the specified type.
+ *
+ * @param type the type of cursor.
+ */
+ public Cursor(int type) {
+ checkType(type);
+ this.type = type;
+ if ((type >= 0) && (type < predefinedNames.length)) {
+ name = predefinedNames[type] + " Cursor"; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Instantiates a new cursor.
+ *
+ * @param name the name
+ * @param img the img
+ * @param hotSpot the hot spot
+ */
+ Cursor(String name, Image img, Point hotSpot) {
+ this.name = name;
+ type = CUSTOM_CURSOR;
+ this.hotSpot = hotSpot;
+ image = img;
+ }
+
+ /**
+ * Finalize method overrided finalize method from Object class.
+ *
+ * @throws Throwable if the native cursor is not null and throws
+ * a throwable when destroyed.
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ if (nativeCursor != null) {
+ nativeCursor.destroyCursor();
+ }
+ }
+
+ /**
+ * Gets the name of the cursor.
+ *
+ * @return the name of the cursor.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the String representation of the cursor.
+ *
+ * @return the String representation of the cursor.
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + "[" + name + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Gets the cursor type.
+ *
+ * @return the cursor type
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Gets the predefined cursor with the specified type.
+ *
+ * @param type the type of cursor.
+ *
+ * @return the predefined cursor with the specified type.
+ */
+ public static Cursor getPredefinedCursor(int type) {
+ checkType(type);
+ Cursor cursor = predefined[type];
+ if (cursor == null) {
+ cursor = new Cursor(type);
+ predefined[type] = cursor;
+ }
+ return cursor;
+ }
+
+ /**
+ * Gets the default cursor.
+ *
+ * @return the default cursor.
+ */
+ public static Cursor getDefaultCursor() {
+ return getPredefinedCursor(DEFAULT_CURSOR);
+ }
+
+ /**
+ * Gets the specified system custom cursor.
+ *
+ * @param name the name of the desired system cursor.
+ *
+ * @return the specific system cursor with the specified name.
+ *
+ * @throws AWTException if the desired cursor has malformed data
+ * such as an incorrectly defined hot spot.
+ * @throws HeadlessException if the isHeadless method of the GraphicsEnvironment
+ * returns true.
+ */
+ public static Cursor getSystemCustomCursor(String name)
+ throws AWTException, HeadlessException {
+ Toolkit.checkHeadless();
+ return getSystemCustomCursorFromMap(name);
+ }
+
+ /**
+ * Gets the specified system custom cursor from the map of system custom cursors.
+ *
+ * @param name the name of the desired cursor.
+ *
+ * @return the desired system custom cursor from the
+ * map of system custom cursors.
+ *
+ * @throws AWTException the AWT exception
+ */
+ private static Cursor getSystemCustomCursorFromMap (String name)
+ throws AWTException {
+ loadCursorProps();
+ if (systemCustomCursors == null) {
+ systemCustomCursors = new HashMap<String, Cursor>();
+ }
+ Cursor cursor = systemCustomCursors.get(name);
+ if (cursor != null) {
+ return cursor;
+ }
+ // awt.141=failed to parse hotspot property for cursor:
+ String exMsg = Messages.getString("awt.141") + name; //$NON-NLS-1$
+ String nm = "Cursor." + name; //$NON-NLS-1$
+ String nameStr = cursorProps.getProperty(nm + ".Name"); //$NON-NLS-1$
+ String hotSpotStr = cursorProps.getProperty(nm + ".HotSpot"); //$NON-NLS-1$
+ String fileStr = cursorProps.getProperty(nm + ".File"); //$NON-NLS-1$
+ int idx = hotSpotStr.indexOf(',');
+ if (idx < 0) {
+ throw new AWTException(exMsg);
+ }
+ int x, y;
+ try {
+ x = new Integer(hotSpotStr.substring(0, idx)).intValue();
+ y = new Integer(hotSpotStr.substring(idx + 1,
+ hotSpotStr.length())).intValue();
+ } catch (NumberFormatException nfe) {
+ throw new AWTException(exMsg);
+ }
+ Image img = Toolkit.getDefaultToolkit().createImage(fileStr);
+ cursor = new Cursor(nameStr, img, new Point(x, y));
+ systemCustomCursors.put(name, cursor);
+
+ return cursor;
+ }
+
+ /**
+ * Load cursor props.
+ *
+ * @throws AWTException the AWT exception
+ */
+ private static void loadCursorProps() throws AWTException {
+ if (cursorProps != null) {
+ return;
+ }
+ String sep = File.separator;
+ String cursorsDir = "lib" + sep + "images" + sep + "cursors"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ String cursorsAbsDir = System.getProperty("java.home") + sep + //$NON-NLS-1$
+ cursorsDir;
+ String cursorPropsFileName = "cursors.properties"; //$NON-NLS-1$
+ String cursorPropsFullFileName = (cursorsAbsDir + sep +
+ cursorPropsFileName);
+ cursorProps = new Properties();
+ try {
+ cursorProps.load(new FileInputStream(new File(
+ cursorPropsFullFileName)));
+ } catch (FileNotFoundException e) {
+ // awt.142=Exception: class {0} {1} occurred while loading: {2}
+ throw new AWTException(Messages.getString("awt.142",//$NON-NLS-1$
+ new Object[]{e.getClass(), e.getMessage(), cursorPropsFullFileName}));
+ } catch (IOException e) {
+ throw new AWTException(e.getMessage());
+ }
+
+ }
+
+ /**
+ * Check type.
+ *
+ * @param type the type
+ */
+ static void checkType(int type) {
+ // can't use predefined array here because it may not have been
+ // initialized yet
+ if ((type < 0) || (type >= predefinedNames.length)) {
+ // awt.143=illegal cursor type
+ throw new IllegalArgumentException(Messages.getString("awt.143")); //$NON-NLS-1$
+ }
+ }
+
+ // "lazily" create native cursors:
+ /**
+ * Gets the native cursor.
+ *
+ * @return the native cursor
+ */
+ NativeCursor getNativeCursor() {
+ if (nativeCursor != null) {
+ return nativeCursor;
+ }
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ if (type != CUSTOM_CURSOR) {
+ nativeCursor = toolkit.createNativeCursor(type);
+ } else {
+ nativeCursor = toolkit.createCustomNativeCursor(image, hotSpot,
+ name);
+ }
+ return nativeCursor;
+ }
+
+ /**
+ * Sets the native cursor.
+ *
+ * @param nativeCursor the new native cursor
+ */
+ void setNativeCursor(NativeCursor nativeCursor) {
+ this.nativeCursor = nativeCursor;
+ }
+}
+
diff --git a/awt/java/awt/Dimension.java b/awt/java/awt/Dimension.java
new file mode 100644
index 0000000..8137846
--- /dev/null
+++ b/awt/java/awt/Dimension.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.Dimension2D;
+import java.io.Serializable;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Dimension represents the size (width and height) of a component.
+ * The width and height values can be negative, but in that case the
+ * behavior of some methods is unexpected.
+ */
+public class Dimension extends Dimension2D implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 4723952579491349524L;
+
+ /** The width dimension. */
+ public int width;
+
+ /** The height dimension. */
+ public int height;
+
+ /**
+ * Instantiates a new Dimension with the same data as the specified Dimension.
+ *
+ * @param d the Dimension to copy the data from when creating the
+ * new Dimension object.
+ */
+ public Dimension(Dimension d) {
+ this(d.width, d.height);
+ }
+
+ /**
+ * Instantiates a new Dimension with zero width and height.
+ */
+ public Dimension() {
+ this(0, 0);
+ }
+
+ /**
+ * Instantiates a new Dimension with the specified width and height.
+ *
+ * @param width the width of the new Dimension.
+ * @param height the height of the new Dimension.
+ */
+ public Dimension(int width, int height) {
+ setSize(width, height);
+ }
+
+ /**
+ * Returns the hash code of the Dimension.
+ *
+ * @return the hash code of the Dimension.
+ */
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(width);
+ hash.append(height);
+ return hash.hashCode();
+ }
+
+ /**
+ * Compares this Dimension object with the specified object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified Object is a Dimension with
+ * the same width and height data as this Dimension.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Dimension) {
+ Dimension d = (Dimension)obj;
+ return (d.width == width && d.height == height);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the String associated to this Dimension object.
+ *
+ * @return the String associated to this Dimension object.
+ */
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour. It could be obtained in the following way
+ // System.out.println(new Dimension().toString())
+ return getClass().getName() + "[width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /**
+ * Sets the size of this Dimension object with the specified width and height.
+ *
+ * @param width the width of the Dimension.
+ * @param height the height of the Dimension.
+ */
+ public void setSize(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Sets the size of this Dimension object by copying the
+ * data from the specified Dimension object.
+ *
+ * @param d the Dimension that gives the new size values.
+ */
+ public void setSize(Dimension d) {
+ setSize(d.width, d.height);
+ }
+
+ /**
+ * Sets the size of this Dimension object with the specified double width
+ * and height.
+ *
+ * @param width the width of the Dimension.
+ * @param height the height of the Dimension.
+ *
+ * @see java.awt.geom.Dimension2D#setSize(double, double)
+ */
+ @Override
+ public void setSize(double width, double height) {
+ setSize((int)Math.ceil(width), (int)Math.ceil(height));
+ }
+
+ /**
+ * Gets the size of the Dimension.
+ *
+ * @return the size of the Dimension.
+ */
+ public Dimension getSize() {
+ return new Dimension(width, height);
+ }
+
+ /**
+ * Gets the height of the Dimension.
+ *
+ * @return the height of the Dimension.
+ *
+ * @see java.awt.geom.Dimension2D#getHeight()
+ */
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the width of the Dimension.
+ *
+ * @return the width of the Dimension.
+ *
+ * @see java.awt.geom.Dimension2D#getWidth()
+ */
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+}
+
diff --git a/awt/java/awt/Dispatcher.java b/awt/java/awt/Dispatcher.java
new file mode 100644
index 0000000..d457af4
--- /dev/null
+++ b/awt/java/awt/Dispatcher.java
@@ -0,0 +1,723 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov, Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.ComponentEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.PaintEvent;
+import java.awt.event.WindowEvent;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.NativeEvent;
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+
+/**
+ * Helper package-private class for managing lightweight components &
+ * dispatching events from heavyweight source
+ */
+class Dispatcher {
+
+ //???AWT: final PopupDispatcher popupDispatcher = new PopupDispatcher();
+
+ //???AWT: final FocusDispatcher focusDispatcher;
+
+ final MouseGrabManager mouseGrabManager = new MouseGrabManager();
+
+ final MouseDispatcher mouseDispatcher;
+
+ private final ComponentDispatcher componentDispatcher = new ComponentDispatcher();
+
+ private final KeyDispatcher keyDispatcher = new KeyDispatcher();
+
+ private final Toolkit toolkit;
+
+ int clickInterval = 250;
+
+ /**
+ * @param toolkit - AWT toolkit
+ */
+ Dispatcher(Toolkit toolkit) {
+ this.toolkit = toolkit;
+
+ //???AWT: focusDispatcher = new FocusDispatcher(toolkit);
+ mouseDispatcher = new MouseDispatcher(mouseGrabManager, toolkit);
+ }
+
+ /**
+ * Dispatch native event: produce appropriate AWT events,
+ * update component's fields when needed
+ * @param event - native event to dispatch
+ * @return - true means default processing by OS is not needed
+ */
+ public boolean onEvent(NativeEvent event) {
+ int eventId = event.getEventId();
+
+ if (eventId == NativeEvent.ID_CREATED) {
+ return toolkit.onWindowCreated(event.getWindowId());
+ } else if (eventId == NativeEvent.ID_MOUSE_GRAB_CANCELED) {
+ return mouseGrabManager.onGrabCanceled();
+ //???AWT
+// } else if (popupDispatcher.onEvent(event)) {
+// return false;
+ } else {
+ Component src = toolkit.getComponentById(event.getWindowId());
+
+ if (src != null) {
+ if (((eventId >= ComponentEvent.COMPONENT_FIRST) && (eventId <= ComponentEvent.COMPONENT_LAST))
+ || ((eventId >= WindowEvent.WINDOW_FIRST) && (eventId <= WindowEvent.WINDOW_LAST))
+ || (eventId == NativeEvent.ID_INSETS_CHANGED)
+ || (eventId == NativeEvent.ID_BOUNDS_CHANGED)
+ || (eventId == NativeEvent.ID_THEME_CHANGED)) {
+ return componentDispatcher.dispatch(src, event);
+ } else if ((eventId >= MouseEvent.MOUSE_FIRST)
+ && (eventId <= MouseEvent.MOUSE_LAST)) {
+ return mouseDispatcher.dispatch(src, event);
+ } else if (eventId == PaintEvent.PAINT) {
+ //???AWT: src.redrawManager.addPaintRegion(src, event.getClipRects());
+ return true;
+ }
+ }
+ if ((eventId >= FocusEvent.FOCUS_FIRST)
+ && (eventId <= FocusEvent.FOCUS_LAST)) {
+
+ //???AWT: return focusDispatcher.dispatch(src, event);
+ return false;
+ } else if ((eventId >= KeyEvent.KEY_FIRST)
+ && (eventId <= KeyEvent.KEY_LAST)) {
+ return keyDispatcher.dispatch(src, event);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * The dispatcher of native events that affect
+ * component's state or bounds
+ */
+ final class ComponentDispatcher {
+
+ /**
+ * Handle native event that affects component's state or bounds
+ * @param src - the component updated by the event
+ * @param event - the native event
+ * @return - as in Dispatcher.onEvent()
+ * @see Dispatcher#onEvent(NativeEvent)
+ */
+ boolean dispatch(Component src, NativeEvent event) {
+ int id = event.getEventId();
+
+ if ((id == NativeEvent.ID_INSETS_CHANGED)
+ || (id == NativeEvent.ID_THEME_CHANGED)) {
+ return dispatchInsets(event, src);
+ } else if ((id >= WindowEvent.WINDOW_FIRST)
+ && (id <= WindowEvent.WINDOW_LAST)) {
+ return dispatchWindow(event, src);
+ } else {
+ return dispatchPureComponent(event, src);
+ }
+ }
+
+ /**
+ * Handle the change of top-level window's native decorations
+ * @param event - the native event
+ * @param src - the component updated by the event
+ * @return - as in Dispatcher.onEvent()
+ * @see Dispatcher#onEvent(NativeEvent)
+ */
+ boolean dispatchInsets(NativeEvent event, Component src) {
+ //???AWT
+ /*
+ if (src instanceof Window) {
+ ((Window) src).setNativeInsets(event.getInsets());
+ }
+ */
+ return false;
+ }
+
+ /**
+ * Handle the change of top-level window's state
+ * @param event - the native event
+ * @param src - the component updated by the event
+ * @return - as in Dispatcher.onEvent()
+ * @see Dispatcher#onEvent(NativeEvent)
+ */
+ boolean dispatchWindow(NativeEvent event, Component src) {
+ //???AWT
+ /*
+ Window window = (Window) src;
+ int id = event.getEventId();
+
+ if (id == WindowEvent.WINDOW_CLOSING) {
+ toolkit.getSystemEventQueueImpl().postEvent(
+ new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
+
+ return true;
+ } else if (id == WindowEvent.WINDOW_STATE_CHANGED) {
+ if (window instanceof Frame) {
+ ((Frame) window)
+ .updateExtendedState(event.getWindowState());
+ }
+ }
+ */
+
+ return false;
+ }
+
+ /**
+ * Handle the change of component's size and/or position
+ * @param event - the native event
+ * @param src - the component updated by the event
+ * @return - as in Dispatcher.onEvent()
+ * @see Dispatcher#onEvent(NativeEvent)
+ */
+ private boolean dispatchPureComponent(NativeEvent event, Component src) {
+ Rectangle rect = event.getWindowRect();
+ Point loc = rect.getLocation();
+ int mask;
+
+ switch (event.getEventId()) {
+ case NativeEvent.ID_BOUNDS_CHANGED:
+ mask = 0;
+ break;
+ case ComponentEvent.COMPONENT_MOVED:
+ mask = NativeWindow.BOUNDS_NOSIZE;
+ break;
+ case ComponentEvent.COMPONENT_RESIZED:
+ mask = NativeWindow.BOUNDS_NOMOVE;
+ break;
+ default:
+ // awt.12E=Unknown component event id.
+ throw new RuntimeException(Messages.getString("awt.12E")); //$NON-NLS-1$
+ }
+
+ //???AWT
+ /*
+ if (!(src instanceof Window)) {
+ Component compTo = src.getParent();
+ Component compFrom = src.getHWAncestor();
+
+ if ((compTo != null) && (compFrom != null)) {
+ loc = MouseDispatcher.convertPoint(compFrom, loc, compTo);
+ }
+ } else {
+ int windowState = event.getWindowState();
+
+ if ((windowState >= 0) && (src instanceof Frame)) {
+ ((Frame) src).updateExtendedState(windowState);
+ }
+ }
+ src.setBounds(loc.x, loc.y, rect.width, rect.height, mask, false);
+ */
+
+ return false;
+ }
+
+ }
+
+ /**
+ * The dispatcher of the keyboard events
+ */
+ final class KeyDispatcher {
+
+ /**
+ * Handle the keyboard event using the KeyboardFocusManager
+ * @param src - the component receiving the event
+ * @param event - the native event
+ * @return - as in Dispatcher.onEvent()
+ * @see Dispatcher#onEvent(NativeEvent)
+ */
+ boolean dispatch(Component src, NativeEvent event) {
+ int id = event.getEventId();
+ int modifiers = event.getInputModifiers();
+ int location = event.getKeyLocation();
+ int code = event.getVKey();
+ StringBuffer chars = event.getKeyChars();
+ int charsLength = chars.length();
+ long time = event.getTime();
+ char keyChar = event.getLastChar();
+
+ //???AWT
+ /*
+ if (src == null) {
+ //retarget focus proxy key events to focusOwner:
+ Window focusProxyOwner = toolkit.getFocusProxyOwnerById(event
+ .getWindowId());
+ if (focusProxyOwner == null) {
+ return false;
+ }
+ src = KeyboardFocusManager.actualFocusOwner;
+ }
+ */
+
+ EventQueue eventQueue = toolkit.getSystemEventQueueImpl();
+
+ if (src != null) {
+ eventQueue.postEvent(new KeyEvent(src, id, time, modifiers,
+ code, keyChar, location));
+ // KEY_TYPED goes after KEY_PRESSED
+ if (id == KeyEvent.KEY_PRESSED) {
+ for (int i = 0; i < charsLength; i++) {
+ keyChar = chars.charAt(i);
+ if (keyChar != KeyEvent.CHAR_UNDEFINED) {
+ eventQueue.postEvent(new KeyEvent(src,
+ KeyEvent.KEY_TYPED, time, modifiers,
+ KeyEvent.VK_UNDEFINED, keyChar,
+ KeyEvent.KEY_LOCATION_UNKNOWN));
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ }
+
+ /**
+ * Retargets the mouse events to the grab owner when mouse is grabbed,
+ * grab and ungrab mouse when mouse buttons are pressed and released
+ */
+
+ static final class MouseGrabManager {
+
+ /**
+ * The top-level window holding the mouse grab
+ * that was explicitly started by startGrab() method
+ */
+ //???AWT: private Window nativeGrabOwner = null;
+ /**
+ * The component that owns the synthetic
+ * mouse grab while at least one of the
+ * mouse buttons is pressed
+ */
+ private Component syntheticGrabOwner = null;
+
+ /**
+ * Previous value of syntheticGrabOwner
+ */
+ private Component lastSyntheticGrabOwner = null;
+
+ /**
+ * Number of mouse buttons currently pressed
+ */
+ private int syntheticGrabDepth = 0;
+
+ /**
+ * The callback to be called when the explicit mouse grab ends
+ */
+ private Runnable whenCanceled;
+
+ /**
+ * Explicitly start the mouse grab
+ * @param grabWindow - the window that will own the grab
+ * @param whenCanceled - the callback to call when the grab ends.
+ * This parameter can be null
+ */
+ //???AWT
+ /*
+ void startGrab(Window grabWindow, Runnable whenCanceled) {
+
+ if (nativeGrabOwner != null) {
+ // awt.12F=Attempt to start nested mouse grab
+ throw new RuntimeException(Messages.getString("awt.12F")); //$NON-NLS-1$
+ }
+
+ NativeWindow win = grabWindow.getNativeWindow();
+ if (win == null) {
+ // awt.130=Attempt to grab mouse in not displayable window
+ throw new RuntimeException(Messages.getString("awt.130")); //$NON-NLS-1$
+ }
+
+ nativeGrabOwner = grabWindow;
+ this.whenCanceled = whenCanceled;
+ win.grabMouse();
+ }
+ */
+
+ /**
+ * Ends the explicit mouse grab. If the non-null callback was provided
+ * in the startGrab() method, this callback is called
+ */
+ void endGrab() {
+ //???AWT
+ /*
+ if (nativeGrabOwner == null) {
+ return;
+ }
+
+ Window grabWindow = nativeGrabOwner;
+ nativeGrabOwner = null;
+ NativeWindow win = grabWindow.getNativeWindow();
+
+ if (win != null) {
+ win.ungrabMouse();
+ if (whenCanceled != null) {
+ whenCanceled.run();
+ whenCanceled = null;
+ }
+ }
+ */
+ }
+
+ /**
+ * Ends both explicit and synthetic grans
+ * @return - always returns false
+ */
+ boolean onGrabCanceled() {
+ endGrab();
+ resetSyntheticGrab();
+
+ return false;
+ }
+
+ /**
+ * Starts the synthetic mouse grab, increases the counter
+ * of currently pressed mouse buttons
+ * @param source - the component where mouse press event occured
+ * @return - the component that owns the synthetic grab
+ */
+ Component onMousePressed(Component source) {
+ if (syntheticGrabDepth == 0) {
+ syntheticGrabOwner = source;
+ lastSyntheticGrabOwner = source;
+ }
+ syntheticGrabDepth++;
+
+ return syntheticGrabOwner;
+ }
+
+ /**
+ * Decreases the counter of currently pressed mouse buttons,
+ * ends the synthetic mouse grab, when this counter becomes zero
+ * @param source - the component where mouse press event occured
+ * @return - the component that owns the synthetic grab,
+ * or source parameter if mouse grab was released
+ */
+ Component onMouseReleased(Component source) {
+ Component ret = source;
+
+ //???AWT
+ /*
+ if (syntheticGrabOwner != null && nativeGrabOwner == null) {
+ ret = syntheticGrabOwner;
+ }
+ */
+ syntheticGrabDepth--;
+ if (syntheticGrabDepth <= 0) {
+ resetSyntheticGrab();
+ lastSyntheticGrabOwner = null;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Update the state of synthetic ouse gram
+ * when the mouse is moved/dragged
+ * @param event - the native event
+ */
+ void preprocessEvent(NativeEvent event) {
+ int id = event.getEventId();
+ switch (id) {
+ case MouseEvent.MOUSE_MOVED:
+ if (syntheticGrabOwner != null) {
+ syntheticGrabOwner = null;
+ syntheticGrabDepth = 0;
+ }
+ if (lastSyntheticGrabOwner != null) {
+ lastSyntheticGrabOwner = null;
+ }
+ case MouseEvent.MOUSE_DRAGGED:
+ if (syntheticGrabOwner == null
+ && lastSyntheticGrabOwner != null) {
+ syntheticGrabOwner = lastSyntheticGrabOwner;
+ syntheticGrabDepth = 0;
+ int mask = event.getInputModifiers();
+ syntheticGrabDepth += (mask & InputEvent.BUTTON1_DOWN_MASK) != 0 ? 1
+ : 0;
+ syntheticGrabDepth += (mask & InputEvent.BUTTON2_DOWN_MASK) != 0 ? 1
+ : 0;
+ syntheticGrabDepth += (mask & InputEvent.BUTTON3_DOWN_MASK) != 0 ? 1
+ : 0;
+ }
+ }
+ }
+
+ /**
+ * @return the component that currently owns the synthetic grab
+ */
+ Component getSyntheticGrabOwner() {
+ return syntheticGrabOwner;
+ }
+
+ /**
+ * ends synthetic grab
+ */
+ private void resetSyntheticGrab() {
+ syntheticGrabOwner = null;
+ syntheticGrabDepth = 0;
+ }
+
+ }
+
+ /**
+ * Dispatches native events related to the pop-up boxes
+ * (the non-component windows such as menus and drop lists)
+ */
+// final class PopupDispatcher {
+//
+// private PopupBox activePopup;
+//
+// private PopupBox underCursor;
+//
+// private final MouseGrab grab = new MouseGrab();
+//
+// /**
+// * Handles the mouse grab for pop-up boxes
+// */
+// private final class MouseGrab {
+// private int depth;
+//
+// private PopupBox owner;
+//
+// private final Point start = new Point();
+//
+// /**
+// * Starts the grab when mouse is pressed
+// * @param src - the pop-up box where mouse event has occured
+// * @param where - the mouse pointer location
+// * @return - the grab owner
+// */
+// PopupBox mousePressed(PopupBox src, Point where) {
+// if (depth == 0) {
+// owner = src;
+// start.setLocation(where);
+// }
+// depth++;
+// return owner;
+// }
+//
+// /**
+// * Ends the grab when all mousebuttons are released
+// * @param src - the pop-up box where mouse event has occured
+// * @param where - the mouse pointer location
+// * @return - the grab owner, or src parameter if the grab has ended
+// */
+// PopupBox mouseReleased(PopupBox src, Point where) {
+// PopupBox ret = (owner != null) ? owner : src;
+// if (depth == 0) {
+// return ret;
+// }
+// depth--;
+// if (depth == 0) {
+// PopupBox tgt = owner;
+// owner = null;
+// if (tgt != null && src == null) {
+// Point a = new Point(start);
+// Point b = new Point(where);
+// Point pos = tgt.getScreenLocation();
+// a.translate(-pos.x, -pos.y);
+// b.translate(-pos.x, -pos.y);
+// if (tgt.closeOnUngrab(a, b)) {
+// return null;
+// }
+// }
+// }
+// return ret;
+// }
+//
+// /**
+// * Set the grab owner to null
+// */
+// void reset() {
+// depth = 0;
+// owner = null;
+// start.setLocation(0, 0);
+// }
+//
+// /**
+// * @return - the pop-up box currently owning the grab
+// */
+// public PopupBox getOwner() {
+// return owner;
+// }
+// }
+//
+// /**
+// * Call the mouse event handler of the pop-up box
+// * @param src - the pop-up box where the mouse event occured
+// * @param eventId - the event ID, one of MouseEvent.MOUSE_* constants
+// * @param where - the mouse pointer location
+// * @param event - native event
+// */
+// private void mouseEvent(PopupBox src, int eventId, Point where,
+// NativeEvent event) {
+// Point pos = src.getScreenLocation();
+// pos.setLocation(where.x - pos.x, where.y - pos.y);
+//
+// src.onMouseEvent(eventId, pos, event.getMouseButton(), event
+// .getTime(), event.getInputModifiers(), event
+// .getWheelRotation());
+// }
+//
+// /**
+// * Handle the native event targeted by a pop-up box. This could be
+// * paint event, mouse or keyboard event.
+// * @param event - the native event
+// * @return - false if the event was handled and doesn't
+// * need the further processing; true when the further
+// * processing is needed
+// */
+// boolean onEvent(NativeEvent event) {
+// PopupBox src = toolkit.getPopupBoxById(event.getWindowId());
+// int id = event.getEventId();
+//
+// if ((id == PaintEvent.PAINT)) {
+// if (src != null) {
+// src.paint(event.getClipRects());
+// return true;
+// }
+// Component c = toolkit.getComponentById(event.getWindowId());
+// if ((c != null) && (c instanceof Frame)) {
+// ((Frame) c).paintMenuBar(event.getClipRects());
+// }
+// return false;
+// }
+//
+// if ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST)) {
+// Point where = event.getScreenPos();
+//
+// if (src != underCursor) {
+// if (underCursor != null) {
+// mouseEvent(underCursor, MouseEvent.MOUSE_EXITED, where,
+// event);
+// }
+// underCursor = src;
+// if (underCursor != null) {
+// mouseEvent(underCursor, MouseEvent.MOUSE_ENTERED,
+// where, event);
+// underCursor.setDefaultCursor();
+// }
+// }
+// if (id == MouseEvent.MOUSE_EXITED) {
+// underCursor = null;
+// }
+//
+// if ((activePopup == null) && (src == null || !src.isMenuBar())) {
+// return false;
+// }
+//
+// if (id == MouseEvent.MOUSE_PRESSED) {
+// src = grab.mousePressed(src, where);
+// } else if (id == MouseEvent.MOUSE_RELEASED) {
+// src = grab.mouseReleased(src, where);
+// } else if (src == null) {
+// src = grab.getOwner();
+// }
+//
+// PopupBox wasActive = activePopup;
+//
+// if (src != null) {
+// mouseEvent(src, id, where, event);
+// return src.isMenu() || src.contains(where);
+// }
+//
+// if (wasActive != null && activePopup == null) {
+// return wasActive.isMenu();
+// }
+//
+// if ((id == MouseEvent.MOUSE_PRESSED)
+// || (id == MouseEvent.MOUSE_RELEASED)) {
+// boolean isMenu = activePopup.isMenu();
+// deactivateAll();
+// return !isMenu;
+// }
+// return true;
+// }
+//
+// if (activePopup == null) {
+// return false;
+// }
+//
+// if ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST)) {
+// boolean isMenu = activePopup.isMenu();
+// activePopup.dispatchKeyEvent(id, event.getVKey(), event
+// .getTime(), event.getInputModifiers());
+//
+// return isMenu;
+// }
+//
+// return false;
+// }
+//
+// /**
+// * Remember the pop-up as active and grab the mouse on it
+// * @param popup - the pop-up box to activate
+// */
+// void activate(final PopupBox popup) {
+// if (activePopup == null) {
+//
+// activePopup = popup;
+// mouseGrabManager.startGrab(popup.getOwner(), new Runnable() {
+// public void run() {
+// deactivate(popup);
+// }
+// });
+// }
+// }
+//
+// /**
+// * Deactivate the currently active pop-up box
+// */
+// void deactivateAll() {
+// deactivate(activePopup);
+// }
+//
+// /**
+// * Deactivate the pop-up box, end the mouse grab
+// */
+// void deactivate(PopupBox popup) {
+// grab.reset();
+//
+// if (activePopup != null && activePopup == popup) {
+// activePopup = null;
+// mouseGrabManager.endGrab();
+// popup.hide();
+// underCursor = null;
+// }
+// }
+//
+// /**
+// * Check that the pop-up box is currently active
+// * @param popup - the pop-up box to check
+// * @return - true if active
+// */
+// boolean isActive(PopupBox popup) {
+// return (popup == activePopup) && (popup != null);
+// }
+// }
+
+} \ No newline at end of file
diff --git a/awt/java/awt/DisplayMode.java b/awt/java/awt/DisplayMode.java
new file mode 100644
index 0000000..082c7b8
--- /dev/null
+++ b/awt/java/awt/DisplayMode.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The DisplayMode class containes the bit depth, height, width and
+ * refresh rate of a GraphicsDevice.
+ */
+public final class DisplayMode {
+
+ /** The width. */
+ private final int width;
+
+ /** The height. */
+ private final int height;
+
+ /** The bit depth. */
+ private final int bitDepth;
+
+ /** The refresh rate. */
+ private final int refreshRate;
+
+ /** The Constant Value BIT_DEPTH_MULTI indicates the bit depth */
+
+ public static final int BIT_DEPTH_MULTI = -1;
+
+ /** The Constant REFRESH_RATE_UNKNOWN indicates the refresh rate. */
+ public static final int REFRESH_RATE_UNKNOWN = 0;
+
+ /**
+ * Creates a new DisplayMode object with the specified parameters.
+ *
+ * @param width the width of the display.
+ * @param height the height of the display.
+ * @param bitDepth the bit depth of the display.
+ * @param refreshRate the refresh rate of the display.
+ */
+
+ public DisplayMode(int width, int height, int bitDepth, int refreshRate) {
+ this.width = width;
+ this.height = height;
+ this.bitDepth = bitDepth;
+ this.refreshRate = refreshRate;
+ }
+
+
+ /**
+ * Compares if this DisplayMode is equal to the specified object or not.
+ *
+ * @param dm the Object to be compared.
+ *
+ * @return true, if the specified object is a DisplayMode with the same
+ * data values as this DisplayMode, false otherwise.
+ */
+
+ @Override
+ public boolean equals(Object dm) {
+ if (dm instanceof DisplayMode) {
+ return equals((DisplayMode)dm);
+ }
+ return false;
+ }
+
+ /**
+ * Compares if this DisplayMode is equal to the specified DisplayMode object
+ * or not.
+ *
+ * @param dm the DisplayMode to be compared.
+ *
+ * @return true, if all of the data values of this DisplayMode are equal
+ * to the values of the specified DisplayMode object, false otherwise.
+ */
+ public boolean equals(DisplayMode dm) {
+ if (dm == null) {
+ return false;
+ }
+ if (dm.bitDepth != bitDepth) {
+ return false;
+ }
+ if (dm.refreshRate != refreshRate) {
+ return false;
+ }
+ if (dm.width != width) {
+ return false;
+ }
+ if (dm.height != height) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Gets the bit depth of the DisplayMode, returns BIT_DEPTH_MULTI value
+ * if multiple bit depths are supported in this display mode.
+ *
+ * @return the bit depth of the DisplayMode.
+ */
+ public int getBitDepth() {
+ return bitDepth;
+ }
+
+ /**
+ * Gets the height of the DisplayMode.
+ *
+ * @return the height of the DisplayMode.
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the refresh rate of the DisplayMode, returns REFRESH_RATE_UNKNOWN
+ * value if the information is not available.
+ *
+ * @return the refresh rate of the DisplayMode.
+ */
+ public int getRefreshRate() {
+ return refreshRate;
+ }
+
+ /**
+ * Gets the width of the DisplayMode.
+ *
+ * @return the width of the DisplayMode.
+ */
+ public int getWidth() {
+ return width;
+ }
+}
diff --git a/awt/java/awt/Event.java b/awt/java/awt/Event.java
new file mode 100644
index 0000000..f074258
--- /dev/null
+++ b/awt/java/awt/Event.java
@@ -0,0 +1,479 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.io.Serializable;
+
+/**
+ * The Event Class is obsolete and has been replaced by AWTEvent class.
+ *
+ */
+public class Event implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 5488922509400504703L;
+
+ /**
+ * The Constant SHIFT_MASK indicates that the Shift key is down when
+ * the event occurred.
+ */
+ public static final int SHIFT_MASK = 1;
+
+ /**
+ * The Constant CTRL_MASK indicates that the Control key is down when
+ * the event occurred.
+ */
+ public static final int CTRL_MASK = 2;
+
+ /** The Constant META_MASK indicates that the Meta key is down when t
+ * he event occurred (or the right mouse button). */
+ public static final int META_MASK = 4;
+
+ /**
+ * The Constant ALT_MASK indicates that the Alt key is down when
+ * the event occurred (or the middle mouse button).
+ */
+ public static final int ALT_MASK = 8;
+
+ /** The Constant HOME indicates Home key. */
+ public static final int HOME = 1000;
+
+ /** The Constant END indicates End key. */
+ public static final int END = 1001;
+
+ /** The Constant PGUP indicates Page Up key. */
+ public static final int PGUP = 1002;
+
+ /** The Constant PGDN indicates Page Down key. */
+ public static final int PGDN = 1003;
+
+ /** The Constant UP indicates Up key. */
+ public static final int UP = 1004;
+
+ /** The Constant DOWN indicates Down key. */
+ public static final int DOWN = 1005;
+
+ /** The Constant LEFT indicates Left key. */
+ public static final int LEFT = 1006;
+
+ /** The Constant RIGHT indicates Right key. */
+ public static final int RIGHT = 1007;
+
+ /** The Constant F1 indicates F1 key. */
+ public static final int F1 = 1008;
+
+ /** The Constant F2 indicates F2 key. */
+ public static final int F2 = 1009;
+
+ /** The Constant F3 indicates F3 key. */
+ public static final int F3 = 1010;
+
+ /** The Constant F4 indicates F4 key. */
+ public static final int F4 = 1011;
+
+ /** The Constant F5 indicates F5 key. */
+ public static final int F5 = 1012;
+
+ /** The Constant F6 indicates F6 key. */
+ public static final int F6 = 1013;
+
+ /** The Constant F7 indicates F7 key. */
+ public static final int F7 = 1014;
+
+ /** The Constant F8 indicates F8 key. */
+ public static final int F8 = 1015;
+
+ /** The Constant F9 indicates F9 key. */
+ public static final int F9 = 1016;
+
+ /** The Constant F10 indicates F10 key. */
+ public static final int F10 = 1017;
+
+ /** The Constant F11 indicates F11 key. */
+ public static final int F11 = 1018;
+
+ /** The Constant F12 indicates F12 key. */
+ public static final int F12 = 1019;
+
+ /** The Constant PRINT_SCREEN indicates Print Screen key. */
+ public static final int PRINT_SCREEN = 1020;
+
+ /** The Constant SCROLL_LOCK indicates Scroll Lock key. */
+ public static final int SCROLL_LOCK = 1021;
+
+ /** The Constant CAPS_LOCK indicates Caps Lock key. */
+ public static final int CAPS_LOCK = 1022;
+
+ /** The Constant NUM_LOCK indicates Num Lock key. */
+ public static final int NUM_LOCK = 1023;
+
+ /** The Constant PAUSE indicates Pause key. */
+ public static final int PAUSE = 1024;
+
+ /** The Constant INSERT indicates Insert key. */
+ public static final int INSERT = 1025;
+
+ /** The Constant ENTER indicates Enter key. */
+ public static final int ENTER = 10;
+
+ /** The Constant BACK_SPACE indicates Back Space key. */
+ public static final int BACK_SPACE = 8;
+
+ /** The Constant TAB indicates TAb key. */
+ public static final int TAB = 9;
+
+ /** The Constant ESCAPE indicates Escape key. */
+ public static final int ESCAPE = 27;
+
+ /** The Constant DELETE indicates Delete key. */
+ public static final int DELETE = 127;
+
+ /**
+ * The Constant WINDOW_DESTROY indicates an event when the user has asked the
+ * window manager to kill the window.
+ */
+ public static final int WINDOW_DESTROY = 201;
+
+ /**
+ * The Constant WINDOW_EXPOSE indicates an event when the user has asked the
+ * window manager to expose the window.
+ */
+ public static final int WINDOW_EXPOSE = 202;
+
+ /**
+ * The Constant WINDOW_ICONIFY indicates an event when the user has asked the
+ * window manager to inconify the window.
+ */
+ public static final int WINDOW_ICONIFY = 203;
+
+ /**
+ * The Constant WINDOW_DEICONIFY indicates an event when the user has asked the
+ * window manager to deinconify the window.
+ */
+ public static final int WINDOW_DEICONIFY = 204;
+
+ /**
+ * The Constant WINDOW_MOVED indicates an event when the user has asked the
+ * window manager to move the window.
+ */
+ public static final int WINDOW_MOVED = 205;
+
+ /**
+ * The Constant KEY_PRESS indicates an event when the user presses
+ * a normal key.
+ */
+ public static final int KEY_PRESS = 401;
+
+ /**
+ * The Constant KEY_RELEASE indicates an event when the user releases
+ * a normal key.
+ */
+ public static final int KEY_RELEASE = 402;
+
+ /**
+ * The Constant KEY_ACTION indicates an event when the user pressed
+ * a non-ASCII action key.
+ */
+ public static final int KEY_ACTION = 403;
+
+ /**
+ * The Constant KEY_ACTION_RELEASE indicates an event when the user released
+ * a non-ASCII action key.
+ */
+ public static final int KEY_ACTION_RELEASE = 404;
+
+ /**
+ * The Constant MOUSE_DOWN indicates an event when the user has pressed
+ * the mouse button.
+ */
+ public static final int MOUSE_DOWN = 501;
+
+ /**
+ * The Constant MOUSE_UP indicates an event when the user has released
+ * the mouse button.
+ */
+ public static final int MOUSE_UP = 502;
+
+ /**
+ * The Constant MOUSE_MOVE indicates an event when the user has moved
+ * the mouse with no button pressed.
+ */
+ public static final int MOUSE_MOVE = 503;
+
+ /**
+ * The Constant MOUSE_ENTER indicates an event when the mouse
+ * has entered a component.
+ */
+ public static final int MOUSE_ENTER = 504;
+
+ /**
+ * The Constant MOUSE_EXIT indicates an event when the mouse
+ * has exited a component.
+ */
+ public static final int MOUSE_EXIT = 505;
+
+ /** The Constant MOUSE_DRAG indicates an event when the user
+ * has moved a mouse with the pressed button.
+ */
+ public static final int MOUSE_DRAG = 506;
+
+ /**
+ * The Constant SCROLL_LINE_UP indicates an event when the user has
+ * activated line-up area of scrollbar.
+ */
+ public static final int SCROLL_LINE_UP = 601;
+
+ /**
+ * The Constant SCROLL_LINE_DOWN indicates an event when the user has
+ * activated line-down area of scrollbar.
+ */
+ public static final int SCROLL_LINE_DOWN = 602;
+
+ /**
+ * The Constant SCROLL_PAGE_UP indicates an event when the user has
+ * activated page up area of scrollbar.
+ */
+ public static final int SCROLL_PAGE_UP = 603;
+
+ /**
+ * The Constant SCROLL_PAGE_DOWN indicates an event when the user has
+ * activated page down area of scrollbar.
+ */
+ public static final int SCROLL_PAGE_DOWN = 604;
+
+ /**
+ * The Constant SCROLL_ABSOLUTE indicates an event when the user
+ * has moved the bubble in a scroll bar.
+ */
+ public static final int SCROLL_ABSOLUTE = 605;
+
+ /** The Constant SCROLL_BEGIN indicates a scroll begin event. */
+ public static final int SCROLL_BEGIN = 606;
+
+ /** The Constant SCROLL_END indicates a scroll end event. */
+ public static final int SCROLL_END = 607;
+
+ /**
+ * The Constant LIST_SELECT indicates that an item in a list
+ * has been selected.
+ */
+ public static final int LIST_SELECT = 701;
+
+ /**
+ * The Constant LIST_DESELECT indicates that an item in a list
+ * has been deselected.
+ */
+ public static final int LIST_DESELECT = 702;
+
+ /**
+ * The Constant ACTION_EVENT indicates that the user wants some
+ * action to occur.
+ */
+ public static final int ACTION_EVENT = 1001;
+
+ /** The Constant LOAD_FILE indicates a file loading event. */
+ public static final int LOAD_FILE = 1002;
+
+ /** The Constant SAVE_FILE indicates a file saving event. */
+ public static final int SAVE_FILE = 1003;
+
+ /** The Constant GOT_FOCUS indicates that a component got the focus. */
+ public static final int GOT_FOCUS = 1004;
+
+ /** The Constant LOST_FOCUS indicates that the component lost the focus. */
+ public static final int LOST_FOCUS = 1005;
+
+ /** The target is the component with which the event is associated. */
+ public Object target;
+
+ /** The when is timestamp when event has occured. */
+ public long when;
+
+ /** The id indicates the type of the event. */
+ public int id;
+
+ /** The x coordinate of event. */
+ public int x;
+
+ /** The y coordinate of event. */
+ public int y;
+
+ /** The key code of key event. */
+ public int key;
+
+ /** The state of the modifier keys (given by a bitmask). */
+ public int modifiers;
+
+ /** The click count indicates the number of consecutive clicks. */
+ public int clickCount;
+
+ /** The argument of the event. */
+ public Object arg;
+
+ /** The next event. */
+ public Event evt;
+
+ /**
+ * Instantiates a new event with the specified target component,
+ * event type, and argument.
+ *
+ * @param target the target component.
+ * @param id the event type.
+ * @param arg the argument.
+ */
+ public Event(Object target, int id, Object arg) {
+ this(target, 0l, id, 0, 0, 0, 0, arg);
+ }
+
+ /**
+ * Instantiates a new event with the specified target component, time stamp,
+ * event type, x and y coordinates, keyboard key, state of the modifier
+ * keys, and an argument set to null.
+ *
+ * @param target the target component.
+ * @param when the time stamp.
+ * @param id the event type.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ * @param key the key.
+ * @param modifiers the modifier keys state.
+ */
+ public Event(Object target, long when, int id, int x, int y, int key, int modifiers) {
+ this(target, when, id, x, y, key, modifiers, null);
+ }
+
+ /**
+ * Instantiates a new event with the specified target component, time stamp,
+ * event type, x and y coordinates, keyboard key, state of the modifier
+ * keys, and an argument.
+ *
+ * @param target the target component.
+ * @param when the time stamp.
+ * @param id the event type.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ * @param key the key.
+ * @param modifiers the modifier keys state.
+ * @param arg the specified argument.
+ */
+ public Event(Object target, long when, int id, int x, int y, int key, int modifiers, Object arg) {
+ this.target = target;
+ this.when = when;
+ this.id = id;
+ this.x = x;
+ this.y = y;
+ this.key = key;
+ this.modifiers = modifiers;
+ this.arg = arg;
+ }
+
+ /**
+ * Returns a string representation of this Event.
+ *
+ * @return a string representation of this Event.
+ */
+ @Override
+ public String toString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * Event e = new Event(new Button(), 0l, Event.KEY_PRESS,
+ * 0, 0, Event.TAB, Event.SHIFT_MASK, "arg");
+ * System.out.println(e);
+ */
+
+ return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Returns a string representing the state of this Event.
+ *
+ * @return a string representing the state of this Event.
+ */
+ protected String paramString() {
+ return "id=" + id + ",x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ (key != 0 ? ",key=" + key + getModifiersString() : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ ",target=" + target + //$NON-NLS-1$
+ (arg != null ? ",arg=" + arg : ""); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Gets a string representation of the modifiers.
+ *
+ * @return a string representation of the modifiers
+ */
+ private String getModifiersString() {
+ String strMod = ""; //$NON-NLS-1$
+ if (shiftDown()) {
+ strMod += ",shift"; //$NON-NLS-1$
+ }
+ if (controlDown()) {
+ strMod += ",control"; //$NON-NLS-1$
+ }
+ if (metaDown()) {
+ strMod += ",meta"; //$NON-NLS-1$
+ }
+ return strMod;
+ }
+
+ /**
+ * Translates x and y coordinates of his event to the x+dx and x+dy
+ * coordinates.
+ *
+ * @param dx the dx - the distance by which the event's x coordinate
+ * is increased
+ * @param dy the dy - the distance by which the event's y coordinate
+ * is increased
+ */
+ public void translate(int dx, int dy) {
+ x += dx;
+ y += dy;
+ }
+
+ /**
+ * Checks if Control key is down or not.
+ *
+ * @return true, if Control key is down; false otherwise.
+ */
+ public boolean controlDown() {
+ return (modifiers & CTRL_MASK) != 0;
+ }
+
+ /**
+ * Checks if Meta key is down or not.
+ *
+ * @return true, if Meta key is down; false otherwise.
+ */
+ public boolean metaDown() {
+ return (modifiers & META_MASK) != 0;
+ }
+
+ /**
+ * Checks if Shift key is down or not.
+ *
+ * @return true, if Shift key is down; false otherwise.
+ */
+ public boolean shiftDown() {
+ return (modifiers & SHIFT_MASK) != 0;
+ }
+
+}
+
diff --git a/awt/java/awt/EventDispatchThread.java b/awt/java/awt/EventDispatchThread.java
new file mode 100644
index 0000000..442c8a2
--- /dev/null
+++ b/awt/java/awt/EventDispatchThread.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import org.apache.harmony.awt.wtk.NativeEvent;
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+
+class EventDispatchThread extends Thread {
+
+ private static final class MarkerEvent extends AWTEvent {
+ MarkerEvent(Object source, int id) {
+ super(source, id);
+ }
+ }
+
+ final Dispatcher dispatcher;
+ final Toolkit toolkit;
+ private NativeEventQueue nativeQueue;
+
+ protected volatile boolean shutdownPending = false;
+
+ /**
+ * Initialise and run the main event loop
+ */
+ @Override
+ public void run() {
+ nativeQueue = toolkit.getNativeEventQueue();
+
+ try {
+ runModalLoop(null);
+ } finally {
+ toolkit.shutdownWatchdog.forceShutdown();
+ }
+ }
+
+ void runModalLoop(ModalContext context) {
+ long lastPaintTime = System.currentTimeMillis();
+ while (!shutdownPending && (context == null || context.isModalLoopRunning())) {
+ try {
+ EventQueue eventQueue = toolkit.getSystemEventQueueImpl();
+
+ NativeEvent ne = nativeQueue.getNextEvent();
+ if (ne != null) {
+ dispatcher.onEvent(ne);
+ MarkerEvent marker = new MarkerEvent(this, 0);
+ eventQueue.postEvent(marker);
+ for (AWTEvent ae = eventQueue.getNextEventNoWait();
+ (ae != null) && (ae != marker);
+ ae = eventQueue.getNextEventNoWait()) {
+ eventQueue.dispatchEvent(ae);
+ }
+ } else {
+ toolkit.shutdownWatchdog.setNativeQueueEmpty(true);
+ AWTEvent ae = eventQueue.getNextEventNoWait();
+ if (ae != null) {
+ eventQueue.dispatchEvent(ae);
+ long curTime = System.currentTimeMillis();
+ if (curTime - lastPaintTime > 10) {
+ toolkit.onQueueEmpty();
+ lastPaintTime = System.currentTimeMillis();
+ }
+ } else {
+ toolkit.shutdownWatchdog.setAwtQueueEmpty(true);
+ toolkit.onQueueEmpty();
+ lastPaintTime = System.currentTimeMillis();
+ waitForAnyEvent();
+ }
+ }
+ } catch (Throwable t) {
+ // TODO: Exception handler should be implemented
+ // t.printStackTrace();
+ }
+ }
+ }
+
+ private void waitForAnyEvent() {
+ EventQueue eventQueue = toolkit.getSystemEventQueueImpl();
+ if (!eventQueue.isEmpty() || !nativeQueue.isEmpty()) {
+ return;
+ }
+ Object eventMonitor = nativeQueue.getEventMonitor();
+ synchronized(eventMonitor) {
+ try {
+ eventMonitor.wait();
+ } catch (InterruptedException e) {}
+ }
+ }
+
+ void shutdown() {
+ shutdownPending = true;
+ }
+
+ EventDispatchThread(Toolkit toolkit, Dispatcher dispatcher ) {
+ this.toolkit = toolkit;
+ this.dispatcher = dispatcher;
+ setName("AWT-EventDispatchThread"); //$NON-NLS-1$
+ setDaemon(true);
+ }
+
+}
diff --git a/awt/java/awt/EventQueue.java b/awt/java/awt/EventQueue.java
new file mode 100644
index 0000000..3997546
--- /dev/null
+++ b/awt/java/awt/EventQueue.java
@@ -0,0 +1,310 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.InvocationEvent;
+import java.lang.reflect.InvocationTargetException;
+import java.util.EmptyStackException;
+
+/**
+ * The EventQueue class manages events. It is a platform-independent class
+ * that queues events both from the underlying peer classes and from trusted
+ * application classes.
+ */
+public class EventQueue {
+
+ /** The core ref. */
+ private final EventQueueCoreAtomicReference coreRef =
+ new EventQueueCoreAtomicReference();
+
+ /**
+ * The Class EventQueueCoreAtomicReference.
+ */
+ private static final class EventQueueCoreAtomicReference {
+
+ /** The core. */
+ private EventQueueCore core;
+
+ /*synchronized*/ /**
+ * Gets the.
+ *
+ * @return the event queue core
+ */
+ EventQueueCore get() {
+ return core;
+ }
+
+ /*synchronized*/ /**
+ * Sets the.
+ *
+ * @param newCore the new core
+ */
+ void set(EventQueueCore newCore) {
+ core = newCore;
+ }
+ }
+
+ /**
+ * Returns true if the calling thread is the current
+ * AWT EventQueue's dispatch thread.
+ *
+ * @return true, if the calling thread is the current
+ * AWT EventQueue's dispatch thread; false otherwise.
+ */
+ public static boolean isDispatchThread() {
+ return Thread.currentThread() instanceof EventDispatchThread;
+ }
+
+ /**
+ * Posts an InvocationEvent which executes the run() method on a Runnable
+ * when dispatched by the AWT event dispatcher thread.
+ *
+ * @param runnable the Runnable whose run method should be executed
+ * synchronously on the EventQueue.
+ */
+ public static void invokeLater(Runnable runnable) {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ InvocationEvent event = new InvocationEvent(toolkit, runnable);
+ toolkit.getSystemEventQueueImpl().postEvent(event);
+ }
+
+ /**
+ * Posts an InvocationEvent which executes the run() method on a Runnable
+ * when dispatched by the AWT event dispatcher thread and the
+ * notifyAll method is called on it immediately after run returns.
+ *
+ * @param runnable the Runnable whose run method should be executed
+ * synchronously on the EventQueue.
+ *
+ * @throws InterruptedException if another thread has interrupted
+ * this thread.
+ * @throws InvocationTargetException if a throwable is thrown
+ * when running the runnable.
+ */
+ public static void invokeAndWait(Runnable runnable)
+ throws InterruptedException, InvocationTargetException {
+
+ if (isDispatchThread()) {
+ throw new Error();
+ }
+
+ final Toolkit toolkit = Toolkit.getDefaultToolkit();
+ final Object notifier = new Object(); //$NON-LOCK-1$
+ InvocationEvent event = new InvocationEvent(
+ toolkit, runnable, notifier, true);
+
+ synchronized (notifier) {
+ toolkit.getSystemEventQueueImpl().postEvent(event);
+ notifier.wait();
+ }
+
+ Exception exception = event.getException();
+
+ if (exception != null) {
+ throw new InvocationTargetException(exception);
+ }
+ }
+
+ /**
+ * Gets the system event queue.
+ *
+ * @return the system event queue
+ */
+ private static EventQueue getSystemEventQueue() {
+ Thread th = Thread.currentThread();
+ if (th instanceof EventDispatchThread) {
+ return ((EventDispatchThread)th).toolkit.getSystemEventQueueImpl();
+ }
+ return null;
+ }
+
+ /**
+ * Gets the most recent event's timestamp.
+ * This event was dispatched from the EventQueue associated with the
+ * calling thread.
+ *
+ * @return the timestamp of the last Event to be dispatched,
+ * or System.currentTimeMillis() if this method is invoked from
+ * a thread other than an event-dispatching thread.
+ */
+ public static long getMostRecentEventTime() {
+ EventQueue eq = getSystemEventQueue();
+ return (eq != null) ?
+ eq.getMostRecentEventTimeImpl() : System.currentTimeMillis();
+ }
+
+ /**
+ * Gets the most recent event time impl.
+ *
+ * @return the most recent event time impl
+ */
+ private long getMostRecentEventTimeImpl() {
+ return getCore().getMostRecentEventTime();
+ }
+
+ /**
+ * Returns the the currently dispatched event by the EventQueue
+ * associated with the calling thread.
+ *
+ * @return the currently dispatched event or null if this method
+ * is invoked from a thread other than an event-dispatching thread.
+ */
+ public static AWTEvent getCurrentEvent() {
+ EventQueue eq = getSystemEventQueue();
+ return (eq != null) ?
+ eq.getCurrentEventImpl() : null;
+ }
+
+ /**
+ * Gets the current event impl.
+ *
+ * @return the current event impl
+ */
+ private AWTEvent getCurrentEventImpl() {
+ return getCore().getCurrentEvent();
+ }
+
+ /**
+ * Instantiates a new event queue.
+ */
+ public EventQueue() {
+ setCore(new EventQueueCore(this));
+ }
+
+ /**
+ * Instantiates a new event queue.
+ *
+ * @param t the t
+ */
+ EventQueue(Toolkit t) {
+ setCore(new EventQueueCore(this, t));
+ }
+
+ /**
+ * Posts a event to the EventQueue.
+ *
+ * @param event AWTEvent.
+ */
+ public void postEvent(AWTEvent event) {
+ event.isPosted = true;
+ getCore().postEvent(event);
+ }
+
+ /**
+ * Returns an event from the EventQueue and removes it from this queue.
+ *
+ * @return the next AWTEvent.
+ *
+ * @throws InterruptedException is thrown if another thread
+ * interrupts this thread.
+ */
+ public AWTEvent getNextEvent() throws InterruptedException {
+ return getCore().getNextEvent();
+ }
+
+ /**
+ * Gets the next event no wait.
+ *
+ * @return the next event no wait
+ */
+ AWTEvent getNextEventNoWait() {
+ return getCore().getNextEventNoWait();
+ }
+
+ /**
+ * Returns the first event of the EventQueue (without removing it
+ * from the queue).
+ *
+ * @return the the first AWT event of the EventQueue.
+ */
+ public AWTEvent peekEvent() {
+ return getCore().peekEvent();
+ }
+
+ /**
+ * Returns the first event of the EventQueue with the specified ID
+ * (without removing it from the queue).
+ *
+ * @param id the type ID of event.
+ *
+ * @return the first event of the EventQueue with the specified ID.
+ */
+ public AWTEvent peekEvent(int id) {
+ return getCore().peekEvent(id);
+ }
+
+ /**
+ * Replaces the existing EventQueue with the specified EventQueue.
+ * Any pending events are transferred to the new EventQueue.
+ *
+ * @param newEventQueue the new event queue.
+ */
+ public void push(EventQueue newEventQueue) {
+ getCore().push(newEventQueue);
+ }
+
+ /**
+ * Stops dispatching events using this EventQueue.
+ * Any pending events are transferred to the previous EventQueue.
+ *
+ * @throws EmptyStackException is thrown if no previous push
+ * was made on this EventQueue.
+ */
+ protected void pop() throws EmptyStackException {
+ getCore().pop();
+ }
+
+ /**
+ * Dispatches the specified event.
+ *
+ * @param event the AWTEvent.
+ */
+ protected void dispatchEvent(AWTEvent event) {
+ getCore().dispatchEventImpl(event);
+ }
+
+ /**
+ * Checks if the queue is empty.
+ *
+ * @return true, if is empty
+ */
+ boolean isEmpty() {
+ return getCore().isEmpty();
+ }
+
+ /**
+ * Gets the core.
+ *
+ * @return the core
+ */
+ EventQueueCore getCore() {
+ return coreRef.get();
+ }
+
+ /**
+ * Sets the core.
+ *
+ * @param newCore the new core
+ */
+ void setCore(EventQueueCore newCore) {
+ coreRef.set((newCore != null) ? newCore : new EventQueueCore(this));
+ }
+}
diff --git a/awt/java/awt/EventQueueCore.java b/awt/java/awt/EventQueueCore.java
new file mode 100644
index 0000000..ffc7c46
--- /dev/null
+++ b/awt/java/awt/EventQueueCore.java
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.InvocationEvent;
+import java.awt.event.MouseEvent;
+import java.util.LinkedList;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The events storage for EventQueue
+ */
+final class EventQueueCore {
+
+ private final LinkedList<EventQueue> queueStack = new LinkedList<EventQueue>();
+ private final LinkedList<AWTEvent> events = new LinkedList<AWTEvent>();
+
+ private Toolkit toolkit;
+ private EventQueue activeQueue;
+ private Thread dispatchThread;
+
+ AWTEvent currentEvent;
+ long mostRecentEventTime = System.currentTimeMillis();
+
+ EventQueueCore(EventQueue eq) {
+ synchronized (this) {
+ queueStack.addLast(eq);
+ activeQueue = eq;
+ }
+ }
+
+ EventQueueCore(EventQueue eq, Toolkit t) {
+ synchronized (this) {
+ queueStack.addLast(eq);
+ activeQueue = eq;
+ setToolkit(t);
+ }
+ }
+
+ synchronized long getMostRecentEventTime() {
+ return mostRecentEventTime;
+ }
+
+ synchronized AWTEvent getCurrentEvent() {
+ return currentEvent;
+ }
+
+ synchronized boolean isSystemEventQueue() {
+ return toolkit != null;
+ }
+
+ private void setToolkit(Toolkit t) {
+ toolkit = t;
+ if (toolkit != null) {
+ toolkit.setSystemEventQueueCore(this);
+ dispatchThread = toolkit.dispatchThread;
+ }
+ }
+
+ synchronized void postEvent(AWTEvent event) {
+ //???AWT
+ /*
+ events.addLast(event);
+ if ((toolkit == null) && (dispatchThread == null)) {
+ dispatchThread = new EventQueueThread(this);
+ dispatchThread.start();
+ }
+ // TODO: add event coalescing
+ if (toolkit != null) {
+ toolkit.shutdownWatchdog.setAwtQueueEmpty(false);
+ if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) {
+ notifyEventMonitor(toolkit);
+ }
+ }
+ notifyAll();
+ */
+ }
+
+ void notifyEventMonitor(Toolkit t) {
+ Object em = t.getNativeEventQueue().getEventMonitor();
+ synchronized (em) {
+ em.notifyAll();
+ }
+ }
+
+ synchronized AWTEvent getNextEvent() throws InterruptedException {
+ while (events.isEmpty()) {
+ wait();
+ }
+ AWTEvent event = events.removeFirst();
+ // TODO: add event coalescing
+ return event;
+ }
+
+ synchronized AWTEvent peekEvent() {
+ return events.isEmpty() ? null : events.getFirst();
+ }
+
+ synchronized AWTEvent peekEvent(int id) {
+ for (AWTEvent event : events) {
+ if (event.getID() == id) {
+ return event;
+ }
+ }
+ return null;
+ }
+
+ synchronized void dispatchEvent(AWTEvent event) {
+ updateCurrentEventAndTime(event);
+ try {
+ activeQueue.dispatchEvent(event);
+ } finally {
+ currentEvent = null;
+ }
+ }
+
+ void dispatchEventImpl(AWTEvent event) {
+ if (event instanceof ActiveEvent) {
+ updateCurrentEventAndTime(event);
+ try {
+ ((ActiveEvent) event).dispatch();
+ } finally {
+ currentEvent = null;
+ }
+ return;
+ }
+
+ Object src = event.getSource();
+
+ if (src instanceof Component) {
+ if (preprocessComponentEvent(event)) {
+ ((Component) src).dispatchEvent(event);
+ }
+ } else {
+ if (toolkit != null) {
+ toolkit.dispatchAWTEvent(event);
+ }
+ if (src instanceof MenuComponent) {
+ ((MenuComponent) src).dispatchEvent(event);
+ }
+ }
+ }
+
+ private final boolean preprocessComponentEvent(AWTEvent event) {
+ if (event instanceof MouseEvent) {
+ return preprocessMouseEvent((MouseEvent)event);
+ }
+ return true;
+ }
+
+ private final boolean preprocessMouseEvent(MouseEvent event) {
+ //???AWT
+ /*
+ if (toolkit != null && toolkit.mouseEventPreprocessor != null) {
+ toolkit.lockAWT();
+ try {
+ return toolkit.mouseEventPreprocessor.preprocess(event);
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ return true;
+ */
+ return true;
+ }
+
+ private void updateCurrentEventAndTime(AWTEvent event) {
+ currentEvent = event;
+ long when = 0;
+ if (event instanceof ActionEvent) {
+ when = ((ActionEvent) event).getWhen();
+ } else if (event instanceof InputEvent) {
+ when = ((InputEvent) event).getWhen();
+ } else if (event instanceof InputMethodEvent) {
+ when = ((InputMethodEvent) event).getWhen();
+ } else if (event instanceof InvocationEvent) {
+ when = ((InvocationEvent) event).getWhen();
+ }
+ if (when != 0) {
+ mostRecentEventTime = when;
+ }
+ }
+
+ synchronized void push(EventQueue newEventQueue) {
+ // TODO: handle incorrect situations
+ if (queueStack.isEmpty()) {
+ // awt.6B=Queue stack is empty
+ throw new IllegalStateException(Messages.getString("awt.6B")); //$NON-NLS-1$
+ }
+
+ queueStack.addLast(newEventQueue);
+ activeQueue = newEventQueue;
+ activeQueue.setCore(this);
+ }
+
+ synchronized void pop() {
+ EventQueue removed = queueStack.removeLast();
+ if (removed != activeQueue) {
+ // awt.6C=Event queue stack is broken
+ throw new IllegalStateException(Messages.getString("awt.6C")); //$NON-NLS-1$
+ }
+ activeQueue = queueStack.getLast();
+ removed.setCore(null);
+ }
+
+ synchronized AWTEvent getNextEventNoWait() {
+ try {
+ return events.isEmpty() ? null : activeQueue.getNextEvent();
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
+
+ synchronized boolean isEmpty() {
+ return (currentEvent == null) && events.isEmpty();
+ }
+
+ synchronized boolean isEmpty(long timeout) {
+ if (!isEmpty()) {
+ return false;
+ }
+ try {
+ wait(timeout);
+ } catch (InterruptedException e) {}
+ return isEmpty();
+ }
+
+ synchronized EventQueue getActiveEventQueue() {
+ return activeQueue;
+ }
+}
diff --git a/awt/java/awt/Font.java b/awt/java/awt/Font.java
new file mode 100644
index 0000000..139ae68
--- /dev/null
+++ b/awt/java/awt/Font.java
@@ -0,0 +1,1500 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.LineMetrics;
+import java.awt.font.TextAttribute;
+import java.awt.font.TransformAttribute;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.text.CharacterIterator;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.harmony.awt.gl.font.AndroidGlyphVector;
+import org.apache.harmony.awt.gl.font.CommonGlyphVector;
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.gl.font.LineMetricsImpl;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+
+/**
+ * The Font class represents fonts for rendering text.
+ * This class allow to map characters to glyphs.
+ * <p>
+ * A glyph is a shape used to render a character or a sequence of
+ * characters. For example one character of Latin writing system
+ * represented by one glyth, but in complex writing system such as
+ * South and South-East Asian there is more complicated correspondence
+ * between characters and glyphs.
+ * <p>
+ * The Font object is identified by two types of names. The logical font name
+ * is the name that is used to construct the font. The font name
+ * is the name of a particular font face (for example, Arial Bold).
+ * The family name is the font's family name that specifies
+ * the typographic design across several faces (for example, Arial). In
+ * all the Font is identified by three attributes: the family name,
+ * the style (such as bold or italic), and the size.
+ */
+public class Font implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -4206021311591459213L;
+
+ // Identity Transform attribute
+ /** The Constant IDENTITY_TRANSFORM. */
+ private static final TransformAttribute IDENTITY_TRANSFORM = new TransformAttribute(
+ new AffineTransform());
+
+ /** The Constant PLAIN indicates font's plain style. */
+ public static final int PLAIN = 0;
+
+ /** The Constant BOLD indicates font's bold style. */
+ public static final int BOLD = 1;
+
+ /** The Constant ITALIC indicates font's italic style. */
+ public static final int ITALIC = 2;
+
+ /** The Constant ROMAN_BASELINE indicated roman baseline. */
+ public static final int ROMAN_BASELINE = 0;
+
+ /** The Constant CENTER_BASELINE indicates center baseline. */
+ public static final int CENTER_BASELINE = 1;
+
+ /** The Constant HANGING_BASELINE indicates hanging baseline. */
+ public static final int HANGING_BASELINE = 2;
+
+ /**
+ * The Constant TRUETYPE_FONT indicates a font resource of
+ * type TRUETYPE.
+ */
+ public static final int TRUETYPE_FONT = 0;
+
+ /**
+ * The Constant TYPE1_FONT indicates a font resource of
+ * type TYPE1.
+ */
+ public static final int TYPE1_FONT = 1;
+
+ /**
+ * The Constant LAYOUT_LEFT_TO_RIGHT indicates that text is
+ * left to right.
+ */
+ public static final int LAYOUT_LEFT_TO_RIGHT = 0;
+
+ /**
+ * The Constant LAYOUT_RIGHT_TO_LEFT indicates that text is
+ * right to left.
+ */
+ public static final int LAYOUT_RIGHT_TO_LEFT = 1;
+
+ /**
+ * The Constant LAYOUT_NO_START_CONTEXT indicates that the text
+ * in the char array before the indicated start should not be examined.
+ */
+ public static final int LAYOUT_NO_START_CONTEXT = 2;
+
+ /** The Constant LAYOUT_NO_LIMIT_CONTEXT indicates that text in
+ * the char array after the indicated limit should not be examined. */
+ public static final int LAYOUT_NO_LIMIT_CONTEXT = 4;
+
+ /** The Constant DEFAULT_FONT. */
+ static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12); //$NON-NLS-1$
+
+ /** The name of the Font. */
+ protected String name;
+
+ /** The style of the Font. */
+ protected int style;
+
+ /** The size of the Font. */
+ protected int size;
+
+ /** The point size of the Font. */
+ protected float pointSize;
+
+ // Flag if the Font object transformed
+ /** The transformed. */
+ private boolean transformed;
+
+ // Set of font attributes
+ /** The requested attributes. */
+ private Hashtable<Attribute, Object> fRequestedAttributes;
+
+ // font peer object corresponding to this Font
+ /** The font peer. */
+ private transient FontPeerImpl fontPeer;
+
+ // number of glyphs in this Font
+ /** The num glyphs. */
+ private transient int numGlyphs = -1;
+
+ // code for missing glyph for this Font
+ /** The missing glyph code. */
+ private transient int missingGlyphCode = -1;
+
+ /**
+ * Writes object to ObjectOutputStream.
+ *
+ * @param out ObjectOutputStream
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ }
+
+ /**
+ * Reads object from ObjectInputStream object and set native platform
+ * dependent fields to default values.
+ *
+ * @param in ObjectInputStream object
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ * @throws ClassNotFoundException the class not found exception
+ */
+ private void readObject(java.io.ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
+ in.defaultReadObject();
+
+ numGlyphs = -1;
+ missingGlyphCode = -1;
+
+ }
+
+ /**
+ * Instantiates a new Font with the specified attributes.
+ * The Font will be created with default attributes
+ * if the attribute's parameter is null.
+ *
+ * @param attributes the attributes to be assigned to the new Font, or null.
+ */
+ public Font(Map<? extends Attribute, ?> attributes) {
+ Object currAttr;
+
+ // Default values are taken from the documentation of the Font class.
+ // See Font constructor, decode and getFont sections.
+
+ this.name = "default"; //$NON-NLS-1$
+ this.size = 12;
+ this.pointSize = 12;
+ this.style = Font.PLAIN;
+
+ if (attributes != null) {
+
+ fRequestedAttributes = new Hashtable<Attribute, Object>(attributes);
+
+ currAttr = attributes.get(TextAttribute.SIZE);
+ if (currAttr != null) {
+ this.pointSize = ((Float) currAttr).floatValue();
+ this.size = (int) Math.ceil(this.pointSize);
+ }
+
+ currAttr = attributes.get(TextAttribute.POSTURE);
+ if (currAttr != null
+ && currAttr.equals(TextAttribute.POSTURE_OBLIQUE)) {
+ this.style |= Font.ITALIC;
+ }
+
+ currAttr = attributes.get(TextAttribute.WEIGHT);
+ if ((currAttr != null)
+ && (((Float) currAttr).floatValue() >= (TextAttribute.WEIGHT_BOLD)
+ .floatValue())) {
+ this.style |= Font.BOLD;
+ }
+
+ currAttr = attributes.get(TextAttribute.FAMILY);
+ if (currAttr != null) {
+ this.name = (String) currAttr;
+ }
+
+ currAttr = attributes.get(TextAttribute.TRANSFORM);
+ if (currAttr != null) {
+ if (currAttr instanceof TransformAttribute) {
+ this.transformed = !((TransformAttribute) currAttr)
+ .getTransform().isIdentity();
+ } else if (currAttr instanceof AffineTransform) {
+ this.transformed = !((AffineTransform) currAttr)
+ .isIdentity();
+ }
+ }
+
+ } else {
+ fRequestedAttributes = new Hashtable<Attribute, Object>(5);
+ fRequestedAttributes.put(TextAttribute.TRANSFORM,
+ IDENTITY_TRANSFORM);
+
+ this.transformed = false;
+
+ fRequestedAttributes.put(TextAttribute.FAMILY, name);
+
+ fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size));
+
+ if ((this.style & Font.BOLD) != 0) {
+ fRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_BOLD);
+ } else {
+ fRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_REGULAR);
+ }
+ if ((this.style & Font.ITALIC) != 0) {
+ fRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ } else {
+ fRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_REGULAR);
+ }
+
+ }
+ }
+
+ /**
+ * Instantiates a new Font with the specified name, style and size.
+ *
+ * @param name the name of font.
+ * @param style the style of font.
+ * @param size the size of font.
+ */
+ public Font(String name, int style, int size) {
+
+ this.name = (name != null) ? name : "Default"; //$NON-NLS-1$
+ this.size = (size >= 0) ? size : 0;
+ this.style = (style & ~0x03) == 0 ? style : Font.PLAIN;
+ this.pointSize = this.size;
+
+ fRequestedAttributes = new Hashtable<Attribute, Object>(5);
+
+ fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM);
+
+ this.transformed = false;
+
+ fRequestedAttributes.put(TextAttribute.FAMILY, this.name);
+ fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size));
+
+ if ((this.style & Font.BOLD) != 0) {
+ fRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_BOLD);
+ } else {
+ fRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_REGULAR);
+ }
+ if ((this.style & Font.ITALIC) != 0) {
+ fRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ } else {
+ fRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_REGULAR);
+ }
+ }
+
+ /**
+ * Returns true if this Font has a glyph for the specified character.
+ *
+ * @param c the character.
+ *
+ * @return true if this Font has a glyph for the specified character,
+ * false otherwise.
+ */
+ public boolean canDisplay(char c) {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ return peer.canDisplay(c);
+ }
+
+ /**
+ * Returns true if the Font can display the characters of the
+ * the specified text from the specified start position
+ * to the specified limit position.
+ *
+ * @param text the text.
+ * @param start the start offset (in the character array).
+ * @param limit the limit offset (in the character array).
+ *
+ * @return the a character's position in the text that this Font
+ * can not display, or -1 if this Font can display all characters
+ * in this text.
+ */
+ public int canDisplayUpTo(char[] text, int start, int limit) {
+ int st = start;
+ int result;
+ while ((st < limit) && canDisplay(text[st])) {
+ st++;
+ }
+
+ if (st == limit) {
+ result = -1;
+ } else {
+ result = st;
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns true if the Font can display the characters of the
+ * the specified CharacterIterator from the specified start position
+ * and the specified limit position.
+ *
+ * @param iter the CharacterIterator.
+ * @param start the start offset.
+ * @param limit the limit offset.
+ *
+ * @return the a character's position in the CharacterIterator
+ * that this Font can not display, or -1 if this Font can display
+ * all characters in this text.
+ */
+ public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
+ int st = start;
+ char c = iter.setIndex(start);
+ int result;
+
+ while ((st < limit) && (canDisplay(c))) {
+ st++;
+ c = iter.next();
+ }
+ if (st == limit) {
+ result = -1;
+ } else {
+ result = st;
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns true if this Font can display a specified String.
+ *
+ * @param str the String.
+ *
+ * @return the a character's position in the String that
+ * this Font can not display, or -1 if this Font can display
+ * all characters in this text.
+ */
+ public int canDisplayUpTo(String str) {
+ char[] chars = str.toCharArray();
+ return canDisplayUpTo(chars, 0, chars.length);
+ }
+
+ /**
+ * Creates a GlyphVector of associating characters to glyphs
+ * based on the unicode map of this Font.
+ *
+ * @param frc the FontRenderContext.
+ * @param chars the characters array.
+ *
+ * @return the GlyphVector of associating characters to glyphs
+ * based on the unicode map of this Font.
+ */
+ public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) {
+ return new AndroidGlyphVector(chars, frc, this, 0);
+ }
+
+ /**
+ * Creates a GlyphVector of associating characters contained
+ * in the specified CharacterIterator to glyphs based on
+ * the unicode map of this Font.
+ *
+ * @param frc the FontRenderContext.
+ * @param iter the CharacterIterator.
+ *
+ * @return the GlyphVector of associating characters contained
+ * in the specified CharacterIterator to glyphs
+ * based on the unicode map of this Font.
+ */
+ public GlyphVector createGlyphVector(FontRenderContext frc,
+ CharacterIterator iter) {
+ throw new RuntimeException("Not implemented!"); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates a GlyphVector of associating characters to glyphs based on
+ * the unicode map of this Font.
+ *
+ * @param frc the FontRenderContext.
+ * @param glyphCodes the specified integer array of glyph codes.
+ *
+ * @return the GlyphVector of associating characters to glyphs
+ * based on the unicode map of this Font.
+ */
+ public GlyphVector createGlyphVector(FontRenderContext frc, int[] glyphCodes)
+ throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented!"); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates a GlyphVector of associating characters to glyphs based on
+ * the unicode map of this Font.
+ *
+ * @param frc the FontRenderContext.
+ * @param str the specified String.
+ *
+ * @return the GlyphVector of associating characters to glyphs
+ * based on the unicode map of this Font.
+ */
+ public GlyphVector createGlyphVector(FontRenderContext frc, String str) {
+ return new AndroidGlyphVector(str.toCharArray(), frc, this, 0);
+
+ }
+
+ /**
+ * Returns the font style constant value corresponding to one of the font style
+ * names ("BOLD", "ITALIC", "BOLDITALIC"). This method returns Font.PLAIN if
+ * the argument is not one of the predefined style names.
+ *
+ * @param fontStyleName font style name
+ *
+ * @return font style constant value corresponding to the font style name
+ * specified.
+ */
+ private static int getFontStyle(String fontStyleName) {
+ int result = Font.PLAIN;
+
+ if (fontStyleName.toUpperCase().equals("BOLDITALIC")) { //$NON-NLS-1$
+ result = Font.BOLD | Font.ITALIC;
+ } else if (fontStyleName.toUpperCase().equals("BOLD")) { //$NON-NLS-1$
+ result = Font.BOLD;
+ } else if (fontStyleName.toUpperCase().equals("ITALIC")) { //$NON-NLS-1$
+ result = Font.ITALIC;
+ }
+
+ return result;
+ }
+
+ /**
+ * Decodes the specified string which described the Font. The string
+ * should have the following format: fontname-style-pointsize.
+ * The style can be PLAIN, BOLD, BOLDITALIC, or ITALIC.
+ *
+ * @param str the string which describes the font.
+ *
+ * @return the Font from the specified string.
+ */
+ public static Font decode(String str) {
+ // XXX: Documentation doesn't describe all cases, e.g. fonts face names
+ // with
+ // symbols that are suggested as delimiters in the documentation.
+ // In this decode implementation only ***-***-*** format is used with
+ // '-'
+ // as the delimiter to avoid unexpected parse results of font face names
+ // with spaces.
+
+ if (str == null) {
+ return DEFAULT_FONT;
+ }
+
+ StringTokenizer strTokens;
+ String delim = "-"; //$NON-NLS-1$
+ String substr;
+
+ int fontSize = DEFAULT_FONT.size;
+ int fontStyle = DEFAULT_FONT.style;
+ String fontName = DEFAULT_FONT.name;
+
+ strTokens = new StringTokenizer(str.trim(), delim);
+
+ // Font Name
+ if (strTokens.hasMoreTokens()) {
+ fontName = strTokens.nextToken(); // first token is the font name
+ }
+
+ // Font Style or Size (if the style is undefined)
+ if (strTokens.hasMoreTokens()) {
+ substr = strTokens.nextToken();
+
+ try {
+ // if second token is the font size
+ fontSize = Integer.parseInt(substr);
+ } catch (NumberFormatException e) {
+ // then second token is the font style
+ fontStyle = getFontStyle(substr);
+ }
+
+ }
+
+ // Font Size
+ if (strTokens.hasMoreTokens()) {
+ try {
+ fontSize = Integer.parseInt(strTokens.nextToken());
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ return new Font(fontName, fontStyle, fontSize);
+ }
+
+ /**
+ * Perfoms the specified affine transform to the Font and returns
+ * a new Font.
+ *
+ * @param trans the AffineTransform.
+ *
+ * @return the Font object.
+ *
+ * @throws IllegalArgumentException if affine transform parameter
+ * is null.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(AffineTransform trans) {
+
+ if (trans == null) {
+ // awt.94=transform can not be null
+ throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$
+ }
+
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+
+ derivefRequestedAttributes.put(TextAttribute.TRANSFORM,
+ new TransformAttribute(trans));
+
+ return new Font(derivefRequestedAttributes);
+
+ }
+
+ /**
+ * Returns a new Font that is a copy of the current Font
+ * modified so that the size is the specified size.
+ *
+ * @param size the size of font.
+ *
+ * @return the Font object.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(float size) {
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+ derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size));
+ return new Font(derivefRequestedAttributes);
+ }
+
+ /**
+ * Returns a new Font that is a copy of the current Font
+ * modified so that the style is the specified style.
+ *
+ * @param style the style of font.
+ *
+ * @return the Font object.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(int style) {
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+
+ if ((style & Font.BOLD) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_BOLD);
+ } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
+ }
+
+ if ((style & Font.ITALIC) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.POSTURE);
+ }
+
+ return new Font(derivefRequestedAttributes);
+ }
+
+ /**
+ * Returns a new Font that is a copy of the current Font
+ * modified to match the specified style and with the specified
+ * affine transform applied to its glyphs.
+ *
+ * @param style the style of font.
+ * @param trans the AffineTransform.
+ *
+ * @return the Font object.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(int style, AffineTransform trans) {
+
+ if (trans == null) {
+ // awt.94=transform can not be null
+ throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$
+ }
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+
+ if ((style & BOLD) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_BOLD);
+ } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
+ }
+
+ if ((style & ITALIC) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.POSTURE);
+ }
+ derivefRequestedAttributes.put(TextAttribute.TRANSFORM,
+ new TransformAttribute(trans));
+
+ return new Font(derivefRequestedAttributes);
+ }
+
+ /**
+ * Returns a new Font that is a copy of the current Font
+ * modified so that the size and style are the specified
+ * size and style.
+ *
+ * @param style the style of font.
+ * @param size the size of font.
+ *
+ * @return the Font object.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(int style, float size) {
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+
+ if ((style & BOLD) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.WEIGHT,
+ TextAttribute.WEIGHT_BOLD);
+ } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.WEIGHT);
+ }
+
+ if ((style & ITALIC) != 0) {
+ derivefRequestedAttributes.put(TextAttribute.POSTURE,
+ TextAttribute.POSTURE_OBLIQUE);
+ } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) {
+ derivefRequestedAttributes.remove(TextAttribute.POSTURE);
+ }
+
+ derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size));
+ return new Font(derivefRequestedAttributes);
+
+ }
+
+ /**
+ * Returns a new Font object with a new set of font attributes.
+ *
+ * @param attributes the map of attributes.
+ *
+ * @return the Font.
+ */
+ @SuppressWarnings("unchecked")
+ public Font deriveFont(Map<? extends Attribute, ?> attributes) {
+ Attribute[] avalAttributes = this.getAvailableAttributes();
+
+ Hashtable<Attribute, Object> derivefRequestedAttributes = (Hashtable<Attribute, Object>) fRequestedAttributes
+ .clone();
+ Object currAttribute;
+ for (Attribute element : avalAttributes) {
+ currAttribute = attributes.get(element);
+ if (currAttribute != null) {
+ derivefRequestedAttributes.put(element, currAttribute);
+ }
+ }
+ return new Font(derivefRequestedAttributes);
+ }
+
+ /**
+ * Compares the specified Object with the current Font.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified Object is an instance of Font
+ * with the same family, size, and style as this Font, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj != null) {
+ try {
+ Font font = (Font) obj;
+
+ return ((this.style == font.style) && (this.size == font.size)
+ && this.name.equals(font.name)
+ && (this.pointSize == font.pointSize) && (this
+ .getTransform()).equals(font.getTransform()));
+ } catch (ClassCastException e) {
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Gets the map of font's attributes.
+ *
+ * @return the map of font's attributes.
+ */
+ @SuppressWarnings("unchecked")
+ public Map<TextAttribute, ?> getAttributes() {
+ return (Map<TextAttribute, ?>) fRequestedAttributes.clone();
+ }
+
+ /**
+ * Gets the keys of all available attributes.
+ *
+ * @return the keys array of all available attributes.
+ */
+ public Attribute[] getAvailableAttributes() {
+ Attribute[] attrs = { TextAttribute.FAMILY, TextAttribute.POSTURE,
+ TextAttribute.SIZE, TextAttribute.TRANSFORM,
+ TextAttribute.WEIGHT, TextAttribute.SUPERSCRIPT,
+ TextAttribute.WIDTH };
+ return attrs;
+ }
+
+ /**
+ * Gets the baseline for this character.
+ *
+ * @param c the character.
+ *
+ * @return the baseline for this character.
+ */
+ public byte getBaselineFor(char c) {
+ // TODO: implement using TT BASE table data
+ return 0;
+ }
+
+ /**
+ * Gets the family name of the Font.
+ *
+ * @return the family name of the Font.
+ */
+ public String getFamily() {
+ if (fRequestedAttributes != null) {
+ fRequestedAttributes.get(TextAttribute.FAMILY);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the family name of this Font associated with
+ * the specified locale.
+ *
+ * @param l the locale.
+ *
+ * @return the family name of this Font associated with
+ * the specified locale.
+ */
+ public String getFamily(Locale l) {
+ if (l == null) {
+ // awt.01='{0}' parameter is null
+ throw new NullPointerException(Messages.getString(
+ "awt.01", "Locale")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return getFamily();
+ }
+
+ /**
+ * Gets a Font with the specified attribute set.
+ *
+ * @param attributes the attributes to be assigned to the new Font.
+ *
+ * @return the Font.
+ */
+ public static Font getFont(Map<? extends Attribute, ?> attributes) {
+ Font fnt = (Font) attributes.get(TextAttribute.FONT);
+ if (fnt != null) {
+ return fnt;
+ }
+ return new Font(attributes);
+ }
+
+ /**
+ * Gets a Font object from the system properties list with the specified name
+ * or returns the specified Font if there is no such property.
+ *
+ * @param sp the specified property name.
+ * @param f the Font.
+ *
+ * @return the Font object from the system properties list with the specified name
+ * or the specified Font if there is no such property.
+ */
+ public static Font getFont(String sp, Font f) {
+ String pr = System.getProperty(sp);
+ if (pr == null) {
+ return f;
+ }
+ return decode(pr);
+ }
+
+ /**
+ * Gets a Font object from the system properties list with the specified name.
+ *
+ * @param sp the system property name.
+ *
+ * @return the Font, or null if there is no shuch property
+ * with the specified name.
+ */
+ public static Font getFont(String sp) {
+ return getFont(sp, null);
+ }
+
+ /**
+ * Gets the font name.
+ *
+ * @return the font name.
+ */
+ public String getFontName() {
+ if (fRequestedAttributes != null) {
+ fRequestedAttributes.get(TextAttribute.FAMILY);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the font name associated with the specified locale.
+ *
+ * @param l the locale.
+ *
+ * @return the font name associated with the specified locale.
+ */
+ public String getFontName(Locale l) {
+ return getFamily();
+ }
+
+ /**
+ * Returns a LineMetrics object created with the specified parameters.
+ *
+ * @param chars the chars array.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return the LineMetrics for the specified parameters.
+ */
+ public LineMetrics getLineMetrics(char[] chars, int start, int end,
+ FontRenderContext frc) {
+ if (frc == null) {
+ // awt.00=FontRenderContext is null
+ throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+ }
+
+ //FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics();
+ FontMetrics fm = new FontMetricsImpl(this);
+ float[] fmet = {fm.getAscent(), fm.getDescent(), fm.getLeading()};
+ return new LineMetricsImpl(chars.length, fmet, null);
+ }
+
+ /**
+ * Returns a LineMetrics object created with the specified parameters.
+ *
+ * @param iter the CharacterIterator.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return the LineMetrics for the specified parameters.
+ */
+ public LineMetrics getLineMetrics(CharacterIterator iter, int start,
+ int end, FontRenderContext frc) {
+
+ if (frc == null) {
+ // awt.00=FontRenderContext is null
+ throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+ }
+
+ String resultString;
+ int iterCount;
+
+ iterCount = end - start;
+ if (iterCount < 0) {
+ resultString = ""; //$NON-NLS-1$
+ } else {
+ char[] chars = new char[iterCount];
+ int i = 0;
+ for (char c = iter.setIndex(start); c != CharacterIterator.DONE
+ && (i < iterCount); c = iter.next()) {
+ chars[i] = c;
+ i++;
+ }
+ resultString = new String(chars);
+ }
+ return this.getLineMetrics(resultString, frc);
+ }
+
+ /**
+ * Returns a LineMetrics object created with the specified parameters.
+ *
+ * @param str the String.
+ * @param frc the FontRenderContext.
+ *
+ * @return the LineMetrics for the specified parameters.
+ */
+ public LineMetrics getLineMetrics(String str, FontRenderContext frc) {
+ //FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics();
+ FontMetrics fm = new FontMetricsImpl(this);
+ float[] fmet = {fm.getAscent(), fm.getDescent(), fm.getLeading()};
+ //Log.i("FONT FMET", fmet.toString());
+ return new LineMetricsImpl(str.length(), fmet, null);
+
+ }
+
+ /**
+ * Returns a LineMetrics object created with the specified parameters.
+ *
+ * @param str the String.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return the LineMetrics for the specified parameters.
+ */
+ public LineMetrics getLineMetrics(String str, int start, int end,
+ FontRenderContext frc) {
+ return this.getLineMetrics(str.substring(start, end), frc);
+ }
+
+ /**
+ * Gets the logical bounds of the specified String in
+ * the specified FontRenderContext. The logical bounds contains
+ * the origin, ascent, advance, and height.
+ *
+ * @param ci the specified CharacterIterator.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return a Rectangle2D object.
+ */
+ public Rectangle2D getStringBounds(CharacterIterator ci, int start,
+ int end, FontRenderContext frc) {
+ int first = ci.getBeginIndex();
+ int finish = ci.getEndIndex();
+ char[] chars;
+
+ if (start < first) {
+ // awt.95=Wrong start index: {0}
+ throw new IndexOutOfBoundsException(Messages.getString(
+ "awt.95", start)); //$NON-NLS-1$
+ }
+ if (end > finish) {
+ // awt.96=Wrong finish index: {0}
+ throw new IndexOutOfBoundsException(Messages.getString(
+ "awt.96", end)); //$NON-NLS-1$
+ }
+ if (start > end) {
+ // awt.97=Wrong range length: {0}
+ throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$
+ (end - start)));
+ }
+
+ if (frc == null) {
+ throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+ }
+
+ chars = new char[end - start];
+
+ ci.setIndex(start);
+ for (int i = 0; i < chars.length; i++) {
+ chars[i] = ci.current();
+ ci.next();
+ }
+
+ return this.getStringBounds(chars, 0, chars.length, frc);
+
+ }
+
+ /**
+ * Gets the logical bounds of the specified String in
+ * the specified FontRenderContext. The logical bounds contains
+ * the origin, ascent, advance, and height.
+ *
+ * @param str the specified String.
+ * @param frc the FontRenderContext.
+ *
+ * @return a Rectangle2D object.
+ */
+ public Rectangle2D getStringBounds(String str, FontRenderContext frc) {
+ char[] chars = str.toCharArray();
+ return this.getStringBounds(chars, 0, chars.length, frc);
+
+ }
+
+ /**
+ * Gets the logical bounds of the specified String in
+ * the specified FontRenderContext. The logical bounds contains
+ * the origin, ascent, advance, and height.
+ *
+ * @param str the specified String.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return a Rectangle2D object.
+ */
+ public Rectangle2D getStringBounds(String str, int start, int end,
+ FontRenderContext frc) {
+
+ return this.getStringBounds((str.substring(start, end)), frc);
+ }
+
+ /**
+ * Gets the logical bounds of the specified String in
+ * the specified FontRenderContext. The logical bounds contains
+ * the origin, ascent, advance, and height.
+ *
+ * @param chars the specified character array.
+ * @param start the start offset.
+ * @param end the end offset.
+ * @param frc the FontRenderContext.
+ *
+ * @return a Rectangle2D object.
+ */
+ public Rectangle2D getStringBounds(char[] chars, int start, int end,
+ FontRenderContext frc) {
+ if (start < 0) {
+ // awt.95=Wrong start index: {0}
+ throw new IndexOutOfBoundsException(Messages.getString(
+ "awt.95", start)); //$NON-NLS-1$
+ }
+ if (end > chars.length) {
+ // awt.96=Wrong finish index: {0}
+ throw new IndexOutOfBoundsException(Messages.getString(
+ "awt.96", end)); //$NON-NLS-1$
+ }
+ if (start > end) {
+ // awt.97=Wrong range length: {0}
+ throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$
+ (end - start)));
+ }
+
+ if (frc == null) {
+ throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+ }
+
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+
+ final int TRANSFORM_MASK = AffineTransform.TYPE_GENERAL_ROTATION
+ | AffineTransform.TYPE_GENERAL_TRANSFORM;
+ Rectangle2D bounds;
+
+ AffineTransform transform = getTransform();
+
+ // XXX: for transforms where an angle between basis vectors is not 90
+ // degrees Rectanlge2D class doesn't fit as Logical bounds.
+ if ((transform.getType() & TRANSFORM_MASK) == 0) {
+ int width = 0;
+ for (int i = start; i < end; i++) {
+ width += peer.charWidth(chars[i]);
+ }
+ //LineMetrics nlm = peer.getLineMetrics();
+
+ LineMetrics nlm = getLineMetrics(chars, start, end, frc);
+
+ bounds = transform.createTransformedShape(
+ new Rectangle2D.Float(0, -nlm.getAscent(), width, nlm
+ .getHeight())).getBounds2D();
+ } else {
+ int len = end - start;
+ char[] subChars = new char[len];
+ System.arraycopy(chars, start, subChars, 0, len);
+ bounds = createGlyphVector(frc, subChars).getLogicalBounds();
+ }
+ return bounds;
+ }
+
+ /**
+ * Gets the character's maximum bounds as defined in
+ * the specified FontRenderContext.
+ *
+ * @param frc the FontRenderContext.
+ *
+ * @return the character's maximum bounds.
+ */
+ public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
+ if (frc == null) {
+ // awt.00=FontRenderContext is null
+ throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$
+ }
+
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+
+ Rectangle2D bounds = peer.getMaxCharBounds(frc);
+ AffineTransform transform = getTransform();
+ // !! Documentation doesn't describe meaning of max char bounds
+ // for the fonts that have rotate transforms. For all transforms
+ // returned bounds are the bounds of transformed maxCharBounds
+ // Rectangle2D that corresponds to the font with identity transform.
+ // TODO: resolve this issue to return correct bounds
+ bounds = transform.createTransformedShape(bounds).getBounds2D();
+
+ return bounds;
+ }
+
+ /**
+ * Returns a new GlyphVector object performing full layout of
+ * the text.
+ *
+ * @param frc the FontRenderContext.
+ * @param chars the character array to be layout.
+ * @param start the start offset of the text to use for
+ * the GlyphVector.
+ * @param count the count of characters to use for
+ * the GlyphVector.
+ * @param flags the flag indicating text direction:
+ * LAYOUT_RIGHT_TO_LEFT, LAYOUT_LEFT_TO_RIGHT.
+ *
+ * @return the GlyphVector.
+ */
+ public GlyphVector layoutGlyphVector(FontRenderContext frc, char[] chars,
+ int start, int count, int flags) {
+ // TODO: implement method for bidirectional text.
+ // At the moment only LTR and RTL texts supported.
+ if (start < 0) {
+ // awt.95=Wrong start index: {0}
+ throw new ArrayIndexOutOfBoundsException(Messages.getString(
+ "awt.95", //$NON-NLS-1$
+ start));
+ }
+
+ if (count < 0) {
+ // awt.98=Wrong count value, can not be negative: {0}
+ throw new ArrayIndexOutOfBoundsException(Messages.getString(
+ "awt.98", //$NON-NLS-1$
+ count));
+ }
+
+ if (start + count > chars.length) {
+ // awt.99=Wrong [start + count] is out of range: {0}
+ throw new ArrayIndexOutOfBoundsException(Messages.getString(
+ "awt.99", //$NON-NLS-1$
+ (start + count)));
+ }
+
+ char[] out = new char[count];
+ System.arraycopy(chars, start, out, 0, count);
+
+ return new CommonGlyphVector(out, frc, this, flags);
+ }
+
+ /**
+ * Returns the String representation of this Font.
+ *
+ * @return the String representation of this Font.
+ */
+ @Override
+ public String toString() {
+ String stl = "plain"; //$NON-NLS-1$
+ String result;
+
+ if (this.isBold() && this.isItalic()) {
+ stl = "bolditalic"; //$NON-NLS-1$
+ }
+ if (this.isBold() && !this.isItalic()) {
+ stl = "bold"; //$NON-NLS-1$
+ }
+
+ if (!this.isBold() && this.isItalic()) {
+ stl = "italic"; //$NON-NLS-1$
+ }
+
+ result = this.getClass().getName() + "[family=" + this.getFamily() + //$NON-NLS-1$
+ ",name=" + this.name + //$NON-NLS-1$
+ ",style=" + stl + //$NON-NLS-1$
+ ",size=" + this.size + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ return result;
+ }
+
+ /**
+ * Gets the postscript name of this Font.
+ *
+ * @return the postscript name of this Font.
+ */
+ public String getPSName() {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ return peer.getPSName();
+ }
+
+ /**
+ * Gets the logical name of this Font.
+ *
+ * @return the logical name of this Font.
+ */
+ public String getName() {
+ return (this.name);
+ }
+
+ /**
+ * Gets the peer of this Font.
+ *
+ * @return the peer of this Font.
+ *
+ * @deprecated Font rendering is platform independent now.
+ */
+ @Deprecated
+ public java.awt.peer.FontPeer getPeer() {
+ if (fontPeer == null) {
+ fontPeer = (FontPeerImpl) Toolkit.getDefaultToolkit()
+ .getGraphicsFactory().getFontPeer(this);
+ }
+ return fontPeer;
+
+ }
+
+ /**
+ * Gets the transform acting on this Font (from the Font's
+ * attributes).
+ *
+ * @return the transformation of this Font.
+ */
+ public AffineTransform getTransform() {
+ Object transform = fRequestedAttributes.get(TextAttribute.TRANSFORM);
+
+ if (transform != null) {
+ if (transform instanceof TransformAttribute) {
+ return ((TransformAttribute) transform).getTransform();
+ }
+ if (transform instanceof AffineTransform) {
+ return new AffineTransform((AffineTransform) transform);
+ }
+ } else {
+ transform = new AffineTransform();
+ }
+ return (AffineTransform) transform;
+
+ }
+
+ /**
+ * Checks if this font is transformed or not.
+ *
+ * @return true, if this font is transformed, false otherwise.
+ */
+ public boolean isTransformed() {
+ return this.transformed;
+ }
+
+ /**
+ * Checks if this font has plain style or not.
+ *
+ * @return true, if this font has plain style, false otherwise.
+ */
+ public boolean isPlain() {
+ return (this.style == PLAIN);
+ }
+
+ /**
+ * Checks if this font has italic style or not.
+ *
+ * @return true, if this font has italic style, false otherwise.
+ */
+ public boolean isItalic() {
+ return (this.style & ITALIC) != 0;
+ }
+
+ /**
+ * Checks if this font has bold style or not.
+ *
+ * @return true, if this font has bold style, false otherwise.
+ */
+ public boolean isBold() {
+ return (this.style & BOLD) != 0;
+ }
+
+ /**
+ * Returns true if this Font has uniform line metrics.
+ *
+ * @return true if this Font has uniform line metrics,
+ * false otherwise.
+ */
+ public boolean hasUniformLineMetrics() {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ return peer.hasUniformLineMetrics();
+ }
+
+ /**
+ * Returns hash code of this Font object.
+ *
+ * @return the hash code of this Font object.
+
+ */
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+
+ hash.append(this.name);
+ hash.append(this.style);
+ hash.append(this.size);
+
+ return hash.hashCode();
+ }
+
+ /**
+ * Gets the style of this Font.
+ *
+ * @return the style of this Font.
+ */
+ public int getStyle() {
+ return this.style;
+ }
+
+ /**
+ * Gets the size of this Font.
+ *
+ * @return the size of this Font.
+ */
+ public int getSize() {
+ return this.size;
+ }
+
+ /**
+ * Gets the number of glyphs for this Font.
+ *
+ * @return the number of glyphs for this Font.
+ */
+ public int getNumGlyphs() {
+ if (numGlyphs == -1) {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ this.numGlyphs = peer.getNumGlyphs();
+ }
+ return this.numGlyphs;
+ }
+
+ /**
+ * Gets the glyphCode which is used as default glyph when this Font
+ * does not have a glyph for a specified unicode.
+ *
+ * @return the missing glyph code.
+ */
+ public int getMissingGlyphCode() {
+ if (missingGlyphCode == -1) {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ this.missingGlyphCode = peer.getMissingGlyphCode();
+ }
+ return this.missingGlyphCode;
+ }
+
+ /**
+ * Gets the float value of font's size.
+ *
+ * @return the float value of font's size.
+ */
+ public float getSize2D() {
+ return this.pointSize;
+ }
+
+ /**
+ * Gets the italic angle of this Font.
+ *
+ * @return the italic angle of this Font.
+ */
+ public float getItalicAngle() {
+ FontPeerImpl peer = (FontPeerImpl) this.getPeer();
+ return peer.getItalicAngle();
+ }
+
+ /**
+ * Creates the font with the specified font format and font file.
+ *
+ * @param fontFormat the font format.
+ * @param fontFile the file object represented the input data
+ * for the font.
+ *
+ * @return the Font.
+ *
+ * @throws FontFormatException is thrown if fontFile does not contain
+ * the required font tables for the specified format.
+ * @throws IOException signals that an I/O exception has occurred.
+ */
+ public static Font createFont(int fontFormat, File fontFile)
+ throws FontFormatException, IOException {
+ // ???AWT not supported
+ InputStream is = new FileInputStream(fontFile);
+ try {
+ return createFont(fontFormat, is);
+ } finally {
+ is.close();
+ }
+ }
+
+ /**
+ * Creates the font with the specified font format and input stream.
+ *
+ * @param fontFormat the font format.
+ * @param fontStream the input stream represented input data for
+ * the font.
+ *
+ * @return the Font.
+ *
+ * @throws FontFormatException is thrown if fontFile does not contain
+ * the required font tables for the specified format.
+ * @throws IOException signals that an I/O exception has occurred.
+ */
+ public static Font createFont(int fontFormat, InputStream fontStream)
+ throws FontFormatException, IOException {
+
+ // ???AWT not supported
+
+ BufferedInputStream buffStream;
+ int bRead = 0;
+ int size = 8192;
+ // memory page size, for the faster reading
+ byte buf[] = new byte[size];
+
+ if (fontFormat != TRUETYPE_FONT) { // awt.9A=Unsupported font format
+ throw new IllegalArgumentException(Messages.getString("awt.9A")); //$NON-NLS-1$
+ }
+
+ /* Get font file in system-specific directory */
+
+ File fontFile = Toolkit.getDefaultToolkit().getGraphicsFactory()
+ .getFontManager().getTempFontFile();
+
+ // BEGIN android-modified
+ buffStream = new BufferedInputStream(fontStream, 8192);
+ // END android-modified
+ FileOutputStream fOutStream = new FileOutputStream(fontFile);
+
+ bRead = buffStream.read(buf, 0, size);
+
+ while (bRead != -1) {
+ fOutStream.write(buf, 0, bRead);
+ bRead = buffStream.read(buf, 0, size);
+ }
+
+ buffStream.close();
+ fOutStream.close();
+
+ Font font = null;
+
+ font = Toolkit.getDefaultToolkit().getGraphicsFactory().embedFont(
+ fontFile.getAbsolutePath());
+ if (font == null) { // awt.9B=Can't create font - bad font data
+ throw new FontFormatException(Messages.getString("awt.9B")); //$NON-NLS-1$
+ }
+ return font;
+ }
+
+}
diff --git a/awt/java/awt/FontFormatException.java b/awt/java/awt/FontFormatException.java
new file mode 100644
index 0000000..c017fd2
--- /dev/null
+++ b/awt/java/awt/FontFormatException.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The FontFormatException class is used to provide notification
+ * and information that font can't be created.
+ */
+public class FontFormatException extends Exception {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -4481290147811361272L;
+
+ /**
+ * Instantiates a new font format exception with detailed message.
+ *
+ * @param reason the detailed message.
+ */
+ public FontFormatException(String reason) {
+ super(reason);
+ }
+
+}
diff --git a/awt/java/awt/FontMetrics.java b/awt/java/awt/FontMetrics.java
new file mode 100644
index 0000000..3948d73
--- /dev/null
+++ b/awt/java/awt/FontMetrics.java
@@ -0,0 +1,456 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.geom.Rectangle2D;
+import java.io.Serializable;
+import java.text.CharacterIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The FontMetrics class contains information about the rendering
+ * of a particular font on a particular screen.
+ * <p>
+ * Each character in the Font has three values that help define where
+ * to place it: an ascent, a descent, and an advance. The ascent is the
+ * distance the character extends above the baseline. The descent is
+ * the distance the character extends below the baseline.
+ * The advance width defines the position at which the next character
+ * should be placed.
+ * <p>
+ * An array of characters or a string has an ascent, a descent,
+ * and an advance width too. The ascent or descent of the array
+ * is specified by the maximum ascent or descent of the characters
+ * in the array. The advance width is the sum of the advance widths
+ * of each of the characters in the character array.
+ */
+public abstract class FontMetrics implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 1681126225205050147L;
+
+ /** The font from which the FontMetrics is created. */
+ protected Font font;
+
+ /**
+ * Instantiates a new font metrics from the specified Font.
+ *
+ * @param fnt the Font.
+ */
+ protected FontMetrics(Font fnt) {
+ this.font = fnt;
+ }
+
+ /**
+ * Returns the String representation of this FontMetrics.
+ *
+ * @return the string
+ */
+ @Override
+ public String toString() {
+ return this.getClass().getName() +
+ "[font=" + this.getFont() + //$NON-NLS-1$
+ "ascent=" + this.getAscent() + //$NON-NLS-1$
+ ", descent=" + this.getDescent() + //$NON-NLS-1$
+ ", height=" + this.getHeight() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Gets the font associated with this FontMetrics.
+ *
+ * @return the font associated with this FontMetrics.
+ */
+ public Font getFont() {
+ return font;
+ }
+
+ /**
+ * Gets the height of the text line in this Font.
+ *
+ * @return the height of the text line in this Font.
+ */
+ public int getHeight() {
+ return this.getAscent() + this.getDescent() + this.getLeading();
+ }
+
+ /**
+ * Gets the font ascent of the Font associated with this FontMetrics.
+ * The font ascent is the distance from the font's baseline to
+ * the top of most alphanumeric characters.
+ *
+ * @return the ascent of the Font associated with this FontMetrics.
+ */
+ public int getAscent() {
+ return 0;
+ }
+
+ /**
+ * Gets the font descent of the Font associated with this FontMetrics.
+ * The font descent is the distance from the font's baseline to
+ * the bottom of most alphanumeric characters with descenders.
+ *
+ * @return the descent of the Font associated with this FontMetrics.
+ */
+ public int getDescent() {
+ return 0;
+ }
+
+ /**
+ * Gets the leading of the Font associated with this FontMetrics.
+ *
+ * @return the leading of the Font associated with this FontMetrics.
+ */
+ public int getLeading() {
+ return 0;
+ }
+
+ /**
+ * Gets the LineMetrics object for the specified CharacterIterator
+ * in the specified Graphics.
+ *
+ * @param ci the CharacterIterator.
+ * @param beginIndex the offset.
+ * @param limit the number of characters to be used.
+ * @param context the Graphics.
+ *
+ * @return the LineMetrics object for the specified CharacterIterator
+ * in the specified Graphics.
+ */
+ public LineMetrics getLineMetrics(CharacterIterator ci, int beginIndex,
+ int limit, Graphics context) {
+ return font.getLineMetrics(ci, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the LineMetrics object for the specified String
+ * in the specified Graphics.
+ *
+ * @param str the String.
+ * @param context the Graphics.
+ *
+ * @return the LineMetrics object for the specified String
+ * in the specified Graphics.
+ */
+ public LineMetrics getLineMetrics(String str, Graphics context) {
+ return font.getLineMetrics(str, this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the LineMetrics object for the specified character
+ * array in the specified Graphics.
+ *
+ * @param chars the character array.
+ * @param beginIndex the offset of array.
+ * @param limit the number of characters to be used.
+ * @param context the Graphics.
+ *
+ * @return the LineMetrics object for the specified character
+ * array in the specified Graphics.
+ */
+ public LineMetrics getLineMetrics(char[] chars, int beginIndex, int limit,
+ Graphics context) {
+ return font.getLineMetrics(chars, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the LineMetrics object for the specified String
+ * in the specified Graphics.
+ *
+ * @param str the String.
+ * @param beginIndex the offset.
+ * @param limit the number of characters to be used.
+ * @param context the Graphics.
+ *
+ * @return the LineMetrics object for the specified String
+ * in the specified Graphics.
+ */
+ public LineMetrics getLineMetrics(String str, int beginIndex, int limit,
+ Graphics context) {
+ return font.getLineMetrics(str, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Returns the character's maximum bounds in the specified
+ * Graphics context.
+ *
+ * @param context the Graphics context.
+ *
+ * @return the character's maximum bounds in the specified
+ * Graphics context.
+ */
+ public Rectangle2D getMaxCharBounds(Graphics context) {
+ return this.font.getMaxCharBounds(this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the bounds of the specified CharacterIterator
+ * in the specified Graphics context.
+ *
+ * @param ci the CharacterIterator.
+ * @param beginIndex the begin offset of the array.
+ * @param limit the number of characters.
+ * @param context the Graphics.
+ *
+ * @return the bounds of the specified CharacterIterator
+ * in the specified Graphics context.
+ */
+ public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex,
+ int limit, Graphics context) {
+ return font.getStringBounds(ci, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the bounds of the specified String
+ * in the specified Graphics context.
+ *
+ * @param str the String.
+ * @param beginIndex the begin offset of the array.
+ * @param limit the number of characters.
+ * @param context the Graphics.
+ *
+ * @return the bounds of the specified String
+ * in the specified Graphics context.
+ */
+ public Rectangle2D getStringBounds(String str, int beginIndex, int limit,
+ Graphics context) {
+ return font.getStringBounds(str, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+
+ /**
+ * Gets the bounds of the specified characters array
+ * in the specified Graphics context.
+ *
+ * @param chars the characters array.
+ * @param beginIndex the begin offset of the array.
+ * @param limit the number of characters.
+ * @param context the Graphics.
+ *
+ * @return the bounds of the specified characters array
+ * in the specified Graphics context.
+ */
+ public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit,
+ Graphics context) {
+ return font.getStringBounds(chars, beginIndex, limit,
+ this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Gets the bounds of the specified String
+ * in the specified Graphics context.
+ *
+ * @param str the String.
+ * @param context the Graphics.
+ *
+ * @return the bounds of the specified String
+ * in the specified Graphics context.
+ */
+ public Rectangle2D getStringBounds(String str, Graphics context) {
+ return font.getStringBounds(str, this.getFRCFromGraphics(context));
+ }
+
+ /**
+ * Checks if the Font has uniform line metrics or not.
+ * The Font can contain characters of other fonts for
+ * covering character set. In this case the Font isn't
+ * uniform.
+ *
+ * @return true, if the Font has uniform line metrics,
+ * false otherwise.
+ */
+ public boolean hasUniformLineMetrics() {
+ return this.font.hasUniformLineMetrics();
+ }
+
+ /**
+ * Returns the distance from the leftmost point to the rightmost
+ * point on the string's baseline showing the specified array
+ * of bytes in this Font.
+ *
+ * @param data the array of bytes to be measured.
+ * @param off the start offset.
+ * @param len the number of bytes to be measured.
+ *
+ * @return the advance width of the array.
+ */
+ public int bytesWidth(byte[] data, int off, int len) {
+ int width = 0;
+ if ((off >= data.length) || (off < 0)){
+ // awt.13B=offset off is out of range
+ throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$
+ }
+
+ if ((off+len > data.length)){
+ // awt.13C=number of elemets len is out of range
+ throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$
+ }
+
+ for (int i = off; i < off+len; i++){
+ width += charWidth(data[i]);
+ }
+
+ return width;
+ }
+
+ /**
+ * Returns the distance from the leftmost point to the rightmost
+ * point on the string's baseline showing the specified array
+ * of characters in this Font.
+ *
+ * @param data the array of characters to be measured.
+ * @param off the start offset.
+ * @param len the number of bytes to be measured.
+ *
+ * @return the advance width of the array.
+ */
+ public int charsWidth(char[] data, int off , int len){
+ int width = 0;
+ if ((off >= data.length) || (off < 0)){
+ // awt.13B=offset off is out of range
+ throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$
+ }
+
+ if ((off+len > data.length)){
+ // awt.13C=number of elemets len is out of range
+ throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$
+ }
+
+ for (int i = off; i < off+len; i++){
+ width += charWidth(data[i]);
+ }
+
+ return width;
+ }
+
+ /**
+ * Returns the distance from the leftmost point to the rightmost
+ * point of the specified character in this Font.
+ *
+ * @param ch the specified unicode point code of
+ * character to be measured.
+ *
+ * @return the advance width of the character.
+ */
+ public int charWidth(int ch) {
+ return 0;
+ }
+
+ /**
+ * Returns the distance from the leftmost point to the rightmost
+ * point of the specified character in this Font.
+ *
+ * @param ch the specified character to be measured.
+ *
+ * @return the advance width of the character.
+ */
+ public int charWidth(char ch) {
+ return 0;
+ }
+
+ /**
+ * Gets the maximum advance width of character in this Font.
+ *
+ * @return the maximum advance width of character in this Font.
+ */
+ public int getMaxAdvance() {
+ return 0;
+ }
+
+ /**
+ * Gets the maximum font ascent of the Font associated with
+ * this FontMetrics.
+ *
+ * @return the maximum font ascent of the Font associated with
+ * this FontMetrics.
+ */
+ public int getMaxAscent() {
+ return 0;
+ }
+
+ /**
+ * Gets the maximum font descent of character in this Font.
+ *
+ * @return the maximum font descent of character in this Font.
+ *
+ * @deprecated Replaced by getMaxDescent() method.
+ */
+ @Deprecated
+ public int getMaxDecent() {
+ return 0;
+ }
+
+ /**
+ * Gets the maximum font descent of character in this Font.
+ *
+ * @return the maximum font descent of character in this Font.
+ */
+ public int getMaxDescent() {
+ return 0;
+ }
+
+ /**
+ * Gets the advance widths of the characters in the Font.
+ *
+ * @return the advance widths of the characters in the Font.
+ */
+ public int[] getWidths() {
+ return null;
+ }
+
+ /**
+ * Returns the advance width for the specified String in this Font.
+ *
+ * @param str String to be measured.
+ *
+ * @return the the advance width for the specified String
+ * in this Font.
+ */
+ public int stringWidth(String str) {
+ return 0;
+ }
+
+ /**
+ * Returns FontRenderContext instanse of the Graphics context specified.
+ *
+ * @param context the specified Graphics context
+ *
+ * @return a FontRenderContext of the specified Graphics context.
+ */
+ private FontRenderContext getFRCFromGraphics(Graphics context){
+ FontRenderContext frc;
+ if (context instanceof Graphics2D) {
+ frc = ((Graphics2D)context).getFontRenderContext();
+ } else {
+ frc = new FontRenderContext(null, false, false);
+ }
+
+ return frc;
+ }
+}
+
diff --git a/awt/java/awt/GradientPaint.java b/awt/java/awt/GradientPaint.java
new file mode 100644
index 0000000..0e06528
--- /dev/null
+++ b/awt/java/awt/GradientPaint.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GradientPaint class defines a way to fill a Shape with a linear color
+ * gradient pattern.
+ * <p>
+ * The GradientPaint's fill pattern is determined by two points and two colors,
+ * plus the cyclic mode option.
+ * Each of the two points is painted with its corresponding color, and on
+ * the line segment connecting the two points, the color is proportionally
+ * changed between the two colors. For points on the same line which are not
+ * between the two specified points (outside of the connecting segment) their
+ * color is determined by the cyclic mode option. If the mode is cyclic, then
+ * the rest of the line repeats the color pattern of the connecting segment,
+ * cycling back and forth between the two colors. If not, the mode is acyclic
+ * which means that all points
+ * on the line outside the connecting line segment are given the same
+ * color as the closest of the two specified points.
+ * <p>
+ * The color of points that are not on the line connecting the two
+ * specified points are given by perpendicular projection: by taking
+ * the set of lines perpendicular to the connecting line and for each
+ * one, the whole line is colored with the same color.
+ */
+public class GradientPaint implements Paint {
+
+ /** The start point color. */
+ Color color1;
+
+ /** The end color point. */
+ Color color2;
+
+ /** The location of the start point. */
+ Point2D point1;
+
+ /** The location of the end point. */
+ Point2D point2;
+
+ /** The indicator of cycle filling. If TRUE filling
+ * repeated outside points stripe, if FALSE solid color filling outside. */
+ boolean cyclic;
+
+ /**
+ * Instantiates a new GradientPaint with cyclic or acyclic mode.
+ *
+ * @param point1 the first specified point.
+ * @param color1 the Color of the first specified point.
+ * @param point2 the second specified point.
+ * @param color2 the Color of the second specified point.
+ * @param cyclic the cyclic mode - true if the gradient pattern should cycle
+ * repeatedly between the two colors; false otherwise.
+ */
+ public GradientPaint(Point2D point1, Color color1, Point2D point2,
+ Color color2, boolean cyclic) {
+ if (point1 == null || point2 == null) {
+ // awt.6D=Point is null
+ throw new NullPointerException(Messages.getString("awt.6D")); //$NON-NLS-1$
+ }
+ if (color1 == null || color2 == null) {
+ // awt.6E=Color is null
+ throw new NullPointerException(Messages.getString("awt.6E")); //$NON-NLS-1$
+ }
+
+ this.point1 = point1;
+ this.point2 = point2;
+ this.color1 = color1;
+ this.color2 = color2;
+ this.cyclic = cyclic;
+ }
+
+ /**
+ * Instantiates a new GradientPaint with cyclic or acyclic mode;
+ * points are specified by coordinates.
+ *
+ * @param x1 the X coordinate of the first point.
+ * @param y1 the Y coordinate of the first point.
+ * @param color1 the color of the first point.
+ * @param x2 the X coordinate of the second point.
+ * @param y2 the Y coordinate of the second point.
+ * @param color2 the color of the second point.
+ * @param cyclic the cyclic mode - true if the gradient pattern should cycle
+ * repeatedly between the two colors; false otherwise.
+ */
+ public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2,
+ boolean cyclic) {
+ this(new Point2D.Float(x1, y1), color1, new Point2D.Float(x2, y2), color2, cyclic);
+ }
+
+ /**
+ * Instantiates a new acyclic GradientPaint;
+ * points are specified by coordinates.
+ *
+ * @param x1 the X coordinate of the first point.
+ * @param y1 the Y coordinate of the first point.
+ * @param color1 the color of the first point.
+ * @param x2 the X coordinate of the second point.
+ * @param y2 the Y coordinate of the second point.
+ * @param color2 the color of the second point.
+ */
+ public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2) {
+ this(x1, y1, color1, x2, y2, color2, false);
+ }
+
+ /**
+ * Instantiates a new acyclic GradientPaint.
+ *
+ * @param point1 the first specified point.
+ * @param color1 the Color of the first specified point.
+ * @param point2 the second specified point.
+ * @param color2 the Color of the second specified point.
+ */
+ public GradientPaint(Point2D point1, Color color1, Point2D point2, Color color2) {
+ this(point1, color1, point2, color2, false);
+ }
+
+ /**
+ * Creates PaintContext for a color pattern generating.
+ *
+ * @param cm the ColorModel of the Paint data.
+ * @param deviceBounds the bounding Rectangle of graphics primitives
+ * being rendered in the device space.
+ * @param userBounds tthe bounding Rectangle of graphics primitives
+ * being rendered in the user space.
+ * @param t the AffineTransform from user space into device space.
+ * @param hints the RrenderingHints object.
+ *
+ * @return the PaintContext for color pattern generating.
+ *
+ * @see java.awt.Paint#createContext(java.awt.image.ColorModel, java.awt.Rectangle, java.awt.geom.Rectangle2D, java.awt.geom.AffineTransform, java.awt.RenderingHints)
+ */
+ public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
+ Rectangle2D userBounds, AffineTransform t, RenderingHints hints) {
+ return new GradientPaintContext(cm, t, point1, color1, point2, color2, cyclic);
+ }
+
+ /**
+ * Gets the color of the first point.
+ *
+ * @return the color of the first point.
+ */
+ public Color getColor1() {
+ return color1;
+ }
+
+ /**
+ * Gets the color of the second point.
+ *
+ * @return the color of the second point.
+ */
+ public Color getColor2() {
+ return color2;
+ }
+
+ /**
+ * Gets the first point.
+ *
+ * @return the Point object - the first point.
+ */
+ public Point2D getPoint1() {
+ return point1;
+ }
+
+ /**
+ * Gets the second point.
+ *
+ * @return the Point object - the second point.
+ */
+ public Point2D getPoint2() {
+ return point2;
+ }
+
+ /**
+ * Gets the transparency mode for the GradientPaint.
+ *
+ * @return the transparency mode for the GradientPaint.
+ *
+ * @see java.awt.Transparency#getTransparency()
+ */
+ public int getTransparency() {
+ int a1 = color1.getAlpha();
+ int a2 = color2.getAlpha();
+ return (a1 == 0xFF && a2 == 0xFF) ? OPAQUE : TRANSLUCENT;
+ }
+
+ /**
+ * Returns the GradientPaint mode: true for cyclic mode, false for
+ * acyclic mode.
+ *
+ * @return true if the gradient cycles repeatedly between the two colors;
+ * false otherwise.
+ */
+ public boolean isCyclic() {
+ return cyclic;
+ }
+}
diff --git a/awt/java/awt/GradientPaintContext.java b/awt/java/awt/GradientPaintContext.java
new file mode 100644
index 0000000..74575f5
--- /dev/null
+++ b/awt/java/awt/GradientPaintContext.java
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+class GradientPaintContext implements PaintContext {
+
+ /**
+ * The size of noncyclic part of color lookup table
+ */
+ static int LOOKUP_SIZE = 256;
+
+ /**
+ * The index mask to lookup color in the table
+ */
+ static int LOOKUP_MASK = 0x1FF;
+
+ /**
+ * The min value equivalent to zero. If absolute value less then ZERO it considered as zero.
+ */
+ static double ZERO = 1E-10;
+
+ /**
+ * The ColorModel user defined for PaintContext
+ */
+ ColorModel cm;
+
+ /**
+ * The indicator of cycle filling.
+ */
+ boolean cyclic;
+
+ /**
+ * The integer color value of the start point
+ */
+ int c1;
+
+ /**
+ * The integer color value of the end point
+ */
+ int c2;
+
+ /**
+ * The lookup gradient color table
+ */
+ int[] table;
+
+ /**
+ * The tempopary pre-calculated value to evalutae color index
+ */
+ int dx;
+
+ /**
+ * The tempopary pre-calculated value to evalutae color index
+ */
+ int dy;
+
+ /**
+ * The tempopary pre-calculated value to evalutae color index
+ */
+ int delta;
+
+ /**
+ * Constructs a new GradientPaintcontext
+ * @param cm - not used
+ * @param t - the fill transformation
+ * @param point1 - the start fill point
+ * @param color1 - color of the start point
+ * @param point2 - the end fill point
+ * @param color2 - color of the end point
+ * @param cyclic - the indicator of cycle filling
+ */
+ GradientPaintContext(ColorModel cm, AffineTransform t, Point2D point1, Color color1, Point2D point2, Color color2, boolean cyclic) {
+ this.cyclic = cyclic;
+ this.cm = ColorModel.getRGBdefault();
+
+ c1 = color1.getRGB();
+ c2 = color2.getRGB();
+
+ double px = point2.getX() - point1.getX();
+ double py = point2.getY() - point1.getY();
+
+ Point2D p = t.transform(point1, null);
+ Point2D bx = new Point2D.Double(px, py);
+ Point2D by = new Point2D.Double(py, -px);
+
+ t.deltaTransform(bx, bx);
+ t.deltaTransform(by, by);
+
+ double vec = bx.getX() * by.getY() - bx.getY() * by.getX();
+
+ if (Math.abs(vec) < ZERO) {
+ dx = dy = delta = 0;
+ table = new int[1];
+ table[0] = c1;
+ } else {
+ double mult = LOOKUP_SIZE * 256 / vec;
+ dx = (int)(by.getX() * mult);
+ dy = (int)(by.getY() * mult);
+ delta = (int)((p.getX() * by.getY() - p.getY() * by.getX()) * mult);
+ createTable();
+ }
+ }
+
+ /**
+ * Create color index lookup table. Calculate 256 step trasformation from
+ * the start point color to the end point color. Colors multiplied by 256 to do integer calculations.
+ */
+ void createTable() {
+ double ca = (c1 >> 24) & 0xFF;
+ double cr = (c1 >> 16) & 0xFF;
+ double cg = (c1 >> 8) & 0xFF;
+ double cb = c1 & 0xFF;
+
+ double k = 1.0 / LOOKUP_SIZE;
+ double da = (((c2 >> 24) & 0xFF) - ca) * k;
+ double dr = (((c2 >> 16) & 0xFF) - cr) * k;
+ double dg = (((c2 >> 8) & 0xFF) - cg) * k;
+ double db = ((c2 & 0xFF) - cb) * k;
+
+ table = new int[cyclic ? LOOKUP_SIZE + LOOKUP_SIZE : LOOKUP_SIZE];
+ for(int i = 0; i < LOOKUP_SIZE; i++) {
+ table[i] =
+ (int)ca << 24 |
+ (int)cr << 16 |
+ (int)cg << 8 |
+ (int)cb;
+ ca += da;
+ cr += dr;
+ cg += dg;
+ cb += db;
+ }
+ if (cyclic) {
+ for(int i = 0; i < LOOKUP_SIZE; i++) {
+ table[LOOKUP_SIZE + LOOKUP_SIZE - 1 - i] = table[i];
+ }
+ }
+ }
+
+ public ColorModel getColorModel() {
+ return cm;
+ }
+
+ public void dispose() {
+ }
+
+ public Raster getRaster(int x, int y, int w, int h) {
+ WritableRaster rast = cm.createCompatibleWritableRaster(w, h);
+
+ int[] buf = ((DataBufferInt)rast.getDataBuffer()).getData();
+
+ int c = x * dy - y * dx - delta;
+ int cx = dy;
+ int cy = - w * dy - dx;
+ int k = 0;
+
+ if (cyclic) {
+ for(int j = 0; j < h; j++) {
+ for(int i = 0; i < w; i++) {
+ buf[k++] = table[(c >> 8) & LOOKUP_MASK];
+ c += cx;
+ }
+ c += cy;
+ }
+ } else {
+ for(int j = 0; j < h; j++) {
+ for(int i = 0; i < w; i++) {
+ int index = c >> 8;
+ buf[k++] = index < 0 ? c1 : index >= LOOKUP_SIZE ? c2 : table[index];
+ c += cx;
+ }
+ c += cy;
+ }
+ }
+
+ return rast;
+ }
+
+}
+
diff --git a/awt/java/awt/Graphics.java b/awt/java/awt/Graphics.java
new file mode 100644
index 0000000..c20f6bc
--- /dev/null
+++ b/awt/java/awt/Graphics.java
@@ -0,0 +1,737 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.image.ImageObserver;
+import java.text.AttributedCharacterIterator;
+
+/**
+ * The abstract Graphics class allows applications to draw on a screen
+ * or other rendering target. There are several properties which
+ * define rendering options: origin point, clipping area, color, font.
+ * <br><br>
+ * The origin point specifies the beggining of the clipping area coordinate
+ * system. All coordinates used in rendering operations are computed with
+ * respect to this point. The clipping area defines the boundaries where
+ * rendering operations can be performed. Rendering operations can't modify
+ * pixels outside of the clipping area.
+ * <br><br>
+ * The draw and fill methods allow applications to drawing shapes, text,
+ * images with specified font and color options in the specified part
+ * of the screen.
+ *
+ */
+public abstract class Graphics {
+
+ // Constructors
+
+ /**
+ * Instantiates a new Graphics. This constructor is default for Graphics and
+ * can not be called directly.
+ */
+ protected Graphics() {
+ }
+
+ // Public methods
+
+ /**
+ * Creates a copy of the Graphics object with a new origin and a new
+ * specified clip area. The new clip area is the rectangle defined by
+ * the origin point with coordinates X,Y and the given width and height.
+ * The coordinates of all subsequent rendering operations will be computed
+ * with respect to the new origin and can be performed only within the
+ * range of the clipping area dimentions.
+ *
+ * @param x the X coordinate of the original point
+ * @param y the Y coordinate of the original point
+ * @param width the width of clipping area
+ * @param height the height of clipping area
+ *
+ * @return the Graphics object with new origin point and clipping area.
+ */
+ public Graphics create(int x, int y, int width, int height) {
+ Graphics res = create();
+ res.translate(x, y);
+ res.clipRect(0, 0, width, height);
+ return res;
+ }
+
+ /**
+ * Draws the higlighted outline of a rectangle.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ * @param raised a boolean value that determines whether the rectangle
+ * is drawn as raised or indented.
+ */
+ public void draw3DRect(int x, int y, int width, int height, boolean raised) {
+ // Note: lighter/darker colors should be used to draw 3d rect.
+ // The resulting rect is (width+1)x(height+1). Stroke and paint attributes of
+ // the Graphics2D should be reset to the default values.
+ // fillRect is used instead of drawLine to bypass stroke
+ // reset/set and rasterization.
+
+ Color color = getColor();
+ Color colorUp, colorDown;
+ if (raised) {
+ colorUp = color.brighter();
+ colorDown = color.darker();
+ } else {
+ colorUp = color.darker();
+ colorDown = color.brighter();
+ }
+
+ setColor(colorUp);
+ fillRect(x, y, width, 1);
+ fillRect(x, y+1, 1, height);
+
+ setColor(colorDown);
+ fillRect(x+width, y, 1, height);
+ fillRect(x+1, y+height, width, 1);
+ }
+
+ /**
+ * Draws the text represented by byte array. This method uses the current
+ * font and color for rendering.
+ *
+ * @param bytes the byte array which contains the text to be drawn.
+ * @param off the offset within the byte array of the text to be drawn.
+ * @param len the number of bytes of text to draw.
+ * @param x the X coordinate where the text is to be drawn.
+ * @param y the Y coordinate where the text is to be drawn.
+ */
+ public void drawBytes(byte[] bytes, int off, int len, int x, int y) {
+ drawString(new String(bytes, off, len), x, y);
+ }
+
+ /**
+ * Draws the text represented by character array. This method uses the
+ * current font and color for rendering.
+ *
+ * @param chars the character array.
+ * @param off the offset within the character array of the text to be drawn.
+ * @param len the number of characters which will be drawn.
+ * @param x the X coordinate where the text is to be drawn.
+ * @param y the Y coordinate where the text is to be drawn.
+ */
+ public void drawChars(char[] chars, int off, int len, int x, int y) {
+ drawString(new String(chars, off, len), x, y);
+ }
+
+ /**
+ * Draws the outline of a polygon which is defined by Polygon object.
+ *
+ * @param p the Polygon object.
+ */
+ public void drawPolygon(Polygon p) {
+ drawPolygon(p.xpoints, p.ypoints, p.npoints);
+ }
+
+ /**
+ * Draws the rectangle with the specified width and length and top left
+ * corner coordinates.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ */
+ public void drawRect(int x, int y, int width, int height) {
+ int []xpoints = {x, x, x+width, x+width};
+ int []ypoints = {y, y+height, y+height, y};
+
+ drawPolygon(xpoints, ypoints, 4);
+ }
+
+ /**
+ * Fills the higlighted outline of a rectangle.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ * @param raised a boolean value that determines whether the rectangle
+ * is drawn as raised or indented.
+ */
+ public void fill3DRect(int x, int y, int width, int height, boolean raised) {
+ // Note: lighter/darker colors should be used to draw 3d rect.
+ // The resulting rect is (width)x(height), same as fillRect.
+ // Stroke and paint attributes of the Graphics2D should be reset
+ // to the default values. fillRect is used instead of drawLine to
+ // bypass stroke reset/set and line rasterization.
+
+ Color color = getColor();
+ Color colorUp, colorDown;
+ if (raised) {
+ colorUp = color.brighter();
+ colorDown = color.darker();
+ setColor(color);
+ } else {
+ colorUp = color.darker();
+ colorDown = color.brighter();
+ setColor(colorUp);
+ }
+
+ width--;
+ height--;
+ fillRect(x+1, y+1, width-1, height-1);
+
+ setColor(colorUp);
+ fillRect(x, y, width, 1);
+ fillRect(x, y+1, 1, height);
+
+ setColor(colorDown);
+ fillRect(x+width, y, 1, height);
+ fillRect(x+1, y+height, width, 1);
+ }
+
+ /**
+ * Fills the polygon with the current color.
+ *
+ * @param p the Polygon object.
+ */
+ public void fillPolygon(Polygon p) {
+ fillPolygon(p.xpoints, p.ypoints, p.npoints);
+ }
+
+ /**
+ * Disposes of the Graphics.
+ */
+ @Override
+ public void finalize() {
+ }
+
+ /**
+ * Gets the bounds of the current clipping area as a rectangle
+ * and copies it to an existing rectangle.
+ *
+ * @param r a Rectangle object where the current clipping area
+ * bounds are to be copied.
+ *
+ * @return the bounds of the current clipping area.
+ */
+ public Rectangle getClipBounds(Rectangle r) {
+ Shape clip = getClip();
+
+ if (clip != null) {
+ // TODO: Can we get shape bounds without creating Rectangle object?
+ Rectangle b = clip.getBounds();
+ r.x = b.x;
+ r.y = b.y;
+ r.width = b.width;
+ r.height = b.height;
+ }
+
+ return r;
+ }
+
+ /**
+ * Gets the bounds of the current clipping area as a rectangle.
+ *
+ * @return a Rectangle object
+ *
+ * @deprecated Use {@link #getClipBounds()}
+ */
+ @Deprecated
+ public Rectangle getClipRect() {
+ return getClipBounds();
+ }
+
+ /**
+ * Gets the font metrics of the current font.
+ * The font metrics object contains information about the rendering
+ * of a particular font.
+ *
+ * @return the font metrics of current font.
+ */
+ public FontMetrics getFontMetrics() {
+ return getFontMetrics(getFont());
+ }
+
+ /**
+ * Determines whether or not the specified rectangle intersects the
+ * current clipping area.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ *
+ * @return true, if the specified rectangle intersects the current clipping area,
+ * overwise false.
+ */
+ public boolean hitClip(int x, int y, int width, int height) {
+ // TODO: Create package private method Rectangle.intersects(int, int, int, int);
+ return getClipBounds().intersects(new Rectangle(x, y, width, height));
+ }
+
+ /**
+ * Returns string which represents this Graphics object.
+ *
+ * @return the string which represents this Graphics object.
+ */
+ @Override
+ public String toString() {
+ // TODO: Think about string representation of Graphics.
+ return "Graphics"; //$NON-NLS-1$
+ }
+
+ // Abstract methods
+
+ /**
+ * Clears the specified rectangle. This method fills specified rectangle
+ * with background color.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ */
+ public abstract void clearRect(int x, int y, int width, int height);
+
+ /**
+ * Intersects the current clipping area with a new rectangle.
+ * If the current clipping area is not defined, the rectangle
+ * becomes a new clipping area. Rendering operations are only allowed
+ * within the new the clipping area.
+ *
+ * @param x the X coordinate of the rectangle for intersection.
+ * @param y the Y coordinate of the rectangle for intersection.
+ * @param width the width of the rectangle for intersection.
+ * @param height the height of the rectangle for intersection.
+ */
+ public abstract void clipRect(int x, int y, int width, int height);
+
+ /**
+ * Copies the rectangle area to another area specified by
+ * a distance (dx, dy) from the original rectangle's location.
+ * Positive dx and dy values give a new location defined by
+ * translation to the right and down from the original location,
+ * negative dx and dy values - to the left and up.
+ * <br><br>
+ *
+ * @param sx the X coordinate of the rectangle which will be copied.
+ * @param sy the Y coordinate of the rectangle which will be copied.
+ * @param width the width of the rectangle which will be copied.
+ * @param height the height of the rectangle which will be copied.
+ * @param dx the horizontal distance from the source rectangle's
+ * location to the copy's location.
+ * @param dy the vertical distance from the source rectangle's
+ * location to the copy's location.
+ */
+ public abstract void copyArea(int sx, int sy, int width, int height, int dx, int dy);
+
+ /**
+ * Creates a new copy of this Graphics.
+ *
+ * @return a new Graphics context which is a copy of this Graphics.
+ */
+ public abstract Graphics create();
+
+ /**
+ * Disposes of the Graphics. This Graphics object can not be used after
+ * calling this method.
+ */
+ public abstract void dispose();
+
+ /**
+ * Draws the arc covering the specified rectangle and using the current color.
+ * The rectangle is defined by the origin point (X, Y) and dimentions
+ * (width and height). The arc center is the the center of specified rectangle.
+ * The angle origin is 3 o'clock position, the positive angle is counted as a
+ * counter-clockwise rotation, the negotive angle is counted as clockwise rotation.
+ *
+ * @param x the X origin coordinate of the rectangle which scales the arc.
+ * @param y the Y origin coordinate of the rectangle which scales the arc.
+ * @param width the width of the rectangle which scales the arc.
+ * @param height the height of the rectangle which scales the arc.
+ * @param sa start angle - the origin angle of arc.
+ * @param ea arc angle - the angular arc value relative to the start angle.
+ */
+ public abstract void drawArc(int x, int y, int width, int height, int sa, int ea);
+
+ /**
+ * Draws the specified image with the defined background color.
+ * The top left corner of image will be drawn at point (x, y)
+ * in current coordinate system. The image loading process notifies the
+ * specified Image Observer. This method returns true if the image
+ * has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param x the X coordinate of the image top left corner.
+ * @param y the Y coordinate of the image top left corner.
+ * @param bgcolor the background color.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer);
+
+ /**
+ * Draws the specified image.
+ * The top left corner of image will be drawn at point (x, y)
+ * in current coordinate system. The image loading process notifies the
+ * specified Image Observer. This method returns true if the image
+ * has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param x the X coordinate of the image top left corner.
+ * @param y the Y coordinate of the image top left corner.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int x, int y, ImageObserver observer);
+
+ /**
+ * Scales the specified image to fit in the specified rectangle and
+ * draws it with the defined background color. The top left corner
+ * of the image will be drawn at the point (x, y) in current coordinate
+ * system. The non-opaque pixels will be drawn in the background color.
+ * The image loading process notifies the specified Image Observer.
+ * This method returns true if the image has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param x the X coordinate of the image's top left corner.
+ * @param y the Y coordinate of the image's top left corner.
+ * @param width the width of rectangle which scales the image.
+ * @param height the height of rectangle which scales the image.
+ * @param bgcolor the background color.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer);
+
+ /**
+ * Scales the specified image to fit in the specified rectangle and
+ * draws it. The top left corner of the image will be drawn at the
+ * point (x, y) in current coordinate system. The image loading process
+ * notifies the specified Image Observer.
+ * This method returns true if the image has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param x the X coordinate of the image top left corner.
+ * @param y the Y coordinate of the image top left corner.
+ * @param width the width of rectangle which scales the image.
+ * @param height the height of rectangle which scales the image.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer);
+
+ /**
+ * Scales the specified area of the specified image to fit in the rectangle area
+ * defined by its corners coordinates and draws the sub-image with the specified
+ * background color. The sub-image to be drawn is defined by its top left
+ * corner coordinates (sx1, sy1) and bottom right corner coordinates (sx2, sy2)
+ * computed with respect to the origin (top left corner) of the source image.
+ * The non opaque pixels will be drawn in the background color. The
+ * image loading process notifies specified Image Observer.
+ * This method returns true if the image
+ * has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param dx1 the X top left corner coordinate of the destination rectangle area.
+ * @param dy1 the Y top left corner coordinate of the destination rectangle area.
+ * @param dx2 the X bottom right corner coordinate of the destination rectangle area.
+ * @param dy2 the Y bottom right corner coordinate of the destination rectangle area.
+ * @param sx1 the X top left corner coordinate of the area to be drawn within the source image.
+ * @param sy1 the Y top left corner coordinate of the area to be drawn within the source image.
+ * @param sx2 the X bottom right corner coordinate of the area to be drawn within the source image.
+ * @param sy2 the Y bottom right corner coordinate of the area to be drawn within the source image.
+ * @param bgcolor the background color.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer);
+
+ /**
+ * Scales the specified area of the specified image to fit in the rectangle area
+ * defined by its corners coordinates and draws the sub-image. The sub-image
+ * to be drawn is defined by its top left
+ * corner coordinates (sx1, sy1) and bottom right corner coordinates (sx2, sy2)
+ * computed with respect to the origin (top left corner) of the source image.
+ * The image loading process notifies specified Image Observer.
+ * This method returns true if the image
+ * has loaded, overwise it returns false.
+ *
+ * @param img the image which will be drawn.
+ * @param dx1 the X top left corner coordinate of the destination rectangle area.
+ * @param dy1 the Y top left corner coordinate of the destination rectangle area.
+ * @param dx2 the X bottom right corner coordinate of the destination rectangle area.
+ * @param dy2 the Y bottom right corner coordinate of the destination rectangle area.
+ * @param sx1 the X top left corner coordinate of the area to be drawn within the source image.
+ * @param sy1 the Y top left corner coordinate of the area to be drawn within the source image.
+ * @param sx2 the X bottom right corner coordinate of the area to be drawn within the source image.
+ * @param sy2 the Y bottom right corner coordinate of the area to be drawn within the source image.
+ * @param observer the ImageObserver object which should be notified about image loading process.
+ *
+ * @return true, if loading image is successful or image is null, overwise false.
+ */
+ public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer);
+
+ /**
+ * Draws a line from the point (x1, y1) to the point (x2, y2).
+ * This method draws the line with current color
+ * which can be changed by setColor(Color c) method.
+ *
+ * @param x1 the X coordinate of the first point.
+ * @param y1 the Y coordinate of the first point.
+ * @param x2 the X coordinate of the second point.
+ * @param y2 the Y coordinate of the second point.
+ */
+ public abstract void drawLine(int x1, int y1, int x2, int y2);
+
+ /**
+ * Draws the ouline of an oval to fit in the rectangle defined
+ * by the given width, height, and top left corner.
+ *
+ * @param x the X top left corner oval coordinate
+ * @param y the Y top left corner oval coordinate
+ * @param width the oval width
+ * @param height the oval height
+ */
+ public abstract void drawOval(int x, int y, int width, int height);
+
+ /**
+ * Draws the outline of a polygon. The polygon vertices are defined by points
+ * with xpoints[i], ypoints[i] as coordinates. The polygon edges are the
+ * lines from the points with (xpoints[i-1], ypoints[i-1]) coordinates to
+ * the points with (xpoints[i], ypoints[i]) coordinates, for 0 < i < npoints +1.
+ *
+ * @param xpoints the array of X coordinates of the polygon vertices.
+ * @param ypoints the array of Y coordinates of the polygon vertices.
+ * @param npoints the number of polygon vertices/points.
+ */
+ public abstract void drawPolygon(int[] xpoints, int[] ypoints, int npoints);
+
+ /**
+ * Draws a set of connected lines which are defined by the x and y coordinate arrays.
+ * The polyline is closed if coordinates of the first point are the same as
+ * coordinates of the last point.
+ *
+ * @param xpoints the array of X point coordinates.
+ * @param ypoints the array of Y point coordinates.
+ * @param npoints the number of points.
+ */
+ public abstract void drawPolyline(int[] xpoints, int[] ypoints, int npoints);
+
+ /**
+ * Draws the outline of a rectangle with round corners.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ * @param arcWidth the arc width for the corners.
+ * @param arcHeight the arc height for the corners.
+ */
+ public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight);
+
+ /**
+ * Draws a text defined by an iterator. The iterator should specify the font
+ * for every character.
+ *
+ * @param iterator the iterator.
+ * @param x the X coordinate of the firt character.
+ * @param y the Y coordinate of the first character.
+ */
+ public abstract void drawString(AttributedCharacterIterator iterator, int x, int y);
+
+ /**
+ * Draws a text defined by a string. This method draws the text with current
+ * font and color.
+ *
+ * @param str the string.
+ * @param x the X coordinate of the firt character.
+ * @param y the Y coordinate of the first character.
+ */
+ public abstract void drawString(String str, int x, int y);
+
+ /**
+ * Fills the arc covering the rectangle and using the current color.
+ * The rectangle is defined by the origin point (X, Y) and dimentions (width and height).
+ * The arc center is the the center of specified rectangle.
+ * The angle origin is at the 3 o'clock position, and a positive angle gives
+ * counter-clockwise rotation, a negative angle gives clockwise rotation.
+ *
+ * @param x the X origin coordinate of the rectangle which scales the arc.
+ * @param y the Y origin coordinate of the rectangle which scales the arc.
+ * @param width the width of the rectangle which scales the arc.
+ * @param height the height of the rectangle which scales the arc.
+ * @param sa start angle - the origin angle of arc.
+ * @param ea arc angle - the angular arc value relative to the start angle.
+ */
+ public abstract void fillArc(int x, int y, int width, int height, int sa, int ea);
+
+ /**
+ * Fills an oval with the current color where the oval is defined by the
+ * bounding rectangle with the given width, height, and top left corner.
+ *
+ * @param x the X top left corner oval coordinate.
+ * @param y the Y top left corner oval coordinate.
+ * @param width the oval width.
+ * @param height the oval height.
+ */
+ public abstract void fillOval(int x, int y, int width, int height);
+
+ /**
+ * Fills a polygon with the current color. The polygon vertices are defined by the points
+ * with xpoints[i], ypoints[i] as coordinates. The polygon edges are the
+ * lines from the points with (xpoints[i-1], ypoints[i-1]) coordinates to
+ * the points with (xpoints[i], ypoints[i]) coordinates, for 0 < i < npoints +1.
+ *
+ * @param xpoints the array of X coordinates of the polygon vertices.
+ * @param ypoints the array of Y coordinates of the polygon vertices.
+ * @param npoints the number of polygon vertices/points.
+ */
+ public abstract void fillPolygon(int[] xpoints, int[] ypoints, int npoints);
+
+ /**
+ * Fills a rectangle with the current color.
+ * The rectangle is defined by its width and length and top left corner coordinates.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ */
+ public abstract void fillRect(int x, int y, int width, int height);
+
+ /**
+ * Fills a round cornered rectangle with the current color.
+ *
+ * @param x the X coordinate of the top left corner of the bounding rectangle.
+ * @param y the Y coordinate of the top left corner of the bounding rectangle.
+ * @param width the width of the bounding rectangle.
+ * @param height the height of the bounding rectangle.
+ * @param arcWidth the arc width at the corners.
+ * @param arcHeight the arc height at the corners.
+ */
+ public abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight);
+
+ /**
+ * Gets the clipping area.
+ * <br> <br>
+ *
+ * @return a Shape object of the clipping area or null if it is not set.
+ */
+ public abstract Shape getClip();
+
+ /**
+ * Gets the bounds of the current clipping area as a rectangle.
+ *
+ * @return a Rectangle object which represents the bounds of the current clipping area.
+ */
+ public abstract Rectangle getClipBounds();
+
+ /**
+ * Gets the current color of Graphics.
+ *
+ * @return the current color.
+ */
+ public abstract Color getColor();
+
+ /**
+ * Gets the current font of Graphics.
+ *
+ * @return the current font.
+ */
+ public abstract Font getFont();
+
+ /**
+ * Gets the font metrics of the specified font.
+ * The font metrics object contains information about the rendering of a particular font.
+ *
+ * @param font the specified font
+ *
+ * @return the font metrics for the specified font.
+ */
+ public abstract FontMetrics getFontMetrics(Font font);
+
+ /**
+ * Sets the new clipping area specified by rectangle. The new clipping area
+ * doesn't depend on the window's visibility. Rendering operations can't be performed
+ * outside new clipping area.
+ *
+ * @param x the X coordinate of the new clipping rectangle.
+ * @param y the Y coordinate of the new clipping rectangle.
+ * @param width the width of the new clipping rectangle.
+ * @param height the height of the new clipping rectangle.
+ */
+ public abstract void setClip(int x, int y, int width, int height);
+
+ /**
+ * Sets the new clipping area to be the area specified by Shape object.
+ * The new clipping area doesn't depend on the window's visibility.
+ * Rendering operations can't be performed outside new clipping area.
+ *
+ * @param clip a Shape object which representes new clipping area.
+ */
+ public abstract void setClip(Shape clip);
+
+ /**
+ * Sets the current Graphics color. All rendering operations with this Graphics
+ * will use this color.
+ *
+ * @param c the new color.
+ */
+ public abstract void setColor(Color c);
+
+ /**
+ * Sets the current Graphics font. All rendering operations with this Graphics
+ * will use this font.
+ *
+ * @param font the new font.
+ */
+ public abstract void setFont(Font font);
+
+ /**
+ * Sets the paint mode for the Graphics which overwrites all rendering
+ * operations with the current color.
+ *
+ */
+ public abstract void setPaintMode();
+
+ /**
+ * Sets the XOR mode for the Graphics which changes a pixel from
+ * the current color to the specified XOR color.
+ * <br> <br>
+ *
+ * @param color the new XOR mode
+ */
+ public abstract void setXORMode(Color color);
+
+ /**
+ * Translates the origin of Graphics current coordinate system
+ * to the point with X, Y coordinates in the current coordinate system.
+ * All rendering operation in this Graphics will be related to the new origin.
+ *
+ * @param x the X coordinate of the origin
+ * @param y the Y coordinate of the origin
+ */
+ public abstract void translate(int x, int y);
+}
diff --git a/awt/java/awt/Graphics2D.java b/awt/java/awt/Graphics2D.java
new file mode 100644
index 0000000..2ff5e0c
--- /dev/null
+++ b/awt/java/awt/Graphics2D.java
@@ -0,0 +1,456 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.awt.font.GlyphVector;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+/**
+ * The Graphics2D class extends Graphics class and provides more capabilities
+ * for rendering text, images, shapes. This provides methods to peform
+ * transformation of coordinate system, color management, and text layout.
+ * The following attributes exist for rendering:
+ * <ul>
+ * <li>Color - current Graphics2D color;</li>
+ * <li>Font - current Graphics2D font;</li>
+ * <li>Stroke - pen with a width of 1 pixel;</li>
+ * <li>Transform - current Graphics2D Transformation;</li>
+ * <li>Composite - alpha compositing rules for combining source and destination colors.</li>
+ * </ul>
+ */
+public abstract class Graphics2D extends Graphics {
+
+ /**
+ * Instantiates a new Graphics2D object. This constructor should never be
+ * called directly.
+ */
+ protected Graphics2D() {
+ super();
+ }
+
+ /**
+ * Adds preferences for the rendering algorithms. The preferences
+ * are arbitrary and specified by Map objects. All specified by Map object
+ * preferencies can be modified.
+ *
+ * @param hints the rendering hints.
+ */
+ public abstract void addRenderingHints(Map<?, ?> hints);
+
+ /**
+ * Intersects the current clipping area with the specified Shape
+ * and the result becomes a new clipping area.
+ * If current clipping area is not defined, the Shape
+ * becomes the new clipping area. No rendering operations
+ * are allowed outside the clipping area.
+ *
+ * @param s the specified Shape object which will be intersected
+ * with current clipping area.
+ */
+ public abstract void clip(Shape s);
+
+ /**
+ * Draws the outline of the specified Shape.
+ *
+ * @param s the Shape which ouline is drawn.
+ */
+ public abstract void draw(Shape s);
+
+ /**
+ * Draws the specified GlyphVector object's text at the point x, y.
+ *
+ * @param g the GlyphVector object to be drawn.
+ * @param x the X position where the GlyphVector's text should
+ * be rendered.
+ * @param y the Y position where the GlyphVector's text should
+ * be rendered.
+ */
+ public abstract void drawGlyphVector(GlyphVector g, float x, float y);
+
+ /**
+ * Draws the BufferedImage -- modified according to the operation
+ * BufferedImageOp -- at the point x, y.
+ *
+ * @param img the BufferedImage to be rendered.
+ * @param op the filter to be applied to the image before rendering.
+ * @param x the X coordinate of the point where the image's upper left corner
+ * will be placed.
+ * @param y the Y coordinate of the point where the image's upper left corner
+ * will be placed.
+ */
+ public abstract void drawImage(BufferedImage img, BufferedImageOp op, int x, int y);
+
+ /**
+ * Draws BufferedImage transformed from image space into user space
+ * according to the AffineTransform xform and notifies the ImageObserver.
+ *
+ * @param img the BufferedImage to be rendered.
+ * @param xform the affine transformation from the image to the user space.
+ * @param obs the ImageObserver to be notified about the image conversion.
+ *
+ * @return true, if the image is successfully loaded and rendered,
+ * or it's null, otherwise false.
+ */
+ public abstract boolean drawImage(Image img, AffineTransform xform, ImageObserver obs);
+
+ /**
+ * Draws a RenderableImage which is transformed from image space into user
+ * according to the AffineTransform xform.
+ *
+ * @param img the RenderableImage to be rendered.
+ * @param xform the affine transformation from image to user space.
+ */
+ public abstract void drawRenderableImage(RenderableImage img, AffineTransform xform);
+
+ /**
+ * Draws a RenderedImage which is transformed from image space into user
+ * according to the AffineTransform xform.
+ *
+ * @param img the RenderedImage to be rendered.
+ * @param xform the affine transformation from image to user space.
+ */
+ public abstract void drawRenderedImage(RenderedImage img, AffineTransform xform);
+
+ /**
+ * Draws the string specified by the AttributedCharacterIterator.
+ * The first character's position is specified by the X, Y parameters.
+ *
+ * @param iterator whose text is drawn.
+ * @param x the X position where the first character is drawn.
+ * @param y the Y position where the first character is drawn.
+ */
+ public abstract void drawString(AttributedCharacterIterator iterator, float x, float y);
+
+ /**
+ * Draws the string specified by the AttributedCharacterIterator.
+ * The first character's position is specified by the X, Y parameters.
+ *
+ * @param iterator whose text is drawn.
+ * @param x the X position where the first character is drawn.
+ * @param y the Y position where the first character is drawn.
+ *
+ * @see java.awt.Graphics#drawString(AttributedCharacterIterator, int, int)
+ */
+ @Override
+ public abstract void drawString(AttributedCharacterIterator iterator, int x, int y);
+
+ /**
+ * Draws the String whose the first character position is specified
+ * by the parameters X, Y.
+ *
+ * @param s the String to be drawn.
+ * @param x the X position of the first character.
+ * @param y the Y position of the first character.
+ */
+ public abstract void drawString(String s, float x, float y);
+
+ /**
+ * Draws the String whose the first character coordinates are specified
+ * by the parameters X, Y.
+ *
+ * @param str the String to be drawn.
+ * @param x the X coordinate of the first character.
+ * @param y the Y coordinate of the first character.
+ *
+ * @see java.awt.Graphics#drawString(String, int, int)
+ */
+ @Override
+ public abstract void drawString(String str, int x, int y);
+
+ /**
+ * Fills the interior of the specified Shape.
+ *
+ * @param s the Shape to be filled.
+ */
+ public abstract void fill(Shape s);
+
+ /**
+ * Gets the background color.
+ *
+ * @return the current background color.
+ */
+ public abstract Color getBackground();
+
+ /**
+ * Gets the current composite of the Graphics2D.
+ *
+ * @return the current composite which specifies the compositing style.
+ */
+ public abstract Composite getComposite();
+
+ /**
+ * Gets the device configuration.
+ *
+ * @return the device configuration
+ */
+ public abstract GraphicsConfiguration getDeviceConfiguration();
+
+ /**
+ * Gets the rendering context of the Font.
+ *
+ * @return the FontRenderContext.
+ */
+ public abstract FontRenderContext getFontRenderContext();
+
+ /**
+ * Gets the current Paint of Graphics2D.
+ *
+ * @return the current Paint of Graphics2D.
+ */
+ public abstract Paint getPaint();
+
+ /**
+ * Gets the value of single preference for specified key.
+ *
+ * @param key the specified key of the rendering hint.
+ *
+ * @return the value of rendering hint for specified key.
+ */
+ public abstract Object getRenderingHint(RenderingHints.Key key);
+
+ /**
+ * Gets the set of the rendering preferences as a collection of
+ * key/value pairs.
+ *
+ * @return the RenderingHints which contains the rendering preferences.
+ */
+ public abstract RenderingHints getRenderingHints();
+
+ /**
+ * Gets current stroke of the Graphics2D.
+ *
+ * @return current stroke of the Graphics2D.
+ */
+ public abstract Stroke getStroke();
+
+ /**
+ * Gets current affine transform of the Graphics2D.
+ *
+ * @return current AffineTransform of the Graphics2D.
+ */
+ public abstract AffineTransform getTransform();
+
+ /**
+ * Determines wether or not the specified Shape intersects the specified
+ * Rectangle. If the onStroke parameter is true, this method
+ * checks whether or not the specified Shape outline intersects the specified
+ * Rectangle, otherwise this method checks whether or not the specified
+ * Shape's interior intersects the specified Rectangle.
+ *
+ * @param rect the specified Rectangle.
+ * @param s the Shape to check for intersection.
+ * @param onStroke the parameter determines whether or not this method checks
+ * for intersection of the Shape outline or of the Shape interior with
+ * the Rectangle.
+ *
+ * @return true, if there is a hit, otherwise false.
+ */
+ public abstract boolean hit(Rectangle rect, Shape s, boolean onStroke);
+
+ /**
+ * Performs a rotation transform relative to current Graphics2D Transform.
+ * The coordinate system is rotated by the specified angle in radians relative to
+ * current origin.
+ *
+ * @param theta the angle of rotation in radians.
+ */
+ public abstract void rotate(double theta);
+
+ /**
+ * Performs a translated rotation transform relative to current Graphics2D
+ * Transform. The coordinate system is rotated by the specified angle in radians
+ * relative to current origin and then moved to point (x, y).
+ *
+ * Is this right?
+ *
+ * @param theta the angle of rotation in radians.
+ * @param x the X coordinate.
+ * @param y the Y coordinate.
+ */
+ public abstract void rotate(double theta, double x, double y);
+
+ /**
+ * Performs a linear scale transform relative to current Graphics2D Transform.
+ * The coordinate system is rescaled vertically and horizontally
+ * by the specified parameters.
+ *
+ * @param sx the scaling factor by which the X coordinate is multiplied.
+ * @param sy the scaling factor by which the Y coordinate is multiplied.
+ */
+ public abstract void scale(double sx, double sy);
+
+ /**
+ * Sets a new background color for clearing rectangular areas.
+ * The clearRect method uses the current background color.
+ *
+ * @param color the new background color.
+ */
+ public abstract void setBackground(Color color);
+
+ /**
+ * Sets the current composite for Graphics2D.
+ *
+ * @param comp the Composite object.
+ */
+ public abstract void setComposite(Composite comp);
+
+ /**
+ * Sets the paint for Graphics2D.
+ *
+ * @param paint the Paint object.
+ */
+ public abstract void setPaint(Paint paint);
+
+ /**
+ * Sets a key-value pair in the current RenderingHints map.
+ *
+ * @param key the key of the rendering hint to set.
+ * @param value the value to set for the rendering hint.
+ */
+ public abstract void setRenderingHint(RenderingHints.Key key, Object value);
+
+ /**
+ * Replaces the current rendering hints with the specified rendering preferences.
+ *
+ * @param hints the new Map of rendering hints.
+ */
+ public abstract void setRenderingHints(Map<?, ?> hints);
+
+ /**
+ * Sets the stroke for the Graphics2D.
+ *
+ * @param s the Stroke object.
+ */
+ public abstract void setStroke(Stroke s);
+
+ /**
+ * Overwrite the current Transform of the Graphics2D. The specified Transform
+ * should be received from the getTransform() method and should be used
+ * only for restoring the original Graphics2D transform after calling
+ * draw or fill methods.
+ *
+ * @param Tx the specified Transform.
+ */
+ public abstract void setTransform(AffineTransform Tx);
+
+ /**
+ * Performs a shear transform relative to current Graphics2D Transform.
+ * The coordinate system is shifted by the specified multipliers relative to
+ * current position.
+ *
+ * @param shx the multiplier by which the X coordinates shift position
+ * along X axis as a function of Y coordinates.
+ * @param shy the multiplier by which the Y coordinates shift position
+ * along Y axis as a function of X coordinates.
+ */
+ public abstract void shear(double shx, double shy);
+
+ /**
+ * Concatenates the AffineTransform object with current Transform
+ * of this Graphics2D. The transforms are applied in reverse order
+ * with the last specified transform applied first and the next
+ * transformation applied to the result of previous transformation.
+ * More precisely, if Cx is the current Graphics2D transform, the
+ * transform method's result with Tx as the parameter
+ * is the transformation Rx, where Rx(p) = Cx(Tx(p)), for p - a point
+ * in current coordinate system. Rx becomes the current Transform
+ * for this Graphics2D.
+ *
+ * @param Tx the AffineTransform object to be concatenated with
+ * current Transform.
+ */
+ public abstract void transform(AffineTransform Tx);
+
+ /**
+ * Performs a translate transform relative to current Graphics2D Transform.
+ * The coordinate system is moved by the specified distance relative
+ * to current position.
+ *
+ * @param tx the translation distance along the X axis.
+ * @param ty the translation distance along the Y axis.
+ */
+ public abstract void translate(double tx, double ty);
+
+ /**
+ * Moves the origin Graphics2D Transform to the point with x, y
+ * coordinates in current coordinate system. The new origin of coordinate
+ * system is moved to the (x, y) point accordingly. All rendering and
+ * transform operations are performed relative to this new origin.
+ *
+ * @param x the X coordinate.
+ * @param y the Y coordinate.
+ *
+ * @see java.awt.Graphics#translate(int, int)
+ */
+ @Override
+ public abstract void translate(int x, int y);
+
+ /**
+ * Fills a 3D rectangle with the current color.
+ * The rectangle is specified by its width, height, and top left corner
+ * coordinates.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ * @param raised a boolean value that determines whether the rectangle
+ * is drawn as raised or indented.
+ *
+ * @see java.awt.Graphics#fill3DRect(int, int, int, int, boolean)
+ */
+ @Override
+ public void fill3DRect(int x, int y, int width, int height, boolean raised) {
+ // According to the spec, color should be used instead of paint,
+ // so Graphics.fill3DRect resets paint and
+ // it should be restored after the call
+ Paint savedPaint = getPaint();
+ super.fill3DRect(x, y, width, height, raised);
+ setPaint(savedPaint);
+ }
+
+ /**
+ * Draws the higlighted outline of a rectangle.
+ *
+ * @param x the X coordinate of the rectangle's top left corner.
+ * @param y the Y coordinate of the rectangle's top left corner.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ * @param raised a boolean value that determines whether the rectangle
+ * is drawn as raised or indented.
+ *
+ * @see java.awt.Graphics#draw3DRect(int, int, int, int, boolean)
+ */
+ @Override
+ public void draw3DRect(int x, int y, int width, int height, boolean raised) {
+ // According to the spec, color should be used instead of paint,
+ // so Graphics.draw3DRect resets paint and
+ // it should be restored after the call
+ Paint savedPaint = getPaint();
+ super.draw3DRect(x, y, width, height, raised);
+ setPaint(savedPaint);
+ }
+} \ No newline at end of file
diff --git a/awt/java/awt/GraphicsConfiguration.java b/awt/java/awt/GraphicsConfiguration.java
new file mode 100644
index 0000000..8bec253
--- /dev/null
+++ b/awt/java/awt/GraphicsConfiguration.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.VolatileImage;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GraphicsConfiguration class contains the characteristics of graphics
+ * devices such as a printer or monitor, and represents device's capabilities
+ * and modes. Many GraphicsConfiguration objects can be associated with
+ * single graphics device.
+ */
+public abstract class GraphicsConfiguration {
+
+ /**
+ * Constructor could not be used directly and should be obtained in
+ * extended classes.
+ */
+
+ protected GraphicsConfiguration() {
+ }
+
+
+ /**
+ * Creates BufferedImage image object with a data layout and color model
+ * compatible with this GraphicsConfiguration with specified width
+ * and height parameters.
+ *
+ * @param width the width of BufferedImage.
+ * @param height the height of BufferedImage.
+ *
+ * @return the BufferedImage object with specified width and height
+ * parameters.
+ */
+ public abstract BufferedImage createCompatibleImage(int width, int height);
+
+ /**
+ * Creates a BufferedImage that has the specified width, height,
+ * transparency and has a data layout and color model compatible with this
+ * GraphicsConfiguration.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ * @param transparency the transparency mode.
+ *
+ * @return the BufferedImage object.
+ */
+ public abstract BufferedImage createCompatibleImage(int width, int height, int transparency);
+
+ /**
+ * Creates a VolatileImage that has the specified width and height
+ * and has a data layout and color model compatible with this
+ * GraphicsConfiguration.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ *
+ * @return the VolatileImage object.
+ */
+ public abstract VolatileImage createCompatibleVolatileImage(int width, int height);
+
+ /**
+ * Creates a VolatileImage that supports the specified width, height,
+ * transparency and has a data layout and color model compatible with this
+ * GraphicsConfiguration.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ * @param transparency the transparency mode.
+ *
+ * @return the VolatileImage object.
+ */
+ public abstract VolatileImage createCompatibleVolatileImage(int width, int height, int transparency);
+
+ /**
+ * Gets the bounds of area covered by the GraphicsConfiguration in the
+ * device coordinates space.
+ *
+ * @return the Rectangle of GraphicsConfiguration's bounds.
+ */
+ public abstract Rectangle getBounds();
+
+ /**
+ * Gets the ColorModel of the GraphicsConfiguration.
+ *
+ * @return the ColorModel object of the GraphicsConfiguration.
+ */
+ public abstract ColorModel getColorModel();
+
+ /**
+ * Gets the ColorModel of the GraphicsConfiguration which
+ * supports specified Transparency.
+ *
+ * @param transparency the Transparency mode: OPAQUE, BITMASK, or
+ * TRANSLUCENT.
+ *
+ * @return the ColorModel of the GraphicsConfiguration which
+ * supports specified Transparency.
+ */
+ public abstract ColorModel getColorModel(int transparency);
+
+ /**
+ * Gets the default AffineTransform of the GraphicsConfiguration.
+ * This method translates user coordinates to device coordinates.
+ *
+ * @return the default AffineTransform of the GraphicsConfiguration.
+ */
+ public abstract AffineTransform getDefaultTransform();
+
+ /**
+ * Gets the GraphicsDevice of the GraphicsConfiguration.
+ *
+ * @return the GraphicsDevice of the GraphicsConfiguration.
+ */
+ public abstract GraphicsDevice getDevice();
+
+ /**
+ * Gets the normalizing AffineTransform of the GraphicsConfiguration.
+ *
+ * @return the normalizing AffineTransform of the GraphicsConfiguration.
+ */
+ public abstract AffineTransform getNormalizingTransform();
+
+
+ /**
+ * Creates VolatileImage with specified width, height, ImageCapabilities;
+ * a data layout and color model compatible with this GraphicsConfiguration.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ * @param caps the ImageCapabilities object.
+ *
+ * @return the VolatileImage which data layout and color model compatible
+ * with this GraphicsConfiguration.
+ *
+ * @throws AWTException if ImageCapabilities is not supported by the
+ * GraphicsConfiguration.
+ */
+ public VolatileImage createCompatibleVolatileImage(int width, int height,
+ ImageCapabilities caps) throws AWTException {
+ VolatileImage res = createCompatibleVolatileImage(width, height);
+ if (!res.getCapabilities().equals(caps)) {
+ // awt.14A=Can not create VolatileImage with specified capabilities
+ throw new AWTException(Messages.getString("awt.14A")); //$NON-NLS-1$
+ }
+ return res;
+ }
+
+ /**
+ * Creates a VolatileImage with specified width, height, transparency
+ * and ImageCapabilities; a data layout and color model compatible with
+ * this GraphicsConfiguration.
+ *
+ * @param width the width of image.
+ * @param height the height of image.
+ * @param caps the ImageCapabilities object.
+ * @param transparency the Transparency mode: OPAQUE, BITMASK, or
+ * TRANSLUCENT.
+ *
+ * @return the VolatileImage which data layout and color model compatible
+ * with this GraphicsConfiguration.
+ *
+ * @throws AWTException if ImageCapabilities is not supported by the
+ * GraphicsConfiguration.
+ */
+ public VolatileImage createCompatibleVolatileImage(int width, int height,
+ ImageCapabilities caps, int transparency) throws AWTException {
+ VolatileImage res = createCompatibleVolatileImage(width, height, transparency);
+ if (!res.getCapabilities().equals(caps)) {
+ // awt.14A=Can not create VolatileImage with specified capabilities
+ throw new AWTException(Messages.getString("awt.14A")); //$NON-NLS-1$
+ }
+ return res;
+ }
+
+ /**
+ * Gets the buffering capabilities of the GraphicsConfiguration.
+ *
+ * @return the BufferCapabilities object.
+ */
+ public BufferCapabilities getBufferCapabilities() {
+ return new BufferCapabilities(new ImageCapabilities(false), new ImageCapabilities(false),
+ BufferCapabilities.FlipContents.UNDEFINED);
+ }
+
+ /**
+ * Gets the image capabilities of the GraphicsConfiguration.
+ *
+ * @return the ImageCapabilities object.
+ */
+ public ImageCapabilities getImageCapabilities() {
+ return new ImageCapabilities(false);
+ }
+}
diff --git a/awt/java/awt/GraphicsDevice.java b/awt/java/awt/GraphicsDevice.java
new file mode 100644
index 0000000..8cf700a
--- /dev/null
+++ b/awt/java/awt/GraphicsDevice.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GraphicsDevice class describes the graphics devices (such as screens
+ * or printers) which are available in a particular graphics environment.
+ * Many GraphicsDevice instances can be associated with a single
+ * GraphicsEnvironment. Each GraphicsDevice has one or more GraphicsConfiguration
+ * objects which specify the different configurations and modes of GraphicsDevice.
+ */
+public abstract class GraphicsDevice {
+
+ /** The display mode. */
+ private DisplayMode displayMode;
+
+ //???AWT
+// private Window fullScreenWindow = null;
+
+ /** The Constant TYPE_IMAGE_BUFFER indicates a image buffer device. */
+
+ public static final int TYPE_IMAGE_BUFFER = 2;
+
+ /** The Constant TYPE_PRINTER indicates a printer device. */
+ public static final int TYPE_PRINTER = 1;
+
+ /** The Constant TYPE_RASTER_SCREEN indicates a raster screen device. */
+ public static final int TYPE_RASTER_SCREEN = 0;
+
+ /**
+ * Constructor is not to be used directly as this class is abstract.
+ */
+ protected GraphicsDevice() {
+ displayMode = new DisplayMode(0, 0, DisplayMode.BIT_DEPTH_MULTI, DisplayMode.REFRESH_RATE_UNKNOWN);
+ }
+
+
+ /**
+ * Returns an array of GraphicsConfiguration objects associated
+ * with the GraphicsDevice.
+ *
+ * @return an array of GraphicsConfiguration objects associated
+ * with the GraphicsDevice.
+ */
+ public abstract GraphicsConfiguration[] getConfigurations();
+
+ /**
+ * Gets the default configuration for the GraphicsDevice.
+ *
+ * @return the default GraphicsConfiguration object for the GraphicsDevice.
+ */
+ public abstract GraphicsConfiguration getDefaultConfiguration();
+
+ /**
+ * Gets the String identifier which associated with the GraphicsDevice in
+ * the GraphicsEnvironment.
+ *
+ * @return the String identifier of the GraphicsDevice in
+ * the GraphicsEnvironment.
+ */
+ public abstract String getIDstring();
+
+ /**
+ * Gets the type of this GraphicsDevice:
+ * TYPE_IMAGE_BUFFER, TYPE_PRINTER or TYPE_RASTER_SCREEN.
+ *
+ * @return the type of this GraphicsDevice: TYPE_IMAGE_BUFFER,
+ * TYPE_PRINTER or TYPE_RASTER_SCREEN.
+ */
+ public abstract int getType();
+
+
+
+ /**
+ * Returns the number of bytes available in accelerated
+ * memory on this device.
+ *
+ * @return the number of bytes available accelerated memory.
+ */
+ public int getAvailableAcceleratedMemory() {
+ return 0;
+ }
+
+ /* ???AWT
+ public GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate gct) {
+ return gct.getBestConfiguration(getConfigurations());
+ }
+ */
+
+ /**
+ * Gets the current display mode of the GraphicsDevice.
+ *
+ * @return the current display mode of the GraphicsDevice.
+ */
+ public DisplayMode getDisplayMode() {
+ return displayMode;
+ }
+
+ /**
+ * Gets an array of display modes available in this GraphicsDevice.
+ *
+ * @return an array of display modes available in this GraphicsDevice.
+ */
+ public DisplayMode[] getDisplayModes() {
+ DisplayMode []dms = {displayMode};
+ return dms;
+ }
+
+ /* ???AWT
+ public Window getFullScreenWindow() {
+ return fullScreenWindow;
+ }
+ */
+
+ /**
+ * Returns true if this GraphicsDevice supports low-level
+ * display changes.
+ *
+ * @return true, if this GraphicsDevice supports low-level
+ * display changes; false otherwise.
+ */
+ public boolean isDisplayChangeSupported() {
+ return false;
+ }
+
+ /**
+ * Returns true if this GraphicsDevice supports full screen
+ * mode.
+ *
+ * @return true, if this GraphicsDevice supports full screen
+ * mode; otherwise false.
+ */
+ public boolean isFullScreenSupported() {
+ return false;
+ }
+ //an array of display modes available in this GraphicsDevice.
+
+ /**
+ * Sets the display mode of this GraphicsDevice.
+ *
+ * @param dm the new display mode of this GraphicsDevice.
+ */
+ public void setDisplayMode(DisplayMode dm) {
+ if (!isDisplayChangeSupported()) {
+ // awt.122=Does not support display mode changes
+ throw new UnsupportedOperationException(Messages.getString("awt.122")); //$NON-NLS-1$
+ }
+
+ DisplayMode []dms = getDisplayModes();
+ for (DisplayMode element : dms) {
+ if (element.equals(dm)) {
+ displayMode = dm;
+ return;
+ }
+ }
+ // awt.123=Unsupported display mode: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.123", dm)); //$NON-NLS-1$
+ }
+
+ /* ???AWT
+ public void setFullScreenWindow(Window w) {
+ if (w == null) {
+ fullScreenWindow = null;
+ return;
+ }
+
+ fullScreenWindow = w;
+
+ if (isFullScreenSupported()) {
+ w.enableInputMethods(false);
+ } else {
+ w.setSize(displayMode.getWidth(), displayMode.getHeight());
+ w.setLocation(0, 0);
+ }
+ w.setVisible(true);
+ w.setAlwaysOnTop(true);
+ }
+ */
+}
diff --git a/awt/java/awt/GraphicsEnvironment.java b/awt/java/awt/GraphicsEnvironment.java
new file mode 100644
index 0000000..3b14f55
--- /dev/null
+++ b/awt/java/awt/GraphicsEnvironment.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt;
+
+import java.awt.image.BufferedImage;
+import java.util.Locale;
+
+import org.apache.harmony.awt.ContextStorage;
+import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
+
+/**
+ * The GraphicsEnvironment class defines a collection of GraphicsDevice
+ * objects and Font objects which are available for Java application on
+ * current platform.
+ */
+public abstract class GraphicsEnvironment {
+
+ /**
+ * Constructor could not be used directly and should be obtained in
+ * extended classes.
+ */
+ protected GraphicsEnvironment() {}
+
+ /**
+ * Gets the local GraphicsEnvironment.
+ *
+ * @return the local GraphicsEnvironment.
+ */
+ public static GraphicsEnvironment getLocalGraphicsEnvironment() {
+ synchronized(ContextStorage.getContextLock()) {
+ if (ContextStorage.getGraphicsEnvironment() == null) {
+ if (isHeadless()) {
+ ContextStorage.setGraphicsEnvironment(new HeadlessGraphicsEnvironment());
+ } else {
+ CommonGraphics2DFactory g2df =
+ (CommonGraphics2DFactory) Toolkit.getDefaultToolkit().getGraphicsFactory();
+
+ ContextStorage.setGraphicsEnvironment(
+ g2df.createGraphicsEnvironment(ContextStorage.getWindowFactory())
+ );
+ }
+ }
+
+ return ContextStorage.getGraphicsEnvironment();
+ }
+ }
+
+ /**
+ * Returns whether or not a display, keyboard, and mouse are supported
+ * in this graphics environment.
+ *
+ * @return true, if HeadlessException will be thrown from areas of
+ * the graphics environment that are dependent on a display, keyboard,
+ * or mouse; false otherwise.
+ */
+ public boolean isHeadlessInstance() {
+ return false;
+ }
+
+ /**
+ * Checks whether or not a display, keyboard, and mouse are supported
+ * in this environment.
+ *
+ * @return true, if a HeadlessException is thrown from areas of
+ * the Toolkit and GraphicsEnvironment that are dependent on
+ * a display, keyboard, or mouse; false otherwise.
+ */
+ public static boolean isHeadless() {
+ return "true".equals(System.getProperty("java.awt.headless"));
+ }
+
+ /**
+ * Gets the maximum bounds of system centered windows.
+ *
+ * @return the maximum bounds of system centered windows.
+ *
+ * @throws HeadlessException if isHeadless() method returns true.
+ */
+ public Rectangle getMaximumWindowBounds() throws HeadlessException {
+ return getDefaultScreenDevice().getDefaultConfiguration().getBounds();
+ }
+
+ /**
+ * Gets the Point which should defines the center of system window.
+ *
+ * @return the Point where the system window should be centered.
+ *
+ * @throws HeadlessException if isHeadless() method returns true.
+ */
+ public Point getCenterPoint() throws HeadlessException {
+ Rectangle mwb = getMaximumWindowBounds();
+ return new Point(mwb.width >> 1, mwb.height >> 1);
+ }
+
+ /**
+ * Indicates that the primary font should be used.
+ * Primary font is specified by initial system locale or default encoding).
+ *
+ */
+ public void preferLocaleFonts() {
+ // Note: API specification says following:
+ // "The actual change in font rendering behavior resulting
+ // from a call to this method is implementation dependent;
+ // it may have no effect at all." So, doing nothing is an
+ // acceptable behavior for this method.
+
+ // For now FontManager uses 1.4 font.properties scheme for font mapping, so
+ // this method doesn't make any sense. The implementation of this method
+ // which will influence font mapping is postponed until
+ // 1.5 mapping scheme not implemented.
+
+ // todo - Implement non-default behavior with 1.5 font mapping scheme
+ }
+
+ /**
+ * Indicates that a proportional preference of the font should be used.
+ */
+ public void preferProportionalFonts() {
+ // Note: API specification says following:
+ // "The actual change in font rendering behavior resulting
+ // from a call to this method is implementation dependent;
+ // it may have no effect at all." So, doing nothing is an
+ // acceptable behavior for this method.
+
+ // For now FontManager uses 1.4 font.properties scheme for font mapping, so
+ // this method doesn't make any sense. The implementation of this method
+ // which will influence font mapping is postponed until
+ // 1.5 mapping scheme not implemented.
+
+ // todo - Implement non-default behavior with 1.5 font mapping scheme
+ }
+
+ /**
+ * Creates the Graphics2D object for rendering to the specified
+ * BufferedImage.
+ *
+ * @param bufferedImage the BufferedImage object.
+ *
+ * @return the Graphics2D object which allows to render to the specified
+ * BufferedImage.
+ */
+ public abstract Graphics2D createGraphics(BufferedImage bufferedImage);
+
+ /**
+ * Gets the array of all available fonts instances in this
+ * GraphicsEnviroments.
+ *
+ * @return the array of all available fonts instances in this
+ * GraphicsEnviroments.
+ */
+ public abstract Font[] getAllFonts();
+
+ /**
+ * Gets the array of all available font family names.
+ *
+ * @return the array of all available font family names.
+ */
+ public abstract String[] getAvailableFontFamilyNames();
+
+ /**
+ * Gets the array of all available font family names for the specified
+ * locale.
+ *
+ * @param locale the Locale object which represents geographical
+ * region. The default locale is used if locale is null.
+ *
+ * @return the array of available font family names for the specified
+ * locale.
+ */
+ public abstract String[] getAvailableFontFamilyNames(Locale locale);
+
+ /**
+ * Gets the default screen device as GraphicDevice object.
+ *
+ * @return the GraphicDevice object which represents default screen device.
+ *
+ * @throws HeadlessException if isHeadless() returns true.
+ */
+ public abstract GraphicsDevice getDefaultScreenDevice() throws HeadlessException;
+
+ /**
+ * Gets an array of all available screen devices.
+ *
+ * @return the array of GraphicsDevice obgects which represents
+ * all available screen devices.
+ *
+ * @throws HeadlessException if isHeadless() returns true.
+ */
+ public abstract GraphicsDevice[] getScreenDevices() throws HeadlessException;
+}
diff --git a/awt/java/awt/HeadlessException.java b/awt/java/awt/HeadlessException.java
new file mode 100644
index 0000000..28e463b
--- /dev/null
+++ b/awt/java/awt/HeadlessException.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The HeadlessException class provides notifications and error messages
+ * when code that is dependent on a keyboard, display, or mouse is called
+ * in an environment that does not support a keyboard, display, or mouse.
+ */
+public class HeadlessException extends UnsupportedOperationException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 167183644944358563L;
+
+ /**
+ * Instantiates a new headless exception.
+ */
+ public HeadlessException() {
+ super();
+ }
+
+ /**
+ * Instantiates a new headless exception with the specified message.
+ *
+ * @param msg the String which represents error message.
+ */
+ public HeadlessException(String msg) {
+ super(msg);
+ }
+}
diff --git a/awt/java/awt/HeadlessGraphicsEnvironment.java b/awt/java/awt/HeadlessGraphicsEnvironment.java
new file mode 100644
index 0000000..97f88d1
--- /dev/null
+++ b/awt/java/awt/HeadlessGraphicsEnvironment.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package java.awt;
+
+import java.awt.GraphicsDevice;
+import java.awt.HeadlessException;
+
+import org.apache.harmony.awt.gl.CommonGraphicsEnvironment;
+
+/**
+ * The HeadlessGraphicsEnvironment class is the CommonGraphicsEnvironment
+ * implementation to use in the case where the environment lacks display,
+ * keyboard, and mouse support.
+ */
+public class HeadlessGraphicsEnvironment extends CommonGraphicsEnvironment {
+
+ /**
+ * Returns whether or not a display, keyboard, and mouse are supported
+ * in this graphics environment.
+ *
+ * @return true, if HeadlessException will be thrown from areas of
+ * the graphics environment that are dependent on a display, keyboard,
+ * or mouse; false otherwise.
+ */
+ @Override
+ public boolean isHeadlessInstance() {
+ return true;
+ }
+
+ /**
+ * Gets the default screen device as GraphicDevice object.
+ *
+ * @return the GraphicDevice object which represents default screen device.
+ *
+ * @throws HeadlessException if isHeadless() returns true.
+ */
+ @Override
+ public GraphicsDevice getDefaultScreenDevice() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ /**
+ * Gets an array of all available screen devices.
+ *
+ * @return the array of GraphicsDevice objects which represents
+ * all available screen devices.
+ *
+ * @throws HeadlessException if isHeadless() returns true.
+ */
+ @Override
+ public GraphicsDevice[] getScreenDevices() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+}
diff --git a/awt/java/awt/HeadlessToolkit.java b/awt/java/awt/HeadlessToolkit.java
new file mode 100644
index 0000000..a7dd557
--- /dev/null
+++ b/awt/java/awt/HeadlessToolkit.java
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+//???AWT
+//import java.awt.datatransfer.Clipboard;
+//import java.awt.dnd.DragGestureEvent;
+//import java.awt.dnd.DragGestureListener;
+//import java.awt.dnd.DragGestureRecognizer;
+//import java.awt.dnd.DragSource;
+//import java.awt.dnd.InvalidDnDOperationException;
+//import java.awt.dnd.peer.DragSourceContextPeer;
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.ColorModel;
+//import java.awt.peer.*;
+//import java.beans.PropertyChangeSupport;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.harmony.awt.ComponentInternals;
+//import org.apache.harmony.awt.datatransfer.DTK;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+import org.apache.harmony.awt.wtk.WindowFactory;
+
+/**
+ * The HeadlessToolkit class is a subclass of ToolkitImpl to
+ * be used for graphical environments that lack keyboard and
+ * mouse capabilities.
+ */
+public final class HeadlessToolkit extends ToolkitImpl {
+
+ //???AWT
+ /*
+ @Override
+ protected ButtonPeer createButton(Button a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected CheckboxPeer createCheckbox(Checkbox a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected ChoicePeer createChoice(Choice a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ public Cursor createCustomCursor(Image img, Point hotSpot, String name)
+ throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected DialogPeer createDialog(Dialog a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
+ Class<T> recognizerAbstractClass, DragSource ds, Component c, int srcActions,
+ DragGestureListener dgl) {
+ return null;
+ }
+
+ @Override
+ public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge)
+ throws InvalidDnDOperationException {
+ throw new InvalidDnDOperationException();
+ }
+
+ @Override
+ protected FileDialogPeer createFileDialog(FileDialog a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected FramePeer createFrame(Frame a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected LabelPeer createLabel(Label a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected ListPeer createList(List a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected MenuPeer createMenu(Menu a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected MenuBarPeer createMenuBar(MenuBar a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected MenuItemPeer createMenuItem(MenuItem a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected PopupMenuPeer createPopupMenu(PopupMenu a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected ScrollbarPeer createScrollbar(Scrollbar a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected ScrollPanePeer createScrollPane(ScrollPane a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected TextAreaPeer createTextArea(TextArea a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected TextFieldPeer createTextField(TextField a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected WindowPeer createWindow(Window a0) throws HeadlessException {
+ throw new HeadlessException();
+ }
+ */
+
+ @Override
+ public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public ColorModel getColorModel() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public GraphicsFactory getGraphicsFactory() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public boolean getLockingKeyState(int keyCode) throws UnsupportedOperationException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public int getMaximumCursorColors() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public int getMenuShortcutKeyMask() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ //???AWT
+ /*
+ @Override
+ NativeEventQueue getNativeEventQueue() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public PrintJob getPrintJob(Frame frame, String jobtitle, JobAttributes jobAttributes,
+ PageAttributes pageAttributes) throws IllegalArgumentException {
+ throw new IllegalArgumentException();
+ }
+
+ @Override
+ public PrintJob getPrintJob(Frame frame, String jobtitle, Properties props) throws NullPointerException {
+ throw new NullPointerException();
+ }
+ */
+
+ @Override
+ public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public int getScreenResolution() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public Dimension getScreenSize() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ //???AWT
+ /*
+ @Override
+ public Clipboard getSystemClipboard() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public Clipboard getSystemSelection() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ WindowFactory getWindowFactory() throws HeadlessException {
+ throw new HeadlessException();
+ }
+ */
+
+ @Override
+ protected void init() {
+ lockAWT();
+ try {
+ ComponentInternals.setComponentInternals(new ComponentInternalsImpl());
+ //???AWT: new EventQueue(this); // create the system EventQueue
+ //???AWT: dispatcher = new Dispatcher(this);
+ desktopProperties = new HashMap<String, Object>();
+ //???AWT: desktopPropsSupport = new PropertyChangeSupport(this);
+// ???AWT: awtEventsManager = new AWTEventsManager();
+// ???AWT: dispatchThread = new HeadlessEventDispatchThread(this, dispatcher);
+// ???AWT: dtk = DTK.getDTK();
+ dispatchThread.start();
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public boolean isDynamicLayoutActive() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected boolean isDynamicLayoutSet() throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public boolean isFrameStateSupported(int state) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ protected void loadSystemColors(int[] systemColors) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight(
+ InputMethodHighlight highlight) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlightImpl(
+ InputMethodHighlight highlight) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public void setDynamicLayout(boolean dynamic) throws HeadlessException {
+ throw new HeadlessException();
+ }
+
+ @Override
+ public void setLockingKeyState(int keyCode, boolean on) throws UnsupportedOperationException {
+ throw new HeadlessException();
+ }
+}
diff --git a/awt/java/awt/IllegalComponentStateException.java b/awt/java/awt/IllegalComponentStateException.java
new file mode 100644
index 0000000..21dc35f
--- /dev/null
+++ b/awt/java/awt/IllegalComponentStateException.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The IllegalComponentStateException class is used to provide
+ * notification that AWT component is not in an appropriate state
+ * for the requested operation.
+ */
+public class IllegalComponentStateException extends IllegalStateException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -1889339587208144238L;
+
+ /**
+ * Instantiates a new IllegalComponentStateException with
+ * the specified message.
+ *
+ * @param s the String message which describes the exception.
+ */
+ public IllegalComponentStateException(String s) {
+ super(s);
+ }
+
+ /**
+ * Instantiates a new IllegalComponentStateException without
+ * detailed message.
+ */
+ public IllegalComponentStateException() {
+ }
+
+}
+
diff --git a/awt/java/awt/Image.java b/awt/java/awt/Image.java
new file mode 100644
index 0000000..c217e38
--- /dev/null
+++ b/awt/java/awt/Image.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.image.AreaAveragingScaleFilter;
+import java.awt.image.FilteredImageSource;
+import java.awt.image.ImageFilter;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.ReplicateScaleFilter;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Image abstract class represents the graphic images.
+ */
+public abstract class Image {
+
+ /**
+ * The UndefinedProperty object should be returned if
+ * property is not defined for a particular image.
+ */
+ public static final Object UndefinedProperty = new Object(); //$NON-LOCK-1$
+
+ /**
+ * The Constant SCALE_DEFAULT indicates the default image
+ * scaling algorithm.
+ */
+ public static final int SCALE_DEFAULT = 1;
+
+ /**
+ * The Constant SCALE_FAST indicates an image scaling algorithm which
+ * places a higher priority on scaling speed than on the image's smoothness.
+ */
+ public static final int SCALE_FAST = 2;
+
+ /**
+ * The Constant SCALE_SMOOTH indicates an image scaling algorithm which
+ * places a higher priority on image smoothness than on scaling speed.
+ */
+ public static final int SCALE_SMOOTH = 4;
+
+ /**
+ * The Constant SCALE_REPLICATE indicates the image scaling
+ * algorithm in the ReplicateScaleFilter class.
+ */
+ public static final int SCALE_REPLICATE = 8;
+
+ /**
+ * The Constant SCALE_AREA_AVERAGING indicates
+ * the area averaging image scaling algorithm.
+ */
+ public static final int SCALE_AREA_AVERAGING = 16;
+
+ /**
+ * The acceleration priority indicates image acceleration.
+ */
+ protected float accelerationPriority = 0.5f;
+
+ /** The Constant capabilities. */
+ private static final ImageCapabilities capabilities = new ImageCapabilities(false);
+
+ /**
+ * Gets the image property with the specified name.
+ * The UndefinedProperty object should be return if the property is
+ * not specified for this image. The return value should be null if the
+ * property is currently unknown yet and the specified ImageObserver is
+ * to be notified later.
+ *
+ * @param name the name of image's property.
+ * @param observer the ImageObserver.
+ *
+ * @return the Object which represents value of the specified property.
+ */
+ public abstract Object getProperty(String name, ImageObserver observer);
+
+ /**
+ * Gets the ImageProducer object which represents data of this Image.
+ *
+ * @return the ImageProducer object which represents data of this Image.
+ */
+ public abstract ImageProducer getSource();
+
+ /**
+ * Gets the width of this image. The specified ImageObserver object
+ * is notified when the width of this image is available.
+ *
+ * @param observer the ImageObserver object which is
+ * is notified when the width of this image is available.
+ *
+ * @return the width of image, or -1 if the width of this image
+ * is not available.
+ */
+ public abstract int getWidth(ImageObserver observer);
+
+ /**
+ * Gets the height of this image. The specified ImageObserver object
+ * is notified when the height of this image is available.
+ *
+ * @param observer the ImageObserver object which is
+ * is notified when the height of this image is available.
+ *
+ * @return the height of image, or -1 if the height of this image
+ * is not available.
+ */
+ public abstract int getHeight(ImageObserver observer);
+
+ /**
+ * Gets the scaled instance of this Image. This method returns
+ * an Image object constructed from the source of this image
+ * with the specified width, height, and applied scaling
+ * alghorithm.
+ *
+ * @param width the width of scaled Image.
+ * @param height the height of scaled Image.
+ * @param hints the constant which indicates scaling algorithm.
+ *
+ * @return the scaled Image.
+ */
+ public Image getScaledInstance(int width, int height, int hints) {
+ ImageFilter filter;
+ if ((hints & (SCALE_SMOOTH | SCALE_AREA_AVERAGING)) != 0) {
+ filter = new AreaAveragingScaleFilter(width, height);
+ } else {
+ filter = new ReplicateScaleFilter(width, height);
+ }
+ ImageProducer producer = new FilteredImageSource(getSource(), filter);
+ return Toolkit.getDefaultToolkit().createImage(producer);
+ }
+
+ /**
+ * Gets a Graphics object for rendering this image.
+ * This method can be used for off-screen images.
+ *
+ * @return a Graphics object for rendering to this image.
+ */
+ public abstract Graphics getGraphics();
+
+ /**
+ * Flushes resources which are used by this Image object.
+ * This method resets the image to the reconstructered state
+ * from the image's source.
+ */
+ public abstract void flush();
+
+ /**
+ * Gets the acceleration priority of this image.
+ *
+ * @return the acceleration priority of this image.
+ */
+ public float getAccelerationPriority() {
+ return accelerationPriority;
+ }
+
+ /**
+ * Sets the acceleration priority for this image.
+ *
+ * @param priority the new acceleration priority (value in the
+ * range 0-1).
+ */
+ public void setAccelerationPriority(float priority) {
+ if (priority < 0 || priority > 1) {
+ // awt.10A=Priority must be a value between 0 and 1, inclusive
+ throw new IllegalArgumentException(Messages.getString("awt.10A")); //$NON-NLS-1$
+ }
+ accelerationPriority = priority;
+ }
+
+ /**
+ * Gets an ImageCapabilities object of this Image object
+ * for the specified GraphicsConfiguration.
+ *
+ * @param gc the specified GraphicsConfiguration object
+ * (null value means default GraphicsConfiguration).
+ *
+ * @return an ImageCapabilities object of this Image object
+ * for the specified GraphicsConfiguration.
+ */
+ public ImageCapabilities getCapabilities(GraphicsConfiguration gc) {
+ // Note: common image is not accelerated.
+ return capabilities;
+ }
+}
+
+
diff --git a/awt/java/awt/ImageCapabilities.java b/awt/java/awt/ImageCapabilities.java
new file mode 100644
index 0000000..6e9ecfc
--- /dev/null
+++ b/awt/java/awt/ImageCapabilities.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The ImageCapabilities class gives information about an image's capabilities.
+ */
+public class ImageCapabilities implements Cloneable {
+
+ /** The accelerated. */
+ private final boolean accelerated;
+
+ /**
+ * Instantiates a new ImageCapabilities with the specified
+ * acceleration flag which indicates whether acceleration
+ * is desired or not.
+ *
+ * @param accelerated the accelerated flag.
+ */
+ public ImageCapabilities(boolean accelerated) {
+ this.accelerated = accelerated;
+ }
+
+ /**
+ * Returns a copy of this ImageCapabilities object.
+ *
+ * @return the copy of this ImageCapabilities object.
+ */
+ @Override
+ public Object clone() {
+ return new ImageCapabilities(accelerated);
+ }
+
+ /**
+ * Returne true if the Image of this ImageCapabilities is or can be
+ * accelerated.
+ *
+ * @return true, if the Image of this ImageCapabilities is or can be
+ * accelerated, false otherwise.
+ */
+ public boolean isAccelerated() {
+ return accelerated;
+ }
+
+ /**
+ * Returns true if this ImageCapabilities applies to
+ * the VolatileImage which can lose its surfaces.
+ *
+ * @return true if this ImageCapabilities applies to
+ * the VolatileImage which can lose its surfaces,
+ * false otherwise.
+ */
+ public boolean isTrueVolatile() {
+ return true;
+ }
+}
diff --git a/awt/java/awt/Insets.java b/awt/java/awt/Insets.java
new file mode 100644
index 0000000..61f3fd8
--- /dev/null
+++ b/awt/java/awt/Insets.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.io.Serializable;
+
+import org.apache.harmony.misc.HashCode;
+
+
+/**
+ * The Insets class represents the borders of a container.
+ * This class describes the space that a container should leave at each edge:
+ * the top, the bottom, the right side, and the left side.
+ * The space can be filled with a border, a blank space, or a title.
+ */
+public class Insets implements Cloneable, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -2272572637695466749L;
+
+ /**
+ * The top inset indicates the size of the space added to the
+ * top of the rectangle.
+ */
+ public int top;
+
+ /**
+ * The left inset indicates the size of the space added to the
+ * left side of the rectangle.
+ */
+ public int left;
+
+ /**
+ * The bottom inset indicates the size of the space subtracted from
+ * the bottom of the rectangle.
+ */
+ public int bottom;
+
+ /** The right inset indicates the size of the space subtracted from
+ * the right side of the rectangle.
+ */
+ public int right;
+
+ /**
+ * Instantiates a new Inset object with the specified top, left, bottom,
+ * right parameters.
+ *
+ * @param top the top inset.
+ * @param left the left inset.
+ * @param bottom the bottom inset.
+ * @param right the right inset.
+ */
+ public Insets(int top, int left, int bottom, int right) {
+ setValues(top, left, bottom, right);
+ }
+
+ /**
+ * Returns a hash code of the Insets object.
+ *
+ * @return a hash code of the Insets object.
+ */
+ @Override
+ public int hashCode() {
+ int hashCode = HashCode.EMPTY_HASH_CODE;
+ hashCode = HashCode.combine(hashCode, top);
+ hashCode = HashCode.combine(hashCode, left);
+ hashCode = HashCode.combine(hashCode, bottom);
+ hashCode = HashCode.combine(hashCode, right);
+ return hashCode;
+ }
+
+ /**
+ * Returns a copy of this Insets object.
+ *
+ * @return a copy of this Insets object.
+ */
+ @Override
+ public Object clone() {
+ return new Insets(top, left, bottom, right);
+ }
+
+ /**
+ * Checks if this Insets object is equal to the specified object.
+ *
+ * @param o the Object to be compared.
+ *
+ * @return true, if the object is an Insets object whose data values
+ * are equal to those of this object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof Insets) {
+ Insets i = (Insets) o;
+ return ((i.left == left) && (i.bottom == bottom) &&
+ (i.right == right) && (i.top == top));
+ }
+ return false;
+ }
+
+ /**
+ * Returns a String representation of this Insets object.
+ *
+ * @return a String representation of this Insets object.
+ */
+ @Override
+ public String toString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ * System.out.println(new Insets(1, 2, 3, 4));
+ */
+
+ return (getClass().getName() +
+ "[left=" + left + ",top=" + top + //$NON-NLS-1$ //$NON-NLS-2$
+ ",right=" + right + ",bottom=" + bottom + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /**
+ * Sets top, left, bottom, and right insets to the specified values.
+ *
+ * @param top the top inset.
+ * @param left the left inset.
+ * @param bottom the bottom inset.
+ * @param right the right inset.
+ */
+ public void set(int top, int left, int bottom, int right) {
+ setValues(top, left, bottom, right);
+ }
+
+ /**
+ * Sets the values.
+ *
+ * @param top the top
+ * @param left the left
+ * @param bottom the bottom
+ * @param right the right
+ */
+ private void setValues(int top, int left, int bottom, int right) {
+ this.top = top;
+ this.left = left;
+ this.bottom = bottom;
+ this.right = right;
+ }
+}
+
diff --git a/awt/java/awt/ItemSelectable.java b/awt/java/awt/ItemSelectable.java
new file mode 100644
index 0000000..a46364b
--- /dev/null
+++ b/awt/java/awt/ItemSelectable.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.ItemListener;
+
+/**
+ * The ItemSelectable interface represents a set of items which can be selected.
+ */
+public interface ItemSelectable {
+
+ /**
+ * Adds an ItemListener for receiving item events when the state of an item
+ * is changed by the user.
+ *
+ * @param l the ItemListener.
+ */
+ public void addItemListener(ItemListener l);
+
+ /**
+ * Gets an array of the selected objects or null if there is no selected object.
+ *
+ * @return an array of the selected objects or null if there is no selected
+ * object.
+ */
+ public Object[] getSelectedObjects();
+
+ /**
+ * Removes the specified ItemListener.
+ *
+ * @param l the ItemListener which will be removed.
+ */
+ public void removeItemListener(ItemListener l);
+
+}
diff --git a/awt/java/awt/MenuComponent.java b/awt/java/awt/MenuComponent.java
new file mode 100644
index 0000000..9eb4f3d
--- /dev/null
+++ b/awt/java/awt/MenuComponent.java
@@ -0,0 +1,1041 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.awt.event.FocusListener;
+import java.awt.event.MouseEvent;
+import java.awt.peer.MenuComponentPeer;
+import java.io.Serializable;
+import java.util.Locale;
+//import javax.accessibility.Accessible;
+//import javax.accessibility.AccessibleComponent;
+//import javax.accessibility.AccessibleContext;
+//import javax.accessibility.AccessibleRole;
+//import javax.accessibility.AccessibleSelection;
+//import javax.accessibility.AccessibleStateSet;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.state.MenuItemState;
+import org.apache.harmony.awt.state.MenuState;
+
+/**
+ * The MenuComponent abstract class is the superclass for menu
+ * components. Menu components receive and process AWT events.
+ */
+public abstract class MenuComponent implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -4536902356223894379L;
+
+ /** The name. */
+ private String name;
+
+ /** The font. */
+ private Font font;
+
+ /** The parent. */
+ MenuContainer parent;
+
+ /** The deprecated event handler. */
+ boolean deprecatedEventHandler = true;
+
+ /** The selected item index. */
+ private int selectedItemIndex;
+
+ //???AWT: private AccessibleContext accessibleContext;
+
+ /** The toolkit. */
+ final Toolkit toolkit = Toolkit.getDefaultToolkit();
+
+ //???AWT
+ /*
+ protected abstract class AccessibleAWTMenuComponent extends AccessibleContext implements
+ Serializable, AccessibleComponent, AccessibleSelection {
+ private static final long serialVersionUID = -4269533416223798698L;
+
+ public void addFocusListener(FocusListener listener) {
+ }
+
+ public boolean contains(Point pt) {
+ return false;
+ }
+
+ public Accessible getAccessibleAt(Point pt) {
+ return null;
+ }
+
+ public Color getBackground() {
+ return null;
+ }
+
+ public Rectangle getBounds() {
+ return null;
+ }
+
+ public Cursor getCursor() {
+ return null;
+ }
+
+ public Font getFont() {
+ return MenuComponent.this.getFont();
+ }
+
+ public FontMetrics getFontMetrics(Font font) {
+ return null;
+ }
+
+ public Color getForeground() {
+ return null;
+ }
+
+ public Point getLocation() {
+ return null;
+ }
+
+ public Point getLocationOnScreen() {
+ return null;
+ }
+
+ public Dimension getSize() {
+ return null;
+ }
+
+ public boolean isEnabled() {
+ return true; // always enabled
+ }
+
+ public boolean isFocusTraversable() {
+ return true; // always focus traversable
+ }
+
+ public boolean isShowing() {
+ return true;// always showing
+ }
+
+ public boolean isVisible() {
+ return true; // always visible
+ }
+
+ public void removeFocusListener(FocusListener listener) {
+ }
+
+ public void requestFocus() {
+ }
+
+ public void setBackground(Color color) {
+ }
+
+ public void setBounds(Rectangle rect) {
+ }
+
+ public void setCursor(Cursor cursor) {
+ }
+
+ public void setEnabled(boolean enabled) {
+ }
+
+ public void setFont(Font font) {
+ MenuComponent.this.setFont(font);
+ }
+
+ public void setForeground(Color color) {
+ }
+
+ public void setLocation(Point pt) {
+ }
+
+ public void setSize(Dimension pt) {
+ }
+
+ public void setVisible(boolean visible) {
+ }
+
+ public void addAccessibleSelection(int index) {
+ }
+
+ public void clearAccessibleSelection() {
+ }
+
+ public Accessible getAccessibleSelection(int index) {
+ return null;
+ }
+
+ public int getAccessibleSelectionCount() {
+ return 0;
+ }
+
+ public boolean isAccessibleChildSelected(int index) {
+ return false;
+ }
+
+ public void removeAccessibleSelection(int index) {
+ }
+
+ public void selectAllAccessibleSelection() {
+ }
+
+ @Override
+ public Accessible getAccessibleChild(int index) {
+ return null;
+ }
+
+ @Override
+ public int getAccessibleChildrenCount() {
+ return 0;
+ }
+
+ @Override
+ public AccessibleComponent getAccessibleComponent() {
+ return this;
+ }
+
+ @Override
+ public String getAccessibleDescription() {
+ return super.getAccessibleDescription();
+ }
+
+ @Override
+ public int getAccessibleIndexInParent() {
+ toolkit.lockAWT();
+ try {
+ Accessible aParent = getAccessibleParent();
+ int aIndex = -1;
+ if (aParent instanceof MenuComponent) {
+ MenuComponent parent = (MenuComponent) aParent;
+ int count = parent.getItemCount();
+ for (int i = 0; i < count; i++) {
+ MenuComponent comp = parent.getItem(i);
+ if (comp instanceof Accessible) {
+ aIndex++;
+ if (comp == MenuComponent.this) {
+ return aIndex;
+ }
+ }
+ }
+ }
+ return -1;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public String getAccessibleName() {
+ return super.getAccessibleName();
+ }
+
+ @Override
+ public Accessible getAccessibleParent() {
+ toolkit.lockAWT();
+ try {
+ Accessible aParent = super.getAccessibleParent();
+ if (aParent != null) {
+ return aParent;
+ }
+ MenuContainer parent = getParent();
+ if (parent instanceof Accessible) {
+ aParent = (Accessible) parent;
+ }
+ return aParent;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ @Override
+ public AccessibleRole getAccessibleRole() {
+ return AccessibleRole.AWT_COMPONENT;
+ }
+
+ @Override
+ public AccessibleSelection getAccessibleSelection() {
+ return this;
+ }
+
+ @Override
+ public AccessibleStateSet getAccessibleStateSet() {
+ return new AccessibleStateSet();
+ }
+
+ @Override
+ public Locale getLocale() {
+ return Locale.getDefault();
+ }
+ }
+ */
+
+ /**
+ * The accessor to MenuComponent internal state,
+ * utilized by the visual theme.
+ *
+ * @throws HeadlessException the headless exception
+ */
+ //???AWT
+ /*
+ class State implements MenuState {
+ Dimension size;
+
+ Dimension getSize() {
+ if (size == null) {
+ calculate();
+ }
+ return size;
+ }
+
+ public int getWidth() {
+ return getSize().width;
+ }
+
+ public int getHeight() {
+ return getSize().height;
+ }
+
+ public Font getFont() {
+ return MenuComponent.this.getFont();
+ }
+
+ public int getItemCount() {
+ return MenuComponent.this.getItemCount();
+ }
+
+ public int getSelectedItemIndex() {
+ return MenuComponent.this.getSelectedItemIndex();
+ }
+
+ public boolean isFontSet() {
+ return MenuComponent.this.isFontSet();
+ }
+
+ @SuppressWarnings("deprecation")
+ public FontMetrics getFontMetrics(Font f) {
+ return MenuComponent.this.toolkit.getFontMetrics(f);
+ }
+
+ public Point getLocation() {
+ return MenuComponent.this.getLocation();
+ }
+
+ public MenuItemState getItem(int index) {
+ MenuItem item = MenuComponent.this.getItem(index);
+ return item.itemState;
+ }
+
+ public void setSize(int w, int h) {
+ this.size = new Dimension(w, h);
+ }
+
+ void calculate() {
+ size = new Dimension();
+ size.setSize(toolkit.theme.calculateMenuSize(this));
+ }
+
+ void reset() {
+ for (int i = 0; i < getItemCount(); i++) {
+ ((MenuItem.State) getItem(i)).reset();
+ }
+ }
+
+ }
+ */
+
+ /**
+ * Pop-up box for menu. It transfers the paint events,
+ * keyboard and mouse events to the menu component itself
+ */
+ //???AWT
+ /*
+ class MenuPopupBox extends PopupBox {
+ private final Point lastMousePos = new Point();
+
+ @Override
+ boolean isMenu() {
+ return true;
+ }
+
+ @Override
+ void paint(Graphics gr) {
+ MenuComponent.this.paint(gr);
+ }
+
+ @Override
+ void onKeyEvent(int eventId, int vKey, long when, int modifiers) {
+ MenuComponent.this.onKeyEvent(eventId, vKey, when, modifiers);
+ }
+
+ @Override
+ void onMouseEvent(int eventId, Point where, int mouseButton, long when, int modifiers,
+ int wheelRotation) {
+ // prevent conflict of mouse and keyboard
+ // when sub-menu drops down due to keyboard navigation
+ if (lastMousePos.equals(where)
+ && (eventId == MouseEvent.MOUSE_MOVED || eventId == MouseEvent.MOUSE_ENTERED)) {
+ return;
+ }
+ lastMousePos.setLocation(where);
+ MenuComponent.this.onMouseEvent(eventId, where, mouseButton, when, modifiers);
+ }
+ }
+ */
+
+ /**
+ * Instantiates a new MenuComponent object.
+ *
+ * @throws HeadlessException if the graphical interface
+ * environment can't support MenuComponents
+ */
+ public MenuComponent() throws HeadlessException {
+ toolkit.lockAWT();
+ try {
+ Toolkit.checkHeadless();
+ name = autoName();
+ selectedItemIndex = -1;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the name of the MenuComponent object.
+ *
+ * @return the name of the MenuComponent object.
+ */
+ public String getName() {
+ toolkit.lockAWT();
+ try {
+ return name;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns a String representation of the MenuComponent object.
+ *
+ * @return a String representation of the MenuComponent object.
+ */
+ @Override
+ public String toString() {
+ toolkit.lockAWT();
+ try {
+ return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the Parent menu Container .
+ *
+ * @return the parent
+ */
+ public MenuContainer getParent() {
+ toolkit.lockAWT();
+ try {
+ return parent;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the name of the MenuComponent to the specified string.
+ *
+ * @param name the new name of the MenuComponent object.
+ */
+ public void setName(String name) {
+ toolkit.lockAWT();
+ try {
+ this.name = name;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Dispatches AWT event.
+ *
+ * @param event the AWTEvent.
+ */
+ public final void dispatchEvent(AWTEvent event) {
+ toolkit.lockAWT();
+ try {
+ processEvent(event);
+ if (deprecatedEventHandler) {
+ postDeprecatedEvent(event);
+ }
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Post deprecated event.
+ *
+ * @param event the event
+ */
+ void postDeprecatedEvent(AWTEvent event) {
+ Event evt = event.getEvent();
+ if (evt != null) {
+ postEvent(evt);
+ }
+ }
+
+ /**
+ * Gets the peer of the MenuComponent; an application must not
+ * use this method directly.
+ *
+ * @return the MenuComponentPeer object.
+ *
+ * @deprecated an application must not use this method directly.
+ */
+ @Deprecated
+ public MenuComponentPeer getPeer() throws org.apache.harmony.luni.util.NotImplementedException {
+ toolkit.lockAWT();
+ try {
+ } finally {
+ toolkit.unlockAWT();
+ }
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Gets the locking object of this MenuComponent.
+ *
+ * @return the locking object of this MenuComponent.
+ */
+ protected final Object getTreeLock() {
+ return toolkit.awtTreeLock;
+ }
+
+ /**
+ * Posts the Event to the MenuComponent.
+ *
+ * @param e the Event.
+ *
+ * @return true, if the event is posted successfully;
+ * false otherwise.
+ *
+ * @deprecated Replaced dispatchEvent method.
+ */
+ @SuppressWarnings("deprecation")
+ @Deprecated
+ public boolean postEvent(Event e) {
+ toolkit.lockAWT();
+ try {
+ if (parent != null) {
+ return parent.postEvent(e);
+ }
+ return false;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the string representation of the MenuComponent state.
+ *
+ * @return returns the string representation of the MenuComponent
+ * state.
+ */
+ protected String paramString() {
+ toolkit.lockAWT();
+ try {
+ return getName();
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ //???AWT
+ /*
+ public AccessibleContext getAccessibleContext() {
+ toolkit.lockAWT();
+ try {
+ if (accessibleContext == null) {
+ accessibleContext = createAccessibleContext();
+ }
+ return accessibleContext;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+ */
+
+ /**
+ * Gets the font of the MenuComponent object.
+ *
+ * @return the Font of the MenuComponent object.
+ */
+ public Font getFont() {
+ toolkit.lockAWT();
+ try {
+ if (font == null && hasDefaultFont()) {
+ return toolkit.getDefaultFont();
+ }
+ if (font == null && parent != null) {
+ return parent.getFont();
+ }
+ return font;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if is font set.
+ *
+ * @return true, if is font set
+ */
+ boolean isFontSet() {
+ return font != null
+ || ((parent instanceof MenuComponent) && ((MenuComponent) parent).isFontSet());
+ }
+
+ /**
+ * Checks for default font.
+ *
+ * @return true, if successful
+ */
+ boolean hasDefaultFont() {
+ return false;
+ }
+
+ /**
+ * Processes an AWTEevent on this menu component.
+ *
+ * @param event the AWTEvent.
+ */
+ protected void processEvent(AWTEvent event) {
+ toolkit.lockAWT();
+ try {
+ // do nothing
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Removes the peer of the MenuComponent.
+ */
+ public void removeNotify() {
+ toolkit.lockAWT();
+ try {
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the Font for this MenuComponent object.
+ *
+ * @param font the new Font to be used for this MenuComponent.
+ */
+ public void setFont(Font font) {
+ toolkit.lockAWT();
+ try {
+ this.font = font;
+ } finally {
+ toolkit.unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the parent.
+ *
+ * @param parent the new parent
+ */
+ void setParent(MenuContainer parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Gets the location.
+ *
+ * @return the location
+ */
+ Point getLocation() {
+ // to be overridden
+ return new Point(0, 0);
+ }
+
+ /**
+ * Gets the width.
+ *
+ * @return the width
+ */
+ int getWidth() {
+ // to be overridden
+ return 1;
+ }
+
+ /**
+ * Gets the height.
+ *
+ * @return the height
+ */
+ int getHeight() {
+ // to be overridden
+ return 1;
+ }
+
+ /**
+ * Recursively find the menu item for a menu shortcut.
+ *
+ * @param gr the gr
+ *
+ * @return the menu item;
+ * or null if the item is not available for this shortcut
+ */
+ //???AWT
+ /*
+ MenuItem getShortcutMenuItemImpl(MenuShortcut ms) {
+ if (ms == null) {
+ return null;
+ }
+ for (int i = 0; i < getItemCount(); i++) {
+ MenuItem mi = getItem(i);
+ if (mi instanceof Menu) {
+ mi = ((Menu) mi).getShortcutMenuItemImpl(ms);
+ if (mi != null) {
+ return mi;
+ }
+ } else if (ms.equals(mi.getShortcut())) {
+ return mi;
+ }
+ }
+ return null;
+ }
+ */
+
+ void paint(Graphics gr) {
+ gr.setColor(Color.LIGHT_GRAY);
+ gr.fillRect(0, 0, getWidth(), getHeight());
+ gr.setColor(Color.BLACK);
+ }
+
+ /**
+ * Mouse events handler.
+ *
+ * @param eventId - one of the MouseEvent.MOUSE_* constants
+ * @param where - mouse location
+ * @param mouseButton - mouse button that was pressed or released
+ * @param when - event time
+ * @param modifiers - input event modifiers
+ */
+ void onMouseEvent(int eventId, Point where, int mouseButton, long when, int modifiers) {
+ // to be overridden
+ }
+
+ /**
+ * Keyboard event handler.
+ *
+ * @param eventId - one of the KeyEvent.KEY_* constants
+ * @param vKey - the key code
+ * @param when - event time
+ * @param modifiers - input event modifiers
+ */
+ void onKeyEvent(int eventId, int vKey, long when, int modifiers) {
+ // to be overridden
+ }
+
+ /**
+ * Post the ActionEvent or ItemEvent,
+ * depending on type of the menu item.
+ *
+ * @param index the index
+ *
+ * @return the item rect
+ */
+ //???AWT
+ /*
+ void fireItemAction(int item, long when, int modifiers) {
+ MenuItem mi = getItem(item);
+ mi.itemSelected(when, modifiers);
+ }
+
+ MenuItem getItem(int index) {
+ // to be overridden
+ return null;
+ }
+
+ int getItemCount() {
+ return 0;
+ }
+ */
+
+ /**
+ * @return The sub-menu of currently selecetd item,
+ * or null if such a sub-menu is not available
+ */
+ //???AWT
+ /*
+ Menu getSelectedSubmenu() {
+ if (selectedItemIndex < 0) {
+ return null;
+ }
+ MenuItem item = getItem(selectedItemIndex);
+ return (item instanceof Menu) ? (Menu) item : null;
+ }
+ */
+
+ /**
+ * Convenience method for selectItem(index, true)
+ */
+ //???AWT
+ /*
+ void selectItem(int index) {
+ selectItem(index, true);
+ }
+ */
+
+ /**
+ * Change the selection in the menu
+ * @param index - new selecetd item's index
+ * @param showSubMenu - if new selected item has a sub-menu,
+ * should that sub-menu be displayed
+ */
+ //???AWT
+ /*
+ void selectItem(int index, boolean showSubMenu) {
+ if (selectedItemIndex == index) {
+ return;
+ }
+ if (selectedItemIndex >= 0 && getItem(selectedItemIndex) instanceof Menu) {
+ ((Menu) getItem(selectedItemIndex)).hide();
+ }
+ MultiRectArea clip = getUpdateClip(index, selectedItemIndex);
+ selectedItemIndex = index;
+ Graphics gr = getGraphics(clip);
+ if (gr != null) {
+ paint(gr);
+ }
+ if (showSubMenu) {
+ showSubMenu(selectedItemIndex);
+ }
+ }
+ */
+
+ /**
+ * Change the selected item to the next one in the requested direction
+ * moving cyclically, skipping separators
+ * @param forward - the direction to move the selection
+ * @param showSubMenu - if new selected item has a sub-menu,
+ * should that sub-menu be displayed
+ */
+ //???AWT
+ /*
+ void selectNextItem(boolean forward, boolean showSubMenu) {
+ int selected = getSelectedItemIndex();
+ int count = getItemCount();
+ if (count == 0) {
+ return;
+ }
+ if (selected < 0) {
+ selected = (forward ? count - 1 : 0);
+ }
+ int i = selected;
+ do {
+ i = (forward ? (i + 1) : (i + count - 1)) % count;
+ i %= count;
+ MenuItem item = getItem(i);
+ if (!"-".equals(item.getLabel())) { //$NON-NLS-1$
+ selectItem(i, showSubMenu);
+ return;
+ }
+ } while (i != selected);
+ }
+
+
+ void showSubMenu(int index) {
+ if ((index < 0) || !isActive()) {
+ return;
+ }
+ MenuItem item = getItem(index);
+ if (item instanceof Menu) {
+ Menu menu = ((Menu) getItem(index));
+ if (menu.getItemCount() == 0) {
+ return;
+ }
+ Point location = getSubmenuLocation(index);
+ menu.show(location.x, location.y, false);
+ }
+ }
+ */
+
+ /**
+ * @return - the menu bar which is the root of crrent menu's hierarchy;
+ * or null if the hierarchy root is not a menu bar
+ */
+ //???AWT
+ /*
+ MenuBar getMenuBar() {
+ if (parent instanceof MenuBar) {
+ return (MenuBar) parent;
+ }
+ if (parent instanceof MenuComponent) {
+ return ((MenuComponent) parent).getMenuBar();
+ }
+ return null;
+ }
+
+ PopupBox getPopupBox() {
+ return null;
+ }
+ */
+
+ Rectangle getItemRect(int index) {
+ // to be overridden
+ return null;
+ }
+
+ /**
+ * Determine the clip region when menu selection is changed
+ * from index1 to index2.
+ *
+ * @param index1 - old selected intem
+ * @param index2 - new selected item
+ *
+ * @return - the region to repaint
+ */
+ final MultiRectArea getUpdateClip(int index1, int index2) {
+ MultiRectArea clip = new MultiRectArea();
+ if (index1 >= 0) {
+ clip.add(getItemRect(index1));
+ }
+ if (index2 >= 0) {
+ clip.add(getItemRect(index2));
+ }
+ return clip;
+ }
+
+ /**
+ * Gets the submenu location.
+ *
+ * @param index the index
+ *
+ * @return the submenu location
+ */
+ Point getSubmenuLocation(int index) {
+ // to be overridden
+ return new Point(0, 0);
+ }
+
+ /**
+ * Gets the selected item index.
+ *
+ * @return the selected item index
+ */
+ int getSelectedItemIndex() {
+ return selectedItemIndex;
+ }
+
+ /**
+ * Hide.
+ */
+ void hide() {
+ selectedItemIndex = -1;
+ if (parent instanceof MenuComponent) {
+ ((MenuComponent) parent).itemHidden(this);
+ }
+ }
+
+ /**
+ * Item hidden.
+ *
+ * @param mc the mc
+ */
+ void itemHidden(MenuComponent mc) {
+ // to be overridden
+ }
+
+ /**
+ * Checks if is visible.
+ *
+ * @return true, if is visible
+ */
+ boolean isVisible() {
+ return true;
+ }
+
+ /**
+ * Checks if is active.
+ *
+ * @return true, if is active
+ */
+ boolean isActive() {
+ return true;
+ }
+
+ /**
+ * Hide all menu hierarchy.
+ */
+ void endMenu() {
+ //???AWT: toolkit.dispatcher.popupDispatcher.deactivateAll();
+ }
+
+ /**
+ * Handle the mouse click or Enter key event on a menu's item.
+ *
+ * @param when - the event time
+ * @param modifiers - input event modifiers
+ */
+ void itemSelected(long when, int modifiers) {
+ endMenu();
+ }
+
+ /**
+ * Auto name.
+ *
+ * @return the string
+ */
+ String autoName() {
+ String name = getClass().getName();
+ if (name.indexOf("$") != -1) { //$NON-NLS-1$
+ return null;
+ }
+ //???AWT: int number = toolkit.autoNumber.nextMenuComponent++;
+ int number = 0;
+ name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$
+ return name;
+ }
+
+ /**
+ * Creates the Graphics object for the pop-up box of this menu component.
+ *
+ * @param clip - the clip to set on this Graphics
+ *
+ * @return - the created Graphics object,
+ * or null if such object is not available.
+ */
+ Graphics getGraphics(MultiRectArea clip) {
+ // to be overridden
+ return null;
+ }
+
+ /**
+ * @return accessible context specific for particular menu component
+ */
+ //???AWT
+ /*
+ AccessibleContext createAccessibleContext() {
+ return null;
+ }
+ */
+}
diff --git a/awt/java/awt/MenuContainer.java b/awt/java/awt/MenuContainer.java
new file mode 100644
index 0000000..7a48f13
--- /dev/null
+++ b/awt/java/awt/MenuContainer.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The MenuContainer interface represents all menu containers.
+ */
+public interface MenuContainer {
+
+ /**
+ * Removes the specified MenuComponent from the MenuContainer.
+ *
+ * @param c the MenuComponent.
+ */
+ public void remove(MenuComponent c);
+
+ /**
+ * Gets the Font of the MenuContainer.
+ *
+ * @return the font of the MenuContainer.
+ */
+ public Font getFont();
+
+ /**
+ * Posts an Event.
+ *
+ * @param e the Event.
+ *
+ * @return true if the event is posted successfully;
+ * false otherwise.
+ *
+ * @deprecated Replaced by dispatchEvent method.
+ */
+ @Deprecated
+ public boolean postEvent(Event e);
+
+}
+
diff --git a/awt/java/awt/ModalContext.java b/awt/java/awt/ModalContext.java
new file mode 100644
index 0000000..32a5912
--- /dev/null
+++ b/awt/java/awt/ModalContext.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ *
+ * The context for nested event loop. It can be dialog, popup menu etc.
+ */
+class ModalContext {
+
+ private boolean running = false;
+
+ private final Toolkit toolkit;
+
+ ModalContext() {
+ toolkit = Toolkit.getDefaultToolkit();
+ }
+
+ /**
+ * Set up and run modal loop in this context
+ *
+ */
+ void runModalLoop() {
+ running = true;
+ toolkit.dispatchThread.runModalLoop(this);
+ }
+
+ /**
+ * Leave the modal loop running in this context
+ * This method doesn't stops the loop immediately,
+ * it just sets the flag that says the modal loop to stop
+ *
+ */
+ void endModalLoop() {
+ running = false;
+ }
+
+ /**
+ *
+ * @return modal loop is currently running in this context
+ */
+ boolean isModalLoopRunning() {
+ return running;
+ }
+
+}
diff --git a/awt/java/awt/MouseDispatcher.java b/awt/java/awt/MouseDispatcher.java
new file mode 100644
index 0000000..df48f9d
--- /dev/null
+++ b/awt/java/awt/MouseDispatcher.java
@@ -0,0 +1,418 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev, Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.Dispatcher.MouseGrabManager;
+import java.util.EventListener;
+
+import org.apache.harmony.awt.wtk.NativeEvent;
+import org.apache.harmony.awt.wtk.NativeWindow;
+
+
+class MouseDispatcher {
+
+ // Fields for synthetic mouse click events generation
+ private static final int clickDelta = 5;
+ private final long[] lastPressTime = new long[] {0l, 0l, 0l};
+ private final Point[] lastPressPos = new Point[] {null, null, null};
+ private final boolean[] buttonPressed = new boolean[] {false, false, false};
+ private final int[] clickCount = new int[] {0, 0, 0};
+
+ // Fields for mouse entered/exited support
+ private Component lastUnderPointer = null;
+ private final Point lastScreenPos = new Point(-1, -1);
+
+ // Fields for redundant mouse moved/dragged filtering
+ private Component lastUnderMotion = null;
+ private Point lastLocalPos = new Point(-1, -1);
+
+ private final MouseGrabManager mouseGrabManager;
+ private final Toolkit toolkit;
+
+ static Point convertPoint(Component src, int x, int y, Component dest) {
+ Point srcPoint = getAbsLocation(src);
+ Point destPoint = getAbsLocation(dest);
+
+ return new Point(x + (srcPoint.x - destPoint.x),
+ y + (srcPoint.y - destPoint.y));
+ }
+
+ static Point convertPoint(Component src, Point p, Component dst) {
+ return convertPoint(src, p.x, p.y, dst);
+ }
+
+ private static Point getAbsLocation(Component comp) {
+ Point location = new Point(0, 0);
+// BEGIN android-changed: AWT components not supported
+// for (Component parent = comp; parent != null; parent = parent.parent) {
+// Point parentPos = (parent instanceof EmbeddedWindow ?
+// parent.getNativeWindow().getScreenPos() :
+// parent.getLocation());
+//
+// location.translate(parentPos.x, parentPos.y);
+//
+// if (parent instanceof Window) {
+// break;
+// }
+// }
+// END android-changed
+
+ return location;
+ }
+
+ MouseDispatcher(MouseGrabManager mouseGrabManager,
+ Toolkit toolkit) {
+ this.mouseGrabManager = mouseGrabManager;
+ this.toolkit = toolkit;
+ }
+
+ Point getPointerPos() {
+ return lastScreenPos;
+ }
+
+ boolean dispatch(Component src, NativeEvent event) {
+ int id = event.getEventId();
+
+ lastScreenPos.setLocation(event.getScreenPos());
+ checkMouseEnterExit(event.getInputModifiers(), event.getTime());
+
+ if (id == MouseEvent.MOUSE_WHEEL) {
+// BEGIN android-changed: AWT components not supported
+// dispatchWheelEvent(src, event);
+// END android-changed
+ } else if ((id != MouseEvent.MOUSE_ENTERED) &&
+ (id != MouseEvent.MOUSE_EXITED)) {
+ PointerInfo info = new PointerInfo(src, event.getLocalPos());
+
+ mouseGrabManager.preprocessEvent(event);
+ findEventSource(info);
+ if ((id == MouseEvent.MOUSE_PRESSED) ||
+ (id == MouseEvent.MOUSE_RELEASED)) {
+
+ dispatchButtonEvent(info, event);
+ } else if ((id == MouseEvent.MOUSE_MOVED) ||
+ (id == MouseEvent.MOUSE_DRAGGED)) {
+
+ dispatchMotionEvent(info, event);
+ }
+ }
+
+ return false;
+ }
+
+ private void checkMouseEnterExit(int modifiers, long when) {
+// BEGIN android-changed: AWT components not supported
+// PointerInfo info = findComponentUnderPointer();
+// Component curUnderPointer =
+// propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK,
+// MouseListener.class, false).src;
+//
+// if (curUnderPointer != lastUnderPointer) {
+// Point pos = info.position;
+// if ((lastUnderPointer != null) &&
+// lastUnderPointer.isMouseExitedExpected()) {
+//
+// Point exitPos = convertPoint(null, lastScreenPos.x,
+// lastScreenPos.y, lastUnderPointer);
+//
+// postMouseEnterExit(MouseEvent.MOUSE_EXITED, modifiers, when,
+// exitPos.x, exitPos.y, lastUnderPointer);
+// }
+// setCursor(curUnderPointer);
+// if (curUnderPointer != null) {
+// postMouseEnterExit(MouseEvent.MOUSE_ENTERED, modifiers, when,
+// pos.x, pos.y, curUnderPointer);
+// }
+// lastUnderPointer = curUnderPointer;
+// }
+// END android-changed
+ }
+
+ private void setCursor(Component comp) {
+ if (comp == null) {
+ return;
+ }
+ Component grabOwner = mouseGrabManager.getSyntheticGrabOwner();
+ Component cursorComp = ((grabOwner != null) &&
+ grabOwner.isShowing() ? grabOwner : comp);
+ cursorComp.setCursor();
+ }
+
+ private void postMouseEnterExit(int id, int mod, long when,
+ int x, int y, Component comp) {
+ if (comp.isIndirectlyEnabled()) {
+ toolkit.getSystemEventQueueImpl().postEvent(
+ new MouseEvent(comp, id, when, mod, x, y, 0, false));
+ comp.setMouseExitedExpected(id == MouseEvent.MOUSE_ENTERED);
+ } else {
+ comp.setMouseExitedExpected(false);
+ }
+ }
+
+ // BEGIN android-changed: AWT components not supported
+// private PointerInfo findComponentUnderPointer() {
+// NativeWindow nativeWindow = toolkit.getWindowFactory().
+// getWindowFromPoint(lastScreenPos);
+//
+// if (nativeWindow != null) {
+// Component comp = toolkit.getComponentById(nativeWindow.getId());
+//
+// if (comp != null) {
+// Window window = comp.getWindowAncestor();
+// Point pointerPos = convertPoint(null, lastScreenPos.x,
+// lastScreenPos.y, window);
+//
+// if (window.getClient().contains(pointerPos)) {
+// PointerInfo info = new PointerInfo(window, pointerPos);
+//
+// fall2Child(info);
+//
+// return info;
+// }
+// }
+// }
+//
+// return new PointerInfo(null, null);
+// }
+// END android-changed
+
+ private void findEventSource(PointerInfo info) {
+ Component grabOwner = mouseGrabManager.getSyntheticGrabOwner();
+
+ if (grabOwner != null && grabOwner.isShowing()) {
+ info.position = convertPoint(info.src, info.position, grabOwner);
+ info.src = grabOwner;
+ } else {
+ //???AWT: rise2TopLevel(info);
+ //???AWT: fall2Child(info);
+ }
+ }
+
+ // BEGIN android-changed: AWT components not supported
+// private void rise2TopLevel(PointerInfo info) {
+// while (!(info.src instanceof Window)) {
+// info.position.translate(info.src.x, info.src.y);
+// info.src = info.src.parent;
+// }
+// }
+//
+// private void fall2Child(PointerInfo info) {
+// Insets insets = info.src.getInsets();
+//
+// final Point pos = info.position;
+// final int x = pos.x;
+// final int y = pos.y;
+// if ((x >= insets.left) && (y >= insets.top) &&
+// (x < (info.src.w - insets.right)) &&
+// (y < (info.src.h - insets.bottom)))
+// {
+// Component[] children = ((Container) info.src).getComponents();
+//
+// for (Component child : children) {
+// if (child.isShowing()) {
+// if (child.contains(x - child.getX(),
+// y - child.getY()))
+// {
+// info.src = child;
+// pos.translate(-child.x, -child.y);
+//
+// if (child instanceof Container) {
+// fall2Child(info);
+// }
+//
+// return;
+// }
+// }
+// }
+// }
+// }
+// END android-changed
+
+ private void dispatchButtonEvent(PointerInfo info, NativeEvent event) {
+ int button = event.getMouseButton();
+ long time = event.getTime();
+ int id = event.getEventId();
+ int index = button - 1;
+ boolean clickRequired = false;
+
+ propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK,
+ MouseListener.class, false);
+ if (id == MouseEvent.MOUSE_PRESSED) {
+ int clickInterval = toolkit.dispatcher.clickInterval;
+ mouseGrabManager.onMousePressed(info.src);
+ buttonPressed[index] = true;
+ clickCount[index] = (!deltaExceeded(index, info) &&
+ ((time - lastPressTime[index]) <= clickInterval)) ?
+ clickCount[index] + 1 : 1;
+ lastPressTime[index] = time;
+ lastPressPos[index] = info.position;
+ } else {
+ mouseGrabManager.onMouseReleased(info.src);
+ // set cursor back on synthetic mouse grab end:
+// BEGIN android-changed: AWT components not supported
+// setCursor(findComponentUnderPointer().src);
+// END android-changed
+ if (buttonPressed[index]) {
+ buttonPressed[index] = false;
+ clickRequired = !deltaExceeded(index, info);
+ } else {
+ clickCount[index] = 0;
+ }
+ }
+ if (info.src.isIndirectlyEnabled()) {
+ final Point pos = info.position;
+ final int mod = event.getInputModifiers();
+ toolkit.getSystemEventQueueImpl().postEvent(
+ new MouseEvent(info.src, id, time, mod, pos.x,
+ pos.y, clickCount[index],
+ event.getTrigger(), button));
+ if (clickRequired) {
+ toolkit.getSystemEventQueueImpl().postEvent(
+ new MouseEvent(info.src,
+ MouseEvent.MOUSE_CLICKED,
+ time, mod, pos.x, pos.y,
+ clickCount[index], false,
+ button));
+ }
+ }
+ }
+
+ private boolean deltaExceeded(int index, PointerInfo info) {
+ final Point lastPos = lastPressPos[index];
+ if (lastPos == null) {
+ return true;
+ }
+ return ((Math.abs(lastPos.x - info.position.x) > clickDelta) ||
+ (Math.abs(lastPos.y - info.position.y) > clickDelta));
+ }
+
+ private void dispatchMotionEvent(PointerInfo info, NativeEvent event) {
+ propagateEvent(info, AWTEvent.MOUSE_MOTION_EVENT_MASK,
+ MouseMotionListener.class, false);
+ final Point pos = info.position;
+ if ((lastUnderMotion != info.src) ||
+ !lastLocalPos.equals(pos)) {
+
+ lastUnderMotion = info.src;
+ lastLocalPos = pos;
+
+ if (info.src.isIndirectlyEnabled()) {
+ toolkit.getSystemEventQueueImpl().postEvent(
+ new MouseEvent(info.src, event.getEventId(),
+ event.getTime(),
+ event.getInputModifiers(),
+ pos.x, pos.y, 0, false));
+ }
+ }
+ }
+
+ MouseWheelEvent createWheelEvent(Component src, NativeEvent event,
+ Point where) {
+
+ Integer scrollAmountProperty =
+ (Integer)toolkit.getDesktopProperty("awt.wheelScrollingSize"); //$NON-NLS-1$
+ int amount = 1;
+ int type = MouseWheelEvent.WHEEL_UNIT_SCROLL;
+
+ if (scrollAmountProperty != null) {
+ amount = scrollAmountProperty.intValue();
+ if (amount == -1) {
+ type = MouseWheelEvent.WHEEL_BLOCK_SCROLL;
+ amount = 1;
+ }
+ }
+ return new MouseWheelEvent(src, event.getEventId(),
+ event.getTime(), event.getInputModifiers(),
+ where.x, where.y, 0, false, type, amount,
+ event.getWheelRotation());
+ }
+
+// BEGIN android-changed: AWT components not supported
+// private void dispatchWheelEvent(Component src, NativeEvent event) {
+// PointerInfo info = findComponentUnderPointer();
+//
+// if (info.src == null) {
+// info.src = src;
+// info.position = event.getLocalPos();
+// }
+//
+// propagateEvent(info, AWTEvent.MOUSE_WHEEL_EVENT_MASK,
+// MouseWheelListener.class, true);
+// if ((info.src != null) && info.src.isIndirectlyEnabled()) {
+// toolkit.getSystemEventQueueImpl().postEvent(
+// createWheelEvent(info.src, event, info.position));
+// }
+// }
+// END android-changed
+
+ private PointerInfo propagateEvent(PointerInfo info, long mask,
+ Class<? extends EventListener> type, boolean pierceHW) {
+ Component src = info.src;
+ while ((src != null) &&
+ (src.isLightweight() || pierceHW) &&
+ !(src.isMouseEventEnabled(mask) ||
+ (src.getListeners(type).length > 0))) {
+
+ info.position.translate(src.x, src.y);
+// BEGIN android-changed: AWT components not supported
+// src = src.parent;
+// END android-changed
+ info.src = src;
+ }
+
+ return info;
+ }
+
+// BEGIN android-changed: AWT components not supported
+// Window findWindowAt(Point p) {
+// NativeWindow nativeWindow =
+// toolkit.getWindowFactory().getWindowFromPoint(p);
+//
+// Window window = null;
+// if (nativeWindow != null) {
+// Component comp = toolkit.getComponentById(nativeWindow.getId());
+//
+// if (comp != null) {
+// window = comp.getWindowAncestor();
+// }
+// }
+// return window;
+// }
+// END android-changed
+
+ private class PointerInfo {
+
+ Component src;
+ Point position;
+
+ PointerInfo(Component src, Point position) {
+ this.src = src;
+ this.position = position;
+ }
+
+ }
+
+}
diff --git a/awt/java/awt/Paint.java b/awt/java/awt/Paint.java
new file mode 100644
index 0000000..f8732c8
--- /dev/null
+++ b/awt/java/awt/Paint.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+
+/**
+ * The Paint interface provides possibility of generating
+ * color patterns in device space for fill, draw, or stroke operations
+ * in a Graphics2D.
+ */
+public interface Paint extends Transparency {
+
+ /**
+ * Creates the PaintContext which is used to generate color
+ * patterns for rendering operations of Graphics2D.
+ *
+ * @param cm the ColorModel object, or null.
+ * @param deviceBounds the Rectangle represents the bounding box of
+ * device space for the graphics rendering operations.
+ * @param userBounds the Rectangle represents bounding box of
+ * user space for the graphics rendering operations.
+ * @param xform the AffineTransform for translation from user space
+ * to device space.
+ * @param hints the RenderingHints preferences.
+ *
+ * @return the PaintContext for generating color patterns.
+ */
+ PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
+ Rectangle2D userBounds, AffineTransform xform,
+ RenderingHints hints);
+}
diff --git a/awt/java/awt/PaintContext.java b/awt/java/awt/PaintContext.java
new file mode 100644
index 0000000..647de8b
--- /dev/null
+++ b/awt/java/awt/PaintContext.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+
+/**
+ * The PaintContext interface determines the specific environment for
+ * generating color patterns in device space for fill, draw, or stroke
+ * rendering operations using Graphics2D. This interface provides colors
+ * through the Raster object associated with the specific ColorModel
+ * for Graphics2D rendering operations.
+ */
+public interface PaintContext {
+
+ /**
+ * Releases the resources allocated for the operation.
+ */
+ void dispose();
+
+ /**
+ * Gets the color model.
+ *
+ * @return the ColorModel object.
+ */
+ ColorModel getColorModel();
+
+ /**
+ * Gets the Raster which defines the colors of the specified rectangular
+ * area for Graphics2D rendering operations.
+ *
+ * @param x the X coordinate of the device space area for which
+ * colors are generated.
+ * @param y the Y coordinate of the device space area for which
+ * colors are generated.
+ * @param w the width of the device space area for which
+ * colors are generated.
+ * @param h the height of the device space area for which
+ * colors are generated.
+ *
+ * @return the Raster object which contains the colors of the specified
+ * rectangular area for Graphics2D rendering operations.
+ */
+ Raster getRaster(int x, int y, int w, int h);
+}
diff --git a/awt/java/awt/Point.java b/awt/java/awt/Point.java
new file mode 100644
index 0000000..99418ed
--- /dev/null
+++ b/awt/java/awt/Point.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.Point2D;
+import java.io.Serializable;
+
+/**
+ * The Point class represents a point location with coordinates X, Y in
+ * current coordinate system.
+ */
+public class Point extends Point2D implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -5276940640259749850L;
+
+ /** The X coordinate of Point. */
+ public int x;
+
+ /** The Y coordinate of Point. */
+ public int y;
+
+ /**
+ * Instantiates a new point with (0, O) coordinates, the origin of
+ * coordinate system.
+ */
+ public Point() {
+ setLocation(0, 0);
+ }
+
+ /**
+ * Instantiates a new point with (x, y) coordinates.
+ *
+ * @param x the X coordinate of Point.
+ * @param y the Y coordinate of Point.
+ */
+ public Point(int x, int y) {
+ setLocation(x, y);
+ }
+
+ /**
+ * Instantiates a new point, giving it the same locaion as
+ * the parameter p.
+ *
+ * @param p the Point object giving the coordinates of the new point.
+ */
+ public Point(Point p) {
+ setLocation(p.x, p.y);
+ }
+
+ /**
+ * Compares current Point with the specified object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the Object being compared is a Point
+ * whose coordinates are equal to the coordinates of this
+ * Point, otherwise false.
+ *
+ * @see java.awt.geom.Point2D#equals(Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Point) {
+ Point p = (Point)obj;
+ return x == p.x && y == p.y;
+ }
+ return false;
+ }
+
+ /**
+ * Returns string representation of the current Point object.
+ *
+ * @return a string representation of the current Point object.
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /**
+ * Gets X coordinate of Point as a double.
+ *
+ * @return X coordinate of the point as a double.
+ *
+ * @see java.awt.geom.Point2D#getX()
+ */
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ /**
+ * Gets Y coordinate of Point as a double.
+ *
+ * @return Y coordinate of the point as a double.
+ *
+ * @see java.awt.geom.Point2D#getY()
+ */
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ /**
+ * Gets the location of the Point as a new Point object.
+ *
+ * @return a copy of the Point.
+ */
+ public Point getLocation() {
+ return new Point(x, y);
+ }
+
+ /**
+ * Sets the location of the Point to the same coordinates as p.
+ *
+ * @param p the Point that gives the new location.
+ */
+ public void setLocation(Point p) {
+ setLocation(p.x, p.y);
+ }
+
+ /**
+ * Sets the location of the Point to the coordinates X, Y.
+ *
+ * @param x the X coordinate of the Point's new location.
+ * @param y the Y coordinate of the Point's new location.
+ */
+ public void setLocation(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Sets the location of Point to the specified double coordinates.
+ *
+ * @param x the X the Point's new location.
+ * @param y the Y the Point's new location.
+ *
+ * @see java.awt.geom.Point2D#setLocation(double, double)
+ */
+ @Override
+ public void setLocation(double x, double y) {
+ x = x < Integer.MIN_VALUE ? Integer.MIN_VALUE : x > Integer.MAX_VALUE ? Integer.MAX_VALUE : x;
+ y = y < Integer.MIN_VALUE ? Integer.MIN_VALUE : y > Integer.MAX_VALUE ? Integer.MAX_VALUE : y;
+ setLocation((int)Math.round(x), (int)Math.round(y));
+ }
+
+ /**
+ * Moves the Point to the specified (x, y) location.
+ *
+ * @param x the X coordinate of the new location.
+ * @param y the Y coordinate of the new location.
+ */
+ public void move(int x, int y) {
+ setLocation(x, y);
+ }
+
+ /**
+ * Translates current Point moving it from the position (x, y)
+ * to the new position given by (x+dx, x+dy) coordinates.
+ *
+ * @param dx the horizontal delta - the Point is moved to this distance along
+ * X axis.
+ * @param dy the vertical delta - the Point is moved to this distance along
+ * Y axis.
+ */
+ public void translate(int dx, int dy) {
+ x += dx;
+ y += dy;
+ }
+
+}
+
diff --git a/awt/java/awt/Polygon.java b/awt/java/awt/Polygon.java
new file mode 100644
index 0000000..6f3fc97
--- /dev/null
+++ b/awt/java/awt/Polygon.java
@@ -0,0 +1,494 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.Serializable;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.*;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Polygon class defines an closed area specified by n vertices and
+ * n edges. The coordinates of the vertices are specified by x, y arrays.
+ * The edges are the line segments from the point (x[i], y[i]) to the point
+ * (x[i+1], y[i+1]), for -1 < i < (n-1) plus the line segment from
+ * the point (x[n-1], y[n-1]) to the point (x[0], y[0]) point.
+ * The Polygon is empty if the number of vertices is zero.
+ */
+public class Polygon implements Shape, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -6460061437900069969L;
+
+ /** The points buffer capacity. */
+ private static final int BUFFER_CAPACITY = 4;
+
+ /** The number of Polygon vertices.*/
+ public int npoints;
+
+ /** The array of X coordinates of the vertices. */
+ public int[] xpoints;
+
+ /** The array of Y coordinates of the vertices. */
+ public int[] ypoints;
+
+ /**
+ * The smallest Rectangle that completely contains this Polygon.
+ */
+ protected Rectangle bounds;
+
+ /*
+ * Polygon path iterator
+ */
+ /**
+ * The internal Class Iterator.
+ */
+ class Iterator implements PathIterator {
+
+ /** The source Polygon object. */
+ public Polygon p;
+
+ /** The path iterator transformation. */
+ public AffineTransform t;
+
+ /** The current segmenet index. */
+ public int index;
+
+ /**
+ * Constructs a new Polygon.Iterator for the given polygon and transformation
+ *
+ * @param at - the AffineTransform object to apply rectangle path
+ * @param p the p
+ */
+ public Iterator(AffineTransform at, Polygon p) {
+ this.p = p;
+ this.t = at;
+ if (p.npoints == 0) {
+ index = 1;
+ }
+ }
+
+ public int getWindingRule() {
+ return WIND_EVEN_ODD;
+ }
+
+ public boolean isDone() {
+ return index > p.npoints;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.110=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.110")); //$NON-NLS-1$
+ }
+ if (index == p.npoints) {
+ return SEG_CLOSE;
+ }
+ coords[0] = p.xpoints[index];
+ coords[1] = p.ypoints[index];
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return index == 0 ? SEG_MOVETO : SEG_LINETO;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.110=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.110")); //$NON-NLS-1$
+ }
+ if (index == p.npoints) {
+ return SEG_CLOSE;
+ }
+ coords[0] = p.xpoints[index];
+ coords[1] = p.ypoints[index];
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return index == 0 ? SEG_MOVETO : SEG_LINETO;
+ }
+ }
+
+ /**
+ * Instantiates a new empty polygon.
+ */
+ public Polygon() {
+ xpoints = new int[BUFFER_CAPACITY];
+ ypoints = new int[BUFFER_CAPACITY];
+ }
+
+ /**
+ * Instantiates a new polygon with the specified number of vertices,
+ * and the given arrays of x, y vertex coordinates. The length of
+ * each coordinate array may not be less than the specified number of
+ * vertices but may be greater. Only the first n elements are used from
+ * each coordinate array.
+ *
+ * @param xpoints the array of X vertex coordinates.
+ * @param ypoints the array of Y vertex coordinates.
+ * @param npoints the number vertices of the polygon.
+ * @throws IndexOutOfBoundsException if the length of xpoints or ypoints
+ * is less than n.
+ * @throws NegativeArraySizeException if n is negative.
+ */
+ public Polygon(int[] xpoints, int[] ypoints, int npoints) {
+ if (npoints > xpoints.length || npoints > ypoints.length) {
+ // awt.111=Parameter npoints is greater than array length
+ throw new IndexOutOfBoundsException(Messages.getString("awt.111")); //$NON-NLS-1$
+ }
+ if (npoints < 0) {
+ // awt.112=Negative number of points
+ throw new NegativeArraySizeException(Messages.getString("awt.112")); //$NON-NLS-1$
+ }
+ this.npoints = npoints;
+ this.xpoints = new int[npoints];
+ this.ypoints = new int[npoints];
+ System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
+ System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
+ }
+
+ /**
+ * Resets the current Polygon to an empty Polygon. More precisely,
+ * the number of Polygon vertices is set to zero, but x, y coordinates
+ * arrays are not affected.
+ */
+ public void reset() {
+ npoints = 0;
+ bounds = null;
+ }
+
+ /**
+ * Invalidates the data that depends on the vertex coordinates.
+ * This method should be called after direct manipulations
+ * of the x, y vertex coordinates arrays to avoid unpredictable
+ * results of methods which rely on the bounding box.
+ */
+ public void invalidate() {
+ bounds = null;
+ }
+
+ /**
+ * Adds the point to the Polygon and updates the bounding box
+ * accordingly.
+ *
+ * @param px the X coordinate of the added vertex.
+ * @param py the Y coordinate of the added vertex.
+ */
+ public void addPoint(int px, int py) {
+ if (npoints == xpoints.length) {
+ int[] tmp;
+
+ tmp = new int[xpoints.length + BUFFER_CAPACITY];
+ System.arraycopy(xpoints, 0, tmp, 0, xpoints.length);
+ xpoints = tmp;
+
+ tmp = new int[ypoints.length + BUFFER_CAPACITY];
+ System.arraycopy(ypoints, 0, tmp, 0, ypoints.length);
+ ypoints = tmp;
+ }
+
+ xpoints[npoints] = px;
+ ypoints[npoints] = py;
+ npoints++;
+
+ if (bounds != null) {
+ bounds.setFrameFromDiagonal(
+ Math.min(bounds.getMinX(), px),
+ Math.min(bounds.getMinY(), py),
+ Math.max(bounds.getMaxX(), px),
+ Math.max(bounds.getMaxY(), py));
+ }
+ }
+
+ /**
+ * Gets the bounding rectangle of the Polygon. The bounding rectangle
+ * is the smallest rectangle which contains the Polygon.
+ *
+ * @return the bounding rectangle of the Polygon.
+ *
+ * @see java.awt.Shape#getBounds()
+ */
+ public Rectangle getBounds() {
+ if (bounds != null) {
+ return bounds;
+ }
+ if (npoints == 0) {
+ return new Rectangle();
+ }
+
+ int bx1 = xpoints[0];
+ int by1 = ypoints[0];
+ int bx2 = bx1;
+ int by2 = by1;
+
+ for (int i = 1; i < npoints; i++) {
+ int x = xpoints[i];
+ int y = ypoints[i];
+ if (x < bx1) {
+ bx1 = x;
+ } else if (x > bx2) {
+ bx2 = x;
+ }
+ if (y < by1) {
+ by1 = y;
+ } else if (y > by2) {
+ by2 = y;
+ }
+ }
+
+ return bounds = new Rectangle(bx1, by1, bx2 - bx1, by2 - by1);
+ }
+
+ /**
+ * Gets the bounding rectangle of the Polygon. The bounding rectangle
+ * is the smallest rectangle which contains the Polygon.
+ *
+ * @return the bounding rectangle of the Polygon.
+ *
+ * @deprecated Use getBounds() method.
+ */
+ @Deprecated
+ public Rectangle getBoundingBox() {
+ return getBounds();
+ }
+
+ /**
+ * Gets the Rectangle2D which represents Polygon bounds.
+ * The bounding rectangle is the smallest rectangle which contains
+ * the Polygon.
+ *
+ * @return the bounding rectangle of the Polygon.
+ *
+ * @see java.awt.Shape#getBounds2D()
+ */
+ public Rectangle2D getBounds2D() {
+ return getBounds().getBounds2D();
+ }
+
+ /**
+ * Translates all vertices of Polygon the specified distances
+ * along X, Y axis.
+ *
+ * @param mx the distance to translate horizontally.
+ * @param my the distance to translate vertically.
+ */
+ public void translate(int mx, int my) {
+ for (int i = 0; i < npoints; i++) {
+ xpoints[i] += mx;
+ ypoints[i] += my;
+ }
+ if (bounds != null) {
+ bounds.translate(mx, my);
+ }
+ }
+
+ /**
+ * Checks whether or not the point given by the coordinates x, y lies inside
+ * the Polygon.
+ *
+ * @param x the X coordinate of the point to check.
+ * @param y the Y coordinate of the point to check.
+ *
+ * @return true, if the specified point lies inside the Polygon,
+ * otherwise false.
+ *
+ * @deprecated Use contains(int, int) method.
+ */
+ @Deprecated
+ public boolean inside(int x, int y) {
+ return contains((double) x, (double) y);
+ }
+
+ /**
+ * Checks whether or not the point given by the coordinates x, y lies inside
+ * the Polygon.
+ *
+ * @param x the X coordinate of the point to check.
+ * @param y the Y coordinate of the point to check.
+ *
+ * @return true, if the specified point lies inside the Polygon,
+ * otherwise false.
+ */
+ public boolean contains(int x, int y) {
+ return contains((double) x, (double) y);
+ }
+
+ /**
+ * Checks whether or not the point with specified double coordinates
+ * lies inside the Polygon.
+ *
+ * @param x the X coordinate of the point to check.
+ * @param y the Y coordinate of the point to check.
+ *
+ * @return true, if the point given by the double coordinates
+ * lies inside the Polygon, otherwise false.
+ *
+ * @see java.awt.Shape#contains(double, double)
+ */
+ public boolean contains(double x, double y) {
+ return Crossing.isInsideEvenOdd(Crossing.crossShape(this, x, y));
+ }
+
+ /**
+ * Checks whether or not the rectangle determined by the parameters
+ * [x, y, width, height] lies inside the Polygon.
+ *
+ * @param x the X coordinate of the rectangles's left upper
+ * corner as a double.
+ * @param y the Y coordinate of the rectangles's left upper
+ * corner as a double.
+ * @param width the width of rectangle as a double.
+ * @param width the height of rectangle as a double.
+ *
+ * @return true, if the specified rectangle lies inside the Polygon,
+ * otherwise false.
+ *
+ * @see java.awt.Shape#contains(double, double, double, double)
+ */
+ public boolean contains(double x, double y, double width, double height) {
+ int cross = Crossing.intersectShape(this, x, y, width, height);
+ return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
+ }
+
+ /**
+ * Checks whether or not the rectangle determined by the parameters
+ * [x, y, width, height] intersects the interior of
+ * the Polygon.
+ *
+ * @param x the X coordinate of the rectangles's left upper
+ * corner as a double.
+ * @param y the Y coordinate of the rectangles's left upper
+ * corner as a double.
+ * @param width the width of rectangle as a double.
+ * @param width the height of rectangle as a double.
+ *
+ * @return true, if the specified rectangle intersects the interior of
+ * the Polygon, otherwise false.
+ *
+ * @see java.awt.Shape#intersects(double, double, double, double)
+ */
+ public boolean intersects(double x, double y, double width, double height) {
+ int cross = Crossing.intersectShape(this, x, y, width, height);
+ return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
+ }
+
+ /**
+ * Checks whether or not the specified rectangle lies inside the Polygon.
+ *
+ * @param rect the Rectangle2D object.
+ *
+ * @return true, if the specified rectangle lies inside the Polygon,
+ * otherwise false.
+ *
+ * @see java.awt.Shape#contains(java.awt.geom.Rectangle2D)
+ */
+ public boolean contains(Rectangle2D rect) {
+ return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ /**
+ * Checks whether or not the specified Point lies inside the Polygon.
+ *
+ * @param point the Point object.
+ *
+ * @return true, if the specified Point lies inside the Polygon,
+ * otherwise false.
+ */
+ public boolean contains(Point point) {
+ return contains(point.getX(), point.getY());
+ }
+
+ /**
+ * Checks whether or not the specified Point2D lies inside the Polygon.
+ *
+ * @param point the Point2D object.
+ *
+ * @return true, if the specified Point2D lies inside the Polygon,
+ * otherwise false.
+ *
+ * @see java.awt.Shape#contains(java.awt.geom.Point2D)
+ */
+ public boolean contains(Point2D point) {
+ return contains(point.getX(), point.getY());
+ }
+
+ /**
+ * Checks whether or not the interior of rectangle specified by
+ * the Rectangle2D object intersects the interior of the Polygon.
+ *
+ * @param rect the Rectangle2D object.
+ *
+ * @return true, if the Rectangle2D intersects the interior of
+ * the Polygon, otherwise false.
+ *
+ * @see java.awt.Shape#intersects(java.awt.geom.Rectangle2D)
+ */
+ public boolean intersects(Rectangle2D rect) {
+ return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ /**
+ * Gets the PathIterator object which gives the coordinates of
+ * the polygon, transformed according to the specified AffineTransform.
+ *
+ * @param t the specified AffineTransform object, or null.
+ *
+ * @return PathIterator object for the Polygon.
+ *
+ * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform)
+ */
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(t, this);
+ }
+
+ /**
+ * Gets the PathIterator object which gives the coordinates of
+ * the polygon, transformed according to the specified AffineTransform.
+ * The flatness parameter is ignored.
+ *
+ * @param t the specified AffineTransform object, or null.
+ * @param flatness the maximum number of the control points for
+ * a given curve which varies from colinear before a subdivided curve
+ * is replaced by a straight line connecting the endpoints.
+ * This parameter is ignored for the Polygon class.
+ *
+ * @return PathIterator object for the Polygon.
+ *
+ * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform, double)
+ */
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new Iterator(t, this);
+ }
+
+}
+
diff --git a/awt/java/awt/Rectangle.java b/awt/java/awt/Rectangle.java
new file mode 100644
index 0000000..86c4dfc
--- /dev/null
+++ b/awt/java/awt/Rectangle.java
@@ -0,0 +1,686 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.Rectangle2D;
+import java.io.Serializable;
+
+/**
+ * The Rectangle class defines the rectangular area in terms of its
+ * upper left corner coordinates [x,y], its width, and its height.
+ * A Rectangle specified by [x, y, width, height] parameters has an
+ * outline path with corners at [x, y], [x + width,y], [x + width,y + height],
+ * and [x, y + height].
+ * <br><br>
+ * The rectangle is empty if the width or height is negative or zero.
+ * In this case the isEmpty method returns true.
+ */
+public class Rectangle extends Rectangle2D implements Shape, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -4345857070255674764L;
+
+ /** The X coordinate of the rectangle's left upper corner. */
+ public int x;
+
+ /** The Y coordinate of the rectangle's left upper corner. */
+ public int y;
+
+ /** The width of rectangle. */
+ public int width;
+
+ /** The height of rectangle. */
+ public int height;
+
+ /**
+ * Instantiates a new rectangle with [0, 0] upper left corner coordinates,
+ * the width and the height are zero.
+ */
+ public Rectangle() {
+ setBounds(0, 0, 0, 0);
+ }
+
+ /**
+ * Instantiates a new rectangle whose upper left corner coordinates are
+ * given by the Point object (p.X and p.Y), and the width and
+ * the height are zero.
+ *
+ * @param p the Point specifies the upper left corner coordinates of
+ * the rectangle.
+ */
+ public Rectangle(Point p) {
+ setBounds(p.x, p.y, 0, 0);
+ }
+
+ /**
+ * Instantiates a new rectangle whose upper left corner coordinates are
+ * given by the Point object (p.X and p.Y), and the width and the height
+ * are given by Dimension object (d.width and d.height).
+ *
+ * @param p the Point specifies the upper left corner coordinates of
+ * the rectangle.
+ * @param d the Dimention specifies the width and the height of the rectangle.
+ */
+ public Rectangle(Point p, Dimension d) {
+ setBounds(p.x, p.y, d.width, d.height);
+ }
+
+ /**
+ * Instantiates a new rectangle determined by the upper left corner
+ * coordinates (x, y), width and height.
+ *
+ * @param x the X upper left corner coordinate of the rectangle.
+ * @param y the Y upper left corner coordinate of the rectangle.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ */
+ public Rectangle(int x, int y, int width, int height) {
+ setBounds(x, y, width, height);
+ }
+
+ /**
+ * Instantiates a new rectangle with [0, 0] as its upper left
+ * corner coordinates and the specified width and height.
+ *
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ */
+ public Rectangle(int width, int height) {
+ setBounds(0, 0, width, height);
+ }
+
+ /**
+ * Instantiates a new rectangle with the same coordinates
+ * as the given source rectangle.
+ *
+ * @param r the Rectangle object which parameters will be used for
+ * instantiating a new Rectangle.
+ */
+ public Rectangle(Rectangle r) {
+ setBounds(r.x, r.y, r.width, r.height);
+ }
+/*
+ public Rectangle(Dimension d) {
+ setBounds(0, 0, d.width, d.height);
+ }
+*/
+ /**
+ * Gets the X coordinate of bound as a double.
+ *
+ * @return the X coordinate of bound as a double.
+ *
+ * @see java.awt.geom.RectangularShape#getX()
+ */
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ /**
+ * Gets the Y coordinate of bound as a double.
+ *
+ * @return the Y coordinate of bound as a double.
+ *
+ * @see java.awt.geom.RectangularShape#getY()
+ */
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ /**
+ * Gets the height of the rectangle as a double.
+ *
+ * @return the height of the rectangle as a double.
+ *
+ * @see java.awt.geom.RectangularShape#getHeight()
+ */
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the width of the rectangle as a double.
+ *
+ * @return the width of the rectangle as a double.
+ *
+ * @see java.awt.geom.RectangularShape#getWidth()
+ */
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ /**
+ * Determines whether or not the rectangle is empty. The rectangle is empty if
+ * its width or height is negative or zero.
+ *
+ * @return true, if the rectangle is empty, otherwise false.
+ *
+ * @see java.awt.geom.RectangularShape#isEmpty()
+ */
+ @Override
+ public boolean isEmpty() {
+ return width <= 0 || height <= 0;
+ }
+
+ /**
+ * Gets the size of a Rectangle as Dimention object.
+ *
+ * @return a Dimention object which represents size of the rectangle.
+ */
+ public Dimension getSize() {
+ return new Dimension(width, height);
+ }
+
+ /**
+ * Sets the size of the Rectangle.
+ *
+ * @param width the new width of the rectangle.
+ * @param height the new height of the rectangle.
+ */
+ public void setSize(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Sets the size of a Rectangle specified as Dimension object.
+ *
+ * @param d a Dimension object which represents new size of a rectangle.
+ */
+ public void setSize(Dimension d) {
+ setSize(d.width, d.height);
+ }
+
+ /**
+ * Gets the location of a rectangle's upper left corner as a Point object.
+ *
+ * @return the Point object with coordinates equal to the upper left corner
+ * of the rectangle.
+ */
+ public Point getLocation() {
+ return new Point(x, y);
+ }
+
+ /**
+ * Sets the location of the rectangle in terms of its upper left
+ * corner coordinates X and Y.
+ *
+ * @param x the X coordinate of the rectangle's upper left corner.
+ * @param y the Y coordinate of the rectangle's upper left corner.
+ */
+ public void setLocation(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Sets the location of a rectangle using a Point object to give the
+ * coordinates of the upper left corner.
+ *
+ * @param p the Point object which represents the new upper left corner
+ * coordinates of rectangle.
+ */
+ public void setLocation(Point p) {
+ setLocation(p.x, p.y);
+ }
+
+ /**
+ * Moves a rectangle to the new location by moving its upper left corner
+ * to the point with coordinates X and Y.
+ *
+ * @param x the new X coordinate of the rectangle's upper left corner.
+ * @param y the new Y coordinate of the rectangle's upper left corner.
+ *
+ * @deprecated Use setLocation(int, int) method.
+ */
+ @Deprecated
+ public void move(int x, int y) {
+ setLocation(x, y);
+ }
+
+ /**
+ * Sets the rectangle to be the nearest rectangle with integer coordinates
+ * bounding the rectangle defined by the double-valued parameters.
+ *
+ * @param x the X coordinate of the upper left corner of the double-valued
+ * rectangle to be bounded.
+ * @param y the Y coordinate of the upper left corner of the double-valued
+ * rectangle to be bounded.
+ * @param width the width of the rectangle to be bounded.
+ * @param height the height of the rectangle to be bounded.
+ *
+ * @see java.awt.geom.Rectangle2D#setRect(double, double, double, double)
+ */
+ @Override
+ public void setRect(double x, double y, double width, double height) {
+ int x1 = (int)Math.floor(x);
+ int y1 = (int)Math.floor(y);
+ int x2 = (int)Math.ceil(x + width);
+ int y2 = (int)Math.ceil(y + height);
+ setBounds(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Sets a new size for the rectangle.
+ *
+ * @param width the rectangle's new width.
+ * @param height the rectangle's new height.
+ *
+ * @deprecated use the setSize(int, int) method.
+ */
+ @Deprecated
+ public void resize(int width, int height) {
+ setBounds(x, y, width, height);
+ }
+
+ /**
+ * Resets the bounds of a rectangle to the specified x, y, width and height
+ * parameters.
+ *
+ * @param x the new X coordinate of the upper left corner.
+ * @param y the new Y coordinate of the upper left corner.
+ * @param width the new width of rectangle.
+ * @param height the new height of rectangle.
+ *
+ * @deprecated use setBounds(int, int, int, int) method
+ */
+ @Deprecated
+ public void reshape(int x, int y, int width, int height) {
+ setBounds(x, y, width, height);
+ }
+
+ /**
+ * Gets bounds of the rectangle as a new Rectangle object.
+ *
+ * @return the Rectangle object with the same bounds as
+ * the original rectangle.
+ *
+ * @see java.awt.geom.RectangularShape#getBounds()
+ */
+ @Override
+ public Rectangle getBounds() {
+ return new Rectangle(x, y, width, height);
+ }
+
+ /**
+ * Gets the bounds of the original rectangle as a Rectangle2D object.
+ *
+ * @return the Rectangle2D object which represents the bounds of
+ * the original rectangle.
+ *
+ * @see java.awt.geom.Rectangle2D#getBounds2D()
+ */
+ @Override
+ public Rectangle2D getBounds2D() {
+ return getBounds();
+ }
+
+ /**
+ * Sets the bounds of a rectangle to the specified x, y, width, and height
+ * parameters.
+ *
+ * @param x the X coordinate of the upper left corner.
+ * @param y the Y coordinate of the upper left corner.
+ * @param width the width of rectangle.
+ * @param height the height of rectangle.
+ */
+ public void setBounds(int x, int y, int width, int height) {
+ this.x = x;
+ this.y = y;
+ this.height = height;
+ this.width = width;
+ }
+
+ /**
+ * Sets the bounds of the rectangle to match the bounds of the
+ * Rectangle object sent as a parameter.
+ *
+ * @param r the Rectangle object which specifies the new bounds.
+ */
+ public void setBounds(Rectangle r) {
+ setBounds(r.x, r.y, r.width, r.height);
+ }
+
+ /**
+ * Enlarges the rectangle by moving each corner outward from the
+ * center by a distance of dx horizonally and a distance of dy
+ * vertically. Specifically, changes a rectangle with
+ * [x, y, width, height] parameters to
+ * a rectangle with [x-dx, y-dy, width+2*dx, height+2*dy]
+ * parameters.
+ *
+ * @param dx the horizontal distance to move each corner coordinate.
+ * @param dy the vertical distance to move each corner coordinate.
+ */
+ public void grow(int dx, int dy) {
+ x -= dx;
+ y -= dy;
+ width += dx + dx;
+ height += dy + dy;
+ }
+
+ /**
+ * Moves a rectangle a distance of mx along the x coordinate axis
+ * and a distance of my along y coordinate axis.
+ *
+ * @param mx the horizontal translation increment.
+ * @param my the vertical translation increment.
+ */
+ public void translate(int mx, int my) {
+ x += mx;
+ y += my;
+ }
+
+ /**
+ * Enlarges the rectangle to cover the specified point.
+ *
+ * @param px the X coordinate of the new point to be covered by the rectangle.
+ * @param py the Y coordinate of the new point to be covered by the rectangle.
+ */
+ public void add(int px, int py) {
+ int x1 = Math.min(x, px);
+ int x2 = Math.max(x + width, px);
+ int y1 = Math.min(y, py);
+ int y2 = Math.max(y + height, py);
+ setBounds(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Enlarges the rectangle to cover the specified point with the
+ * new point given as a Point object.
+ *
+ * @param p the Point object that specifies the new point to
+ * be covered by the rectangle.
+ */
+ public void add(Point p) {
+ add(p.x, p.y);
+ }
+
+ /**
+ * Adds a new rectangle to the original rectangle, the result is an union of
+ * the specified specified rectangle and original rectangle.
+ *
+ * @param r the Rectangle which is added to the original rectangle.
+ */
+ public void add(Rectangle r) {
+ int x1 = Math.min(x, r.x);
+ int x2 = Math.max(x + width, r.x + r.width);
+ int y1 = Math.min(y, r.y);
+ int y2 = Math.max(y + height, r.y + r.height);
+ setBounds(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Determines whether or not the point with specified coordinates [px, py]
+ * is within the bounds of the rectangle.
+ *
+ * @param px the X coordinate of point.
+ * @param py the Y coordinate of point.
+ *
+ * @return true, if the point with specified coordinates [px, py] is
+ * within the bounds of the rectangle, otherwise false.
+ */
+ public boolean contains(int px, int py) {
+ if (isEmpty()) {
+ return false;
+ }
+ if (px < x || py < y) {
+ return false;
+ }
+ px -= x;
+ py -= y;
+ return px < width && py < height;
+ }
+
+ /**
+ * Determines whether or not the point given as a Point object
+ * is within the bounds of the rectangle.
+ *
+ * @param p the Point object
+ *
+ * @return true, if the point p is within the bounds of the
+ * rectangle, otherwise false.
+ */
+ public boolean contains(Point p) {
+ return contains(p.x, p.y);
+ }
+
+ /**
+ * Determines whether or not the rectangle specified by [rx, ry, rw, rh]
+ * parameters is located inside the original rectangle.
+ *
+ * @param rx the X coordinate of the rectangle to compare.
+ * @param ry the Y coordinate of the rectangle to compare.
+ * @param rw the width of the rectangle to compare.
+ * @param rh the height of the rectangle to compare.
+ *
+ * @return true, if a rectangle with [rx, ry, rw, rh] parameters is entirely
+ * contained in the original rectangle, otherwise false.
+ */
+ public boolean contains(int rx, int ry, int rw, int rh) {
+ return contains(rx, ry) && contains(rx + rw - 1, ry + rh - 1);
+ }
+
+ /**
+ * Compares whether or not the rectangle specified by the Rectangle object
+ * is located inside the original rectangle.
+ *
+ * @param r the Rectangle object.
+ *
+ * @return true, if the rectangle specified by Rectangle object is entirely
+ * contained in the original rectangle, otherwise false.
+ */
+ public boolean contains(Rectangle r) {
+ return contains(r.x, r.y, r.width, r.height);
+ }
+
+ /**
+ * Compares whether or not a point with specified coordinates [px, py] belongs
+ * to a rectangle.
+ *
+ * @param px the X coordinate of a point.
+ * @param py the Y coordinate of a point.
+ *
+ * @return true, if a point with specified coordinates [px, py] belongs
+ * to a rectangle, otherwise false.
+ *
+ * @deprecated use contains(int, int) method.
+ */
+ @Deprecated
+ public boolean inside(int px, int py) {
+ return contains(px, py);
+ }
+
+ /**
+ * Returns the intersection of the original rectangle with the
+ * specified Rectangle2D.
+ *
+ * @param r the Rectangle2D object.
+ *
+ * @return the Rectangle2D object that is the result of intersecting
+ * the original rectangle with the specified Rectangle2D.
+ *
+ * @see java.awt.geom.Rectangle2D#createIntersection(java.awt.geom.Rectangle2D)
+ */
+ @Override
+ public Rectangle2D createIntersection(Rectangle2D r) {
+ if (r instanceof Rectangle) {
+ return intersection((Rectangle) r);
+ }
+ Rectangle2D dst = new Rectangle2D.Double();
+ Rectangle2D.intersect(this, r, dst);
+ return dst;
+ }
+
+ /**
+ * Returns the intersection of the original rectangle with the
+ * specified rectangle. An empty rectangle is returned if there is no
+ * intersection.
+ *
+ * @param r the Rectangle object.
+ *
+ * @return the Rectangle object is result of the original rectangle with the
+ * specified rectangle.
+ */
+ public Rectangle intersection(Rectangle r) {
+ int x1 = Math.max(x, r.x);
+ int y1 = Math.max(y, r.y);
+ int x2 = Math.min(x + width, r.x + r.width);
+ int y2 = Math.min(y + height, r.y + r.height);
+ return new Rectangle(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Determines whether or not the original rectangle intersects
+ * the specified rectangle.
+ *
+ * @param r the Rectangle object.
+ *
+ * @return true, if the two rectangles overlap; otherwise false.
+ */
+ public boolean intersects(Rectangle r) {
+ return !intersection(r).isEmpty();
+ }
+
+ /**
+ * Determines where the specified Point is located with respect to
+ * the rectangle. This method computes whether the point is to the
+ * right or to the left of the rectangle and whether it is above
+ * or below the rectangle, and packs the result into an int by
+ * using a binary OR operation with the following masks:
+ * <ul>
+ *<li>Rectangle2D.OUT_LEFT</li>
+ *<li>Rectangle2D.OUT_TOP</li>
+ *<li>Rectangle2D.OUT_RIGHT</li>
+ *<li>Rectangle2D.OUT_BOTTOM</li>
+ *</ul>
+ *
+ * If the rectangle is empty, all masks are set, and if the
+ * point is inside the rectangle, none are set.
+ *
+ * @param px the X coordinate of the specified point.
+ * @param py the Y coordinate of the specified point.
+ *
+ * @return the location of the Point relative to the rectangle
+ * as the result of logical OR operation with all out masks.
+ *
+ * @see java.awt.geom.Rectangle2D#outcode(double, double)
+ */
+ @Override
+ public int outcode(double px, double py) {
+ int code = 0;
+
+ if (width <= 0) {
+ code |= OUT_LEFT | OUT_RIGHT;
+ } else
+ if (px < x) {
+ code |= OUT_LEFT;
+ } else
+ if (px > x + width) {
+ code |= OUT_RIGHT;
+ }
+
+ if (height <= 0) {
+ code |= OUT_TOP | OUT_BOTTOM;
+ } else
+ if (py < y) {
+ code |= OUT_TOP;
+ } else
+ if (py > y + height) {
+ code |= OUT_BOTTOM;
+ }
+
+ return code;
+ }
+
+ /**
+ * Enlarges the rectangle to cover the specified Rectangle2D.
+ *
+ * @param r the Rectangle2D object.
+ *
+ * @return the union of the original and the specified Rectangle2D.
+ *
+ * @see java.awt.geom.Rectangle2D#createUnion(java.awt.geom.Rectangle2D)
+ */
+ @Override
+ public Rectangle2D createUnion(Rectangle2D r) {
+ if (r instanceof Rectangle) {
+ return union((Rectangle)r);
+ }
+ Rectangle2D dst = new Rectangle2D.Double();
+ Rectangle2D.union(this, r, dst);
+ return dst;
+ }
+
+ /**
+ * Enlarges the rectangle to cover the specified rectangle.
+ *
+ * @param r the Rectangle.
+ *
+ * @return the union of the original and the specified rectangle.
+ */
+ public Rectangle union(Rectangle r) {
+ Rectangle dst = new Rectangle(this);
+ dst.add(r);
+ return dst;
+ }
+
+ /**
+ * Compares the original Rectangle with the specified object.
+ *
+ * @param obj the specified Object for comparison.
+ *
+ * @return true, if the specified Object is a rectangle with the
+ * same dimensions as the original rectangle, otherwise false.
+ *
+ * @see java.awt.geom.Rectangle2D#equals(Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Rectangle) {
+ Rectangle r = (Rectangle)obj;
+ return r.x == x && r.y == y && r.width == width && r.height == height;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a string representation of the rectangle; the string contains
+ * [x, y, width, height] parameters of the rectangle.
+ *
+ * @return the string representation of the rectangle.
+ */
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour. It could be obtained in the following way
+ // System.out.println(new Rectangle().toString())
+ return getClass().getName() + "[x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$
+ ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+}
+
diff --git a/awt/java/awt/RenderingHints.java b/awt/java/awt/RenderingHints.java
new file mode 100644
index 0000000..4957884
--- /dev/null
+++ b/awt/java/awt/RenderingHints.java
@@ -0,0 +1,601 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The RenderingHints class represents preferences for the rendering algorithms.
+ * The preferences are arbitrary and can be specified by Map objects or by
+ * key-value pairs.
+ */
+public class RenderingHints implements Map<Object, Object>, Cloneable {
+
+ /**
+ * The Constant KEY_ALPHA_INTERPOLATION - alpha interpolation rendering
+ * hint key.
+ */
+ public static final Key KEY_ALPHA_INTERPOLATION = new KeyImpl(1);
+
+ /**
+ * The Constant VALUE_ALPHA_INTERPOLATION_DEFAULT - alpha interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_ALPHA_INTERPOLATION_DEFAULT = new KeyValue(KEY_ALPHA_INTERPOLATION);
+
+ /**
+ * The Constant VALUE_ALPHA_INTERPOLATION_SPEED - alpha interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_ALPHA_INTERPOLATION_SPEED = new KeyValue(KEY_ALPHA_INTERPOLATION);
+
+ /**
+ * The Constant VALUE_ALPHA_INTERPOLATION_QUALITY - alpha interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_ALPHA_INTERPOLATION_QUALITY = new KeyValue(KEY_ALPHA_INTERPOLATION);
+
+ /**
+ * The Constant KEY_ANTIALIASING - antialiasing rendering
+ * hint key.
+ */
+ public static final Key KEY_ANTIALIASING = new KeyImpl(2);
+
+ /**
+ * The Constant VALUE_ANTIALIAS_DEFAULT - antialiasing
+ * rendering hint value.
+ */
+ public static final Object VALUE_ANTIALIAS_DEFAULT = new KeyValue(KEY_ANTIALIASING);
+
+ /**
+ * The Constant VALUE_ANTIALIAS_ON - antialiasing
+ * rendering hint value.
+ */
+ public static final Object VALUE_ANTIALIAS_ON = new KeyValue(KEY_ANTIALIASING);
+
+ /**
+ * The Constant VALUE_ANTIALIAS_OFF - antialiasing
+ * rendering hint value.
+ */
+ public static final Object VALUE_ANTIALIAS_OFF = new KeyValue(KEY_ANTIALIASING);
+
+ /**
+ * The Constant KEY_COLOR_RENDERING - color rendering
+ * hint key.
+ */
+ public static final Key KEY_COLOR_RENDERING = new KeyImpl(3);
+
+ /**
+ * The Constant VALUE_COLOR_RENDER_DEFAULT - color
+ * rendering hint value.
+ */
+ public static final Object VALUE_COLOR_RENDER_DEFAULT = new KeyValue(KEY_COLOR_RENDERING);
+
+ /**
+ * The Constant VALUE_COLOR_RENDER_SPEED - color
+ * rendering hint value.
+ */
+ public static final Object VALUE_COLOR_RENDER_SPEED = new KeyValue(KEY_COLOR_RENDERING);
+
+ /**
+ * The Constant VALUE_COLOR_RENDER_QUALITY - color
+ * rendering hint value.
+ */
+ public static final Object VALUE_COLOR_RENDER_QUALITY = new KeyValue(KEY_COLOR_RENDERING);
+
+ /**
+ * The Constant KEY_DITHERING - dithering
+ * rendering hint key.
+ */
+ public static final Key KEY_DITHERING = new KeyImpl(4);
+
+ /**
+ * The Constant VALUE_DITHER_DEFAULT - dithering
+ * rendering hint value.
+ */
+ public static final Object VALUE_DITHER_DEFAULT = new KeyValue(KEY_DITHERING);
+
+ /**
+ * The Constant VALUE_DITHER_DISABLE - dithering
+ * rendering hint value.
+ */
+ public static final Object VALUE_DITHER_DISABLE = new KeyValue(KEY_DITHERING);
+
+ /**
+ * The Constant VALUE_DITHER_DISABLE - dithering
+ * rendering hint value.
+ */
+ public static final Object VALUE_DITHER_ENABLE = new KeyValue(KEY_DITHERING);
+
+ /**
+ * The Constant KEY_FRACTIONALMETRICS - fractional metrics
+ * rendering hint key.
+ */
+ public static final Key KEY_FRACTIONALMETRICS = new KeyImpl(5);
+
+ /**
+ * The Constant VALUE_FRACTIONALMETRICS_DEFAULT - fractional metrics
+ * rendering hint value.
+ */
+ public static final Object VALUE_FRACTIONALMETRICS_DEFAULT = new KeyValue(KEY_FRACTIONALMETRICS);
+
+ /**
+ * The Constant VALUE_FRACTIONALMETRICS_ON - fractional metrics
+ * rendering hint value.
+ */
+ public static final Object VALUE_FRACTIONALMETRICS_ON = new KeyValue(KEY_FRACTIONALMETRICS);
+
+ /**
+ * The Constant VALUE_FRACTIONALMETRICS_OFF - fractional metrics
+ * rendering hint value.
+ */
+ public static final Object VALUE_FRACTIONALMETRICS_OFF = new KeyValue(KEY_FRACTIONALMETRICS);
+
+ /**
+ * The Constant KEY_INTERPOLATION - interpolation
+ * rendering hint key.
+ */
+ public static final Key KEY_INTERPOLATION = new KeyImpl(6);
+
+ /**
+ * The Constant VALUE_INTERPOLATION_BICUBIC - interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_INTERPOLATION_BICUBIC = new KeyValue(KEY_INTERPOLATION);
+
+ /**
+ * The Constant VALUE_INTERPOLATION_BILINEAR - interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_INTERPOLATION_BILINEAR = new KeyValue(KEY_INTERPOLATION);
+
+ /** The Constant VALUE_INTERPOLATION_NEAREST_NEIGHBOR - interpolation
+ * rendering hint value.
+ */
+ public static final Object VALUE_INTERPOLATION_NEAREST_NEIGHBOR = new KeyValue(KEY_INTERPOLATION);
+
+ /**
+ * The Constant KEY_RENDERING - rendering hint key.
+ */
+ public static final Key KEY_RENDERING = new KeyImpl(7);
+
+ /**
+ * The Constant VALUE_RENDER_DEFAULT - rendering hint value.
+ */
+ public static final Object VALUE_RENDER_DEFAULT = new KeyValue(KEY_RENDERING);
+
+ /**
+ * The Constant VALUE_RENDER_SPEED - rendering hint value.
+ */
+ public static final Object VALUE_RENDER_SPEED = new KeyValue(KEY_RENDERING);
+
+ /**
+ * The Constant VALUE_RENDER_QUALITY - rendering hint value.
+ */
+ public static final Object VALUE_RENDER_QUALITY = new KeyValue(KEY_RENDERING);
+
+ /**
+ * The Constant KEY_STROKE_CONTROL - stroke control hint key.
+ */
+ public static final Key KEY_STROKE_CONTROL = new KeyImpl(8);
+
+ /**
+ * The Constant VALUE_STROKE_DEFAULT - stroke hint value.
+ */
+ public static final Object VALUE_STROKE_DEFAULT = new KeyValue(KEY_STROKE_CONTROL);
+
+ /**
+ * The Constant VALUE_STROKE_NORMALIZE - stroke hint value.
+ */
+ public static final Object VALUE_STROKE_NORMALIZE = new KeyValue(KEY_STROKE_CONTROL);
+
+ /**
+ * The Constant VALUE_STROKE_PURE - stroke hint value.
+ */
+ public static final Object VALUE_STROKE_PURE = new KeyValue(KEY_STROKE_CONTROL);
+
+ /**
+ * The Constant KEY_TEXT_ANTIALIASING - text antialiasing hint key.
+ */
+ public static final Key KEY_TEXT_ANTIALIASING = new KeyImpl(9);
+
+ /**
+ * The Constant VALUE_TEXT_ANTIALIAS_DEFAULT - text antialiasing hint key.
+ */
+ public static final Object VALUE_TEXT_ANTIALIAS_DEFAULT = new KeyValue(KEY_TEXT_ANTIALIASING);
+
+ /**
+ * The Constant VALUE_TEXT_ANTIALIAS_ON - text antialiasing hint key.
+ */
+ public static final Object VALUE_TEXT_ANTIALIAS_ON = new KeyValue(KEY_TEXT_ANTIALIASING);
+
+ /**
+ * The Constant VALUE_TEXT_ANTIALIAS_OFF - text antialiasing hint key.
+ */
+ public static final Object VALUE_TEXT_ANTIALIAS_OFF = new KeyValue(KEY_TEXT_ANTIALIASING);
+
+ /** The map. */
+ private HashMap<Object, Object> map = new HashMap<Object, Object>();
+
+ /**
+ * Instantiates a new rendering hints object from specified Map object with defined
+ * key/value pairs or null for empty RenderingHints.
+ *
+ * @param map the Map object with defined key/value pairs or null for
+ * empty RenderingHints.
+ */
+ public RenderingHints(Map<Key, ?> map) {
+ super();
+ if (map != null) {
+ putAll(map);
+ }
+ }
+
+ /**
+ * Instantiates a new rendering hints object with the specified key/value pair.
+ *
+ * @param key the key of hint property.
+ * @param value the value of hint property.
+ */
+ public RenderingHints(Key key, Object value) {
+ super();
+ put(key, value);
+ }
+
+ /**
+ * Adds the properties represented by key/value pairs from the specified
+ * RenderingHints object to current object.
+ *
+ * @param hints the RenderingHints to be added.
+ */
+ public void add(RenderingHints hints) {
+ map.putAll(hints.map);
+ }
+
+ /**
+ * Puts the specified value to the specified key. Neither the key nor
+ * the value can be null.
+ *
+ * @param key the rendering hint key.
+ * @param value the rendering hint value.
+ *
+ * @return the previous rendering hint value assigned to the key or null.
+ *
+ */
+ public Object put(Object key, Object value) {
+ if (!((Key)key).isCompatibleValue(value)) {
+ throw new IllegalArgumentException();
+ }
+
+ return map.put(key, value);
+ }
+
+ /**
+ * Removes the specified key and corresponding value from
+ * the RenderingHints object.
+ *
+ * @param key the specified hint key to be removed.
+ *
+ * @return the object of previous rendering hint value which is
+ * assigned to the specified key, or null.
+ */
+ public Object remove(Object key) {
+ return map.remove(key);
+ }
+
+ /**
+ * Gets the value assigned to the specified key.
+ *
+ * @param key the rendering hint key.
+ *
+ * @return the object assigned to the specified key.
+ */
+ public Object get(Object key) {
+ return map.get(key);
+ }
+
+ /**
+ * Returns a set of rendering hints keys for current RenderingHints object.
+ *
+ * @return the set of rendering hints keys.
+ */
+ public Set<Object> keySet() {
+ return map.keySet();
+ }
+
+ /**
+ * Returns a set of Map.Entry objects which contain current RenderingHint
+ * key/value pairs.
+ *
+ * @return the a set of mapped RenderingHint key/value pairs.
+ */
+ public Set<Map.Entry<Object, Object>> entrySet() {
+ return map.entrySet();
+ }
+
+ /**
+ * Puts all of the preferences from the specified Map into
+ * the current RenderingHints object. These mappings replace
+ * all existing preferences.
+ *
+ * @param m the specified Map of preferences.
+ */
+ public void putAll(Map<?, ?> m) {
+ if (m instanceof RenderingHints) {
+ map.putAll(((RenderingHints) m).map);
+ } else {
+ Set<?> entries = m.entrySet();
+
+ if (entries != null){
+ Iterator<?> it = entries.iterator();
+ while (it.hasNext()) {
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
+ Key key = (Key) entry.getKey();
+ Object val = entry.getValue();
+ put(key, val);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a Collection of values contained in current RenderingHints object.
+ *
+ * @return the Collection of RenderingHints's values.
+ */
+ public Collection<Object> values() {
+ return map.values();
+ }
+
+ /**
+ * Checks whether or not current RenderingHints object contains at least one
+ * the value which is equal to the specified Object.
+ *
+ * @param value the specified Object.
+ *
+ * @return true, if the specified object is assigned to at least one
+ * RenderingHint's key, false otherwise.
+ */
+ public boolean containsValue(Object value) {
+ return map.containsValue(value);
+ }
+
+ /**
+ * Checks whether or not current RenderingHints object contains the key
+ * which is equal to the specified Object.
+ *
+ * @param key the specified Object.
+ *
+ * @return true, if the RenderingHints object contains the specified Object
+ * as a key, false otherwise.
+ *
+ */
+ public boolean containsKey(Object key) {
+ if (key == null) {
+ throw new NullPointerException();
+ }
+
+ return map.containsKey(key);
+ }
+
+ /**
+ * Checks whether or not the RenderingHints object contains any
+ * key/value pairs.
+ *
+ * @return true, if the RenderingHints object is empty, false otherwise.
+ */
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /**
+ * Clears the RenderingHints of all key/value pairs.
+ */
+ public void clear() {
+ map.clear();
+ }
+
+ /**
+ * Returns the number of key/value pairs in the RenderingHints.
+ *
+ * @return the number of key/value pairs.
+ */
+ public int size() {
+ return map.size();
+ }
+
+ /**
+ * Compares the RenderingHints object with the specified object.
+ *
+ * @param o the specified Object to be compaired.
+ *
+ * @return true, if the Object is a Map whose key/value pairs
+ * match this RenderingHints' key/value pairs,
+ * false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Map)) {
+ return false;
+ }
+
+ Map<?, ?> m = (Map<?, ?>)o;
+ Set<?> keys = keySet();
+ if (!keys.equals(m.keySet())) {
+ return false;
+ }
+
+ Iterator<?> it = keys.iterator();
+ while (it.hasNext()) {
+ Key key = (Key)it.next();
+ Object v1 = get(key);
+ Object v2 = m.get(key);
+ if (!(v1==null?v2==null:v1.equals(v2))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the hash code for this RenderingHints object.
+ *
+ * @return the hash code for this RenderingHints object.
+ */
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+
+ /**
+ * Returns the clone of the RenderingHints object with the same contents.
+ *
+ * @return the clone of the RenderingHints instance.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object clone() {
+ RenderingHints clone = new RenderingHints(null);
+ clone.map = (HashMap<Object, Object>)this.map.clone();
+ return clone;
+ }
+
+ /**
+ * Returns the string representation of the RenderingHints object.
+ *
+ * @return the String object which represents RenderingHints object.
+ */
+ @Override
+ public String toString() {
+ return "RenderingHints["+map.toString()+"]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * The RenderingHints.Key class is abstract and defines a base type for
+ * all RenderingHints keys.
+ */
+ public abstract static class Key {
+
+ /** The key. */
+ private final int key;
+
+ /**
+ * Instantiates a new key with unique int identifier.
+ * No two objects of the same subclass with the same integer key
+ * can be instantiated.
+ *
+ * @param key the unique key.
+ */
+ protected Key(int key) {
+ this.key = key;
+ }
+
+ /**
+ * Compares the Key object with the specified object.
+ *
+ * @param o the specified Object to be compaired.
+ *
+ * @return true, if the Key is equal to the specified object,
+ * false otherwise.
+ */
+ @Override
+ public final boolean equals(Object o) {
+ return this == o;
+ }
+
+ /**
+ * Returns the hash code for this Key object.
+ *
+ * @return the hash code for this Key object.
+ */
+ @Override
+ public final int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ /**
+ * Returns int unique key with which this Key object has been
+ * instantiated.
+ *
+ * @return the int unique key with which this Key object has been
+ * instantiated.
+ */
+ protected final int intKey() {
+ return key;
+ }
+
+ /**
+ * Checks whether or not specified value is compatible with the Key.
+ *
+ * @param val the Object.
+ *
+ * @return true, if the specified value is compatible with the Key,
+ * false otherwise.
+ */
+ public abstract boolean isCompatibleValue(Object val);
+ }
+
+ /**
+ * Private implementation of Key class.
+ */
+ private static class KeyImpl extends Key {
+
+ /**
+ * Instantiates a new key impl.
+ *
+ * @param key the key
+ */
+ protected KeyImpl(int key) {
+ super(key);
+ }
+
+ @Override
+ public boolean isCompatibleValue(Object val) {
+ if (!(val instanceof KeyValue)) {
+ return false;
+ }
+
+ return ((KeyValue)val).key == this;
+ }
+ }
+
+ /**
+ * Private class KeyValue is used as value for Key class instance.
+ */
+ private static class KeyValue {
+
+ /** The key. */
+ private final Key key;
+
+ /**
+ * Instantiates a new key value.
+ *
+ * @param key the key
+ */
+ protected KeyValue(Key key) {
+ this.key = key;
+ }
+ }
+}
diff --git a/awt/java/awt/Shape.java b/awt/java/awt/Shape.java
new file mode 100644
index 0000000..3dbad25
--- /dev/null
+++ b/awt/java/awt/Shape.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The Shape interface defines a geometric shape defined by a boundary
+ * (outline) path. The path outline can be accessed through a
+ * PathIterator object. The Shape
+ * interface provides methods for obtaining the bounding box (which is
+ * the smallest rectangle containing the shape and for obtaining a PathIterator
+ * object for current Shape, as well as utility methods which
+ * determine if the Shape contains or intersects a Rectangle or contains a Point.
+ */
+public interface Shape {
+
+ /**
+ * Checks whether or not the point with specified coordinates lies inside
+ * the Shape.
+ *
+ * @param x the X coordinate.
+ * @param y the Y coordinate.
+ *
+ * @return true, if the specified coordinates lie inside the Shape,
+ * otherwise false.
+ */
+ public boolean contains(double x, double y);
+
+ /**
+ * Checks whether or not the rectangle with specified
+ * [x, y, width, height] parameters lies inside the Shape.
+ *
+ * @param x the X double coordinate of the rectangle's upper left
+ * corner.
+ * @param y the Y double coordinate of the rectangle's upper left
+ * corner.
+ * @param w the width of rectangle.
+ * @param h the height of rectangle.
+ *
+ * @return true, if the specified rectangle lies inside the Shape,
+ * otherwise false.
+ */
+ public boolean contains(double x, double y, double w, double h);
+
+ /**
+ * Checks whether or not the specified Point2D lies inside the Shape.
+ *
+ * @param point the Point2D object.
+ *
+ * @return true, if the specified Point2D lies inside the Shape,
+ * otherwise false.
+ */
+ public boolean contains(Point2D point);
+
+ /**
+ * Checks whether or not the specified rectangle lies inside the Shape.
+ *
+ * @param r the Rectangle2D object.
+ *
+ * @return true, if the specified rectangle lies inside the Shape,
+ * otherwise false.
+ */
+ public boolean contains(Rectangle2D r);
+
+ /**
+ * Gets the bounding rectangle of the Shape. The bounding rectangle
+ * is the smallest rectangle which contains the Shape.
+ *
+ * @return the bounding rectangle of the Shape.
+ */
+ public Rectangle getBounds();
+
+ /**
+ * Gets the Rectangle2D which represents Shape bounds.
+ * The bounding rectangle is the smallest rectangle which contains
+ * the Shape.
+ *
+ * @return the bounding rectangle of the Shape.
+ */
+ public Rectangle2D getBounds2D();
+
+ /**
+ * Gets the PathIterator object of the Shape which provides
+ * access to the shape's boundary modified
+ * by the specified AffineTransform.
+ *
+ * @param at the specified AffineTransform object, or null.
+ *
+ * @return PathIterator object for the Shape.
+ */
+ public PathIterator getPathIterator(AffineTransform at);
+
+ /**
+ * Gets the PathIterator object of the Shape which provides
+ * access to the coordinates of the shapes boundary modified
+ * by the specified AffineTransform. The flatness parameter
+ * defines the amount of subdivision of the curved segments and
+ * specifies the maximum distance which every point on the
+ * unflattened transformed curve can deviate from the returned
+ * flattened path segments.
+ *
+ * @param at the specified AffineTransform object, or null.
+ * @param flatness the maximum number of the control points for
+ * a given curve which varies from colinear before a subdivided
+ * curve is replaced by a straight line connecting the endpoints.
+ *
+ * @return PathIterator object for the Shape.
+ */
+ public PathIterator getPathIterator(AffineTransform at, double flatness);
+
+ /**
+ * Checks whether or not the interior of rectangular specified by
+ * [x, y, width, height] parameters intersects the interior of
+ * the Shape.
+ *
+ * @param x the X double coordinate of the rectangle's upper left
+ * corner.
+ * @param y the Y double coordinate of the rectangle's upper left
+ * corner.
+ * @param w the width of rectangle.
+ * @param h the height of rectangle.
+ *
+ * @return true, if the rectangle specified by
+ * [x, y, width, height] parameters intersects the interior of
+ * the Shape, otherwise false.
+ *
+ */
+ public boolean intersects(double x, double y, double w, double h);
+
+ /**
+ * Checks whether or not the interior of rectangl specified by
+ * Rectangle2D object intersects the interior of the Shape.
+ *
+ * @param r the Rectangle2D object.
+ *
+ * @return true, if the Rectangle2D intersects the interior of
+ * the Shape, otherwise false.
+ */
+ public boolean intersects(Rectangle2D r);
+}
diff --git a/awt/java/awt/Stroke.java b/awt/java/awt/Stroke.java
new file mode 100644
index 0000000..e6d683d
--- /dev/null
+++ b/awt/java/awt/Stroke.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The Stroke interface gives a pen style to be used by the
+ * Graphics2D interface. It provides a means for getting a stroked version
+ * of a shape, which is the version that is suitable for drawing via
+ * the Graphics2D interface. Stroking a shape gives the shape's outline
+ * a width or drawing style.
+ * <p>
+ * The Draw methods from Graphics2D interface should use the Stroke object for
+ * rendering the shape's outline. The stroke should be set by
+ * setStroke(java.awt.Stroke) method of the Graphics2D interface.
+ * @see java.awt.Graphics2D#setStroke(java.awt.Stroke)
+ */
+public interface Stroke {
+
+ /**
+ * Creates the stroked shape, which is the version that is suitable for drawing via
+ * the Graphics2D interface. Stroking a shape gives the shape's outline
+ * a width or drawing style.
+ *
+ * @param p the original shape.
+ *
+ * @return the stroked shape.
+ */
+ public Shape createStrokedShape(Shape p);
+}
diff --git a/awt/java/awt/Toolkit.java b/awt/java/awt/Toolkit.java
new file mode 100644
index 0000000..0c066b2
--- /dev/null
+++ b/awt/java/awt/Toolkit.java
@@ -0,0 +1,1338 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.awt.event.AWTEventListener;
+import java.awt.event.AWTEventListenerProxy;
+import java.awt.event.InputEvent;
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.peer.FontPeer;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Properties;
+import java.util.ResourceBundle;
+
+import org.apache.harmony.awt.ChoiceStyle;
+import org.apache.harmony.awt.ComponentInternals;
+import org.apache.harmony.awt.ContextStorage;
+import org.apache.harmony.awt.ReadOnlyIterator;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.CreationParams;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+import org.apache.harmony.awt.wtk.NativeCursor;
+
+import org.apache.harmony.awt.wtk.NativeEventQueue;
+import org.apache.harmony.awt.wtk.NativeEventThread;
+import org.apache.harmony.awt.wtk.ShutdownWatchdog;
+import org.apache.harmony.awt.wtk.Synchronizer;
+import org.apache.harmony.awt.wtk.WTK;
+
+/**
+ * The Toolkit class is the representation of the platform-specific
+ * Abstract Window Toolkit implementation. Toolkit's subclasses
+ * are used to bind the various components to particular native
+ * toolkit implementations.
+ */
+public abstract class Toolkit {
+
+ /** The Constant RECOURCE_PATH. */
+ private static final String RECOURCE_PATH = "org.apache.harmony.awt.resources.AWTProperties"; //$NON-NLS-1$
+
+ /** The Constant properties. */
+ private static final ResourceBundle properties = loadResources(RECOURCE_PATH);
+
+ /** The dispatcher. */
+ Dispatcher dispatcher;
+
+ /** The system event queue core. */
+ private EventQueueCore systemEventQueueCore;
+
+ /** The dispatch thread. */
+ EventDispatchThread dispatchThread;
+
+ /** The native thread. */
+ NativeEventThread nativeThread;
+
+ /** The awt events manager. */
+ protected AWTEventsManager awtEventsManager;
+
+ /**
+ * The Class AWTTreeLock.
+ */
+ private class AWTTreeLock {
+ }
+
+ /** The awt tree lock. */
+ final Object awtTreeLock = new AWTTreeLock();
+
+ /** The synchronizer. */
+ private final Synchronizer synchronizer = ContextStorage.getSynchronizer();
+
+ /** The shutdown watchdog. */
+ final ShutdownWatchdog shutdownWatchdog = new ShutdownWatchdog();
+
+ /** The auto number. */
+ final AutoNumber autoNumber = new AutoNumber();
+
+ /** The event type lookup. */
+ final AWTEvent.EventTypeLookup eventTypeLookup = new AWTEvent.EventTypeLookup();
+
+ /** The b dynamic layout set. */
+ private boolean bDynamicLayoutSet = true;
+
+ /** The set of desktop properties that user set directly. */
+ private final HashSet<String> userPropSet = new HashSet<String>();
+
+ /** The desktop properties. */
+ protected Map<String, Object> desktopProperties;
+
+ /** The desktop props support. */
+ protected PropertyChangeSupport desktopPropsSupport;
+
+ /**
+ * For this component the native window is being created
+ * It is used in the callback-driven window creation
+ * (e.g. on Windows in the handler of WM_CREATE event)
+ * to establish the connection between this component
+ * and its native window.
+ */
+ private Object recentNativeWindowComponent;
+
+ /** The wtk. */
+ private WTK wtk;
+
+ /**
+ * The Class ComponentInternalsImpl.
+ */
+ protected final class ComponentInternalsImpl extends ComponentInternals {
+
+ /**
+ * Shutdown.
+ */
+ @Override
+ public void shutdown() {
+ dispatchThread.shutdown();
+ }
+
+ /**
+ * Sets the desktop property to the specified value and fires a property
+ * change event.
+ *
+ * @param name the name of property.
+ * @param value the new value of property.
+ */
+ @Override
+ public void setDesktopProperty(String name, Object value) {
+ Toolkit.this.setDesktopProperty(name, value);
+ }
+ }
+
+
+ /**
+ * A lot of methods must throw HeadlessException
+ * if <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>.
+ *
+ * @throws HeadlessException the headless exception
+ */
+ static void checkHeadless() throws HeadlessException {
+ if (GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance())
+ throw new HeadlessException();
+ }
+
+ /**
+ * Lock awt.
+ */
+ final void lockAWT() {
+ synchronizer.lock();
+ }
+
+ /**
+ * Static lock awt.
+ */
+ static final void staticLockAWT() {
+ ContextStorage.getSynchronizer().lock();
+ }
+
+ /**
+ * Unlock awt.
+ */
+ final void unlockAWT() {
+ synchronizer.unlock();
+ }
+
+ /**
+ * Static unlock awt.
+ */
+ static final void staticUnlockAWT() {
+ ContextStorage.getSynchronizer().unlock();
+ }
+
+ /**
+ * InvokeAndWait under AWT lock. W/o this method system can hang up.
+ * Added to support modality (Dialog.show() & PopupMenu.show()) from
+ * not event dispatch thread. Use in other cases is not recommended.
+ *
+ * Still can be called only for whole API methods that
+ * cannot be called from other classes API methods.
+ * Examples:
+ * show() for modal dialogs - correct, only user can call it,
+ * directly or through setVisible(true)
+ * setBounds() for components - incorrect, setBounds()
+ * can be called from layoutContainer()
+ * for layout managers
+ *
+ * @param runnable the runnable
+ *
+ * @throws InterruptedException the interrupted exception
+ * @throws InvocationTargetException the invocation target exception
+ */
+ final void unsafeInvokeAndWait(Runnable runnable) throws InterruptedException,
+ InvocationTargetException {
+ synchronizer.storeStateAndFree();
+ try {
+ EventQueue.invokeAndWait(runnable);
+ } finally {
+ synchronizer.lockAndRestoreState();
+ }
+ }
+
+ /**
+ * Gets the synchronizer.
+ *
+ * @return the synchronizer
+ */
+ final Synchronizer getSynchronizer() {
+ return synchronizer;
+ }
+
+ /**
+ * Gets the wTK.
+ *
+ * @return the wTK
+ */
+ final WTK getWTK() {
+ return wtk;
+ }
+
+ /**
+ * Gets the property with the specified key and default value.
+ * This method returns the defValue if the property is not found.
+ *
+ * @param propName the name of property.
+ * @param defVal the default value.
+ *
+ * @return the property value.
+ */
+ public static String getProperty(String propName, String defVal) {
+ if (propName == null) {
+ // awt.7D=Property name is null
+ throw new NullPointerException(Messages.getString("awt.7D")); //$NON-NLS-1$
+ }
+ staticLockAWT();
+ try {
+ String retVal = null;
+ if (properties != null) {
+ try {
+ retVal = properties.getString(propName);
+ } catch (MissingResourceException e) {
+ } catch (ClassCastException e) {
+ }
+ }
+ return (retVal == null) ? defVal : retVal;
+ } finally {
+ staticUnlockAWT();
+ }
+ }
+
+ /**
+ * Gets the default Toolkit.
+ *
+ * @return the default Toolkit
+ */
+ public static Toolkit getDefaultToolkit() {
+ synchronized (ContextStorage.getContextLock()) {
+ if (ContextStorage.shutdownPending()) {
+ return null;
+ }
+ Toolkit defToolkit = ContextStorage.getDefaultToolkit();
+ if (defToolkit != null) {
+ return defToolkit;
+ }
+ staticLockAWT();
+ try {
+ defToolkit = GraphicsEnvironment.isHeadless() ?
+ new HeadlessToolkit() : new ToolkitImpl();
+ ContextStorage.setDefaultToolkit(defToolkit);
+ return defToolkit;
+ } finally {
+ staticUnlockAWT();
+ }
+ //TODO: read system property named awt.toolkit
+ //and create an instance of the specified class,
+ //by default use ToolkitImpl
+ }
+ }
+
+ /**
+ * Gets the default Font.
+ *
+ * @return the derault Font for Toolkit.
+ */
+ Font getDefaultFont() {
+ return wtk.getSystemProperties().getDefaultFont();
+ }
+
+ /**
+ * Load resources.
+ *
+ * @param path the path
+ *
+ * @return the resource bundle
+ */
+ private static ResourceBundle loadResources(String path) {
+ try {
+ return ResourceBundle.getBundle(path);
+ } catch (MissingResourceException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the wTK class name.
+ *
+ * @return the wTK class name
+ */
+ private static String getWTKClassName() {
+ return "com.android.internal.awt.AndroidWTK";
+ }
+
+ /**
+ * Gets the component by id.
+ *
+ * @param id the id
+ *
+ * @return the component by id
+ */
+ Component getComponentById(long id) {
+ if (id == 0) {
+ return null;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the GraphicsFactory.
+ *
+ * @return the GraphicsFactory object.
+ */
+ public GraphicsFactory getGraphicsFactory() {
+ return wtk.getGraphicsFactory();
+ }
+
+ /**
+ * Instantiates a new toolkit.
+ */
+ public Toolkit() {
+ init();
+ }
+
+ /**
+ * Inits AWT.
+ */
+ protected void init() {
+ lockAWT();
+ try {
+ ComponentInternals.setComponentInternals(new ComponentInternalsImpl());
+ new EventQueue(this); // create the system EventQueue
+ dispatcher = new Dispatcher(this);
+ final String className = getWTKClassName();
+ desktopProperties = new HashMap<String, Object>();
+ desktopPropsSupport = new PropertyChangeSupport(this);
+ awtEventsManager = new AWTEventsManager();
+ dispatchThread = new EventDispatchThread(this, dispatcher);
+ nativeThread = new NativeEventThread();
+ NativeEventThread.Init init = new NativeEventThread.Init() {
+ public WTK init() {
+ wtk = createWTK(className);
+ wtk.getNativeEventQueue().setShutdownWatchdog(shutdownWatchdog);
+ synchronizer.setEnvironment(wtk, dispatchThread);
+ ContextStorage.setWTK(wtk);
+ return wtk;
+ }
+ };
+ nativeThread.start(init);
+ dispatchThread.start();
+ wtk.getNativeEventQueue().awake();
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Synchronizes this toolkit's graphics.
+ */
+ public abstract void sync();
+
+ /**
+ * Returns the construction status of a specified image that is being created.
+ *
+ * @param a0 the image to be checked.
+ * @param a1 the width of scaled image for which the status is being checked, or -1.
+ * @param a2 the height of scaled image for which the status is being checked, or -1.
+ * @param a3 the ImageObserver object to be notified while
+ * the image is being prepared.
+ *
+ * @return the ImageObserver flags which give the current state of the image data.
+ */
+ public abstract int checkImage(Image a0, int a1, int a2, ImageObserver a3);
+
+ /**
+ * Creates the image with the specified ImageProducer.
+ *
+ * @param a0 the ImageProducer to be used for image creation.
+ *
+ * @return the image with the specified ImageProducer.
+ */
+ public abstract Image createImage(ImageProducer a0);
+
+ /**
+ * Creates the image from the specified byte array, offset and length.
+ * The byte array should contain data with image format supported by
+ * Toolkit such as JPEG, GIF, or PNG.
+ *
+ * @param a0 the byte array with the image data.
+ * @param a1 the offset of the beggining the image data in the byte array.
+ * @param a2 the length of the image data in the byte array.
+ *
+ * @return the created Image.
+ */
+ public abstract Image createImage(byte[] a0, int a1, int a2);
+
+ /**
+ * Creates the image using image data from the specified URL.
+ *
+ * @param a0 the URL for extracting image data.
+ *
+ * @return the Image.
+ */
+ public abstract Image createImage(URL a0);
+
+ /**
+ * Creates the image using image data from the specified file.
+ *
+ * @param a0 the file name which contains image data of supported format.
+ *
+ * @return the Image.
+ */
+ public abstract Image createImage(String a0);
+
+ /**
+ * Gets the color model.
+ *
+ * @return the ColorModel of Toolkit's screen.
+ *
+ * @throws HeadlessException if the
+ * GraphicsEnvironment.isHeadless() method returns true.
+ */
+ public abstract ColorModel getColorModel() throws HeadlessException;
+
+ /**
+ * Gets the screen device metrics for the specified font.
+ *
+ * @param font the Font.
+ *
+ * @return the FontMetrics for the specified Font.
+ *
+ * @deprecated Use getLineMetrics method from Font class.
+ */
+
+ @Deprecated
+ public abstract FontMetrics getFontMetrics(Font font);
+
+ /**
+ * Prepares the specified image for rendering on the screen with the
+ * specified size.
+ *
+ * @param a0 the Image to be prepared.
+ * @param a1 the width of the screen representation or -1 for the current screen.
+ * @param a2 the height of the screen representation or -1 for the current screen.
+ * @param a3 the ImageObserver object to be notified as soon as
+ * the image is prepared.
+ *
+ * @return true, if image is fully prepared; false otherwise.
+ */
+ public abstract boolean prepareImage(Image a0, int a1, int a2, ImageObserver a3);
+
+ /**
+ * Creates an audio beep.
+ */
+ public abstract void beep();
+
+ /**
+ * Returns the array of font names which are available in this Toolkit.
+ *
+ * @return the array of font names which are available in this Toolkit.
+ *
+ * @deprecated use GraphicsEnvironment.getAvailableFontFamilyNames() method.
+ */
+ @Deprecated
+ public abstract String[] getFontList();
+
+ /**
+ * Gets the the Font implementation using the specified peer
+ * interface.
+ *
+ * @param a0 the Font name to be implemented.
+ * @param a1 the the font style: PLAIN, BOLD, ITALIC.
+ *
+ * @return the FontPeer implementation of the specified Font.
+ *
+ * @deprecated use java.awt.GraphicsEnvironment.getAllFonts method.
+ */
+
+ @Deprecated
+ protected abstract FontPeer getFontPeer(String a0, int a1);
+
+ /**
+ * Gets the image from the specified file which contains image data in
+ * a supported image format (such as JPEG, GIF, or PNG); this method
+ * should return the same Image for multiple calls of this method with
+ * the same image file name.
+ *
+ * @param a0 the file name which contains image data in
+ * a supported image format (such as JPEG, GIF, or PNG).
+ *
+ * @return the Image.
+ */
+ public abstract Image getImage(String a0);
+
+ /**
+ * Gets the image from the specified URL which contains image data in
+ * a supported image format (such as JPEG, GIF, or PNG); this method
+ * should return the same Image for multiple calls of this method with
+ * the same image URL.
+ *
+ * @param a0 the URL which contains image data in
+ * a supported image format (such as JPEG, GIF, or PNG).
+ *
+ * @return the Image.
+ */
+ public abstract Image getImage(URL a0);
+
+ /**
+ * Gets the screen resolution.
+ *
+ * @return the screen resolution.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public abstract int getScreenResolution() throws HeadlessException;
+
+ /**
+ * Gets the screen size.
+ *
+ * @return a Dimension object containing the width and height of
+ * the screen.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public abstract Dimension getScreenSize() throws HeadlessException;
+
+ /**
+ * Gets the EventQueue instance without checking access.
+ *
+ * @return the system EventQueue.
+ */
+ protected abstract EventQueue getSystemEventQueueImpl();
+
+ /**
+ * Returns a map of text attributes for the abstract level description
+ * of the specified input method highlight, or null if no mapping is found.
+ *
+ * @param highlight the InputMethodHighlight.
+ *
+ * @return the Map<java.awt.font. text attribute,?>
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public abstract Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight(
+ InputMethodHighlight highlight) throws HeadlessException;
+
+ /**
+ * Map input method highlight impl.
+ *
+ * @param highlight the highlight
+ *
+ * @return the map<java.awt.font. text attribute,?>
+ *
+ * @throws HeadlessException the headless exception
+ */
+ Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlightImpl(
+ InputMethodHighlight highlight) throws HeadlessException {
+ HashMap<java.awt.font.TextAttribute, ?> map = new HashMap<java.awt.font.TextAttribute, Object>();
+ wtk.getSystemProperties().mapInputMethodHighlight(highlight, map);
+ return Collections.<java.awt.font.TextAttribute, Object> unmodifiableMap(map);
+ }
+
+ /**
+ * Adds the specified PropertyChangeListener listener for the specified
+ * property.
+ *
+ * @param propName the property name for which the specified PropertyChangeListener
+ * will be added.
+ * @param l the PropertyChangeListener object.
+ */
+ public void addPropertyChangeListener(String propName, PropertyChangeListener l) {
+ lockAWT();
+ try {
+ if (desktopProperties.isEmpty()) {
+ initializeDesktopProperties();
+ }
+ } finally {
+ unlockAWT();
+ }
+ if (l != null) { // there is no guarantee that null listener will not be added
+ desktopPropsSupport.addPropertyChangeListener(propName, l);
+ }
+ }
+
+ /**
+ * Returns an array of the property change listeners registered with
+ * this Toolkit.
+ *
+ * @return an array of the property change listeners registered with
+ * this Toolkit.
+ */
+ public PropertyChangeListener[] getPropertyChangeListeners() {
+ return desktopPropsSupport.getPropertyChangeListeners();
+ }
+
+ /**
+ * Returns an array of the property change listeners registered with
+ * this Toolkit for notification regarding the specified property.
+ *
+ * @param propName the property name for which the PropertyChangeListener
+ * was registered.
+ *
+ * @return the array of PropertyChangeListeners registered for the specified
+ * property name.
+ */
+ public PropertyChangeListener[] getPropertyChangeListeners(String propName) {
+ return desktopPropsSupport.getPropertyChangeListeners(propName);
+ }
+
+ /**
+ * Removes the specified property change listener registered for the
+ * specified property name.
+ *
+ * @param propName the property name.
+ * @param l the PropertyChangeListener registered for the specified property name.
+ */
+ public void removePropertyChangeListener(String propName, PropertyChangeListener l) {
+ desktopPropsSupport.removePropertyChangeListener(propName, l);
+ }
+
+ /**
+ * Creates a custom cursor with the specified Image, hot spot, and cursor
+ * description.
+ *
+ * @param img the image of activated cursor.
+ * @param hotSpot the Point giving the coordinates of the cursor's hot spot.
+ * @param name the cursor description.
+ *
+ * @return the cursor with the specified Image, hot spot, and cursor
+ * description.
+ *
+ * @throws IndexOutOfBoundsException if the hot spot values are outside
+ * the bounds of the cursor.
+ * @throws HeadlessException if isHeadless() method of GraphicsEnvironment
+ * class returns true.
+ */
+ public Cursor createCustomCursor(Image img, Point hotSpot, String name)
+ throws IndexOutOfBoundsException, HeadlessException {
+ lockAWT();
+ try {
+ int w = img.getWidth(null), x = hotSpot.x;
+ int h = img.getHeight(null), y = hotSpot.y;
+ if (x < 0 || x >= w || y < 0 || y >= h) {
+ // awt.7E=invalid hotSpot
+ throw new IndexOutOfBoundsException(Messages.getString("awt.7E")); //$NON-NLS-1$
+ }
+ return new Cursor(name, img, hotSpot);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the supported cursor dimension which is closest to the
+ * specified width and height. If the Toolkit only supports a single
+ * cursor size, this method should return the supported cursor size.
+ * If custom cursor is not supported, a dimension of 0, 0 should be
+ * returned.
+ *
+ * @param prefWidth the preffered cursor width.
+ * @param prefHeight the preffered cursor height.
+ *
+ * @return the supported cursor dimension which is closest to the
+ * specified width and height.
+ *
+ * @throws HeadlessException if GraphicsEnvironment.isHeadless()
+ * returns true.
+ */
+ public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException {
+ lockAWT();
+ try {
+ return wtk.getCursorFactory().getBestCursorSize(prefWidth, prefHeight);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the value for the specified desktop property.
+ *
+ * @param propName the property name.
+ *
+ * @return the Object that is the property's value.
+ */
+ public final Object getDesktopProperty(String propName) {
+ lockAWT();
+ try {
+ if (desktopProperties.isEmpty()) {
+ initializeDesktopProperties();
+ }
+ if (propName.equals("awt.dynamicLayoutSupported")) { //$NON-NLS-1$
+ // dynamicLayoutSupported is special case
+ return Boolean.valueOf(isDynamicLayoutActive());
+ }
+ Object val = desktopProperties.get(propName);
+ if (val == null) {
+ // try to lazily load prop value
+ // just for compatibility, our lazilyLoad is empty
+ val = lazilyLoadDesktopProperty(propName);
+ }
+ return val;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the locking key state for the specified key.
+ *
+ * @param a0 the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK,
+ * or VK_KANA_LOCK.
+ *
+ * @return true if the specified key code is in the locked state,
+ * false otherwise.
+ *
+ * @throws UnsupportedOperationException if the state of this key
+ * can't be retrieved, or if the keyboard doesn't have this key.
+ * @throws NotImplementedException if this method is not implemented.
+ */
+ public boolean getLockingKeyState(int a0) throws UnsupportedOperationException, org.apache.harmony.luni.util.NotImplementedException {
+ lockAWT();
+ try {
+ } finally {
+ unlockAWT();
+ }
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$
+ }
+ return true;
+ }
+
+ /**
+ * Returns the maximum number of colors which the Toolkit supports for
+ * custom cursor.
+ *
+ * @return the maximum cursor colors.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public int getMaximumCursorColors() throws HeadlessException {
+ lockAWT();
+ try {
+ return wtk.getCursorFactory().getMaximumCursorColors();
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the menu shortcut key mask.
+ *
+ * @return the menu shortcut key mask.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public int getMenuShortcutKeyMask() throws HeadlessException {
+ lockAWT();
+ try {
+ return InputEvent.CTRL_MASK;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the screen insets.
+ *
+ * @param gc the GraphicsConfiguration.
+ *
+ * @return the insets of this toolkit.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException {
+ if (gc == null) {
+ throw new NullPointerException();
+ }
+ lockAWT();
+ try {
+ return new Insets(0, 0, 0, 0); //TODO: get real screen insets
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the system EventQueue instance.
+ * If the default implementation of checkAwtEventQueueAccess is used,
+ * then this results of a call to the security manager's checkPermission
+ * method with an AWTPermission("accessEventQueue") permission.
+ *
+ * @return the system EventQueue instance.
+ */
+ public final EventQueue getSystemEventQueue() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkAwtEventQueueAccess();
+ }
+ return getSystemEventQueueImpl();
+ }
+
+ /**
+ * Gets the system event queue core.
+ *
+ * @return the system event queue core
+ */
+ EventQueueCore getSystemEventQueueCore() {
+ return systemEventQueueCore;
+ }
+
+ /**
+ * Sets the system event queue core.
+ *
+ * @param core the new system event queue core
+ */
+ void setSystemEventQueueCore(EventQueueCore core) {
+ systemEventQueueCore = core;
+ }
+
+ /**
+ * Initialize the desktop properties.
+ */
+ protected void initializeDesktopProperties() {
+ lockAWT();
+ try {
+ wtk.getSystemProperties().init(desktopProperties);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if dynamic layout of Containers is active or not.
+ *
+ * @return true, if is dynamic layout of Containers is active,
+ * false otherwise.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public boolean isDynamicLayoutActive() throws HeadlessException {
+ lockAWT();
+ try {
+ // always return true
+ return true;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+
+ /**
+ * Returns if the layout of Containers is checked dynamically during resizing,
+ * or statically after resizing is completed.
+ *
+ * @return true, if if the layout of Containers is checked dynamically during
+ * resizing; false, if the layout of Containers is checked statically after
+ * resizing is completed.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ protected boolean isDynamicLayoutSet() throws HeadlessException {
+ lockAWT();
+ try {
+ return bDynamicLayoutSet;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Checks if the specified frame state is supported by Toolkit or not.
+ *
+ * @param state the frame state.
+ *
+ * @return true, if frame state is supported; false othrwise.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public boolean isFrameStateSupported(int state) throws HeadlessException {
+ lockAWT();
+ try {
+ return wtk.getWindowFactory().isWindowStateSupported(state);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Loads the value of the desktop property with the specified property name.
+ *
+ * @param propName the property name.
+ *
+ * @return the desktop property values.
+ */
+ protected Object lazilyLoadDesktopProperty(String propName) {
+ return null;
+ }
+
+ /**
+ * Loads the current system color values to the specified array.
+ *
+ * @param colors the array where the current system color values
+ * are written by this method.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ protected void loadSystemColors(int[] colors) throws HeadlessException {
+ lockAWT();
+ try {
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the value of the desktop property with the specified name.
+ *
+ * @param propName the property's name.
+ * @param value the property's value.
+ */
+ protected final void setDesktopProperty(String propName, Object value) {
+ Object oldVal;
+ lockAWT();
+ try {
+ oldVal = getDesktopProperty(propName);
+ userPropSet.add(propName);
+ desktopProperties.put(propName, value);
+ } finally {
+ unlockAWT();
+ }
+ desktopPropsSupport.firePropertyChange(propName, oldVal, value);
+ }
+
+ /**
+ * Sets the layout state, whether the Container layout is checked
+ * dynamically during resizing, or statically after resizing is completed.
+ *
+ * @param dynamic the new dynamic layout state - if true the layout of
+ * Containers is checked dynamically during resizing, if false -
+ * statically after resizing is completed.
+ *
+ * @throws HeadlessException if the GraphicsEnvironment.isHeadless()
+ * method returns true.
+ */
+ public void setDynamicLayout(boolean dynamic) throws HeadlessException {
+ lockAWT();
+ try {
+ bDynamicLayoutSet = dynamic;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Sets the locking key state for the specified key code.
+ *
+ * @param a0 the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK,
+ * or VK_KANA_LOCK.
+ * @param a1 the state - true to set the specified key code to the locked state,
+ * false - to unlock it.
+ *
+ * @throws UnsupportedOperationException if the state of this key
+ * can't be set, or if the keyboard doesn't have this key.
+ * @throws NotImplementedException if this method is not implemented.
+ */
+ public void setLockingKeyState(int a0, boolean a1) throws UnsupportedOperationException, org.apache.harmony.luni.util.NotImplementedException {
+ lockAWT();
+ try {
+ } finally {
+ unlockAWT();
+ }
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$
+ }
+ return;
+ }
+
+
+ /**
+ * On queue empty.
+ */
+ void onQueueEmpty() {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ /**
+ * Creates the wtk.
+ *
+ * @param clsName the cls name
+ *
+ * @return the wTK
+ */
+ private WTK createWTK(String clsName) {
+ WTK newWTK = null;
+ try {
+ newWTK = (WTK) Class.forName(clsName).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return newWTK;
+ }
+
+ /**
+ * Connect the component to its native window
+ * @param winId - id of native window just created
+ */
+ boolean onWindowCreated(long winId) {
+ return false;
+ }
+
+ /**
+ * Gets the native event queue.
+ *
+ * @return the native event queue
+ */
+ NativeEventQueue getNativeEventQueue() {
+ return wtk.getNativeEventQueue();
+ }
+
+ /**
+ * Returns a shared instance of implementation of org.apache.harmony.awt.wtk.NativeCursor
+ * for current platform for
+ *
+ * @param type - Java Cursor type
+ *
+ * @return new instance of implementation of NativeCursor
+ */
+ NativeCursor createNativeCursor(int type) {
+ return wtk.getCursorFactory().getCursor(type);
+ }
+
+ /**
+ * Returns a shared instance of implementation of org.apache.harmony.awt.wtk.NativeCursor
+ * for current platform for custom cursor
+ *
+ * @param img the img
+ * @param hotSpot the hot spot
+ * @param name the name
+ *
+ * @return new instance of implementation of NativeCursor
+ */
+ NativeCursor createCustomNativeCursor(Image img, Point hotSpot, String name) {
+ return wtk.getCursorFactory().createCustomCursor(img, hotSpot.x, hotSpot.y);
+ }
+
+ /**
+ * Adds an AWTEventListener to the Toolkit to listen for events
+ * of types corresponding to bits in the specified event mask.
+ * Event masks are defined in AWTEvent class.
+ *
+ * @param listener the AWTEventListener.
+ * @param eventMask he bitmask of event types.
+ */
+ public void addAWTEventListener(AWTEventListener listener, long eventMask) {
+ lockAWT();
+ try {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkPermission(awtEventsManager.permission);
+ }
+ awtEventsManager.addAWTEventListener(listener, eventMask);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Removes the specified awt event listener.
+ *
+ * @param listener the AWTEventListener to be removed.
+ */
+ public void removeAWTEventListener(AWTEventListener listener) {
+ lockAWT();
+ try {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkPermission(awtEventsManager.permission);
+ }
+ awtEventsManager.removeAWTEventListener(listener);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Gets the array of all AWT event listeners registered with this Toolkit.
+ *
+ * @return the array of all AWT event listeners registered with this Toolkit.
+ */
+ public AWTEventListener[] getAWTEventListeners() {
+ lockAWT();
+ try {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkPermission(awtEventsManager.permission);
+ }
+ return awtEventsManager.getAWTEventListeners();
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Returns the array of the AWT event listeners registered with this Toolkit
+ * for the event types corresponding to the specified event mask.
+ *
+ * @param eventMask the bit mask of event type.
+ *
+ * @return the array of the AWT event listeners registered in this Toolkit
+ * for the event types corresponding to the specified event mask.
+ */
+ public AWTEventListener[] getAWTEventListeners(long eventMask) {
+ lockAWT();
+ try {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkPermission(awtEventsManager.permission);
+ }
+ return awtEventsManager.getAWTEventListeners(eventMask);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ /**
+ * Dispatch awt event.
+ *
+ * @param event the event
+ */
+ void dispatchAWTEvent(AWTEvent event) {
+ awtEventsManager.dispatchAWTEvent(event);
+ }
+
+ /**
+ * The Class AWTEventsManager.
+ */
+ final class AWTEventsManager {
+
+ /** The permission. */
+ AWTPermission permission = new AWTPermission("listenToAllAWTEvents"); //$NON-NLS-1$
+
+ /** The listeners. */
+ private final AWTListenerList<AWTEventListenerProxy> listeners = new AWTListenerList<AWTEventListenerProxy>();
+
+ /**
+ * Adds the awt event listener.
+ *
+ * @param listener the listener
+ * @param eventMask the event mask
+ */
+ void addAWTEventListener(AWTEventListener listener, long eventMask) {
+ if (listener != null) {
+ listeners.addUserListener(new AWTEventListenerProxy(eventMask, listener));
+ }
+ }
+
+ /**
+ * Removes the awt event listener.
+ *
+ * @param listener the listener
+ */
+ void removeAWTEventListener(AWTEventListener listener) {
+ if (listener != null) {
+ for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+ if (listener == proxy.getListener()) {
+ listeners.removeUserListener(proxy);
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the aWT event listeners.
+ *
+ * @return the aWT event listeners
+ */
+ AWTEventListener[] getAWTEventListeners() {
+ HashSet<EventListener> listenersSet = new HashSet<EventListener>();
+ for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+ listenersSet.add(proxy.getListener());
+ }
+ return listenersSet.toArray(new AWTEventListener[listenersSet.size()]);
+ }
+
+ /**
+ * Gets the aWT event listeners.
+ *
+ * @param eventMask the event mask
+ *
+ * @return the aWT event listeners
+ */
+ AWTEventListener[] getAWTEventListeners(long eventMask) {
+ HashSet<EventListener> listenersSet = new HashSet<EventListener>();
+ for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+ if ((proxy.getEventMask() & eventMask) == eventMask) {
+ listenersSet.add(proxy.getListener());
+ }
+ }
+ return listenersSet.toArray(new AWTEventListener[listenersSet.size()]);
+ }
+
+ /**
+ * Dispatch awt event.
+ *
+ * @param event the event
+ */
+ void dispatchAWTEvent(AWTEvent event) {
+ AWTEvent.EventDescriptor descriptor = eventTypeLookup.getEventDescriptor(event);
+ if (descriptor == null) {
+ return;
+ }
+ for (AWTEventListenerProxy proxy : listeners.getUserListeners()) {
+ if ((proxy.getEventMask() & descriptor.eventMask) != 0) {
+ proxy.eventDispatched(event);
+ }
+ }
+ }
+ }
+
+ /**
+ * The Class AutoNumber.
+ */
+ static final class AutoNumber {
+
+ /** The next component. */
+ int nextComponent = 0;
+
+ /** The next canvas. */
+ int nextCanvas = 0;
+
+ /** The next panel. */
+ int nextPanel = 0;
+
+ /** The next window. */
+ int nextWindow = 0;
+
+ /** The next frame. */
+ int nextFrame = 0;
+
+ /** The next dialog. */
+ int nextDialog = 0;
+
+ /** The next button. */
+ int nextButton = 0;
+
+ /** The next menu component. */
+ int nextMenuComponent = 0;
+
+ /** The next label. */
+ int nextLabel = 0;
+
+ /** The next check box. */
+ int nextCheckBox = 0;
+
+ /** The next scrollbar. */
+ int nextScrollbar = 0;
+
+ /** The next scroll pane. */
+ int nextScrollPane = 0;
+
+ /** The next list. */
+ int nextList = 0;
+
+ /** The next choice. */
+ int nextChoice = 0;
+
+ /** The next file dialog. */
+ int nextFileDialog = 0;
+
+ /** The next text area. */
+ int nextTextArea = 0;
+
+ /** The next text field. */
+ int nextTextField = 0;
+ }
+
+ private class Lock {
+ }
+
+ /** The lock. */
+ private final Object lock = new Lock();
+
+}
diff --git a/awt/java/awt/ToolkitImpl.java b/awt/java/awt/ToolkitImpl.java
new file mode 100644
index 0000000..5015aef
--- /dev/null
+++ b/awt/java/awt/ToolkitImpl.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.awt;
+
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.peer.*;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.Hashtable;
+import java.util.Map;
+import org.apache.harmony.awt.gl.image.*;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+
+class ToolkitImpl extends Toolkit {
+
+ static final Hashtable<Serializable, Image> imageCache = new Hashtable<Serializable, Image>();
+
+ @Override
+ public void sync() {
+ lockAWT();
+ try {
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public int checkImage(Image image, int width, int height, ImageObserver observer) {
+ lockAWT();
+ try {
+ if (width == 0 || height == 0) {
+ return ImageObserver.ALLBITS;
+ }
+ if (!(image instanceof OffscreenImage)) {
+ return ImageObserver.ALLBITS;
+ }
+ OffscreenImage oi = (OffscreenImage) image;
+ return oi.checkImage(observer);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Image createImage(ImageProducer producer) {
+ lockAWT();
+ try {
+ return new OffscreenImage(producer);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Image createImage(byte[] imagedata, int imageoffset, int imagelength) {
+ lockAWT();
+ try {
+ return new OffscreenImage(new ByteArrayDecodingImageSource(imagedata, imageoffset,
+ imagelength));
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Image createImage(URL url) {
+ lockAWT();
+ try {
+ return new OffscreenImage(new URLDecodingImageSource(url));
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Image createImage(String filename) {
+ lockAWT();
+ try {
+ return new OffscreenImage(new FileDecodingImageSource(filename));
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public ColorModel getColorModel() {
+ lockAWT();
+ try {
+ return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
+ .getDefaultConfiguration().getColorModel();
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ @Deprecated
+ public FontMetrics getFontMetrics(Font font) {
+ lockAWT();
+ try {
+ GraphicsFactory gf = getGraphicsFactory();
+ return gf.getFontMetrics(font);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public boolean prepareImage(Image image, int width, int height, ImageObserver observer) {
+ lockAWT();
+ try {
+ if (width == 0 || height == 0) {
+ return true;
+ }
+ if (!(image instanceof OffscreenImage)) {
+ return true;
+ }
+ OffscreenImage oi = (OffscreenImage) image;
+ return oi.prepareImage(observer);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public void beep() {
+ lockAWT();
+ try {
+ // ???AWT: is there nothing to be implemented here?
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ @Deprecated
+ public String[] getFontList() {
+ lockAWT();
+ try {
+ } finally {
+ unlockAWT();
+ }
+ return null;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ @Deprecated
+ protected FontPeer getFontPeer(String a0, int a1) {
+ lockAWT();
+ try {
+ return null;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Image getImage(String filename) {
+ return getImage(filename, this);
+ }
+
+ static Image getImage(String filename, Toolkit toolkit) {
+ synchronized (imageCache) {
+ Image im = (filename == null ? null : imageCache.get(filename));
+
+ if (im == null) {
+ try {
+ im = toolkit.createImage(filename);
+ imageCache.put(filename, im);
+ } catch (Exception e) {
+ }
+ }
+
+ return im;
+ }
+ }
+
+ @Override
+ public Image getImage(URL url) {
+ return getImage(url, this);
+ }
+
+ static Image getImage(URL url, Toolkit toolkit) {
+ synchronized (imageCache) {
+ Image im = imageCache.get(url);
+ if (im == null) {
+ try {
+ im = toolkit.createImage(url);
+ imageCache.put(url, im);
+ } catch (Exception e) {
+ }
+ }
+ return im;
+ }
+ }
+
+ @Override
+ public int getScreenResolution() throws HeadlessException {
+ lockAWT();
+ try {
+ return 62;
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Dimension getScreenSize() {
+ lockAWT();
+ try {
+ DisplayMode dm = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice().getDisplayMode();
+ return new Dimension(dm.getWidth(), dm.getHeight());
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ public Map<java.awt.font.TextAttribute, ?> mapInputMethodHighlight(
+ InputMethodHighlight highlight) throws HeadlessException {
+ lockAWT();
+ try {
+ return mapInputMethodHighlightImpl(highlight);
+ } finally {
+ unlockAWT();
+ }
+ }
+
+ @Override
+ protected EventQueue getSystemEventQueueImpl() {
+ return getSystemEventQueueCore().getActiveEventQueue();
+ }
+}
diff --git a/awt/java/awt/Transparency.java b/awt/java/awt/Transparency.java
new file mode 100644
index 0000000..9793114
--- /dev/null
+++ b/awt/java/awt/Transparency.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt;
+
+/**
+ * The Transparency interface defines transparency's general modes.
+ */
+public interface Transparency {
+
+ /** The Constant OPAQUE represents completely opaque data,
+ * all pixels have an alpha value of 1.0.
+ */
+ public static final int OPAQUE = 1;
+
+ /** The Constant BITMASK represents data which can be either
+ * completely opaque, with an alpha value of 1.0, or completely
+ * transparent, with an alpha value of 0.0.
+ */
+ public static final int BITMASK = 2;
+
+ /** The Constant TRANSLUCENT represents data which alpha value
+ * can vary between and including 0.0 and 1.0. */
+ public static final int TRANSLUCENT = 3;
+
+ /**
+ * Gets the transparency mode.
+ *
+ * @return the transparency mode: OPAQUE, BITMASK or TRANSLUCENT.
+ */
+ public int getTransparency();
+
+}
+
diff --git a/awt/java/awt/color/CMMException.java b/awt/java/awt/color/CMMException.java
new file mode 100644
index 0000000..16fe76e
--- /dev/null
+++ b/awt/java/awt/color/CMMException.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+/**
+ * The CMMException is thrown as soon as a native CMM error
+ * occures.
+ */
+public class CMMException extends java.lang.RuntimeException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 5775558044142994965L;
+
+ /**
+ * Instantiates a new CMM exception with detail message.
+ *
+ * @param s the String - detail message.
+ */
+ public CMMException (String s) {
+ super (s);
+ }
+}
diff --git a/awt/java/awt/color/ColorSpace.java b/awt/java/awt/color/ColorSpace.java
new file mode 100644
index 0000000..f961514
--- /dev/null
+++ b/awt/java/awt/color/ColorSpace.java
@@ -0,0 +1,340 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import java.io.Serializable;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ColorSpace class defines a color space type for a Color and provides methods
+ * for arrays of color component operations.
+ */
+public abstract class ColorSpace implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -409452704308689724L;
+
+ /** The Constant TYPE_XYZ indicates XYZ color space type. */
+ public static final int TYPE_XYZ = 0;
+
+ /** The Constant TYPE_Lab indicates Lab color space type. */
+ public static final int TYPE_Lab = 1;
+
+ /** The Constant TYPE_Luv indicates Luv color space type. */
+ public static final int TYPE_Luv = 2;
+
+ /** The Constant TYPE_YCbCr indicates YCbCr color space type. */
+ public static final int TYPE_YCbCr = 3;
+
+ /** The Constant TYPE_Yxy indicates Yxy color space type. */
+ public static final int TYPE_Yxy = 4;
+
+ /** The Constant TYPE_RGB indicates RGB color space type. */
+ public static final int TYPE_RGB = 5;
+
+ /** The Constant TYPE_GRAY indicates Gray color space type. */
+ public static final int TYPE_GRAY = 6;
+
+ /** The Constant TYPE_HSV indicates HSV color space type. */
+ public static final int TYPE_HSV = 7;
+
+ /** The Constant TYPE_HLS indicates HLS color space type. */
+ public static final int TYPE_HLS = 8;
+
+ /** The Constant TYPE_CMYK indicates CMYK color space type. */
+ public static final int TYPE_CMYK = 9;
+
+ /** The Constant TYPE_CMY indicates CMY color space type. */
+ public static final int TYPE_CMY = 11;
+
+ /** The Constant TYPE_2CLR indicates color spaces with 2 components. */
+ public static final int TYPE_2CLR = 12;
+
+ /** The Constant TYPE_3CLR indicates color spaces with 3 components. */
+ public static final int TYPE_3CLR = 13;
+
+ /** The Constant TYPE_4CLR indicates color spaces with 4 components. */
+ public static final int TYPE_4CLR = 14;
+
+ /** The Constant TYPE_5CLR indicates color spaces with 5 components. */
+ public static final int TYPE_5CLR = 15;
+
+ /** The Constant TYPE_6CLR indicates color spaces with 6 components. */
+ public static final int TYPE_6CLR = 16;
+
+ /** The Constant TYPE_7CLR indicates color spaces with 7 components. */
+ public static final int TYPE_7CLR = 17;
+
+ /** The Constant TYPE_8CLR indicates color spaces with 8 components. */
+ public static final int TYPE_8CLR = 18;
+
+ /** The Constant TYPE_9CLR indicates color spaces with 9 components. */
+ public static final int TYPE_9CLR = 19;
+
+ /** The Constant TYPE_ACLR indicates color spaces with 10 components. */
+ public static final int TYPE_ACLR = 20;
+
+ /** The Constant TYPE_BCLR indicates color spaces with 11 components. */
+ public static final int TYPE_BCLR = 21;
+
+ /** The Constant TYPE_CCLR indicates color spaces with 12 components. */
+ public static final int TYPE_CCLR = 22;
+
+ /** The Constant TYPE_DCLR indicates color spaces with 13 components. */
+ public static final int TYPE_DCLR = 23;
+
+ /** The Constant TYPE_ECLR indicates color spaces with 14 components. */
+ public static final int TYPE_ECLR = 24;
+
+ /** The Constant TYPE_FCLR indicates color spaces with 15 components. */
+ public static final int TYPE_FCLR = 25;
+
+ /** The Constant CS_sRGB indicates standard RGB color space.*/
+ public static final int CS_sRGB = 1000;
+
+ /** The Constant CS_LINEAR_RGB indicates linear RGB color space. */
+ public static final int CS_LINEAR_RGB = 1004;
+
+ /** The Constant CS_CIEXYZ indicates CIEXYZ conversion color space. */
+ public static final int CS_CIEXYZ = 1001;
+
+ /** The Constant CS_PYCC indicates Photo YCC conversion color space. */
+ public static final int CS_PYCC = 1002;
+
+ /** The Constant CS_GRAY indicates linear gray scale color space. */
+ public static final int CS_GRAY = 1003;
+
+ /** The cs_ gray. */
+ private static ColorSpace cs_Gray = null;
+
+ /** The cs_ pycc. */
+ private static ColorSpace cs_PYCC = null;
+
+ /** The cs_ ciexyz. */
+ private static ColorSpace cs_CIEXYZ = null;
+
+ /** The cs_ lrgb. */
+ private static ColorSpace cs_LRGB = null;
+
+ /** The cs_s rgb. */
+ private static ColorSpace cs_sRGB = null;
+
+ /** The type. */
+ private int type;
+
+ /** The num components. */
+ private int numComponents;
+
+ /**
+ * Instantiates a ColorSpace with the specified
+ * ColorSpace type and number of components.
+ *
+ * @param type the type of color space.
+ * @param numcomponents the number of components.
+ */
+ protected ColorSpace(int type, int numcomponents) {
+ this.numComponents = numcomponents;
+ this.type = type;
+ }
+
+ /**
+ * Gets the name of the component for the specified component index.
+ *
+ * @param idx the index of the component.
+ *
+ * @return the name of the component.
+ */
+ public String getName(int idx) {
+ if (idx < 0 || idx > numComponents - 1) {
+ // awt.16A=Invalid component index: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.16A", idx)); //$NON-NLS-1$
+ }
+
+ return "Unnamed color component #" + idx; //$NON-NLS-1$
+ }
+
+ /**
+ * Perform transformation a color from this ColorSpace
+ * into the RGB color space.
+ *
+ * @param colorvalue the color value in this ColorSpace.
+ *
+ * @return the float array with color components in the
+ * RGB color space.
+ */
+ public abstract float[] toRGB(float[] colorvalue);
+
+ /**
+ * Perform transformation a color from this ColorSpace
+ * into the CS_CIEXYZ color space.
+ *
+ * @param colorvalue the color value in this ColorSpace.
+ *
+ * @return the float array with color components in the
+ * CS_CIEXYZ color space.
+ */
+ public abstract float[] toCIEXYZ(float[] colorvalue);
+
+ /**
+ * Performs color transformation from the RGB color space
+ * into this ColorSpace.
+ *
+ * @param rgbvalue a float array in the RGB color space.
+ *
+ * @return the float[] an array of transformed color
+ * components.
+ */
+ public abstract float[] fromRGB(float[] rgbvalue);
+
+ /**
+ * Performs color transformation from the CS_CIEXYZ color space
+ * into this ColorSpace.
+ *
+ * @param colorvalue a float array in the CS_CIEXYZ color space.
+ *
+ * @return the float[] an array of transformed color
+ * components.
+ */
+ public abstract float[] fromCIEXYZ(float[] colorvalue);
+
+ /**
+ * Gets the minimum normalized color component value for
+ * the specified component.
+ *
+ * @param component the component.
+ *
+ * @return the miniimum normalized value of the component.
+ */
+ public float getMinValue(int component) {
+ if (component < 0 || component > numComponents - 1) {
+ // awt.16A=Invalid component index: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.16A", component)); //$NON-NLS-1$
+ }
+ return 0;
+ }
+
+ /**
+ * Gets the maximum normalized color component value for
+ * the specified component.
+ *
+ * @param component the component.
+ *
+ * @return the maximum normalized value of the component.
+ */
+ public float getMaxValue(int component) {
+ if (component < 0 || component > numComponents - 1) {
+ // awt.16A=Invalid component index: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.16A", component)); //$NON-NLS-1$
+ }
+ return 1;
+ }
+
+ /**
+ * Checks if this ColorSpace has CS_sRGB type or not.
+ *
+ * @return true, if this ColorSpace has CS_sRGB type,
+ * false otherwise.
+ */
+ public boolean isCS_sRGB() {
+ // If our color space is sRGB, then cs_sRGB
+ // is already initialized
+ return (this == cs_sRGB);
+ }
+
+ /**
+ * Gets the type of the ColorSpace.
+ *
+ * @return the type of the ColorSpace.
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Gets the number of components for this ColorSpace.
+ *
+ * @return the number of components.
+ */
+ public int getNumComponents() {
+ return numComponents;
+ }
+
+
+ /**
+ * Gets the single instance of ColorSpace with the specified
+ * ColorSpace: CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, CS_GRAY,
+ * or CS_PYCC.
+ *
+ * @param colorspace the identifier of the specified Colorspace.
+ *
+ * @return the single instance of the desired ColorSpace.
+ */
+ public static ColorSpace getInstance(int colorspace) {
+ switch (colorspace) {
+ case CS_sRGB:
+ if (cs_sRGB == null) {
+ cs_sRGB = new ICC_ColorSpace(
+ new ICC_ProfileStub(CS_sRGB));
+ LUTColorConverter.sRGB_CS = cs_sRGB;
+ //ICC_Profile.getInstance (CS_sRGB));
+ }
+ return cs_sRGB;
+ case CS_CIEXYZ:
+ if (cs_CIEXYZ == null) {
+ cs_CIEXYZ = new ICC_ColorSpace(
+ new ICC_ProfileStub(CS_CIEXYZ));
+ //ICC_Profile.getInstance (CS_CIEXYZ));
+ }
+ return cs_CIEXYZ;
+ case CS_GRAY:
+ if (cs_Gray == null) {
+ cs_Gray = new ICC_ColorSpace(
+ new ICC_ProfileStub(CS_GRAY));
+ LUTColorConverter.LINEAR_GRAY_CS = cs_Gray;
+ //ICC_Profile.getInstance (CS_GRAY));
+ }
+ return cs_Gray;
+ case CS_PYCC:
+ if (cs_PYCC == null) {
+ cs_PYCC = new ICC_ColorSpace(
+ new ICC_ProfileStub(CS_PYCC));
+ //ICC_Profile.getInstance (CS_PYCC));
+ }
+ return cs_PYCC;
+ case CS_LINEAR_RGB:
+ if (cs_LRGB == null) {
+ cs_LRGB = new ICC_ColorSpace(
+ new ICC_ProfileStub(CS_LINEAR_RGB));
+ LUTColorConverter.LINEAR_GRAY_CS = cs_Gray;
+ //ICC_Profile.getInstance (CS_LINEAR_RGB));
+ }
+ return cs_LRGB;
+ default:
+ }
+
+ // Unknown argument passed
+ // awt.16B=Not a predefined colorspace
+ throw new IllegalArgumentException(Messages.getString("Not a predefined colorspace")); //$NON-NLS-1$
+ }
+
+} \ No newline at end of file
diff --git a/awt/java/awt/color/ICC_ColorSpace.java b/awt/java/awt/color/ICC_ColorSpace.java
new file mode 100644
index 0000000..5ece2ef
--- /dev/null
+++ b/awt/java/awt/color/ICC_ColorSpace.java
@@ -0,0 +1,379 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import org.apache.harmony.awt.gl.color.ColorConverter;
+import org.apache.harmony.awt.gl.color.ColorScaler;
+import org.apache.harmony.awt.gl.color.ICC_Transform;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+import java.io.*;
+
+/**
+ * ICC_ColorSpace class implements ColorSpace abstract class and
+ * represents device independent and device dependent color spaces.
+ * This color space is based on the International Color Consortium
+ * Specification (ICC) File Format for Color Profiles:
+ * <a href="http://www.color.org">http://www.color.org</a>
+ */
+public class ICC_ColorSpace extends ColorSpace {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 3455889114070431483L;
+
+ // Need to keep compatibility with serialized form
+ /** The Constant serialPersistentFields. */
+ private static final ObjectStreamField[]
+ serialPersistentFields = {
+ new ObjectStreamField("thisProfile", ICC_Profile.class), //$NON-NLS-1$
+ new ObjectStreamField("minVal", float[].class), //$NON-NLS-1$
+ new ObjectStreamField("maxVal", float[].class), //$NON-NLS-1$
+ new ObjectStreamField("diffMinMax", float[].class), //$NON-NLS-1$
+ new ObjectStreamField("invDiffMinMax", float[].class), //$NON-NLS-1$
+ new ObjectStreamField("needScaleInit", Boolean.TYPE) //$NON-NLS-1$
+ };
+
+
+ /**
+ * According to ICC specification (from http://www.color.org)
+ * "For the CIEXYZ encoding, each component (X, Y, and Z)
+ * is encoded as a u1Fixed15Number".
+ * This means that max value for this encoding is 1 + (32767/32768)
+ */
+ private static final float MAX_XYZ = 1f + (32767f/32768f);
+
+ /** The Constant MAX_SHORT. */
+ private static final float MAX_SHORT = 65535f;
+
+ /** The Constant INV_MAX_SHORT. */
+ private static final float INV_MAX_SHORT = 1f/MAX_SHORT;
+
+ /** The Constant SHORT2XYZ_FACTOR. */
+ private static final float SHORT2XYZ_FACTOR = MAX_XYZ/MAX_SHORT;
+
+ /** The Constant XYZ2SHORT_FACTOR. */
+ private static final float XYZ2SHORT_FACTOR = MAX_SHORT/MAX_XYZ;
+
+ /** The profile. */
+ private ICC_Profile profile = null;
+
+ /** The min values. */
+ private float minValues[] = null;
+
+ /** The max values. */
+ private float maxValues[] = null;
+
+ // cache transforms here - performance gain
+ /** The to rgb transform. */
+ private ICC_Transform toRGBTransform = null;
+
+ /** The from rgb transform. */
+ private ICC_Transform fromRGBTransform = null;
+
+ /** The to xyz transform. */
+ private ICC_Transform toXYZTransform = null;
+
+ /** The from xyz transform. */
+ private ICC_Transform fromXYZTransform = null;
+
+ /** The converter. */
+ private final ColorConverter converter = new ColorConverter();
+
+ /** The scaler. */
+ private final ColorScaler scaler = new ColorScaler();
+
+ /** The scaling data loaded. */
+ private boolean scalingDataLoaded = false;
+
+ /** The resolved deserialized inst. */
+ private ICC_ColorSpace resolvedDeserializedInst;
+
+ /**
+ * Instantiates a new ICC color space from an ICC_Profile object.
+ *
+ * @param pf the ICC_Profile object.
+ */
+ public ICC_ColorSpace(ICC_Profile pf) {
+ super(pf.getColorSpaceType(), pf.getNumComponents());
+
+ int pfClass = pf.getProfileClass();
+
+ switch (pfClass) {
+ case ICC_Profile.CLASS_COLORSPACECONVERSION:
+ case ICC_Profile.CLASS_DISPLAY:
+ case ICC_Profile.CLASS_OUTPUT:
+ case ICC_Profile.CLASS_INPUT:
+ break; // OK, it is color conversion profile
+ default:
+ // awt.168=Invalid profile class.
+ throw new IllegalArgumentException(Messages.getString("awt.168")); //$NON-NLS-1$
+ }
+
+ profile = pf;
+ fillMinMaxValues();
+ }
+
+ /**
+ * Returns the ICC_Profile for this ICC_ColorSpace.
+ *
+ * @return the ICC_Profile for this ICC_ColorSpace.
+ */
+ public ICC_Profile getProfile() {
+ if (profile instanceof ICC_ProfileStub) {
+ profile = ((ICC_ProfileStub) profile).loadProfile();
+ }
+
+ return profile;
+ }
+
+ @Override
+ public float[] toRGB(float[] colorvalue) {
+ if (toRGBTransform == null) {
+ ICC_Profile sRGBProfile =
+ ((ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB)).getProfile();
+ ICC_Profile[] profiles = {getProfile(), sRGBProfile};
+ toRGBTransform = new ICC_Transform(profiles);
+ if (!scalingDataLoaded) {
+ scaler.loadScalingData(this);
+ scalingDataLoaded = true;
+ }
+ }
+
+ short[] data = new short[getNumComponents()];
+
+ scaler.scale(colorvalue, data, 0);
+
+ short[] converted =
+ converter.translateColor(toRGBTransform, data, null);
+
+ // unscale to sRGB
+ float[] res = new float[3];
+
+ res[0] = ((converted[0] & 0xFFFF)) * INV_MAX_SHORT;
+ res[1] = ((converted[1] & 0xFFFF)) * INV_MAX_SHORT;
+ res[2] = ((converted[2] & 0xFFFF)) * INV_MAX_SHORT;
+
+ return res;
+ }
+
+ @Override
+ public float[] toCIEXYZ(float[] colorvalue) {
+ if (toXYZTransform == null) {
+ ICC_Profile xyzProfile =
+ ((ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ)).getProfile();
+ ICC_Profile[] profiles = {getProfile(), xyzProfile};
+ try {
+ int[] intents = {
+ ICC_Profile.icRelativeColorimetric,
+ ICC_Profile.icPerceptual};
+ toXYZTransform = new ICC_Transform(profiles, intents);
+ } catch (CMMException e) { // No such tag, use what we can
+ toXYZTransform = new ICC_Transform(profiles);
+ }
+
+ if (!scalingDataLoaded) {
+ scaler.loadScalingData(this);
+ scalingDataLoaded = true;
+ }
+ }
+
+ short[] data = new short[getNumComponents()];
+
+ scaler.scale(colorvalue, data, 0);
+
+ short[] converted =
+ converter.translateColor(toXYZTransform, data, null);
+
+ // unscale to XYZ
+ float[] res = new float[3];
+
+ res[0] = ((converted[0] & 0xFFFF)) * SHORT2XYZ_FACTOR;
+ res[1] = ((converted[1] & 0xFFFF)) * SHORT2XYZ_FACTOR;
+ res[2] = ((converted[2] & 0xFFFF)) * SHORT2XYZ_FACTOR;
+
+ return res;
+ }
+
+ @Override
+ public float[] fromRGB(float[] rgbvalue) {
+ if (fromRGBTransform == null) {
+ ICC_Profile sRGBProfile =
+ ((ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB)).getProfile();
+ ICC_Profile[] profiles = {sRGBProfile, getProfile()};
+ fromRGBTransform = new ICC_Transform(profiles);
+ if (!scalingDataLoaded) {
+ scaler.loadScalingData(this);
+ scalingDataLoaded = true;
+ }
+ }
+
+ // scale rgb value to short
+ short[] scaledRGBValue = new short[3];
+ scaledRGBValue[0] = (short)(rgbvalue[0] * MAX_SHORT + 0.5f);
+ scaledRGBValue[1] = (short)(rgbvalue[1] * MAX_SHORT + 0.5f);
+ scaledRGBValue[2] = (short)(rgbvalue[2] * MAX_SHORT + 0.5f);
+
+ short[] converted =
+ converter.translateColor(fromRGBTransform, scaledRGBValue, null);
+
+ float[] res = new float[getNumComponents()];
+
+ scaler.unscale(res, converted, 0);
+
+ return res;
+ }
+
+ @Override
+ public float[] fromCIEXYZ(float[] xyzvalue) {
+ if (fromXYZTransform == null) {
+ ICC_Profile xyzProfile =
+ ((ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ)).getProfile();
+ ICC_Profile[] profiles = {xyzProfile, getProfile()};
+ try {
+ int[] intents = {
+ ICC_Profile.icPerceptual,
+ ICC_Profile.icRelativeColorimetric};
+ fromXYZTransform = new ICC_Transform(profiles, intents);
+ } catch (CMMException e) { // No such tag, use what we can
+ fromXYZTransform = new ICC_Transform(profiles);
+ }
+
+ if (!scalingDataLoaded) {
+ scaler.loadScalingData(this);
+ scalingDataLoaded = true;
+ }
+
+ }
+
+ // scale xyz value to short
+ short[] scaledXYZValue = new short[3];
+ scaledXYZValue[0] = (short)(xyzvalue[0] * XYZ2SHORT_FACTOR + 0.5f);
+ scaledXYZValue[1] = (short)(xyzvalue[1] * XYZ2SHORT_FACTOR + 0.5f);
+ scaledXYZValue[2] = (short)(xyzvalue[2] * XYZ2SHORT_FACTOR + 0.5f);
+
+ short[] converted =
+ converter.translateColor(fromXYZTransform, scaledXYZValue, null);
+
+ float[] res = new float[getNumComponents()];
+
+ scaler.unscale(res, converted, 0);
+
+ return res;
+ }
+
+ @Override
+ public float getMinValue(int component) {
+ if ((component < 0) || (component > this.getNumComponents() - 1)) {
+ // awt.169=Component index out of range
+ throw new IllegalArgumentException(Messages.getString("awt.169")); //$NON-NLS-1$
+ }
+
+ return minValues[component];
+ }
+
+ @Override
+ public float getMaxValue(int component) {
+ if ((component < 0) || (component > this.getNumComponents() - 1)) {
+ // awt.169=Component index out of range
+ throw new IllegalArgumentException(Messages.getString("awt.169")); //$NON-NLS-1$
+ }
+
+ return maxValues[component];
+ }
+
+ /**
+ * Fill min max values.
+ */
+ private void fillMinMaxValues() {
+ int n = getNumComponents();
+ maxValues = new float[n];
+ minValues = new float[n];
+ switch (getType()) {
+ case ColorSpace.TYPE_XYZ:
+ minValues[0] = 0;
+ minValues[1] = 0;
+ minValues[2] = 0;
+ maxValues[0] = MAX_XYZ;
+ maxValues[1] = MAX_XYZ;
+ maxValues[2] = MAX_XYZ;
+ break;
+ case ColorSpace.TYPE_Lab:
+ minValues[0] = 0;
+ minValues[1] = -128;
+ minValues[2] = -128;
+ maxValues[0] = 100;
+ maxValues[1] = 127;
+ maxValues[2] = 127;
+ break;
+ default:
+ for(int i=0; i<n; i++) {
+ minValues[i] = 0;
+ maxValues[i] = 1;
+ }
+ }
+ }
+
+ /**
+ * Write object.
+ *
+ * @param out the out
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ ObjectOutputStream.PutField fields = out.putFields();
+
+ fields.put("thisProfile", profile); //$NON-NLS-1$
+ fields.put("minVal", null); //$NON-NLS-1$
+ fields.put("maxVal", null); //$NON-NLS-1$
+ fields.put("diffMinMax", null); //$NON-NLS-1$
+ fields.put("invDiffMinMax", null); //$NON-NLS-1$
+ fields.put("needScaleInit", true); //$NON-NLS-1$
+
+ out.writeFields();
+ }
+
+ /**
+ * Read object.
+ *
+ * @param in the in
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ * @throws ClassNotFoundException the class not found exception
+ */
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField fields = in.readFields();
+ resolvedDeserializedInst =
+ new ICC_ColorSpace((ICC_Profile) fields.get("thisProfile", null)); //$NON-NLS-1$
+ }
+
+ /**
+ * Read resolve.
+ *
+ * @return the object
+ *
+ * @throws ObjectStreamException the object stream exception
+ */
+ Object readResolve() throws ObjectStreamException {
+ return resolvedDeserializedInst;
+ }
+}
+
diff --git a/awt/java/awt/color/ICC_Profile.java b/awt/java/awt/color/ICC_Profile.java
new file mode 100644
index 0000000..ad704e0
--- /dev/null
+++ b/awt/java/awt/color/ICC_Profile.java
@@ -0,0 +1,1231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.StringTokenizer;
+
+import org.apache.harmony.awt.gl.color.ICC_ProfileHelper;
+import org.apache.harmony.awt.gl.color.NativeCMM;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ICC_Profile class represents a color profile data for color spaces
+ * based on the International Color Consortium Specification ICC.1:2001-12,
+ * File Format for Color Profiles.
+ */
+public class ICC_Profile implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -3938515861990936766L;
+
+ // NOTE: Constant field values are noted in 1.5 specification.
+
+ /**
+ * The Constant CLASS_INPUT indicates that profile class is input.
+ */
+ public static final int CLASS_INPUT = 0;
+
+ /**
+ * The Constant CLASS_DISPLAY indicates that profile class is display.
+ */
+ public static final int CLASS_DISPLAY = 1;
+
+ /**
+ * The Constant CLASS_OUTPUT indicates that profile class is output.
+ */
+ public static final int CLASS_OUTPUT = 2;
+
+ /**
+ * The Constant CLASS_DEVICELINK indicates that profile class
+ * is device link.
+ */
+ public static final int CLASS_DEVICELINK = 3;
+
+ /**
+ * The Constant CLASS_COLORSPACECONVERSION indicates that profile class
+ * is color space conversion.
+ */
+ public static final int CLASS_COLORSPACECONVERSION = 4;
+
+ /** The Constant CLASS_ABSTRACT indicates that profile class is abstract. */
+ public static final int CLASS_ABSTRACT = 5;
+
+ /**
+ * The Constant CLASS_NAMEDCOLOR indicates that profile class
+ * is named color.
+ */
+ public static final int CLASS_NAMEDCOLOR = 6;
+
+ /** The Constant icSigXYZData - ICC Profile Color Space Type Signature. */
+ public static final int icSigXYZData = 1482250784;
+
+ /** The Constant icSigLabData - ICC Profile Color Space Type Signature. */
+ public static final int icSigLabData = 1281450528;
+
+ /** The Constant icSigLuvData - ICC Profile Color Space Type Signature. */
+ public static final int icSigLuvData = 1282766368;
+
+ /** The Constant icSigYCbCrData - ICC Profile Color Space Type Signature. */
+ public static final int icSigYCbCrData = 1497588338;
+
+ /** The Constant icSigYxyData - ICC Profile Color Space Type Signature. */
+ public static final int icSigYxyData = 1501067552;
+
+ /** The Constant icSigRgbData - ICC Profile Color Space Type Signature. */
+ public static final int icSigRgbData = 1380401696;
+
+ /** The Constant icSigGrayData - ICC Profile Color Space Type Signature. */
+ public static final int icSigGrayData = 1196573017;
+
+ /** The Constant icSigHsvData - ICC Profile Color Space Type Signature. */
+ public static final int icSigHsvData = 1213421088;
+
+ /** The Constant icSigHlsData - ICC Profile Color Space Type Signature. */
+ public static final int icSigHlsData = 1212961568;
+
+ /** The Constant icSigCmykData - ICC Profile Color Space Type Signature. */
+ public static final int icSigCmykData = 1129142603;
+
+ /** The Constant icSigCmyData - ICC Profile Color Space Type Signature. */
+ public static final int icSigCmyData = 1129142560;
+
+ /** The Constant icSigSpace2CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace2CLR = 843271250;
+
+ /** The Constant icSigSpace3CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace3CLR = 860048466;
+
+ /** The Constant icSigSpace4CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace4CLR = 876825682;
+
+ /** The Constant icSigSpace5CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace5CLR = 893602898;
+
+ /** The Constant icSigSpace6CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace6CLR = 910380114;
+
+ /** The Constant icSigSpace7CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace7CLR = 927157330;
+
+ /** The Constant icSigSpace8CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace8CLR = 943934546;
+
+ /** The Constant icSigSpace9CLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpace9CLR = 960711762;
+
+ /** The Constant icSigSpaceACLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceACLR = 1094929490;
+
+ /** The Constant icSigSpaceBCLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceBCLR = 1111706706;
+
+ /** The Constant icSigSpaceCCLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceCCLR = 1128483922;
+
+ /** The Constant icSigSpaceDCLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceDCLR = 1145261138;
+
+ /** The Constant icSigSpaceECLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceECLR = 1162038354;
+
+ /** The Constant icSigSpaceFCLR - ICC Profile Color Space Type Signature. */
+ public static final int icSigSpaceFCLR = 1178815570;
+
+ /** The Constant icSigInputClass - ICC Profile Class Signature. */
+ public static final int icSigInputClass = 1935896178;
+
+ /** The Constant icSigDisplayClass - ICC Profile Class Signature. */
+ public static final int icSigDisplayClass = 1835955314;
+
+ /** The Constant icSigOutputClass - ICC Profile Class Signature. */
+ public static final int icSigOutputClass = 1886549106;
+
+ /** The Constant icSigLinkClass - ICC Profile Class Signature. */
+ public static final int icSigLinkClass = 1818848875;
+
+ /** The Constant icSigAbstractClass - ICC Profile Class Signature. */
+ public static final int icSigAbstractClass = 1633842036;
+
+ /** The Constant icSigColorantOrderTag - ICC Profile Tag Signature. */
+ public static final int icSigColorantOrderTag = 1668051567;
+
+ /** The Constant icSigColorantTableTag - ICC Profile Tag Signature. */
+ public static final int icSigColorantTableTag = 1668051572;
+
+ /** The Constant icSigColorSpaceClass - ICC Profile Tag Signature. */
+ public static final int icSigColorSpaceClass = 1936744803;
+
+ /** The Constant icSigNamedColorClass - ICC Profile Tag Signature. */
+ public static final int icSigNamedColorClass = 1852662636;
+
+ /** The Constant icPerceptual - ICC Profile Rendering Intent. */
+ public static final int icPerceptual = 0;
+
+ /** The Constant icRelativeColorimetric - ICC Profile Rendering Intent. */
+ public static final int icRelativeColorimetric = 1;
+
+ /** The Constant icSaturation - ICC Profile Rendering Intent. */
+ public static final int icSaturation = 2;
+
+ /** The Constant icAbsoluteColorimetric - ICC Profile Rendering Intent. */
+ public static final int icAbsoluteColorimetric = 3;
+
+ /** The Constant icSigHead - ICC Profile Tag Signature. */
+ public static final int icSigHead = 1751474532;
+
+ /** The Constant icSigAToB0Tag - ICC Profile Tag Signature. */
+ public static final int icSigAToB0Tag = 1093812784;
+
+ /** The Constant icSigAToB1Tag - ICC Profile Tag Signature. */
+ public static final int icSigAToB1Tag = 1093812785;
+
+ /** The Constant icSigAToB2Tag - ICC Profile Tag Signature. */
+ public static final int icSigAToB2Tag = 1093812786;
+
+ /** The Constant icSigBlueColorantTag - ICC Profile Tag Signature. */
+ public static final int icSigBlueColorantTag = 1649957210;
+
+ /** The Constant icSigBlueMatrixColumnTag - ICC Profile Tag Signature. */
+ public static final int icSigBlueMatrixColumnTag = 1649957210;
+
+ /** The Constant icSigBlueTRCTag - ICC Profile Tag Signature. */
+ public static final int icSigBlueTRCTag = 1649693251;
+
+ /** The Constant icSigBToA0Tag - ICC Profile Tag Signature. */
+ public static final int icSigBToA0Tag = 1110589744;
+
+ /** The Constant icSigBToA1Tag - ICC Profile Tag Signature. */
+ public static final int icSigBToA1Tag = 1110589745;
+
+ /** The Constant icSigBToA2Tag - ICC Profile Tag Signature. */
+ public static final int icSigBToA2Tag = 1110589746;
+
+ /** The Constant icSigCalibrationDateTimeTag - ICC Profile Tag Signature. */
+ public static final int icSigCalibrationDateTimeTag = 1667329140;
+
+ /** The Constant icSigCharTargetTag - ICC Profile Tag Signature. */
+ public static final int icSigCharTargetTag = 1952543335;
+
+ /** The Constant icSigCopyrightTag - ICC Profile Tag Signature. */
+ public static final int icSigCopyrightTag = 1668313716;
+
+ /** The Constant icSigCrdInfoTag - ICC Profile Tag Signature. */
+ public static final int icSigCrdInfoTag = 1668441193;
+
+ /** The Constant icSigDeviceMfgDescTag - ICC Profile Tag Signature. */
+ public static final int icSigDeviceMfgDescTag = 1684893284;
+
+ /** The Constant icSigDeviceModelDescTag - ICC Profile Tag Signature. */
+ public static final int icSigDeviceModelDescTag = 1684890724;
+
+ /** The Constant icSigDeviceSettingsTag - ICC Profile Tag Signature. */
+ public static final int icSigDeviceSettingsTag = 1684371059;
+
+ /** The Constant icSigGamutTag - ICC Profile Tag Signature. */
+ public static final int icSigGamutTag = 1734438260;
+
+ /** The Constant icSigGrayTRCTag - ICC Profile Tag Signature. */
+ public static final int icSigGrayTRCTag = 1800688195;
+
+ /** The Constant icSigGreenColorantTag - ICC Profile Tag Signature. */
+ public static final int icSigGreenColorantTag = 1733843290;
+
+ /** The Constant icSigGreenMatrixColumnTag - ICC Profile Tag Signature. */
+ public static final int icSigGreenMatrixColumnTag = 1733843290;
+
+ /** The Constant icSigGreenTRCTag - ICC Profile Tag Signature. */
+ public static final int icSigGreenTRCTag = 1733579331;
+
+ /** The Constant icSigLuminanceTag - ICC Profile Tag Signature. */
+ public static final int icSigLuminanceTag = 1819635049;
+
+ /** The Constant icSigMeasurementTag - ICC Profile Tag Signature. */
+ public static final int icSigMeasurementTag = 1835360627;
+
+ /** The Constant icSigMediaBlackPointTag - ICC Profile Tag Signature. */
+ public static final int icSigMediaBlackPointTag = 1651208308;
+
+ /** The Constant icSigMediaWhitePointTag - ICC Profile Tag Signature. */
+ public static final int icSigMediaWhitePointTag = 2004119668;
+
+ /** The Constant icSigNamedColor2Tag - ICC Profile Tag Signature. */
+ public static final int icSigNamedColor2Tag = 1852009522;
+
+ /** The Constant icSigOutputResponseTag - ICC Profile Tag Signature. */
+ public static final int icSigOutputResponseTag = 1919251312;
+
+ /** The Constant icSigPreview0Tag - ICC Profile Tag Signature. */
+ public static final int icSigPreview0Tag = 1886545200;
+
+ /** The Constant icSigPreview1Tag - ICC Profile Tag Signature. */
+ public static final int icSigPreview1Tag = 1886545201;
+
+ /** The Constant icSigPreview2Tag - ICC Profile Tag Signature. */
+ public static final int icSigPreview2Tag = 1886545202;
+
+ /** The Constant icSigProfileDescriptionTag - ICC Profile Tag Signature. */
+ public static final int icSigProfileDescriptionTag = 1684370275;
+
+ /** The Constant icSigProfileSequenceDescTag - ICC Profile Tag Signature. */
+ public static final int icSigProfileSequenceDescTag = 1886610801;
+
+ /** The Constant icSigPs2CRD0Tag - ICC Profile Tag Signature. */
+ public static final int icSigPs2CRD0Tag = 1886610480;
+
+ /** The Constant icSigPs2CRD1Tag - ICC Profile Tag Signature. */
+ public static final int icSigPs2CRD1Tag = 1886610481;
+
+ /** The Constant icSigPs2CRD2Tag - ICC Profile Tag Signature. */
+ public static final int icSigPs2CRD2Tag = 1886610482;
+
+ /** The Constant icSigPs2CRD3Tag - ICC Profile Tag Signature. */
+ public static final int icSigPs2CRD3Tag = 1886610483;
+
+ /** The Constant icSigPs2CSATag - ICC Profile Tag Signature. */
+ public static final int icSigPs2CSATag = 1886597747;
+
+ /** The Constant icSigPs2RenderingIntentTag - ICC Profile Tag Signature. */
+ public static final int icSigPs2RenderingIntentTag = 1886597737;
+
+ /** The Constant icSigRedColorantTag - ICC Profile Tag Signature. */
+ public static final int icSigRedColorantTag = 1918392666;
+
+ /** The Constant icSigRedMatrixColumnTag - ICC Profile Tag Signature. */
+ public static final int icSigRedMatrixColumnTag = 1918392666;
+
+ /** The Constant icSigRedTRCTag - ICC Profile Tag Signature. */
+ public static final int icSigRedTRCTag = 1918128707;
+
+ /** The Constant icSigScreeningDescTag - ICC Profile Tag Signature. */
+ public static final int icSigScreeningDescTag = 1935897188;
+
+ /** The Constant icSigScreeningTag - ICC Profile Tag Signature. */
+ public static final int icSigScreeningTag = 1935897198;
+
+ /** The Constant icSigTechnologyTag - ICC Profile Tag Signature. */
+ public static final int icSigTechnologyTag = 1952801640;
+
+ /** The Constant icSigUcrBgTag - ICC Profile Tag Signature. */
+ public static final int icSigUcrBgTag = 1650877472;
+
+ /** The Constant icSigViewingCondDescTag - ICC Profile Tag Signature. */
+ public static final int icSigViewingCondDescTag = 1987405156;
+
+ /** The Constant icSigViewingConditionsTag - ICC Profile Tag Signature. */
+ public static final int icSigViewingConditionsTag = 1986618743;
+
+ /** The Constant icSigChromaticAdaptationTag - ICC Profile Tag Signature. */
+ public static final int icSigChromaticAdaptationTag = 1667785060;
+
+ /** The Constant icSigChromaticityTag - ICC Profile Tag Signature. */
+ public static final int icSigChromaticityTag = 1667789421;
+
+ /** The Constant icHdrSize - ICC Profile Header Location. */
+ public static final int icHdrSize = 0;
+
+ /** The Constant icHdrCmmId - ICC Profile Header Location. */
+ public static final int icHdrCmmId = 4;
+
+ /** The Constant icHdrVersion - ICC Profile Header Location. */
+ public static final int icHdrVersion = 8;
+
+ /** The Constant icHdrDeviceClass - ICC Profile Header Location. */
+ public static final int icHdrDeviceClass = 12;
+
+ /** The Constant icHdrColorSpace - ICC Profile Header Location. */
+ public static final int icHdrColorSpace = 16;
+
+ /** The Constant icHdrPcs - ICC Profile Header Location. */
+ public static final int icHdrPcs = 20;
+
+ /** The Constant icHdrDate - ICC Profile Header Location. */
+ public static final int icHdrDate = 24;
+
+ /** The Constant icHdrMagic - ICC Profile Header Location. */
+ public static final int icHdrMagic = 36;
+
+ /** The Constant icHdrPlatform - ICC Profile Header Location. */
+ public static final int icHdrPlatform = 40;
+
+ /** The Constant icHdrProfileID - ICC Profile Header Location. */
+ public static final int icHdrProfileID = 84;
+
+ /** The Constant icHdrFlags - ICC Profile Header Location. */
+ public static final int icHdrFlags = 44;
+
+ /** The Constant icHdrManufacturer - ICC Profile Header Location. */
+ public static final int icHdrManufacturer = 48;
+
+ /** The Constant icHdrModel - ICC Profile Header Location. */
+ public static final int icHdrModel = 52;
+
+ /** The Constant icHdrAttributes - ICC Profile Header Location. */
+ public static final int icHdrAttributes = 56;
+
+ /** The Constant icHdrRenderingIntent - ICC Profile Header Location. */
+ public static final int icHdrRenderingIntent = 64;
+
+ /** The Constant icHdrIlluminant - ICC Profile Header Location. */
+ public static final int icHdrIlluminant = 68;
+
+ /** The Constant icHdrCreator - ICC Profile Header Location. */
+ public static final int icHdrCreator = 80;
+
+ /** The Constant icICCAbsoluteColorimetric - ICC Profile Rendering Intent. */
+ public static final int icICCAbsoluteColorimetric = 3;
+
+ /** The Constant icMediaRelativeColorimetric - ICC Profile Rendering Intent. */
+ public static final int icMediaRelativeColorimetric = 1;
+
+ /** The Constant icTagType - ICC Profile Constant. */
+ public static final int icTagType = 0;
+
+ /** The Constant icTagReserved - ICC Profile Constant. */
+ public static final int icTagReserved = 4;
+
+ /** The Constant icCurveCount - ICC Profile Constant. */
+ public static final int icCurveCount = 8;
+
+ /** The Constant icCurveData - ICC Profile Constant. */
+ public static final int icCurveData = 12;
+
+ /** The Constant icXYZNumberX - ICC Profile Constant. */
+ public static final int icXYZNumberX = 8;
+
+ /** Size of a profile header. */
+ private static final int headerSize = 128;
+
+ /** header magic number. */
+ private static final int headerMagicNumber = 0x61637370;
+
+ // Cache of predefined profiles
+ /** The s rgb profile. */
+ private static ICC_Profile sRGBProfile;
+
+ /** The xyz profile. */
+ private static ICC_Profile xyzProfile;
+
+ /** The gray profile. */
+ private static ICC_Profile grayProfile;
+
+ /** The pycc profile. */
+ private static ICC_Profile pyccProfile;
+
+ /** The linear rgb profile. */
+ private static ICC_Profile linearRGBProfile;
+
+ /** Handle to the current profile. */
+ private transient long profileHandle = 0;
+
+ /** If handle is used by another class this object is not responsible for closing profile. */
+ private transient boolean handleStolen = false;
+
+ /** Cached header data. */
+ private transient byte[] headerData = null;
+
+ /** Serialization support. */
+ private transient ICC_Profile openedProfileObject;
+
+ /**
+ * Instantiates a new iC c_ profile.
+ *
+ * @param data the data
+ */
+ private ICC_Profile(byte[] data) {
+ profileHandle = NativeCMM.cmmOpenProfile(data);
+ NativeCMM.addHandle(this, profileHandle);
+ }
+
+ /**
+ * Used to instantiate dummy ICC_ProfileStub objects.
+ */
+ ICC_Profile() {
+ }
+
+ /**
+ * Used to instantiate subclasses (ICC_ProfileGrey and ICC_ProfileRGB).
+ *
+ * @param profileHandle - should be valid handle to opened color profile
+ */
+ ICC_Profile(long profileHandle) {
+ this.profileHandle = profileHandle;
+ // A new object reference, need to add it.
+ NativeCMM.addHandle(this, profileHandle);
+ }
+
+ /**
+ * Writes the ICC_Profile to a file with the specified name.
+ *
+ * @param fileName the file name.
+ *
+ * @throws IOException signals that an I/O exception has occurred during
+ * writing or opening the file.
+ */
+ public void write(String fileName) throws IOException {
+ FileOutputStream oStream = new FileOutputStream(fileName);
+ oStream.write(getData());
+ oStream.close();
+ }
+
+ /**
+ * Serializable implementation.
+ *
+ * @param s the s
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ private void writeObject(ObjectOutputStream s) throws IOException {
+ s.defaultWriteObject();
+ s.writeObject(null);
+ s.writeObject(getData());
+ }
+
+ /**
+ * Serializable implementation.
+ *
+ * @param s the s
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ * @throws ClassNotFoundException the class not found exception
+ */
+ private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
+ s.defaultReadObject();
+ String colorSpaceStr = (String)s.readObject();
+ byte[] data = (byte[])s.readObject();
+
+ if (colorSpaceStr != null) {
+ if (colorSpaceStr.equals("CS_sRGB")) { //$NON-NLS-1$
+ openedProfileObject = getInstance(ColorSpace.CS_sRGB);
+ } else if (colorSpaceStr.equals("CS_GRAY")) { //$NON-NLS-1$
+ openedProfileObject = getInstance(ColorSpace.CS_GRAY);
+ } else if (colorSpaceStr.equals("CS_LINEAR_RGB")) { //$NON-NLS-1$
+ openedProfileObject = getInstance(ColorSpace.CS_LINEAR_RGB);
+ } else if (colorSpaceStr.equals("CS_CIEXYZ")) { //$NON-NLS-1$
+ openedProfileObject = getInstance(ColorSpace.CS_CIEXYZ);
+ } else if (colorSpaceStr.equals("CS_PYCC")) { //$NON-NLS-1$
+ openedProfileObject = getInstance(ColorSpace.CS_PYCC);
+ } else {
+ openedProfileObject = ICC_Profile.getInstance(data);
+ }
+ } else {
+ openedProfileObject = ICC_Profile.getInstance(data);
+ }
+ }
+
+ /**
+ * Resolves instances being deserialized into instances registered with CMM.
+ *
+ * @return ICC_Profile object for profile registered with CMM.
+ *
+ * @throws ObjectStreamException if there is an error in the serialized
+ * files or during the process of reading them.
+ */
+ protected Object readResolve() throws ObjectStreamException {
+ return openedProfileObject;
+ }
+
+ /**
+ * Writes the ICC_Profile to an OutputStream.
+ *
+ * @param s the OutputStream.
+ *
+ * @throws IOException signals that an I/O exception has occurred during
+ * writing or opening OutputStream.
+ */
+ public void write(OutputStream s) throws IOException {
+ s.write(getData());
+ }
+
+ /**
+ * Sets a tagged data element in the profile from a byte array.
+ *
+ * @param tagSignature the ICC tag signature for the data element to be set.
+ * @param tagData the data to be set for the specified tag signature.
+ */
+ public void setData(int tagSignature, byte[] tagData) {
+ NativeCMM.cmmSetProfileElement(profileHandle, tagSignature, tagData);
+ // Remove cached header data if header is modified
+ if (tagSignature == icSigHead) {
+ headerData = null;
+ }
+ }
+
+ /**
+ * Gets a tagged data element from the profile as a byte array.
+ * Elements are identified by tag signatures as defined in
+ * the ICC specification.
+ *
+ * @param tagSignature the ICC tag signature for the data element to get.
+ *
+ * @return a byte array that contains the tagged data element.
+ */
+ public byte[] getData(int tagSignature) {
+ int tagSize = 0;
+ try {
+ tagSize = NativeCMM.cmmGetProfileElementSize(
+ profileHandle,
+ tagSignature
+ );
+ } catch (CMMException e) {
+ // We'll get this exception if there's no element with
+ // the specified tag signature
+ return null;
+ }
+
+ byte[] data = new byte[tagSize];
+ NativeCMM.cmmGetProfileElement(profileHandle, tagSignature, data);
+ return data;
+ }
+
+ /**
+ * Gets a data byte array of this ICC_Profile.
+ *
+ * @return a byte array that contains the ICC Profile data.
+ */
+ public byte[] getData() {
+ int profileSize = NativeCMM.cmmGetProfileSize(profileHandle);
+ byte[] data = new byte[profileSize];
+ NativeCMM.cmmGetProfile(profileHandle, data);
+ return data;
+ }
+
+ /**
+ * Frees the resources associated with an ICC_Profile object.
+ */
+ @Override
+ protected void finalize() {
+ if (profileHandle!=0 && !handleStolen) {
+ NativeCMM.cmmCloseProfile(profileHandle);
+ }
+
+ // Always remove because key no more exist
+ // when object is destroyed
+ NativeCMM.removeHandle(this);
+ }
+
+ /**
+ * Gets the profile class.
+ *
+ * @return the profile class constant.
+ */
+ public int getProfileClass() {
+ int deviceClassSignature = getIntFromHeader(icHdrDeviceClass);
+
+ switch (deviceClassSignature) {
+ case icSigColorSpaceClass:
+ return CLASS_COLORSPACECONVERSION;
+ case icSigDisplayClass:
+ return CLASS_DISPLAY;
+ case icSigOutputClass:
+ return CLASS_OUTPUT;
+ case icSigInputClass:
+ return CLASS_INPUT;
+ case icSigLinkClass:
+ return CLASS_DEVICELINK;
+ case icSigAbstractClass:
+ return CLASS_ABSTRACT;
+ case icSigNamedColorClass:
+ return CLASS_NAMEDCOLOR;
+ default:
+ }
+
+ // Not an ICC profile class
+ // awt.15F=Profile class does not comply with ICC specification
+ throw new IllegalArgumentException(Messages.getString("awt.15F")); //$NON-NLS-1$
+
+ }
+
+ /**
+ * Returns the color space type of the Profile Connection Space (PCS).
+ *
+ * @return the PCS type.
+ */
+ public int getPCSType() {
+ return csFromSignature(getIntFromHeader(icHdrPcs));
+ }
+
+ /**
+ * Gets the number of components of this ICC Profile.
+ *
+ * @return the number of components of this ICC Profile.
+ */
+ public int getNumComponents() {
+ switch (getIntFromHeader(icHdrColorSpace)) {
+ // The most common cases go first to increase speed
+ case icSigRgbData:
+ case icSigXYZData:
+ case icSigLabData:
+ return 3;
+ case icSigCmykData:
+ return 4;
+ // Then all other
+ case icSigGrayData:
+ return 1;
+ case icSigSpace2CLR:
+ return 2;
+ case icSigYCbCrData:
+ case icSigLuvData:
+ case icSigYxyData:
+ case icSigHlsData:
+ case icSigHsvData:
+ case icSigCmyData:
+ case icSigSpace3CLR:
+ return 3;
+ case icSigSpace4CLR:
+ return 4;
+ case icSigSpace5CLR:
+ return 5;
+ case icSigSpace6CLR:
+ return 6;
+ case icSigSpace7CLR:
+ return 7;
+ case icSigSpace8CLR:
+ return 8;
+ case icSigSpace9CLR:
+ return 9;
+ case icSigSpaceACLR:
+ return 10;
+ case icSigSpaceBCLR:
+ return 11;
+ case icSigSpaceCCLR:
+ return 12;
+ case icSigSpaceDCLR:
+ return 13;
+ case icSigSpaceECLR:
+ return 14;
+ case icSigSpaceFCLR:
+ return 15;
+ default:
+ }
+
+ // awt.160=Color space doesn't comply with ICC specification
+ throw new ProfileDataException(Messages.getString("awt.160") //$NON-NLS-1$
+ );
+ }
+
+ /**
+ * Gets the minor version of this ICC profile.
+ *
+ * @return the minor version of this ICC profile.
+ */
+ public int getMinorVersion() {
+ return getByteFromHeader(icHdrVersion+1);
+ }
+
+ /**
+ * Gets the major version of this ICC profile.
+ *
+ * @return the major version of this ICC profile.
+ */
+ public int getMajorVersion() {
+ return getByteFromHeader(icHdrVersion);
+ }
+
+ /**
+ * Gets the color space type of this ICC_Profile.
+ *
+ * @return the color space type.
+ */
+ public int getColorSpaceType() {
+ return csFromSignature(getIntFromHeader(icHdrColorSpace));
+ }
+
+ /**
+ * Tries to open file at the specified path. Path entries can be
+ * divided by a separator character.
+ *
+ * @param path the path
+ * @param fileName the file name
+ *
+ * @return the file input stream
+ */
+ private static FileInputStream tryPath(String path, String fileName) {
+ FileInputStream fiStream = null;
+
+ if (path == null) {
+ return null;
+ }
+
+ StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
+
+ while (st.hasMoreTokens()) {
+ String pathEntry = st.nextToken();
+ try {
+ fiStream = new FileInputStream(pathEntry + File.separatorChar + fileName);
+ if (fiStream != null) {
+ return fiStream;
+ }
+ } catch (FileNotFoundException e) {}
+ }
+
+ return fiStream;
+ }
+
+ /**
+ * Gets the single instance of ICC_Profile from data in the specified file.
+ *
+ * @param fileName the specified name of file with ICC profile data.
+ *
+ * @return single instance of ICC_Profile.
+ *
+ * @throws IOException signals that an I/O error occured while reading the file
+ * or the file doesn't exist.
+ */
+ public static ICC_Profile getInstance(String fileName) throws IOException {
+ final String fName = fileName; // to use in the privileged block
+
+ FileInputStream fiStream = (FileInputStream) AccessController.doPrivileged(
+ new PrivilegedAction<FileInputStream>() {
+ public FileInputStream run() {
+ FileInputStream fiStream = null;
+
+ // Open absolute path
+ try {
+ fiStream = new FileInputStream(fName);
+ if (fiStream != null) {
+ return fiStream;
+ }
+ } catch (FileNotFoundException e) {}
+
+ // Check java.iccprofile.path entries
+ fiStream = tryPath(System.getProperty("java.iccprofile.path"), fName); //$NON-NLS-1$
+ if (fiStream != null) {
+ return fiStream;
+ }
+
+ // Check java.class.path entries
+ fiStream = tryPath(System.getProperty("java.class.path"), fName); //$NON-NLS-1$
+ if (fiStream != null) {
+ return fiStream;
+ }
+
+ // Check directory with java sample profiles
+ String home = System.getProperty("java.home"); //$NON-NLS-1$
+ if (home != null) {
+ fiStream = tryPath(
+ home + File.separatorChar +
+ "lib" + File.separatorChar + "cmm", fName //$NON-NLS-1$ //$NON-NLS-2$
+ );
+ }
+
+ return fiStream;
+ }
+ });
+
+ if (fiStream == null) {
+ // awt.161=Unable to open file {0}
+ throw new IOException(Messages.getString("awt.161", fileName)); //$NON-NLS-1$
+ }
+
+ ICC_Profile pf = getInstance(fiStream);
+ fiStream.close();
+ return pf;
+ }
+
+ /**
+ * Gets the single instance of ICC_Profile with data in
+ * the specified InputStream.
+ *
+ * @param s the InputStream with ICC profile data.
+ *
+ * @return single instance of ICC_Profile.
+ *
+ * @throws IOException if an I/O exception has occurred during reading
+ * from InputStream.
+ * @throws IllegalArgumentException if the file does not contain valid
+ * ICC Profile data.
+ */
+ public static ICC_Profile getInstance(InputStream s) throws IOException {
+ byte[] header = new byte[headerSize];
+ // awt.162=Invalid ICC Profile Data
+ String invalidDataMessage = Messages.getString("awt.162"); //$NON-NLS-1$
+
+ // Get header from the input stream
+ if (s.read(header) != headerSize) {
+ throw new IllegalArgumentException(invalidDataMessage);
+ }
+
+ // Check the profile data for consistency
+ if (
+ ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrMagic) !=
+ headerMagicNumber
+ ) {
+ throw new IllegalArgumentException(invalidDataMessage);
+ }
+
+ // Get profile size from header, create an array for profile data
+ int profileSize = ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrSize);
+ byte[] profileData = new byte[profileSize];
+
+ // Copy header into it
+ System.arraycopy(header, 0, profileData, 0, headerSize);
+
+ // Read the profile itself
+ if (
+ s.read(profileData, headerSize, profileSize - headerSize) !=
+ profileSize - headerSize
+ ) {
+ throw new IllegalArgumentException(invalidDataMessage);
+ }
+
+ return getInstance(profileData);
+ }
+
+ /**
+ * Gets the single instance of ICC_Profile from the specified data in
+ * a byte array.
+ *
+ * @param data the byte array of ICC profile.
+ *
+ * @return single instance of ICC_Profile from the specified data in
+ * a byte array.
+ *
+ * @throws IllegalArgumentException if the file does not contain valid
+ * ICC Profile data.
+ */
+ public static ICC_Profile getInstance(byte[] data) {
+ ICC_Profile res = null;
+
+ try {
+ res = new ICC_Profile(data);
+ } catch (CMMException e) {
+ // awt.162=Invalid ICC Profile Data
+ throw new IllegalArgumentException(Messages.getString("awt.162")); //$NON-NLS-1$
+ }
+
+ if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) { //$NON-NLS-1$ //$NON-NLS-2$
+ try {
+ if ( res.getColorSpaceType () == ColorSpace.TYPE_RGB &&
+ res.getDataSize(icSigMediaWhitePointTag) > 0 &&
+ res.getDataSize(icSigRedColorantTag) > 0 &&
+ res.getDataSize(icSigGreenColorantTag) > 0 &&
+ res.getDataSize(icSigBlueColorantTag) > 0 &&
+ res.getDataSize(icSigRedTRCTag) > 0 &&
+ res.getDataSize(icSigGreenTRCTag) > 0 &&
+ res.getDataSize(icSigBlueTRCTag) > 0
+ ) {
+ res = new ICC_ProfileRGB(res.getProfileHandle());
+ } else if ( res.getColorSpaceType () == ColorSpace.TYPE_GRAY &&
+ res.getDataSize(icSigMediaWhitePointTag) > 0 &&
+ res.getDataSize(icSigGrayTRCTag) > 0
+ ) {
+ res = new ICC_ProfileGray (res.getProfileHandle());
+ }
+
+ } catch (CMMException e) { /* return res in this case */ }
+ }
+
+ return res;
+ }
+
+ /**
+ * Gets the single instance of ICC_Profile with the specific color space
+ * defined by the ColorSpace class: CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ,
+ * CS_PYCC, CS_GRAY.
+ *
+ * @param cspace the type of color space defined in the ColorSpace class.
+ *
+ * @return single instance of ICC_Profile.
+ *
+ * @throws IllegalArgumentException is not one of the defined color
+ * space types.
+ */
+ public static ICC_Profile getInstance(int cspace) {
+ try {
+ switch (cspace) {
+
+ case ColorSpace.CS_sRGB:
+ if (sRGBProfile == null) {
+ sRGBProfile = getInstance("sRGB.pf"); //$NON-NLS-1$
+ }
+ return sRGBProfile;
+
+ case ColorSpace.CS_CIEXYZ:
+ if (xyzProfile == null) {
+ xyzProfile = getInstance("CIEXYZ.pf"); //$NON-NLS-1$
+ }
+ return xyzProfile;
+
+ case ColorSpace.CS_GRAY:
+ if (grayProfile == null) {
+ grayProfile = getInstance("GRAY.pf"); //$NON-NLS-1$
+ }
+ return grayProfile;
+
+ case ColorSpace.CS_PYCC:
+ if (pyccProfile == null) {
+ pyccProfile = getInstance("PYCC.pf"); //$NON-NLS-1$
+ }
+ return pyccProfile;
+
+ case ColorSpace.CS_LINEAR_RGB:
+ if (linearRGBProfile == null) {
+ linearRGBProfile = getInstance("LINEAR_RGB.pf"); //$NON-NLS-1$
+ }
+ return linearRGBProfile;
+ }
+
+ } catch (IOException e) {
+ // awt.163=Can't open color profile
+ throw new IllegalArgumentException(Messages.getString("Can't open color profile")); //$NON-NLS-1$
+ }
+
+ // awt.164=Not a predefined color space
+ throw new IllegalArgumentException(Messages.getString("Not a predefined color space")); //$NON-NLS-1$
+ }
+
+ /**
+ * Reads an integer from the profile header at the specified position.
+ *
+ * @param idx - offset in bytes from the beginning of the header
+ *
+ * @return the int from header
+ */
+ private int getIntFromHeader(int idx) {
+ if (headerData == null) {
+ headerData = getData(icSigHead);
+ }
+
+ return ((headerData[idx] & 0xFF) << 24)|
+ ((headerData[idx+1] & 0xFF) << 16)|
+ ((headerData[idx+2] & 0xFF) << 8) |
+ ((headerData[idx+3] & 0xFF));
+ }
+
+ /**
+ * Reads byte from the profile header at the specified position.
+ *
+ * @param idx - offset in bytes from the beginning of the header
+ *
+ * @return the byte from header
+ */
+ private byte getByteFromHeader(int idx) {
+ if (headerData == null) {
+ headerData = getData(icSigHead);
+ }
+
+ return headerData[idx];
+ }
+
+ /**
+ * Converts ICC color space signature to the java predefined
+ * color space type.
+ *
+ * @param signature the signature
+ *
+ * @return the int
+ */
+ private int csFromSignature(int signature) {
+ switch (signature) {
+ case icSigRgbData:
+ return ColorSpace.TYPE_RGB;
+ case icSigXYZData:
+ return ColorSpace.TYPE_XYZ;
+ case icSigCmykData:
+ return ColorSpace.TYPE_CMYK;
+ case icSigLabData:
+ return ColorSpace.TYPE_Lab;
+ case icSigGrayData:
+ return ColorSpace.TYPE_GRAY;
+ case icSigHlsData:
+ return ColorSpace.TYPE_HLS;
+ case icSigLuvData:
+ return ColorSpace.TYPE_Luv;
+ case icSigYCbCrData:
+ return ColorSpace.TYPE_YCbCr;
+ case icSigYxyData:
+ return ColorSpace.TYPE_Yxy;
+ case icSigHsvData:
+ return ColorSpace.TYPE_HSV;
+ case icSigCmyData:
+ return ColorSpace.TYPE_CMY;
+ case icSigSpace2CLR:
+ return ColorSpace.TYPE_2CLR;
+ case icSigSpace3CLR:
+ return ColorSpace.TYPE_3CLR;
+ case icSigSpace4CLR:
+ return ColorSpace.TYPE_4CLR;
+ case icSigSpace5CLR:
+ return ColorSpace.TYPE_5CLR;
+ case icSigSpace6CLR:
+ return ColorSpace.TYPE_6CLR;
+ case icSigSpace7CLR:
+ return ColorSpace.TYPE_7CLR;
+ case icSigSpace8CLR:
+ return ColorSpace.TYPE_8CLR;
+ case icSigSpace9CLR:
+ return ColorSpace.TYPE_9CLR;
+ case icSigSpaceACLR:
+ return ColorSpace.TYPE_ACLR;
+ case icSigSpaceBCLR:
+ return ColorSpace.TYPE_BCLR;
+ case icSigSpaceCCLR:
+ return ColorSpace.TYPE_CCLR;
+ case icSigSpaceDCLR:
+ return ColorSpace.TYPE_DCLR;
+ case icSigSpaceECLR:
+ return ColorSpace.TYPE_ECLR;
+ case icSigSpaceFCLR:
+ return ColorSpace.TYPE_FCLR;
+ default:
+ }
+
+ // awt.165=Color space doesn't comply with ICC specification
+ throw new IllegalArgumentException (Messages.getString("awt.165")); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the profile handle.
+ *
+ * @return the profile handle
+ */
+ private long getProfileHandle() {
+ handleStolen = true;
+ return profileHandle;
+ }
+
+ /**
+ * Gets the data size.
+ *
+ * @param tagSignature the tag signature
+ *
+ * @return the data size
+ */
+ private int getDataSize(int tagSignature) {
+ return NativeCMM.cmmGetProfileElementSize(
+ profileHandle,
+ tagSignature
+ );
+ }
+
+ /**
+ * Reads XYZ value from the tag data.
+ *
+ * @param tagSignature the tag signature
+ *
+ * @return the XYZ value
+ */
+ float[] getXYZValue(int tagSignature) {
+ float[] res = new float[3];
+ byte[] data = getData(tagSignature);
+
+ // Convert from ICC s15Fixed16Number type
+ // 1 (float) = 0x10000 (s15Fixed16Number),
+ // hence dividing by 0x10000
+ res[0] = ICC_ProfileHelper.getIntFromByteArray(data, 0) / 65536.f;
+ res[1] = ICC_ProfileHelper.getIntFromByteArray(data, 4) / 65536.f;
+ res[2] = ICC_ProfileHelper.getIntFromByteArray(data, 8) / 65536.f;
+
+ return res;
+ }
+
+ /**
+ * Gets the media white point.
+ *
+ * @return the media white point
+ */
+ float[] getMediaWhitePoint() {
+ return getXYZValue(icSigMediaWhitePointTag);
+ }
+
+ /**
+ * If TRC is not a table returns gamma via return value
+ * and sets dataTRC to null. If TRC is a table returns 0
+ * and fills dataTRC with values.
+ *
+ * @param tagSignature the tag signature
+ * @param dataTRC the data trc
+ *
+ * @return - gamma or zero if TRC is a table
+ */
+ private float getGammaOrTRC(int tagSignature, short[] dataTRC) {
+ byte[] data = getData(tagSignature);
+ int trcSize = ICC_ProfileHelper.getIntFromByteArray(data, icCurveCount);
+
+ dataTRC = null;
+
+ if (trcSize == 0) {
+ return 1.0f;
+ }
+
+ if (trcSize == 1) {
+ // Cast from ICC u8Fixed8Number to float
+ return ICC_ProfileHelper.getShortFromByteArray(data, icCurveData) / 256.f;
+ }
+
+ // TRC is a table
+ dataTRC = new short[trcSize];
+ for (int i = 0, pos = icCurveData; i < trcSize; i++, pos += 2) {
+ dataTRC[i] = ICC_ProfileHelper.getShortFromByteArray(data, pos);
+ }
+ return 0;
+ }
+
+ /**
+ * Gets the gamma.
+ *
+ * @param tagSignature the tag signature
+ *
+ * @return the gamma
+ */
+ float getGamma(int tagSignature) {
+ short[] dataTRC = null;
+ float gamma = getGammaOrTRC(tagSignature, dataTRC);
+
+ if (dataTRC == null) {
+ return gamma;
+ }
+ // awt.166=TRC is not a simple gamma value.
+ throw new ProfileDataException(Messages.getString("awt.166")); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the tRC.
+ *
+ * @param tagSignature the tag signature
+ *
+ * @return the tRC
+ */
+ short[] getTRC(int tagSignature) {
+ short[] dataTRC = null;
+ getGammaOrTRC(tagSignature, dataTRC);
+
+ if (dataTRC == null) {
+ // awt.167=TRC is a gamma value, not a table.
+ throw new ProfileDataException(Messages.getString("awt.167")); //$NON-NLS-1$
+ }
+ return dataTRC;
+ }
+}
+
diff --git a/awt/java/awt/color/ICC_ProfileGray.java b/awt/java/awt/color/ICC_ProfileGray.java
new file mode 100644
index 0000000..f009b18
--- /dev/null
+++ b/awt/java/awt/color/ICC_ProfileGray.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+/**
+ * The ICC_ProfileGray class represent profiles with TYPE_GRAY color space type,
+ * and includes the grayTRCTag and mediaWhitePointTag tags.
+ *
+ * The gray component can be transformed from a GRAY device profile color space
+ * to the CIEXYZ Profile through the tone reproduction curve (TRC):
+ * <p>PCSY = grayTRC[deviceGray]
+ */
+public class ICC_ProfileGray extends ICC_Profile {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -1124721290732002649L;
+
+ /**
+ * Instantiates a new iC c_ profile gray.
+ *
+ * @param profileHandle the profile handle
+ */
+ ICC_ProfileGray(long profileHandle) {
+ super(profileHandle);
+ }
+
+ /**
+ * Gets the TRC as an array of shorts.
+ *
+ * @return a short array of the TRC.
+ */
+ public short[] getTRC() {
+ return super.getTRC(icSigGrayTRCTag);
+ }
+
+ @Override
+ public float[] getMediaWhitePoint() {
+ return super.getMediaWhitePoint();
+ }
+
+ /**
+ * Gets a gamma value representing the tone reproduction curve (TRC).
+ *
+ * @return the gamma value representing the tone reproduction curve (TRC).
+ */
+ public float getGamma() {
+ return super.getGamma(icSigGrayTRCTag);
+ }
+}
+
diff --git a/awt/java/awt/color/ICC_ProfileRGB.java b/awt/java/awt/color/ICC_ProfileRGB.java
new file mode 100644
index 0000000..beb1a0c
--- /dev/null
+++ b/awt/java/awt/color/ICC_ProfileRGB.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ICC_ProfileRGB class represents profiles with RGB color space type and
+ * contains the redColorantTag, greenColorantTag, blueColorantTag, redTRCTag,
+ * greenTRCTag, blueTRCTag, and mediaWhitePointTag tags.
+ */
+public class ICC_ProfileRGB extends ICC_Profile {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 8505067385152579334L;
+
+ /**
+ * Instantiates a new iC c_ profile rgb.
+ *
+ * @param profileHandle the profile handle
+ */
+ ICC_ProfileRGB(long profileHandle) {
+ super(profileHandle);
+ }
+
+ /** The Constant REDCOMPONENT indicates the red component. */
+ public static final int REDCOMPONENT = 0;
+
+ /** The Constant GREENCOMPONENT indicates the green component. */
+ public static final int GREENCOMPONENT = 1;
+
+ /** The Constant BLUECOMPONENT indicates the blue component. */
+ public static final int BLUECOMPONENT = 2;
+
+ // awt.15E=Unknown component. Must be REDCOMPONENT, GREENCOMPONENT or BLUECOMPONENT.
+ /** The Constant UNKNOWN_COMPONENT_MSG. */
+ private static final String UNKNOWN_COMPONENT_MSG = Messages
+ .getString("awt.15E"); //$NON-NLS-1$
+
+ @Override
+ public short[] getTRC(int component) {
+ switch (component) {
+ case REDCOMPONENT:
+ return super.getTRC(icSigRedTRCTag);
+ case GREENCOMPONENT:
+ return super.getTRC(icSigGreenTRCTag);
+ case BLUECOMPONENT:
+ return super.getTRC(icSigBlueTRCTag);
+ default:
+ }
+
+ throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG);
+ }
+
+ @Override
+ public float getGamma(int component) {
+ switch (component) {
+ case REDCOMPONENT:
+ return super.getGamma(icSigRedTRCTag);
+ case GREENCOMPONENT:
+ return super.getGamma(icSigGreenTRCTag);
+ case BLUECOMPONENT:
+ return super.getGamma(icSigBlueTRCTag);
+ default:
+ }
+
+ throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG);
+ }
+
+ /**
+ * Gets a float matrix which contains the X, Y, and Z components of
+ * the profile's redColorantTag, greenColorantTag, and blueColorantTag.
+ *
+ * @return a float matrix which contains the X, Y, and Z components of
+ * the profile's redColorantTag, greenColorantTag, and blueColorantTag.
+ */
+ public float[][] getMatrix() {
+ float [][] m = new float[3][3]; // The matrix
+
+ float[] redXYZ = getXYZValue(icSigRedColorantTag);
+ float[] greenXYZ = getXYZValue(icSigGreenColorantTag);
+ float[] blueXYZ = getXYZValue(icSigBlueColorantTag);
+
+ m[0][0] = redXYZ[0];
+ m[1][0] = redXYZ[1];
+ m[2][0] = redXYZ[2];
+
+ m[0][1] = greenXYZ[0];
+ m[1][1] = greenXYZ[1];
+ m[2][1] = greenXYZ[2];
+
+ m[0][2] = blueXYZ[0];
+ m[1][2] = blueXYZ[1];
+ m[2][2] = blueXYZ[2];
+
+ return m;
+ }
+
+ @Override
+ public float[] getMediaWhitePoint() {
+ return super.getMediaWhitePoint();
+ }
+}
+
diff --git a/awt/java/awt/color/ICC_ProfileStub.java b/awt/java/awt/color/ICC_ProfileStub.java
new file mode 100644
index 0000000..bc04c8a
--- /dev/null
+++ b/awt/java/awt/color/ICC_ProfileStub.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.color;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectStreamException;
+import java.io.OutputStream;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+final class ICC_ProfileStub extends ICC_Profile {
+ private static final long serialVersionUID = 501389760875253507L;
+
+ transient int colorspace;
+
+ public ICC_ProfileStub(int csSpecifier) {
+ switch (csSpecifier) {
+ case ColorSpace.CS_sRGB:
+ case ColorSpace.CS_CIEXYZ:
+ case ColorSpace.CS_LINEAR_RGB:
+ case ColorSpace.CS_PYCC:
+ case ColorSpace.CS_GRAY:
+ break;
+ default:
+ // awt.15D=Invalid colorspace
+ throw new IllegalArgumentException(Messages.getString("awt.15D")); //$NON-NLS-1$
+ }
+ colorspace = csSpecifier;
+ }
+
+ @Override
+ public void write(String fileName) throws IOException {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ /**
+ * Serializable implementation
+ *
+ * @throws ObjectStreamException
+ */
+ private Object writeReplace() throws ObjectStreamException {
+ return loadProfile();
+ }
+
+ @Override
+ public void write(OutputStream s) throws IOException {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public void setData(int tagSignature, byte[] tagData) {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public byte[] getData(int tagSignature) {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public byte[] getData() {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ protected void finalize() {
+ }
+
+ @Override
+ public int getProfileClass() {
+ return CLASS_COLORSPACECONVERSION;
+ }
+
+ @Override
+ public int getPCSType() {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public int getNumComponents() {
+ switch (colorspace) {
+ case ColorSpace.CS_sRGB:
+ case ColorSpace.CS_CIEXYZ:
+ case ColorSpace.CS_LINEAR_RGB:
+ case ColorSpace.CS_PYCC:
+ return 3;
+ case ColorSpace.CS_GRAY:
+ return 1;
+ default:
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public int getMinorVersion() {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public int getMajorVersion() {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ @Override
+ public int getColorSpaceType() {
+ switch (colorspace) {
+ case ColorSpace.CS_sRGB:
+ case ColorSpace.CS_LINEAR_RGB:
+ return ColorSpace.TYPE_RGB;
+ case ColorSpace.CS_CIEXYZ:
+ return ColorSpace.TYPE_XYZ;
+ case ColorSpace.CS_PYCC:
+ return ColorSpace.TYPE_3CLR;
+ case ColorSpace.CS_GRAY:
+ return ColorSpace.TYPE_GRAY;
+ default:
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+ }
+
+ public static ICC_Profile getInstance(String fileName) throws IOException {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ public static ICC_Profile getInstance(InputStream s) throws IOException {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ public static ICC_Profile getInstance(byte[] data) {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ public static ICC_Profile getInstance(int cspace) {
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+
+ public ICC_Profile loadProfile() {
+ switch (colorspace) {
+ case ColorSpace.CS_sRGB:
+ return ICC_Profile.getInstance(ColorSpace.CS_sRGB);
+ case ColorSpace.CS_GRAY:
+ return ICC_Profile.getInstance(ColorSpace.CS_GRAY);
+ case ColorSpace.CS_CIEXYZ:
+ return ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ);
+ case ColorSpace.CS_LINEAR_RGB:
+ return ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB);
+ case ColorSpace.CS_PYCC:
+ return ICC_Profile.getInstance(ColorSpace.CS_PYCC);
+ default:
+ throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$
+ }
+ }
+} \ No newline at end of file
diff --git a/awt/java/awt/color/ProfileDataException.java b/awt/java/awt/color/ProfileDataException.java
new file mode 100644
index 0000000..ca169fe
--- /dev/null
+++ b/awt/java/awt/color/ProfileDataException.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.color;
+
+/**
+ * The ProfileDataException class represents an error which occurs
+ * while accessing or processing an ICC_Profile object.
+ */
+public class ProfileDataException extends RuntimeException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 7286140888240322498L;
+
+ /**
+ * Instantiates a new profile data exception with detailed message.
+ *
+ * @param s the detailed message.
+ */
+ public ProfileDataException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/awt/java/awt/event/AWTEventListener.java b/awt/java/awt/event/AWTEventListener.java
new file mode 100644
index 0000000..f621c9b
--- /dev/null
+++ b/awt/java/awt/event/AWTEventListener.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.util.EventListener;
+
+public interface AWTEventListener extends EventListener {
+
+ public void eventDispatched(AWTEvent event);
+
+}
diff --git a/awt/java/awt/event/AWTEventListenerProxy.java b/awt/java/awt/event/AWTEventListenerProxy.java
new file mode 100644
index 0000000..5ee5e59
--- /dev/null
+++ b/awt/java/awt/event/AWTEventListenerProxy.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+
+import java.util.EventListenerProxy;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class AWTEventListenerProxy extends EventListenerProxy implements AWTEventListener {
+
+ private AWTEventListener listener;
+ private long eventMask;
+
+ public AWTEventListenerProxy(long eventMask, AWTEventListener listener) {
+ super(listener);
+
+ // awt.193=Listener can't be zero
+ assert listener != null : Messages.getString("awt.193"); //$NON-NLS-1$
+
+ this.listener = listener;
+ this.eventMask = eventMask;
+ }
+
+ public void eventDispatched(AWTEvent evt) {
+ listener.eventDispatched(evt);
+ }
+
+ public long getEventMask() {
+ return eventMask;
+ }
+
+}
diff --git a/awt/java/awt/event/ActionEvent.java b/awt/java/awt/event/ActionEvent.java
new file mode 100644
index 0000000..c32fc4b
--- /dev/null
+++ b/awt/java/awt/event/ActionEvent.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+
+public class ActionEvent extends AWTEvent {
+
+ private static final long serialVersionUID = -7671078796273832149L;
+
+ public static final int SHIFT_MASK = 1;
+
+ public static final int CTRL_MASK = 2;
+
+ public static final int META_MASK = 4;
+
+ public static final int ALT_MASK = 8;
+
+ public static final int ACTION_FIRST = 1001;
+
+ public static final int ACTION_LAST = 1001;
+
+ public static final int ACTION_PERFORMED = 1001;
+
+ private long when;
+ private int modifiers;
+ private String command;
+
+ public ActionEvent(Object source, int id, String command) {
+ this(source, id, command, 0);
+ }
+
+ public ActionEvent(Object source, int id, String command, int modifiers) {
+ this(source, id, command, 0l, modifiers);
+ }
+
+ public ActionEvent(Object source, int id, String command, long when, int modifiers) {
+ super(source, id);
+
+ this.command = command;
+ this.when = when;
+ this.modifiers = modifiers;
+ }
+
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ public String getActionCommand() {
+ return command;
+ }
+
+ public long getWhen() {
+ return when;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * ActionEvent e = new ActionEvent(new Component(){},
+ * ActionEvent.ACTION_PERFORMED, "Command",
+ * ActionEvent.SHIFT_MASK|ActionEvent.CTRL_MASK|
+ * ActionEvent.META_MASK|ActionEvent.ALT_MASK);
+ * System.out.println(e);
+ */
+
+ String idString = (id == ACTION_PERFORMED) ?
+ "ACTION_PERFORMED" : "unknown type"; //$NON-NLS-1$ //$NON-NLS-2$
+ String modifiersString = ""; //$NON-NLS-1$
+
+ if ((modifiers & SHIFT_MASK) > 0) {
+ modifiersString += "Shift"; //$NON-NLS-1$
+ }
+ if ((modifiers & CTRL_MASK) > 0) {
+ modifiersString += modifiersString.length() == 0 ? "Ctrl" : "+Ctrl"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiers & META_MASK) > 0) {
+ modifiersString += modifiersString.length() == 0 ? "Meta" : "+Meta"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiers & ALT_MASK) > 0) {
+ modifiersString += modifiersString.length() == 0 ? "Alt" : "+Alt"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ return (idString + ",cmd=" + command + ",when=" + when + //$NON-NLS-1$ //$NON-NLS-2$
+ ",modifiers=" + modifiersString); //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/ActionListener.java b/awt/java/awt/event/ActionListener.java
new file mode 100644
index 0000000..473d2b6
--- /dev/null
+++ b/awt/java/awt/event/ActionListener.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface ActionListener extends EventListener {
+
+ public void actionPerformed(ActionEvent e);
+
+}
diff --git a/awt/java/awt/event/AdjustmentEvent.java b/awt/java/awt/event/AdjustmentEvent.java
new file mode 100644
index 0000000..a2b11a8
--- /dev/null
+++ b/awt/java/awt/event/AdjustmentEvent.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Adjustable;
+
+public class AdjustmentEvent extends AWTEvent {
+
+ private static final long serialVersionUID = 5700290645205279921L;
+
+ public static final int ADJUSTMENT_FIRST = 601;
+
+ public static final int ADJUSTMENT_LAST = 601;
+
+ public static final int ADJUSTMENT_VALUE_CHANGED = 601;
+
+ public static final int UNIT_INCREMENT = 1;
+
+ public static final int UNIT_DECREMENT = 2;
+
+ public static final int BLOCK_DECREMENT = 3;
+
+ public static final int BLOCK_INCREMENT = 4;
+
+ public static final int TRACK = 5;
+
+ private int type;
+ private int value;
+ private boolean isAdjusting;
+
+ public AdjustmentEvent(Adjustable source, int id, int type, int value) {
+ this(source, id, type, value, false);
+ }
+
+ public AdjustmentEvent(Adjustable source, int id, int type, int value,
+ boolean isAdjusting) {
+ super(source, id);
+ this.type = type;
+ this.value = value;
+ this.isAdjusting = isAdjusting;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public int getAdjustmentType() {
+ return type;
+ }
+
+ public boolean getValueIsAdjusting() {
+ return isAdjusting;
+ }
+
+ public Adjustable getAdjustable() {
+ return (Adjustable) source;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * AdjustmentEvent e = new AdjustmentEvent(new Scrollbar(),
+ * AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED,
+ * AdjustmentEvent.UNIT_INCREMENT, 1);
+ * System.out.println(e);
+ */
+
+ String idString = (id == ADJUSTMENT_VALUE_CHANGED ?
+ "ADJUSTMENT_VALUE_CHANGED" : "unknown type"); //$NON-NLS-1$ //$NON-NLS-2$
+ String adjType = null;
+
+ switch (type) {
+ case UNIT_INCREMENT:
+ adjType = "UNIT_INCREMENT"; //$NON-NLS-1$
+ break;
+ case UNIT_DECREMENT:
+ adjType = "UNIT_DECREMENT"; //$NON-NLS-1$
+ break;
+ case BLOCK_INCREMENT:
+ adjType = "BLOCK_INCREMENT"; //$NON-NLS-1$
+ break;
+ case BLOCK_DECREMENT:
+ adjType = "BLOCK_DECREMENT"; //$NON-NLS-1$
+ break;
+ case TRACK:
+ adjType = "TRACK"; //$NON-NLS-1$
+ break;
+ default:
+ adjType = "unknown type"; //$NON-NLS-1$
+ }
+
+ return (idString + ",adjType=" + adjType + ",value=" + value + //$NON-NLS-1$ //$NON-NLS-2$
+ ",isAdjusting=" + isAdjusting); //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/AdjustmentListener.java b/awt/java/awt/event/AdjustmentListener.java
new file mode 100644
index 0000000..ef7c378
--- /dev/null
+++ b/awt/java/awt/event/AdjustmentListener.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface AdjustmentListener extends EventListener {
+
+ public void adjustmentValueChanged(AdjustmentEvent e);
+
+}
diff --git a/awt/java/awt/event/ComponentAdapter.java b/awt/java/awt/event/ComponentAdapter.java
new file mode 100644
index 0000000..4f0bd90
--- /dev/null
+++ b/awt/java/awt/event/ComponentAdapter.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class ComponentAdapter implements ComponentListener {
+
+ public ComponentAdapter() {
+ }
+
+ public void componentHidden(ComponentEvent e) {
+ }
+
+ public void componentMoved(ComponentEvent e) {
+ }
+
+ public void componentResized(ComponentEvent e) {
+ }
+
+ public void componentShown(ComponentEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/ComponentEvent.java b/awt/java/awt/event/ComponentEvent.java
new file mode 100644
index 0000000..d0bca54
--- /dev/null
+++ b/awt/java/awt/event/ComponentEvent.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+
+public class ComponentEvent extends AWTEvent {
+
+ private static final long serialVersionUID = 8101406823902992965L;
+
+ public static final int COMPONENT_FIRST = 100;
+
+ public static final int COMPONENT_LAST = 103;
+
+ public static final int COMPONENT_MOVED = 100;
+
+ public static final int COMPONENT_RESIZED = 101;
+
+ public static final int COMPONENT_SHOWN = 102;
+
+ public static final int COMPONENT_HIDDEN = 103;
+
+ public ComponentEvent(Component source, int id) {
+ super(source, id);
+ }
+
+ public Component getComponent() {
+ return (Component) source;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * ComponentEvent e = new ComponentEvent(new Button("Button"),
+ * ComponentEvent.COMPONENT_SHOWN);
+ * System.out.println(e);
+ */
+
+ String idString = null;
+ Component c = getComponent();
+
+ switch (id) {
+ case COMPONENT_MOVED:
+ idString = "COMPONENT_MOVED"; //$NON-NLS-1$
+ break;
+ case COMPONENT_RESIZED:
+ idString = "COMPONENT_RESIZED"; //$NON-NLS-1$
+ break;
+ case COMPONENT_SHOWN:
+ return "COMPONENT_SHOWN"; //$NON-NLS-1$
+ case COMPONENT_HIDDEN:
+ return "COMPONENT_HIDDEN"; //$NON-NLS-1$
+ default:
+ return "unknown type"; //$NON-NLS-1$
+ }
+
+ return (idString + " (" + c.getX() + "," + c.getY() + //$NON-NLS-1$ //$NON-NLS-2$
+ " " + c.getWidth()+ "x" + c.getHeight() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+}
diff --git a/awt/java/awt/event/ComponentListener.java b/awt/java/awt/event/ComponentListener.java
new file mode 100644
index 0000000..147e9e0
--- /dev/null
+++ b/awt/java/awt/event/ComponentListener.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface ComponentListener extends EventListener {
+
+ public void componentHidden(ComponentEvent e);
+
+ public void componentMoved(ComponentEvent e);
+
+ public void componentResized(ComponentEvent e);
+
+ public void componentShown(ComponentEvent e);
+
+}
diff --git a/awt/java/awt/event/ContainerAdapter.java b/awt/java/awt/event/ContainerAdapter.java
new file mode 100644
index 0000000..12dc3de
--- /dev/null
+++ b/awt/java/awt/event/ContainerAdapter.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class ContainerAdapter implements ContainerListener {
+
+ public ContainerAdapter() {
+ }
+
+ public void componentAdded(ContainerEvent e) {
+ }
+
+ public void componentRemoved(ContainerEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/ContainerEvent.java b/awt/java/awt/event/ContainerEvent.java
new file mode 100644
index 0000000..1a1055c
--- /dev/null
+++ b/awt/java/awt/event/ContainerEvent.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+//???AWT: import java.awt.Container;
+
+public class ContainerEvent extends ComponentEvent {
+
+ private static final long serialVersionUID = -4114942250539772041L;
+
+ public static final int CONTAINER_FIRST = 300;
+
+ public static final int CONTAINER_LAST = 301;
+
+ public static final int COMPONENT_ADDED = 300;
+
+ public static final int COMPONENT_REMOVED = 301;
+
+ private Component child;
+
+ public ContainerEvent(Component src, int id, Component child) {
+ super(src, id);
+ this.child = child;
+ }
+
+ public Component getChild() {
+ return child;
+ }
+
+ //???AWT
+ /*
+ public Container getContainer() {
+ return (Container) source;
+ }
+ */
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * ContainerEvent e = new ContainerEvent(new Panel(),
+ * ContainerEvent.COMPONENT_ADDED,
+ * new Button("Button"));
+ * System.out.println(e);
+ */
+
+ String idString = null;
+
+ switch (id) {
+ case COMPONENT_ADDED:
+ idString = "COMPONENT_ADDED"; //$NON-NLS-1$
+ break;
+ case COMPONENT_REMOVED:
+ idString = "COMPONENT_REMOVED"; //$NON-NLS-1$
+ break;
+ default:
+ idString = "unknown type"; //$NON-NLS-1$
+ }
+
+ return (idString + ",child=" + child.getName()); //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/ContainerListener.java b/awt/java/awt/event/ContainerListener.java
new file mode 100644
index 0000000..bf47664
--- /dev/null
+++ b/awt/java/awt/event/ContainerListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface ContainerListener extends EventListener {
+
+ public void componentAdded(ContainerEvent e);
+
+ public void componentRemoved(ContainerEvent e);
+
+}
diff --git a/awt/java/awt/event/FocusAdapter.java b/awt/java/awt/event/FocusAdapter.java
new file mode 100644
index 0000000..3489e11
--- /dev/null
+++ b/awt/java/awt/event/FocusAdapter.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class FocusAdapter implements FocusListener {
+
+ public FocusAdapter() {
+ }
+
+ public void focusGained(FocusEvent e) {
+ }
+
+ public void focusLost(FocusEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/FocusEvent.java b/awt/java/awt/event/FocusEvent.java
new file mode 100644
index 0000000..1db5263
--- /dev/null
+++ b/awt/java/awt/event/FocusEvent.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+
+public class FocusEvent extends ComponentEvent {
+
+ private static final long serialVersionUID = 523753786457416396L;
+
+ public static final int FOCUS_FIRST = 1004;
+
+ public static final int FOCUS_LAST = 1005;
+
+ public static final int FOCUS_GAINED = 1004;
+
+ public static final int FOCUS_LOST = 1005;
+
+ private boolean temporary;
+ private Component opposite;
+
+ public FocusEvent(Component source, int id) {
+ this(source, id, false);
+ }
+
+ public FocusEvent(Component source, int id, boolean temporary) {
+ this(source, id, temporary, null);
+ }
+
+ public FocusEvent(Component source, int id, boolean temporary, Component opposite) {
+ super(source, id);
+ this.temporary = temporary;
+ this.opposite = opposite;
+ }
+
+ public Component getOppositeComponent() {
+ return opposite;
+ }
+
+ public boolean isTemporary() {
+ return temporary;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * FocusEvent e = new FocusEvent(new Button("Button0"),
+ * FocusEvent.FOCUS_GAINED, false, new Button("Button1"));
+ * System.out.println(e);
+ */
+
+ String idString = null;
+
+ switch (id) {
+ case FOCUS_GAINED:
+ idString = "FOCUS_GAINED"; //$NON-NLS-1$
+ break;
+ case FOCUS_LOST:
+ idString = "FOCUS_LOST"; //$NON-NLS-1$
+ break;
+ default:
+ idString = "unknown type"; //$NON-NLS-1$
+ }
+
+ return (idString +
+ (temporary ? ",temporary" : ",permanent") + //$NON-NLS-1$ //$NON-NLS-2$
+ ",opposite=" + opposite); //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/FocusListener.java b/awt/java/awt/event/FocusListener.java
new file mode 100644
index 0000000..ee98d90
--- /dev/null
+++ b/awt/java/awt/event/FocusListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface FocusListener extends EventListener {
+
+ public void focusGained(FocusEvent e);
+
+ public void focusLost(FocusEvent e);
+
+}
diff --git a/awt/java/awt/event/HierarchyBoundsAdapter.java b/awt/java/awt/event/HierarchyBoundsAdapter.java
new file mode 100644
index 0000000..24e3d9d
--- /dev/null
+++ b/awt/java/awt/event/HierarchyBoundsAdapter.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class HierarchyBoundsAdapter implements HierarchyBoundsListener {
+
+ public HierarchyBoundsAdapter() {
+ }
+
+ public void ancestorMoved(HierarchyEvent e) {
+ }
+
+ public void ancestorResized(HierarchyEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/HierarchyBoundsListener.java b/awt/java/awt/event/HierarchyBoundsListener.java
new file mode 100644
index 0000000..4288f52
--- /dev/null
+++ b/awt/java/awt/event/HierarchyBoundsListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface HierarchyBoundsListener extends EventListener {
+
+ public void ancestorMoved(HierarchyEvent e);
+
+ public void ancestorResized(HierarchyEvent e);
+
+}
diff --git a/awt/java/awt/event/HierarchyEvent.java b/awt/java/awt/event/HierarchyEvent.java
new file mode 100644
index 0000000..1881667
--- /dev/null
+++ b/awt/java/awt/event/HierarchyEvent.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+//???AWT: import java.awt.Container;
+
+public class HierarchyEvent extends AWTEvent {
+
+ private static final long serialVersionUID = -5337576970038043990L;
+
+ public static final int HIERARCHY_FIRST = 1400;
+
+ public static final int HIERARCHY_CHANGED = 1400;
+
+ public static final int ANCESTOR_MOVED = 1401;
+
+ public static final int ANCESTOR_RESIZED = 1402;
+
+ public static final int HIERARCHY_LAST = 1402;
+
+ public static final int PARENT_CHANGED = 1;
+
+ public static final int DISPLAYABILITY_CHANGED = 2;
+
+ public static final int SHOWING_CHANGED = 4;
+
+ //???AWT: private Container changedParent;
+ private Component changed;
+ private long changeFlag;
+
+ //???AWT
+ /*
+ public HierarchyEvent(Component source, int id, Component changed,
+ Container changedParent) {
+ this(source, id, changed, changedParent, 0l);
+ }
+ */
+
+ //???AWT
+ /*
+ public HierarchyEvent(Component source, int id, Component changed,
+ Container changedParent, long changeFlags) {
+ super(source, id);
+
+ this.changed = changed;
+ this.changedParent = changedParent;
+ this.changeFlag = changeFlags;
+ }
+ */
+ //???AWT: Fake constructor, should be as above.
+ public HierarchyEvent(Component source, int id, Component changed,
+ Object changedParent, long changeFlags) {
+ super(source, id);
+
+// this.changed = changed;
+// this.changedParent = changedParent;
+// this.changeFlag = changeFlags;
+ }
+
+ public Component getComponent() {
+ return (Component) source;
+ }
+
+ public long getChangeFlags() {
+ return changeFlag;
+ }
+
+ public Component getChanged() {
+ return changed;
+ }
+
+ //???AWT
+ /*
+ public Container getChangedParent() {
+ return changedParent;
+
+ }
+ */
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * HierarchyEvent e = new HierarchyEvent(new Button("Button"),
+ * HierarchyEvent.HIERARCHY_CHANGED,
+ * new Panel(), new Container());
+ * System.out.println(e);
+ */
+ String paramString = null;
+
+ switch (id) {
+ case HIERARCHY_CHANGED:
+ paramString = "HIERARCHY_CHANGED"; //$NON-NLS-1$
+ break;
+ case ANCESTOR_MOVED:
+ paramString = "ANCESTOR_MOVED"; //$NON-NLS-1$
+ break;
+ case ANCESTOR_RESIZED:
+ paramString = "ANCESTOR_RESIZED"; //$NON-NLS-1$
+ break;
+ default:
+ paramString = "unknown type"; //$NON-NLS-1$
+ }
+
+ paramString += " ("; //$NON-NLS-1$
+
+ if (id == HIERARCHY_CHANGED) {
+ if ((changeFlag & PARENT_CHANGED) > 0) {
+ paramString += "PARENT_CHANGED,"; //$NON-NLS-1$
+ }
+ if ((changeFlag & DISPLAYABILITY_CHANGED) > 0) {
+ paramString += "DISPLAYABILITY_CHANGED,"; //$NON-NLS-1$
+ }
+ if ((changeFlag & SHOWING_CHANGED) > 0) {
+ paramString += "SHOWING_CHANGED,"; //$NON-NLS-1$
+ }
+ }
+
+ //???AWT
+ /*
+ return paramString + "changed=" + changed + //$NON-NLS-1$
+ ",changedParent=" + changedParent + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ */
+ return paramString;
+ }
+
+}
diff --git a/awt/java/awt/event/HierarchyListener.java b/awt/java/awt/event/HierarchyListener.java
new file mode 100644
index 0000000..e01ba11
--- /dev/null
+++ b/awt/java/awt/event/HierarchyListener.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface HierarchyListener extends EventListener {
+
+ public void hierarchyChanged(HierarchyEvent e);
+
+}
diff --git a/awt/java/awt/event/InputEvent.java b/awt/java/awt/event/InputEvent.java
new file mode 100644
index 0000000..c98382d
--- /dev/null
+++ b/awt/java/awt/event/InputEvent.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+
+public abstract class InputEvent extends ComponentEvent {
+
+ private static final long serialVersionUID = -2482525981698309786L;
+
+ public static final int SHIFT_MASK = 1;
+
+ public static final int CTRL_MASK = 2;
+
+ public static final int META_MASK = 4;
+
+ public static final int ALT_MASK = 8;
+
+ public static final int ALT_GRAPH_MASK = 32;
+
+ public static final int BUTTON1_MASK = 16;
+
+ public static final int BUTTON2_MASK = 8;
+
+ public static final int BUTTON3_MASK = 4;
+
+ public static final int SHIFT_DOWN_MASK = 64;
+
+ public static final int CTRL_DOWN_MASK = 128;
+
+ public static final int META_DOWN_MASK = 256;
+
+ public static final int ALT_DOWN_MASK = 512;
+
+ public static final int BUTTON1_DOWN_MASK = 1024;
+
+ public static final int BUTTON2_DOWN_MASK = 2048;
+
+ public static final int BUTTON3_DOWN_MASK = 4096;
+
+ public static final int ALT_GRAPH_DOWN_MASK = 8192;
+
+ private static final int DOWN_MASKS = SHIFT_DOWN_MASK | CTRL_DOWN_MASK |
+ META_DOWN_MASK | ALT_DOWN_MASK | BUTTON1_DOWN_MASK |
+ BUTTON2_DOWN_MASK | BUTTON3_DOWN_MASK | ALT_GRAPH_DOWN_MASK;
+
+ private long when;
+ private int modifiersEx;
+
+ public static String getModifiersExText(int modifiers/*Ex*/) {
+ return MouseEvent.addMouseModifiersExText(
+ KeyEvent.getKeyModifiersExText(modifiers), modifiers);
+ }
+
+ static int extractExFlags(int modifiers) {
+ int exFlags = modifiers & DOWN_MASKS;
+
+ if ((modifiers & SHIFT_MASK) != 0) {
+ exFlags |= SHIFT_DOWN_MASK;
+ }
+ if ((modifiers & CTRL_MASK) != 0) {
+ exFlags |= CTRL_DOWN_MASK;
+ }
+ if ((modifiers & META_MASK) != 0) {
+ exFlags |= META_DOWN_MASK;
+ }
+ if ((modifiers & ALT_MASK) != 0) {
+ exFlags |= ALT_DOWN_MASK;
+ }
+ if ((modifiers & ALT_GRAPH_MASK) != 0) {
+ exFlags |= ALT_GRAPH_DOWN_MASK;
+ }
+ if ((modifiers & BUTTON1_MASK) != 0) {
+ exFlags |= BUTTON1_DOWN_MASK;
+ }
+ if ((modifiers & BUTTON2_MASK) != 0) {
+ exFlags |= BUTTON2_DOWN_MASK;
+ }
+ if ((modifiers & BUTTON3_MASK) != 0) {
+ exFlags |= BUTTON3_DOWN_MASK;
+ }
+
+ return exFlags;
+ }
+
+ InputEvent(Component source, int id, long when, int modifiers) {
+ super(source, id);
+
+ this.when = when;
+ modifiersEx = extractExFlags(modifiers);
+ }
+
+ public int getModifiers() {
+ int modifiers = 0;
+
+ if ((modifiersEx & SHIFT_DOWN_MASK) != 0) {
+ modifiers |= SHIFT_MASK;
+ }
+ if ((modifiersEx & CTRL_DOWN_MASK) != 0) {
+ modifiers |= CTRL_MASK;
+ }
+ if ((modifiersEx & META_DOWN_MASK) != 0) {
+ modifiers |= META_MASK;
+ }
+ if ((modifiersEx & ALT_DOWN_MASK) != 0) {
+ modifiers |= ALT_MASK;
+ }
+ if ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0) {
+ modifiers |= ALT_GRAPH_MASK;
+ }
+ if ((modifiersEx & BUTTON1_DOWN_MASK) != 0) {
+ modifiers |= BUTTON1_MASK;
+ }
+ if ((modifiersEx & BUTTON2_DOWN_MASK) != 0) {
+ modifiers |= BUTTON2_MASK;
+ }
+ if ((modifiersEx & BUTTON3_DOWN_MASK) != 0) {
+ modifiers |= BUTTON3_MASK;
+ }
+
+ return modifiers;
+ }
+
+ public int getModifiersEx() {
+ return modifiersEx;
+ }
+
+ void setModifiers(int modifiers) {
+ modifiersEx = extractExFlags(modifiers);
+ }
+
+ public boolean isAltDown() {
+ return ((modifiersEx & ALT_DOWN_MASK) != 0);
+ }
+
+ public boolean isAltGraphDown() {
+ return ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0);
+ }
+
+ public boolean isControlDown() {
+ return ((modifiersEx & CTRL_DOWN_MASK) != 0);
+ }
+
+ public boolean isMetaDown() {
+ return ((modifiersEx & META_DOWN_MASK) != 0);
+ }
+
+ public boolean isShiftDown() {
+ return ((modifiersEx & SHIFT_DOWN_MASK) != 0);
+ }
+
+ public long getWhen() {
+ return when;
+ }
+
+ @Override
+ public void consume() {
+ super.consume();
+ }
+
+ @Override
+ public boolean isConsumed() {
+ return super.isConsumed();
+ }
+
+}
diff --git a/awt/java/awt/event/InputMethodEvent.java b/awt/java/awt/event/InputMethodEvent.java
new file mode 100644
index 0000000..a5cac4e
--- /dev/null
+++ b/awt/java/awt/event/InputMethodEvent.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.font.TextHitInfo;
+import java.text.AttributedCharacterIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class InputMethodEvent extends AWTEvent {
+
+ private static final long serialVersionUID = 4727190874778922661L;
+
+ public static final int INPUT_METHOD_FIRST = 1100;
+
+ public static final int INPUT_METHOD_TEXT_CHANGED = 1100;
+
+ public static final int CARET_POSITION_CHANGED = 1101;
+
+ public static final int INPUT_METHOD_LAST = 1101;
+
+ private AttributedCharacterIterator text;
+ private TextHitInfo visiblePosition;
+ private TextHitInfo caret;
+ private int committedCharacterCount;
+ private long when;
+
+ public InputMethodEvent(Component src, int id,
+ TextHitInfo caret,
+ TextHitInfo visiblePos) {
+ this(src, id, null, 0, caret, visiblePos);
+ }
+
+ public InputMethodEvent(Component src, int id,
+ AttributedCharacterIterator text,
+ int commitedCharCount,
+ TextHitInfo caret,
+ TextHitInfo visiblePos) {
+ this(src, id, 0l, text, commitedCharCount, caret, visiblePos);
+ }
+
+ public InputMethodEvent(Component src, int id, long when,
+ AttributedCharacterIterator text,
+ int committedCharacterCount,
+ TextHitInfo caret,
+ TextHitInfo visiblePos) {
+ super(src, id);
+
+ if ((id < INPUT_METHOD_FIRST) || (id > INPUT_METHOD_LAST)) {
+ // awt.18E=Wrong event id
+ throw new IllegalArgumentException(Messages.getString("awt.18E")); //$NON-NLS-1$
+ }
+ if ((id == CARET_POSITION_CHANGED) && (text != null)) {
+ // awt.18F=Text must be null for CARET_POSITION_CHANGED
+ throw new IllegalArgumentException(Messages.getString("awt.18F")); //$NON-NLS-1$
+ }
+ if ((text != null) &&
+ ((committedCharacterCount < 0) ||
+ (committedCharacterCount >
+ (text.getEndIndex() - text.getBeginIndex())))) {
+ // awt.190=Wrong committedCharacterCount
+ throw new IllegalArgumentException(Messages.getString("awt.190")); //$NON-NLS-1$
+ }
+
+ this.when = when;
+ this.text = text;
+ this.caret = caret;
+ this.visiblePosition = visiblePos;
+ this.committedCharacterCount = committedCharacterCount;
+ }
+
+ public TextHitInfo getCaret() {
+ return caret;
+ }
+
+ public int getCommittedCharacterCount() {
+ return committedCharacterCount;
+ }
+
+ public AttributedCharacterIterator getText() {
+ return text;
+ }
+
+ public TextHitInfo getVisiblePosition() {
+ return visiblePosition;
+ }
+
+ public long getWhen() {
+ return when;
+ }
+
+ @Override
+ public void consume() {
+ super.consume();
+ }
+
+ @Override
+ public boolean isConsumed() {
+ return super.isConsumed();
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * InputMethodEvent e = new InputMethodEvent(new Component(){},
+ * InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
+ * TextHitInfo.leading(1), TextHitInfo.trailing(2));
+ * System.out.println(e);
+ */
+ String typeString = null;
+
+ switch (id) {
+ case INPUT_METHOD_TEXT_CHANGED:
+ typeString = "INPUT_METHOD_TEXT_CHANGED"; //$NON-NLS-1$
+ break;
+ case CARET_POSITION_CHANGED:
+ typeString = "CARET_POSITION_CHANGED"; //$NON-NLS-1$
+ break;
+ default:
+ typeString = "unknown type"; //$NON-NLS-1$
+ }
+
+ return typeString + ",text=" + text + //$NON-NLS-1$
+ ",commitedCharCount=" + committedCharacterCount + //$NON-NLS-1$
+ ",caret=" + caret + ",visiblePosition=" + visiblePosition; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+}
diff --git a/awt/java/awt/event/InputMethodListener.java b/awt/java/awt/event/InputMethodListener.java
new file mode 100644
index 0000000..0ab6918
--- /dev/null
+++ b/awt/java/awt/event/InputMethodListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface InputMethodListener extends EventListener {
+
+ public void caretPositionChanged(InputMethodEvent e);
+
+ public void inputMethodTextChanged(InputMethodEvent e);
+
+}
diff --git a/awt/java/awt/event/InvocationEvent.java b/awt/java/awt/event/InvocationEvent.java
new file mode 100644
index 0000000..59346ed
--- /dev/null
+++ b/awt/java/awt/event/InvocationEvent.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.ActiveEvent;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class InvocationEvent extends AWTEvent implements ActiveEvent {
+
+ private static final long serialVersionUID = 436056344909459450L;
+
+ public static final int INVOCATION_FIRST = 1200;
+
+ public static final int INVOCATION_DEFAULT = 1200;
+
+ public static final int INVOCATION_LAST = 1200;
+
+ protected Runnable runnable;
+
+ protected Object notifier;
+
+ protected boolean catchExceptions;
+
+ private long when;
+ private Throwable throwable;
+
+ public InvocationEvent(Object source, Runnable runnable) {
+ this(source, runnable, null, false);
+ }
+
+ public InvocationEvent(Object source, Runnable runnable,
+ Object notifier, boolean catchExceptions) {
+ this(source, INVOCATION_DEFAULT, runnable, notifier, catchExceptions);
+ }
+
+ protected InvocationEvent(Object source, int id, Runnable runnable,
+ Object notifier, boolean catchExceptions)
+ {
+ super(source, id);
+
+ // awt.18C=Cannot invoke null runnable
+ assert runnable != null : Messages.getString("awt.18C"); //$NON-NLS-1$
+
+ if (source == null) {
+ // awt.18D=Source is null
+ throw new IllegalArgumentException(Messages.getString("awt.18D")); //$NON-NLS-1$
+ }
+ this.runnable = runnable;
+ this.notifier = notifier;
+ this.catchExceptions = catchExceptions;
+
+ throwable = null;
+ when = System.currentTimeMillis();
+ }
+
+ public void dispatch() {
+ if (!catchExceptions) {
+ runAndNotify();
+ } else {
+ try {
+ runAndNotify();
+ } catch (Throwable t) {
+ throwable = t;
+ }
+ }
+ }
+
+ private void runAndNotify() {
+ if (notifier != null) {
+ synchronized(notifier) {
+ try {
+ runnable.run();
+ } finally {
+ notifier.notifyAll();
+ }
+ }
+ } else {
+ runnable.run();
+ }
+ }
+
+ public Exception getException() {
+ return (throwable != null && throwable instanceof Exception) ?
+ (Exception)throwable : null;
+ }
+
+ public Throwable getThrowable() {
+ return throwable;
+ }
+
+ public long getWhen() {
+ return when;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * InvocationEvent e = new InvocationEvent(new Component(){},
+ * new Runnable() { public void run(){} });
+ * System.out.println(e);
+ */
+
+ return ((id == INVOCATION_DEFAULT ? "INVOCATION_DEFAULT" : "unknown type") + //$NON-NLS-1$ //$NON-NLS-2$
+ ",runnable=" + runnable + //$NON-NLS-1$
+ ",notifier=" + notifier + //$NON-NLS-1$
+ ",catchExceptions=" + catchExceptions + //$NON-NLS-1$
+ ",when=" + when); //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/ItemEvent.java b/awt/java/awt/event/ItemEvent.java
new file mode 100644
index 0000000..842da14
--- /dev/null
+++ b/awt/java/awt/event/ItemEvent.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+import java.awt.ItemSelectable;
+
+public class ItemEvent extends AWTEvent {
+
+ private static final long serialVersionUID = -608708132447206933L;
+
+ public static final int ITEM_FIRST = 701;
+
+ public static final int ITEM_LAST = 701;
+
+ public static final int ITEM_STATE_CHANGED = 701;
+
+ public static final int SELECTED = 1;
+
+ public static final int DESELECTED = 2;
+
+ private Object item;
+ private int stateChange;
+
+ public ItemEvent(ItemSelectable source, int id, Object item, int stateChange) {
+ super(source, id);
+
+ this.item = item;
+ this.stateChange = stateChange;
+ }
+
+ public Object getItem() {
+ return item;
+ }
+
+ public int getStateChange() {
+ return stateChange;
+ }
+
+ public ItemSelectable getItemSelectable() {
+ return (ItemSelectable) source;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * Checkbox c = new Checkbox("Checkbox", true);
+ * ItemEvent e = new ItemEvent(c, ItemEvent.ITEM_STATE_CHANGED,
+ * c, ItemEvent.SELECTED);
+ * System.out.println(e);
+ */
+
+ String stateString = null;
+
+ switch (stateChange) {
+ case SELECTED:
+ stateString = "SELECTED"; //$NON-NLS-1$
+ break;
+ case DESELECTED:
+ stateString = "DESELECTED"; //$NON-NLS-1$
+ break;
+ default:
+ stateString = "unknown type"; //$NON-NLS-1$
+ }
+
+ return ((id == ITEM_STATE_CHANGED ? "ITEM_STATE_CHANGED" : "unknown type") + //$NON-NLS-1$ //$NON-NLS-2$
+ ",item=" + item + ",stateChange=" + stateString); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+}
diff --git a/awt/java/awt/event/ItemListener.java b/awt/java/awt/event/ItemListener.java
new file mode 100644
index 0000000..33633be
--- /dev/null
+++ b/awt/java/awt/event/ItemListener.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface ItemListener extends EventListener {
+
+ public void itemStateChanged(ItemEvent e);
+
+}
diff --git a/awt/java/awt/event/KeyAdapter.java b/awt/java/awt/event/KeyAdapter.java
new file mode 100644
index 0000000..423b5c9
--- /dev/null
+++ b/awt/java/awt/event/KeyAdapter.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class KeyAdapter implements KeyListener {
+
+ public KeyAdapter() {
+ }
+
+ public void keyPressed(KeyEvent e) {
+ }
+
+ public void keyReleased(KeyEvent e) {
+ }
+
+ public void keyTyped(KeyEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/KeyEvent.java b/awt/java/awt/event/KeyEvent.java
new file mode 100644
index 0000000..056c64c
--- /dev/null
+++ b/awt/java/awt/event/KeyEvent.java
@@ -0,0 +1,681 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+import java.awt.Toolkit;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class KeyEvent extends InputEvent {
+
+ private static final long serialVersionUID = -2352130953028126954L;
+
+ public static final int KEY_FIRST = 400;
+
+ public static final int KEY_LAST = 402;
+
+ public static final int KEY_TYPED = 400;
+
+ public static final int KEY_PRESSED = 401;
+
+ public static final int KEY_RELEASED = 402;
+
+ public static final int VK_ENTER = 10;
+
+ public static final int VK_BACK_SPACE = 8;
+
+ public static final int VK_TAB = 9;
+
+ public static final int VK_CANCEL = 3;
+
+ public static final int VK_CLEAR = 12;
+
+ public static final int VK_SHIFT = 16;
+
+ public static final int VK_CONTROL = 17;
+
+ public static final int VK_ALT = 18;
+
+ public static final int VK_PAUSE = 19;
+
+ public static final int VK_CAPS_LOCK = 20;
+
+ public static final int VK_ESCAPE = 27;
+
+ public static final int VK_SPACE = 32;
+
+ public static final int VK_PAGE_UP = 33;
+
+ public static final int VK_PAGE_DOWN = 34;
+
+ public static final int VK_END = 35;
+
+ public static final int VK_HOME = 36;
+
+ public static final int VK_LEFT = 37;
+
+ public static final int VK_UP = 38;
+
+ public static final int VK_RIGHT = 39;
+
+ public static final int VK_DOWN = 40;
+
+ public static final int VK_COMMA = 44;
+
+ public static final int VK_MINUS = 45;
+
+ public static final int VK_PERIOD = 46;
+
+ public static final int VK_SLASH = 47;
+
+ public static final int VK_0 = 48;
+
+ public static final int VK_1 = 49;
+
+ public static final int VK_2 = 50;
+
+ public static final int VK_3 = 51;
+
+ public static final int VK_4 = 52;
+
+ public static final int VK_5 = 53;
+
+ public static final int VK_6 = 54;
+
+ public static final int VK_7 = 55;
+
+ public static final int VK_8 = 56;
+
+ public static final int VK_9 = 57;
+
+ public static final int VK_SEMICOLON = 59;
+
+ public static final int VK_EQUALS = 61;
+
+ public static final int VK_A = 65;
+
+ public static final int VK_B = 66;
+
+ public static final int VK_C = 67;
+
+ public static final int VK_D = 68;
+
+ public static final int VK_E = 69;
+
+ public static final int VK_F = 70;
+
+ public static final int VK_G = 71;
+
+ public static final int VK_H = 72;
+
+ public static final int VK_I = 73;
+
+ public static final int VK_J = 74;
+
+ public static final int VK_K = 75;
+
+ public static final int VK_L = 76;
+
+ public static final int VK_M = 77;
+
+ public static final int VK_N = 78;
+
+ public static final int VK_O = 79;
+
+ public static final int VK_P = 80;
+
+ public static final int VK_Q = 81;
+
+ public static final int VK_R = 82;
+
+ public static final int VK_S = 83;
+
+ public static final int VK_T = 84;
+
+ public static final int VK_U = 85;
+
+ public static final int VK_V = 86;
+
+ public static final int VK_W = 87;
+
+ public static final int VK_X = 88;
+
+ public static final int VK_Y = 89;
+
+ public static final int VK_Z = 90;
+
+ public static final int VK_OPEN_BRACKET = 91;
+
+ public static final int VK_BACK_SLASH = 92;
+
+ public static final int VK_CLOSE_BRACKET = 93;
+
+ public static final int VK_NUMPAD0 = 96;
+
+ public static final int VK_NUMPAD1 = 97;
+
+ public static final int VK_NUMPAD2 = 98;
+
+ public static final int VK_NUMPAD3 = 99;
+
+ public static final int VK_NUMPAD4 = 100;
+
+ public static final int VK_NUMPAD5 = 101;
+
+ public static final int VK_NUMPAD6 = 102;
+
+ public static final int VK_NUMPAD7 = 103;
+
+ public static final int VK_NUMPAD8 = 104;
+
+ public static final int VK_NUMPAD9 = 105;
+
+ public static final int VK_MULTIPLY = 106;
+
+ public static final int VK_ADD = 107;
+
+ public static final int VK_SEPARATER = 108;
+
+ public static final int VK_SEPARATOR = 108;
+
+ public static final int VK_SUBTRACT = 109;
+
+ public static final int VK_DECIMAL = 110;
+
+ public static final int VK_DIVIDE = 111;
+
+ public static final int VK_DELETE = 127;
+
+ public static final int VK_NUM_LOCK = 144;
+
+ public static final int VK_SCROLL_LOCK = 145;
+
+ public static final int VK_F1 = 112;
+
+ public static final int VK_F2 = 113;
+
+ public static final int VK_F3 = 114;
+
+ public static final int VK_F4 = 115;
+
+ public static final int VK_F5 = 116;
+
+ public static final int VK_F6 = 117;
+
+ public static final int VK_F7 = 118;
+
+ public static final int VK_F8 = 119;
+
+ public static final int VK_F9 = 120;
+
+ public static final int VK_F10 = 121;
+
+ public static final int VK_F11 = 122;
+
+ public static final int VK_F12 = 123;
+
+ public static final int VK_F13 = 61440;
+
+ public static final int VK_F14 = 61441;
+
+ public static final int VK_F15 = 61442;
+
+ public static final int VK_F16 = 61443;
+
+ public static final int VK_F17 = 61444;
+
+ public static final int VK_F18 = 61445;
+
+ public static final int VK_F19 = 61446;
+
+ public static final int VK_F20 = 61447;
+
+ public static final int VK_F21 = 61448;
+
+ public static final int VK_F22 = 61449;
+
+ public static final int VK_F23 = 61450;
+
+ public static final int VK_F24 = 61451;
+
+ public static final int VK_PRINTSCREEN = 154;
+
+ public static final int VK_INSERT = 155;
+
+ public static final int VK_HELP = 156;
+
+ public static final int VK_META = 157;
+
+ public static final int VK_BACK_QUOTE = 192;
+
+ public static final int VK_QUOTE = 222;
+
+ public static final int VK_KP_UP = 224;
+
+ public static final int VK_KP_DOWN = 225;
+
+ public static final int VK_KP_LEFT = 226;
+
+ public static final int VK_KP_RIGHT = 227;
+
+ public static final int VK_DEAD_GRAVE = 128;
+
+ public static final int VK_DEAD_ACUTE = 129;
+
+ public static final int VK_DEAD_CIRCUMFLEX = 130;
+
+ public static final int VK_DEAD_TILDE = 131;
+
+ public static final int VK_DEAD_MACRON = 132;
+
+ public static final int VK_DEAD_BREVE = 133;
+
+ public static final int VK_DEAD_ABOVEDOT = 134;
+
+ public static final int VK_DEAD_DIAERESIS = 135;
+
+ public static final int VK_DEAD_ABOVERING = 136;
+
+ public static final int VK_DEAD_DOUBLEACUTE = 137;
+
+ public static final int VK_DEAD_CARON = 138;
+
+ public static final int VK_DEAD_CEDILLA = 139;
+
+ public static final int VK_DEAD_OGONEK = 140;
+
+ public static final int VK_DEAD_IOTA = 141;
+
+ public static final int VK_DEAD_VOICED_SOUND = 142;
+
+ public static final int VK_DEAD_SEMIVOICED_SOUND = 143;
+
+ public static final int VK_AMPERSAND = 150;
+
+ public static final int VK_ASTERISK = 151;
+
+ public static final int VK_QUOTEDBL = 152;
+
+ public static final int VK_LESS = 153;
+
+ public static final int VK_GREATER = 160;
+
+ public static final int VK_BRACELEFT = 161;
+
+ public static final int VK_BRACERIGHT = 162;
+
+ public static final int VK_AT = 512;
+
+ public static final int VK_COLON = 513;
+
+ public static final int VK_CIRCUMFLEX = 514;
+
+ public static final int VK_DOLLAR = 515;
+
+ public static final int VK_EURO_SIGN = 516;
+
+ public static final int VK_EXCLAMATION_MARK = 517;
+
+ public static final int VK_INVERTED_EXCLAMATION_MARK = 518;
+
+ public static final int VK_LEFT_PARENTHESIS = 519;
+
+ public static final int VK_NUMBER_SIGN = 520;
+
+ public static final int VK_PLUS = 521;
+
+ public static final int VK_RIGHT_PARENTHESIS = 522;
+
+ public static final int VK_UNDERSCORE = 523;
+
+ public static final int VK_FINAL = 24;
+
+ public static final int VK_WINDOWS = 524;
+
+ public static final int VK_CONTEXT_MENU = 525;
+
+ public static final int VK_CONVERT = 28;
+
+ public static final int VK_NONCONVERT = 29;
+
+ public static final int VK_ACCEPT = 30;
+
+ public static final int VK_MODECHANGE = 31;
+
+ public static final int VK_KANA = 21;
+
+ public static final int VK_KANJI = 25;
+
+ public static final int VK_ALPHANUMERIC = 240;
+
+ public static final int VK_KATAKANA = 241;
+
+ public static final int VK_HIRAGANA = 242;
+
+ public static final int VK_FULL_WIDTH = 243;
+
+ public static final int VK_HALF_WIDTH = 244;
+
+ public static final int VK_ROMAN_CHARACTERS = 245;
+
+ public static final int VK_ALL_CANDIDATES = 256;
+
+ public static final int VK_PREVIOUS_CANDIDATE = 257;
+
+ public static final int VK_CODE_INPUT = 258;
+
+ public static final int VK_JAPANESE_KATAKANA = 259;
+
+ public static final int VK_JAPANESE_HIRAGANA = 260;
+
+ public static final int VK_JAPANESE_ROMAN = 261;
+
+ public static final int VK_KANA_LOCK = 262;
+
+ public static final int VK_INPUT_METHOD_ON_OFF = 263;
+
+ public static final int VK_CUT = 65489;
+
+ public static final int VK_COPY = 65485;
+
+ public static final int VK_PASTE = 65487;
+
+ public static final int VK_UNDO = 65483;
+
+ public static final int VK_AGAIN = 65481;
+
+ public static final int VK_FIND = 65488;
+
+ public static final int VK_PROPS = 65482;
+
+ public static final int VK_STOP = 65480;
+
+ public static final int VK_COMPOSE = 65312;
+
+ public static final int VK_ALT_GRAPH = 65406;
+
+ public static final int VK_BEGIN = 65368;
+
+ public static final int VK_UNDEFINED = 0;
+
+ public static final char CHAR_UNDEFINED = (char)(-1);
+
+ public static final int KEY_LOCATION_UNKNOWN = 0;
+
+ public static final int KEY_LOCATION_STANDARD = 1;
+
+ public static final int KEY_LOCATION_LEFT = 2;
+
+ public static final int KEY_LOCATION_RIGHT = 3;
+
+ public static final int KEY_LOCATION_NUMPAD = 4;
+
+ private int keyCode;
+ private char keyChar;
+ private int keyLocation;
+
+ public static String getKeyModifiersText(int modifiers) {
+ return getKeyModifiersExText(extractExFlags(modifiers));
+ }
+
+ static String getKeyModifiersExText(int modifiersEx) {
+ String text = ""; //$NON-NLS-1$
+
+ if ((modifiersEx & InputEvent.META_DOWN_MASK) != 0) {
+ text += Toolkit.getProperty("AWT.meta", "Meta"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.CTRL_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.control", "Ctrl"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.ALT_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.alt", "Alt"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.SHIFT_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.shift", "Shift"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.altGraph", "Alt Graph"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ return text;
+ }
+
+ public static String getKeyText(int keyCode) {
+ String[] rawName = getPublicStaticFinalIntFieldName(keyCode); //$NON-NLS-1$
+
+ if ((rawName == null) || (rawName.length == 0)) {
+ return ("Unknown keyCode: " + (keyCode >= 0 ? "0x" : "-0x") + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ Integer.toHexString(Math.abs(keyCode)));
+ }
+
+ String propertyName = getPropertyName(rawName);
+ String defaultName = getDefaultName(rawName);
+
+ return Toolkit.getProperty(propertyName, defaultName);
+ }
+
+ private static String getDefaultName(String[] rawName) {
+ String name = ""; //$NON-NLS-1$
+
+ for (int i = 0; true; i++) {
+ String part = rawName[i];
+
+ name += new String(new char[] {part.charAt(0)}).toUpperCase() +
+ part.substring(1).toLowerCase();
+
+ if (i == (rawName.length - 1)) {
+ break;
+ }
+ name += " "; //$NON-NLS-1$
+ }
+
+ return name;
+ }
+
+ private static String getPropertyName(String[] rawName) {
+ String name = rawName[0].toLowerCase();
+
+ for (int i = 1; i < rawName.length; i++) {
+ String part = rawName[i];
+
+ name += new String(new char[] {part.charAt(0)}).toUpperCase() +
+ part.substring(1).toLowerCase();
+ }
+
+ return ("AWT." + name); //$NON-NLS-1$
+ }
+
+ private static String[] getPublicStaticFinalIntFieldName(int value) {
+ Field[] allFields = KeyEvent.class.getDeclaredFields();
+
+ try {
+ for (Field field : allFields) {
+ Class<?> ssalc = field.getType();
+ int modifiers = field.getModifiers();
+
+ if (ssalc.isPrimitive() && ssalc.getName().equals("int") && //$NON-NLS-1$
+ Modifier.isFinal(modifiers) && Modifier.isPublic(modifiers) &&
+ Modifier.isStatic(modifiers))
+ {
+ if (field.getInt(null) == value){
+ final String name = field.getName();
+ final int prefixLength = name.indexOf("_") + 1;
+ return name.substring(prefixLength).split("_"); //$NON-NLS-1$
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return null;
+ }
+
+ @Deprecated
+ public KeyEvent(Component src, int id,
+ long when, int modifiers,
+ int keyCode) {
+ this(src, id, when, modifiers, keyCode,
+ (keyCode > (2 << 7) - 1) ? CHAR_UNDEFINED : (char) keyCode);
+ }
+
+ public KeyEvent(Component src, int id,
+ long when, int modifiers,
+ int keyCode, char keyChar) {
+ this(src, id, when, modifiers, keyCode, keyChar, KEY_LOCATION_UNKNOWN);
+ }
+
+ public KeyEvent(Component src, int id,
+ long when, int modifiers,
+ int keyCode, char keyChar,
+ int keyLocation) {
+ super(src, id, when, modifiers);
+
+ if (id == KEY_TYPED) {
+ if (keyCode != VK_UNDEFINED) {
+ // awt.191=Invalid keyCode for KEY_TYPED event, must be VK_UNDEFINED
+ throw new IllegalArgumentException(Messages.getString("awt.191")); //$NON-NLS-1$
+ }
+ if (keyChar == CHAR_UNDEFINED) {
+ // awt.192=Invalid keyChar for KEY_TYPED event, can't be CHAR_UNDEFINED
+ throw new IllegalArgumentException(Messages.getString("awt.192")); //$NON-NLS-1$
+ }
+ }
+
+ if ((keyLocation < KEY_LOCATION_UNKNOWN)
+ || (keyLocation > KEY_LOCATION_NUMPAD)) {
+ // awt.297=Invalid keyLocation
+ throw new IllegalArgumentException(Messages.getString("awt.297")); //$NON-NLS-1$
+ }
+
+ this.keyChar = keyChar;
+ this.keyLocation = keyLocation;
+ this.keyCode = keyCode;
+ }
+
+ public int getKeyCode() {
+ return keyCode;
+ }
+
+ public void setKeyCode(int keyCode) {
+ this.keyCode = keyCode;
+ }
+
+ public char getKeyChar() {
+ return keyChar;
+ }
+
+ public void setKeyChar(char keyChar) {
+ this.keyChar = keyChar;
+ }
+
+ public int getKeyLocation() {
+ return keyLocation;
+ }
+
+ @Override
+ @Deprecated
+ public void setModifiers(int modifiers) {
+ super.setModifiers(modifiers);
+ }
+
+ public boolean isActionKey() {
+ return ((keyChar == CHAR_UNDEFINED) && (keyCode != VK_UNDEFINED) &&
+ !((keyCode == VK_ALT) || (keyCode == VK_ALT_GRAPH) ||
+ (keyCode == VK_CONTROL) || (keyCode == VK_META) || (keyCode == VK_SHIFT)));
+ }
+
+ @Override
+ public String paramString() {
+ /*
+ * The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * KeyEvent e = new KeyEvent(new Component() {},
+ * KeyEvent.KEY_PRESSED, 0,
+ * KeyEvent.CTRL_DOWN_MASK|KeyEvent.SHIFT_DOWN_MASK,
+ * KeyEvent.VK_A, 'A', KeyEvent.KEY_LOCATION_STANDARD);
+ * System.out.println(e);
+ */
+
+ String idString = null;
+ String locString = null;
+ String paramString = null;
+ String keyCharString = (keyChar == '\n') ?
+ keyCharString = getKeyText(VK_ENTER) : "'" + keyChar + "'"; //$NON-NLS-1$ //$NON-NLS-2$
+
+ switch (id) {
+ case KEY_PRESSED:
+ idString = "KEY_PRESSED"; //$NON-NLS-1$
+ break;
+ case KEY_RELEASED:
+ idString = "KEY_RELEASED"; //$NON-NLS-1$
+ break;
+ case KEY_TYPED:
+ idString = "KEY_TYPED"; //$NON-NLS-1$
+ break;
+ default:
+ idString = "unknown type"; //$NON-NLS-1$
+ }
+
+ switch(keyLocation){
+ case KEY_LOCATION_STANDARD:
+ locString = "KEY_LOCATION_STANDARD"; //$NON-NLS-1$
+ break;
+ case KEY_LOCATION_LEFT:
+ locString = "KEY_LOCATION_LEFT"; //$NON-NLS-1$
+ break;
+ case KEY_LOCATION_RIGHT:
+ locString = "KEY_LOCATION_RIGHT"; //$NON-NLS-1$
+ break;
+ case KEY_LOCATION_NUMPAD:
+ locString = "KEY_LOCATION_NUMPAD"; //$NON-NLS-1$
+ break;
+ case KEY_LOCATION_UNKNOWN:
+ locString = "KEY_LOCATION_UNKNOWN"; //$NON-NLS-1$
+ break;
+ default:
+ locString = "unknown type"; //$NON-NLS-1$
+ }
+
+ paramString = idString + ",keyCode=" + keyCode; //$NON-NLS-1$
+ if (isActionKey()) {
+ paramString += "," + getKeyText(keyCode); //$NON-NLS-1$
+ } else {
+ paramString += ",keyChar=" + keyCharString; //$NON-NLS-1$
+ }
+ if (getModifiersEx() > 0) {
+ paramString += ",modifiers=" + getModifiersExText(getModifiersEx()) + //$NON-NLS-1$
+ ",extModifiers=" + getModifiersExText(getModifiersEx()); //$NON-NLS-1$
+ }
+ paramString += ",keyLocation=" + locString; //$NON-NLS-1$
+
+ return paramString;
+ }
+
+}
diff --git a/awt/java/awt/event/KeyListener.java b/awt/java/awt/event/KeyListener.java
new file mode 100644
index 0000000..f20fc90
--- /dev/null
+++ b/awt/java/awt/event/KeyListener.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface KeyListener extends EventListener {
+
+ public void keyPressed(KeyEvent e);
+
+ public void keyReleased(KeyEvent e);
+
+ public void keyTyped(KeyEvent e);
+
+}
diff --git a/awt/java/awt/event/MouseAdapter.java b/awt/java/awt/event/MouseAdapter.java
new file mode 100644
index 0000000..4973956
--- /dev/null
+++ b/awt/java/awt/event/MouseAdapter.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class MouseAdapter implements MouseListener {
+
+ public MouseAdapter() {
+ }
+
+ public void mouseClicked(MouseEvent e) {
+ }
+
+ public void mouseEntered(MouseEvent e) {
+ }
+
+ public void mouseExited(MouseEvent e) {
+ }
+
+ public void mousePressed(MouseEvent e) {
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/MouseEvent.java b/awt/java/awt/event/MouseEvent.java
new file mode 100644
index 0000000..0b776f9
--- /dev/null
+++ b/awt/java/awt/event/MouseEvent.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+import java.awt.Point;
+import java.awt.Toolkit;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class MouseEvent extends InputEvent {
+
+ private static final long serialVersionUID = -991214153494842848L;
+
+ public static final int MOUSE_FIRST = 500;
+
+ public static final int MOUSE_LAST = 507;
+
+ public static final int MOUSE_CLICKED = 500;
+
+ public static final int MOUSE_PRESSED = 501;
+
+ public static final int MOUSE_RELEASED = 502;
+
+ public static final int MOUSE_MOVED = 503;
+
+ public static final int MOUSE_ENTERED = 504;
+
+ public static final int MOUSE_EXITED = 505;
+
+ public static final int MOUSE_DRAGGED = 506;
+
+ public static final int MOUSE_WHEEL = 507;
+
+ public static final int NOBUTTON = 0;
+
+ public static final int BUTTON1 = 1;
+
+ public static final int BUTTON2 = 2;
+
+ public static final int BUTTON3 = 3;
+
+ private boolean popupTrigger;
+ private int clickCount;
+ private int button;
+ private int x;
+ private int y;
+
+ public static String getMouseModifiersText(int modifiers) {
+ final StringBuffer text = new StringBuffer();
+
+ if ((modifiers & META_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.meta", "Meta")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & SHIFT_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.shift", "Shift")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & CTRL_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.control", "Ctrl")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & ALT_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.alt", "Alt")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & ALT_GRAPH_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.altGraph", "Alt Graph")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & BUTTON1_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.button1", "Button1")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & BUTTON2_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.button2", "Button2")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if ((modifiers & BUTTON3_MASK) != 0) {
+ text.append(Toolkit.getProperty("AWT.button3", "Button3")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ return text.length() == 0 ? text.toString() : text.substring(0, text
+ .length() - 1);
+ }
+
+ static String addMouseModifiersExText(String text, int modifiersEx) {
+ if ((modifiersEx & InputEvent.BUTTON1_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.button1", "Button1"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.BUTTON2_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.button2", "Button2"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if ((modifiersEx & InputEvent.BUTTON3_DOWN_MASK) != 0) {
+ text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ Toolkit.getProperty("AWT.button3", "Button3"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ return text;
+ }
+
+ public MouseEvent(Component source, int id, long when,
+ int modifiers, int x, int y,
+ int clickCount, boolean popupTrigger) {
+ this(source, id, when, modifiers, x, y,
+ clickCount, popupTrigger, NOBUTTON);
+ }
+
+ public MouseEvent(Component source, int id, long when,
+ int modifiers, int x, int y,
+ int clickCount, boolean popupTrigger, int button) {
+ super(source, id, when, modifiers);
+
+ if ((button != NOBUTTON) && (button != BUTTON1) &&
+ (button != BUTTON2) && (button != BUTTON3)) {
+ // awt.18B=Invalid button value
+ throw new IllegalArgumentException(Messages.getString("awt.18B")); //$NON-NLS-1$
+ }
+
+ this.popupTrigger = popupTrigger;
+ this.clickCount = clickCount;
+ this.button = button;
+ this.x = x;
+ this.y = y;
+ }
+
+ public int getButton() {
+ return button;
+ }
+
+ public int getClickCount() {
+ return clickCount;
+ }
+
+ public Point getPoint() {
+ return new Point(x, y);
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public boolean isPopupTrigger() {
+ return popupTrigger;
+ }
+
+ public void translatePoint(int x, int y) {
+ this.x += x;
+ this.y += y;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * MouseEvent e = new MouseEvent(new Component(){},
+ * MouseEvent.MOUSE_PRESSED, 0,
+ * MouseEvent.BUTTON1_DOWN_MASK|MouseEvent.CTRL_DOWN_MASK,
+ * 10, 20, 1, false, MouseEvent.BUTTON1);
+ * System.out.println(e);
+ */
+
+ String idString = null;
+ String paramString = null;
+
+ switch (id) {
+ case MOUSE_MOVED:
+ idString = "MOUSE_MOVED"; //$NON-NLS-1$
+ break;
+ case MOUSE_CLICKED:
+ idString = "MOUSE_CLICKED"; //$NON-NLS-1$
+ break;
+ case MOUSE_PRESSED:
+ idString = "MOUSE_PRESSED"; //$NON-NLS-1$
+ break;
+ case MOUSE_RELEASED:
+ idString = "MOUSE_RELEASED"; //$NON-NLS-1$
+ break;
+ case MOUSE_DRAGGED:
+ idString = "MOUSE_DRAGGED"; //$NON-NLS-1$
+ break;
+ case MOUSE_ENTERED:
+ idString = "MOUSE_ENTERED"; //$NON-NLS-1$
+ break;
+ case MOUSE_EXITED:
+ idString = "MOUSE_EXITED"; //$NON-NLS-1$
+ break;
+ case MOUSE_WHEEL:
+ idString = "MOUSE_WHEEL"; //$NON-NLS-1$
+ break;
+ default:
+ idString = "unknown type"; //$NON-NLS-1$
+ }
+
+ paramString = idString + ",(" + getX() + "," + getY() + ")" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ ",button=" + button; //$NON-NLS-1$
+ if (getModifiersEx() > 0) {
+ paramString +=
+ ",modifiers=" + getModifiersExText(getModifiersEx()) + //$NON-NLS-1$
+ ",extModifiers=" + getModifiersExText(getModifiersEx()); //$NON-NLS-1$
+ }
+ paramString += ",clickCount=" + getClickCount(); //$NON-NLS-1$
+
+ return paramString;
+ }
+
+}
diff --git a/awt/java/awt/event/MouseListener.java b/awt/java/awt/event/MouseListener.java
new file mode 100644
index 0000000..5d32b0f
--- /dev/null
+++ b/awt/java/awt/event/MouseListener.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface MouseListener extends EventListener {
+
+ public void mouseClicked(MouseEvent e);
+
+ public void mouseEntered(MouseEvent e);
+
+ public void mouseExited(MouseEvent e);
+
+ public void mousePressed(MouseEvent e);
+
+ public void mouseReleased(MouseEvent e);
+
+}
diff --git a/awt/java/awt/event/MouseMotionAdapter.java b/awt/java/awt/event/MouseMotionAdapter.java
new file mode 100644
index 0000000..a4bebcc
--- /dev/null
+++ b/awt/java/awt/event/MouseMotionAdapter.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class MouseMotionAdapter implements MouseMotionListener {
+
+ public MouseMotionAdapter() {
+ }
+
+ public void mouseDragged(MouseEvent e) {
+ }
+
+ public void mouseMoved(MouseEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/MouseMotionListener.java b/awt/java/awt/event/MouseMotionListener.java
new file mode 100644
index 0000000..a5c11da
--- /dev/null
+++ b/awt/java/awt/event/MouseMotionListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface MouseMotionListener extends EventListener {
+
+ public void mouseDragged(MouseEvent e);
+
+ public void mouseMoved(MouseEvent e);
+
+}
diff --git a/awt/java/awt/event/MouseWheelEvent.java b/awt/java/awt/event/MouseWheelEvent.java
new file mode 100644
index 0000000..d3ac9d8
--- /dev/null
+++ b/awt/java/awt/event/MouseWheelEvent.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+
+public class MouseWheelEvent extends MouseEvent {
+
+ private static final long serialVersionUID = -9187413581993563929L;
+
+ public static final int WHEEL_UNIT_SCROLL = 0;
+
+ public static final int WHEEL_BLOCK_SCROLL = 1;
+
+ private int wheelRotation;
+ private int scrollAmount;
+ private int scrollType;
+
+ public MouseWheelEvent(Component source, int id, long when, int modifiers,
+ int x, int y, int clickCount, boolean popupTrigger, int scrollType,
+ int scrollAmount, int wheelRotation) {
+ super(source, id, when, modifiers, x, y, clickCount, popupTrigger);
+
+ this.scrollType = scrollType;
+ this.scrollAmount = scrollAmount;
+ this.wheelRotation = wheelRotation;
+ }
+
+ public int getScrollAmount() {
+ return scrollAmount;
+ }
+
+ public int getScrollType() {
+ return scrollType;
+ }
+
+ public int getWheelRotation() {
+ return wheelRotation;
+ }
+
+ public int getUnitsToScroll() {
+ return (scrollAmount * wheelRotation);
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * MouseWheelEvent e = new MouseWheelEvent(new Component(){},
+ * MouseWheelEvent.MOUSE_WHEEL, 0,
+ * MouseEvent.BUTTON1_DOWN_MASK|MouseEvent.CTRL_DOWN_MASK,
+ * 10, 20, 1, false, MouseWheelEvent.WHEEL_UNIT_SCROLL,
+ * 1, 3);
+ * System.out.println(e);
+ */
+
+ String paramString = super.paramString();
+ String typeString = null;
+
+ switch (scrollType) {
+ case WHEEL_UNIT_SCROLL:
+ typeString = "WHEEL_UNIT_SCROLL"; //$NON-NLS-1$
+ break;
+ case WHEEL_BLOCK_SCROLL:
+ typeString = "WHEEL_BLOCK_SCROLL"; //$NON-NLS-1$
+ break;
+ default:
+ typeString = "unknown type"; //$NON-NLS-1$
+ }
+
+ paramString += ",scrollType=" + typeString + //$NON-NLS-1$
+ ",scrollAmount=" + scrollAmount + //$NON-NLS-1$
+ ",wheelRotation=" + wheelRotation; //$NON-NLS-1$
+
+ return paramString;
+ }
+
+}
diff --git a/awt/java/awt/event/MouseWheelListener.java b/awt/java/awt/event/MouseWheelListener.java
new file mode 100644
index 0000000..8ca1c8b
--- /dev/null
+++ b/awt/java/awt/event/MouseWheelListener.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface MouseWheelListener extends EventListener {
+
+ public void mouseWheelMoved(MouseWheelEvent e);
+
+}
diff --git a/awt/java/awt/event/PaintEvent.java b/awt/java/awt/event/PaintEvent.java
new file mode 100644
index 0000000..d0573e1
--- /dev/null
+++ b/awt/java/awt/event/PaintEvent.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.Component;
+import java.awt.Rectangle;
+
+public class PaintEvent extends ComponentEvent {
+
+ private static final long serialVersionUID = 1267492026433337593L;
+
+ public static final int PAINT_FIRST = 800;
+
+ public static final int PAINT_LAST = 801;
+
+ public static final int PAINT = 800;
+
+ public static final int UPDATE = 801;
+
+ private Rectangle updateRect;
+
+ public PaintEvent(Component source, int id, Rectangle updateRect) {
+ super(source, id);
+
+ this.updateRect = updateRect;
+ }
+
+ public Rectangle getUpdateRect() {
+ return updateRect;
+ }
+
+ public void setUpdateRect(Rectangle updateRect) {
+ this.updateRect = updateRect;
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * PaintEvent e = new PaintEvent(new Component(){},
+ * PaintEvent.PAINT, new Rectangle(0, 0, 10, 20));
+ * System.out.println(e);
+ */
+
+ String typeString = null;
+
+ switch (id) {
+ case PAINT:
+ typeString = "PAINT"; //$NON-NLS-1$
+ break;
+ case UPDATE:
+ typeString = "UPDATE"; //$NON-NLS-1$
+ break;
+ default:
+ typeString = "unknown type"; //$NON-NLS-1$
+ }
+
+ return typeString + ",updateRect=" + updateRect; //$NON-NLS-1$
+ }
+
+}
diff --git a/awt/java/awt/event/TextEvent.java b/awt/java/awt/event/TextEvent.java
new file mode 100644
index 0000000..e2bfd96
--- /dev/null
+++ b/awt/java/awt/event/TextEvent.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.awt.AWTEvent;
+
+public class TextEvent extends AWTEvent {
+
+ private static final long serialVersionUID = 6269902291250941179L;
+
+ public static final int TEXT_FIRST = 900;
+
+ public static final int TEXT_LAST = 900;
+
+ public static final int TEXT_VALUE_CHANGED = 900;
+
+ public TextEvent(Object src, int id) {
+ super(src, id);
+ }
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * TextEvent e = new TextEvent(new Component(){},
+ * TextEvent.TEXT_VALUE_CHANGED);
+ * System.out.println(e);
+ */
+
+ return (id == TEXT_VALUE_CHANGED) ?
+ "TEXT_VALUE_CHANGED" : "unknown type"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+}
diff --git a/awt/java/awt/event/TextListener.java b/awt/java/awt/event/TextListener.java
new file mode 100644
index 0000000..6c5a671
--- /dev/null
+++ b/awt/java/awt/event/TextListener.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface TextListener extends EventListener {
+
+ public void textValueChanged(TextEvent e);
+
+}
+
diff --git a/awt/java/awt/event/WindowAdapter.java b/awt/java/awt/event/WindowAdapter.java
new file mode 100644
index 0000000..9d4b377
--- /dev/null
+++ b/awt/java/awt/event/WindowAdapter.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+public abstract class WindowAdapter implements WindowListener, WindowStateListener, WindowFocusListener {
+
+ public WindowAdapter() {
+ }
+
+ public void windowActivated(WindowEvent e) {
+ }
+
+ public void windowClosed(WindowEvent e) {
+ }
+
+ public void windowClosing(WindowEvent e) {
+ }
+
+ public void windowDeactivated(WindowEvent e) {
+ }
+
+ public void windowDeiconified(WindowEvent e) {
+ }
+
+ public void windowGainedFocus(WindowEvent e) {
+ }
+
+ public void windowIconified(WindowEvent e) {
+ }
+
+ public void windowLostFocus(WindowEvent e) {
+ }
+
+ public void windowOpened(WindowEvent e) {
+ }
+
+ public void windowStateChanged(WindowEvent e) {
+ }
+
+}
diff --git a/awt/java/awt/event/WindowEvent.java b/awt/java/awt/event/WindowEvent.java
new file mode 100644
index 0000000..65a30e4
--- /dev/null
+++ b/awt/java/awt/event/WindowEvent.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+
+//???AWT
+//import java.awt.Window;
+//import java.awt.Frame;
+
+public class WindowEvent extends ComponentEvent {
+
+ private static final long serialVersionUID = -1567959133147912127L;
+
+ public static final int WINDOW_FIRST = 200;
+
+ public static final int WINDOW_OPENED = 200;
+
+ public static final int WINDOW_CLOSING = 201;
+
+ public static final int WINDOW_CLOSED = 202;
+
+ public static final int WINDOW_ICONIFIED = 203;
+
+ public static final int WINDOW_DEICONIFIED = 204;
+
+ public static final int WINDOW_ACTIVATED = 205;
+
+ public static final int WINDOW_DEACTIVATED = 206;
+
+ public static final int WINDOW_GAINED_FOCUS = 207;
+
+ public static final int WINDOW_LOST_FOCUS = 208;
+
+ public static final int WINDOW_STATE_CHANGED = 209;
+
+ public static final int WINDOW_LAST = 209;
+
+ //???AWT: private Window oppositeWindow;
+ private int oldState;
+ private int newState;
+
+ //???AWT
+ /*
+ public WindowEvent(Window source, int id) {
+ this(source, id, null);
+ }
+
+ public WindowEvent(Window source, int id, Window opposite) {
+ this(source, id, opposite, Frame.NORMAL, Frame.NORMAL);
+ }
+
+ public WindowEvent(Window source, int id, int oldState, int newState) {
+ this(source, id, null, oldState, newState);
+ }
+
+ public WindowEvent(Window source, int id, Window opposite,
+ int oldState, int newState) {
+ super(source, id);
+
+ oppositeWindow = opposite;
+ this.oldState = oldState;
+ this.newState = newState;
+ }
+ */
+ //???AWT: Fake constructor
+ public WindowEvent() {
+ super(null, 0);
+ }
+
+ public int getNewState() {
+ return newState;
+ }
+
+ public int getOldState() {
+ return oldState;
+ }
+
+ //???AWT
+ /*
+ public Window getOppositeWindow() {
+ return oppositeWindow;
+ }
+
+ public Window getWindow() {
+ return (Window) source;
+ }
+ */
+
+ @Override
+ public String paramString() {
+ /* The format is based on 1.5 release behavior
+ * which can be revealed by the following code:
+ *
+ * WindowEvent e = new WindowEvent(new Frame(),
+ * WindowEvent.WINDOW_OPENED);
+ * System.out.println(e);
+ */
+
+ String typeString = null;
+
+ switch (id) {
+ case WINDOW_OPENED:
+ typeString = "WINDOW_OPENED"; //$NON-NLS-1$
+ break;
+ case WINDOW_CLOSING:
+ typeString = "WINDOW_CLOSING"; //$NON-NLS-1$
+ break;
+ case WINDOW_CLOSED:
+ typeString = "WINDOW_CLOSED"; //$NON-NLS-1$
+ break;
+ case WINDOW_ICONIFIED:
+ typeString = "WINDOW_ICONIFIED"; //$NON-NLS-1$
+ break;
+ case WINDOW_DEICONIFIED:
+ typeString = "WINDOW_DEICONIFIED"; //$NON-NLS-1$
+ break;
+ case WINDOW_ACTIVATED:
+ typeString = "WINDOW_ACTIVATED"; //$NON-NLS-1$
+ break;
+ case WINDOW_DEACTIVATED:
+ typeString = "WINDOW_DEACTIVATED"; //$NON-NLS-1$
+ break;
+ case WINDOW_GAINED_FOCUS:
+ typeString = "WINDOW_GAINED_FOCUS"; //$NON-NLS-1$
+ break;
+ case WINDOW_LOST_FOCUS:
+ typeString = "WINDOW_LOST_FOCUS"; //$NON-NLS-1$
+ break;
+ case WINDOW_STATE_CHANGED:
+ typeString = "WINDOW_STATE_CHANGED"; //$NON-NLS-1$
+ break;
+ default:
+ typeString = "unknown type"; //$NON-NLS-1$
+ }
+
+ //???AWT
+ /*
+ return typeString + ",opposite=" + oppositeWindow + //$NON-NLS-1$
+ ",oldState=" + oldState + ",newState=" + newState; //$NON-NLS-1$ //$NON-NLS-2$
+ */
+ return typeString;
+ }
+
+}
diff --git a/awt/java/awt/event/WindowFocusListener.java b/awt/java/awt/event/WindowFocusListener.java
new file mode 100644
index 0000000..e0200f2
--- /dev/null
+++ b/awt/java/awt/event/WindowFocusListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface WindowFocusListener extends EventListener {
+
+ public void windowGainedFocus(WindowEvent e);
+
+ public void windowLostFocus(WindowEvent e);
+
+}
diff --git a/awt/java/awt/event/WindowListener.java b/awt/java/awt/event/WindowListener.java
new file mode 100644
index 0000000..20a2b08
--- /dev/null
+++ b/awt/java/awt/event/WindowListener.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface WindowListener extends EventListener {
+
+ public void windowActivated(WindowEvent e);
+
+ public void windowClosed(WindowEvent e);
+
+ public void windowClosing(WindowEvent e);
+
+ public void windowDeactivated(WindowEvent e);
+
+ public void windowDeiconified(WindowEvent e);
+
+ public void windowIconified(WindowEvent e);
+
+ public void windowOpened(WindowEvent e);
+
+}
diff --git a/awt/java/awt/event/WindowStateListener.java b/awt/java/awt/event/WindowStateListener.java
new file mode 100644
index 0000000..12dbc20
--- /dev/null
+++ b/awt/java/awt/event/WindowStateListener.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov
+ * @version $Revision$
+ */
+package java.awt.event;
+
+import java.util.EventListener;
+
+public interface WindowStateListener extends EventListener {
+
+ public void windowStateChanged(WindowEvent e);
+
+}
+
diff --git a/awt/java/awt/font/FontRenderContext.java b/awt/java/awt/font/FontRenderContext.java
new file mode 100644
index 0000000..766300d
--- /dev/null
+++ b/awt/java/awt/font/FontRenderContext.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.geom.AffineTransform;
+
+/**
+ * The FontRenderContext class contains the information
+ * about text measurement. Anti-aliasing and fractional-metrics
+ * modes are defined by an application and affect the size of
+ * a character.
+ */
+public class FontRenderContext {
+
+ // Affine transform of this mode
+ /** The transform. */
+ private AffineTransform transform;
+
+ // Is the anti-aliased mode used
+ /** The anti aliased. */
+ private boolean fAntiAliased;
+
+ // Is the fractional metrics used
+ /** The fractional metrics. */
+ private boolean fFractionalMetrics;
+
+
+ /**
+ * Instantiates a new FontRenderContext object with the specified
+ * AffineTransform, anti-aliasing and fractional metrics flags.
+ *
+ * @param trans the AffineTransform.
+ * @param antiAliased the anti-aliasing flag.
+ * @param usesFractionalMetrics the fractional metrics flag.
+ */
+ public FontRenderContext(AffineTransform trans, boolean antiAliased,
+ boolean usesFractionalMetrics) {
+ if (trans != null){
+ transform = new AffineTransform(trans);
+ }
+ fAntiAliased = antiAliased;
+ fFractionalMetrics = usesFractionalMetrics;
+ }
+
+ /**
+ * Instantiates a new FontRenderContext object.
+ */
+ protected FontRenderContext() {
+ }
+
+ /**
+ * Compares the specified Object with current FontRenderContext object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified Object is equal to current
+ * FontRenderContext object.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj != null) {
+ try {
+ return equals((FontRenderContext) obj);
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+ return false;
+
+ }
+
+ /**
+ * Gets the transform which is used for scaling typographical points
+ * to pixels in this FontRenderContext.
+ *
+ * @return the AffineTransform which is used for scaling typographical
+ * points to pixels in this FontRenderContext.
+ */
+ public AffineTransform getTransform() {
+ if (transform != null){
+ return new AffineTransform(transform);
+ }
+ return new AffineTransform();
+ }
+
+ /**
+ * Compares the specified FontRenderContext object with current
+ * FontRenderContext.
+ *
+ * @param frc the FontRenderContext object to be compared.
+ *
+ * @return true, if the specified FontRenderContext object is
+ * equal to current FontRenderContext.
+ */
+ public boolean equals(FontRenderContext frc) {
+ if (this == frc){
+ return true;
+ }
+
+ if (frc == null){
+ return false;
+ }
+
+ if (!frc.getTransform().equals(this.getTransform()) &&
+ !frc.isAntiAliased() == this.fAntiAliased &&
+ !frc.usesFractionalMetrics() == this.fFractionalMetrics){
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if the text fractional metrics are used in
+ * this FontRenderContext.
+ *
+ * @return true, if the text fractional metrics are used in
+ * this FontRenderContext, false otherwise.
+ */
+ public boolean usesFractionalMetrics() {
+ return this.fFractionalMetrics;
+ }
+
+ /**
+ * Returns true if anti-aliasing is used in this FontRenderContext.
+ *
+ * @return true, if is anti-aliasing is used in this FontRenderContext,
+ * false otherwise.
+ */
+ public boolean isAntiAliased() {
+ return this.fAntiAliased;
+ }
+
+ /**
+ * Returns hash code of the FontRenderContext object.
+ *
+ * @return the hash code of the FontRenderContext object.
+ */
+ @Override
+ public int hashCode() {
+ return this.getTransform().hashCode() ^
+ new Boolean(this.fFractionalMetrics).hashCode() ^
+ new Boolean(this.fAntiAliased).hashCode();
+ }
+
+}
+
diff --git a/awt/java/awt/font/GlyphJustificationInfo.java b/awt/java/awt/font/GlyphJustificationInfo.java
new file mode 100644
index 0000000..4c3e02e
--- /dev/null
+++ b/awt/java/awt/font/GlyphJustificationInfo.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GlyphJustificationInfo class provides information about
+ * the glyph's justification properties. There are four justification
+ * properties: weight, priority, absorb, and limit.
+ * <p>
+ * There are two sets of metrics: growing and shrinking.
+ * Growing metrics are used when the glyphs are to be spread apart
+ * to fit a larger width. Shrinking metrics are used when the glyphs
+ * are to be moved together to fit a smaller width.
+ */
+public final class GlyphJustificationInfo {
+
+ /**
+ * The Constant PRIORITY_KASHIDA indicates the highest
+ * justification priority.
+ */
+ public static final int PRIORITY_KASHIDA = 0;
+
+ /**
+ * The Constant PRIORITY_WHITESPACE indicates the second highest
+ * justification priority.
+ */
+ public static final int PRIORITY_WHITESPACE = 1;
+
+ /**
+ * The Constant PRIORITY_INTERCHAR indicates the second lowest
+ * justification priority.
+ */
+ public static final int PRIORITY_INTERCHAR = 2;
+
+ /**
+ * The Constant PRIORITY_NONE indicates the lowest justification
+ * priority.
+ */
+ public static final int PRIORITY_NONE = 3;
+
+ /**
+ * The grow absorb flag indicates if this glyph absorbs all extra
+ * space at this and lower priority levels when it grows.
+ */
+ public final boolean growAbsorb;
+
+ /**
+ * The grow left limit value represents the maximum value by which
+ * the left side of this glyph grows.
+ */
+ public final float growLeftLimit;
+
+ /**
+ * The grow right limit value repesents the maximum value by which
+ * the right side of this glyph grows.
+ */
+ public final float growRightLimit;
+
+ /**
+ * The grow priority value represents the priority level of this
+ * glyph as it is growing.
+ */
+ public final int growPriority;
+
+ /**
+ * The shrink absorb fleg indicates this glyph absorbs all remaining
+ * shrinkage at this and lower priority levels as it shrinks.
+ */
+ public final boolean shrinkAbsorb;
+
+ /**
+ * The shrink left limit value represents the maximum value by which
+ * the left side of this glyph shrinks.
+ */
+ public final float shrinkLeftLimit;
+
+ /**
+ * The shrink right limit value represents the maximum value by which
+ * the right side of this glyph shrinks.
+ */
+ public final float shrinkRightLimit;
+
+ /**
+ * The shrink priority represents the glyth's priority level
+ * as it is shrinking.
+ */
+ public final int shrinkPriority;
+
+ /**
+ * The weight of the glyph.
+ */
+ public final float weight;
+
+ /**
+ * Instantiates a new GlyphJustificationInfo object which contains
+ * glyph's justification properties.
+ *
+ * @param weight the weight of glyph.
+ * @param growAbsorb indicates if this glyph contais all space
+ * at this priority and lower priority levels when it grows.
+ * @param growPriority indicates the priority level of this glyph
+ * when it grows.
+ * @param growLeftLimit indicates the maximum value of which the
+ * left side of this glyph can grow.
+ * @param growRightLimit the maximum value of which the right side of
+ * this glyph can grow.
+ * @param shrinkAbsorb indicates if this glyph contains all remaining
+ * shrinkage at this and lower priority levels when it shrinks.
+ * @param shrinkPriority indicates the glyph's priority level when
+ * it shrinks.
+ * @param shrinkLeftLimit indicates the maximum value of which
+ * the left side of this glyph can shrink.
+ * @param shrinkRightLimit indicates the maximum amount by which
+ * the right side of this glyph can shrink.
+ */
+ public GlyphJustificationInfo(float weight, boolean growAbsorb, int growPriority,
+ float growLeftLimit, float growRightLimit, boolean shrinkAbsorb,
+ int shrinkPriority, float shrinkLeftLimit, float shrinkRightLimit) {
+
+ if (weight < 0) {
+ // awt.19C=weight must be a positive number
+ throw new IllegalArgumentException(Messages.getString("awt.19C")); //$NON-NLS-1$
+ }
+ this.weight = weight;
+
+ if (growLeftLimit < 0) {
+ // awt.19D=growLeftLimit must be a positive number
+ throw new IllegalArgumentException(Messages.getString("awt.19D")); //$NON-NLS-1$
+ }
+ this.growLeftLimit = growLeftLimit;
+
+ if (growRightLimit < 0) {
+ // awt.19E=growRightLimit must be a positive number
+ throw new IllegalArgumentException(Messages.getString("awt.19E")); //$NON-NLS-1$
+ }
+ this.growRightLimit = growRightLimit;
+
+ if ((shrinkPriority < 0) || (shrinkPriority > PRIORITY_NONE)) {
+ // awt.19F=incorrect value for shrinkPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value
+ throw new IllegalArgumentException(Messages.getString("awt.19F")); //$NON-NLS-1$
+ }
+ this.shrinkPriority = shrinkPriority;
+
+ if ((growPriority < 0) || (growPriority > PRIORITY_NONE)) {
+ // awt.200=incorrect value for growPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value
+ throw new IllegalArgumentException(Messages.getString("awt.200")); //$NON-NLS-1$
+ }
+ this.growPriority = growPriority;
+
+ if (shrinkLeftLimit < 0) {
+ // awt.201=shrinkLeftLimit must be a positive number
+ throw new IllegalArgumentException(Messages.getString("awt.201")); //$NON-NLS-1$
+ }
+ this.shrinkLeftLimit = shrinkLeftLimit;
+
+ if (shrinkRightLimit < 0) {
+ // awt.202=shrinkRightLimit must be a positive number
+ throw new IllegalArgumentException(Messages.getString("awt.202")); //$NON-NLS-1$
+ }
+ this.shrinkRightLimit = shrinkRightLimit;
+
+ this.shrinkAbsorb = shrinkAbsorb;
+ this.growAbsorb = growAbsorb;
+ }
+}
diff --git a/awt/java/awt/font/GlyphMetrics.java b/awt/java/awt/font/GlyphMetrics.java
new file mode 100644
index 0000000..d96ef18
--- /dev/null
+++ b/awt/java/awt/font/GlyphMetrics.java
@@ -0,0 +1,248 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The GlyphMetrics class provides information about the size and shape
+ * of a single glyph.
+ * Each glyph has information to specify whether its baseline is horizontal
+ * or vertical as well as information on how it interacts with
+ * other characters in a text, given as one of the
+ * following types: STANDARD, LIGATURE, COMBINING, or COMPONENT.
+ */
+public final class GlyphMetrics {
+
+ // advance width of the glyph character cell
+ /** The advance x. */
+ private float advanceX;
+
+ // advance height of the glyph character cell
+ /** The advance y. */
+ private float advanceY;
+
+ // flag if the glyph horizontal
+ /** The horizontal. */
+ private boolean horizontal;
+
+ // glyph type code
+ /** The glyph type. */
+ private byte glyphType;
+
+ // bounding box for outline of the glyph
+ /** The bounds. */
+ private Rectangle2D.Float bounds;
+
+ /**
+ * The Constant STANDARD indicates a glyph that represents a single
+ * character.
+ */
+ public static final byte STANDARD = 0;
+
+ /**
+ * The Constant LIGATURE indicates a glyph that represents multiple
+ * characters as a ligature.
+ */
+ public static final byte LIGATURE = 1;
+
+ /**
+ * The Constant COMBINING indicates a glyph which has no caret position
+ * between glyphs (for example umlaut).
+ */
+ public static final byte COMBINING = 2;
+
+ /**
+ * The Constant COMPONENT indicates a glyph with no corresponding character
+ * in the backing store.
+ */
+ public static final byte COMPONENT = 3;
+
+ /**
+ * The Constant WHITESPACE indicates a glyph without visual
+ * representation.
+ */
+ public static final byte WHITESPACE = 4;
+
+ /**
+ * Instantiates a new GlyphMetrics object with the specified parameters.
+ *
+ * @param horizontal specifies if metrics are for a horizontal baseline
+ * (true value), or a vertical baseline (false value).
+ * @param advanceX the X component of the glyph's advance.
+ * @param advanceY the Y component of the glyph's advance.
+ * @param bounds the glyph's bounds.
+ * @param glyphType the glyph's type.
+ */
+ public GlyphMetrics(boolean horizontal, float advanceX, float advanceY,
+ Rectangle2D bounds, byte glyphType) {
+ this.horizontal = horizontal;
+ this.advanceX = advanceX;
+ this.advanceY = advanceY;
+
+ this.bounds = new Rectangle2D.Float();
+ this.bounds.setRect(bounds);
+
+ this.glyphType = glyphType;
+ }
+
+ /**
+ * Instantiates a new horizontal GlyphMetrics with the specified parameters.
+ *
+ * @param advanceX the X component of the glyph's advance.
+ * @param bounds the glyph's bounds.
+ * @param glyphType the glyph's type.
+ */
+ public GlyphMetrics(float advanceX, Rectangle2D bounds, byte glyphType) {
+ this.advanceX = advanceX;
+ this.advanceY = 0;
+
+ this.horizontal = true;
+
+ this.bounds = new Rectangle2D.Float();
+ this.bounds.setRect(bounds);
+
+ this.glyphType = glyphType;
+ }
+
+ /**
+ * Gets the glyph's bounds.
+ *
+ * @return glyph's bounds.
+ */
+ public Rectangle2D getBounds2D() {
+ return (Rectangle2D.Float) this.bounds.clone();
+ }
+
+ /**
+ * Checks if this glyph is whitespace or not.
+ *
+ * @return true, if this glyph is whitespace, false otherwise.
+ */
+ public boolean isWhitespace() {
+ return ((this.glyphType & 4) == WHITESPACE);
+ }
+
+ /**
+ * Checks if this glyph is standard or not.
+ *
+ * @return true, if this glyph is standard, false otherwise.
+ */
+ public boolean isStandard() {
+ return ((this.glyphType & 3) == STANDARD);
+ }
+
+ /**
+ * Checks if this glyph is ligature or not.
+ *
+ * @return true, if this glyph is ligature, false otherwise.
+ */
+ public boolean isLigature() {
+ return ((this.glyphType & 3) == LIGATURE);
+ }
+
+ /**
+ * Checks if this glyph is component or not.
+ *
+ * @return true, if this glyph is component, false otherwise.
+ */
+ public boolean isComponent() {
+ return ((this.glyphType & 3) == COMPONENT);
+ }
+
+ /**
+ * Checks if this glyph is combining or not.
+ *
+ * @return true, if this glyph is combining, false otherwise.
+ */
+ public boolean isCombining() {
+ return ((this.glyphType & 3) == COMBINING);
+ }
+
+ /**
+ * Gets the glyph's type.
+ *
+ * @return the glyph's type.
+ */
+ public int getType() {
+ return this.glyphType;
+ }
+
+ /**
+ * Gets the distance from the right (for horizontal) or
+ * bottom (for vertical) of the glyph bounds to the advance.
+ *
+ * @return the distance from the right (for horizontal) or
+ * bottom (for vertical) of the glyph bounds to the advance.
+ */
+ public float getRSB() {
+ if (this.horizontal) {
+ return this.advanceX - this.bounds.x - (float)this.bounds.getWidth();
+ }
+ return this.advanceY - this.bounds.y - (float)this.bounds.getHeight();
+ }
+
+ /**
+ * Gets the distance from 0, 0 to the left (for horizontal)
+ * or top (for vertical) of the glyph bounds.
+ *
+ * @return the distance from 0, 0 to the left (for horizontal)
+ * or top (for vertical) of the glyph bounds.
+ */
+ public float getLSB() {
+ if (this.horizontal) {
+ return this.bounds.x;
+ }
+ return this.bounds.y;
+ }
+
+ /**
+ * Gets the Y component of the glyph's advance.
+ *
+ * @return the Y component of the glyph's advance.
+ */
+ public float getAdvanceY() {
+ return this.advanceY;
+ }
+
+ /**
+ * Gets the X component of the glyph's advance.
+ *
+ * @return the X component of the glyph's advance.
+ */
+ public float getAdvanceX() {
+ return this.advanceX;
+ }
+
+ /**
+ * Gets the glyph's advance along the baseline.
+ *
+ * @return the glyph's advance.
+ */
+ public float getAdvance() {
+ if (this.horizontal) {
+ return this.advanceX;
+ }
+ return this.advanceY;
+ }
+
+}
+
diff --git a/awt/java/awt/font/GlyphVector.java b/awt/java/awt/font/GlyphVector.java
new file mode 100644
index 0000000..b3c9406
--- /dev/null
+++ b/awt/java/awt/font/GlyphVector.java
@@ -0,0 +1,394 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.Font;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The GlyphVector class contains a collection of glyphs with geometric
+ * information and each glyph's location. Each GlyphVector can be associated
+ * with only one Font. GlyphVector contains the following properties for
+ * each glyph:
+ * <ul>
+ * <li>the glyph position;</li>
+ * <li>the transform of the glyph;</li>
+ * <li>the metrics of the glyph in the context of the GlyphVector.</li>
+ * </ul>
+ */
+public abstract class GlyphVector implements Cloneable {
+
+ /**
+ * The Constant FLAG_HAS_TRANSFORMS indicates that this GlyphVector
+ * has per-glyph transforms.
+ */
+ public static final int FLAG_HAS_TRANSFORMS = 1;
+
+ /**
+ * The Constant FLAG_HAS_POSITION_ADJUSTMENTS indicates that
+ * the GlyphVector has per-glyph position adjustments.
+ */
+ public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2;
+
+ /**
+ * The Constant FLAG_RUN_RTL indicates that this GlyphVector has a
+ * right to left run direction.
+ */
+ public static final int FLAG_RUN_RTL = 4;
+
+ /**
+ * The Constant FLAG_COMPLEX_GLYPHS indicates that this GlyphVector
+ * has a complex glyph to char mapping.
+ */
+ public static final int FLAG_COMPLEX_GLYPHS = 8;
+
+ /**
+ * The Constant FLAG_MASK indicates a mask for supported flags
+ * from getLayoutFlags.
+ */
+ public static final int FLAG_MASK = 15; // (|) mask of other flags
+
+ /**
+ * Instantiates a new GlyphVector.
+ */
+ public GlyphVector() {
+ }
+
+ /**
+ * Gets the pixel bounds of the GlyphVector when rendered
+ * at the specified location with the specified FontRenderContext.
+ *
+ * @param frc the FontRenderContext.
+ * @param x the X coordinate of the GlyphVector's location.
+ * @param y the Y coordinate of the GlyphVector's location.
+ *
+ * @return the pixel bounds
+ */
+ public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) {
+ // default implementation - integer Rectangle, that encloses visual
+ // bounds rectangle
+ Rectangle2D visualRect = getVisualBounds();
+
+ int minX = (int)Math.floor(visualRect.getMinX() + x);
+ int minY = (int)Math.floor(visualRect.getMinY() + y);
+ int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX;
+ int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY;
+
+ return new Rectangle(minX, minY, width, height);
+ }
+
+ /**
+ * Gets the pixel bounds of the glyph with the specified index in
+ * this GlyphVector which is rendered with the specified
+ * FontRenderContext at the specified location.
+ *
+ * @param index the glyph index in this GlyphVector.
+ * @param frc the FontRenderContext.
+ * @param x the X coordinate of the GlyphVector's location.
+ * @param y the Y coordinate of the GlyphVector's location.
+ *
+ * @return a Rectangle bounds.
+ */
+ public Rectangle getGlyphPixelBounds(int index, FontRenderContext frc,
+ float x, float y) {
+ Rectangle2D visualRect = getGlyphVisualBounds(index).getBounds2D();
+
+ int minX = (int)Math.floor(visualRect.getMinX() + x);
+ int minY = (int)Math.floor(visualRect.getMinY() + y);
+ int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX;
+ int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY;
+
+ return new Rectangle(minX, minY, width, height);
+ }
+
+ /**
+ * Gets the visual bounds of the GlyphVector.
+ *
+ * @return the visual bounds of the GlyphVector.
+ */
+ public abstract Rectangle2D getVisualBounds();
+
+ /**
+ * Gets the logical bounds of the GlyphVector.
+ *
+ * @return the logical bounds of the GlyphVector.
+ */
+ public abstract Rectangle2D getLogicalBounds();
+
+ /**
+ * Sets the position of the specified glyph in this GlyphVector.
+ *
+ * @param glyphIndex the glyph index in this GlyphVector.
+ * @param newPos the new position of the glyph at the specified glyphIndex.
+ */
+ public abstract void setGlyphPosition(int glyphIndex, Point2D newPos);
+
+ /**
+ * Gets the position of the specified glyph in this GlyphVector.
+ *
+ * @param glyphIndex the glyph index in this GlyphVector.
+ *
+ * @return the position of the specified glyph in this GlyphVector.
+ */
+ public abstract Point2D getGlyphPosition(int glyphIndex);
+
+ /**
+ * Sets the affine transform to a glyph with the specified index
+ * in this GlyphVector.
+ *
+ * @param glyphIndex the glyth index in this GlyphVector.
+ * @param trans the AffineTransform to be assigned to the
+ * specified glyph.
+ */
+ public abstract void setGlyphTransform(int glyphIndex,
+ AffineTransform trans);
+
+ /**
+ * Gets the transform of the specified glyph in this GlyphVector.
+ *
+ * @param glyphIndex the glyph index in this GlyphVector.
+ *
+ * @return the new transform of the glyph.
+ */
+ public abstract AffineTransform getGlyphTransform(int glyphIndex);
+
+ /**
+ * Compares this GlyphVector with the specified GlyphVector objects.
+ *
+ * @param glyphVector the GlyphVector object to be compared.
+ *
+ * @return true, if this GlyphVector is equal to the specified GlyphVector
+ * object, false otherwise.
+ */
+ public abstract boolean equals(GlyphVector glyphVector);
+
+ /**
+ * Gets the metrics of the glyph with the specified index
+ * in this GlyphVector.
+ *
+ * @param glyphIndex index in this GlyphVector.
+ *
+ * @return the metrics of the glyph with the specified index
+ * in this GlyphVector.
+ */
+ public abstract GlyphMetrics getGlyphMetrics(int glyphIndex);
+
+ /**
+ * Gets the justification information of the glyph
+ * whose index is specified.
+ *
+ * @param glyphIndex the glyph index.
+ *
+ * @return the GlyphJustificationInfo for the specified glyph.
+ */
+ public abstract GlyphJustificationInfo getGlyphJustificationInfo(
+ int glyphIndex);
+
+ /**
+ * Gets the FontRenderContext of this GlyphVector.
+ *
+ * @return the FontRenderContext of this GlyphVector.
+ */
+ public abstract FontRenderContext getFontRenderContext();
+
+ /**
+ * Gets a Shape object which defines the visual representation
+ * of the specified glyph in this GlyphVector, translated a
+ * distance of x in the X direction and y in the Y direction.
+ *
+ * @param glyphIndex the glyth index in this GlyphVector.
+ * @param x the distance in the X direction to translate the
+ * shape object before returning it.
+ * @param y the distance in the Y direction to translate the
+ * shape object before returning it.
+ *
+ * @return a Shape object which represents the visual representation
+ * of the specified glyph in this GlyphVector - glyph outline.
+ */
+ public Shape getGlyphOutline(int glyphIndex, float x, float y) {
+ Shape initialShape = getGlyphOutline(glyphIndex);
+ AffineTransform trans = AffineTransform.getTranslateInstance(x, y);
+ return trans.createTransformedShape(initialShape);
+ }
+
+ /**
+ * Gets the visual bounds of the specified glyph in the GlyphVector.
+ *
+ * @param glyphIndex the glyph index in this GlyphVector.
+ *
+ * @return the glyph visual bounds of the glyph with the specified
+ * index in the GlyphVector.
+ */
+ public abstract Shape getGlyphVisualBounds(int glyphIndex);
+
+ /**
+ * Gets a Shape object which defines the visual representation
+ * of the specified glyph in this GlyphVector.
+ *
+ * @param glyphIndex the glyth index in this GlyphVector.
+ *
+ * @return a Shape object which represents the visual representation
+ * of the specified glyph in this GlyphVector - glyph outline.
+ */
+ public abstract Shape getGlyphOutline(int glyphIndex);
+
+ /**
+ * Gets the logical bounds of the specified glyph in
+ * the GlyphVector.
+ *
+ * @param glyphIndex the index in this GlyphVector of the glyph from which
+ * to retrieve its logical bounds
+ *
+ * @return the logical bounds of the specified glyph in
+ * the GlyphVector.
+ */
+ public abstract Shape getGlyphLogicalBounds(int glyphIndex);
+
+ /**
+ * Gets the visual representation of this GlyphVector rendered in
+ * x, y location as a Shape object.
+ *
+ * @param x the x coordinate of the GlyphVector.
+ * @param y the y coordinate of the GlyphVector.
+ *
+ * @return the visual representation of this GlyphVector as a Shape object.
+ */
+ public abstract Shape getOutline(float x, float y);
+
+ /**
+ * Gets the visual representation of this GlyphVector as a Shape object.
+ *
+ * @return the visual representation of this GlyphVector as a Shape object.
+ */
+ public abstract Shape getOutline();
+
+ /**
+ * Gets the font of this GlyphVector.
+ *
+ * @return the font of this GlyphVector.
+ */
+ public abstract Font getFont();
+
+ /**
+ * Gets an array of the glyph codes of the specified glyphs.
+ *
+ * @param beginGlyphIndex the index into this GlyphVector at which
+ * to start retrieving glyph codes.
+ * @param numEntries the number of glyph codes.
+ * @param codeReturn the array into which the resulting
+ * glyphcodes will be written.
+ *
+ * @return the array of the glyph codes.
+ */
+ public abstract int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
+ int[] codeReturn);
+
+ /**
+ * Gets an array of the character indices of
+ * the specified glyphs.
+ *
+ * @param beginGlyphIndex the index of the first glyph to return information for.
+ * @param numEntries the number of glyph indices to return.
+ * @param codeReturn the array into which the resulting character
+ * indices will be written.
+ *
+ * @return an array of character indices for the specifies glyphs.
+ */
+ public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries,
+ int[] codeReturn) {
+ if (codeReturn == null) {
+ codeReturn = new int[numEntries];
+ }
+
+ for (int i = 0; i < numEntries; i++){
+ codeReturn[i] = getGlyphCharIndex(i+beginGlyphIndex);
+ }
+ return codeReturn;
+ }
+
+ /**
+ * Gets an array of the positions of the specified glyphs in
+ * this GlyphVector.
+ *
+ * @param beginGlyphIndex the index of the first glyph to return information for.
+ * @param numEntries the number of glyphs to return information for.
+ * @param positionReturn the array where the result will be stored.
+ *
+ * @return an array of glyph positions.
+ */
+ public abstract float[] getGlyphPositions(int beginGlyphIndex,
+ int numEntries, float[] positionReturn);
+
+ /**
+ * Gets the glyph code of the specified glyph.
+ *
+ * @param glyphIndex the index in this GlyphVector which corresponds
+ * to the glyph from which to retrieve the glyphcode.
+ *
+ * @return the glyphcode of the specified glyph.
+ */
+ public abstract int getGlyphCode(int glyphIndex);
+
+ /**
+ * Gets the first logical character's index of the specified glyph.
+ *
+ * @param glyphIndex the glyph index.
+ *
+ * @return the the first logical character's index.
+ */
+ public int getGlyphCharIndex(int glyphIndex){
+ // default implemetation one-to-one
+ return glyphIndex;
+ }
+
+ /**
+ * Sets default layout to this GlyphVector.
+ */
+ public abstract void performDefaultLayout();
+
+ /**
+ * Gets the number of glyphs in the GlyphVector.
+ *
+ * @return the number of glyphs in the GlyphVector.
+ */
+ public abstract int getNumGlyphs();
+
+ /**
+ * Gets flags which describe the global state of the GlyphVector.
+ * The default implementation returns 0.
+ *
+ * @return the layout flags
+ */
+ public int getLayoutFlags(){
+ // default implementation - returned value is 0
+ return 0;
+ }
+
+}
+
diff --git a/awt/java/awt/font/GraphicAttribute.java b/awt/java/awt/font/GraphicAttribute.java
new file mode 100644
index 0000000..2f41951
--- /dev/null
+++ b/awt/java/awt/font/GraphicAttribute.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The GraphicAttribute abstract class provides an opportunity to
+ * insert graphical elements in printed text.
+ */
+public abstract class GraphicAttribute {
+
+ /**
+ * The Constant TOP_ALIGNMENT indicates using the top line to
+ * calculate placement of graphics.
+ */
+ public static final int TOP_ALIGNMENT = -1;
+
+ /**
+ * The Constant BOTTOM_ALIGNMENT indicates using the bottom line to
+ * calculate placement of graphics.
+ */
+ public static final int BOTTOM_ALIGNMENT = -2;
+
+ /**
+ * The Constant ROMAN_BASELINE indicates the placement of the roman
+ * baseline with respect to the graphics origin.
+ */
+ public static final int ROMAN_BASELINE = 0;
+
+ /**
+ * The Constant CENTER_BASELINE indicates the placement of the center
+ * baseline with respect to the graphics origin.
+ */
+ public static final int CENTER_BASELINE = 1;
+
+ /**
+ * The Constant HANGING_BASELINE indicates the placement of the hanging
+ * baseline with respect to the graphics origin.
+ */
+ public static final int HANGING_BASELINE = 2;
+
+ // the alignment of this GraphicAttribute
+ /** The alignment. */
+ private int alignment;
+
+ /**
+ * Instantiates a new graphic attribute with the specified alignment.
+ *
+ * @param align the specified alignment.
+ */
+ protected GraphicAttribute(int align) {
+ if ((align < BOTTOM_ALIGNMENT) || (align > HANGING_BASELINE)) {
+ // awt.198=Illegal alignment argument
+ throw new IllegalArgumentException(Messages.getString("awt.198")); //$NON-NLS-1$
+ }
+ this.alignment = align;
+ }
+
+ /**
+ * Draws the GraphicAttribute at the specified location.
+ *
+ * @param graphics the Graphics.
+ * @param x the X coordinate of GraphicAttribute location.
+ * @param y the Y coordinate of GraphicAttribute location.
+ */
+ public abstract void draw(Graphics2D graphics, float x, float y);
+
+ /**
+ * Gets the GraphicAttribute's advance. It's the distance from the point
+ * at which the graphic is rendered and the point where the next character
+ * or graphic is rendered.
+ *
+ * @return the GraphicAttribute's advance.
+ */
+ public abstract float getAdvance();
+
+ /**
+ * Gets the alignment of this GraphicAttribute.
+ *
+ * @return the alignment of this GraphicAttribute.
+ */
+ public final int getAlignment() {
+ return this.alignment;
+ }
+
+ /**
+ * Gets the ascent of this GraphicAttribute.
+ *
+ * @return the ascent of this GraphicAttribute.
+ */
+ public abstract float getAscent();
+
+ /**
+ * Gets the bounds of this GraphicAttribute.
+ *
+ * @return the bounds of this GraphicAttribute.
+ */
+ public Rectangle2D getBounds() {
+ float ascent = getAscent();
+ float advance = getAdvance();
+ float descent = getDescent();
+
+ // Default implementation - see API documentation.
+ return new Rectangle2D.Float(0, -ascent, advance, ascent + descent);
+ }
+
+ /**
+ * Gets the descent of this GraphicAttribute.
+ *
+ * @return the descent of this GraphicAttribute.
+ */
+ public abstract float getDescent();
+
+ /**
+ * Gets the GlyphJustificationInfo of this GraphicAttribute.
+ *
+ * @return the GlyphJustificationInfo of this GraphicAttribute.
+ */
+ public GlyphJustificationInfo getJustificationInfo() {
+
+ /* Default implementation.
+ * Since documentation doesn't describe default values,
+ * they were calculated based on 1.5 release
+ * behavior and can be obtained using next test sample:
+ *
+ * // Create GraphicAttribute class implementation
+ * public class MyGraphicAttribute extends GraphicAttribute {
+ * protected MyGraphicAttribute(int align) {
+ * super(align);
+ * }
+ *
+ * public float getDescent() {
+ * return 0;
+ * }
+ *
+ * public float getAdvance() {
+ * return 1;
+ * }
+ *
+ * public void draw(Graphics2D g2, float x, float y) {
+ * }
+ *
+ * public float getAscent() {
+ * return 0;
+ * }
+ * }
+ *
+ * MyGraphicAttribute myGA = gat.new MyGraphicAttribute(0);
+ * // print justification parameters
+ * System.out.println(myGA.getJustificationInfo().growAbsorb);
+ * System.out.println(myGA.getJustificationInfo().shrinkAbsorb);
+ * System.out.println(myGA.getJustificationInfo().growLeftLimit);
+ * System.out.println(myGA.getJustificationInfo().growPriority);
+ * System.out.println(myGA.getJustificationInfo().growRightLimit);
+ * System.out.println(myGA.getJustificationInfo().shrinkLeftLimit);
+ * System.out.println(myGA.getJustificationInfo().shrinkPriority);
+ * System.out.println(myGA.getJustificationInfo().shrinkRightLimit);
+ * System.out.println(myGA.getJustificationInfo().weight);
+ */
+ float advance = getAdvance();
+ return new GlyphJustificationInfo(
+ advance,
+ false,
+ GlyphJustificationInfo.PRIORITY_INTERCHAR,
+ advance / 3,
+ advance / 3,
+ false,
+ GlyphJustificationInfo.PRIORITY_WHITESPACE,
+ 0,
+ 0);
+ }
+
+}
+
diff --git a/awt/java/awt/font/ImageGraphicAttribute.java b/awt/java/awt/font/ImageGraphicAttribute.java
new file mode 100644
index 0000000..41f90b8
--- /dev/null
+++ b/awt/java/awt/font/ImageGraphicAttribute.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The ImageGraphicAttribute class provides an opportunity to insert
+ * images to a text.
+ */
+public final class ImageGraphicAttribute extends GraphicAttribute {
+
+ // Image object rendered by this ImageGraphicAttribute
+ /** The image. */
+ private Image fImage;
+
+ // X coordinate of the origin point
+ /** The origin x. */
+ private float fOriginX;
+
+ // Y coordinate of the origin point
+ /** The origin y. */
+ private float fOriginY;
+
+ // the width of the image object
+ /** The img width. */
+ private float fImgWidth;
+
+ // the height of the image object
+ /** The img height. */
+ private float fImgHeight;
+
+ /**
+ * Instantiates a new ImageGraphicAttribute with the specified image,
+ * alignment and origins.
+ *
+ * @param image the Image to be rendered by ImageGraphicAttribute.
+ * @param alignment the alignment of the ImageGraphicAttribute.
+ * @param originX the origin X coordinate in the image of
+ * ImageGraphicAttribute.
+ * @param originY the origin Y coordinate in the image of
+ * ImageGraphicAttribute.
+ */
+ public ImageGraphicAttribute(Image image, int alignment, float originX,
+ float originY) {
+ super(alignment);
+
+ this.fImage = image;
+ this.fOriginX = originX;
+ this.fOriginY = originY;
+
+ this.fImgWidth = fImage.getWidth(null);
+ this.fImgHeight = fImage.getHeight(null);
+
+ }
+
+ /**
+ * Instantiates a new ImageGraphicAttribute with the specified image and
+ * alignment.
+ *
+ * @param image the Image to be rendered by ImageGraphicAttribute.
+ * @param alignment the alignment of the ImageGraphicAttribute.
+ */
+ public ImageGraphicAttribute(Image image, int alignment) {
+ this(image, alignment, 0, 0);
+ }
+
+ /**
+ * Returns a hash code of this ImageGraphicAttribute object.
+ *
+ * @return the hash code of this ImageGraphicAttribute object.
+ */
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+
+ hash.append(fImage.hashCode());
+ hash.append(getAlignment());
+ return hash.hashCode();
+ }
+
+ /**
+ * Compares the specified ImageGraphicAttribute object with this
+ * ImageGraphicAttribute object.
+ *
+ * @param iga the ImageGraphicAttribute object to be compared.
+ *
+ * @return true, if the specified ImageGraphicAttribute object is equal to
+ * this ImageGraphicAttribute object, false otherwise.
+ */
+ public boolean equals(ImageGraphicAttribute iga) {
+ if (iga == null) {
+ return false;
+ }
+
+ if (iga == this) {
+ return true;
+ }
+
+ return (fOriginX == iga.fOriginX &&
+ fOriginY == iga.fOriginY &&
+ getAlignment() == iga.getAlignment() &&
+ fImage.equals(iga.fImage));
+ }
+
+ /**
+ * Compares the specified Object with this ImageGraphicAttribute object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified Object is equal to this
+ * ImageGraphicAttribute object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ try {
+ return equals((ImageGraphicAttribute) obj);
+ }
+ catch(ClassCastException e) {
+ return false;
+ }
+
+ }
+
+ @Override
+ public void draw(Graphics2D g2, float x, float y) {
+ g2.drawImage(fImage, (int)(x - fOriginX), (int)(y - fOriginY), null);
+ }
+
+ /**
+ * @see java.awt.font.GraphicAttribute#getAdvance()
+ */
+ @Override
+ public float getAdvance() {
+ return Math.max(0, fImgWidth - fOriginX);
+ }
+
+ @Override
+ public float getAscent() {
+ return Math.max(0, fOriginY);
+ }
+
+ @Override
+ public Rectangle2D getBounds() {
+ return new Rectangle2D.Float(-fOriginX, -fOriginY, fImgWidth, fImgHeight);
+ }
+
+ /**
+ * @see java.awt.font.GraphicAttribute#getDescent()
+ */
+ @Override
+ public float getDescent() {
+ return Math.max(0, fImgHeight - fOriginY);
+ }
+
+}
+
diff --git a/awt/java/awt/font/LineBreakMeasurer.java b/awt/java/awt/font/LineBreakMeasurer.java
new file mode 100644
index 0000000..efce615
--- /dev/null
+++ b/awt/java/awt/font/LineBreakMeasurer.java
@@ -0,0 +1,231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.text.AttributedCharacterIterator;
+//???AWT: import java.text.BreakIterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The class LineBreakMeasurer provides methods to measure the graphical
+ * representation of a text in order to determine where to add line
+ * breaks so the resulting line of text fits its wrapping width.
+ * The wrapping width defines the visual width of the paragraph.
+ */
+public final class LineBreakMeasurer {
+
+ /** The tm. */
+ private TextMeasurer tm = null;
+ //???AWT private BreakIterator bi = null;
+ /** The position. */
+ private int position = 0;
+
+ /** The maxpos. */
+ int maxpos = 0;
+
+ /**
+ * Instantiates a new LineBreakMeasurer object for the specified text.
+ *
+ * @param text the AttributedCharacterIterator object which contains
+ * text with at least one character.
+ * @param frc the FontRenderContext represented information
+ * about graphic device.
+ */
+ public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc) {
+ //???AWT: this(text, BreakIterator.getLineInstance(), frc);
+ }
+
+ /* ???AWT
+ public LineBreakMeasurer(
+ AttributedCharacterIterator text,
+ BreakIterator bi,
+ FontRenderContext frc
+ ) {
+ tm = new TextMeasurer(text, frc);
+ this.bi = bi;
+ this.bi.setText(text);
+ position = text.getBeginIndex();
+ maxpos = tm.aci.getEndIndex();
+ }
+ */
+
+ /**
+ * Deletes a character from the specified position of the text,
+ * updates this LineBreakMeasurer object.
+ *
+ * @param newText the new text.
+ * @param pos the posion of the character which is deleted.
+ */
+ public void deleteChar(AttributedCharacterIterator newText, int pos) {
+ tm.deleteChar(newText, pos);
+ //???AWT: bi.setText(newText);
+
+ position = newText.getBeginIndex();
+
+ maxpos--;
+ }
+
+ /**
+ * Gets current position of this LineBreakMeasurer.
+ *
+ * @return current position of this LineBreakMeasurer
+ */
+ public int getPosition() {
+ return position;
+ }
+
+ /**
+ * Insertes a character at the specified position in the text,
+ * updates this LineBreakMeasurer object.
+ *
+ * @param newText the new text.
+ * @param pos the posion of the character which is inserted.
+ */
+ public void insertChar(AttributedCharacterIterator newText, int pos) {
+ tm.insertChar(newText, pos);
+// ???AWT: bi.setText(newText);
+
+ position = newText.getBeginIndex();
+
+ maxpos++;
+ }
+
+ /**
+ * Returns the next line of text, updates current position in this
+ * LineBreakMeasurer.
+ *
+ * @param wrappingWidth the maximum visible line width.
+ * @param offsetLimit the limit point withing the text indicating
+ * that no further text should be included on the line; the paragraph break.
+ * @param requireNextWord if true, null is returned (the entire word at the current
+ * position does not fit within the wrapping width);
+ * if false, a valid layout is returned that includes at least the
+ * character at the current position.
+ *
+ * @return the next TextLayout which begins at the current position and
+ * represents the next line of text with width wrappingWidth, null is
+ * returned if the entire word at the current position does not fit within
+ * the wrapping width.
+ */
+ public TextLayout nextLayout(float wrappingWidth, int offsetLimit, boolean requireNextWord) {
+ if (position == maxpos) {
+ return null;
+ }
+
+ int nextPosition = nextOffset(wrappingWidth, offsetLimit, requireNextWord);
+
+ if (nextPosition == position) {
+ return null;
+ }
+ TextLayout layout = tm.getLayout(position, nextPosition);
+ position = nextPosition;
+ return layout;
+ }
+
+ /**
+ * Returns the next line of text.
+ *
+ * @param wrappingWidth the maximum visible line width.
+ *
+ * @return the next line of text.
+ */
+ public TextLayout nextLayout(float wrappingWidth) {
+ return nextLayout(wrappingWidth, maxpos, false);
+ }
+
+ /**
+ * Returns the end position of the next line of text.
+ *
+ * @param wrappingWidth the maximum visible line width.
+ *
+ * @return the end position of the next line of text.
+ */
+ public int nextOffset(float wrappingWidth) {
+ return nextOffset(wrappingWidth, maxpos, false);
+ }
+
+ /**
+ * Returns the end position of the next line of text.
+ *
+ * @param wrappingWidth the maximum visible line width.
+ * @param offsetLimit the limit point withing the text indicating
+ * that no further text should be included on the line; the paragraph break.
+ * @param requireNextWord if true, the current position is returned
+ * if the entire next word does not fit within wrappingWidth;
+ * if false, the offset returned is at least one greater than the current
+ * position.
+ *
+ * @return the end position of the next line of text.
+ *
+ * @throws IllegalArgumentException if the offsetLimit is less than
+ * the current position.
+ */
+ public int nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord) {
+ if (offsetLimit <= position) {
+ // awt.203=Offset limit should be greater than current position.
+ throw new IllegalArgumentException(Messages.getString("awt.203")); //$NON-NLS-1$
+ }
+
+ if (position == maxpos) {
+ return position;
+ }
+
+ int breakPos = tm.getLineBreakIndex(position, wrappingWidth);
+ int correctedPos = breakPos;
+
+ // This check is required because bi.preceding(maxpos) throws an exception
+ /* ???AWT
+ if (breakPos == maxpos) {
+ correctedPos = maxpos;
+ } else if (Character.isWhitespace(bi.getText().setIndex(breakPos))) {
+ correctedPos = bi.following(breakPos);
+ } else {
+ correctedPos = bi.preceding(breakPos);
+ }
+ */
+
+ if (position >= correctedPos) {
+ if (requireNextWord) {
+ correctedPos = position;
+ } else {
+ correctedPos = Math.max(position+1, breakPos);
+ }
+ }
+
+ return Math.min(correctedPos, offsetLimit);
+ }
+
+ /**
+ * Sets the new position of this LineBreakMeasurer.
+ *
+ * @param pos the new position of this LineBreakMeasurer.
+ */
+ public void setPosition(int pos) {
+ if (tm.aci.getBeginIndex() > pos || maxpos < pos) {
+ // awt.33=index is out of range
+ throw new IllegalArgumentException(Messages.getString("awt.33")); //$NON-NLS-1$
+ }
+ position = pos;
+ }
+}
+
diff --git a/awt/java/awt/font/LineMetrics.java b/awt/java/awt/font/LineMetrics.java
new file mode 100644
index 0000000..2857187
--- /dev/null
+++ b/awt/java/awt/font/LineMetrics.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+/**
+ * The LineMetrics class provides information such as concerning how the text
+ * is positioned with respect to the base line, such as ascent, descent,
+ * and leading.
+ *
+ */
+public abstract class LineMetrics {
+
+ /**
+ * Gets the baseline offsets of the text according to the
+ * the baseline of this text.
+ *
+ * @return the baseline offsets of the text according to the
+ * the baseline of this text.
+ */
+ public abstract float[] getBaselineOffsets();
+
+ /**
+ * Gets the number of characters of the text.
+ *
+ * @return the number of characters of the text.
+ */
+ public abstract int getNumChars();
+
+ /**
+ * Gets the baseline index, returns one of the following
+ * index: ROMAN_BASELINE, CENTER_BASELINE, HANGING_BASELINE.
+ *
+ * @return the baseline index: ROMAN_BASELINE, CENTER_BASELINE
+ * or HANGING_BASELINE.
+ */
+ public abstract int getBaselineIndex();
+
+ /**
+ * Gets the thickness of the underline.
+ *
+ * @return the thickness of the underline.
+ */
+ public abstract float getUnderlineThickness();
+
+ /**
+ * Gets the offset of the underline.
+ *
+ * @return the offset of the underline.
+ */
+ public abstract float getUnderlineOffset();
+
+ /**
+ * Gets the thickness of strike through line.
+ *
+ * @return the thickness of strike through line.
+ */
+ public abstract float getStrikethroughThickness();
+
+ /**
+ * Gets the offset of the strike through line.
+ *
+ * @return the offset of the strike through line.
+ */
+ public abstract float getStrikethroughOffset();
+
+ /**
+ * Gets the leading of the text.
+ *
+ * @return the leading of the text.
+ */
+ public abstract float getLeading();
+
+ /**
+ * Gets the height of the text as a sum of the ascent, the descent
+ * and the leading.
+ *
+ * @return the height of the text as a sum of the ascent, the descent
+ * and the leading.
+ */
+ public abstract float getHeight();
+
+ /**
+ * Gets the descent of the text.
+ *
+ * @return the descent of the text.
+ */
+ public abstract float getDescent();
+
+ /**
+ * Gets the ascent of the text.
+ *
+ * @return the ascent of the text.
+ */
+ public abstract float getAscent();
+
+}
+
diff --git a/awt/java/awt/font/MultipleMaster.java b/awt/java/awt/font/MultipleMaster.java
new file mode 100644
index 0000000..773bfcf
--- /dev/null
+++ b/awt/java/awt/font/MultipleMaster.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.Font;
+
+/**
+ * The MultipleMaster interface provides methods to manipulate MultipleMaster
+ * type fonts and retrieve graphical and design data from them.
+ */
+public interface MultipleMaster {
+
+ /**
+ * Derives a new multiple master font based on the specified
+ * parameters.
+ *
+ * @param glyphWidths float array which represents width of each glyph
+ * in font space.
+ * @param avgStemWidth the average stem width in font space.
+ * @param typicalCapHeight the typical upper case char height.
+ * @param typicalXHeight the typical lower case char height.
+ * @param italicAngle the slope angle for italics.
+ *
+ * @return a MultipleMaster font.
+ */
+ public Font deriveMMFont(float[] glyphWidths, float avgStemWidth,
+ float typicalCapHeight, float typicalXHeight, float italicAngle);
+
+ /**
+ * Derives a new multiple master font based on the design axis values
+ * contained in the specified array.
+ *
+ * @param axes an float array which contains axis values.
+ *
+ * @return a MultipleMaster font.
+ */
+ public Font deriveMMFont(float[] axes);
+
+ /**
+ * Gets default design values for the axes.
+ *
+ * @return the default design values for the axes.
+ */
+ public float[] getDesignAxisDefaults();
+
+ /**
+ * Gets the array of design axis names.
+ *
+ * @return the array of design axis names.
+ */
+ public String[] getDesignAxisNames();
+
+ /**
+ * Gets the array of design axis ranges.
+ *
+ * @return the array of design axis ranges.
+ */
+ public float[] getDesignAxisRanges();
+
+ /**
+ * Gets the number of multiple master design controls.
+ *
+ * @return the number of multiple master design controls.
+ */
+ public int getNumDesignAxes();
+
+}
+
diff --git a/awt/java/awt/font/OpenType.java b/awt/java/awt/font/OpenType.java
new file mode 100644
index 0000000..53cb6c0
--- /dev/null
+++ b/awt/java/awt/font/OpenType.java
@@ -0,0 +1,410 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+/**
+ * The OpenType interface provides constants and methods for getting
+ * instance data for fonts of type OpenType and TrueType. For more information,
+ * see the <a href="http://partners.adobe.com/public/developer/opentype/index_spec.html">OpenType specification</a>.
+ */
+public interface OpenType {
+
+ /**
+ * The Constant TAG_ACNT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_ACNT = 1633906292;
+
+ /**
+ * The Constant TAG_AVAR indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_AVAR = 1635148146;
+
+ /**
+ * The Constant TAG_BASE indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_BASE = 1111577413;
+
+ /**
+ * The Constant TAG_BDAT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_BDAT = 1650745716;
+
+ /**
+ * The Constant TAG_BLOC indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_BLOC = 1651273571;
+
+ /**
+ * The Constant TAG_BSLN indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_BSLN = 1651731566;
+
+ /**
+ * The Constant TAG_CFF indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_CFF = 1128678944;
+
+ /**
+ * The Constant TAG_CMAP indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_CMAP = 1668112752;
+
+ /**
+ * The Constant TAG_CVAR indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_CVAR = 1668702578;
+
+ /**
+ * The Constant TAG_CVT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_CVT = 1668707360;
+
+ /**
+ * The Constant TAG_DSIG indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_DSIG = 1146308935;
+
+ /**
+ * The Constant TAG_EBDT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_EBDT = 1161970772;
+
+ /**
+ * The Constant TAG_EBLC indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_EBLC = 1161972803;
+
+ /**
+ * The Constant TAG_EBSC indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_EBSC = 1161974595;
+
+ /**
+ * The Constant TAG_FDSC indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_FDSC = 1717859171;
+
+ /**
+ * The Constant TAG_FEAT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_FEAT = 1717920116;
+
+ /**
+ * The Constant TAG_FMTX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_FMTX = 1718449272;
+
+ /**
+ * The Constant TAG_FPGM indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_FPGM = 1718642541;
+
+ /**
+ * The Constant TAG_FVAR indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_FVAR = 1719034226;
+
+ /**
+ * The Constant TAG_GASP indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GASP = 1734439792;
+
+ /**
+ * The Constant TAG_GDEF indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GDEF = 1195656518;
+
+ /**
+ * The Constant TAG_GLYF indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GLYF = 1735162214;
+
+ /**
+ * The Constant TAG_GPOS indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GPOS = 1196445523;
+
+ /**
+ * The Constant TAG_GSUB indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GSUB = 1196643650;
+
+ /**
+ * The Constant TAG_GVAR indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_GVAR = 1735811442;
+
+ /**
+ * The Constant TAG_HDMX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_HDMX = 1751412088;
+
+ /**
+ * The Constant TAG_HEAD indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_HEAD = 1751474532;
+
+ /**
+ * The Constant TAG_HHEA indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_HHEA = 1751672161;
+
+ /**
+ * The Constant TAG_HMTX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_HMTX = 1752003704;
+
+ /**
+ * The Constant TAG_JSTF indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_JSTF = 1246975046;
+
+ /**
+ * The Constant TAG_JUST indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_JUST = 1786082164;
+
+ /**
+ * The Constant TAG_KERN indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_KERN = 1801810542;
+
+ /**
+ * The Constant TAG_LCAR indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_LCAR = 1818452338;
+
+ /**
+ * The Constant TAG_LOCA indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_LOCA = 1819239265;
+
+ /**
+ * The Constant TAG_LTSH indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_LTSH = 1280594760;
+
+ /**
+ * The Constant TAG_MAXP indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_MAXP = 1835104368;
+
+ /**
+ * The Constant TAG_MMFX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_MMFX = 1296909912;
+
+ /**
+ * The Constant TAG_MMSD indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_MMSD = 1296913220;
+
+ /**
+ * The Constant TAG_MORT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_MORT = 1836020340;
+
+ /**
+ * The Constant TAG_NAME indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_NAME = 1851878757;
+
+ /**
+ * The Constant TAG_OPBD indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_OPBD = 1836020340;
+
+ /**
+ * The Constant TAG_OS2 indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_OS2 = 1330851634;
+
+ /**
+ * The Constant TAG_PCLT indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_PCLT = 1346587732;
+
+ /**
+ * The Constant TAG_POST indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_POST = 1886352244;
+
+ /**
+ * The Constant TAG_PREP indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_PREP = 1886545264;
+
+ /**
+ * The Constant TAG_PROP indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_PROP = 1886547824;
+
+ /**
+ * The Constant TAG_TRAK indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_TRAK = 1953653099;
+
+ /**
+ * The Constant TAG_TYP1 indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_TYP1 = 1954115633;
+
+ /**
+ * The Constant TAG_VDMX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_VDMX = 1447316824;
+
+ /**
+ * The Constant TAG_VHEA indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_VHEA = 1986553185;
+
+ /**
+ * The Constant TAG_VMTX indicates corresponding table tag
+ * in the Open Type Specification.
+ */
+ public static final int TAG_VMTX = 1986884728;
+
+ /**
+ * Returns the OpenType font version.
+ *
+ * @return the the OpenType font version.
+ */
+ public int getVersion();
+
+ /**
+ * Gets the table for a specified tag.
+ * Sfnt tables include cmap, name and head items.
+ *
+ * @param sfntTag the sfnt tag.
+ *
+ * @return a byte array contains the font data corresponding
+ * to the specified tag.
+ */
+ public byte[] getFontTable(int sfntTag);
+
+ /**
+ * Gets the table for a specified tag.
+ * Sfnt tables include cmap, name and head items.
+ *
+ * @param sfntTag the sfnt tag.
+ * @param offset the offset of the returned table.
+ * @param count the number of returned table.
+ *
+ * @return the table corresponding to sfntTag and containing
+ * the bytes starting at offset byte and including count bytes.
+ */
+ public byte[] getFontTable(int sfntTag, int offset, int count);
+
+ /**
+ * Gets the table for a specified tag.
+ * Sfnt tables include cmap, name and head items.
+ *
+ * @param strSfntTag the str sfnt tag as a String.
+ *
+ * @return a byte array contains the font data corresponding
+ * to the specified tag.
+ */
+ public byte[] getFontTable(String strSfntTag);
+
+ /**
+ * Gets the table for a specified tag.
+ * Sfnt tables include cmap, name and head items.
+ *
+ * @param strSfntTag the sfnt tag as a String.
+ * @param offset the offset of the returned table.
+ * @param count the number of returned table.
+ *
+ * @return the table corresponding to sfntTag and containing
+ * the bytes starting at offset byte and including count bytes.
+ */
+ public byte[] getFontTable(String strSfntTag, int offset, int count);
+
+ /**
+ * Gets the table size for a specified tag.
+ *
+ * @param strSfntTag the sfnt tag as a String.
+ *
+ * @return the table size for a specified tag.
+ */
+ public int getFontTableSize(String strSfntTag);
+
+ /**
+ * Gets the table size for a specified tag.
+ *
+ * @param sfntTag the sfnt tag.
+ *
+ * @return the table size for a specified tag.
+ */
+ public int getFontTableSize(int sfntTag);
+
+}
+
diff --git a/awt/java/awt/font/ShapeGraphicAttribute.java b/awt/java/awt/font/ShapeGraphicAttribute.java
new file mode 100644
index 0000000..45199fd
--- /dev/null
+++ b/awt/java/awt/font/ShapeGraphicAttribute.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.misc.HashCode;
+
+
+/**
+ * The ShapeGraphicAttribute class provides an opportunity to insert
+ * shapes to a text.
+ */
+public final class ShapeGraphicAttribute extends GraphicAttribute {
+
+ // shape to render
+ /** The shape. */
+ private Shape fShape;
+
+ // flag, if the shape should be stroked (true) or filled (false)
+ /** The stroke. */
+ private boolean fStroke;
+
+ // bounds of the shape
+ /** The bounds. */
+ private Rectangle2D fBounds;
+
+ // X coordinate of the origin point
+ /** The origin x. */
+ private float fOriginX;
+
+ // Y coordinate of the origin point
+ /** The origin y. */
+ private float fOriginY;
+
+ // width of the shape
+ /** The shape width. */
+ private float fShapeWidth;
+
+ // height of the shape
+ /** The shape height. */
+ private float fShapeHeight;
+
+ /**
+ * The Constant STROKE indicates whether the Shape is stroked
+ * or not.
+ */
+ public static final boolean STROKE = true;
+
+ /**
+ * The Constant FILL indicates whether the Shape is filled
+ * or not. */
+ public static final boolean FILL = false;
+
+ /**
+ * Instantiates a new ShapeGraphicAttribute object for the specified
+ * Shape.
+ *
+ * @param shape the shape to be rendered by this
+ * ShapeGraphicAttribute.
+ * @param alignment the alignment of this ShapeGraphicAttribute.
+ * @param stroke true if the Shape is stroked,
+ * false if the Shape is filled.
+ */
+ public ShapeGraphicAttribute(Shape shape, int alignment, boolean stroke) {
+ super(alignment);
+
+ this.fShape = shape;
+ this.fStroke = stroke;
+
+ this.fBounds = fShape.getBounds2D();
+
+ this.fOriginX = (float)fBounds.getMinX();
+ this.fOriginY = (float)fBounds.getMinY();
+
+ this.fShapeWidth = (float)fBounds.getWidth();
+ this.fShapeHeight = (float)fBounds.getHeight();
+ }
+
+ /**
+ * Returns a hash code of this ShapeGraphicAttribute object.
+ *
+ * @return a hash code of this ShapeGraphicAttribute object.
+ */
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+
+ hash.append(fShape.hashCode());
+ hash.append(getAlignment());
+ return hash.hashCode();
+ }
+
+ /**
+ * Compares this ShapeGraphicAttribute object to the specified
+ * ShapeGraphicAttribute object.
+ *
+ * @param sga the ShapeGraphicAttribute object to be compared.
+ *
+ * @return true, if this ShapeGraphicAttribute object is equal
+ * to the specified ShapeGraphicAttribute object, false otherwise.
+ */
+ public boolean equals(ShapeGraphicAttribute sga) {
+ if (sga == null) {
+ return false;
+ }
+
+ if (sga == this) {
+ return true;
+ }
+
+ return ( fStroke == sga.fStroke &&
+ getAlignment() == sga.getAlignment() &&
+ fShape.equals(sga.fShape));
+
+ }
+
+ /**
+ * Compares this ShapeGraphicAttribute object to the specified
+ * Object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if this ShapeGraphicAttribute object is equal
+ * to the specified Object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ try {
+ return equals((ShapeGraphicAttribute) obj);
+ }
+ catch(ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public void draw(Graphics2D g2, float x, float y) {
+ AffineTransform at = AffineTransform.getTranslateInstance(x, y);
+ if (fStroke == STROKE){
+ Stroke oldStroke = g2.getStroke();
+ g2.setStroke(new BasicStroke());
+ g2.draw(at.createTransformedShape(fShape));
+ g2.setStroke(oldStroke);
+ } else {
+ g2.fill(at.createTransformedShape(fShape));
+ }
+
+ }
+
+ @Override
+ public float getAdvance() {
+ return Math.max(0, fShapeWidth + fOriginX);
+ }
+
+ @Override
+ public float getAscent() {
+ return Math.max(0, -fOriginY);
+ }
+
+ @Override
+ public Rectangle2D getBounds() {
+ return (Rectangle2D)fBounds.clone();
+ }
+
+ @Override
+ public float getDescent() {
+ return Math.max(0, fShapeHeight + fOriginY);
+ }
+
+}
+
diff --git a/awt/java/awt/font/TextHitInfo.java b/awt/java/awt/font/TextHitInfo.java
new file mode 100644
index 0000000..17bbf71
--- /dev/null
+++ b/awt/java/awt/font/TextHitInfo.java
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import org.apache.harmony.misc.HashCode;
+
+
+/**
+ * The TextHitInfo class provides information about a caret position
+ * in a text model for insertion or deletion of a character in a text.
+ * The TextHitInfo defines two biases of the character: leading or trailing.
+ * Leading position means the left edge of the specified character
+ * (TextHitInfo.leading(2) method for "text" returns the left side of "x").
+ * Trailing position means the right edge of the specified character
+ * (TextHitInfo.trailing(2) method for "text" returns the right side of "x").
+ */
+public final class TextHitInfo {
+
+ /** The char idx. */
+ private int charIdx; // Represents character index in the line
+
+ /** The is trailing. */
+ private boolean isTrailing;
+
+ /**
+ * Instantiates a new text hit info.
+ *
+ * @param idx the idx
+ * @param isTrailing the is trailing
+ */
+ private TextHitInfo(int idx, boolean isTrailing) {
+ charIdx = idx;
+ this.isTrailing = isTrailing;
+ }
+
+ /**
+ * To string.
+ *
+ * @return the string
+ */
+ @Override
+ public String toString() {
+ return new String(
+ "TextHitInfo[" + charIdx + ", " + //$NON-NLS-1$ //$NON-NLS-2$
+ (isTrailing?"Trailing":"Leading") + "]" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ );
+ }
+
+ /**
+ * Compares this TextHitInfo object with the specified object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if the specified object is a TextHitInfo object
+ * with the same data values as this TextHitInfo, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof TextHitInfo) {
+ return equals((TextHitInfo) obj);
+ }
+ return false;
+ }
+
+ /**
+ * Compares this TextHitInfo object with the specified TextHitInfo
+ * object.
+ *
+ * @param thi the TextHitInfo object to be compared.
+ *
+ * @return true, if this TextHitInfo object has the same data values as the
+ * specified TextHitInfo object, false otherwise.
+ */
+ public boolean equals(TextHitInfo thi) {
+ return
+ thi != null &&
+ thi.charIdx == charIdx &&
+ thi.isTrailing == isTrailing;
+ }
+
+ /**
+ * Gets a TextHitInfo object with its character index
+ * at the specified offset from the character index of
+ * this TextHitInfo.
+ *
+ * @param offset the offset.
+ *
+ * @return the TextHitInfo.
+ */
+ public TextHitInfo getOffsetHit(int offset) {
+ return new TextHitInfo(charIdx + offset, isTrailing);
+ }
+
+ /**
+ * Gets a TextHitInfo associated with the other side of
+ * the insertion point.
+ *
+ * @return the other hit.
+ */
+ public TextHitInfo getOtherHit() {
+ return isTrailing ?
+ new TextHitInfo(charIdx+1, false) :
+ new TextHitInfo(charIdx-1, true);
+ }
+
+ /**
+ * Returns true if the leading edge of the character is hit,
+ * false if the trailing edge of the character is hit.
+ *
+ * @return true if the leading edge of the character is hit,
+ * false if the trailing edge of the character is hit.
+ */
+ public boolean isLeadingEdge() {
+ return !isTrailing;
+ }
+
+ /**
+ * Hash code.
+ *
+ * @return the int
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.combine(charIdx, isTrailing);
+ }
+
+ /**
+ * Gets the insertion index.
+ *
+ * @return the insertion index: character index if the leading edge
+ * is hit, or character index + 1 if the trailing edge is hit.
+ */
+ public int getInsertionIndex() {
+ return isTrailing ? charIdx+1 : charIdx;
+ }
+
+ /**
+ * Gets the index of the character hit.
+ *
+ * @return the character hit's index.
+ */
+ public int getCharIndex() {
+ return charIdx;
+ }
+
+ /**
+ * Returns a TextHitInfo associated with the trailing edge of
+ * the character at the specified char index.
+ *
+ * @param charIndex the char index.
+ *
+ * @return the TextHitInfo associated with the trailing edge of
+ * the character at the specified char index.
+ */
+ public static TextHitInfo trailing(int charIndex) {
+ return new TextHitInfo(charIndex, true);
+ }
+
+ /**
+ * Returns a TextHitInfo object associated with the leading edge
+ * of the character at the specified char index.
+ *
+ * @param charIndex the char index.
+ *
+ * @return the TextHitInfo object associated with the leading edge
+ * of the character at the specified char index.
+ */
+ public static TextHitInfo leading(int charIndex) {
+ return new TextHitInfo(charIndex, false);
+ }
+
+ /**
+ * Returns a (trailing) TextHitInfo object associated with the character
+ * before the specified offset.
+ *
+ * @param offset the offset.
+ *
+ * @return the TextHitInfo object associated with the character
+ * before the specified offset.
+ */
+ public static TextHitInfo beforeOffset(int offset) {
+ return new TextHitInfo(offset-1, true);
+ }
+
+ /**
+ * Returns a (leading) TextHitInfo object associated with the character
+ * after the specified offset.
+ *
+ * @param offset the offset.
+ *
+ * @return the TextHitInfo object associated with the character
+ * after the specified offset.
+ */
+ public static TextHitInfo afterOffset(int offset) {
+ return new TextHitInfo(offset, false);
+ }
+}
diff --git a/awt/java/awt/font/TextLayout.java b/awt/java/awt/font/TextLayout.java
new file mode 100644
index 0000000..e80afd0
--- /dev/null
+++ b/awt/java/awt/font/TextLayout.java
@@ -0,0 +1,916 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.util.Map;
+
+import org.apache.harmony.awt.gl.font.BasicMetrics;
+import org.apache.harmony.awt.gl.font.CaretManager;
+import org.apache.harmony.awt.gl.font.TextMetricsCalculator;
+import org.apache.harmony.awt.gl.font.TextRunBreaker;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The TextLayout class defines the graphical representation of character data.
+ * This class provides method for obtaining information about cursor
+ * positioning and movement, split cursors for text with different directions,
+ * logical and visual highlighting, multiple baselines, hits, justification,
+ * ascent, descent, and advance, and rendering. A TextLayout object can be
+ * rendered using Graphics context.
+ */
+public final class TextLayout implements Cloneable {
+
+ /**
+ * The CaretPolicy class provides a policy for obtaining the
+ * caret location. The single getStrongCaret method specifies
+ * the policy.
+ */
+ public static class CaretPolicy {
+
+ /**
+ * Instantiates a new CaretPolicy.
+ */
+ public CaretPolicy() {
+ // Nothing to do
+ }
+
+ /**
+ * Returns whichever of the two specified TextHitInfo objects
+ * has the stronger caret (higher character level) in the
+ * specified TextLayout.
+ *
+ * @param hit1 the first TextHitInfo of the specified TextLayout.
+ * @param hit2 the second TextHitInfo of the specified TextLayout.
+ * @param layout the TextLayout.
+ *
+ * @return the TextHitInfo with the stronger caret.
+ */
+ public TextHitInfo getStrongCaret(TextHitInfo hit1, TextHitInfo hit2, TextLayout layout) {
+ // Stronger hit is the one with greater level.
+ // If the level is same, leading edge is stronger.
+
+ int level1 = layout.getCharacterLevel(hit1.getCharIndex());
+ int level2 = layout.getCharacterLevel(hit2.getCharIndex());
+
+ if (level1 == level2) {
+ return (hit2.isLeadingEdge() && (!hit1.isLeadingEdge())) ? hit2 : hit1;
+ }
+ return level1 > level2 ? hit1 : hit2;
+ }
+
+ }
+
+ /**
+ * The Constant DEFAULT_CARET_POLICY indicates the default caret policy.
+ */
+ public static final TextLayout.CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy();
+
+ /** The breaker. */
+ private TextRunBreaker breaker;
+
+ /** The metrics valid. */
+ private boolean metricsValid = false;
+
+ /** The tmc. */
+ private TextMetricsCalculator tmc;
+
+ /** The metrics. */
+ private BasicMetrics metrics;
+
+ /** The caret manager. */
+ private CaretManager caretManager;
+
+ /** The justification width. */
+ float justificationWidth = -1;
+
+ /**
+ * Instantiates a new TextLayout object from the specified string
+ * and Font.
+ *
+ * @param string the string to be displayed.
+ * @param font the font of the text.
+ * @param frc the FontRenderContext object for obtaining
+ * information about a graphics device.
+ */
+ public TextLayout(String string, Font font, FontRenderContext frc) {
+ if (string == null){
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (font == null){
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "font")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (string.length() == 0){
+ // awt.02='{0}' parameter has zero length
+ throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ AttributedString as = new AttributedString(string);
+ as.addAttribute(TextAttribute.FONT, font);
+ this.breaker = new TextRunBreaker(as.getIterator(), frc);
+ caretManager = new CaretManager(breaker);
+ }
+
+ /**
+ * Instantiates a new TextLayout from the specified text and
+ * a map of attributes.
+ *
+ * @param string the string to be displayed.
+ * @param attributes the attributes to be used for obtaining the text
+ * style.
+ * @param frc the FontRenderContext object for obtaining
+ * information about a graphics device.
+ */
+ public TextLayout(
+ String string,
+ Map<? extends java.text.AttributedCharacterIterator.Attribute, ?> attributes,
+ FontRenderContext frc ) {
+ if (string == null){
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (attributes == null){
+ // awt.01='{0}' parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.01", "attributes")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (string.length() == 0){
+ // awt.02='{0}' parameter has zero length
+ throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+
+ AttributedString as = new AttributedString(string);
+ as.addAttributes(attributes, 0, string.length());
+ this.breaker = new TextRunBreaker(as.getIterator(), frc);
+ caretManager = new CaretManager(breaker);
+ }
+
+ /**
+ * Instantiates a new TextLayout from the AttributedCharacterIterator.
+ *
+ * @param text the AttributedCharacterIterator.
+ * @param frc the FontRenderContext object for obtaining
+ * information about a graphics device.
+ */
+ public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) {
+ if (text == null){
+ // awt.03='{0}' iterator parameter is null
+ throw new IllegalArgumentException(Messages.getString("awt.03", "text")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (text.getBeginIndex() == text.getEndIndex()){
+ // awt.04='{0}' iterator parameter has zero length
+ throw new IllegalArgumentException(Messages.getString("awt.04", "text")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ this.breaker = new TextRunBreaker(text, frc);
+ caretManager = new CaretManager(breaker);
+ }
+
+ /**
+ * Instantiates a new text layout.
+ *
+ * @param breaker the breaker
+ */
+ TextLayout(TextRunBreaker breaker) {
+ this.breaker = breaker;
+ caretManager = new CaretManager(this.breaker);
+ }
+
+ /**
+ * Returns a hash code of this TextLayout object.
+ *
+ * @return a hash code of this TextLayout object.
+ */
+ @Override
+ public int hashCode() {
+ return breaker.hashCode();
+ }
+
+ /**
+ * Returns a copy of this object.
+ *
+ * @return a copy of this object.
+ */
+ @Override
+ protected Object clone() {
+ TextLayout res = new TextLayout((TextRunBreaker) breaker.clone());
+
+ if (justificationWidth >= 0) {
+ res.handleJustify(justificationWidth);
+ }
+
+ return res;
+ }
+
+ /**
+ * Compares this TextLayout object to the specified TextLayout object.
+ *
+ * @param layout the TextLayout object to be compared.
+ *
+ * @return true, if this TextLayout object is equal to
+ * the specified TextLayout object, false otherwise.
+ */
+ public boolean equals(TextLayout layout) {
+ if (layout == null) {
+ return false;
+ }
+ return this.breaker.equals(layout.breaker);
+ }
+
+ /**
+ * Compares this TextLayout object to the specified Object.
+ *
+ * @param obj the Object to be compared.
+ *
+ * @return true, if this TextLayout object is equal to
+ * the specified Object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof TextLayout ? equals((TextLayout) obj) : false;
+ }
+
+ /**
+ * Gets the string representation for this TextLayout.
+ *
+ * @return the string representation for this TextLayout.
+ */
+ @Override
+ public String toString() { // what for?
+ return super.toString();
+ }
+
+ /**
+ * Draws this TextLayout at the specified location with the
+ * specified Graphics2D context.
+ *
+ * @param g2d the Graphics2D object which renders this TextLayout.
+ * @param x the X coordinate of the TextLayout origin.
+ * @param y the Y coordinate of the TextLayout origin.
+ */
+ public void draw(Graphics2D g2d, float x, float y) {
+ updateMetrics();
+ breaker.drawSegments(g2d, x ,y);
+ }
+
+ /**
+ * Update metrics.
+ */
+ private void updateMetrics() {
+ if (!metricsValid) {
+ breaker.createAllSegments();
+ tmc = new TextMetricsCalculator(breaker);
+ metrics = tmc.createMetrics();
+ metricsValid = true;
+ }
+ }
+
+ /**
+ * Gets the advance of this TextLayout object.
+ *
+ * @return the advance of this TextLayout object.
+ */
+ public float getAdvance() {
+ updateMetrics();
+ return metrics.getAdvance();
+ }
+
+ /**
+ * Gets the ascent of this TextLayout object.
+ *
+ * @return the ascent of this TextLayout object.
+ */
+ public float getAscent() {
+ updateMetrics();
+ return metrics.getAscent();
+ }
+
+ /**
+ * Gets the baseline of this TextLayout object.
+ *
+ * @return the baseline of this TextLayout object.
+ */
+ public byte getBaseline() {
+ updateMetrics();
+ return (byte) metrics.getBaseLineIndex();
+ }
+
+ /**
+ * Gets the float array of offsets for the baselines which
+ * are used in this TextLayout.
+ *
+ * @return the float array of offsets for the baselines which
+ * are used in this TextLayout.
+ */
+ public float[] getBaselineOffsets() {
+ updateMetrics();
+ return tmc.getBaselineOffsets();
+ }
+
+ /**
+ * Gets the black box bounds of the characters in the specified area.
+ * The black box bounds is an Shape which contains all
+ * bounding boxes of all the glyphs of the characters
+ * between firstEndpoint and secondEndpoint parameters values.
+ *
+ * @param firstEndpoint the first point of the area.
+ * @param secondEndpoint the second point of the area.
+ *
+ * @return the Shape which contains black box bounds.
+ */
+ public Shape getBlackBoxBounds(int firstEndpoint, int secondEndpoint) {
+ updateMetrics();
+ if (firstEndpoint < secondEndpoint) {
+ return breaker.getBlackBoxBounds(firstEndpoint, secondEndpoint);
+ }
+ return breaker.getBlackBoxBounds(secondEndpoint, firstEndpoint);
+ }
+
+ /**
+ * Gets the bounds of this TextLayout.
+ *
+ * @return the bounds of this TextLayout.
+ */
+ public Rectangle2D getBounds() {
+ updateMetrics();
+ return breaker.getVisualBounds();
+ }
+
+ /**
+ * Gets information about the caret of the specified TextHitInfo.
+ *
+ * @param hitInfo the TextHitInfo.
+ *
+ * @return the information about the caret of the specified TextHitInfo.
+ */
+ public float[] getCaretInfo(TextHitInfo hitInfo) {
+ updateMetrics();
+ return caretManager.getCaretInfo(hitInfo);
+ }
+
+ /**
+ * Gets information about the caret of the specified TextHitInfo
+ * of a character in this TextLayout.
+ *
+ * @param hitInfo the TextHitInfo of a character in this TextLayout.
+ * @param bounds the bounds to which the caret info is constructed.
+ *
+ * @return the caret of the specified TextHitInfo.
+ */
+ public float[] getCaretInfo(TextHitInfo hitInfo, Rectangle2D bounds) {
+ updateMetrics();
+ return caretManager.getCaretInfo(hitInfo);
+ }
+
+ /**
+ * Gets a Shape which represents the caret of the specified TextHitInfo
+ * in the bounds of this TextLayout.
+ *
+ * @param hitInfo the TextHitInfo.
+ * @param bounds the bounds to which the caret info is constructed.
+ *
+ * @return the Shape which represents the caret.
+ */
+ public Shape getCaretShape(TextHitInfo hitInfo, Rectangle2D bounds) {
+ updateMetrics();
+ return caretManager.getCaretShape(hitInfo, this);
+ }
+
+ /**
+ * Gets a Shape which represents the caret of the specified TextHitInfo
+ * in the bounds of this TextLayout.
+ *
+ * @param hitInfo the TextHitInfo.
+ *
+ * @return the Shape which represents the caret.
+ */
+ public Shape getCaretShape(TextHitInfo hitInfo) {
+ updateMetrics();
+ return caretManager.getCaretShape(hitInfo, this);
+ }
+
+ /**
+ * Gets two Shapes for the strong and weak carets with
+ * default caret policy and null bounds: the first element
+ * is the strong caret, the second is the weak caret or null.
+ *
+ * @param offset an offset in the TextLayout.
+ *
+ * @return an array of two Shapes corresponded to the strong
+ * and weak carets.
+ */
+ public Shape[] getCaretShapes(int offset) {
+ return getCaretShapes(offset, null, TextLayout.DEFAULT_CARET_POLICY);
+ }
+
+ /**
+ * Gets two Shapes for the strong and weak carets with
+ * the default caret policy: the first element is the strong
+ * caret, the second is the weak caret or null.
+ *
+ * @param offset an offset in the TextLayout.
+ * @param bounds the bounds to which to extend the carets.
+ *
+ * @return an array of two Shapes corresponded to the strong
+ * and weak carets.
+ */
+ public Shape[] getCaretShapes(int offset, Rectangle2D bounds) {
+ return getCaretShapes(offset, bounds, TextLayout.DEFAULT_CARET_POLICY);
+ }
+
+ /**
+ * Gets two Shapes for the strong and weak carets: the first
+ * element is the strong caret, the second is the weak caret
+ * or null.
+ *
+ * @param offset an offset in the TextLayout.
+ * @param bounds the bounds to which to extend the carets.
+ * @param policy the specified CaretPolicy.
+ *
+ * @return an array of two Shapes corresponded to the strong
+ * and weak carets.
+ */
+ public Shape[] getCaretShapes(int offset, Rectangle2D bounds, TextLayout.CaretPolicy policy) {
+ if (offset < 0 || offset > breaker.getCharCount()) {
+ // awt.195=Offset is out of bounds
+ throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$
+ }
+
+ updateMetrics();
+ return caretManager.getCaretShapes(offset, bounds, policy, this);
+ }
+
+ /**
+ * Gets the number of characters in this TextLayout.
+ *
+ * @return the number of characters in this TextLayout.
+ */
+ public int getCharacterCount() {
+ return breaker.getCharCount();
+ }
+
+ /**
+ * Gets the level of the character with the specified index.
+ *
+ * @param index the specified index of the character.
+ *
+ * @return the level of the character.
+ */
+ public byte getCharacterLevel(int index) {
+ if (index == -1 || index == getCharacterCount()) {
+ return (byte) breaker.getBaseLevel();
+ }
+ return breaker.getLevel(index);
+ }
+
+ /**
+ * Gets the descent of this TextLayout.
+ *
+ * @return the descent of this TextLayout.
+ */
+ public float getDescent() {
+ updateMetrics();
+ return metrics.getDescent();
+ }
+
+ /**
+ * Gets the TextLayout wich is justified with the specified
+ * width related to this TextLayout.
+ *
+ * @param justificationWidth the width which is used
+ * for justification.
+ *
+ * @return a TextLayout justified to the specified width.
+ *
+ * @throws Error the error occures if this TextLayout has been
+ * already justified.
+ */
+ public TextLayout getJustifiedLayout(float justificationWidth) throws Error {
+ float justification = breaker.getJustification();
+
+ if (justification < 0) {
+ // awt.196=Justification impossible, layout already justified
+ throw new Error(Messages.getString("awt.196")); //$NON-NLS-1$
+ } else if (justification == 0) {
+ return this;
+ }
+
+ TextLayout justifiedLayout = new TextLayout((TextRunBreaker) breaker.clone());
+ justifiedLayout.handleJustify(justificationWidth);
+ return justifiedLayout;
+ }
+
+ /**
+ * Gets the leading of this TextLayout.
+ *
+ * @return the leading of this TextLayout.
+ */
+ public float getLeading() {
+ updateMetrics();
+ return metrics.getLeading();
+ }
+
+ /**
+ * Gets a Shape representing the logical selection betweeen
+ * the specified endpoints and extended to the natural
+ * bounds of this TextLayout.
+ *
+ * @param firstEndpoint the first selected endpoint within the area of characters
+ * @param secondEndpoint the second selected endpoint within the area of characters
+ *
+ * @return a Shape represented the logical selection betweeen
+ * the specified endpoints.
+ */
+ public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint) {
+ updateMetrics();
+ return getLogicalHighlightShape(firstEndpoint, secondEndpoint, breaker.getLogicalBounds());
+ }
+
+ /**
+ * Gets a Shape representing the logical selection betweeen
+ * the specified endpoints and extended to the specified
+ * bounds of this TextLayout.
+ *
+ * @param firstEndpoint the first selected endpoint within the area of characters
+ * @param secondEndpoint the second selected endpoint within the area of characters
+ * @param bounds the specified bounds of this TextLayout.
+ *
+ * @return a Shape represented the logical selection betweeen
+ * the specified endpoints.
+ */
+ public Shape getLogicalHighlightShape(
+ int firstEndpoint,
+ int secondEndpoint,
+ Rectangle2D bounds
+ ) {
+ updateMetrics();
+
+ if (firstEndpoint > secondEndpoint) {
+ if (secondEndpoint < 0 || firstEndpoint > breaker.getCharCount()) {
+ // awt.197=Endpoints are out of range
+ throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$
+ }
+ return caretManager.getLogicalHighlightShape(
+ secondEndpoint,
+ firstEndpoint,
+ bounds,
+ this
+ );
+ }
+ if (firstEndpoint < 0 || secondEndpoint > breaker.getCharCount()) {
+ // awt.197=Endpoints are out of range
+ throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$
+ }
+ return caretManager.getLogicalHighlightShape(
+ firstEndpoint,
+ secondEndpoint,
+ bounds,
+ this
+ );
+ }
+
+ /**
+ * Gets the logical ranges of text which corresponds to a visual
+ * selection.
+ *
+ * @param hit1 the first endpoint of the visual range.
+ * @param hit2 the second endpoint of the visual range.
+ *
+ * @return the logical ranges of text which corresponds to a visual
+ * selection.
+ */
+ public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) {
+ return caretManager.getLogicalRangesForVisualSelection(hit1, hit2);
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the left (or
+ * up at the end of the line) of the specified offset.
+ *
+ * @param offset the offset in this TextLayout.
+ *
+ * @return the TextHitInfo for the next caret to the left (or
+ * up at the end of the line) of the specified hit, or null
+ * if there is no hit.
+ */
+ public TextHitInfo getNextLeftHit(int offset) {
+ return getNextLeftHit(offset, DEFAULT_CARET_POLICY);
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the left (or
+ * up at the end of the line) of the specified hit.
+ *
+ * @param hitInfo the initial hit.
+ *
+ * @return the TextHitInfo for the next caret to the left (or
+ * up at the end of the line) of the specified hit, or null
+ * if there is no hit.
+ */
+ public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) {
+ breaker.createAllSegments();
+ return caretManager.getNextLeftHit(hitInfo);
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the left (or
+ * up at the end of the line) of the specified offset, given the
+ * specified caret policy.
+ *
+ * @param offset the offset in this TextLayout.
+ * @param policy the policy to be used for obtaining the strong caret.
+ *
+ * @return the TextHitInfo for the next caret to the left of the
+ * specified offset, or null if there is no hit.
+ */
+ public TextHitInfo getNextLeftHit(int offset, TextLayout.CaretPolicy policy) {
+ if (offset < 0 || offset > breaker.getCharCount()) {
+ // awt.195=Offset is out of bounds
+ throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$
+ }
+
+ TextHitInfo hit = TextHitInfo.afterOffset(offset);
+ TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this);
+ TextHitInfo nextLeftHit = getNextLeftHit(strongHit);
+
+ if (nextLeftHit != null) {
+ return policy.getStrongCaret(getVisualOtherHit(nextLeftHit), nextLeftHit, this);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the right (or
+ * down at the end of the line) of the specified hit.
+ *
+ * @param hitInfo the initial hit.
+ *
+ * @return the TextHitInfo for the next caret to the right (or
+ * down at the end of the line) of the specified hit, or null
+ * if there is no hit.
+ */
+ public TextHitInfo getNextRightHit(TextHitInfo hitInfo) {
+ breaker.createAllSegments();
+ return caretManager.getNextRightHit(hitInfo);
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the right (or
+ * down at the end of the line) of the specified offset.
+ *
+ * @param offset the offset in this TextLayout.
+ *
+ * @return the TextHitInfo for the next caret to the right of the
+ * specified offset, or null if there is no hit.
+ */
+ public TextHitInfo getNextRightHit(int offset) {
+ return getNextRightHit(offset, DEFAULT_CARET_POLICY);
+ }
+
+ /**
+ * Gets the TextHitInfo for the next caret to the right (or
+ * down at the end of the line) of the specified offset, given the
+ * specified caret policy.
+ *
+ * @param offset the offset in this TextLayout.
+ * @param policy the policy to be used for obtaining the strong caret.
+ *
+ * @return the TextHitInfo for the next caret to the right of the
+ * specified offset, or null if there is no hit.
+ */
+ public TextHitInfo getNextRightHit(int offset, TextLayout.CaretPolicy policy) {
+ if (offset < 0 || offset > breaker.getCharCount()) {
+ // awt.195=Offset is out of bounds
+ throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$
+ }
+
+ TextHitInfo hit = TextHitInfo.afterOffset(offset);
+ TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this);
+ TextHitInfo nextRightHit = getNextRightHit(strongHit);
+
+ if (nextRightHit != null) {
+ return policy.getStrongCaret(getVisualOtherHit(nextRightHit), nextRightHit, this);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the outline of this TextLayout as a Shape.
+ *
+ * @param xform the AffineTransform to be used to transform
+ * the outline before returning it, or null if no transformation
+ * is desired.
+ *
+ * @return the outline of this TextLayout as a Shape.
+ */
+ public Shape getOutline(AffineTransform xform) {
+ breaker.createAllSegments();
+
+ GeneralPath outline = breaker.getOutline();
+
+ if (outline != null && xform != null) {
+ outline.transform(xform);
+ }
+
+ return outline;
+ }
+
+ /**
+ * Gets the visible advance of this TextLayout which is defined as
+ * diffence between leading (advance) and trailing whitespace.
+ *
+ * @return the visible advance of this TextLayout.
+ */
+ public float getVisibleAdvance() {
+ updateMetrics();
+
+ // Trailing whitespace _SHOULD_ be reordered (Unicode spec) to
+ // base direction, so it is also trailing
+ // in logical representation. We use this fact.
+ int lastNonWhitespace = breaker.getLastNonWhitespace();
+
+ if (lastNonWhitespace < 0) {
+ return 0;
+ } else if (lastNonWhitespace == getCharacterCount()-1) {
+ return getAdvance();
+ } else if (justificationWidth >= 0) { // Layout is justified
+ return justificationWidth;
+ } else {
+ breaker.pushSegments(
+ breaker.getACI().getBeginIndex(),
+ lastNonWhitespace + breaker.getACI().getBeginIndex() + 1
+ );
+
+ breaker.createAllSegments();
+
+ float visAdvance = tmc.createMetrics().getAdvance();
+
+ breaker.popSegments();
+ return visAdvance;
+ }
+ }
+
+ /**
+ * Gets a Shape which corresponds to the highlighted (selected) area
+ * based on two hit locations within the text and extends to the bounds.
+ *
+ * @param hit1 the first text hit location.
+ * @param hit2 the second text hit location.
+ * @param bounds the rectangle that the highlighted area should be
+ * extended or restricted to.
+ *
+ * @return a Shape which corresponds to the highlighted (selected) area.
+ */
+ public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2, Rectangle2D bounds) {
+ return caretManager.getVisualHighlightShape(hit1, hit2, bounds, this);
+ }
+
+ /**
+ * Gets a Shape which corresponds to the highlighted (selected) area
+ * based on two hit locations within the text.
+ *
+ * @param hit1 the first text hit location.
+ * @param hit2 the second text hit location.
+ *
+ * @return a Shape which corresponds to the highlighted (selected) area.
+ */
+ public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2) {
+ breaker.createAllSegments();
+ return caretManager.getVisualHighlightShape(hit1, hit2, breaker.getLogicalBounds(), this);
+ }
+
+ /**
+ * Gets the TextHitInfo for a hit on the opposite side of the
+ * specified hit's caret.
+ *
+ * @param hitInfo the specified TextHitInfo.
+ *
+ * @return the TextHitInfo for a hit on the opposite side of the
+ * specified hit's caret.
+ */
+ public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) {
+ return caretManager.getVisualOtherHit(hitInfo);
+ }
+
+ /**
+ * Justifies the text; this method should be overridden
+ * by subclasses.
+ *
+ * @param justificationWidth the width for justification.
+ */
+ protected void handleJustify(float justificationWidth) {
+ float justification = breaker.getJustification();
+
+ if (justification < 0) {
+ // awt.196=Justification impossible, layout already justified
+ throw new IllegalStateException(Messages.getString("awt.196")); //$NON-NLS-1$
+ } else if (justification == 0) {
+ return;
+ }
+
+ float gap = (justificationWidth - getVisibleAdvance()) * justification;
+ breaker.justify(gap);
+ this.justificationWidth = justificationWidth;
+
+ // Correct metrics
+ tmc = new TextMetricsCalculator(breaker);
+ tmc.correctAdvance(metrics);
+ }
+
+ /**
+ * Returns a TextHitInfo object that gives information on which
+ * division point (between two characters) is corresponds to a
+ * hit (such as a mouse click) at the specified coordinates.
+ *
+ * @param x the X coordinate in this TextLayout.
+ * @param y the Y coordinate in this TextLayout.
+ *
+ * TextHitInfo object cooresponding to the given coordinates
+ * within the text.
+ */
+ public TextHitInfo hitTestChar(float x, float y) {
+ return hitTestChar(x, y, getBounds());
+ }
+
+ /**
+ * Returns a TextHitInfo object that gives information on which
+ * division point (between two characters) is corresponds to a
+ * hit (such as a mouse click) at the specified coordinates within
+ * the specified text rectangle.
+ *
+ * @param x the X coordinate in this TextLayout.
+ * @param y the Y coordinate in this TextLayout.
+ * @param bounds the bounds of the text area.
+ *
+ * TextHitInfo object cooresponding to the given coordinates
+ * within the text.
+ */
+ public TextHitInfo hitTestChar(float x, float y, Rectangle2D bounds) {
+ if (x > bounds.getMaxX()) {
+ return breaker.isLTR() ?
+ TextHitInfo.trailing(breaker.getCharCount() - 1) : TextHitInfo.leading(0);
+ }
+
+ if (x < bounds.getMinX()) {
+ return breaker.isLTR() ?
+ TextHitInfo.leading(0) : TextHitInfo.trailing(breaker.getCharCount() - 1);
+ }
+
+ return breaker.hitTest(x, y);
+ }
+
+ /**
+ * Returns true if this TextLayout has a "left to right"
+ * direction.
+ *
+ * @return true if this TextLayout has a "left to right"
+ * direction, false if this TextLayout has a "right to left"
+ * direction.
+ */
+ public boolean isLeftToRight() {
+ return breaker.isLTR();
+ }
+
+ /**
+ * Returns true if this TextLayout is vertical, false otherwise.
+ *
+ * @return true if this TextLayout is vertical, false if horizontal.
+ */
+ public boolean isVertical() {
+ return false;
+ }
+}
+
diff --git a/awt/java/awt/font/TextMeasurer.java b/awt/java/awt/font/TextMeasurer.java
new file mode 100644
index 0000000..017f3d9
--- /dev/null
+++ b/awt/java/awt/font/TextMeasurer.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.font;
+
+
+import java.text.AttributedCharacterIterator;
+
+import org.apache.harmony.awt.gl.font.TextMetricsCalculator;
+import org.apache.harmony.awt.gl.font.TextRunBreaker;
+
+/**
+ * The TextMeasurer class provides utilities for line break operations.
+ */
+public final class TextMeasurer implements Cloneable {
+
+ /** The aci. */
+ AttributedCharacterIterator aci;
+
+ /** The frc. */
+ FontRenderContext frc;
+
+ /** The breaker. */
+ TextRunBreaker breaker = null;
+
+ /** The tmc. */
+ TextMetricsCalculator tmc = null;
+
+ /**
+ * Instantiates a new text measurer from the specified text.
+ *
+ * @param text the source text.
+ * @param frc the FontRenderContext.
+ */
+ public TextMeasurer(AttributedCharacterIterator text, FontRenderContext frc) {
+ this.aci = text;
+ this.frc = frc;
+ breaker = new TextRunBreaker(aci, this.frc);
+ tmc = new TextMetricsCalculator(breaker);
+ }
+
+ /**
+ * Replaces the current text with the new text, inserting a break
+ * character at the specified insert position.
+ *
+ * @param newParagraph the new paragraph text.
+ * @param insertPos the position in the text where the character is inserted.
+ */
+ public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) {
+ AttributedCharacterIterator oldAci = aci;
+ aci = newParagraph;
+ if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) -
+ (aci.getEndIndex() - aci.getBeginIndex()) != -1) {
+ breaker = new TextRunBreaker(aci, this.frc);
+ tmc = new TextMetricsCalculator(breaker);
+ } else {
+ breaker.insertChar(newParagraph, insertPos);
+ }
+ }
+
+ /**
+ * Replaces the current text with the new text and deletes a
+ * character at the specified position.
+ *
+ * @param newParagraph the paragraph text after deletion.
+ * @param deletePos the position in the text where the character is removed.
+ */
+ public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) {
+ AttributedCharacterIterator oldAci = aci;
+ aci = newParagraph;
+ if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) -
+ (aci.getEndIndex() - aci.getBeginIndex()) != 1) {
+ breaker = new TextRunBreaker(aci, this.frc);
+ tmc = new TextMetricsCalculator(breaker);
+ } else {
+ breaker.deleteChar(newParagraph, deletePos);
+ }
+ }
+
+ /**
+ * Returns a copy of this object.
+ *
+ * @return a copy of this object.
+ */
+ @Override
+ protected Object clone() {
+ return new TextMeasurer((AttributedCharacterIterator) aci.clone(), frc);
+ }
+
+ /**
+ * Returns a TextLayout of the specified character range.
+ *
+ * @param start the index of the first character.
+ * @param limit the index after the last character.
+ *
+ * @return a TextLayout for the characters beginning at "start" up
+ * to "end".
+ */
+ public TextLayout getLayout(int start, int limit) {
+ breaker.pushSegments(start - aci.getBeginIndex(), limit - aci.getBeginIndex());
+
+ breaker.createAllSegments();
+ TextLayout layout = new TextLayout((TextRunBreaker) breaker.clone());
+
+ breaker.popSegments();
+ return layout;
+ }
+
+ /**
+ * Returns the graphical width of a line beginning at "start"
+ * parameter and including characters up to "end" parameter.
+ * "start" and "end" are absolute indices, not relative to the
+ * "start" of the paragraph.
+ *
+ * @param start the character index at which to start measuring.
+ * @param end the character index at which to stop measuring.
+ *
+ * @return the graphical width of a line beginning at "start"
+ * and including characters up to "end".
+ */
+ public float getAdvanceBetween(int start, int end) {
+ breaker.pushSegments(start - aci.getBeginIndex(), end - aci.getBeginIndex());
+
+ breaker.createAllSegments();
+ float retval = tmc.createMetrics().getAdvance();
+
+ breaker.popSegments();
+ return retval;
+ }
+
+ /**
+ * Returns the index of the first character which is not fit on
+ * a line beginning at start and possible measuring up to maxAdvance
+ * in graphical width.
+ *
+ * @param start he character index at which to start measuring.
+ * @param maxAdvance the graphical width in which the line must fit.
+ *
+ * @return the index after the last character that is fit on a line
+ * beginning at start, which is not longer than maxAdvance in graphical
+ * width.
+ */
+ public int getLineBreakIndex(int start, float maxAdvance) {
+ breaker.createAllSegments();
+ return breaker.getLineBreakIndex(
+ start - aci.getBeginIndex(), maxAdvance) + aci.getBeginIndex();
+ }
+}
+
diff --git a/awt/java/awt/font/TransformAttribute.java b/awt/java/awt/font/TransformAttribute.java
new file mode 100644
index 0000000..7c9b0bd
--- /dev/null
+++ b/awt/java/awt/font/TransformAttribute.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package java.awt.font;
+
+import java.awt.geom.AffineTransform;
+import java.io.Serializable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The TransformAttribute class is a wrapper for the AffineTransform class in
+ * order to use it as attribute.
+ */
+public final class TransformAttribute implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 3356247357827709530L;
+
+ // affine transform of this TransformAttribute instance
+ /** The transform. */
+ private AffineTransform fTransform;
+
+ /**
+ * Instantiates a new TransformAttribute from the specified
+ * AffineTransform.
+ *
+ * @param transform the AffineTransform to be wrapped.
+ */
+ public TransformAttribute(AffineTransform transform) {
+ if (transform == null) {
+ // awt.94=transform can not be null
+ throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$
+ }
+ if (!transform.isIdentity()){
+ this.fTransform = new AffineTransform(transform);
+ }
+ }
+
+ /**
+ * Gets the initial AffineTransform which is wrapped.
+ *
+ * @return the initial AffineTransform which is wrapped.
+ */
+ public AffineTransform getTransform() {
+ if (fTransform != null){
+ return new AffineTransform(fTransform);
+ }
+ return new AffineTransform();
+ }
+
+ /**
+ * Checks if this transform is an identity transform.
+ *
+ * @return true, if this transform is an identity transform,
+ * false otherwise.
+ */
+ public boolean isIdentity() {
+ return (fTransform == null);
+ }
+
+}
+
diff --git a/awt/java/awt/geom/AffineTransform.java b/awt/java/awt/geom/AffineTransform.java
new file mode 100644
index 0000000..5fd3934
--- /dev/null
+++ b/awt/java/awt/geom/AffineTransform.java
@@ -0,0 +1,1158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Shape;
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Class AffineTransform represents a linear transformation
+ * (rotation, scaling, or shear) followed by a translation that
+ * acts on a coordinate space. It preserves colinearity of points
+ * and ratios of distances between collinear points: so if A, B,
+ * and C are on a line, then after the space has been transformed
+ * via the affine transform, the images of the three points will
+ * still be on a line, and the ratio of the distance from A to B
+ * with the distance from B to C will be the same as the corresponding
+ * ratio in the image space.
+ */
+public class AffineTransform implements Cloneable, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 1330973210523860834L;
+
+ /** The Constant TYPE_IDENTITY. */
+ public static final int TYPE_IDENTITY = 0;
+
+ /** The Constant TYPE_TRANSLATION. */
+ public static final int TYPE_TRANSLATION = 1;
+
+ /** The Constant TYPE_UNIFORM_SCALE. */
+ public static final int TYPE_UNIFORM_SCALE = 2;
+
+ /** The Constant TYPE_GENERAL_SCALE. */
+ public static final int TYPE_GENERAL_SCALE = 4;
+
+ /** The Constant TYPE_QUADRANT_ROTATION. */
+ public static final int TYPE_QUADRANT_ROTATION = 8;
+
+ /** The Constant TYPE_GENERAL_ROTATION. */
+ public static final int TYPE_GENERAL_ROTATION = 16;
+
+ /** The Constant TYPE_GENERAL_TRANSFORM. */
+ public static final int TYPE_GENERAL_TRANSFORM = 32;
+
+ /** The Constant TYPE_FLIP. */
+ public static final int TYPE_FLIP = 64;
+
+ /** The Constant TYPE_MASK_SCALE. */
+ public static final int TYPE_MASK_SCALE = TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE;
+
+ /** The Constant TYPE_MASK_ROTATION. */
+ public static final int TYPE_MASK_ROTATION = TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION;
+
+ /** The <code>TYPE_UNKNOWN</code> is an initial type value. */
+ static final int TYPE_UNKNOWN = -1;
+
+ /** The min value equivalent to zero. If absolute value less then ZERO it considered as zero. */
+ static final double ZERO = 1E-10;
+
+ /** The values of transformation matrix. */
+ double m00;
+
+ /** The m10. */
+ double m10;
+
+ /** The m01. */
+ double m01;
+
+ /** The m11. */
+ double m11;
+
+ /** The m02. */
+ double m02;
+
+ /** The m12. */
+ double m12;
+
+ /** The transformation <code>type</code>. */
+ transient int type;
+
+ /**
+ * Instantiates a new affine transform of type <code>TYPE_IDENTITY</code>
+ * (which leaves coordinates unchanged).
+ */
+ public AffineTransform() {
+ type = TYPE_IDENTITY;
+ m00 = m11 = 1.0;
+ m10 = m01 = m02 = m12 = 0.0;
+ }
+
+ /**
+ * Instantiates a new affine transform that has the same data as
+ * the given AffineTransform.
+ *
+ * @param t the transform to copy.
+ */
+ public AffineTransform(AffineTransform t) {
+ this.type = t.type;
+ this.m00 = t.m00;
+ this.m10 = t.m10;
+ this.m01 = t.m01;
+ this.m11 = t.m11;
+ this.m02 = t.m02;
+ this.m12 = t.m12;
+ }
+
+ /**
+ * Instantiates a new affine transform by specifying the values of the 2x3
+ * transformation matrix as floats. The type is set to the default
+ * type: <code>TYPE_UNKNOWN</code>
+ *
+ * @param m00 the m00 entry in the transformation matrix.
+ * @param m10 the m10 entry in the transformation matrix.
+ * @param m01 the m01 entry in the transformation matrix.
+ * @param m11 the m11 entry in the transformation matrix.
+ * @param m02 the m02 entry in the transformation matrix.
+ * @param m12 the m12 entry in the transformation matrix.
+ */
+ public AffineTransform(float m00, float m10, float m01, float m11, float m02, float m12) {
+ this.type = TYPE_UNKNOWN;
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m02 = m02;
+ this.m12 = m12;
+ }
+
+ /**
+ * Instantiates a new affine transform by specifying the values of the 2x3
+ * transformation matrix as doubles. The type is set to the default
+ * type: <code>TYPE_UNKNOWN</code>
+ *
+ * @param m00 the m00 entry in the transformation matrix.
+ * @param m10 the m10 entry in the transformation matrix.
+ * @param m01 the m01 entry in the transformation matrix.
+ * @param m11 the m11 entry in the transformation matrix.
+ * @param m02 the m02 entry in the transformation matrix.
+ * @param m12 the m12 entry in the transformation matrix.
+ */
+ public AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12) {
+ this.type = TYPE_UNKNOWN;
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m02 = m02;
+ this.m12 = m12;
+ }
+
+ /**
+ * Instantiates a new affine transform by reading the values of the
+ * transformation matrix from an array of floats. The mapping from the
+ * array to the matrix starts with <code>matrix[0]</code> giving the
+ * top-left entry of the matrix and
+ * proceeds with the usual left-to-right and top-down ordering.
+ * <p>
+ * If the array has only four entries, then the two entries of the
+ * last row of the transformation matrix default to zero.
+ *
+ * @param matrix the array of four or six floats giving the values
+ * of the matrix.
+ *
+ * @throws ArrayIndexOutOfBoundsException if the size of the array
+ * is 0, 1, 2, 3, or 5.
+ */
+ public AffineTransform(float[] matrix) {
+ this.type = TYPE_UNKNOWN;
+ m00 = matrix[0];
+ m10 = matrix[1];
+ m01 = matrix[2];
+ m11 = matrix[3];
+ if (matrix.length > 4) {
+ m02 = matrix[4];
+ m12 = matrix[5];
+ }
+ }
+
+ /**
+ * Instantiates a new affine transform by reading the values of the
+ * transformation matrix from an array of doubles. The mapping from the
+ * array to the matrix starts with <code>matrix[0]</code> giving the
+ * top-left entry of the matrix and
+ * proceeds with the usual left-to-right and top-down ordering.
+ * <p>
+ * If the array has only four entries, then the two entries of the
+ * last row of the transformation matrix default to zero.
+ *
+ * @param matrix the array of four or six doubles giving the values
+ * of the matrix.
+ *
+ * @throws ArrayIndexOutOfBoundsException if the size of the array
+ * is 0, 1, 2, 3, or 5.
+ */
+ public AffineTransform(double[] matrix) {
+ this.type = TYPE_UNKNOWN;
+ m00 = matrix[0];
+ m10 = matrix[1];
+ m01 = matrix[2];
+ m11 = matrix[3];
+ if (matrix.length > 4) {
+ m02 = matrix[4];
+ m12 = matrix[5];
+ }
+ }
+
+
+ /**
+ * Returns type of the affine transformation.
+ * <p>
+ * The type is computed as follows: Label the entries of the
+ * transformation matrix as three rows (m00, m01), (m10, m11), and
+ * (m02, m12). Then if the original basis vectors are (1, 0) and (0, 1),
+ * the new basis vectors after transformation are given by (m00, m01)
+ * and (m10, m11), and the translation vector is (m02, m12).
+ * <p>
+ * The types are classified as follows: <br/>
+ * TYPE_IDENTITY - no change<br/>
+ * TYPE_TRANSLATION - The translation vector isn't zero<br/>
+ * TYPE_UNIFORM_SCALE - The new basis vectors have equal length<br/>
+ * TYPE_GENERAL_SCALE - The new basis vectors dont' have equal length<br/>
+ * TYPE_FLIP - The new basis vector orientation differs from the original one<br/>
+ * TYPE_QUADRANT_ROTATION - The new basis is a rotation of the original by 90, 180, 270, or 360 degrees<br/>
+ * TYPE_GENERAL_ROTATION - The new basis is a rotation of the original by an arbitrary angle<br/>
+ * TYPE_GENERAL_TRANSFORM - The transformation can't be inverted.<br/>
+ * <p>
+ * Note that multiple types are possible, thus the types can be combined
+ * using bitwise combinations.
+ *
+ * @return the type of the Affine Transform.
+ */
+ public int getType() {
+ if (type != TYPE_UNKNOWN) {
+ return type;
+ }
+
+ int type = 0;
+
+ if (m00 * m01 + m10 * m11 != 0.0) {
+ type |= TYPE_GENERAL_TRANSFORM;
+ return type;
+ }
+
+ if (m02 != 0.0 || m12 != 0.0) {
+ type |= TYPE_TRANSLATION;
+ } else
+ if (m00 == 1.0 && m11 == 1.0 && m01 == 0.0 && m10 == 0.0) {
+ type = TYPE_IDENTITY;
+ return type;
+ }
+
+ if (m00 * m11 - m01 * m10 < 0.0) {
+ type |= TYPE_FLIP;
+ }
+
+ double dx = m00 * m00 + m10 * m10;
+ double dy = m01 * m01 + m11 * m11;
+ if (dx != dy) {
+ type |= TYPE_GENERAL_SCALE;
+ } else
+ if (dx != 1.0) {
+ type |= TYPE_UNIFORM_SCALE;
+ }
+
+ if ((m00 == 0.0 && m11 == 0.0) ||
+ (m10 == 0.0 && m01 == 0.0 && (m00 < 0.0 || m11 < 0.0)))
+ {
+ type |= TYPE_QUADRANT_ROTATION;
+ } else
+ if (m01 != 0.0 || m10 != 0.0) {
+ type |= TYPE_GENERAL_ROTATION;
+ }
+
+ return type;
+ }
+
+ /**
+ * Gets the scale x entry of the transformation matrix
+ * (the upper left matrix entry).
+ *
+ * @return the scale x value.
+ */
+ public double getScaleX() {
+ return m00;
+ }
+
+ /**
+ * Gets the scale y entry of the transformation matrix
+ * (the lower right entry of the linear transformation).
+ *
+ * @return the scale y value.
+ */
+ public double getScaleY() {
+ return m11;
+ }
+
+ /**
+ * Gets the shear x entry of the transformation matrix
+ * (the upper right entry of the linear transformation).
+ *
+ * @return the shear x value.
+ */
+ public double getShearX() {
+ return m01;
+ }
+
+ /**
+ * Gets the shear y entry of the transformation matrix
+ * (the lower left entry of the linear transformation).
+ *
+ * @return the shear y value.
+ */
+ public double getShearY() {
+ return m10;
+ }
+
+ /**
+ * Gets the x coordinate of the translation vector.
+ *
+ * @return the x coordinate of the translation vector.
+ */
+ public double getTranslateX() {
+ return m02;
+ }
+
+ /**
+ * Gets the y coordinate of the translation vector.
+ *
+ * @return the y coordinate of the translation vector.
+ */
+ public double getTranslateY() {
+ return m12;
+ }
+
+ /**
+ * Checks if the AffineTransformation is the identity.
+ *
+ * @return true, if the AffineTransformation is the identity.
+ */
+ public boolean isIdentity() {
+ return getType() == TYPE_IDENTITY;
+ }
+
+ /**
+ * Writes the values of the transformation matrix into the given
+ * array of doubles. If the array has length 4, only the linear
+ * transformation part will be written into it. If it has length
+ * greater than 4, the translation vector will be included as well.
+ *
+ * @param matrix the array to fill with the values of the matrix.
+ *
+ * @throws ArrayIndexOutOfBoundsException if the size of the array
+ * is 0, 1, 2, 3, or 5.
+ */
+ public void getMatrix(double[] matrix) {
+ matrix[0] = m00;
+ matrix[1] = m10;
+ matrix[2] = m01;
+ matrix[3] = m11;
+ if (matrix.length > 4) {
+ matrix[4] = m02;
+ matrix[5] = m12;
+ }
+ }
+
+ /**
+ * Gets the determinant of the linear transformation matrix.
+ *
+ * @return the determinant of the linear transformation matrix.
+ */
+ public double getDeterminant() {
+ return m00 * m11 - m01 * m10;
+ }
+
+ /**
+ * Sets the transform in terms of a list of double values.
+ *
+ * @param m00 the m00 coordinate of the transformation matrix.
+ * @param m10 the m10 coordinate of the transformation matrix.
+ * @param m01 the m01 coordinate of the transformation matrix.
+ * @param m11 the m11 coordinate of the transformation matrix.
+ * @param m02 the m02 coordinate of the transformation matrix.
+ * @param m12 the m12 coordinate of the transformation matrix.
+ */
+ public void setTransform(double m00, double m10, double m01, double m11, double m02, double m12) {
+ this.type = TYPE_UNKNOWN;
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m02 = m02;
+ this.m12 = m12;
+ }
+
+ /**
+ * Sets the transform's data to match the data of the transform
+ * sent as a parameter.
+ *
+ * @param t the transform that gives the new values.
+ */
+ public void setTransform(AffineTransform t) {
+ type = t.type;
+ setTransform(t.m00, t.m10, t.m01, t.m11, t.m02, t.m12);
+ }
+
+ /**
+ * Sets the transform to the identity transform.
+ */
+ public void setToIdentity() {
+ type = TYPE_IDENTITY;
+ m00 = m11 = 1.0;
+ m10 = m01 = m02 = m12 = 0.0;
+ }
+
+ /**
+ * Sets the transformation to a translation alone.
+ * Sets the linear part of the transformation to identity
+ * and the translation vector to the values sent as parameters.
+ * Sets the type to <code>TYPE_IDENTITY</code>
+ * if the resulting AffineTransformation is the identity
+ * transformation, otherwise sets it to <code>TYPE_TRANSLATION</code>.
+ *
+ * @param mx the distance to translate in the x direction.
+ * @param my the distance to translate in the y direction.
+ */
+ public void setToTranslation(double mx, double my) {
+ m00 = m11 = 1.0;
+ m01 = m10 = 0.0;
+ m02 = mx;
+ m12 = my;
+ if (mx == 0.0 && my == 0.0) {
+ type = TYPE_IDENTITY;
+ } else {
+ type = TYPE_TRANSLATION;
+ }
+ }
+
+ /**
+ * Sets the transformation to being a scale alone, eliminating
+ * rotation, shear, and translation elements.
+ * Sets the type to <code>TYPE_IDENTITY</code>
+ * if the resulting AffineTransformation is the identity
+ * transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
+ *
+ * @param scx the scaling factor in the x direction.
+ * @param scy the scaling factor in the y direction.
+ */
+ public void setToScale(double scx, double scy) {
+ m00 = scx;
+ m11 = scy;
+ m10 = m01 = m02 = m12 = 0.0;
+ if (scx != 1.0 || scy != 1.0) {
+ type = TYPE_UNKNOWN;
+ } else {
+ type = TYPE_IDENTITY;
+ }
+ }
+
+ /**
+ * Sets the transformation to being a shear alone, eliminating
+ * rotation, scaling, and translation elements.
+ * Sets the type to <code>TYPE_IDENTITY</code>
+ * if the resulting AffineTransformation is the identity
+ * transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
+ *
+ * @param shx the shearing factor in the x direction.
+ * @param shy the shearing factor in the y direction.
+ */
+ public void setToShear(double shx, double shy) {
+ m00 = m11 = 1.0;
+ m02 = m12 = 0.0;
+ m01 = shx;
+ m10 = shy;
+ if (shx != 0.0 || shy != 0.0) {
+ type = TYPE_UNKNOWN;
+ } else {
+ type = TYPE_IDENTITY;
+ }
+ }
+
+ /**
+ * Sets the transformation to being a rotation alone, eliminating
+ * shearing, scaling, and translation elements.
+ * Sets the type to <code>TYPE_IDENTITY</code>
+ * if the resulting AffineTransformation is the identity
+ * transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
+ *
+ * @param angle the angle of rotation in radians.
+ */
+ public void setToRotation(double angle) {
+ double sin = Math.sin(angle);
+ double cos = Math.cos(angle);
+ if (Math.abs(cos) < ZERO) {
+ cos = 0.0;
+ sin = sin > 0.0 ? 1.0 : -1.0;
+ } else
+ if (Math.abs(sin) < ZERO) {
+ sin = 0.0;
+ cos = cos > 0.0 ? 1.0 : -1.0;
+ }
+ m00 = m11 = cos;
+ m01 = -sin;
+ m10 = sin;
+ m02 = m12 = 0.0;
+ type = TYPE_UNKNOWN;
+ }
+
+ /**
+ * Sets the transformation to being a rotation followed by a
+ * translation.
+ * Sets the type to <code>TYPE_UNKNOWN</code>.
+ *
+ * @param angle the angle of rotation in radians.
+ * @param px the distance to translate in the x direction.
+ * @param py the distance to translate in the y direction.
+ */
+ public void setToRotation(double angle, double px, double py) {
+ setToRotation(angle);
+ m02 = px * (1.0 - m00) + py * m10;
+ m12 = py * (1.0 - m00) - px * m10;
+ type = TYPE_UNKNOWN;
+ }
+
+ /**
+ * Creates a new AffineTransformation that is a translation alone
+ * with the translation vector given by the values sent as parameters.
+ * The new transformation's type is <code>TYPE_IDENTITY</code>
+ * if the AffineTransformation is the identity
+ * transformation, otherwise it's <code>TYPE_TRANSLATION</code>.
+ *
+ * @param mx the distance to translate in the x direction.
+ * @param my the distance to translate in the y direction.
+
+ * @return the new AffineTransformation.
+ */
+ public static AffineTransform getTranslateInstance(double mx, double my) {
+ AffineTransform t = new AffineTransform();
+ t.setToTranslation(mx, my);
+ return t;
+ }
+
+ /**
+ * Creates a new AffineTransformation that is a scale alone.
+ * The new transformation's type is <code>TYPE_IDENTITY</code>
+ * if the AffineTransformation is the identity
+ * transformation, otherwise it's <code>TYPE_UNKNOWN</code>.
+ *
+ * @param scx the scaling factor in the x direction.
+ * @param scY the scaling factor in the y direction.
+ *
+ * @return the new AffineTransformation.
+ */
+ public static AffineTransform getScaleInstance(double scx, double scY) {
+ AffineTransform t = new AffineTransform();
+ t.setToScale(scx, scY);
+ return t;
+ }
+
+ /**
+ * Creates a new AffineTransformation that is a shear alone.
+ * The new transformation's type is <code>TYPE_IDENTITY</code>
+ * if the AffineTransformation is the identity
+ * transformation, otherwise it's <code>TYPE_UNKNOWN</code>.
+ *
+ * @param shx the shearing factor in the x direction.
+ * @param shy the shearing factor in the y direction.
+ *
+ * @return the new AffineTransformation.
+ */
+ public static AffineTransform getShearInstance(double shx, double shy) {
+ AffineTransform m = new AffineTransform();
+ m.setToShear(shx, shy);
+ return m;
+ }
+
+ /**
+ * Creates a new AffineTransformation that is a rotation alone.
+ * The new transformation's type is <code>TYPE_IDENTITY</code>
+ * if the AffineTransformation is the identity
+ * transformation, otherwise it's <code>TYPE_UNKNOWN</code>.
+ *
+ * @param angle the angle of rotation in radians.
+ *
+ * @return the new AffineTransformation.
+ */
+ public static AffineTransform getRotateInstance(double angle) {
+ AffineTransform t = new AffineTransform();
+ t.setToRotation(angle);
+ return t;
+ }
+
+ /**
+ * Creates a new AffineTransformation that is a rotation followed by a
+ * translation.
+ * Sets the type to <code>TYPE_UNKNOWN</code>.
+ *
+ * @param angle the angle of rotation in radians.
+ * @param x the distance to translate in the x direction.
+ * @param y the distance to translate in the y direction.
+ *
+ * @return the new AffineTransformation.
+ */
+ public static AffineTransform getRotateInstance(double angle, double x, double y) {
+ AffineTransform t = new AffineTransform();
+ t.setToRotation(angle, x, y);
+ return t;
+ }
+
+ /**
+ * Applies a translation to this AffineTransformation.
+ *
+ * @param mx the distance to translate in the x direction.
+ * @param my the distance to translate in the y direction.
+ */
+ public void translate(double mx, double my) {
+ concatenate(AffineTransform.getTranslateInstance(mx, my));
+ }
+
+ /**
+ * Applies a scaling transformation to this AffineTransformation.
+ *
+ * @param scx the scaling factor in the x direction.
+ * @param scy the scaling factor in the y direction.
+ */
+ public void scale(double scx, double scy) {
+ concatenate(AffineTransform.getScaleInstance(scx, scy));
+ }
+
+ /**
+ * Applies a shearing transformation to this AffineTransformation.
+ *
+ * @param shx the shearing factor in the x direction.
+ * @param shy the shearing factor in the y direction.
+ */
+ public void shear(double shx, double shy) {
+ concatenate(AffineTransform.getShearInstance(shx, shy));
+ }
+
+ /**
+ * Applies a rotation transformation to this AffineTransformation.
+ *
+ * @param angle the angle of rotation in radians.
+ */
+ public void rotate(double angle) {
+ concatenate(AffineTransform.getRotateInstance(angle));
+ }
+
+ /**
+ * Applies a rotation and translation transformation to this
+ * AffineTransformation.
+ *
+ * @param angle the angle of rotation in radians.
+ * @param px the distance to translate in the x direction.
+ * @param py the distance to translate in the y direction.
+ */
+ public void rotate(double angle, double px, double py) {
+ concatenate(AffineTransform.getRotateInstance(angle, px, py));
+ }
+
+ /**
+ * Multiplies the matrix representations of two AffineTransform objects.
+ *
+ * @param t1 - the AffineTransform object is a multiplicand
+ * @param t2 - the AffineTransform object is a multiplier
+ *
+ * @return an AffineTransform object that is the result of t1 multiplied by the matrix t2.
+ */
+ AffineTransform multiply(AffineTransform t1, AffineTransform t2) {
+ return new AffineTransform(
+ t1.m00 * t2.m00 + t1.m10 * t2.m01, // m00
+ t1.m00 * t2.m10 + t1.m10 * t2.m11, // m01
+ t1.m01 * t2.m00 + t1.m11 * t2.m01, // m10
+ t1.m01 * t2.m10 + t1.m11 * t2.m11, // m11
+ t1.m02 * t2.m00 + t1.m12 * t2.m01 + t2.m02, // m02
+ t1.m02 * t2.m10 + t1.m12 * t2.m11 + t2.m12);// m12
+ }
+
+ /**
+ * Applies the given AffineTransform to this AffineTransform
+ * via matrix multiplication.
+ *
+ * @param t the AffineTransform to apply to this AffineTransform.
+ */
+ public void concatenate(AffineTransform t) {
+ setTransform(multiply(t, this));
+ }
+
+ /**
+ * Changes the current AffineTransform the one obtained by
+ * taking the transform t and applying this AffineTransform to it.
+ *
+ * @param t the AffineTransform that this AffineTransform is multiplied by.
+ */
+ public void preConcatenate(AffineTransform t) {
+ setTransform(multiply(this, t));
+ }
+
+ /**
+ * Creates an AffineTransform that is the inverse of this transform.
+ *
+ * @return the affine transform that is the inverse of this AffineTransform.
+ *
+ * @throws NoninvertibleTransformException if this AffineTransform cannot be
+ * inverted (the determinant of the linear transformation part is zero).
+ */
+ public AffineTransform createInverse() throws NoninvertibleTransformException {
+ double det = getDeterminant();
+ if (Math.abs(det) < ZERO) {
+ // awt.204=Determinant is zero
+ throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
+ }
+ return new AffineTransform(
+ m11 / det, // m00
+ -m10 / det, // m10
+ -m01 / det, // m01
+ m00 / det, // m11
+ (m01 * m12 - m11 * m02) / det, // m02
+ (m10 * m02 - m00 * m12) / det // m12
+ );
+ }
+
+ /**
+ * Apply the current AffineTransform to the point.
+ *
+ * @param src the original point.
+ * @param dst Point2D object to be filled with the destination
+ * coordinates (where the original point is sent by this AffineTransform). May be null.
+ *
+ * @return the point in the AffineTransform's image space where the
+ * original point is sent.
+ */
+ public Point2D transform(Point2D src, Point2D dst) {
+ if (dst == null) {
+ if (src instanceof Point2D.Double) {
+ dst = new Point2D.Double();
+ } else {
+ dst = new Point2D.Float();
+ }
+ }
+
+ double x = src.getX();
+ double y = src.getY();
+
+ dst.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
+ return dst;
+ }
+
+ /**
+ * Applies this AffineTransform to an array of points.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length > src.length</code> or
+ * <code>dstOff + length > dst.length</code>.
+ */
+ public void transform(Point2D[] src, int srcOff, Point2D[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ Point2D srcPoint = src[srcOff++];
+ double x = srcPoint.getX();
+ double y = srcPoint.getY();
+ Point2D dstPoint = dst[dstOff];
+ if (dstPoint == null) {
+ if (srcPoint instanceof Point2D.Double) {
+ dstPoint = new Point2D.Double();
+ } else {
+ dstPoint = new Point2D.Float();
+ }
+ }
+ dstPoint.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
+ dst[dstOff++] = dstPoint;
+ }
+ }
+
+ /**
+ * Applies this AffineTransform to a set of points given
+ * as an array of double values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ */
+ public void transform(double[] src, int srcOff, double[] dst, int dstOff, int length) {
+ int step = 2;
+ if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) {
+ srcOff = srcOff + length * 2 - 2;
+ dstOff = dstOff + length * 2 - 2;
+ step = -2;
+ }
+ while (--length >= 0) {
+ double x = src[srcOff + 0];
+ double y = src[srcOff + 1];
+ dst[dstOff + 0] = x * m00 + y * m01 + m02;
+ dst[dstOff + 1] = x * m10 + y * m11 + m12;
+ srcOff += step;
+ dstOff += step;
+ }
+ }
+
+ /**
+ * Applies this AffineTransform to a set of points given
+ * as an array of float values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ */
+ public void transform(float[] src, int srcOff, float[] dst, int dstOff, int length) {
+ int step = 2;
+ if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) {
+ srcOff = srcOff + length * 2 - 2;
+ dstOff = dstOff + length * 2 - 2;
+ step = -2;
+ }
+ while (--length >= 0) {
+ float x = src[srcOff + 0];
+ float y = src[srcOff + 1];
+ dst[dstOff + 0] = (float)(x * m00 + y * m01 + m02);
+ dst[dstOff + 1] = (float)(x * m10 + y * m11 + m12);
+ srcOff += step;
+ dstOff += step;
+ }
+ }
+
+ /**
+ * Applies this AffineTransform to a set of points given
+ * as an array of float values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ * The destination coordinates are given as values of type <code>double</code>.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ */
+ public void transform(float[] src, int srcOff, double[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ float x = src[srcOff++];
+ float y = src[srcOff++];
+ dst[dstOff++] = x * m00 + y * m01 + m02;
+ dst[dstOff++] = x * m10 + y * m11 + m12;
+ }
+ }
+
+ /**
+ * Applies this AffineTransform to a set of points given
+ * as an array of double values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ * The destination coordinates are given as values of type <code>float</code>.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ */
+ public void transform(double[] src, int srcOff, float[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ double x = src[srcOff++];
+ double y = src[srcOff++];
+ dst[dstOff++] = (float)(x * m00 + y * m01 + m02);
+ dst[dstOff++] = (float)(x * m10 + y * m11 + m12);
+ }
+ }
+
+ /**
+ * Transforms the point according to the linear transformation
+ * part of this AffineTransformation (without applying the translation).
+ *
+ * @param src the original point.
+ * @param dst the point object where the result of the delta transform
+ * is written.
+ *
+ * @return the result of applying the delta transform (linear part
+ * only) to the original point.
+ */
+ // TODO: is this right? if dst is null, we check what it's an
+ // instance of? Shouldn't it be src instanceof Point2D.Double?
+ public Point2D deltaTransform(Point2D src, Point2D dst) {
+ if (dst == null) {
+ if (dst instanceof Point2D.Double) {
+ dst = new Point2D.Double();
+ } else {
+ dst = new Point2D.Float();
+ }
+ }
+
+ double x = src.getX();
+ double y = src.getY();
+
+ dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
+ return dst;
+ }
+
+ /**
+ * Applies the linear transformation part of this AffineTransform
+ * (ignoring the translation part) to a set of points given
+ * as an array of double values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the delta transformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ */
+ public void deltaTransform(double[] src, int srcOff, double[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ double x = src[srcOff++];
+ double y = src[srcOff++];
+ dst[dstOff++] = x * m00 + y * m01;
+ dst[dstOff++] = x * m10 + y * m11;
+ }
+ }
+
+ /**
+ * Transforms the point according to the inverse of this AffineTransformation.
+ *
+ * @param src the original point.
+ * @param dst the point object where the result of the inverse transform
+ * is written (may be null).
+ *
+ * @return the result of applying the inverse transform.
+ * Inverse transform.
+ *
+ * @throws NoninvertibleTransformException if this AffineTransform cannot be
+ * inverted (the determinant of the linear transformation part is zero).
+ */
+ public Point2D inverseTransform(Point2D src, Point2D dst) throws NoninvertibleTransformException {
+ double det = getDeterminant();
+ if (Math.abs(det) < ZERO) {
+ // awt.204=Determinant is zero
+ throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
+ }
+
+ if (dst == null) {
+ if (src instanceof Point2D.Double) {
+ dst = new Point2D.Double();
+ } else {
+ dst = new Point2D.Float();
+ }
+ }
+
+ double x = src.getX() - m02;
+ double y = src.getY() - m12;
+
+ dst.setLocation((x * m11 - y * m01) / det, (y * m00 - x * m10) / det);
+ return dst;
+ }
+
+ /**
+ * Applies the inverse of this AffineTransform to a set of points given
+ * as an array of double values where every two values in the array
+ * give the coordinates of a point; the even-indexed values giving the
+ * x coordinates and the odd-indexed values giving the y coordinates.
+ *
+ * @param src the array of points to be transformed.
+ * @param srcOff the offset in the source point array of the first point
+ * to be transformed.
+ * @param dst the point array where the images of the points (after
+ * applying the inverse of the AffineTransformation) should be placed.
+ * @param dstOff the offset in the destination array where the new
+ * values should be written.
+ * @param length the number of points to transform.
+ *
+ * @throws ArrayIndexOutOfBoundsException if
+ * <code>srcOff + length*2 > src.length</code> or
+ * <code>dstOff + length*2 > dst.length</code>.
+ * @throws NoninvertibleTransformException if this AffineTransform cannot be
+ * inverted (the determinant of the linear transformation part is zero).
+ */
+ public void inverseTransform(double[] src, int srcOff, double[] dst, int dstOff, int length)
+ throws NoninvertibleTransformException
+ {
+ double det = getDeterminant();
+ if (Math.abs(det) < ZERO) {
+ // awt.204=Determinant is zero
+ throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
+ }
+
+ while (--length >= 0) {
+ double x = src[srcOff++] - m02;
+ double y = src[srcOff++] - m12;
+ dst[dstOff++] = (x * m11 - y * m01) / det;
+ dst[dstOff++] = (y * m00 - x * m10) / det;
+ }
+ }
+
+ /**
+ * Creates a new shape whose data is given by applying this
+ * AffineTransform to the specified shape.
+ *
+ * @param src the original shape whose data is to be transformed.
+ *
+ * @return the new shape found by applying this AffineTransform to
+ * the original shape.
+ */
+ public Shape createTransformedShape(Shape src) {
+ if (src == null) {
+ return null;
+ }
+ if (src instanceof GeneralPath) {
+ return ((GeneralPath)src).createTransformedShape(this);
+ }
+ PathIterator path = src.getPathIterator(this);
+ GeneralPath dst = new GeneralPath(path.getWindingRule());
+ dst.append(path, false);
+ return dst;
+ }
+
+ @Override
+ public String toString() {
+ return
+ getClass().getName() +
+ "[[" + m00 + ", " + m01 + ", " + m02 + "], [" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ + m10 + ", " + m11 + ", " + m12 + "]]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(m00);
+ hash.append(m01);
+ hash.append(m02);
+ hash.append(m10);
+ hash.append(m11);
+ hash.append(m12);
+ return hash.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof AffineTransform) {
+ AffineTransform t = (AffineTransform)obj;
+ return
+ m00 == t.m00 && m01 == t.m01 &&
+ m02 == t.m02 && m10 == t.m10 &&
+ m11 == t.m11 && m12 == t.m12;
+ }
+ return false;
+ }
+
+
+ /**
+ * Writes the AffineTrassform object to the output steam.
+ *
+ * @param stream - the output stream
+ *
+ * @throws IOException - if there are I/O errors while writing to the output strem
+ */
+ private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ }
+
+
+ /**
+ * Read the AffineTransform object from the input stream.
+ *
+ * @param stream - the input steam
+ *
+ * @throws IOException - if there are I/O errors while reading from the input strem
+ * @throws ClassNotFoundException - if class could not be found
+ */
+ private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ type = TYPE_UNKNOWN;
+ }
+
+}
+
diff --git a/awt/java/awt/geom/Arc2D.java b/awt/java/awt/geom/Arc2D.java
new file mode 100644
index 0000000..bc1e95c
--- /dev/null
+++ b/awt/java/awt/geom/Arc2D.java
@@ -0,0 +1,1028 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Arc2D represents a segment of a curve inscribed
+ * in a rectangle. The curve is defined by a start angle and an
+ * extent angle (the end angle minus the start angle) as
+ * a pie wedge whose point is in the center of the rectangle.
+ * The Arc2D as a shape may be either OPEN (including nothing
+ * but the curved arc segment itself), CHORD (the curved arc
+ * segment closed by a connecting segment from the end to the
+ * beginning of the arc, or PIE (the segments from the end
+ * of the arc to the center of the rectangle and from the
+ * center of the rectangle back to the arc's start point are
+ * included).
+ */
+public abstract class Arc2D extends RectangularShape {
+
+ /** The arc type OPEN indicates that the shape includes only the
+ * curved arc segment. */
+ public final static int OPEN = 0;
+
+ /** The arc type CHORD indicates that as a shape the connecting
+ * segment from the end point of the curved arc to the beginning
+ * point is included. */
+ public final static int CHORD = 1;
+
+ /** The arc type PIE indicates that as a shape the two segments
+ * from the arc's endpoint to the center of the rectangle and from
+ * the center of the rectangle to the arc's endpoint are included. */
+ public final static int PIE = 2;
+
+ /**
+ * The Class Float is a subclass of Arc2D in which all of the
+ * data values are given as floats.
+ * @see Arc2D.Double
+ */
+ public static class Float extends Arc2D {
+
+ /** The x coordinate of the upper left corner of the rectangle that
+ * contains the arc. */
+ public float x;
+
+ /** The y coordinate of the upper left corner of the rectangle that
+ * contains the arc. */
+ public float y;
+
+ /** The width of the rectangle that contains the arc. */
+ public float width;
+
+ /** The height of the rectangle that contains the arc. */
+ public float height;
+
+ /** The start angle of the arc in degrees. */
+ public float start;
+
+ /** The width angle of the arc in degrees. */
+ public float extent;
+
+ /**
+ * Instantiates a new Arc2D of type OPEN with float values.
+ */
+ public Float() {
+ super(OPEN);
+ }
+
+ /**
+ * Instantiates a new Arc2D of the specified type with float values.
+ *
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Float(int type) {
+ super(type);
+ }
+
+ /**
+ * Instantiates a Arc2D with the specified float-valued data.
+ *
+ * @param x the x coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param y the y coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param width the width of the rectangle that
+ * contains the arc.
+ * @param height the height of the rectangle that
+ * contains the arc.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the width angle of the arc in degrees.
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Float(float x, float y, float width, float height, float start, float extent, int type) {
+ super(type);
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.start = start;
+ this.extent = extent;
+ }
+
+ /**
+ * Instantiates a new Angle2D with the specified float-valued data
+ * and the bounding rectangle given by the parameter bounds.
+ *
+ * @param bounds the bounding rectangle of the Angle2D.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the width angle of the arc in degrees.
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Float(Rectangle2D bounds, float start, float extent, int type) {
+ super(type);
+ this.x = (float)bounds.getX();
+ this.y = (float)bounds.getY();
+ this.width = (float)bounds.getWidth();
+ this.height = (float)bounds.getHeight();
+ this.start = start;
+ this.extent = extent;
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public double getAngleStart() {
+ return start;
+ }
+
+ @Override
+ public double getAngleExtent() {
+ return extent;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0f || height <= 0.0f;
+ }
+
+ @Override
+ public void setArc(double x, double y, double width, double height,
+ double start, double extent, int type)
+ {
+ this.setArcType(type);
+ this.x = (float)x;
+ this.y = (float)y;
+ this.width = (float)width;
+ this.height = (float)height;
+ this.start = (float)start;
+ this.extent = (float)extent;
+ }
+
+ @Override
+ public void setAngleStart(double start) {
+ this.start = (float)start;
+ }
+
+ @Override
+ public void setAngleExtent(double extent) {
+ this.extent = (float)extent;
+ }
+
+ @Override
+ protected Rectangle2D makeBounds(double x, double y, double width, double height) {
+ return new Rectangle2D.Float((float)x, (float)y, (float)width, (float)height);
+ }
+
+ }
+
+ /**
+ * The Class Double is a subclass of Arc2D in which all of the
+ * data values are given as doubles.
+ * @see Arc2D.Float
+ */
+ public static class Double extends Arc2D {
+
+ /** The x coordinate of the upper left corner of the rectangle that
+ * contains the arc. */
+ public double x;
+
+ /** The y coordinate of the upper left corner of the rectangle that
+ * contains the arc. */
+ public double y;
+
+ /** The width of the rectangle that contains the arc. */
+ public double width;
+
+ /** The height of the rectangle that contains the arc. */
+ public double height;
+
+ /** The start angle of the arc in degrees. */
+ public double start;
+
+ /** The width angle of the arc in degrees. */
+ public double extent;
+
+ /**
+ * Instantiates a new Arc2D of type OPEN with double values.
+ */
+ public Double() {
+ super(OPEN);
+ }
+
+ /**
+ * Instantiates a new Arc2D of the specified type with double values.
+ *
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Double(int type) {
+ super(type);
+ }
+
+ /**
+ * Instantiates a Arc2D with the specified double-valued data.
+ *
+ * @param x the x coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param y the y coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param width the width of the rectangle that
+ * contains the arc.
+ * @param height the height of the rectangle that
+ * contains the arc.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the width angle of the arc in degrees.
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Double(double x, double y, double width, double height,
+ double start, double extent, int type)
+ {
+ super(type);
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.start = start;
+ this.extent = extent;
+ }
+
+ /**
+ * Instantiates a new Angle2D with the specified float-valued data
+ * and the bounding rectangle given by the parameter bounds.
+ *
+ * @param bounds the bounding rectangle of the Angle2D.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the width angle of the arc in degrees.
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public Double(Rectangle2D bounds, double start, double extent, int type) {
+ super(type);
+ this.x = bounds.getX();
+ this.y = bounds.getY();
+ this.width = bounds.getWidth();
+ this.height = bounds.getHeight();
+ this.start = start;
+ this.extent = extent;
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public double getAngleStart() {
+ return start;
+ }
+
+ @Override
+ public double getAngleExtent() {
+ return extent;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0 || height <= 0.0;
+ }
+
+ @Override
+ public void setArc(double x, double y, double width, double height,
+ double start, double extent, int type)
+ {
+ this.setArcType(type);
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.start = start;
+ this.extent = extent;
+ }
+
+ @Override
+ public void setAngleStart(double start) {
+ this.start = start;
+ }
+
+ @Override
+ public void setAngleExtent(double extent) {
+ this.extent = extent;
+ }
+
+ @Override
+ protected Rectangle2D makeBounds(double x, double y, double width, double height) {
+ return new Rectangle2D.Double(x, y, width, height);
+ }
+
+ }
+
+ /**
+ * The Class Iterator is the subclass of PathIterator that is used to
+ * traverse the boundary of a shape of type Arc2D.
+ */
+ class Iterator implements PathIterator {
+
+ /** The x coordinate of the center of the arc's bounding rectangle. */
+ double x;
+
+ /** The y coordinate of the center of the arc's bounding rectangle. */
+ double y;
+
+ /** Half of the width of the arc's bounding rectangle (the radius in the case of a circular arc). */
+ double width;
+
+ /** Half of the height of the arc's bounding rectangle (the radius in the case of a circular arc). */
+ double height;
+
+ /** The start angle of the arc in degrees. */
+ double angle;
+
+ /** The angle extent in degrees. */
+ double extent;
+
+ /** The closure type of the arc. */
+ int type;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segment index. */
+ int index;
+
+ /** The number of arc segments the source arc subdivided to be approximated by Bezier curves. Depends on extent value. */
+ int arcCount;
+
+ /** The number of line segments. Depends on closure type. */
+ int lineCount;
+
+ /** The step to calculate next arc subdivision point. */
+ double step;
+
+ /** The temporary value of cosinus of the current angle. */
+ double cos;
+
+ /** The temporary value of sinus of the current angle. */
+ double sin;
+
+ /** The coefficient to calculate control points of Bezier curves. */
+ double k;
+
+ /** The temporary value of x coordinate of the Bezier curve control vector. */
+ double kx;
+
+ /** The temporary value of y coordinate of the Bezier curve control vector. */
+ double ky;
+
+ /** The x coordinate of the first path point (MOVE_TO). */
+ double mx;
+
+ /** The y coordinate of the first path point (MOVE_TO). */
+ double my;
+
+ /**
+ * Constructs a new Arc2D.Iterator for given line and transformation
+ *
+ * @param a - the source Arc2D object
+ * @param t the AffineTransformation.
+ */
+ Iterator(Arc2D a, AffineTransform t) {
+ if (width < 0 || height < 0) {
+ arcCount = 0;
+ lineCount = 0;
+ index = 1;
+ return;
+ }
+
+ this.width = a.getWidth() / 2.0;
+ this.height = a.getHeight() / 2.0;
+ this.x = a.getX() + width;
+ this.y = a.getY() + height;
+ this.angle = -Math.toRadians(a.getAngleStart());
+ this.extent = -a.getAngleExtent();
+ this.type = a.getArcType();
+ this.t = t;
+
+ if (Math.abs(extent) >= 360.0) {
+ arcCount = 4;
+ k = 4.0 / 3.0 * (Math.sqrt(2.0) - 1.0);
+ step = Math.PI / 2.0;
+ if (extent < 0.0) {
+ step = -step;
+ k = -k;
+ }
+ } else {
+ arcCount = (int)Math.rint(Math.abs(extent) / 90.0);
+ step = Math.toRadians(extent / arcCount);
+ k = 4.0 / 3.0 * (1.0 - Math.cos(step / 2.0))
+ / Math.sin(step / 2.0);
+ }
+
+ lineCount = 0;
+ if (type == Arc2D.CHORD) {
+ lineCount++;
+ } else if (type == Arc2D.PIE) {
+ lineCount += 2;
+ }
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > arcCount + lineCount;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ count = 1;
+ cos = Math.cos(angle);
+ sin = Math.sin(angle);
+ kx = k * width * sin;
+ ky = k * height * cos;
+ coords[0] = mx = x + cos * width;
+ coords[1] = my = y + sin * height;
+ } else if (index <= arcCount) {
+ type = SEG_CUBICTO;
+ count = 3;
+ coords[0] = mx - kx;
+ coords[1] = my + ky;
+ angle += step;
+ cos = Math.cos(angle);
+ sin = Math.sin(angle);
+ kx = k * width * sin;
+ ky = k * height * cos;
+ coords[4] = mx = x + cos * width;
+ coords[5] = my = y + sin * height;
+ coords[2] = mx + kx;
+ coords[3] = my - ky;
+ } else if (index == arcCount + lineCount) {
+ type = SEG_CLOSE;
+ count = 0;
+ } else {
+ type = SEG_LINETO;
+ count = 1;
+ coords[0] = x;
+ coords[1] = y;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ count = 1;
+ cos = Math.cos(angle);
+ sin = Math.sin(angle);
+ kx = k * width * sin;
+ ky = k * height * cos;
+ coords[0] = (float)(mx = x + cos * width);
+ coords[1] = (float)(my = y + sin * height);
+ } else if (index <= arcCount) {
+ type = SEG_CUBICTO;
+ count = 3;
+ coords[0] = (float)(mx - kx);
+ coords[1] = (float)(my + ky);
+ angle += step;
+ cos = Math.cos(angle);
+ sin = Math.sin(angle);
+ kx = k * width * sin;
+ ky = k * height * cos;
+ coords[4] = (float)(mx = x + cos * width);
+ coords[5] = (float)(my = y + sin * height);
+ coords[2] = (float)(mx + kx);
+ coords[3] = (float)(my - ky);
+ } else if (index == arcCount + lineCount) {
+ type = SEG_CLOSE;
+ count = 0;
+ } else {
+ type = SEG_LINETO;
+ count = 1;
+ coords[0] = (float)x;
+ coords[1] = (float)y;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ }
+
+ /** The closure type of the arc. */
+ private int type;
+
+ /**
+ * Instantiates a new arc2D.
+ *
+ * @param type the closure type.
+ */
+ protected Arc2D(int type) {
+ setArcType(type);
+ }
+
+ /**
+ * Takes the double-valued data and creates the corresponding Rectangle2D
+ * object with values either of type float or of type double depending on
+ * whether this Arc2D instance is of type Float or Double.
+ *
+ * @param x the x coordinate of the upper left corner of the bounding rectangle.
+ * @param y the y coordinate of the upper left corner of the bounding rectangle.
+ * @param width the width of the bounding rectangle.
+ * @param height the height of the bounding rectangle.
+ *
+ * @return the corresponding Rectangle2D object.
+ */
+ protected abstract Rectangle2D makeBounds(double x, double y, double width, double height);
+
+ /**
+ * Gets the start angle.
+ *
+ * @return the start angle.
+ */
+ public abstract double getAngleStart();
+
+ /**
+ * Gets the width angle.
+ *
+ * @return the width angle.
+ */
+ public abstract double getAngleExtent();
+
+ /**
+ * Sets the start angle.
+ *
+ * @param start the new start angle.
+ */
+ public abstract void setAngleStart(double start);
+
+ /**
+ * Sets the width angle.
+ *
+ * @param extent the new width angle.
+ */
+ public abstract void setAngleExtent(double extent);
+
+ /**
+ * Sets the data values that define the arc.
+ *
+ * @param x the x coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param y the y coordinate of the upper left corner of the rectangle that
+ * contains the arc.
+ * @param width the width of the rectangle that
+ * contains the arc.
+ * @param height the height of the rectangle that
+ * contains the arc.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the width angle of the arc in degrees.
+ * @param type the type of the new Arc2D, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public abstract void setArc(double x, double y, double width,
+ double height, double start, double extent, int type);
+
+ /**
+ * Gets the arc type, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ *
+ * @return the arc type.
+ */
+ public int getArcType() {
+ return type;
+ }
+
+ /**
+ * Sets the arc type, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ *
+ * @param type the new arc type.
+ */
+ public void setArcType(int type) {
+ if (type != OPEN && type != CHORD && type != PIE) {
+ // awt.205=Invalid type of Arc: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.205", type)); //$NON-NLS-1$
+ }
+ this.type = type;
+ }
+
+ /**
+ * Gets the start point of the arc as a Point2D.
+ *
+ * @return the start point of the curved arc segment.
+ */
+ public Point2D getStartPoint() {
+ double a = Math.toRadians(getAngleStart());
+ return new Point2D.Double(
+ getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0,
+ getY() + (1.0 - Math.sin(a)) * getHeight() / 2.0);
+ }
+
+ /**
+ * Gets the end point of the arc as a Point2D.
+ *
+ * @return the end point of the curved arc segment.
+ */
+ public Point2D getEndPoint() {
+ double a = Math.toRadians(getAngleStart() + getAngleExtent());
+ return new Point2D.Double(
+ getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0,
+ getY() + (1.0 - Math.sin(a)) * getHeight() / 2.0);
+ }
+
+ public Rectangle2D getBounds2D() {
+ if (isEmpty()) {
+ return makeBounds(getX(), getY(), getWidth(), getHeight());
+ }
+ double rx1 = getX();
+ double ry1 = getY();
+ double rx2 = rx1 + getWidth();
+ double ry2 = ry1 + getHeight();
+
+ Point2D p1 = getStartPoint();
+ Point2D p2 = getEndPoint();
+
+ double bx1 = containsAngle(180.0) ? rx1 : Math.min(p1.getX(), p2.getX());
+ double by1 = containsAngle(90.0) ? ry1 : Math.min(p1.getY(), p2.getY());
+ double bx2 = containsAngle(0.0) ? rx2 : Math.max(p1.getX(), p2.getX());
+ double by2 = containsAngle(270.0) ? ry2 : Math.max(p1.getY(), p2.getY());
+
+ if (type == PIE) {
+ double cx = getCenterX();
+ double cy = getCenterY();
+ bx1 = Math.min(bx1, cx);
+ by1 = Math.min(by1, cy);
+ bx2 = Math.max(bx2, cx);
+ by2 = Math.max(by2, cy);
+ }
+ return makeBounds(bx1, by1, bx2 - bx1, by2 - by1);
+ }
+
+ @Override
+ public void setFrame(double x, double y, double width, double height) {
+ setArc(x, y, width, height, getAngleStart(), getAngleExtent(), type);
+ }
+
+ /**
+ * Sets the data that defines the arc.
+ *
+ * @param point the upper left corner of the bounding rectangle.
+ * @param size the size of the bounding rectangle.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the angle witdth of the arc in degrees.
+ * @param type the closure type, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public void setArc(Point2D point, Dimension2D size, double start, double extent, int type) {
+ setArc(point.getX(), point.getY(), size.getWidth(), size.getHeight(), start, extent, type);
+ }
+
+ /**
+ * Sets the data that defines the arc.
+ *
+ * @param rect the arc's bounding rectangle.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the angle witdth of the arc in degrees.
+ * @param type the closure type, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public void setArc(Rectangle2D rect, double start, double extent, int type) {
+ setArc(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), start, extent, type);
+ }
+
+ /**
+ * Sets the data that defines the arc by copying it from another Arc2D.
+ *
+ * @param arc the arc whose data is copied into this arc.
+ */
+ public void setArc(Arc2D arc) {
+ setArc(arc.getX(), arc.getY(), arc.getWidth(), arc.getHeight(), arc
+ .getAngleStart(), arc.getAngleExtent(), arc.getArcType());
+ }
+
+ /**
+ * Sets the data for a circular arc by giving its center and radius.
+ *
+ * @param x the x coordinate of the center of the circle.
+ * @param y the y coordinate of the center of the circle.
+ * @param radius the radius of the circle.
+ * @param start the start angle of the arc in degrees.
+ * @param extent the angle witdth of the arc in degrees.
+ * @param type the closure type, either {@link Arc2D#OPEN},
+ * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}.
+ */
+ public void setArcByCenter(double x, double y, double radius, double start, double extent, int type) {
+ setArc(x - radius, y - radius, radius * 2.0, radius * 2.0, start, extent, type);
+ }
+
+ /**
+ * Sets the arc data for a circular arc based on two tangent lines
+ * and the radius. The two tangent lines are the lines from p1
+ * to p2 and from p2 to p3, which determine a unique circle
+ * with the given radius. The start and end points of the arc
+ * are the points where the circle touches the two lines, and
+ * the arc itself is the shorter of the two circle segments
+ * determined by the two points (in other words, it is the
+ * piece of the circle that is closer to the lines' intersection
+ * point p2 and forms a concave shape with the segments from p1 to p2
+ * and from p2 to p3).
+ *
+ * @param p1 a point which determines one of the two tanget lines (with p2).
+ * @param p2 the point of intersection of the two tangent lines.
+ * @param p3 a point which determines one of the two tanget lines (with p2).
+ * @param radius the radius of the circular arc.
+ */
+ public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double radius) {
+ // Used simple geometric calculations of arc center, radius and angles by tangents
+ double a1 = -Math.atan2(p1.getY() - p2.getY(), p1.getX() - p2.getX());
+ double a2 = -Math.atan2(p3.getY() - p2.getY(), p3.getX() - p2.getX());
+ double am = (a1 + a2) / 2.0;
+ double ah = a1 - am;
+ double d = radius / Math.abs(Math.sin(ah));
+ double x = p2.getX() + d * Math.cos(am);
+ double y = p2.getY() - d * Math.sin(am);
+ ah = ah >= 0.0 ? Math.PI * 1.5 - ah : Math.PI * 0.5 - ah;
+ a1 = getNormAngle(Math.toDegrees(am - ah));
+ a2 = getNormAngle(Math.toDegrees(am + ah));
+ double delta = a2 - a1;
+ if (delta <= 0.0) {
+ delta += 360.0;
+ }
+ setArcByCenter(x, y, radius, a1, delta, type);
+ }
+
+ /**
+ * Sets a new start angle to be the angle given by the the vector
+ * from the current center point to the specified point.
+ *
+ * @param point the point that determines the new start angle.
+ */
+ public void setAngleStart(Point2D point) {
+ double angle = Math.atan2(point.getY() - getCenterY(), point.getX() - getCenterX());
+ setAngleStart(getNormAngle(-Math.toDegrees(angle)));
+ }
+
+ /**
+ * Sets the angles in terms of vectors from the current arc center
+ * to the points (x1, y1) and (x2, y2). The start angle is given
+ * by the vector from the current center to the point (x1, y1) and
+ * the end angle is given by the vector from the center to the point
+ * (x2, y2).
+ *
+ * @param x1 the x coordinate of the point whose vector from the center
+ * point determines the new start angle of the arc.
+ * @param y1 the y coordinate of the point whose vector from the center
+ * point determines the new start angle of the arc.
+ * @param x2 the x coordinate of the point whose vector from the center
+ * point determines the new end angle of the arc.
+ * @param y2 the y coordinate of the point whose vector from the center
+ * point determines the new end angle of the arc.
+ */
+ public void setAngles(double x1, double y1, double x2, double y2) {
+ double cx = getCenterX();
+ double cy = getCenterY();
+ double a1 = getNormAngle(-Math.toDegrees(Math.atan2(y1 - cy, x1 - cx)));
+ double a2 = getNormAngle(-Math.toDegrees(Math.atan2(y2 - cy, x2 - cx)));
+ a2 -= a1;
+ if (a2 <= 0.0) {
+ a2 += 360.0;
+ }
+ setAngleStart(a1);
+ setAngleExtent(a2);
+ }
+
+ /**
+ * Sets the angles in terms of vectors from the current arc center
+ * to the points p1 and p2. The start angle is given
+ * by the vector from the current center to the point p1 and
+ * the end angle is given by the vector from the center to the point
+ * p2.
+ *
+ * @param p1 the point whose vector from the center
+ * point determines the new start angle of the arc.
+ * @param p2 the point whose vector from the center
+ * point determines the new end angle of the arc.
+ */
+ public void setAngles(Point2D p1, Point2D p2) {
+ setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY());
+ }
+
+ /**
+ * Normalizes the angle by removing extra winding (past 360 degrees)
+ * and placing it in the positive degree range.
+ *
+ * @param angle - the source angle in degrees
+ *
+ * @return an angle between 0 and 360 degrees which corresponds
+ * to the same direction vector as the source angle.
+ */
+ double getNormAngle(double angle) {
+ double n = Math.floor(angle / 360.0);
+ return angle - n * 360.0;
+ }
+
+ /**
+ * Determines whether the given angle is contained in the span of the arc.
+ *
+ * @param angle the angle to test in degrees.
+ *
+ * @return true, if the given angle is between the start angle and
+ * the end angle of the arc.
+ */
+ public boolean containsAngle(double angle) {
+ double extent = getAngleExtent();
+ if (extent >= 360.0) {
+ return true;
+ }
+ angle = getNormAngle(angle);
+ double a1 = getNormAngle(getAngleStart());
+ double a2 = a1 + extent;
+ if (a2 > 360.0) {
+ return angle >= a1 || angle <= a2 - 360.0;
+ }
+ if (a2 < 0.0) {
+ return angle >= a2 + 360.0 || angle <= a1;
+ }
+ return extent > 0.0 ? a1 <= angle && angle <= a2 : a2 <= angle
+ && angle <= a1;
+ }
+
+ public boolean contains(double px, double py) {
+ // Normalize point
+ double nx = (px - getX()) / getWidth() - 0.5;
+ double ny = (py - getY()) / getHeight() - 0.5;
+
+ if ((nx * nx + ny * ny) > 0.25) {
+ return false;
+ }
+
+ double extent = getAngleExtent();
+ double absExtent = Math.abs(extent);
+ if (absExtent >= 360.0) {
+ return true;
+ }
+
+ boolean containsAngle = containsAngle(Math.toDegrees(-Math
+ .atan2(ny, nx)));
+ if (type == PIE) {
+ return containsAngle;
+ }
+ if (absExtent <= 180.0 && !containsAngle) {
+ return false;
+ }
+
+ Line2D l = new Line2D.Double(getStartPoint(), getEndPoint());
+ int ccw1 = l.relativeCCW(px, py);
+ int ccw2 = l.relativeCCW(getCenterX(), getCenterY());
+ return ccw1 == 0 || ccw2 == 0
+ || ((ccw1 + ccw2) == 0 ^ absExtent > 180.0);
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+
+ if (!(contains(rx, ry) && contains(rx + rw, ry)
+ && contains(rx + rw, ry + rh) && contains(rx, ry + rh))) {
+ return false;
+ }
+
+ double absExtent = Math.abs(getAngleExtent());
+ if (type != PIE || absExtent <= 180.0 || absExtent >= 360.0) {
+ return true;
+ }
+
+ Rectangle2D r = new Rectangle2D.Double(rx, ry, rw, rh);
+
+ double cx = getCenterX();
+ double cy = getCenterY();
+ if (r.contains(cx, cy)) {
+ return false;
+ }
+
+ Point2D p1 = getStartPoint();
+ Point2D p2 = getEndPoint();
+
+ return !r.intersectsLine(cx, cy, p1.getX(), p1.getY())
+ && !r.intersectsLine(cx, cy, p2.getX(), p2.getY());
+ }
+
+ @Override
+ public boolean contains(Rectangle2D rect) {
+ return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+
+ if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+ return false;
+ }
+
+ // Check: Does arc contain rectangle's points
+ if (contains(rx, ry) || contains(rx + rw, ry) || contains(rx, ry + rh)
+ || contains(rx + rw, ry + rh)) {
+ return true;
+ }
+
+ double cx = getCenterX();
+ double cy = getCenterY();
+ Point2D p1 = getStartPoint();
+ Point2D p2 = getEndPoint();
+ Rectangle2D r = new Rectangle2D.Double(rx, ry, rw, rh);
+
+ // Check: Does rectangle contain arc's points
+ if (r.contains(p1) || r.contains(p2) || (type == PIE && r.contains(cx, cy))) {
+ return true;
+ }
+
+ if (type == PIE) {
+ if (r.intersectsLine(p1.getX(), p1.getY(), cx, cy) ||
+ r.intersectsLine(p2.getX(), p2.getY(), cx, cy))
+ {
+ return true;
+ }
+ } else {
+ if (r.intersectsLine(p1.getX(), p1.getY(), p2.getX(), p2.getY())) {
+ return true;
+ }
+ }
+
+ // Nearest rectangle point
+ double nx = cx < rx ? rx : (cx > rx + rw ? rx + rw : cx);
+ double ny = cy < ry ? ry : (cy > ry + rh ? ry + rh : cy);
+ return contains(nx, ny);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at) {
+ return new Iterator(this, at);
+ }
+
+}
+
diff --git a/awt/java/awt/geom/Area.java b/awt/java/awt/geom/Area.java
new file mode 100644
index 0000000..bc27d4e
--- /dev/null
+++ b/awt/java/awt/geom/Area.java
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Rectangle2D;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Area provides a minimal implementation for a generic shape.
+ */
+public class Area implements Shape, Cloneable {
+
+ /** The source Shape object. */
+ Shape s;
+
+ /**
+ * The Class NullIterator.
+ */
+ private static class NullIterator implements PathIterator {
+
+ /**
+ * Instantiates a new null iterator.
+ */
+ NullIterator() {
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return true;
+ }
+
+ public void next() {
+ // nothing
+ }
+
+ public int currentSegment(double[] coords) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+
+ public int currentSegment(float[] coords) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+
+ }
+
+ /**
+ * Instantiates a new area with no data.
+ */
+ public Area() {
+ }
+
+ /**
+ * Instantiates a new area with data given by the specified shape.
+ *
+ * @param s the shape that gives the data for this Area
+ */
+ public Area(Shape s) {
+ if (s == null) {
+ throw new NullPointerException();
+ }
+ this.s = s;
+ }
+
+ public boolean contains(double x, double y) {
+ return s == null ? false : s.contains(x, y);
+ }
+
+ public boolean contains(double x, double y, double width, double height) {
+ return s == null ? false : s.contains(x, y, width, height);
+ }
+
+ public boolean contains(Point2D p) {
+ if (p == null) {
+ throw new NullPointerException();
+ }
+ return s == null ? false : s.contains(p);
+ }
+
+ public boolean contains(Rectangle2D r) {
+ if (r == null) {
+ throw new NullPointerException();
+ }
+ return s == null ? false : s.contains(r);
+ }
+
+ /**
+ * Tests whether the object is equal to this Area.
+ *
+ * @param obj the object to compare
+ *
+ * @return true, if successful
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public boolean equals(Area obj) throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ public boolean intersects(double x, double y, double width, double height) {
+ return s == null ? false : s.intersects(x, y, width, height);
+ }
+
+ public boolean intersects(Rectangle2D r) {
+ if (r == null) {
+ throw new NullPointerException();
+ }
+ return s == null ? false : s.intersects(r);
+ }
+
+ public Rectangle getBounds() {
+ return s == null ? new Rectangle() : s.getBounds();
+ }
+
+ public Rectangle2D getBounds2D() {
+ return s == null ? new Rectangle2D.Double(): s.getBounds2D();
+ }
+
+ public PathIterator getPathIterator(AffineTransform t) {
+ return s == null ? new NullIterator() : s.getPathIterator(t);
+ }
+
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return s == null ? new NullIterator() : s.getPathIterator(t, flatness);
+ }
+
+ /**
+ * Adds the specified area to this area.
+ *
+ * @param area the area to add to this area
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public void add(Area area) throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Performs an exclusive or operation between this shape and the
+ * specified shape.
+ *
+ * @param area the area to XOR against this area
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public void exclusiveOr(Area area) throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Extracts a Rectangle2D from the source shape if the underlying shape
+ * data describes a rectangle.
+ *
+ * @return a Rectangle2D object if the source shape is rectangle,
+ * or null if shape is empty or not rectangle.
+ */
+ Rectangle2D extractRectangle() {
+ if (s == null) {
+ return null;
+ }
+ float[] points = new float[12];
+ int count = 0;
+ PathIterator p = s.getPathIterator(null);
+ float[] coords = new float[6];
+ while(!p.isDone()) {
+ int type = p.currentSegment(coords);
+ if (count > 12 || type == PathIterator.SEG_QUADTO || type == PathIterator.SEG_CUBICTO) {
+ return null;
+ }
+ points[count++] = coords[0];
+ points[count++] = coords[1];
+ p.next();
+ }
+ if (points[0] == points[6] && points[6] == points[8] && points[2] == points[4] &&
+ points[1] == points[3] && points[3] == points[9] && points[5] == points[7])
+ {
+ return new Rectangle2D.Float(points[0], points[1], points[2] - points[0], points[7] - points[1]);
+ }
+ return null;
+ }
+
+ /**
+ * Reduces the size of this Area by intersecting it with the
+ * specified Area if they are both rectangles.
+ *
+ * @see java.awt.geom.Rectangle2D#intersect(Rectangle2D, Rectangle2D, Rectangle2D)
+ *
+ * @param area the area
+ */
+ public void intersect(Area area) {
+ Rectangle2D src1 = extractRectangle();
+ Rectangle2D src2 = area.extractRectangle();
+ if (src1 != null && src2 != null) {
+ Rectangle2D.intersect(src1, src2, (Rectangle2D)s);
+ }
+ }
+
+ /**
+ * Subtract the specified area from this area.
+ *
+ * @param area the area to subtract
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public void subtract(Area area) throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if this Area is empty.
+ *
+ * @return true, if this Area is empty
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public boolean isEmpty() throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if this Area is polygonal.
+ *
+ * @return true, if this Area is polygonal
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public boolean isPolygonal() throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if this Area is rectangular.
+ *
+ * @return true, if this Area is rectangular
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public boolean isRectangular() throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if this Area is singular.
+ *
+ * @return true, if this Area is singular
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public boolean isSingular() throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Resets the data of this Area.
+ *
+ * @throws NotImplementedException if this method is not implemented
+ */
+ public void reset() throws org.apache.harmony.luni.util.NotImplementedException {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Transforms the data of this Area according to the specified
+ * AffineTransform.
+ *
+ * @param t the transform to use to transform the data
+ */
+ public void transform(AffineTransform t) {
+ s = t.createTransformedShape(s);
+ }
+
+ /**
+ * Creates a new Area that is the result of transforming the data
+ * of this Area according to the specified AffineTransform.
+ *
+ * @param t the transform to use to transform the data
+ *
+ * @return the new Area that is the result of transforming the data
+ * of this Area according to the specified AffineTransform.
+ */
+ public Area createTransformedArea(AffineTransform t) {
+ return s == null ? new Area() : new Area(t.createTransformedShape(s));
+ }
+
+ @Override
+ public Object clone() {
+ return new Area(this);
+ }
+
+}
diff --git a/awt/java/awt/geom/CubicCurve2D.java b/awt/java/awt/geom/CubicCurve2D.java
new file mode 100644
index 0000000..3e440c8
--- /dev/null
+++ b/awt/java/awt/geom/CubicCurve2D.java
@@ -0,0 +1,945 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.Crossing;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class CubicCurve2D is a Shape that represents a segment of a
+ * quadratic (Bezier) curve. The curved segment is determined by four points:
+ * a start point, an end point, and two control points.
+ * The control points give information about the tangent and next
+ * derivative at the endpoints according to the standard theory of
+ * Bezier curves. For more information on Bezier curves,
+ * see <a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">this article</a>.
+ */
+public abstract class CubicCurve2D implements Shape, Cloneable {
+
+ /**
+ * The Class Float is the subclass of CubicCurve2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends CubicCurve2D {
+
+ /** The x coordinate of the starting point. */
+ public float x1;
+
+ /** The y coordinate of the starting point. */
+ public float y1;
+
+ /** The x coordinate of the first control point. */
+ public float ctrlx1;
+
+ /** The y coordinate of the first control point. */
+ public float ctrly1;
+
+ /** The x coordinate of the second control point. */
+ public float ctrlx2;
+
+ /** The y coordinate of the second control point. */
+ public float ctrly2;
+
+ /** The x coordinate of the end point. */
+ public float x2;
+
+ /** The y coordinate of the end point. */
+ public float y2;
+
+ /**
+ * Instantiates a new float-valued CubicCurve2D with all coordinate values
+ * set to zero.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued CubicCurve2D with the specified
+ * coordinate values.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public Float(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, float x2, float y2) {
+ setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getCtrlX1() {
+ return ctrlx1;
+ }
+
+ @Override
+ public double getCtrlY1() {
+ return ctrly1;
+ }
+
+ @Override
+ public double getCtrlX2() {
+ return ctrlx2;
+ }
+
+ @Override
+ public double getCtrlY2() {
+ return ctrly2;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Float(x1, y1);
+ }
+
+ @Override
+ public Point2D getCtrlP1() {
+ return new Point2D.Float(ctrlx1, ctrly1);
+ }
+
+ @Override
+ public Point2D getCtrlP2() {
+ return new Point2D.Float(ctrlx2, ctrly2);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Float(x2, y2);
+ }
+
+ @Override
+ public void setCurve(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2)
+ {
+ this.x1 = (float)x1;
+ this.y1 = (float)y1;
+ this.ctrlx1 = (float)ctrlx1;
+ this.ctrly1 = (float)ctrly1;
+ this.ctrlx2 = (float)ctrlx2;
+ this.ctrly2 = (float)ctrly2;
+ this.x2 = (float)x2;
+ this.y2 = (float)y2;
+ }
+
+ /**
+ * Sets the data values of the curve.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public void setCurve(float x1, float y1, float ctrlx1, float ctrly1,
+ float ctrlx2, float ctrly2, float x2, float y2)
+ {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.ctrlx1 = ctrlx1;
+ this.ctrly1 = ctrly1;
+ this.ctrlx2 = ctrlx2;
+ this.ctrly2 = ctrly2;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ float rx1 = Math.min(Math.min(x1, x2), Math.min(ctrlx1, ctrlx2));
+ float ry1 = Math.min(Math.min(y1, y2), Math.min(ctrly1, ctrly2));
+ float rx2 = Math.max(Math.max(x1, x2), Math.max(ctrlx1, ctrlx2));
+ float ry2 = Math.max(Math.max(y1, y2), Math.max(ctrly1, ctrly2));
+ return new Rectangle2D.Float(rx1, ry1, rx2 - rx1, ry2 - ry1);
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of CubicCurve2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends CubicCurve2D {
+
+ /** The x coordinate of the starting point. */
+ public double x1;
+
+ /** The y coordinate of the starting point. */
+ public double y1;
+
+ /** The x coordinate of the first control point. */
+ public double ctrlx1;
+
+ /** The y coordinate of the first control point. */
+ public double ctrly1;
+
+ /** The x coordinate of the second control point. */
+ public double ctrlx2;
+
+ /** The y coordinate of the second control point. */
+ public double ctrly2;
+
+ /** The x coordinate of the end point. */
+ public double x2;
+
+ /** The y coordinate of the end point. */
+ public double y2;
+
+ /**
+ * Instantiates a new double-valued CubicCurve2D with all coordinate values
+ * set to zero.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued CubicCurve2D with the specified
+ * coordinate values.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public Double(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2) {
+ setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getCtrlX1() {
+ return ctrlx1;
+ }
+
+ @Override
+ public double getCtrlY1() {
+ return ctrly1;
+ }
+
+ @Override
+ public double getCtrlX2() {
+ return ctrlx2;
+ }
+
+ @Override
+ public double getCtrlY2() {
+ return ctrly2;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Double(x1, y1);
+ }
+
+ @Override
+ public Point2D getCtrlP1() {
+ return new Point2D.Double(ctrlx1, ctrly1);
+ }
+
+ @Override
+ public Point2D getCtrlP2() {
+ return new Point2D.Double(ctrlx2, ctrly2);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Double(x2, y2);
+ }
+
+ @Override
+ public void setCurve(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2)
+ {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.ctrlx1 = ctrlx1;
+ this.ctrly1 = ctrly1;
+ this.ctrlx2 = ctrlx2;
+ this.ctrly2 = ctrly2;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ double rx1 = Math.min(Math.min(x1, x2), Math.min(ctrlx1, ctrlx2));
+ double ry1 = Math.min(Math.min(y1, y2), Math.min(ctrly1, ctrly2));
+ double rx2 = Math.max(Math.max(x1, x2), Math.max(ctrlx1, ctrlx2));
+ double ry2 = Math.max(Math.max(y1, y2), Math.max(ctrly1, ctrly2));
+ return new Rectangle2D.Double(rx1, ry1, rx2 - rx1, ry2 - ry1);
+ }
+ }
+
+ /*
+ * CubicCurve2D path iterator
+ */
+ /**
+ * The Iterator class for the Shape CubicCurve2D.
+ */
+ class Iterator implements PathIterator {
+
+ /** The source CubicCurve2D object. */
+ CubicCurve2D c;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segmenet index. */
+ int index;
+
+ /**
+ * Constructs a new CubicCurve2D.Iterator for given line and transformation
+ *
+ * @param c - the source CubicCurve2D object
+ * @param t the t
+ */
+ Iterator(CubicCurve2D c, AffineTransform t) {
+ this.c = c;
+ this.t = t;
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > 1;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = c.getX1();
+ coords[1] = c.getY1();
+ count = 1;
+ } else {
+ type = SEG_CUBICTO;
+ coords[0] = c.getCtrlX1();
+ coords[1] = c.getCtrlY1();
+ coords[2] = c.getCtrlX2();
+ coords[3] = c.getCtrlY2();
+ coords[4] = c.getX2();
+ coords[5] = c.getY2();
+ count = 3;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = (float)c.getX1();
+ coords[1] = (float)c.getY1();
+ count = 1;
+ } else {
+ type = SEG_CUBICTO;
+ coords[0] = (float)c.getCtrlX1();
+ coords[1] = (float)c.getCtrlY1();
+ coords[2] = (float)c.getCtrlX2();
+ coords[3] = (float)c.getCtrlY2();
+ coords[4] = (float)c.getX2();
+ coords[5] = (float)c.getY2();
+ count = 3;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new 2-D cubic curve.
+ */
+ protected CubicCurve2D() {
+ }
+
+ /**
+ * Gets the x coordinate of the starting point.
+ *
+ * @return the x coordinate of the starting point
+ */
+ public abstract double getX1();
+
+ /**
+ * Gets the y coordinate of the starting point.
+ *
+ * @return the y coordinate of the starting point
+ */
+ public abstract double getY1();
+
+ /**
+ * Gets the starting point.
+ *
+ * @return the starting point
+ */
+ public abstract Point2D getP1();
+
+ /**
+ * Gets the x coordinate of the first control point.
+ *
+ * @return the x coordinate of the first control point
+ */
+ public abstract double getCtrlX1();
+
+ /**
+ * Gets the y coordinate of the first control point.
+ *
+ * @return the y coordinate of the first control point
+ */
+ public abstract double getCtrlY1();
+
+ /**
+ * Gets the second control point.
+ *
+ * @return the second control point
+ */
+ public abstract Point2D getCtrlP1();
+
+ /**
+ * Gets the x coordinate of the second control point.
+ *
+ * @return the x coordinate of the second control point
+ */
+ public abstract double getCtrlX2();
+
+ /**
+ * Gets the y coordinate of the second control point.
+ *
+ * @return the y coordinate of the second control point
+ */
+ public abstract double getCtrlY2();
+
+ /**
+ * Gets the second control point.
+ *
+ * @return the second control point
+ */
+ public abstract Point2D getCtrlP2();
+
+ /**
+ * Gets the x coordinate of the end point.
+ *
+ * @return the x coordinate of the end point
+ */
+ public abstract double getX2();
+
+ /**
+ * Gets the y coordinate of the end point.
+ *
+ * @return the y coordinate of the end point
+ */
+ public abstract double getY2();
+
+ /**
+ * Gets the end point.
+ *
+ * @return the end point
+ */
+ public abstract Point2D getP2();
+
+ /**
+ * Sets the data of the curve.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public abstract void setCurve(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2);
+
+ /**
+ * Sets the data of the curve as point objects.
+ *
+ * @param p1 the starting point
+ * @param cp1 the first control point
+ * @param cp2 the second control point
+ * @param p2 the end point
+ *
+ * @throws NullPointerException if any of the points is null.
+ */
+ public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) {
+ setCurve(
+ p1.getX(), p1.getY(),
+ cp1.getX(), cp1.getY(),
+ cp2.getX(), cp2.getY(),
+ p2.getX(), p2.getY());
+ }
+
+ /**
+ * Sets the data of the curve by reading the data from an array
+ * of values. The values are read in the same order as the arguments
+ * of the method {@link CubicCurve2D#setCurve(double, double, double, double, double, double, double, double)}.
+ *
+ * @param coords the array of values containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 8.
+ * @throws NullPointerException if the coordinate array is null.
+ */
+ public void setCurve(double[] coords, int offset) {
+ setCurve(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 2], coords[offset + 3],
+ coords[offset + 4], coords[offset + 5],
+ coords[offset + 6], coords[offset + 7]);
+ }
+
+ /**
+ * Sets the data of the curve by reading the data from an array
+ * of points. The values are read in the same order as the arguments
+ * of the method {@link CubicCurve2D#setCurve(Point2D, Point2D, Point2D, Point2D)}
+ *
+ * @param points the array of points containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @throws ArrayIndexOutOfBoundsException if points.length < offset + .
+ * @throws NullPointerException if the point array is null.
+ */
+ public void setCurve(Point2D[] points, int offset) {
+ setCurve(
+ points[offset + 0].getX(), points[offset + 0].getY(),
+ points[offset + 1].getX(), points[offset + 1].getY(),
+ points[offset + 2].getX(), points[offset + 2].getY(),
+ points[offset + 3].getX(), points[offset + 3].getY());
+ }
+
+ /**
+ * Sets the data of the curve by copying it from another CubicCurve2D.
+ *
+ * @param curve the curve to copy the data points from
+ *
+ * @throws NullPointerException if the curve is null.
+ */
+ public void setCurve(CubicCurve2D curve) {
+ setCurve(
+ curve.getX1(), curve.getY1(),
+ curve.getCtrlX1(), curve.getCtrlY1(),
+ curve.getCtrlX2(), curve.getCtrlY2(),
+ curve.getX2(), curve.getY2());
+ }
+
+ /**
+ * Gets the square of the flatness of this curve, where the flatness is the
+ * maximum distance from the curves control points to the
+ * line segment connecting the two points.
+ *
+ * @return the square of the flatness
+ */
+ public double getFlatnessSq() {
+ return getFlatnessSq(
+ getX1(), getY1(),
+ getCtrlX1(), getCtrlY1(),
+ getCtrlX2(), getCtrlY2(),
+ getX2(), getY2());
+ }
+
+ /**
+ * Gets the square of the flatness of the cubic curve segment
+ * defined by the specified values.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ *
+ * @return the square of the flatness
+ */
+ public static double getFlatnessSq(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2)
+ {
+ return Math.max(
+ Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1, ctrly1),
+ Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx2, ctrly2));
+ }
+
+ /**
+ * Gets the square of the flatness of the cubic curve segment
+ * defined by the specified values. The values are read in the same order as the arguments
+ * of the method {@link CubicCurve2D#getFlatnessSq(double, double, double, double, double, double, double, double)}.
+ *
+ * @param coords the array of points containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @return the square of the flatness
+ *
+ * @throws ArrayIndexOutOfBoundsException if points.length < offset + .
+ * @throws NullPointerException if the point array is null.
+ */
+ public static double getFlatnessSq(double coords[], int offset) {
+ return getFlatnessSq(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 2], coords[offset + 3],
+ coords[offset + 4], coords[offset + 5],
+ coords[offset + 6], coords[offset + 7]);
+ }
+
+ /**
+ * Gets the flatness of this curve, where the flatness is the
+ * maximum distance from the curves control points to the
+ * line segment connecting the two points.
+ *
+ * @return the flatness of this curve
+ */
+ public double getFlatness() {
+ return getFlatness(
+ getX1(), getY1(),
+ getCtrlX1(), getCtrlY1(),
+ getCtrlX2(), getCtrlY2(),
+ getX2(), getY2());
+ }
+
+ /**
+ * Gets the flatness of the cubic curve segment
+ * defined by the specified values.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param ctrlx1 the x coordinate of the first control point
+ * @param ctrly1 the y coordinate of the first control point
+ * @param ctrlx2 the x coordinate of the second control point
+ * @param ctrly2 the y coordinate of the second control point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ *
+ * @return the flatness
+ */
+ public static double getFlatness(double x1, double y1, double ctrlx1, double ctrly1,
+ double ctrlx2, double ctrly2, double x2, double y2)
+ {
+ return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2));
+ }
+
+ /**
+ * Gets the flatness of the cubic curve segment
+ * defined by the specified values. The values are read in the same order as the arguments
+ * of the method {@link CubicCurve2D#getFlatness(double, double, double, double, double, double, double, double)}.
+ *
+ * @param coords the array of points containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @return the flatness
+ *
+ * @throws ArrayIndexOutOfBoundsException if points.length < offset + .
+ * @throws NullPointerException if the point array is null.
+ */
+ public static double getFlatness(double coords[], int offset) {
+ return getFlatness(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 2], coords[offset + 3],
+ coords[offset + 4], coords[offset + 5],
+ coords[offset + 6], coords[offset + 7]);
+ }
+
+ /**
+ * Creates the data for two cubic curves by dividing this
+ * curve in two. The division point is the point on the curve
+ * that is closest to the average of curve's two control points.
+ * The two new control points (nearest the new endpoint) are computed
+ * by averaging the original control points with the new endpoint.
+ * The data of this curve is left unchanged.
+ *
+ * @param left the CubicCurve2D where the left (start) segment's
+ * data is written
+ * @param right the CubicCurve2D where the right (end) segment's
+ * data is written
+ *
+ * @throws NullPointerException if either curve is null.
+ */
+ public void subdivide(CubicCurve2D left, CubicCurve2D right) {
+ subdivide(this, left, right);
+ }
+
+ /**
+ * Creates the data for two cubic curves by dividing the specified
+ * curve in two. The division point is the point on the curve
+ * that is closest to the average of curve's two control points.
+ * The two new control points (nearest the new endpoint) are computed
+ * by averaging the original control points with the new endpoint.
+ * The data of the source curve is left unchanged.
+ *
+ * @param src the original curve to be divided in two
+ * @param left the CubicCurve2D where the left (start) segment's
+ * data is written
+ * @param right the CubicCurve2D where the right (end) segment's
+ * data is written
+ *
+ * @throws NullPointerException if either curve is null.
+ */
+ public static void subdivide(CubicCurve2D src, CubicCurve2D left, CubicCurve2D right) {
+ double x1 = src.getX1();
+ double y1 = src.getY1();
+ double cx1 = src.getCtrlX1();
+ double cy1 = src.getCtrlY1();
+ double cx2 = src.getCtrlX2();
+ double cy2 = src.getCtrlY2();
+ double x2 = src.getX2();
+ double y2 = src.getY2();
+ double cx = (cx1 + cx2) / 2.0;
+ double cy = (cy1 + cy2) / 2.0;
+ cx1 = (x1 + cx1) / 2.0;
+ cy1 = (y1 + cy1) / 2.0;
+ cx2 = (x2 + cx2) / 2.0;
+ cy2 = (y2 + cy2) / 2.0;
+ double ax = (cx1 + cx) / 2.0;
+ double ay = (cy1 + cy) / 2.0;
+ double bx = (cx2 + cx) / 2.0;
+ double by = (cy2 + cy) / 2.0;
+ cx = (ax + bx) / 2.0;
+ cy = (ay + by) / 2.0;
+ if (left != null) {
+ left.setCurve(x1, y1, cx1, cy1, ax, ay, cx, cy);
+ }
+ if (right != null) {
+ right.setCurve(cx, cy, bx, by, cx2, cy2, x2, y2);
+ }
+ }
+
+ /**
+ * Creates the data for two cubic curves by dividing the specified
+ * curve in two. The division point is the point on the curve
+ * that is closest to the average of curve's two control points.
+ * The two new control points (nearest the new endpoint) are computed
+ * by averaging the original control points with the new endpoint.
+ * The data of the source curve is left unchanged. The data for the
+ * three curves is read/written in the usual order: { x1, y1,
+ * ctrlx1, ctrly1, ctrlx2, crtry2, x2, y3 }
+ *
+ * @param src the array that gives the data values for the source curve
+ * @param srcOff the offset in the src array to read the values from
+ * @param left the array where the coordinates of the start curve should be written
+ * @param leftOff the offset in the left array to start writing the values
+ * @param right the array where the coordinates of the end curve should be written
+ * @param rightOff the offset in the right array to start writing the values
+ *
+ * @throws ArrayIndexOutOfBoundsException if src.length < srcoff + 8
+ * or if left.length < leftOff + 8 or if right.length < rightOff + 8.
+ * @throws NullPointerException if one of the arrays is null.
+ */
+ public static void subdivide(double src[], int srcOff, double left[], int leftOff, double right[], int rightOff) {
+ double x1 = src[srcOff + 0];
+ double y1 = src[srcOff + 1];
+ double cx1 = src[srcOff + 2];
+ double cy1 = src[srcOff + 3];
+ double cx2 = src[srcOff + 4];
+ double cy2 = src[srcOff + 5];
+ double x2 = src[srcOff + 6];
+ double y2 = src[srcOff + 7];
+ double cx = (cx1 + cx2) / 2.0;
+ double cy = (cy1 + cy2) / 2.0;
+ cx1 = (x1 + cx1) / 2.0;
+ cy1 = (y1 + cy1) / 2.0;
+ cx2 = (x2 + cx2) / 2.0;
+ cy2 = (y2 + cy2) / 2.0;
+ double ax = (cx1 + cx) / 2.0;
+ double ay = (cy1 + cy) / 2.0;
+ double bx = (cx2 + cx) / 2.0;
+ double by = (cy2 + cy) / 2.0;
+ cx = (ax + bx) / 2.0;
+ cy = (ay + by) / 2.0;
+ if (left != null) {
+ left[leftOff + 0] = x1;
+ left[leftOff + 1] = y1;
+ left[leftOff + 2] = cx1;
+ left[leftOff + 3] = cy1;
+ left[leftOff + 4] = ax;
+ left[leftOff + 5] = ay;
+ left[leftOff + 6] = cx;
+ left[leftOff + 7] = cy;
+ }
+ if (right != null) {
+ right[rightOff + 0] = cx;
+ right[rightOff + 1] = cy;
+ right[rightOff + 2] = bx;
+ right[rightOff + 3] = by;
+ right[rightOff + 4] = cx2;
+ right[rightOff + 5] = cy2;
+ right[rightOff + 6] = x2;
+ right[rightOff + 7] = y2;
+ }
+ }
+
+ /**
+ * Finds the roots of the cubic polynomial. This is
+ * accomplished by finding the (real) values of x that solve
+ * the following equation: eqn[3]*x*x*x + eqn[2]*x*x + eqn[1]*x + eqn[0] = 0.
+ * The solutions are written back into the array eqn starting
+ * from the index 0 in the array. The return value tells how
+ * many array elements have been changed by this method call.
+ *
+ * @param eqn an array containing the coefficients of the
+ * cubic polynomial to solve.
+ *
+ * @return the number of roots of the cubic polynomial
+ *
+ * @throws ArrayIndexOutOfBoundsException if eqn.length < 4.
+ * @throws NullPointerException if the array is null.
+ */
+ public static int solveCubic(double eqn[]) {
+ return solveCubic(eqn, eqn);
+ }
+
+ /**
+ * Finds the roots of the cubic polynomial. This is
+ * accomplished by finding the (real) values of x that solve
+ * the following equation: eqn[3]*x*x*x + eqn[2]*x*x + eqn[1]*x + eqn[0] = 0.
+ * The solutions are written into the array res starting
+ * from the index 0 in the array. The return value tells how
+ * many array elements have been changed by this method call.
+ *
+ * @param eqn an array containing the coefficients of the
+ * cubic polynomial to solve.
+ * @param res the array that this method writes the results into
+ *
+ * @return the number of roots of the cubic polynomial
+ *
+ * @throws ArrayIndexOutOfBoundsException if eqn.length < 4 or
+ * if res.length is less than the number of roots.
+ * @throws NullPointerException if either array is null.
+ */
+ public static int solveCubic(double eqn[], double res[]) {
+ return Crossing.solveCubic(eqn, res);
+ }
+
+ public boolean contains(double px, double py) {
+ return Crossing.isInsideEvenOdd(Crossing.crossShape(this, px, py));
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean contains(Point2D p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ public boolean intersects(Rectangle2D r) {
+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public boolean contains(Rectangle2D r) {
+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public Rectangle getBounds() {
+ return getBounds2D().getBounds();
+ }
+
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
+ return new FlatteningPathIterator(getPathIterator(at), flatness);
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+} \ No newline at end of file
diff --git a/awt/java/awt/geom/Dimension2D.java b/awt/java/awt/geom/Dimension2D.java
new file mode 100644
index 0000000..eef63e6
--- /dev/null
+++ b/awt/java/awt/geom/Dimension2D.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+/**
+ * The Class Dimension2D represents a size (width and height) of a
+ * geometric object. It stores double-valued data in order to be compatible
+ * with high-precision geometric operations.
+ */
+public abstract class Dimension2D implements Cloneable {
+
+ /**
+ * Instantiates a new dimension 2d with no data.
+ */
+ protected Dimension2D() {
+ }
+
+ /**
+ * Gets the width.
+ *
+ * @return the width
+ */
+ public abstract double getWidth();
+
+ /**
+ * Gets the height.
+ *
+ * @return the height
+ */
+ public abstract double getHeight();
+
+ /**
+ * Sets the width and height.
+ *
+ * @param width the width
+ * @param height the height
+ */
+ public abstract void setSize(double width, double height);
+
+ /**
+ * Sets the width and height based on the data of another
+ * Dimension2D object.
+ *
+ * @param d the Dimension2D object providing the data to copy
+ * into this Dimension2D object
+ */
+ public void setSize(Dimension2D d) {
+ setSize(d.getWidth(), d.getHeight());
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+}
+
diff --git a/awt/java/awt/geom/Ellipse2D.java b/awt/java/awt/geom/Ellipse2D.java
new file mode 100644
index 0000000..33464af
--- /dev/null
+++ b/awt/java/awt/geom/Ellipse2D.java
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Ellipse2D describes an ellipse defined by a rectangular
+ * area in which it is inscribed.
+ */
+public abstract class Ellipse2D extends RectangularShape {
+
+ /**
+ * The Class Float is the subclass of Ellipse2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends Ellipse2D {
+
+ /** The x coordinate of the upper left corner of the ellipse's
+ * bounding rectangle. */
+ public float x;
+
+ /** The y coordinate of the upper left corner of the ellipse's
+ * bounding rectangle. */
+ public float y;
+
+ /** The width of the ellipse's bounding rectangle. */
+ public float width;
+
+ /** The height of the ellipse's bounding rectangle. */
+ public float height;
+
+ /**
+ * Instantiates a new float-valued Ellipse2D.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued Ellipse2D with the specified data.
+ *
+ * @param x the x coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param y the y coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param width the width of the ellipse's bounding rectangle
+ * @param height the height of the ellipse's bounding rectangle
+ */
+ public Float(float x, float y, float width, float height) {
+ setFrame(x, y, width, height);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0 || height <= 0.0;
+ }
+
+ /**
+ * Sets the data of the ellipse's bounding rectangle.
+ *
+ * @param x the x coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param y the y coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param width the width of the ellipse's bounding rectangle
+ * @param height the height of the ellipse's bounding rectangle
+ */
+ public void setFrame(float x, float y, float width, float height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public void setFrame(double x, double y, double width, double height) {
+ this.x = (float)x;
+ this.y = (float)y;
+ this.width = (float)width;
+ this.height = (float)height;
+ }
+
+ public Rectangle2D getBounds2D() {
+ return new Rectangle2D.Float(x, y, width, height);
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of Ellipse2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends Ellipse2D {
+
+ /** The x coordinate of the upper left corner of the ellipse's
+ * bounding rectangle. */
+ public double x;
+
+ /** The y coordinate of the upper left corner of the ellipse's
+ * bounding rectangle. */
+ public double y;
+
+ /** The width of the ellipse's bounding rectangle. */
+ public double width;
+
+ /** The height of the ellipse's bounding rectangle. */
+ public double height;
+
+ /**
+ * Instantiates a new double-valued Ellipse2D.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued Ellipse2D with the specified
+ * data.
+ *
+ * @param x the x coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param y the y coordinate of the upper left corner of the ellipse's
+ * bounding rectangle
+ * @param width the width of the ellipse's bounding rectangle
+ * @param height the height of the ellipse's bounding rectangle
+ */
+ public Double(double x, double y, double width, double height) {
+ setFrame(x, y, width, height);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0 || height <= 0.0;
+ }
+
+ @Override
+ public void setFrame(double x, double y, double width, double height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ public Rectangle2D getBounds2D() {
+ return new Rectangle2D.Double(x, y, width, height);
+ }
+ }
+
+ /*
+ * Ellipse2D path iterator
+ */
+ /**
+ * The subclass of PathIterator to traverse an Ellipse2D.
+ */
+ class Iterator implements PathIterator {
+
+ /*
+ * Ellipse is subdivided into four quarters by x and y axis. Each part approximated by
+ * cubic Bezier curve. Arc in first quarter is started in (a, 0) and finished in (0, b) points.
+ * Control points for cubic curve wiil be (a, 0), (a, m), (n, b) and (0, b) where n and m are
+ * calculated based on requirement Bezier curve in point 0.5 should lay on the arc.
+ */
+
+ /** The coefficient to calculate control points of Bezier curves. */
+ final double u = 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0);
+
+ /** The points coordinates calculation table. */
+ final double points[][] = {
+ { 1.0, 0.5 + u, 0.5 + u, 1.0, 0.5, 1.0 },
+ { 0.5 - u, 1.0, 0.0, 0.5 + u, 0.0, 0.5 },
+ { 0.0, 0.5 - u, 0.5 - u, 0.0, 0.5, 0.0 },
+ { 0.5 + u, 0.0, 1.0, 0.5 - u, 1.0, 0.5 }
+ };
+
+ /** The x coordinate of left-upper corner of the ellipse bounds. */
+ double x;
+
+ /** The y coordinate of left-upper corner of the ellipse bounds. */
+ double y;
+
+ /** The width of the ellipse bounds. */
+ double width;
+
+ /** The height of the ellipse bounds. */
+ double height;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segmenet index. */
+ int index;
+
+ /**
+ * Constructs a new Ellipse2D.Iterator for given ellipse and transformation
+ *
+ * @param e - the source Ellipse2D object
+ * @param t the t
+ */
+ Iterator(Ellipse2D e, AffineTransform t) {
+ this.x = e.getX();
+ this.y = e.getY();
+ this.width = e.getWidth();
+ this.height = e.getHeight();
+ this.t = t;
+ if (width < 0.0 || height < 0.0) {
+ index = 6;
+ }
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > 5;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == 5) {
+ return SEG_CLOSE;
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ count = 1;
+ double p[] = points[3];
+ coords[0] = x + p[4] * width;
+ coords[1] = y + p[5] * height;
+ } else {
+ type = SEG_CUBICTO;
+ count = 3;
+ double p[] = points[index - 1];
+ int j = 0;
+ for (int i = 0; i < 3; i++) {
+ coords[j] = x + p[j++] * width;
+ coords[j] = y + p[j++] * height;
+ }
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == 5) {
+ return SEG_CLOSE;
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ count = 1;
+ double p[] = points[3];
+ coords[0] = (float)(x + p[4] * width);
+ coords[1] = (float)(y + p[5] * height);
+ } else {
+ type = SEG_CUBICTO;
+ count = 3;
+ int j = 0;
+ double p[] = points[index - 1];
+ for (int i = 0; i < 3; i++) {
+ coords[j] = (float)(x + p[j++] * width);
+ coords[j] = (float)(y + p[j++] * height);
+ }
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new Ellipse2D.
+ */
+ protected Ellipse2D() {
+ }
+
+ public boolean contains(double px, double py) {
+ if (isEmpty()) {
+ return false;
+ }
+
+ double a = (px - getX()) / getWidth() - 0.5;
+ double b = (py - getY()) / getHeight() - 0.5;
+
+ return a * a + b * b < 0.25;
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+ return false;
+ }
+
+ double cx = getX() + getWidth() / 2.0;
+ double cy = getY() + getHeight() / 2.0;
+
+ double rx1 = rx;
+ double ry1 = ry;
+ double rx2 = rx + rw;
+ double ry2 = ry + rh;
+
+ double nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx);
+ double ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy);
+
+ return contains(nx, ny);
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+ return false;
+ }
+
+ double rx1 = rx;
+ double ry1 = ry;
+ double rx2 = rx + rw;
+ double ry2 = ry + rh;
+
+ return
+ contains(rx1, ry1) &&
+ contains(rx2, ry1) &&
+ contains(rx2, ry2) &&
+ contains(rx1, ry2);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at) {
+ return new Iterator(this, at);
+ }
+}
+
diff --git a/awt/java/awt/geom/FlatteningPathIterator.java b/awt/java/awt/geom/FlatteningPathIterator.java
new file mode 100644
index 0000000..ca5c7c2
--- /dev/null
+++ b/awt/java/awt/geom/FlatteningPathIterator.java
@@ -0,0 +1,326 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class FlatteningPathIterator takes a PathIterator for traversing
+ * a curved shape and flattens it by estimating the curve as a series
+ * of line segments. The flattening factor indicates how far the
+ * estimating line segments are allowed to be from the actual curve:
+ * the FlatteningPathIterator will keep dividing each curved segment
+ * into smaller and smaller flat segments until either the segments
+ * are withing the flattening factor of the curve or until the buffer
+ * limit is reached.
+ */
+public class FlatteningPathIterator implements PathIterator {
+
+ /** The default points buffer size. */
+ private static final int BUFFER_SIZE = 16;
+
+ /** The default curve subdivision limit. */
+ private static final int BUFFER_LIMIT = 16;
+
+ /** The points buffer capacity. */
+ private static final int BUFFER_CAPACITY = 16;
+
+ /** The type of current segment to be flat. */
+ int bufType;
+
+ /** The curve subdivision limit. */
+ int bufLimit;
+
+ /** The current points buffer size. */
+ int bufSize;
+
+ /** The inner cursor position in points buffer. */
+ int bufIndex;
+
+ /** The current subdivision count. */
+ int bufSubdiv;
+
+ /** The points buffer. */
+ double buf[];
+
+ /** The indicator of empty points buffer. */
+ boolean bufEmpty = true;
+
+ /** The source PathIterator. */
+ PathIterator p;
+
+ /** The flatness of new path. */
+ double flatness;
+
+ /** The square of flatness. */
+ double flatness2;
+
+ /** The x coordinate of previous path segment. */
+ double px;
+
+ /** The y coordinate of previous path segment. */
+ double py;
+
+ /** The tamporary buffer for getting points from PathIterator. */
+ double coords[] = new double[6];
+
+ /**
+ * Instantiates a new flattening path iterator given the path
+ * iterator for a (possibly) curved path and a flattening factor
+ * which indicates how close together the points on the curve
+ * should be chosen. The buffer limit defaults to 16 which means
+ * that each curve will be divided into no more than 16 segments
+ * regardless of the flattening factor.
+ *
+ * @param path the path iterator of the original curve
+ * @param flatness the flattening factor that indicates how far the
+ * flat path is allowed to be from the actual curve in order to
+ * decide when to stop dividing the path into smaller and smaller
+ * segments.
+ *
+ * @throws IllegalArgumentException if the flatness is less than zero.
+ * @throws NullPointerException if the path is null.
+ */
+ public FlatteningPathIterator(PathIterator path, double flatness) {
+ this(path, flatness, BUFFER_LIMIT);
+ }
+
+ /**
+ * Instantiates a new flattening path iterator given the path
+ * iterator for a (possibly) curved path and a flattening factor
+ * and a buffer limit. The FlatteningPathIterator will keep
+ * dividing each curved segment into smaller and smaller flat segments
+ * until either the segments are withing the flattening factor of the
+ * curve or until the buffer limit is reached.
+ *
+ * @param path the path iterator of the original curve
+ * @param flatness the flattening factor that indicates how far the
+ * flat path is allowed to be from the actual curve in order to
+ * decide when to stop dividing the path into smaller and smaller
+ * segments.
+ * @param limit the maximum number of flat segments to divide each
+ * curve into
+ *
+ * @throws IllegalArgumentException if the flatness or limit is less than zero.
+ * @throws NullPointerException if the path is null.
+ */
+ public FlatteningPathIterator(PathIterator path, double flatness, int limit) {
+ if (flatness < 0.0) {
+ // awt.206=Flatness is less then zero
+ throw new IllegalArgumentException(Messages.getString("awt.206")); //$NON-NLS-1$
+ }
+ if (limit < 0) {
+ // awt.207=Limit is less then zero
+ throw new IllegalArgumentException(Messages.getString("awt.207")); //$NON-NLS-1$
+ }
+ if (path == null) {
+ // awt.208=Path is null
+ throw new NullPointerException(Messages.getString("awt.208")); //$NON-NLS-1$
+ }
+ this.p = path;
+ this.flatness = flatness;
+ this.flatness2 = flatness * flatness;
+ this.bufLimit = limit;
+ this.bufSize = Math.min(bufLimit, BUFFER_SIZE);
+ this.buf = new double[bufSize];
+ this.bufIndex = bufSize;
+ }
+
+ /**
+ * Gets the flattening factor.
+ *
+ * @return the flattening factor
+ */
+ public double getFlatness() {
+ return flatness;
+ }
+
+ /**
+ * Gets the maximum number of subdivisions per curved segment.
+ *
+ * @return the maximum number of subdivisions per curved segment
+ */
+ public int getRecursionLimit() {
+ return bufLimit;
+ }
+
+ public int getWindingRule() {
+ return p.getWindingRule();
+ }
+
+ public boolean isDone() {
+ return bufEmpty && p.isDone();
+ }
+
+ /**
+ * Calculates flat path points for current segment of the source shape.
+ *
+ * Line segment is flat by itself. Flatness of quad and cubic curves evaluated by getFlatnessSq() method.
+ * Curves subdivided until current flatness is bigger than user defined and subdivision limit isn't exhausted.
+ * Single source segment translated to series of buffer points. The less flatness the bigger serries.
+ * Every currentSegment() call extract one point from the buffer. When series completed evaluate() takes next source shape segment.
+ */
+ void evaluate() {
+ if (bufEmpty) {
+ bufType = p.currentSegment(coords);
+ }
+
+ switch (bufType) {
+ case SEG_MOVETO:
+ case SEG_LINETO:
+ px = coords[0];
+ py = coords[1];
+ break;
+ case SEG_QUADTO:
+ if (bufEmpty) {
+ bufIndex -= 6;
+ buf[bufIndex + 0] = px;
+ buf[bufIndex + 1] = py;
+ System.arraycopy(coords, 0, buf, bufIndex + 2, 4);
+ bufSubdiv = 0;
+ }
+
+ while (bufSubdiv < bufLimit) {
+ if (QuadCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) {
+ break;
+ }
+
+ // Realloc buffer
+ if (bufIndex <= 4) {
+ double tmp[] = new double[bufSize + BUFFER_CAPACITY];
+ System.arraycopy(
+ buf, bufIndex,
+ tmp, bufIndex + BUFFER_CAPACITY,
+ bufSize - bufIndex);
+ buf = tmp;
+ bufSize += BUFFER_CAPACITY;
+ bufIndex += BUFFER_CAPACITY;
+ }
+
+ QuadCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 4, buf, bufIndex);
+
+ bufIndex -= 4;
+ bufSubdiv++;
+ }
+
+ bufIndex += 4;
+ px = buf[bufIndex];
+ py = buf[bufIndex + 1];
+
+ bufEmpty = (bufIndex == bufSize - 2);
+ if (bufEmpty) {
+ bufIndex = bufSize;
+ bufType = SEG_LINETO;
+ } else {
+ bufSubdiv--;
+ }
+ break;
+ case SEG_CUBICTO:
+ if (bufEmpty) {
+ bufIndex -= 8;
+ buf[bufIndex + 0] = px;
+ buf[bufIndex + 1] = py;
+ System.arraycopy(coords, 0, buf, bufIndex + 2, 6);
+ bufSubdiv = 0;
+ }
+
+ while (bufSubdiv < bufLimit) {
+ if (CubicCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) {
+ break;
+ }
+
+ // Realloc buffer
+ if (bufIndex <= 6) {
+ double tmp[] = new double[bufSize + BUFFER_CAPACITY];
+ System.arraycopy(
+ buf, bufIndex,
+ tmp, bufIndex + BUFFER_CAPACITY,
+ bufSize - bufIndex);
+ buf = tmp;
+ bufSize += BUFFER_CAPACITY;
+ bufIndex += BUFFER_CAPACITY;
+ }
+
+ CubicCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 6, buf, bufIndex);
+
+ bufIndex -= 6;
+ bufSubdiv++;
+ }
+
+ bufIndex += 6;
+ px = buf[bufIndex];
+ py = buf[bufIndex + 1];
+
+ bufEmpty = (bufIndex == bufSize - 2);
+ if (bufEmpty) {
+ bufIndex = bufSize;
+ bufType = SEG_LINETO;
+ } else {
+ bufSubdiv--;
+ }
+ break;
+ }
+
+ }
+
+ public void next() {
+ if (bufEmpty) {
+ p.next();
+ }
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4Bx")); //$NON-NLS-1$
+ }
+ evaluate();
+ int type = bufType;
+ if (type != SEG_CLOSE) {
+ coords[0] = (float)px;
+ coords[1] = (float)py;
+ if (type != SEG_MOVETO) {
+ type = SEG_LINETO;
+ }
+ }
+ return type;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ evaluate();
+ int type = bufType;
+ if (type != SEG_CLOSE) {
+ coords[0] = px;
+ coords[1] = py;
+ if (type != SEG_MOVETO) {
+ type = SEG_LINETO;
+ }
+ }
+ return type;
+ }
+}
+
diff --git a/awt/java/awt/geom/GeneralPath.java b/awt/java/awt/geom/GeneralPath.java
new file mode 100644
index 0000000..36b01c4
--- /dev/null
+++ b/awt/java/awt/geom/GeneralPath.java
@@ -0,0 +1,566 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.Crossing;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class GeneralPath represents a shape whose outline is given
+ * by different types of curved and straight segments.
+ */
+public final class GeneralPath implements Shape, Cloneable {
+
+ /** The Constant WIND_EVEN_ODD see {@link PathIterator#WIND_EVEN_ODD}. */
+ public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
+
+ /** The Constant WIND_NON_ZERO see {@link PathIterator#WIND_NON_ZERO}. */
+ public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
+
+ /** The buffers size. */
+ private static final int BUFFER_SIZE = 10;
+
+ /** The buffers capacity. */
+ private static final int BUFFER_CAPACITY = 10;
+
+ /** The point's types buffer. */
+ byte[] types;
+
+ /** The points buffer. */
+ float[] points;
+
+ /** The point's type buffer size. */
+ int typeSize;
+
+ /** The points buffer size. */
+ int pointSize;
+
+ /** The path rule. */
+ int rule;
+
+ /** The space amount in points buffer for different segmenet's types. */
+ static int pointShift[] = {
+ 2, // MOVETO
+ 2, // LINETO
+ 4, // QUADTO
+ 6, // CUBICTO
+ 0}; // CLOSE
+
+ /*
+ * GeneralPath path iterator
+ */
+ /**
+ * The Class Iterator is the subclass of Iterator for traversing the
+ * outline of a GeneralPath.
+ */
+ class Iterator implements PathIterator {
+
+ /** The current cursor position in types buffer. */
+ int typeIndex;
+
+ /** The current cursor position in points buffer. */
+ int pointIndex;
+
+ /** The source GeneralPath object. */
+ GeneralPath p;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /**
+ * Constructs a new GeneralPath.Iterator for given general path
+ *
+ * @param path - the source GeneralPath object
+ */
+ Iterator(GeneralPath path) {
+ this(path, null);
+ }
+
+ /**
+ * Constructs a new GeneralPath.Iterator for given general path and transformation
+ *
+ * @param path - the source GeneralPath object
+ * @param at - the AffineTransform object to apply rectangle path
+ */
+ Iterator(GeneralPath path, AffineTransform at) {
+ this.p = path;
+ this.t = at;
+ }
+
+ public int getWindingRule() {
+ return p.getWindingRule();
+ }
+
+ public boolean isDone() {
+ return typeIndex >= p.typeSize;
+ }
+
+ public void next() {
+ typeIndex++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type = p.types[typeIndex];
+ int count = GeneralPath.pointShift[type];
+ for (int i = 0; i < count; i++) {
+ coords[i] = p.points[pointIndex + i];
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count / 2);
+ }
+ pointIndex += count;
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type = p.types[typeIndex];
+ int count = GeneralPath.pointShift[type];
+ System.arraycopy(p.points, pointIndex, coords, 0, count);
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count / 2);
+ }
+ pointIndex += count;
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new general path with the winding rule set
+ * to {@link PathIterator#WIND_NON_ZERO} and the initial capacity
+ * (number of segments) set to the default value 10.
+ */
+ public GeneralPath() {
+ this(WIND_NON_ZERO, BUFFER_SIZE);
+ }
+
+ /**
+ * Instantiates a new general path with the given winding rule
+ * and the initial capacity (number of segments) set to the
+ * default value 10.
+ *
+ * @param rule the winding rule, either {@link PathIterator#WIND_EVEN_ODD}
+ * or {@link PathIterator#WIND_NON_ZERO}
+ */
+ public GeneralPath(int rule) {
+ this(rule, BUFFER_SIZE);
+ }
+
+ /**
+ * Instantiates a new general path with the given winding rule
+ * and initial capacity (number of segments).
+ *
+ * @param rule the winding rule, either {@link PathIterator#WIND_EVEN_ODD}
+ * or {@link PathIterator#WIND_NON_ZERO}
+ * @param initialCapacity the number of segments the path is set to hold
+ */
+ public GeneralPath(int rule, int initialCapacity) {
+ setWindingRule(rule);
+ types = new byte[initialCapacity];
+ points = new float[initialCapacity * 2];
+ }
+
+ /**
+ * Creates a new GeneralPath from the outline of the given shape.
+ *
+ * @param shape the shape
+ */
+ public GeneralPath(Shape shape) {
+ this(WIND_NON_ZERO, BUFFER_SIZE);
+ PathIterator p = shape.getPathIterator(null);
+ setWindingRule(p.getWindingRule());
+ append(p, false);
+ }
+
+ /**
+ * Sets the winding rule, which determines how to decide whether
+ * a point that isn't on the path itself is inside or outside of
+ * the shape.
+ *
+ * @param rule the new winding rule
+ *
+ * @throws IllegalArgumentException if the winding rule is neither
+ * {@link PathIterator#WIND_EVEN_ODD} nor {@link PathIterator#WIND_NON_ZERO}.
+ */
+ public void setWindingRule(int rule) {
+ if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
+ // awt.209=Invalid winding rule value
+ throw new java.lang.IllegalArgumentException(Messages.getString("awt.209")); //$NON-NLS-1$
+ }
+ this.rule = rule;
+ }
+
+ /**
+ * Gets the winding rule.
+ *
+ * @return the winding rule, either {@link PathIterator#WIND_EVEN_ODD}
+ * or {@link PathIterator#WIND_NON_ZERO}
+ */
+ public int getWindingRule() {
+ return rule;
+ }
+
+ /**
+ * Checks the point data buffer sizes to see whether pointCount additional
+ * point-data elements can fit. (Note that the number of point data
+ * elements to add is more than one per point -- it depends on the type
+ * of point being added.) Reallocates the buffers to enlarge the size if necessary.
+ *
+ * @param pointCount - the number of point data elements to be added
+ * @param checkMove whether to check for existing points
+ *
+ * @throws IllegalPathStateException checkMove is true and the
+ * path is currently empty.
+ */
+ void checkBuf(int pointCount, boolean checkMove) {
+ if (checkMove && typeSize == 0) {
+ // awt.20A=First segment should be SEG_MOVETO type
+ throw new IllegalPathStateException(Messages.getString("awt.20A")); //$NON-NLS-1$
+ }
+ if (typeSize == types.length) {
+ byte tmp[] = new byte[typeSize + BUFFER_CAPACITY];
+ System.arraycopy(types, 0, tmp, 0, typeSize);
+ types = tmp;
+ }
+ if (pointSize + pointCount > points.length) {
+ float tmp[] = new float[pointSize + Math.max(BUFFER_CAPACITY * 2, pointCount)];
+ System.arraycopy(points, 0, tmp, 0, pointSize);
+ points = tmp;
+ }
+ }
+
+ /**
+ * Appends a new point to the end of this general path, disconnected
+ * from the existing path.
+ *
+ * @param x the x coordinate of the next point to append
+ * @param y the y coordinate of the next point to append
+ */
+ public void moveTo(float x, float y) {
+ if (typeSize > 0 && types[typeSize - 1] == PathIterator.SEG_MOVETO) {
+ points[pointSize - 2] = x;
+ points[pointSize - 1] = y;
+ } else {
+ checkBuf(2, false);
+ types[typeSize++] = PathIterator.SEG_MOVETO;
+ points[pointSize++] = x;
+ points[pointSize++] = y;
+ }
+ }
+
+ /**
+ * Appends a new segment to the end of this general path by making
+ * a straight line segment from the current endpoint to the
+ * given new point.
+ *
+ * @param x the x coordinate of the next point to append
+ * @param y the y coordinate of the next point to append
+ */
+ public void lineTo(float x, float y) {
+ checkBuf(2, true);
+ types[typeSize++] = PathIterator.SEG_LINETO;
+ points[pointSize++] = x;
+ points[pointSize++] = y;
+ }
+
+ /**
+ * Appends a new segment to the end of this general path by making
+ * a quadratic curve from the current endpoint to the point (x2, y2)
+ * using the point (x1, y1) as the quadratic curve's control point.
+ *
+ * @param x1 the x coordinate of the quadratic curve's control point
+ * @param y1 the y coordinate of the quadratic curve's control point
+ * @param x2 the x coordinate of the quadratic curve's end point
+ * @param y2 the y coordinate of the quadratic curve's end point
+ */
+ public void quadTo(float x1, float y1, float x2, float y2) {
+ checkBuf(4, true);
+ types[typeSize++] = PathIterator.SEG_QUADTO;
+ points[pointSize++] = x1;
+ points[pointSize++] = y1;
+ points[pointSize++] = x2;
+ points[pointSize++] = y2;
+ }
+
+ /**
+ * Appends a new segment to the end of this general path by making
+ * a cubic curve from the current endpoint to the point (x3, y3)
+ * using (x1, y1) and (x2, y2) as control points.
+ *
+ * @see java.awt.geom.CubicCurve2D
+ *
+ * @param x1 the x coordinate of the new cubic segment's first control point
+ * @param y1 the y coordinate of the new cubic segment's first control point
+ * @param x2 the x coordinate of the new cubic segment's second control point
+ * @param y2 the y coordinate of the new cubic segment's second control point
+ * @param x3 the x coordinate of the new cubic segment's end point
+ * @param y3 the y coordinate of the new cubic segment's end point
+ */
+ public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) {
+ checkBuf(6, true);
+ types[typeSize++] = PathIterator.SEG_CUBICTO;
+ points[pointSize++] = x1;
+ points[pointSize++] = y1;
+ points[pointSize++] = x2;
+ points[pointSize++] = y2;
+ points[pointSize++] = x3;
+ points[pointSize++] = y3;
+ }
+
+ /**
+ * Appends the type information to declare that the current
+ * endpoint closes the curve.
+ */
+ public void closePath() {
+ if (typeSize == 0 || types[typeSize - 1] != PathIterator.SEG_CLOSE) {
+ checkBuf(0, true);
+ types[typeSize++] = PathIterator.SEG_CLOSE;
+ }
+ }
+
+ /**
+ * Appends the outline of the specified shape onto the end
+ * of this GeneralPath.
+ *
+ * @param shape the shape whose outline is to be appended
+ * @param connect true to connect this path's current
+ * endpoint to the first point of the shape's outline or
+ * false to append the shape's outline without connecting it
+ *
+ * @throws NullPointerException if the shape parameter is null
+ */
+ public void append(Shape shape, boolean connect) {
+ PathIterator p = shape.getPathIterator(null);
+ append(p, connect);
+ }
+
+ /**
+ * Appends the path defined by the specified PathIterator onto the end
+ * of this GeneralPath.
+ *
+ * @param path the PathIterator that defines the new path to append
+ * @param connect true to connect this path's current
+ * endpoint to the first point of the shape's outline or
+ * false to append the shape's outline without connecting it
+ */
+ public void append(PathIterator path, boolean connect) {
+ while (!path.isDone()) {
+ float coords[] = new float[6];
+ switch (path.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (!connect || typeSize == 0) {
+ moveTo(coords[0], coords[1]);
+ break;
+ }
+ if (types[typeSize - 1] != PathIterator.SEG_CLOSE &&
+ points[pointSize - 2] == coords[0] &&
+ points[pointSize - 1] == coords[1])
+ {
+ break;
+ }
+ // NO BREAK;
+ case PathIterator.SEG_LINETO:
+ lineTo(coords[0], coords[1]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ quadTo(coords[0], coords[1], coords[2], coords[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ closePath();
+ break;
+ }
+ path.next();
+ connect = false;
+ }
+ }
+
+ /**
+ * Gets the current end point of the path.
+ *
+ * @return the current end point of the path
+ */
+ public Point2D getCurrentPoint() {
+ if (typeSize == 0) {
+ return null;
+ }
+ int j = pointSize - 2;
+ if (types[typeSize - 1] == PathIterator.SEG_CLOSE) {
+
+ for (int i = typeSize - 2; i > 0; i--) {
+ int type = types[i];
+ if (type == PathIterator.SEG_MOVETO) {
+ break;
+ }
+ j -= pointShift[type];
+ }
+ }
+ return new Point2D.Float(points[j], points[j + 1]);
+ }
+
+ /**
+ * Resets the GeneralPath to being an empty path. The underlying
+ * point and segment data is not deleted but rather the end indices
+ * of the data arrays are set to zero.
+ */
+ public void reset() {
+ typeSize = 0;
+ pointSize = 0;
+ }
+
+ /**
+ * Transform all of the coordinates of this path according to the
+ * specified AffineTransform.
+ *
+ * @param t the AffineTransform
+ */
+ public void transform(AffineTransform t) {
+ t.transform(points, 0, points, 0, pointSize / 2);
+ }
+
+ /**
+ * Creates a new GeneralPath whose data is given by this path's
+ * data transformed according to the specified AffineTransform.
+ *
+ * @param t the AffineTransform
+ *
+ * @return the new GeneralPath whose data is given by this path's
+ * data transformed according to the specified AffineTransform
+ */
+ public Shape createTransformedShape(AffineTransform t) {
+ GeneralPath p = (GeneralPath)clone();
+ if (t != null) {
+ p.transform(t);
+ }
+ return p;
+ }
+
+ public Rectangle2D getBounds2D() {
+ float rx1, ry1, rx2, ry2;
+ if (pointSize == 0) {
+ rx1 = ry1 = rx2 = ry2 = 0.0f;
+ } else {
+ int i = pointSize - 1;
+ ry1 = ry2 = points[i--];
+ rx1 = rx2 = points[i--];
+ while (i > 0) {
+ float y = points[i--];
+ float x = points[i--];
+ if (x < rx1) {
+ rx1 = x;
+ } else
+ if (x > rx2) {
+ rx2 = x;
+ }
+ if (y < ry1) {
+ ry1 = y;
+ } else
+ if (y > ry2) {
+ ry2 = y;
+ }
+ }
+ }
+ return new Rectangle2D.Float(rx1, ry1, rx2 - rx1, ry2 - ry1);
+ }
+
+ public Rectangle getBounds() {
+ return getBounds2D().getBounds();
+ }
+
+ /**
+ * Checks the cross count (number of times a ray from the point
+ * crosses the shape's boundary) to determine whether the number
+ * of crossings corresponds to a point inside the shape or not
+ * (according to the shape's path rule).
+ *
+ * @param cross - the point's cross count
+ *
+ * @return true if the point is inside the path, or false otherwise
+ */
+ boolean isInside(int cross) {
+ if (rule == WIND_NON_ZERO) {
+ return Crossing.isInsideNonZero(cross);
+ }
+ return Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean contains(double px, double py) {
+ return isInside(Crossing.crossShape(this, px, py));
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross != Crossing.CROSSING && isInside(cross);
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross == Crossing.CROSSING || isInside(cross);
+ }
+
+ public boolean contains(Point2D p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ public boolean contains(Rectangle2D r) {
+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public boolean intersects(Rectangle2D r) {
+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new FlatteningPathIterator(getPathIterator(t), flatness);
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ GeneralPath p = (GeneralPath) super.clone();
+ p.types = types.clone();
+ p.points = points.clone();
+ return p;
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/geom/IllegalPathStateException.java b/awt/java/awt/geom/IllegalPathStateException.java
new file mode 100644
index 0000000..7f459e7
--- /dev/null
+++ b/awt/java/awt/geom/IllegalPathStateException.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+/**
+ * The Class IllegalPathStateException indicates errors where the
+ * current state of a path object is imcompatible with the desired
+ * action, such as performing non-trivial actions on an empty path.
+ */
+public class IllegalPathStateException extends RuntimeException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -5158084205220481094L;
+
+ /**
+ * Instantiates a new illegal path state exception.
+ */
+ public IllegalPathStateException() {
+ }
+
+ /**
+ * Instantiates a new illegal path state exception with the
+ * specified detail message.
+ *
+ * @param s the details of the error
+ */
+ public IllegalPathStateException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/awt/java/awt/geom/Line2D.java b/awt/java/awt/geom/Line2D.java
new file mode 100644
index 0000000..a53c470
--- /dev/null
+++ b/awt/java/awt/geom/Line2D.java
@@ -0,0 +1,871 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class Line2D represents a line whose data is given in
+ * high-precision values appropriate for graphical operations.
+ */
+public abstract class Line2D implements Shape, Cloneable {
+
+ /**
+ * The Class Float is the subclass of Line2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends Line2D {
+
+ /** The x coordinate of the starting point. */
+ public float x1;
+
+ /** The y coordinate of the starting point. */
+ public float y1;
+
+ /** The x coordinate of the end point. */
+ public float x2;
+
+ /** The y coordinate of the end point. */
+ public float y2;
+
+ /**
+ * Instantiates a new float-valued Line2D with
+ * its data values set to zero.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued Line2D with
+ * the specified endpoints.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public Float(float x1, float y1, float x2, float y2) {
+ setLine(x1, y1, x2, y2);
+ }
+
+ /**
+ * Instantiates a new float-valued Line2D with
+ * the specified endpoints.
+ *
+ * @param p1 the starting point
+ * @param p2 the end point
+ */
+ public Float(Point2D p1, Point2D p2) {
+ setLine(p1, p2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Float(x1, y1);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Float(x2, y2);
+ }
+
+ @Override
+ public void setLine(double x1, double y1, double x2, double y2) {
+ this.x1 = (float)x1;
+ this.y1 = (float)y1;
+ this.x2 = (float)x2;
+ this.y2 = (float)y2;
+ }
+
+ /**
+ * Sets the data values that define the line.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public void setLine(float x1, float y1, float x2, float y2) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ float rx, ry, rw, rh;
+ if (x1 < x2) {
+ rx = x1;
+ rw = x2 - x1;
+ } else {
+ rx = x2;
+ rw = x1 - x2;
+ }
+ if (y1 < y2) {
+ ry = y1;
+ rh = y2 - y1;
+ } else {
+ ry = y2;
+ rh = y1 - y2;
+ }
+ return new Rectangle2D.Float(rx, ry, rw, rh);
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of Line2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends Line2D {
+
+ /** The x coordinate of the starting point. */
+ public double x1;
+
+ /** The y coordinate of the starting point. */
+ public double y1;
+
+ /** The x coordinate of the end point. */
+ public double x2;
+
+ /** The y coordinate of the end point. */
+ public double y2;
+
+ /**
+ * Instantiates a new double-valued Line2D with
+ * its data values set to zero.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued Line2D with
+ * the specified endpoints.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public Double(double x1, double y1, double x2, double y2) {
+ setLine(x1, y1, x2, y2);
+ }
+
+ /**
+ * Instantiates a new double-valued Line2D with
+ * the specified endpoints.
+ *
+ * @param p1 the starting point
+ * @param p2 the end point
+ */
+ public Double(Point2D p1, Point2D p2) {
+ setLine(p1, p2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Double(x1, y1);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Double(x2, y2);
+ }
+
+ @Override
+ public void setLine(double x1, double y1, double x2, double y2) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ double rx, ry, rw, rh;
+ if (x1 < x2) {
+ rx = x1;
+ rw = x2 - x1;
+ } else {
+ rx = x2;
+ rw = x1 - x2;
+ }
+ if (y1 < y2) {
+ ry = y1;
+ rh = y2 - y1;
+ } else {
+ ry = y2;
+ rh = y1 - y2;
+ }
+ return new Rectangle2D.Double(rx, ry, rw, rh);
+ }
+ }
+
+ /*
+ * Line2D path iterator
+ */
+ /**
+ * The subclass of PathIterator to traverse a Line2D.
+ */
+ class Iterator implements PathIterator {
+
+ /** The x coordinate of the start line point. */
+ double x1;
+
+ /** The y coordinate of the start line point. */
+ double y1;
+
+ /** The x coordinate of the end line point. */
+ double x2;
+
+ /** The y coordinate of the end line point. */
+ double y2;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segmenet index. */
+ int index;
+
+ /**
+ * Constructs a new Line2D.Iterator for given line and transformation
+ *
+ * @param l - the source Line2D object
+ * @param at - the AffineTransform object to apply rectangle path
+ */
+ Iterator(Line2D l, AffineTransform at) {
+ this.x1 = l.getX1();
+ this.y1 = l.getY1();
+ this.x2 = l.getX2();
+ this.y2 = l.getY2();
+ this.t = at;
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > 1;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = x1;
+ coords[1] = y1;
+ } else {
+ type = SEG_LINETO;
+ coords[0] = x2;
+ coords[1] = y2;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = (float)x1;
+ coords[1] = (float)y1;
+ } else {
+ type = SEG_LINETO;
+ coords[0] = (float)x2;
+ coords[1] = (float)y2;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new Line2D.
+ */
+ protected Line2D() {
+ }
+
+ /**
+ * Gets the x coordinate of the starting point.
+ *
+ * @return the x coordinate of the starting point
+ */
+ public abstract double getX1();
+
+ /**
+ * Gets the y coordinate of the starting point.
+ *
+ * @return the y coordinate of the starting point
+ */
+ public abstract double getY1();
+
+ /**
+ * Gets the x coordinate of the end point.
+ *
+ * @return the x2
+ */
+ public abstract double getX2();
+
+ /**
+ * Gets the y coordinate of the end point.
+ *
+ * @return the y coordinate of the end point
+ */
+ public abstract double getY2();
+
+ /**
+ * Gets the p the starting point.
+ *
+ * @return the p the starting point
+ */
+ public abstract Point2D getP1();
+
+ /**
+ * Gets the p end point.
+ *
+ * @return the p end point
+ */
+ public abstract Point2D getP2();
+
+ /**
+ * Sets the line's endpoints.
+ *
+ * @param x1 the x coordinate of the starting point
+ * @param y1 the y coordinate of the starting point
+ * @param x2 the x coordinate of the end point
+ * @param y2 the y coordinate of the end point
+ */
+ public abstract void setLine(double x1, double y1, double x2, double y2);
+
+ /**
+ * Sets the line's endpoints.
+ *
+ * @param p1 the starting point
+ * @param p2 the end point
+ */
+ public void setLine(Point2D p1, Point2D p2) {
+ setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
+ }
+
+ /**
+ * Sets the line's endpoints by copying the data from another Line2D.
+ *
+ * @param line the Line2D to copy the endpoint data from
+ */
+ public void setLine(Line2D line) {
+ setLine(line.getX1(), line.getY1(), line.getX2(), line.getY2());
+ }
+
+ public Rectangle getBounds() {
+ return getBounds2D().getBounds();
+ }
+
+ /**
+ * Tells where the point is with respect to the line segment,
+ * given the orientation of the line segment. If the ray
+ * found by extending the line segment from its starting point
+ * is rotated, this method tells whether the ray
+ * should rotate in a clockwise direction or a counter-clockwise
+ * direction to hit the point first. The return value is 0 if the
+ * point is on the line segment, it's 1 if the point is on the ray
+ * or if the ray should rotate in a counter-clockwise direction to get to the
+ * point, and it's -1 if the ray should rotate in a clockwise
+ * direction to get to the point or if the point is on the line
+ * determined by the line segment but not on the ray from the
+ * segment's starting point and through its end point.
+ *
+ * @param x1 the x coordinate of the starting point of the line segment
+ * @param y1 the y coordinate of the starting point of the line segment
+ * @param x2 the x coordinate of the end point of the line segment
+ * @param y2 the y coordinate of the end point of the line segment
+ * @param px the x coordinate of the test point
+ * @param py the p coordinate of the test point
+ *
+ * @return the value that describes where the point is with respect to the line segment,
+ * given the orientation of the line segment
+ */
+ public static int relativeCCW(double x1, double y1, double x2, double y2, double px, double py) {
+ /*
+ * A = (x2-x1, y2-y1) P = (px-x1, py-y1)
+ */
+ x2 -= x1;
+ y2 -= y1;
+ px -= x1;
+ py -= y1;
+ double t = px * y2 - py * x2; // PxA
+ if (t == 0.0) {
+ t = px * x2 + py * y2; // P*A
+ if (t > 0.0) {
+ px -= x2; // B-A
+ py -= y2;
+ t = px * x2 + py * y2; // (P-A)*A
+ if (t < 0.0) {
+ t = 0.0;
+ }
+ }
+ }
+
+ return t < 0.0 ? -1 : (t > 0.0 ? 1 : 0);
+ }
+
+ /**
+ * Tells where the point is with respect to this line segment,
+ * given the orientation of this line segment. If the ray
+ * found by extending the line segment from its starting point
+ * is rotated, this method tells whether the ray
+ * should rotate in a clockwise direction or a counter-clockwise
+ * direction to hit the point first. The return value is 0 if the
+ * point is on the line segment, it's 1 if the point is on the ray
+ * or if the ray should rotate in a counter-clockwise direction to get to the
+ * point, and it's -1 if the ray should rotate in a clockwise
+ * direction to get to the point or if the point is on the line
+ * determined by the line segment but not on the ray from the
+ * segment's starting point and through its end point.
+ *
+ * @param px the x coordinate of the test point
+ * @param py the p coordinate of the test point
+ *
+ * @return the value that describes where the point is with respect to
+ * this line segment, given the orientation of this line segment
+ */
+ public int relativeCCW(double px, double py) {
+ return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py);
+ }
+
+ /**
+ * Tells where the point is with respect to this line segment,
+ * given the orientation of this line segment. If the ray
+ * found by extending the line segment from its starting point
+ * is rotated, this method tells whether the ray
+ * should rotate in a clockwise direction or a counter-clockwise
+ * direction to hit the point first. The return value is 0 if the
+ * point is on the line segment, it's 1 if the point is on the ray
+ * or if the ray should rotate in a counter-clockwise direction to get to the
+ * point, and it's -1 if the ray should rotate in a clockwise
+ * direction to get to the point or if the point is on the line
+ * determined by the line segment but not on the ray from the
+ * segment's starting point and through its end point.
+ *
+ * @param p the test point
+ *
+ * @return the value that describes where the point is with respect to
+ * this line segment, given the orientation of this line segment
+ */
+ public int relativeCCW(Point2D p) {
+ return relativeCCW(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+ }
+
+ /**
+ * Tells whether the two line segments cross.
+ *
+ * @param x1 the x coordinate of the starting point of the first segment
+ * @param y1 the y coordinate of the starting point of the first segment
+ * @param x2 the x coordinate of the end point of the first segment
+ * @param y2 the y coordinate of the end point of the first segment
+ * @param x3 the x coordinate of the starting point of the second segment
+ * @param y3 the y coordinate of the starting point of the second segment
+ * @param x4 the x coordinate of the end point of the second segment
+ * @param y4 the y coordinate of the end point of the second segment
+ *
+ * @return true, if the two line segments cross
+ */
+ public static boolean linesIntersect(double x1, double y1, double x2,
+ double y2, double x3, double y3, double x4, double y4)
+ {
+ /*
+ * A = (x2-x1, y2-y1) B = (x3-x1, y3-y1) C = (x4-x1, y4-y1) D = (x4-x3,
+ * y4-y3) = C-B E = (x1-x3, y1-y3) = -B F = (x2-x3, y2-y3) = A-B
+ *
+ * Result is ((AxB) * (AxC) <=0) and ((DxE) * (DxF) <= 0)
+ *
+ * DxE = (C-B)x(-B) = BxB-CxB = BxC DxF = (C-B)x(A-B) = CxA-CxB-BxA+BxB =
+ * AxB+BxC-AxC
+ */
+
+ x2 -= x1; // A
+ y2 -= y1;
+ x3 -= x1; // B
+ y3 -= y1;
+ x4 -= x1; // C
+ y4 -= y1;
+
+ double AvB = x2 * y3 - x3 * y2;
+ double AvC = x2 * y4 - x4 * y2;
+
+ // Online
+ if (AvB == 0.0 && AvC == 0.0) {
+ if (x2 != 0.0) {
+ return
+ (x4 * x3 <= 0.0) ||
+ ((x3 * x2 >= 0.0) &&
+ (x2 > 0.0 ? x3 <= x2 || x4 <= x2 : x3 >= x2 || x4 >= x2));
+ }
+ if (y2 != 0.0) {
+ return
+ (y4 * y3 <= 0.0) ||
+ ((y3 * y2 >= 0.0) &&
+ (y2 > 0.0 ? y3 <= y2 || y4 <= y2 : y3 >= y2 || y4 >= y2));
+ }
+ return false;
+ }
+
+ double BvC = x3 * y4 - x4 * y3;
+
+ return (AvB * AvC <= 0.0) && (BvC * (AvB + BvC - AvC) <= 0.0);
+ }
+
+ /**
+ * Tells whether the specified line segments crosses this line segment.
+ *
+ * @param x1 the x coordinate of the starting point of the test segment
+ * @param y1 the y coordinate of the starting point of the test segment
+ * @param x2 the x coordinate of the end point of the test segment
+ * @param y2 the y coordinate of the end point of the test segment
+ *
+ * @return true, if the specified line segments crosses this line segment
+ */
+ public boolean intersectsLine(double x1, double y1, double x2, double y2) {
+ return linesIntersect(x1, y1, x2, y2, getX1(), getY1(), getX2(), getY2());
+ }
+
+ /**
+ * Tells whether the specified line segments crosses this line segment.
+ *
+ * @param l the test segment
+ *
+ * @return true, if the specified line segments crosses this line segment
+ *
+ * @throws NullPointerException if l is null
+ */
+ public boolean intersectsLine(Line2D l) {
+ return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(), getX1(), getY1(), getX2(), getY2());
+ }
+
+ /**
+ * Gives the square of the distance between the point and the
+ * line segment.
+ *
+ * @param x1 the x coordinate of the starting point of the line segment
+ * @param y1 the y coordinate of the starting point of the line segment
+ * @param x2 the x coordinate of the end point of the line segment
+ * @param y2 the y coordinate of the end point of the line segment
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the the square of the distance between the point and the
+ * line segment
+ */
+ public static double ptSegDistSq(double x1, double y1, double x2, double y2, double px, double py) {
+ /*
+ * A = (x2 - x1, y2 - y1) P = (px - x1, py - y1)
+ */
+ x2 -= x1; // A = (x2, y2)
+ y2 -= y1;
+ px -= x1; // P = (px, py)
+ py -= y1;
+ double dist;
+ if (px * x2 + py * y2 <= 0.0) { // P*A
+ dist = px * px + py * py;
+ } else {
+ px = x2 - px; // P = A - P = (x2 - px, y2 - py)
+ py = y2 - py;
+ if (px * x2 + py * y2 <= 0.0) { // P*A
+ dist = px * px + py * py;
+ } else {
+ dist = px * y2 - py * x2;
+ dist = dist * dist / (x2 * x2 + y2 * y2); // pxA/|A|
+ }
+ }
+ if (dist < 0) {
+ dist = 0;
+ }
+ return dist;
+ }
+
+ /**
+ * Gives the distance between the point and the
+ * line segment.
+ *
+ * @param x1 the x coordinate of the starting point of the line segment
+ * @param y1 the y coordinate of the starting point of the line segment
+ * @param x2 the x coordinate of the end point of the line segment
+ * @param y2 the y coordinate of the end point of the line segment
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the the distance between the point and the
+ * line segment
+ */
+ public static double ptSegDist(double x1, double y1, double x2, double y2, double px, double py) {
+ return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py));
+ }
+
+ /**
+ * Gives the square of the distance between the point and this
+ * line segment.
+ *
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the the square of the distance between the point and this
+ * line segment
+ */
+ public double ptSegDistSq(double px, double py) {
+ return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), px, py);
+ }
+
+ /**
+ * Gives the square of the distance between the point and this
+ * line segment.
+ *
+ * @param p the test point
+ *
+ * @return the square of the distance between the point and this
+ * line segment
+ */
+ public double ptSegDistSq(Point2D p) {
+ return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+ }
+
+ /**
+ * Gives the distance between the point and this
+ * line segment.
+ *
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the distance between the point and this
+ * line segment
+ */
+ public double ptSegDist(double px, double py) {
+ return ptSegDist(getX1(), getY1(), getX2(), getY2(), px, py);
+ }
+
+ /**
+ * Gives the distance between the point and this
+ * line segment.
+ *
+ * @param p the test point
+ *
+ * @return the distance between the point and this
+ * line segment
+ */
+ public double ptSegDist(Point2D p) {
+ return ptSegDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+ }
+
+ /**
+ * Gives the square of the distance between the point and the
+ * line.
+ *
+ * @param x1 the x coordinate of the starting point of the line segment
+ * @param y1 the y coordinate of the starting point of the line segment
+ * @param x2 the x coordinate of the end point of the line segment
+ * @param y2 the y coordinate of the end point of the line segment
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the square of the distance between the point and the
+ * line
+ */
+ public static double ptLineDistSq(double x1, double y1, double x2, double y2, double px, double py) {
+ x2 -= x1;
+ y2 -= y1;
+ px -= x1;
+ py -= y1;
+ double s = px * y2 - py * x2;
+ return s * s / (x2 * x2 + y2 * y2);
+ }
+
+ /**
+ * Gives the square of the distance between the point and the
+ * line.
+ *
+ * @param x1 the x coordinate of the starting point of the line segment
+ * @param y1 the y coordinate of the starting point of the line segment
+ * @param x2 the x coordinate of the end point of the line segment
+ * @param y2 the y coordinate of the end point of the line segment
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the square of the distance between the point and the
+ * line
+ */
+ public static double ptLineDist(double x1, double y1, double x2, double y2, double px, double py) {
+ return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py));
+ }
+
+ /**
+ * Gives the square of the distance between the point and the
+ * line determined by this Line2D.
+ *
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the square of the distance between the point and the
+ * line determined by this Line2D
+ */
+ public double ptLineDistSq(double px, double py) {
+ return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), px, py);
+ }
+
+ /**
+ * Gives the square of the distance between the point and the
+ * line determined by this Line2D.
+ *
+ * @param p the test point
+ *
+ * @return the square of the distance between the point and the
+ * line determined by this Line2D
+ */
+ public double ptLineDistSq(Point2D p) {
+ return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+ }
+
+ /**
+ * Gives the distance between the point and the
+ * line determined by this Line2D.
+ *
+ * @param px the x coordinate of the test point
+ * @param py the y coordinate of the test point
+ *
+ * @return the distance between the point and the
+ * line determined by this Line2D
+ */
+ public double ptLineDist(double px, double py) {
+ return ptLineDist(getX1(), getY1(), getX2(), getY2(), px, py);
+ }
+
+ /**
+ * Gives the distance between the point and the
+ * line determined by this Line2D.
+ *
+ * @param p the test point
+ *
+ * @return the distance between the point and the
+ * line determined by this Line2D
+ */
+ public double ptLineDist(Point2D p) {
+ return ptLineDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY());
+ }
+
+ public boolean contains(double px, double py) {
+ return false;
+ }
+
+ public boolean contains(Point2D p) {
+ return false;
+ }
+
+ public boolean contains(Rectangle2D r) {
+ return false;
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ return false;
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ return intersects(new Rectangle2D.Double(rx, ry, rw, rh));
+ }
+
+ public boolean intersects(Rectangle2D r) {
+ return r.intersectsLine(getX1(), getY1(), getX2(), getY2());
+ }
+
+ public PathIterator getPathIterator(AffineTransform at) {
+ return new Iterator(this, at);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at, double flatness) {
+ return new Iterator(this, at);
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+}
diff --git a/awt/java/awt/geom/NoninvertibleTransformException.java b/awt/java/awt/geom/NoninvertibleTransformException.java
new file mode 100644
index 0000000..2b7b542
--- /dev/null
+++ b/awt/java/awt/geom/NoninvertibleTransformException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+/**
+ * The Class NoninvertibleTransformException is the exception that is thrown
+ * when an action requires inverting an {@link AffineTransform} that is
+ * not invertible (has determinant 0).
+ */
+public class NoninvertibleTransformException extends java.lang.Exception {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 6137225240503990466L;
+
+ /**
+ * Instantiates a new noninvertible transform exception.
+ *
+ * @param s the error message
+ */
+ public NoninvertibleTransformException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/awt/java/awt/geom/PathIterator.java b/awt/java/awt/geom/PathIterator.java
new file mode 100644
index 0000000..5a98083
--- /dev/null
+++ b/awt/java/awt/geom/PathIterator.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+/**
+ * The Interface PathIterator represents an iterator object that can
+ * be used to traverse the outline of a {@link java.awt.Shape}.
+ * It returns points along the boundary of the Shape
+ * which may be actual vertices (in the case of a shape made of line
+ * segments) or may be points on a curved segment with the distance
+ * between the points determined by a chosen flattening factor.
+ * <p>
+ * If the shape is closed, the outline is traversed in the counter-clockwise
+ * direction. That means that moving forward along the boundary is to travel
+ * in such a way that the interior of the shape is to the left of the
+ * outline path and the exterior of the shape is to the right of the outline
+ * path. The interior and exterior of the shape are determined by a
+ * winding rule.
+ */
+public interface PathIterator {
+
+ /** The Constant WIND_EVEN_ODD indicates the winding rule that says
+ * that a point is outside the shape if any infinite ray from the point
+ * crosses the outline of the shape an even number of times, otherwise
+ * it is inside. */
+ public static final int WIND_EVEN_ODD = 0;
+
+ /** The Constant WIND_NON_ZERO indicates the winding rule that says that
+ * a point is inside the shape if every infinite ray starting from that
+ * point crosses the outline of the shape a non-zero number of times. */
+ public static final int WIND_NON_ZERO = 1;
+
+ /** The Constant SEG_MOVETO indicates that to follow the shape's outline
+ * from the previous point to the current point, the cursor (traversal
+ * point) should be placed directly on the current point. */
+ public static final int SEG_MOVETO = 0;
+
+ /** The Constant SEG_LINETO indicates that to follow the shape's outline
+ * from the previous point to the current point, the cursor (traversal
+ * point) should follow a straight line. */
+ public static final int SEG_LINETO = 1;
+
+ /** The Constant SEG_QUADTO indicates that to follow the shape's outline
+ * from the previous point to the current point, the cursor (traversal
+ * point) should follow a quadratic curve. */
+ public static final int SEG_QUADTO = 2;
+
+ /** The Constant SEG_CUBICTO indicates that to follow the shape's outline
+ * from the previous point to the current point, the cursor (traversal
+ * point) should follow a cubic curve. */
+ public static final int SEG_CUBICTO = 3;
+
+ /** The Constant SEG_CLOSE indicates that the previous point was the end
+ * of the shape's outline. */
+ public static final int SEG_CLOSE = 4;
+
+ /**
+ * Gets the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or
+ * {@link PathIterator#WIND_NON_ZERO}.
+ *
+ * @return the winding rule
+ */
+ public int getWindingRule();
+
+ /**
+ * Checks if this PathIterator has been completely traversed.
+ *
+ * @return true, if this PathIterator has been completely traversed
+ */
+ public boolean isDone();
+
+ /**
+ * Tells this PathIterator to skip to the next segment.
+ */
+ public void next();
+
+ /**
+ * Gets the coordinates of the next vertex point along the shape's outline
+ * and a flag that indicates what kind of segment to use in order to
+ * connect the previous vertex point to the current vertex point to form
+ * the current segment.
+ *
+ * @param coords the array that the coordinates of the end point of the current
+ * segment are written into.
+ *
+ * @return the flag that indicates how to follow the shape's outline
+ * from the previous point to the current one, chosen from
+ * the following constants:
+ * {@link PathIterator#SEG_MOVETO}, {@link PathIterator#SEG_LINETO},
+ * {@link PathIterator#SEG_QUADTO}, {@link PathIterator#SEG_CUBICTO},
+ * or {@link PathIterator#SEG_CLOSE}
+ */
+ public int currentSegment(float[] coords);
+
+ /**
+ * Gets the coordinates of the next vertex point along the shape's outline
+ * and a flag that indicates what kind of segment to use in order to
+ * connect the previous vertex point to the current vertex point to form
+ * the current segment.
+ *
+ * @param coords the array that the coordinates of the end point of the current
+ * segment are written into.
+ *
+ * @return the flag that indicates how to follow the shape's outline
+ * from the previous point to the current one, chosen from
+ * the following constants:
+ * {@link PathIterator#SEG_MOVETO}, {@link PathIterator#SEG_LINETO},
+ * {@link PathIterator#SEG_QUADTO}, {@link PathIterator#SEG_CUBICTO},
+ * or {@link PathIterator#SEG_CLOSE}
+ */
+ public int currentSegment(double[] coords);
+
+}
+
diff --git a/awt/java/awt/geom/Point2D.java b/awt/java/awt/geom/Point2D.java
new file mode 100644
index 0000000..7719e67
--- /dev/null
+++ b/awt/java/awt/geom/Point2D.java
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Class Point2D represents a point whose data is given in
+ * high-precision values appropriate for graphical operations.
+ */
+public abstract class Point2D implements Cloneable {
+
+ /**
+ * The Class Float is the subclass of Point2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends Point2D {
+
+ /** The x coordinate. */
+ public float x;
+
+ /** The y coordinate. */
+ public float y;
+
+ /**
+ * Instantiates a new float-valued Point2D with its data
+ * set to zero.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued Point2D with the specified coordinates.
+ *
+ * @param x the x coordinate
+ * @param y the y coordinate
+ */
+ public Float(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ /**
+ * Sets the point's coordinates.
+ *
+ * @param x the x coordinate
+ * @param y the y coordinate
+ */
+ public void setLocation(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public void setLocation(double x, double y) {
+ this.x = (float)x;
+ this.y = (float)y;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of Point2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends Point2D {
+
+ /** The x coordinate. */
+ public double x;
+
+ /** The y coordinate. */
+ public double y;
+
+ /**
+ * Instantiates a new double-valued Point2D with its data
+ * set to zero.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued Point2D with the specified coordinates.
+ *
+ * @param x the x coordinate
+ * @param y the y coordinate
+ */
+ public Double(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public void setLocation(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + "[x=" + x + ",y=" + y + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+
+ /**
+ * Instantiates a new Point2D.
+ */
+ protected Point2D() {
+ }
+
+ /**
+ * Gets the x coordinate.
+ *
+ * @return the x coordinate
+ */
+ public abstract double getX();
+
+ /**
+ * Gets the y coordinate.
+ *
+ * @return the y coordinate
+ */
+ public abstract double getY();
+
+ /**
+ * Sets the point's coordinates.
+ *
+ * @param x the x coordinate
+ * @param y the y coordinate
+ */
+ public abstract void setLocation(double x, double y);
+
+ /**
+ * Sets the point's coordinates by copying them from another point.
+ *
+ * @param p the point to copy the data from
+ */
+ public void setLocation(Point2D p) {
+ setLocation(p.getX(), p.getY());
+ }
+
+ /**
+ * Finds the square of the distance between the two specified points.
+ *
+ * @param x1 the x coordinate of the first point
+ * @param y1 the y coordinate of the first point
+ * @param x2 the x coordinate of the second point
+ * @param y2 the y coordinate of the second point
+ *
+ * @return the square of the distance between the two specified points
+ */
+ public static double distanceSq(double x1, double y1, double x2, double y2) {
+ x2 -= x1;
+ y2 -= y1;
+ return x2 * x2 + y2 * y2;
+ }
+
+ /**
+ * Finds the square of the distance between this point and the specified point.
+ *
+ * @param px the x coordinate of the point
+ * @param py the y coordinate of the point
+ *
+ * @return the square of the distance between this point and the specified point
+ */
+ public double distanceSq(double px, double py) {
+ return Point2D.distanceSq(getX(), getY(), px, py);
+ }
+
+ /**
+ * Finds the square of the distance between this point and the specified point.
+ *
+ * @param p the other point
+ *
+ * @return the square of the distance between this point and the specified point
+ */
+ public double distanceSq(Point2D p) {
+ return Point2D.distanceSq(getX(), getY(), p.getX(), p.getY());
+ }
+
+ /**
+ * Finds the distance between the two specified points.
+ *
+ * @param x1 the x coordinate of the first point
+ * @param y1 the y coordinate of the first point
+ * @param x2 the x coordinate of the second point
+ * @param y2 the y coordinate of the second point
+ *
+ * @return the distance between the two specified points
+ */
+ public static double distance(double x1, double y1, double x2, double y2) {
+ return Math.sqrt(distanceSq(x1, y1, x2, y2));
+ }
+
+ /**
+ * Finds the distance between this point and the specified point.
+ *
+ * @param px the x coordinate of the point
+ * @param py the y coordinate of the point
+ *
+ * @return the distance between this point and the specified point
+ */
+ public double distance(double px, double py) {
+ return Math.sqrt(distanceSq(px, py));
+ }
+
+ /**
+ * Finds the distance between this point and the specified point.
+ *
+ * @param p the other point
+ *
+ * @return the distance between this point and the specified point
+ */
+ public double distance(Point2D p) {
+ return Math.sqrt(distanceSq(p));
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(getX());
+ hash.append(getY());
+ return hash.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Point2D) {
+ Point2D p = (Point2D) obj;
+ return getX() == p.getX() && getY() == p.getY();
+ }
+ return false;
+ }
+}
+
diff --git a/awt/java/awt/geom/QuadCurve2D.java b/awt/java/awt/geom/QuadCurve2D.java
new file mode 100644
index 0000000..64ea6d6
--- /dev/null
+++ b/awt/java/awt/geom/QuadCurve2D.java
@@ -0,0 +1,824 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.gl.Crossing;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class QuadCurve2D is a Shape that represents a segment of a
+ * quadratic (Bezier) curve. The curved segment is determined by three points:
+ * a start point, an end point, and a control point. The line from the control
+ * point to the starting point gives the tangent to the curve at the
+ * starting point, and the line from the control point to the end point
+ * gives the tangent to the curve at the end point.
+ */
+public abstract class QuadCurve2D implements Shape, Cloneable {
+
+ /**
+ * The Class Float is the subclass of QuadCurve2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends QuadCurve2D {
+
+ /** The x coordinate of the starting point of the curved segment. */
+ public float x1;
+
+ /** The y coordinate of the starting point of the curved segment. */
+ public float y1;
+
+ /** The x coordinate of the control point. */
+ public float ctrlx;
+
+ /** The y coordinate of the control point. */
+ public float ctrly;
+
+ /** The x coordinate of the end point of the curved segment. */
+ public float x2;
+
+ /** The y coordinate of the end point of the curved segment. */
+ public float y2;
+
+ /**
+ * Instantiates a new float-valued QuadCurve2D with all coordinate values
+ * set to zero.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued QuadCurve2D with the specified
+ * coordinate values.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ */
+ public Float(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) {
+ setCurve(x1, y1, ctrlx, ctrly, x2, y2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getCtrlX() {
+ return ctrlx;
+ }
+
+ @Override
+ public double getCtrlY() {
+ return ctrly;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Float(x1, y1);
+ }
+
+ @Override
+ public Point2D getCtrlPt() {
+ return new Point2D.Float(ctrlx, ctrly);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Float(x2, y2);
+ }
+
+ @Override
+ public void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+ this.x1 = (float)x1;
+ this.y1 = (float)y1;
+ this.ctrlx = (float)ctrlx;
+ this.ctrly = (float)ctrly;
+ this.x2 = (float)x2;
+ this.y2 = (float)y2;
+ }
+
+ /**
+ * Sets the data values of the curve.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ */
+ public void setCurve(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.ctrlx = ctrlx;
+ this.ctrly = ctrly;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ float rx0 = Math.min(Math.min(x1, x2), ctrlx);
+ float ry0 = Math.min(Math.min(y1, y2), ctrly);
+ float rx1 = Math.max(Math.max(x1, x2), ctrlx);
+ float ry1 = Math.max(Math.max(y1, y2), ctrly);
+ return new Rectangle2D.Float(rx0, ry0, rx1 - rx0, ry1 - ry0);
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of QuadCurve2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends QuadCurve2D {
+
+ /** The x coordinate of the starting point of the curved segment. */
+ public double x1;
+
+ /** The y coordinate of the starting point of the curved segment. */
+ public double y1;
+
+ /** The x coordinate of the control point. */
+ public double ctrlx;
+
+ /** The y coordinate of the control point. */
+ public double ctrly;
+
+ /** The x coordinate of the end point of the curved segment. */
+ public double x2;
+
+ /** The y coordinate of the end point of the curved segment. */
+ public double y2;
+
+ /**
+ * Instantiates a new double-valued QuadCurve2D with all coordinate values
+ * set to zero.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued QuadCurve2D with the specified
+ * coordinate values.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ */
+ public Double(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+ setCurve(x1, y1, ctrlx, ctrly, x2, y2);
+ }
+
+ @Override
+ public double getX1() {
+ return x1;
+ }
+
+ @Override
+ public double getY1() {
+ return y1;
+ }
+
+ @Override
+ public double getCtrlX() {
+ return ctrlx;
+ }
+
+ @Override
+ public double getCtrlY() {
+ return ctrly;
+ }
+
+ @Override
+ public double getX2() {
+ return x2;
+ }
+
+ @Override
+ public double getY2() {
+ return y2;
+ }
+
+ @Override
+ public Point2D getP1() {
+ return new Point2D.Double(x1, y1);
+ }
+
+ @Override
+ public Point2D getCtrlPt() {
+ return new Point2D.Double(ctrlx, ctrly);
+ }
+
+ @Override
+ public Point2D getP2() {
+ return new Point2D.Double(x2, y2);
+ }
+
+ @Override
+ public void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.ctrlx = ctrlx;
+ this.ctrly = ctrly;
+ this.x2 = x2;
+ this.y2 = y2;
+ }
+
+ public Rectangle2D getBounds2D() {
+ double rx0 = Math.min(Math.min(x1, x2), ctrlx);
+ double ry0 = Math.min(Math.min(y1, y2), ctrly);
+ double rx1 = Math.max(Math.max(x1, x2), ctrlx);
+ double ry1 = Math.max(Math.max(y1, y2), ctrly);
+ return new Rectangle2D.Double(rx0, ry0, rx1 - rx0, ry1 - ry0);
+ }
+ }
+
+ /*
+ * QuadCurve2D path iterator
+ */
+ /**
+ * The PathIterator for a Quad2D curve.
+ */
+ class Iterator implements PathIterator {
+
+ /** The source QuadCurve2D object. */
+ QuadCurve2D c;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segment index. */
+ int index;
+
+ /**
+ * Constructs a new QuadCurve2D.Iterator for given curve and transformation
+ *
+ * @param q - the source QuadCurve2D object
+ * @param t the AffineTransform that acts on the coordinates before
+ * returning them (or null)
+ */
+ Iterator(QuadCurve2D q, AffineTransform t) {
+ this.c = q;
+ this.t = t;
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return (index > 1);
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = c.getX1();
+ coords[1] = c.getY1();
+ count = 1;
+ } else {
+ type = SEG_QUADTO;
+ coords[0] = c.getCtrlX();
+ coords[1] = c.getCtrlY();
+ coords[2] = c.getX2();
+ coords[3] = c.getY2();
+ count = 2;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type;
+ int count;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = (float)c.getX1();
+ coords[1] = (float)c.getY1();
+ count = 1;
+ } else {
+ type = SEG_QUADTO;
+ coords[0] = (float)c.getCtrlX();
+ coords[1] = (float)c.getCtrlY();
+ coords[2] = (float)c.getX2();
+ coords[3] = (float)c.getY2();
+ count = 2;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new quadratic curve.
+ */
+ protected QuadCurve2D() {
+ }
+
+ /**
+ * Gets the x coordinate of the starting point.
+ *
+ * @return the x coordinate of the starting point
+ */
+ public abstract double getX1();
+
+ /**
+ * Gets the y coordinate of the starting point.
+ *
+ * @return the y coordinate of the starting point
+ */
+ public abstract double getY1();
+
+ /**
+ * Gets the starting point.
+ *
+ * @return the starting point
+ */
+ public abstract Point2D getP1();
+
+ /**
+ * Gets the x coordinate of the control point.
+ *
+ * @return the x coordinate of the control point
+ */
+ public abstract double getCtrlX();
+
+ /**
+ * Gets the y coordinate of the control point.
+ *
+ * @return y coordinate of the control point
+ */
+ public abstract double getCtrlY();
+
+ /**
+ * Gets the control point.
+ *
+ * @return the control point
+ */
+ public abstract Point2D getCtrlPt();
+
+ /**
+ * Gets the x coordinate of the end point.
+ *
+ * @return the x coordinate of the end point
+ */
+ public abstract double getX2();
+
+ /**
+ * Gets the y coordinate of the end point.
+ *
+ * @return the y coordinate of the end point
+ */
+ public abstract double getY2();
+
+ /**
+ * Gets the end point.
+ *
+ * @return the end point
+ */
+ public abstract Point2D getP2();
+
+ /**
+ * Sets the data of the curve.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ */
+ public abstract void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2);
+
+ /**
+ * Sets the data of the curve.
+ *
+ * @param p1 the starting point of the curved segment
+ * @param cp the control point
+ * @param p2 the end point of the curved segment
+ *
+ * @throws NullPointerException if any of the three points is null.
+ */
+ public void setCurve(Point2D p1, Point2D cp, Point2D p2) {
+ setCurve(p1.getX(), p1.getY(), cp.getX(), cp.getY(), p2.getX(), p2.getY());
+ }
+
+ /**
+ * Sets the data of the curve by reading the data from an array
+ * of values. The values are read in the same order as the arguments
+ * of the method {@link QuadCurve2D#setCurve(double, double, double, double, double, double)}.
+ *
+ * @param coords the array of values containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 6.
+ * @throws NullPointerException if the coordinate array is null.
+ */
+ public void setCurve(double[] coords, int offset) {
+ setCurve(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 2], coords[offset + 3],
+ coords[offset + 4], coords[offset + 5]);
+ }
+
+ /**
+ * Sets the data of the curve by reading the data from an array
+ * of points. The values are read in the same order as the arguments
+ * of the method {@link QuadCurve2D#setCurve(Point2D, Point2D, Point2D)}
+ *
+ * @param points the array of points containing the new coordinates
+ * @param offset the offset of the data to read within the array
+ *
+ * @throws ArrayIndexOutOfBoundsException if points.length < offset + 3.
+ * @throws NullPointerException if the point array is null.
+ */
+ public void setCurve(Point2D[] points, int offset) {
+ setCurve(
+ points[offset + 0].getX(), points[offset + 0].getY(),
+ points[offset + 1].getX(), points[offset + 1].getY(),
+ points[offset + 2].getX(), points[offset + 2].getY());
+ }
+
+ /**
+ * Sets the data of the curve by copying it from another QuadCurve2D.
+ *
+ * @param curve the curve to copy the data points from
+ *
+ * @throws NullPointerException if the curve is null.
+ */
+ public void setCurve(QuadCurve2D curve) {
+ setCurve(
+ curve.getX1(), curve.getY1(),
+ curve.getCtrlX(), curve.getCtrlY(),
+ curve.getX2(), curve.getY2());
+ }
+
+ /**
+ * Gets the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ * for this curve.
+ *
+ * @return the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ */
+ public double getFlatnessSq() {
+ return Line2D.ptSegDistSq(
+ getX1(), getY1(),
+ getX2(), getY2(),
+ getCtrlX(), getCtrlY());
+ }
+
+ /**
+ * Gets the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ *
+ * @return the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ */
+ public static double getFlatnessSq(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) {
+ return Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx, ctrly);
+ }
+
+ /**
+ * Gets the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ * by reading the coordinates of the points from an array of values.
+ * The values are read in the same order as the arguments
+ * of the method {@link QuadCurve2D#getFlatnessSq(double, double, double, double, double, double)}.
+ *
+ * @param coords the array of points containing the coordinates to use for
+ * the calculation
+ * @param offset the offset of the data to read within the array
+ *
+ * @return the square of the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ *
+ * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 6.
+ * @throws NullPointerException if the coordinate array is null.
+ */
+ public static double getFlatnessSq(double coords[], int offset) {
+ return Line2D.ptSegDistSq(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 4], coords[offset + 5],
+ coords[offset + 2], coords[offset + 3]);
+ }
+
+ /**
+ * Gets the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ * of this QuadCurve2D.
+ *
+ * @return the the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ * of this QuadCurve2D
+ */
+ public double getFlatness() {
+ return Line2D.ptSegDist(getX1(), getY1(), getX2(), getY2(), getCtrlX(), getCtrlY());
+ }
+
+ /**
+ * Gets the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ *
+ * @param x1 the x coordinate of the starting point of the curved segment
+ * @param y1 the y coordinate of the starting point of the curved segment
+ * @param ctrlx the x coordinate of the control point
+ * @param ctrly the y coordinate of the control point
+ * @param x2 the x coordinate of the end point of the curved segment
+ * @param y2 the y coordinate of the end point of the curved segment
+ *
+ * @return the the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ */
+ public static double getFlatness(double x1, double y1, double ctrlx,
+ double ctrly, double x2, double y2)
+ {
+ return Line2D.ptSegDist(x1, y1, x2, y2, ctrlx, ctrly);
+ }
+
+ /**
+ * Gets the the distance from the control point to the
+ * straight line segment connecting the start point and the end point.
+ * The values are read in the same order as the arguments
+ * of the method {@link QuadCurve2D#getFlatness(double, double, double, double, double, double)}.
+ *
+ * @param coords the array of points containing the coordinates to use for
+ * the calculation
+ * @param offset the offset of the data to read within the array
+ *
+ * @return the the distance from the control point to the
+ * straight line segment connecting the start point and the end point
+ *
+ * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 6.
+ * @throws NullPointerException if the coordinate array is null.
+ */
+ public static double getFlatness(double coords[], int offset) {
+ return Line2D.ptSegDist(
+ coords[offset + 0], coords[offset + 1],
+ coords[offset + 4], coords[offset + 5],
+ coords[offset + 2], coords[offset + 3]);
+ }
+
+ /**
+ * Creates the data for two quadratic curves by dividing this
+ * curve in two. The division point is the point on the curve
+ * that is closest to this curve's control point. The data of
+ * this curve is left unchanged.
+ *
+ * @param left the QuadCurve2D where the left (start) segment's
+ * data is written
+ * @param right the QuadCurve2D where the right (end) segment's
+ * data is written
+ *
+ * @throws NullPointerException if either curve is null.
+ */
+ public void subdivide(QuadCurve2D left, QuadCurve2D right) {
+ subdivide(this, left, right);
+ }
+
+ /**
+ * Creates the data for two quadratic curves by dividing a source
+ * curve in two. The division point is the point on the curve
+ * that is closest to the source curve's control point. The data of
+ * the source curve is left unchanged.
+ *
+ * @param src the curve that provides the initial data
+ * @param left the QuadCurve2D where the left (start) segment's
+ * data is written
+ * @param right the QuadCurve2D where the right (end) segment's
+ * data is written
+ *
+ * @throws NullPointerException if one of the curves is null.
+ */
+ public static void subdivide(QuadCurve2D src, QuadCurve2D left, QuadCurve2D right) {
+ double x1 = src.getX1();
+ double y1 = src.getY1();
+ double cx = src.getCtrlX();
+ double cy = src.getCtrlY();
+ double x2 = src.getX2();
+ double y2 = src.getY2();
+ double cx1 = (x1 + cx) / 2.0;
+ double cy1 = (y1 + cy) / 2.0;
+ double cx2 = (x2 + cx) / 2.0;
+ double cy2 = (y2 + cy) / 2.0;
+ cx = (cx1 + cx2) / 2.0;
+ cy = (cy1 + cy2) / 2.0;
+ if (left != null) {
+ left.setCurve(x1, y1, cx1, cy1, cx, cy);
+ }
+ if (right != null) {
+ right.setCurve(cx, cy, cx2, cy2, x2, y2);
+ }
+ }
+
+ /**
+ * Creates the data for two quadratic curves by dividing a source
+ * curve in two. The division point is the point on the curve
+ * that is closest to the source curve's control point. The data
+ * for the three curves is read and written from arrays of values in
+ * the usual order: x1, y1, cx, cy, x2, y2.
+ *
+ * @param src the array that gives the data values for the source curve
+ * @param srcoff the offset in the src array to read the values from
+ * @param left the array where the coordinates of the start curve should be written
+ * @param leftOff the offset in the left array to start writing the values
+ * @param right the array where the coordinates of the end curve should be written
+ * @param rightOff the offset in the right array to start writing the values
+ *
+ * @throws ArrayIndexOutOfBoundsException if src.length < srcoff + 6
+ * or if left.length < leftOff + 6 or if right.length < rightOff + 6.
+ * @throws NullPointerException if one of the arrays is null.
+ */
+ public static void subdivide(double src[], int srcoff, double left[],
+ int leftOff, double right[], int rightOff)
+ {
+ double x1 = src[srcoff + 0];
+ double y1 = src[srcoff + 1];
+ double cx = src[srcoff + 2];
+ double cy = src[srcoff + 3];
+ double x2 = src[srcoff + 4];
+ double y2 = src[srcoff + 5];
+ double cx1 = (x1 + cx) / 2.0;
+ double cy1 = (y1 + cy) / 2.0;
+ double cx2 = (x2 + cx) / 2.0;
+ double cy2 = (y2 + cy) / 2.0;
+ cx = (cx1 + cx2) / 2.0;
+ cy = (cy1 + cy2) / 2.0;
+ if (left != null) {
+ left[leftOff + 0] = x1;
+ left[leftOff + 1] = y1;
+ left[leftOff + 2] = cx1;
+ left[leftOff + 3] = cy1;
+ left[leftOff + 4] = cx;
+ left[leftOff + 5] = cy;
+ }
+ if (right != null) {
+ right[rightOff + 0] = cx;
+ right[rightOff + 1] = cy;
+ right[rightOff + 2] = cx2;
+ right[rightOff + 3] = cy2;
+ right[rightOff + 4] = x2;
+ right[rightOff + 5] = y2;
+ }
+ }
+
+ /**
+ * Finds the roots of the quadratic polynomial. This is
+ * accomplished by finding the (real) values of x that solve
+ * the following equation: eqn[2]*x*x + eqn[1]*x + eqn[0] = 0.
+ * The solutions are written back into the array eqn starting
+ * from the index 0 in the array. The return value tells how
+ * many array elements have been changed by this method call.
+ *
+ * @param eqn an array containing the coefficients of the
+ * quadratic polynomial to solve.
+ *
+ * @return the number of roots of the quadratic polynomial
+ *
+ * @throws ArrayIndexOutOfBoundsException if eqn.length < 3.
+ * @throws NullPointerException if the array is null.
+ */
+ public static int solveQuadratic(double eqn[]) {
+ return solveQuadratic(eqn, eqn);
+ }
+
+ /**
+ * Finds the roots of the quadratic polynomial. This is
+ * accomplished by finding the (real) values of x that solve
+ * the following equation: eqn[2]*x*x + eqn[1]*x + eqn[0] = 0.
+ * The solutions are written into the array res starting
+ * from the index 0 in the array. The return value tells how
+ * many array elements have been written by this method call.
+ *
+ * @param eqn an array containing the coefficients of the
+ * quadratic polynomial to solve.
+ * @param res the array that this method writes the results into
+ *
+ * @return the number of roots of the quadratic polynomial
+ *
+ * @throws ArrayIndexOutOfBoundsException if eqn.length < 3 or
+ * if res.length is less than the number of roots.
+ * @throws NullPointerException if either array is null.
+ */
+ public static int solveQuadratic(double eqn[], double res[]) {
+ return Crossing.solveQuad(eqn, res);
+ }
+
+ public boolean contains(double px, double py) {
+ return Crossing.isInsideEvenOdd(Crossing.crossShape(this, px, py));
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross != Crossing.CROSSING && Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross == Crossing.CROSSING || Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean contains(Point2D p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ public boolean intersects(Rectangle2D r) {
+ return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public boolean contains(Rectangle2D r) {
+ return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ public Rectangle getBounds() {
+ return getBounds2D().getBounds();
+ }
+
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new FlatteningPathIterator(getPathIterator(t), flatness);
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/geom/Rectangle2D.java b/awt/java/awt/geom/Rectangle2D.java
new file mode 100644
index 0000000..d33dd91
--- /dev/null
+++ b/awt/java/awt/geom/Rectangle2D.java
@@ -0,0 +1,761 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+
+/**
+ * The Class Rectangle2D represents a rectangle whose coordinates are given
+ * with the correct precision to be used with the Graphics2D classes.
+ */
+public abstract class Rectangle2D extends RectangularShape {
+
+ /** The Constant OUT_LEFT is a mask that is used to indicate that a
+ * given point is outside the rectangle and to its left. */
+ public static final int OUT_LEFT = 1;
+
+ /** The Constant OUT_TOP is a mask that is used to indicate that a
+ * given point is outside the rectangle and above it. */
+ public static final int OUT_TOP = 2;
+
+ /** The Constant OUT_RIGHT is a mask that is used to indicate that a
+ * given point is outside the rectangle and to its right. */
+ public static final int OUT_RIGHT = 4;
+
+ /** The Constant OUT_BOTTOM is a mask that is used to indicate that a
+ * given point is outside the rectangle and above it. */
+ public static final int OUT_BOTTOM = 8;
+
+ /**
+ * The Class Float is the subclass of Rectangle2D that represents a
+ * rectangle whose data values are given as floats (with float-level
+ * precision).
+ */
+ public static class Float extends Rectangle2D {
+
+ /** The x coordinate of the rectangle's upper left corner. */
+ public float x;
+
+ /** The y coordinate of the rectangle's upper left corner. */
+ public float y;
+
+ /** The width of the rectangle. */
+ public float width;
+
+ /** The height of the rectangle. */
+ public float height;
+
+ /**
+ * Instantiates a new empty rectangle with float-precision data fields.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new rectangle with the specified float-precision data.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ */
+ public Float(float x, float y, float width, float height) {
+ setRect(x, y, width, height);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0f || height <= 0.0f;
+ }
+
+ /**
+ * Sets the rectangle's data to the given values.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ */
+ public void setRect(float x, float y, float width, float height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public void setRect(double x, double y, double width, double height) {
+ this.x = (float)x;
+ this.y = (float)y;
+ this.width = (float)width;
+ this.height = (float)height;
+ }
+
+ @Override
+ public void setRect(Rectangle2D r) {
+ this.x = (float)r.getX();
+ this.y = (float)r.getY();
+ this.width = (float)r.getWidth();
+ this.height = (float)r.getHeight();
+ }
+
+ @Override
+ public int outcode(double px, double py) {
+ int code = 0;
+
+ if (width <= 0.0f) {
+ code |= OUT_LEFT | OUT_RIGHT;
+ } else
+ if (px < x) {
+ code |= OUT_LEFT;
+ } else
+ if (px > x + width) {
+ code |= OUT_RIGHT;
+ }
+
+ if (height <= 0.0f) {
+ code |= OUT_TOP | OUT_BOTTOM;
+ } else
+ if (py < y) {
+ code |= OUT_TOP;
+ } else
+ if (py > y + height) {
+ code |= OUT_BOTTOM;
+ }
+
+ return code;
+ }
+
+ @Override
+ public Rectangle2D getBounds2D() {
+ return new Float(x, y, width, height);
+ }
+
+ @Override
+ public Rectangle2D createIntersection(Rectangle2D r) {
+ Rectangle2D dst;
+ if (r instanceof Double) {
+ dst = new Rectangle2D.Double();
+ } else {
+ dst = new Rectangle2D.Float();
+ }
+ Rectangle2D.intersect(this, r, dst);
+ return dst;
+ }
+
+ @Override
+ public Rectangle2D createUnion(Rectangle2D r) {
+ Rectangle2D dst;
+ if (r instanceof Double) {
+ dst = new Rectangle2D.Double();
+ } else {
+ dst = new Rectangle2D.Float();
+ }
+ Rectangle2D.union(this, r, dst);
+ return dst;
+ }
+
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour. It could be obtained in the following way
+ // System.out.println(new Rectangle2D.Float().toString())
+ return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of Rectangle2D that represents a
+ * rectangle whose data values are given as doubles (with double-precision-level
+ * precision).
+ */
+ public static class Double extends Rectangle2D {
+
+ /** The x coordinate of the rectangle's upper left corner. */
+ public double x;
+
+ /** The y coordinate of the rectangle's upper left corner. */
+ public double y;
+
+ /** The width of the rectangle. */
+ public double width;
+
+ /** The height of the rectangle. */
+ public double height;
+
+ /**
+ * Instantiates a new empty rectangle with double-precision data fields.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new rectangle with the given double values.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ */
+ public Double(double x, double y, double width, double height) {
+ setRect(x, y, width, height);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0 || height <= 0.0;
+ }
+
+ @Override
+ public void setRect(double x, double y, double width, double height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public void setRect(Rectangle2D r) {
+ this.x = r.getX();
+ this.y = r.getY();
+ this.width = r.getWidth();
+ this.height = r.getHeight();
+ }
+
+ @Override
+ public int outcode(double px, double py) {
+ int code = 0;
+
+ if (width <= 0.0) {
+ code |= OUT_LEFT | OUT_RIGHT;
+ } else
+ if (px < x) {
+ code |= OUT_LEFT;
+ } else
+ if (px > x + width) {
+ code |= OUT_RIGHT;
+ }
+
+ if (height <= 0.0) {
+ code |= OUT_TOP | OUT_BOTTOM;
+ } else
+ if (py < y) {
+ code |= OUT_TOP;
+ } else
+ if (py > y + height) {
+ code |= OUT_BOTTOM;
+ }
+
+ return code;
+ }
+
+ @Override
+ public Rectangle2D getBounds2D() {
+ return new Double(x, y, width, height);
+ }
+
+ @Override
+ public Rectangle2D createIntersection(Rectangle2D r) {
+ Rectangle2D dst = new Rectangle2D.Double();
+ Rectangle2D.intersect(this, r, dst);
+ return dst;
+ }
+
+ @Override
+ public Rectangle2D createUnion(Rectangle2D r) {
+ Rectangle2D dest = new Rectangle2D.Double();
+ Rectangle2D.union(this, r, dest);
+ return dest;
+ }
+
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour. It could be obtained in the following way
+ // System.out.println(new Rectangle2D.Double().toString())
+ return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+ }
+
+ /**
+ * The Class Iterator provides
+ * access to the coordinates of the Rectangle2D's boundary modified
+ * by an AffineTransform.
+ */
+ class Iterator implements PathIterator {
+
+ /** The x coordinate of the rectangle's upper left corner. */
+ double x;
+
+ /** The y coordinate of the rectangle's upper left corner. */
+ double y;
+
+
+ /** The width of the rectangle. */
+ double width;
+
+ /** The height of the rectangle. */
+ double height;
+
+ /** The AffineTransform that is used to modify the coordinates
+ * that are returned by the path iterator. */
+ AffineTransform t;
+
+ /** The current segment index. */
+ int index;
+
+ /**
+ * Constructs a new Rectangle2D.Iterator for given rectangle and transformation.
+ *
+ * @param r - the source Rectangle2D object
+ * @param at - the AffineTransform object to apply to the coordinates
+ * before returning them
+ */
+ Iterator(Rectangle2D r, AffineTransform at) {
+ this.x = r.getX();
+ this.y = r.getY();
+ this.width = r.getWidth();
+ this.height = r.getHeight();
+ this.t = at;
+ if (width < 0.0 || height < 0.0) {
+ index = 6;
+ }
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > 5;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == 5) {
+ return SEG_CLOSE;
+ }
+ int type;
+ if (index == 0) {
+ type = SEG_MOVETO;
+ coords[0] = x;
+ coords[1] = y;
+ } else {
+ type = SEG_LINETO;
+ switch(index) {
+ case 1:
+ coords[0] = x + width;
+ coords[1] = y;
+ break;
+ case 2:
+ coords[0] = x + width;
+ coords[1] = y + height;
+ break;
+ case 3:
+ coords[0] = x;
+ coords[1] = y + height;
+ break;
+ case 4:
+ coords[0] = x;
+ coords[1] = y;
+ break;
+ }
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == 5) {
+ return SEG_CLOSE;
+ }
+ int type;
+ if (index == 0) {
+ coords[0] = (float)x;
+ coords[1] = (float)y;
+ type = SEG_MOVETO;
+ } else {
+ type = SEG_LINETO;
+ switch(index) {
+ case 1:
+ coords[0] = (float)(x + width);
+ coords[1] = (float)y;
+ break;
+ case 2:
+ coords[0] = (float)(x + width);
+ coords[1] = (float)(y + height);
+ break;
+ case 3:
+ coords[0] = (float)x;
+ coords[1] = (float)(y + height);
+ break;
+ case 4:
+ coords[0] = (float)x;
+ coords[1] = (float)y;
+ break;
+ }
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Instantiates a new rectangle2 d.
+ */
+ protected Rectangle2D() {
+ }
+
+ /**
+ * Sets the rectangle's location and dimension.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ */
+ public abstract void setRect(double x, double y, double width, double height);
+
+ /**
+ * Gets the location of the point with respect to the rectangle and
+ * packs the information into a single int using the bitmasks
+ * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT},
+ * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}.
+ * If the rectangle has zero or negative width, then every point
+ * is regarded as being both to the left and to the right of the
+ * rectangle. Similarly, if the height is zero or negative then
+ * all points are considered to be both both above and below it.
+ *
+ * @param x the x coordinate of the point to check
+ * @param y the y coordinate of the point to check
+ *
+ * @return the point's location with respect to the rectangle.
+ */
+ public abstract int outcode(double x, double y);
+
+ /**
+ * Creates an new rectangle that is the intersection of this rectangle
+ * with the given rectangle. The resulting rectangle may be empty.
+ * The data of this rectangle is left unchanged.
+ *
+ * @param r the rectangle to intersect with this rectangle.
+ *
+ * @return the new rectangle given by intersection.
+ */
+ public abstract Rectangle2D createIntersection(Rectangle2D r);
+
+ /**
+ * Creates an new rectangle that is the union of this rectangle
+ * with the given rectangle. The new rectangle is the smallest
+ * rectangle which contains both this rectangle and the rectangle
+ * specified as a parameter. The data of this rectangle is left unchanged.
+ *
+ * @param r the rectangle to combine with this rectangle
+ *
+ * @return the new rectangle given by union
+ */
+ public abstract Rectangle2D createUnion(Rectangle2D r);
+
+ /**
+ * Sets the data of this rectangle to match the data of the given
+ * rectangle.
+ *
+ * @param r the rectangle whose data is to be copied into this rectangle's fields.
+ */
+ public void setRect(Rectangle2D r) {
+ setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ @Override
+ public void setFrame(double x, double y, double width, double height) {
+ setRect(x, y, width, height);
+ }
+
+ public Rectangle2D getBounds2D() {
+ return (Rectangle2D)clone();
+ }
+
+ /**
+ * Determines whether any part of the line segment between (and including)
+ * the two given points touches any
+ * part of the rectangle, including its boundary.
+ *
+ * @param x1 the x coordinate of one of the points that determines the
+ * line segment to test
+ * @param y1 the y coordinate of one of the points that determines the
+ * line segment to test
+ * @param x2 the x coordinate of one of the points that determines the
+ * line segment to test
+ * @param y2 the y coordinate of one of the points that determines the
+ * line segment to test
+ *
+ * @return true, if at least one point of the line segment between the
+ * two points matches any point of the interior of the rectangle or the
+ * rectangle's boundary.
+ */
+ public boolean intersectsLine(double x1, double y1, double x2, double y2) {
+ double rx1 = getX();
+ double ry1 = getY();
+ double rx2 = rx1 + getWidth();
+ double ry2 = ry1 + getHeight();
+ return
+ (rx1 <= x1 && x1 <= rx2 && ry1 <= y1 && y1 <= ry2) ||
+ (rx1 <= x2 && x2 <= rx2 && ry1 <= y2 && y2 <= ry2) ||
+ Line2D.linesIntersect(rx1, ry1, rx2, ry2, x1, y1, x2, y2) ||
+ Line2D.linesIntersect(rx2, ry1, rx1, ry2, x1, y1, x2, y2);
+ }
+
+ /**
+ * Determines whether any part of the specified line segment touches any
+ * part of the rectangle, including its boundary.
+ *
+ * @param l the line segment to test
+ *
+ * @return true, if at least one point of the given line segment
+ * matches any point of the interior of the rectangle or the
+ * rectangle's boundary.
+ */
+ public boolean intersectsLine(Line2D l) {
+ return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2());
+ }
+
+ /**
+ * Gets the location of the point with respect to the rectangle and
+ * packs the information into a single int using the bitmasks
+ * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT},
+ * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}.
+ * If the rectangle has zero or negative width, then every point
+ * is regarded as being both to the left and to the right of the
+ * rectangle. Similarly, if the height is zero or negative then
+ * all points are considered to be both both above and below it.
+ *
+ * @param p the point to check
+ *
+ * @return the point's location with respect to the rectangle.
+ */
+ public int outcode(Point2D p) {
+ return outcode(p.getX(), p.getY());
+ }
+
+ public boolean contains(double x, double y) {
+ if (isEmpty()) {
+ return false;
+ }
+
+ double x1 = getX();
+ double y1 = getY();
+ double x2 = x1 + getWidth();
+ double y2 = y1 + getHeight();
+
+ return
+ x1 <= x && x < x2 &&
+ y1 <= y && y < y2;
+ }
+
+ public boolean intersects(double x, double y, double width, double height) {
+ if (isEmpty() || width <= 0.0 || height <= 0.0) {
+ return false;
+ }
+
+ double x1 = getX();
+ double y1 = getY();
+ double x2 = x1 + getWidth();
+ double y2 = y1 + getHeight();
+
+ return
+ x + width > x1 && x < x2 &&
+ y + height > y1 && y < y2;
+ }
+
+ public boolean contains(double x, double y, double width, double height) {
+ if (isEmpty() || width <= 0.0 || height <= 0.0) {
+ return false;
+ }
+
+ double x1 = getX();
+ double y1 = getY();
+ double x2 = x1 + getWidth();
+ double y2 = y1 + getHeight();
+
+ return
+ x1 <= x && x + width <= x2 &&
+ y1 <= y && y + height <= y2;
+ }
+
+ /**
+ * Changes the data values of the destination rectangle to match
+ * the intersection of the two source rectangles, leaving the
+ * two source rectangles unchanged. The resulting rectangle may be empty.
+ *
+ * @param src1 one of the two source rectangles giving the data to intersect
+ * @param src2 one of the two source rectangles giving the data to intersect
+ * @param dst the destination object where the data of the intersection is written
+ */
+ public static void intersect(Rectangle2D src1, Rectangle2D src2, Rectangle2D dst) {
+ double x1 = Math.max(src1.getMinX(), src2.getMinX());
+ double y1 = Math.max(src1.getMinY(), src2.getMinY());
+ double x2 = Math.min(src1.getMaxX(), src2.getMaxX());
+ double y2 = Math.min(src1.getMaxY(), src2.getMaxY());
+ dst.setFrame(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Changes the data values of the destination rectangle to match
+ * the union of the two source rectangles, leaving the
+ * two source rectangles unchanged. The union is the smallest rectangle
+ * tha completely covers the two source rectangles.
+ *
+ * @param src1 one of the two source rectangles giving the data
+ * @param src2 one of the two source rectangles giving the data
+ * @param dst the destination object where the data of the union is written
+ */
+ public static void union(Rectangle2D src1, Rectangle2D src2, Rectangle2D dst) {
+ double x1 = Math.min(src1.getMinX(), src2.getMinX());
+ double y1 = Math.min(src1.getMinY(), src2.getMinY());
+ double x2 = Math.max(src1.getMaxX(), src2.getMaxX());
+ double y2 = Math.max(src1.getMaxY(), src2.getMaxY());
+ dst.setFrame(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Enlarges the rectangle so that it includes the given point.
+ *
+ * @param x the x coordinate of the new point to be covered by the rectangle
+ * @param y the y coordinate of the new point to be covered by the rectangle
+ */
+ public void add(double x, double y) {
+ double x1 = Math.min(getMinX(), x);
+ double y1 = Math.min(getMinY(), y);
+ double x2 = Math.max(getMaxX(), x);
+ double y2 = Math.max(getMaxY(), y);
+ setRect(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Enlarges the rectangle so that it includes the given point.
+ *
+ * @param p the new point to be covered by the rectangle
+ */
+ public void add(Point2D p) {
+ add(p.getX(), p.getY());
+ }
+
+ /**
+ * Enlarges the rectangle so that it covers the given rectangle.
+ *
+ * @param r the new rectangle to be covered by this rectangle
+ */
+ public void add(Rectangle2D r) {
+ union(this, r, this);
+ }
+
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ @Override
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new Iterator(this, t);
+ }
+
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(getX());
+ hash.append(getY());
+ hash.append(getWidth());
+ hash.append(getHeight());
+ return hash.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Rectangle2D) {
+ Rectangle2D r = (Rectangle2D)obj;
+ return
+ getX() == r.getX() &&
+ getY() == r.getY() &&
+ getWidth() == r.getWidth() &&
+ getHeight() == r.getHeight();
+ }
+ return false;
+ }
+
+}
+
diff --git a/awt/java/awt/geom/RectangularShape.java b/awt/java/awt/geom/RectangularShape.java
new file mode 100644
index 0000000..0a77dfd
--- /dev/null
+++ b/awt/java/awt/geom/RectangularShape.java
@@ -0,0 +1,276 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+/**
+ * The Class RectangularShape represents a Shape whose data is
+ * (at least partially) described by a rectangular frame. This includes
+ * shapes which are obviously rectangular (such as Rectangle2D) as well as
+ * shapes like Arc2D which are largely determined by the rectangle they
+ * fit inside.
+ */
+public abstract class RectangularShape implements Shape, Cloneable {
+
+ /**
+ * Instantiates a new rectangular shape.
+ */
+ protected RectangularShape() {
+ }
+
+ /**
+ * Gets the x coordinate of the upper left corner of the rectangle.
+ *
+ * @return the x coordinate of the upper left corner of the rectangle.
+ */
+ public abstract double getX();
+
+ /**
+ * Gets the y coordinate of the upper left corner of the rectangle.
+ *
+ * @return the y coordinate of the upper left corner of the rectangle.
+ */
+ public abstract double getY();
+
+ /**
+ * Gets the width of the rectangle.
+ *
+ * @return the width of the rectangle.
+ */
+ public abstract double getWidth();
+
+ /**
+ * Gets the height of the rectangle.
+ *
+ * @return the height of the rectangle.
+ */
+ public abstract double getHeight();
+
+ /**
+ * Checks if this is an empty rectangle: one with zero as its width or height.
+ *
+ * @return true, if the width or height is empty.
+ */
+ public abstract boolean isEmpty();
+
+ /**
+ * Sets the data for the bounding rectangle in terms of double values.
+ *
+ * @param x the x coordinate of the upper left corner of the rectangle.
+ * @param y the y coordinate of the upper left corner of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ */
+ public abstract void setFrame(double x, double y, double w, double h);
+
+ /**
+ * Gets the minimum x value of the bounding rectangle (the x
+ * coordinate of the upper left corner of the rectangle).
+ *
+ * @return the minimum x value of the bounding rectangle.
+ */
+ public double getMinX() {
+ return getX();
+ }
+
+ /**
+ * Gets the minimum y value of the bounding rectangle (the y
+ * coordinate of the upper left corner of the rectangle).
+ *
+ * @return the minimum y value of the bounding rectangle.
+ */
+ public double getMinY() {
+ return getY();
+ }
+
+ /**
+ * Gets the maximum x value of the bounding rectangle (the x
+ * coordinate of the upper left corner of the rectangle plus the
+ * rectangle's width).
+ *
+ * @return the maximum x value of the bounding rectangle.
+ */
+ public double getMaxX() {
+ return getX() + getWidth();
+ }
+
+ /**
+ * Gets the maximum y value of the bounding rectangle (the y
+ * coordinate of the upper left corner of the rectangle plus the
+ * rectangle's height).
+ *
+ * @return the maximum y value of the bounding rectangle.
+ */
+ public double getMaxY() {
+ return getY() + getHeight();
+ }
+
+ /**
+ * Gets the x coordinate of the center of the rectangle.
+ *
+ * @return the x coordinate of the center of the rectangle.
+ */
+ public double getCenterX() {
+ return getX() + getWidth() / 2.0;
+ }
+
+ /**
+ * Gets the y coordinate of the center of the rectangle.
+ *
+ * @return the y coordinate of the center of the rectangle.
+ */
+ public double getCenterY() {
+ return getY() + getHeight() / 2.0;
+ }
+
+ /**
+ * Places the rectangle's size and location data in a new Rectangle2D
+ * object and returns it.
+ *
+ * @return the bounding rectangle as a new Rectangle2D object.
+ */
+ public Rectangle2D getFrame() {
+ return new Rectangle2D.Double(getX(), getY(), getWidth(), getHeight());
+ }
+
+ /**
+ * Sets the bounding rectangle in terms of a Point2D which gives its
+ * upper left corner and a Dimension2D object giving its width and height.
+ *
+ * @param loc the new upper left corner coordinate.
+ * @param size the new size dimensions.
+ */
+ public void setFrame(Point2D loc, Dimension2D size) {
+ setFrame(loc.getX(), loc.getY(), size.getWidth(), size.getHeight());
+ }
+
+ /**
+ * Sets the bounding rectangle to match the data contained in the
+ * specified Rectangle2D.
+ *
+ * @param r the rectangle that gives the new frame data.
+ */
+ public void setFrame(Rectangle2D r) {
+ setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ /**
+ * Sets the framing rectangle given two opposite corners. Any two corners
+ * may be used in any order as long as they are diagonally opposite one another.
+ *
+ * @param x1 the x coordinate of one of the corner points.
+ * @param y1 the y coordinate of one of the corner points.
+ * @param x2 the x coordinate of the other corner point.
+ * @param y2 the y coordinate of the other corner point.
+ */
+ public void setFrameFromDiagonal(double x1, double y1, double x2, double y2) {
+ double rx, ry, rw, rh;
+ if (x1 < x2) {
+ rx = x1;
+ rw = x2 - x1;
+ } else {
+ rx = x2;
+ rw = x1 - x2;
+ }
+ if (y1 < y2) {
+ ry = y1;
+ rh = y2 - y1;
+ } else {
+ ry = y2;
+ rh = y1 - y2;
+ }
+ setFrame(rx, ry, rw, rh);
+ }
+
+ /**
+ * Sets the framing rectangle given two opposite corners. Any two corners
+ * may be used in any order as long as they are diagonally opposite one another.
+ *
+ * @param p1 one of the corner points.
+ * @param p2 the other corner point.
+ */
+ public void setFrameFromDiagonal(Point2D p1, Point2D p2) {
+ setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY());
+ }
+
+ /**
+ * Sets the framing rectangle given the center point and one corner. Any
+ * corner may be used.
+ *
+ * @param centerX the x coordinate of the center point.
+ * @param centerY the y coordinate of the center point.
+ * @param cornerX the x coordinate of one of the corner points.
+ * @param cornerY the y coordinate of one of the corner points.
+ */
+ public void setFrameFromCenter(double centerX, double centerY, double cornerX, double cornerY) {
+ double width = Math.abs(cornerX - centerX);
+ double height = Math.abs(cornerY - centerY);
+ setFrame(centerX - width, centerY - height, width * 2.0, height * 2.0);
+ }
+
+ /**
+ * Sets the framing rectangle given the center point and one corner. Any
+ * corner may be used.
+ *
+ * @param center the center point.
+ * @param corner a corner point.
+ */
+ public void setFrameFromCenter(Point2D center, Point2D corner) {
+ setFrameFromCenter(center.getX(), center.getY(), corner.getX(), corner.getY());
+ }
+
+ public boolean contains(Point2D point) {
+ return contains(point.getX(), point.getY());
+ }
+
+ public boolean intersects(Rectangle2D rect) {
+ return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ public boolean contains(Rectangle2D rect) {
+ return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ public Rectangle getBounds() {
+ int x1 = (int)Math.floor(getMinX());
+ int y1 = (int)Math.floor(getMinY());
+ int x2 = (int)Math.ceil(getMaxX());
+ int y2 = (int)Math.ceil(getMaxY());
+ return new Rectangle(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new FlatteningPathIterator(getPathIterator(t), flatness);
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/geom/RoundRectangle2D.java b/awt/java/awt/geom/RoundRectangle2D.java
new file mode 100644
index 0000000..680a146
--- /dev/null
+++ b/awt/java/awt/geom/RoundRectangle2D.java
@@ -0,0 +1,552 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package java.awt.geom;
+
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class RoundRectangle2D describes a rectangle with rounded
+ * corners with high-precision data that is appropriate for geometric
+ * operations.
+ */
+public abstract class RoundRectangle2D extends RectangularShape {
+
+ /**
+ * The Class Float is the subclass of RoundRectangle2D that has all
+ * of its data values stored with float-level precision.
+ */
+ public static class Float extends RoundRectangle2D {
+
+ /** The x coordinate of the rectangle's upper left corner. */
+ public float x;
+
+ /** The y coordinate of the rectangle's upper left corner. */
+ public float y;
+
+ /** The width of the rectangle. */
+ public float width;
+
+ /** The height of the rectangle. */
+ public float height;
+
+ /** The arcwidth of the rounded corners. */
+ public float arcwidth;
+
+ /** The archeight of the rounded corners. */
+ public float archeight;
+
+ /**
+ * Instantiates a new float-valued RoundRectangle2D with
+ * its data-values set to zero.
+ */
+ public Float() {
+ }
+
+ /**
+ * Instantiates a new float-valued RoundRectangle2D with
+ * the specified data values
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @param arcwidth the arcwidth of the rounded corners
+ * @param archeight the archeight of the rounded corners
+ */
+ public Float(float x, float y, float width, float height, float arcwidth, float archeight) {
+ setRoundRect(x, y, width, height, arcwidth, archeight);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public double getArcWidth() {
+ return arcwidth;
+ }
+
+ @Override
+ public double getArcHeight() {
+ return archeight;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0f || height <= 0.0f;
+ }
+
+ /**
+ * Sets the data of the round rect.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @param arcwidth the arcwidth of the rounded corners
+ * @param archeight the archeight of the rounded corners
+ */
+ public void setRoundRect(float x, float y, float width, float height, float arcwidth, float archeight) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.arcwidth = arcwidth;
+ this.archeight = archeight;
+ }
+
+ @Override
+ public void setRoundRect(double x, double y, double width, double height, double arcwidth, double archeight) {
+ this.x = (float)x;
+ this.y = (float)y;
+ this.width = (float)width;
+ this.height = (float)height;
+ this.arcwidth = (float)arcwidth;
+ this.archeight = (float)archeight;
+ }
+
+ @Override
+ public void setRoundRect(RoundRectangle2D rr) {
+ this.x = (float)rr.getX();
+ this.y = (float)rr.getY();
+ this.width = (float)rr.getWidth();
+ this.height = (float)rr.getHeight();
+ this.arcwidth = (float)rr.getArcWidth();
+ this.archeight = (float)rr.getArcHeight();
+ }
+
+ public Rectangle2D getBounds2D() {
+ return new Rectangle2D.Float(x, y, width, height);
+ }
+ }
+
+ /**
+ * The Class Double is the subclass of RoundRectangle2D that has all
+ * of its data values stored with double-level precision.
+ */
+ public static class Double extends RoundRectangle2D {
+
+ /** The x coordinate of the rectangle's upper left corner. */
+ public double x;
+
+ /** The y coordinate of the rectangle's upper left corner. */
+ public double y;
+
+ /** The width of the rectangle. */
+ public double width;
+
+ /** The height of the rectangle. */
+ public double height;
+
+ /** The arcwidth of the rounded corners. */
+ public double arcwidth;
+
+ /** The archeight of the rounded corners. */
+ public double archeight;
+
+ /**
+ * Instantiates a new double-valued RoundRectangle2D with
+ * its data-values set to zero.
+ */
+ public Double() {
+ }
+
+ /**
+ * Instantiates a new double-valued RoundRectangle2D with
+ * the specified data values.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @param arcwidth the arcwidth of the rounded corners
+ * @param archeight the archeight of the rounded corners
+ */
+ public Double(double x, double y, double width, double height, double arcwidth, double archeight) {
+ setRoundRect(x, y, width, height, arcwidth, archeight);
+ }
+
+ @Override
+ public double getX() {
+ return x;
+ }
+
+ @Override
+ public double getY() {
+ return y;
+ }
+
+ @Override
+ public double getWidth() {
+ return width;
+ }
+
+ @Override
+ public double getHeight() {
+ return height;
+ }
+
+ @Override
+ public double getArcWidth() {
+ return arcwidth;
+ }
+
+ @Override
+ public double getArcHeight() {
+ return archeight;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return width <= 0.0 || height <= 0.0;
+ }
+
+ @Override
+ public void setRoundRect(double x, double y, double width, double height, double arcwidth, double archeight) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.arcwidth = arcwidth;
+ this.archeight = archeight;
+ }
+
+ @Override
+ public void setRoundRect(RoundRectangle2D rr) {
+ this.x = rr.getX();
+ this.y = rr.getY();
+ this.width = rr.getWidth();
+ this.height = rr.getHeight();
+ this.arcwidth = rr.getArcWidth();
+ this.archeight = rr.getArcHeight();
+ }
+
+ public Rectangle2D getBounds2D() {
+ return new Rectangle2D.Double(x, y, width, height);
+ }
+ }
+
+ /*
+ * RoundRectangle2D path iterator
+ */
+ /**
+ * The subclass of PathIterator to traverse a RoundRectangle2D.
+ */
+ class Iterator implements PathIterator {
+
+ /*
+ * Path for round corners generated the same way as Ellipse2D
+ */
+
+ /** The coefficient to calculate control points of Bezier curves. */
+ double u = 0.5 - 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0);
+
+ /** The points coordinates calculation table. */
+ double points[][] = {
+ { 0.0, 0.5, 0.0, 0.0 }, // MOVETO
+ { 1.0, -0.5, 0.0, 0.0 }, // LINETO
+ { 1.0, -u, 0.0, 0.0, // CUBICTO
+ 1.0, 0.0, 0.0, u,
+ 1.0, 0.0, 0.0, 0.5 },
+ { 1.0, 0.0, 1.0, -0.5 }, // LINETO
+ { 1.0, 0.0, 1.0, -u, // CUBICTO
+ 1.0, -u, 1.0, 0.0,
+ 1.0, -0.5, 1.0, 0.0 },
+ { 0.0, 0.5, 1.0, 0.0 }, // LINETO
+ { 0.0, u, 1.0, 0.0, // CUBICTO
+ 0.0, 0.0, 1.0, -u,
+ 0.0, 0.0, 1.0, -0.5 },
+ { 0.0, 0.0, 0.0, 0.5 }, // LINETO
+ { 0.0, 0.0, 0.0, u, // CUBICTO
+ 0.0, u, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0 } };
+
+ /** The segment types correspond to points array. */
+ int types[] = {
+ SEG_MOVETO,
+ SEG_LINETO,
+ SEG_CUBICTO,
+ SEG_LINETO,
+ SEG_CUBICTO,
+ SEG_LINETO,
+ SEG_CUBICTO,
+ SEG_LINETO,
+ SEG_CUBICTO};
+
+ /** The x coordinate of left-upper corner of the round rectangle bounds. */
+ double x;
+
+ /** The y coordinate of left-upper corner of the round rectangle bounds. */
+ double y;
+
+ /** The width of the round rectangle bounds. */
+ double width;
+
+ /** The height of the round rectangle bounds. */
+ double height;
+
+ /** The width of arc corners of the round rectangle. */
+ double aw;
+
+ /** The height of arc corners of the round rectangle. */
+ double ah;
+
+ /** The path iterator transformation. */
+ AffineTransform t;
+
+ /** The current segmenet index. */
+ int index;
+
+ /**
+ * Constructs a new RoundRectangle2D.Iterator for given round rectangle and transformation.
+ *
+ * @param rr - the source RoundRectangle2D object
+ * @param at - the AffineTransform object to apply rectangle path
+ */
+ Iterator(RoundRectangle2D rr, AffineTransform at) {
+ this.x = rr.getX();
+ this.y = rr.getY();
+ this.width = rr.getWidth();
+ this.height = rr.getHeight();
+ this.aw = Math.min(width, rr.getArcWidth());
+ this.ah = Math.min(height, rr.getArcHeight());
+ this.t = at;
+ if (width < 0.0 || height < 0.0 || aw < 0.0 || ah < 0.0) {
+ index = points.length;
+ }
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return index > points.length;
+ }
+
+ public void next() {
+ index++;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == points.length) {
+ return SEG_CLOSE;
+ }
+ int j = 0;
+ double p[] = points[index];
+ for (int i = 0; i < p.length; i += 4) {
+ coords[j++] = x + p[i + 0] * width + p[i + 1] * aw;
+ coords[j++] = y + p[i + 2] * height + p[i + 3] * ah;
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, j / 2);
+ }
+ return types[index];
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ if (index == points.length) {
+ return SEG_CLOSE;
+ }
+ int j = 0;
+ double p[] = points[index];
+ for (int i = 0; i < p.length; i += 4) {
+ coords[j++] = (float)(x + p[i + 0] * width + p[i + 1] * aw);
+ coords[j++] = (float)(y + p[i + 2] * height + p[i + 3] * ah);
+ }
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, j / 2);
+ }
+ return types[index];
+ }
+
+ }
+
+ /**
+ * Instantiates a new RoundRectangle2D.
+ */
+ protected RoundRectangle2D() {
+ }
+
+ /**
+ * Gets the arc width.
+ *
+ * @return the arc width
+ */
+ public abstract double getArcWidth();
+
+ /**
+ * Gets the arc height.
+ *
+ * @return the arc height
+ */
+ public abstract double getArcHeight();
+
+ /**
+ * Sets the data of the RoundRectangle2D.
+ *
+ * @param x the x coordinate of the rectangle's upper left corner
+ * @param y the y coordinate of the rectangle's upper left corner
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @param arcWidth the arcwidth of the rounded corners
+ * @param arcHeight the archeight of the rounded corners
+ */
+ public abstract void setRoundRect(double x, double y, double width, double height,
+ double arcWidth, double arcHeight);
+
+ /**
+ * Sets the data of the RoundRectangle2D by copying the values
+ * from an existing RoundRectangle2D.
+ *
+ * @param rr the round rectangle to copy the data from
+ *
+ * @throws NullPointerException if rr is null
+ */
+ public void setRoundRect(RoundRectangle2D rr) {
+ setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(), rr
+ .getArcWidth(), rr.getArcHeight());
+ }
+
+ @Override
+ public void setFrame(double x, double y, double width, double height) {
+ setRoundRect(x, y, width, height, getArcWidth(), getArcHeight());
+ }
+
+ public boolean contains(double px, double py) {
+ if (isEmpty()) {
+ return false;
+ }
+
+ double rx1 = getX();
+ double ry1 = getY();
+ double rx2 = rx1 + getWidth();
+ double ry2 = ry1 + getHeight();
+
+ if (px < rx1 || px >= rx2 || py < ry1 || py >= ry2) {
+ return false;
+ }
+
+ double aw = getArcWidth() / 2.0;
+ double ah = getArcHeight() / 2.0;
+
+ double cx, cy;
+
+ if (px < rx1 + aw) {
+ cx = rx1 + aw;
+ } else
+ if (px > rx2 - aw) {
+ cx = rx2 - aw;
+ } else {
+ return true;
+ }
+
+ if (py < ry1 + ah) {
+ cy = ry1 + ah;
+ } else
+ if (py > ry2 - ah) {
+ cy = ry2 - ah;
+ } else {
+ return true;
+ }
+
+ px = (px - cx) / aw;
+ py = (py - cy) / ah;
+ return px * px + py * py <= 1.0;
+ }
+
+ public boolean intersects(double rx, double ry, double rw, double rh) {
+ if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+ return false;
+ }
+
+ double x1 = getX();
+ double y1 = getY();
+ double x2 = x1 + getWidth();
+ double y2 = y1 + getHeight();
+
+ double rx1 = rx;
+ double ry1 = ry;
+ double rx2 = rx + rw;
+ double ry2 = ry + rh;
+
+ if (rx2 < x1 || x2 < rx1 || ry2 < y1 || y2 < ry1) {
+ return false;
+ }
+
+ double cx = (x1 + x2) / 2.0;
+ double cy = (y1 + y2) / 2.0;
+
+ double nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx);
+ double ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy);
+
+ return contains(nx, ny);
+ }
+
+ public boolean contains(double rx, double ry, double rw, double rh) {
+ if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
+ return false;
+ }
+
+ double rx1 = rx;
+ double ry1 = ry;
+ double rx2 = rx + rw;
+ double ry2 = ry + rh;
+
+ return
+ contains(rx1, ry1) &&
+ contains(rx2, ry1) &&
+ contains(rx2, ry2) &&
+ contains(rx1, ry2);
+ }
+
+ public PathIterator getPathIterator(AffineTransform at) {
+ return new Iterator(this, at);
+ }
+
+}
+
diff --git a/awt/java/awt/im/InputContext.java b/awt/java/awt/im/InputContext.java
new file mode 100644
index 0000000..3468474
--- /dev/null
+++ b/awt/java/awt/im/InputContext.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im;
+
+import java.awt.AWTEvent;
+//???AWT: import java.awt.Component;
+import java.util.Locale;
+
+import org.apache.harmony.awt.im.InputMethodContext;
+
+public class InputContext {
+ protected InputContext() {
+ }
+
+ public static InputContext getInstance() {
+ return new InputMethodContext();
+ }
+
+ public void dispatchEvent(AWTEvent event) {
+ }
+
+ public void dispose() {
+ }
+
+ public void endComposition() {
+ }
+
+ public Object getInputMethodControlObject() {
+ return null;
+ }
+
+ public Locale getLocale() {
+ return null;
+ }
+
+ public boolean isCompositionEnabled() {
+ return false;
+ }
+
+ public void reconvert() {
+ }
+
+ //???AWT
+ /*
+ public void removeNotify(Component client) {
+ }
+ */
+
+ public boolean selectInputMethod(Locale locale) {
+ return false;
+ }
+
+ public void setCharacterSubsets(Character.Subset[] subsets) {
+ }
+
+ public void setCompositionEnabled(boolean enable) {
+ }
+}
+
diff --git a/awt/java/awt/im/InputMethodHighlight.java b/awt/java/awt/im/InputMethodHighlight.java
new file mode 100644
index 0000000..53bb20b
--- /dev/null
+++ b/awt/java/awt/im/InputMethodHighlight.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt.im;
+
+import java.util.Map;
+import java.awt.font.TextAttribute;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class InputMethodHighlight {
+
+ public static final int RAW_TEXT = 0;
+
+ public static final int CONVERTED_TEXT = 1;
+
+ public static final InputMethodHighlight
+ UNSELECTED_RAW_TEXT_HIGHLIGHT = new InputMethodHighlight(false, RAW_TEXT);
+
+ public static final InputMethodHighlight
+ SELECTED_RAW_TEXT_HIGHLIGHT = new InputMethodHighlight(true, RAW_TEXT);
+
+ public static final InputMethodHighlight
+ UNSELECTED_CONVERTED_TEXT_HIGHLIGHT =
+ new InputMethodHighlight(false, CONVERTED_TEXT);
+
+ public static final InputMethodHighlight
+ SELECTED_CONVERTED_TEXT_HIGHLIGHT =
+ new InputMethodHighlight(true, CONVERTED_TEXT);
+
+ private boolean selected;
+ private int state;
+ private int variation;
+ private Map<TextAttribute,?> style;
+
+ public InputMethodHighlight(boolean selected, int state, int variation) {
+ this(selected, state, variation, null);
+ }
+
+ public InputMethodHighlight(boolean selected, int state,
+ int variation, Map<java.awt.font.TextAttribute, ?> style) {
+ if ((state != RAW_TEXT) && (state != CONVERTED_TEXT)) {
+ // awt.20B=unknown input method highlight state
+ throw new IllegalArgumentException(Messages.getString("awt.20B")); //$NON-NLS-1$
+ }
+ this.selected = selected;
+ this.state = state;
+ this.variation = variation;
+ this.style = style;
+ }
+
+ public InputMethodHighlight(boolean selected, int state) {
+ this(selected, state, 0, null);
+ }
+
+ public int getState() {
+ return state;
+ }
+
+ public Map<java.awt.font.TextAttribute, ?> getStyle() {
+ return style;
+ }
+
+ public int getVariation() {
+ return variation;
+ }
+
+ public boolean isSelected() {
+ return selected;
+ }
+}
+
diff --git a/awt/java/awt/im/InputMethodRequests.java b/awt/java/awt/im/InputMethodRequests.java
new file mode 100644
index 0000000..bdd25e6
--- /dev/null
+++ b/awt/java/awt/im/InputMethodRequests.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im;
+
+import java.awt.Rectangle;
+import java.awt.font.TextHitInfo;
+import java.text.AttributedCharacterIterator;
+
+public interface InputMethodRequests {
+
+ public AttributedCharacterIterator cancelLatestCommittedText(AttributedCharacterIterator.Attribute[] attributes);
+
+ public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex, AttributedCharacterIterator.Attribute[] attributes);
+
+ public int getCommittedTextLength();
+
+ public int getInsertPositionOffset();
+
+ public TextHitInfo getLocationOffset(int x, int y);
+
+ public AttributedCharacterIterator getSelectedText(AttributedCharacterIterator.Attribute[] attributes);
+
+ public Rectangle getTextLocation(TextHitInfo offset);
+}
+
diff --git a/awt/java/awt/im/InputSubset.java b/awt/java/awt/im/InputSubset.java
new file mode 100644
index 0000000..02a1049
--- /dev/null
+++ b/awt/java/awt/im/InputSubset.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package java.awt.im;
+
+public final class InputSubset extends Character.Subset {
+
+ public static final InputSubset LATIN = new InputSubset("LATIN"); //$NON-NLS-1$
+
+ public static final InputSubset
+ LATIN_DIGITS = new InputSubset("LATIN_DIGITS"); //$NON-NLS-1$
+
+ public static final InputSubset
+ TRADITIONAL_HANZI = new InputSubset("TRADITIONAL_HANZI"); //$NON-NLS-1$
+
+ public static final InputSubset
+ SIMPLIFIED_HANZI = new InputSubset("SIMPLIFIED_HANZI"); //$NON-NLS-1$
+
+ public static final InputSubset KANJI = new InputSubset("KANJI"); //$NON-NLS-1$
+
+ public static final InputSubset HANJA = new InputSubset("HANJA"); //$NON-NLS-1$
+
+ public static final InputSubset
+ HALFWIDTH_KATAKANA = new InputSubset("HALFWIDTH_KATAKANA"); //$NON-NLS-1$
+
+ public static final InputSubset
+ FULLWIDTH_LATIN = new InputSubset("FULLWIDTH_LATIN"); //$NON-NLS-1$
+
+ public static final InputSubset
+ FULLWIDTH_DIGITS = new InputSubset("FULLWIDTH_DIGITS"); //$NON-NLS-1$
+
+ private InputSubset(String name) {
+ super(name);
+ }
+}
+
diff --git a/awt/java/awt/im/spi/InputMethod.java b/awt/java/awt/im/spi/InputMethod.java
new file mode 100644
index 0000000..2c98c46
--- /dev/null
+++ b/awt/java/awt/im/spi/InputMethod.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im.spi;
+
+import java.awt.AWTEvent;
+import java.awt.Rectangle;
+import java.util.Locale;
+
+public interface InputMethod {
+
+ public void activate();
+
+ public void deactivate(boolean isTemporary);
+
+ public void dispatchEvent(AWTEvent event);
+
+ public void dispose();
+
+ public void endComposition();
+
+ public Object getControlObject();
+
+ public Locale getLocale();
+
+ public void hideWindows();
+
+ public boolean isCompositionEnabled();
+
+ public void notifyClientWindowChange(Rectangle bounds);
+
+ public void reconvert();
+
+ public void removeNotify();
+
+ public void setCharacterSubsets(Character.Subset[] subsets);
+
+ public void setCompositionEnabled(boolean enable);
+
+ public void setInputMethodContext(InputMethodContext context);
+
+ public boolean setLocale(Locale locale);
+}
+
diff --git a/awt/java/awt/im/spi/InputMethodContext.java b/awt/java/awt/im/spi/InputMethodContext.java
new file mode 100644
index 0000000..ca33e87
--- /dev/null
+++ b/awt/java/awt/im/spi/InputMethodContext.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im.spi;
+
+//???AWT: import java.awt.Window;
+import java.awt.font.TextHitInfo;
+import java.awt.im.InputMethodRequests;
+import java.text.AttributedCharacterIterator;
+//???AWT: import javax.swing.JFrame;
+
+public interface InputMethodContext extends InputMethodRequests {
+
+// ???AWT: public JFrame createInputMethodJFrame(String title, boolean attachToInputContext);
+
+// ???AWT: public Window createInputMethodWindow(String title, boolean attachToInputContext);
+
+ public void dispatchInputMethodEvent(int id, AttributedCharacterIterator text, int committedCharacterCount, TextHitInfo caret, TextHitInfo visiblePosition);
+
+ public void enableClientWindowNotification(InputMethod inputMethod, boolean enable);
+
+}
+
diff --git a/awt/java/awt/im/spi/InputMethodDescriptor.java b/awt/java/awt/im/spi/InputMethodDescriptor.java
new file mode 100644
index 0000000..3068cac
--- /dev/null
+++ b/awt/java/awt/im/spi/InputMethodDescriptor.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.im.spi;
+
+import java.awt.AWTException;
+import java.awt.Image;
+import java.util.Locale;
+
+public interface InputMethodDescriptor {
+
+ public Locale[] getAvailableLocales() throws AWTException;
+
+ public InputMethod createInputMethod() throws Exception;
+
+ public String getInputMethodDisplayName(Locale inputLocale, Locale displayLanguage);
+
+ public Image getInputMethodIcon(Locale inputLocale);
+
+ public boolean hasDynamicLocaleList();
+
+}
+
diff --git a/awt/java/awt/image/AffineTransformOp.java b/awt/java/awt/image/AffineTransformOp.java
new file mode 100644
index 0000000..546837a
--- /dev/null
+++ b/awt/java/awt/image/AffineTransformOp.java
@@ -0,0 +1,617 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky, Denis M. Kishenko
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.*;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The AffineTransform class translates coordinates from 2D coordinates
+ * in the source image or Raster to 2D coordinates in the destination
+ * image or Raster using Affine transformation. The number of bands in
+ * the source Raster should equal to the number of bands in the destination
+ * Raster.
+ */
+public class AffineTransformOp implements BufferedImageOp, RasterOp {
+
+ /**
+ * The Constant TYPE_NEAREST_NEIGHBOR indicates nearest-neighbor
+ * interpolation type.
+ */
+ public static final int TYPE_NEAREST_NEIGHBOR = 1;
+
+ /**
+ * The Constant TYPE_BILINEAR indicates bilinear interpolation type.
+ */
+ public static final int TYPE_BILINEAR = 2;
+
+ /** The Constant TYPE_BICUBIC indicates bicubic interpolation type. */
+ public static final int TYPE_BICUBIC = 3;
+
+ /** The i type. */
+ private int iType; // interpolation type
+
+ /** The at. */
+ private AffineTransform at;
+
+ /** The hints. */
+ private RenderingHints hints;
+
+ static {
+ // TODO - uncomment
+ //System.loadLibrary("imageops");
+ }
+
+ /**
+ * Instantiates a new AffineTransformOp with the specified
+ * AffineTransform and RenderingHints object which defines
+ * the interpolation type.
+ *
+ * @param xform the AffineTransform.
+ * @param hints the RenderingHints object which defines
+ * the interpolation type.
+ */
+ public AffineTransformOp(AffineTransform xform, RenderingHints hints) {
+ this(xform, TYPE_NEAREST_NEIGHBOR);
+ this.hints = hints;
+
+ if (hints != null) {
+ Object hint = hints.get(RenderingHints.KEY_INTERPOLATION);
+ if (hint != null) {
+ // Nearest neighbor is default
+ if (hint == RenderingHints.VALUE_INTERPOLATION_BILINEAR) {
+ this.iType = TYPE_BILINEAR;
+ } else if (hint == RenderingHints.VALUE_INTERPOLATION_BICUBIC) {
+ this.iType = TYPE_BICUBIC;
+ }
+ } else {
+ hint = hints.get(RenderingHints.KEY_RENDERING);
+ // Determine from rendering quality
+ if (hint == RenderingHints.VALUE_RENDER_QUALITY) {
+ this.iType = TYPE_BILINEAR;
+ // For speed use nearest neighbor
+ }
+ }
+ }
+ }
+
+ /**
+ * Instantiates a new AffineTransformOp with the specified
+ * AffineTransform and a specified interpolation type from the
+ * list of predefined interpolation types.
+ *
+ * @param xform the AffineTransform.
+ * @param interp the one of predefined interpolation types:
+ * TYPE_NEAREST_NEIGHBOR, TYPE_BILINEAR, or TYPE_BICUBIC.
+ */
+ public AffineTransformOp(AffineTransform xform, int interp) {
+ if (Math.abs(xform.getDeterminant()) <= Double.MIN_VALUE) {
+ // awt.24F=Unable to invert transform {0}
+ throw new ImagingOpException(Messages.getString("awt.24F", xform)); //$NON-NLS-1$
+ }
+
+ this.at = (AffineTransform) xform.clone();
+
+ if (interp != TYPE_NEAREST_NEIGHBOR && interp != TYPE_BILINEAR && interp != TYPE_BICUBIC) {
+ // awt.250=Unknown interpolation type: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.250", interp)); //$NON-NLS-1$
+ }
+
+ this.iType = interp;
+ }
+
+ /**
+ * Gets the interpolation type.
+ *
+ * @return the interpolation type
+ */
+ public final int getInterpolationType() {
+ return iType;
+ }
+
+ public final RenderingHints getRenderingHints() {
+ if (hints == null) {
+ Object value = null;
+
+ switch (iType) {
+ case TYPE_NEAREST_NEIGHBOR:
+ value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+ break;
+ case TYPE_BILINEAR:
+ value = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
+ break;
+ case TYPE_BICUBIC:
+ value = RenderingHints.VALUE_INTERPOLATION_BICUBIC;
+ break;
+ default:
+ value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+ }
+
+ hints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, value);
+ }
+
+ return hints;
+ }
+
+ /**
+ * Gets the affine transform associated with this AffineTransformOp.
+ *
+ * @return the AffineTransform.
+ */
+ public final AffineTransform getTransform() {
+ return (AffineTransform) at.clone();
+ }
+
+ public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+ return at.transform(srcPt, dstPt);
+ }
+
+ public final Rectangle2D getBounds2D(BufferedImage src) {
+ return getBounds2D(src.getRaster());
+ }
+
+ public final Rectangle2D getBounds2D(Raster src) {
+ // We position source raster to (0,0) even if it is translated child raster.
+ // This means that we need only width and height of the src
+ int width = src.getWidth();
+ int height = src.getHeight();
+
+ float[] corners = {
+ 0, 0,
+ width, 0,
+ width, height,
+ 0, height
+ };
+
+ at.transform(corners, 0, corners, 0, 4);
+
+ Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0);
+ bounds.add(corners[2], corners[3]);
+ bounds.add(corners[4], corners[5]);
+ bounds.add(corners[6], corners[7]);
+
+ return bounds;
+ }
+
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
+ Rectangle2D newBounds = getBounds2D(src);
+
+ // Destination image should include (0,0) + positive part
+ // of the area bounded by newBounds (in source coordinate system).
+ double dstWidth = newBounds.getX() + newBounds.getWidth();
+ double dstHeight = newBounds.getY() + newBounds.getHeight();
+
+ if (dstWidth <= 0 || dstHeight <= 0) {
+ // awt.251=Transformed width ({0}) and height ({1}) should be greater than 0
+ throw new RasterFormatException(
+ Messages.getString("awt.251", dstWidth, dstHeight)); //$NON-NLS-1$
+ }
+
+ if (destCM != null) {
+ return new BufferedImage(destCM,
+ destCM.createCompatibleWritableRaster((int)dstWidth, (int)dstHeight),
+ destCM.isAlphaPremultiplied(),
+ null
+ );
+ }
+
+ ColorModel cm = src.getColorModel();
+
+ // Interpolation other than NN doesn't make any sense for index color
+ if (iType != TYPE_NEAREST_NEIGHBOR && cm instanceof IndexColorModel) {
+ return new BufferedImage((int)dstWidth, (int)dstHeight, BufferedImage.TYPE_INT_ARGB);
+ }
+
+ // OK, we can get source color model
+ return new BufferedImage(cm,
+ src.getRaster().createCompatibleWritableRaster((int)dstWidth, (int)dstHeight),
+ cm.isAlphaPremultiplied(),
+ null
+ );
+ }
+
+ public WritableRaster createCompatibleDestRaster (Raster src) {
+ // Here approach is other then in createCompatibleDestImage -
+ // destination should include only
+ // transformed image, but not (0,0) in source coordinate system
+
+ Rectangle2D newBounds = getBounds2D(src);
+ return src.createCompatibleWritableRaster(
+ (int) newBounds.getX(), (int) newBounds.getY(),
+ (int) newBounds.getWidth(), (int)newBounds.getHeight()
+ );
+ }
+
+ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ if (src == dst) {
+ // awt.252=Source can't be same as the destination
+ throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$
+ }
+
+ ColorModel srcCM = src.getColorModel();
+ BufferedImage finalDst = null;
+
+ if (
+ srcCM instanceof IndexColorModel &&
+ (iType != TYPE_NEAREST_NEIGHBOR || srcCM.getPixelSize() % 8 != 0)
+ ) {
+ src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true);
+ srcCM = src.getColorModel();
+ }
+
+ if (dst == null) {
+ dst = createCompatibleDestImage(src, srcCM);
+ } else {
+ if (!srcCM.equals(dst.getColorModel())) {
+ // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same
+ if (
+ !(
+ (src.getType() == BufferedImage.TYPE_INT_RGB ||
+ src.getType() == BufferedImage.TYPE_INT_ARGB) &&
+ (dst.getType() == BufferedImage.TYPE_INT_RGB ||
+ dst.getType() == BufferedImage.TYPE_INT_ARGB)
+ )
+ ) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, srcCM);
+ }
+ }
+ }
+
+ // Skip alpha channel for TYPE_INT_RGB images
+ if (slowFilter(src.getRaster(), dst.getRaster()) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ // TODO - uncomment
+ //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0)
+ //throw new ImagingOpException ("Unable to transform source");
+ }
+
+ if (finalDst != null) {
+ Graphics2D g = finalDst.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.drawImage(dst, 0, 0, null);
+ } else {
+ finalDst = dst;
+ }
+
+ return finalDst;
+ }
+
+ public final WritableRaster filter(Raster src, WritableRaster dst) {
+ if (src == dst) {
+ // awt.252=Source can't be same as the destination
+ throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$
+ }
+
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else if (src.getNumBands() != dst.getNumBands()) {
+ // awt.253=Different number of bands in source and destination
+ throw new IllegalArgumentException(Messages.getString("awt.253")); //$NON-NLS-1$
+ }
+
+ if (slowFilter(src, dst) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
+ // TODO - uncomment
+ //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0)
+ // throw new ImagingOpException("Unable to transform source");
+ }
+
+ return dst;
+ }
+
+ // TODO remove when method is used
+ /**
+ * Ipp filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param imageType the image type
+ *
+ * @return the int
+ */
+ @SuppressWarnings("unused")
+ private int ippFilter(Raster src, WritableRaster dst, int imageType) {
+ int srcStride, dstStride;
+ boolean skipChannel = false;
+ int channels;
+ int offsets[] = null;
+
+ switch (imageType) {
+ case BufferedImage.TYPE_INT_RGB:
+ case BufferedImage.TYPE_INT_BGR: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ skipChannel = true;
+ break;
+ }
+
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_GRAY:
+ case BufferedImage.TYPE_BYTE_INDEXED: {
+ channels = 1;
+ srcStride = src.getWidth();
+ dstStride = dst.getWidth();
+ break;
+ }
+
+ case BufferedImage.TYPE_3BYTE_BGR: {
+ channels = 3;
+ srcStride = src.getWidth()*3;
+ dstStride = dst.getWidth()*3;
+ break;
+ }
+
+ case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in native code?
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ case BufferedImage.TYPE_BYTE_BINARY: {
+ return slowFilter(src, dst);
+ }
+
+ default: {
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+
+ if (
+ srcSM instanceof PixelInterleavedSampleModel &&
+ dstSM instanceof PixelInterleavedSampleModel
+ ) {
+ // Check PixelInterleavedSampleModel
+ if (
+ srcSM.getDataType() != DataBuffer.TYPE_BYTE ||
+ dstSM.getDataType() != DataBuffer.TYPE_BYTE
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels
+ if (channels != 1 && channels != 3 && channels != 4) {
+ return slowFilter(src, dst);
+ }
+
+ int dataTypeSize = DataBuffer.getDataTypeSize(srcSM.getDataType()) / 8;
+
+ srcStride = ((ComponentSampleModel) srcSM).getScanlineStride() * dataTypeSize;
+ dstStride = ((ComponentSampleModel) dstSM).getScanlineStride() * dataTypeSize;
+ } else if (
+ srcSM instanceof SinglePixelPackedSampleModel &&
+ dstSM instanceof SinglePixelPackedSampleModel
+ ) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM;
+ SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM;
+
+ // No IPP function for this type
+ if (sppsm1.getDataType() == DataBuffer.TYPE_USHORT) {
+ return slowFilter(src, dst);
+ }
+
+ channels = sppsm1.getNumBands();
+ // Have IPP functions for 1, 3 and 4 channels
+ if (channels != 1 && channels != 3 && channels != 4) {
+ return slowFilter(src, dst);
+ }
+
+ // Check compatibility of sample models
+ if (
+ sppsm1.getDataType() != sppsm2.getDataType() ||
+ !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) ||
+ !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ for (int i=0; i<channels; i++) {
+ if (sppsm1.getSampleSize(i) != 8) {
+ return slowFilter(src, dst);
+ }
+ }
+
+ if (channels == 3) {
+ channels = 4;
+ }
+
+ int dataTypeSize = DataBuffer.getDataTypeSize(sppsm1.getDataType()) / 8;
+
+ srcStride = sppsm1.getScanlineStride() * dataTypeSize;
+ dstStride = sppsm2.getScanlineStride() * dataTypeSize;
+ } else {
+ return slowFilter(src, dst);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (
+ src.getSampleModelTranslateX() != 0 ||
+ src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 ||
+ dst.getSampleModelTranslateY() != 0
+ ) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+ }
+ }
+
+ double m00 = at.getScaleX();
+ double m01 = at.getShearX();
+ double m02 = at.getTranslateX();
+ double m10 = at.getShearY();
+ double m11 = at.getScaleY();
+ double m12 = at.getTranslateY();
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ return ippAffineTransform(
+ m00, m01, m02, m10, m11, m12,
+ srcData, src.getWidth(), src.getHeight(), srcStride,
+ dstData, dst.getWidth(), dst.getHeight(), dstStride,
+ iType, channels, skipChannel, offsets);
+ }
+
+ /**
+ * Slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the int
+ */
+ private int slowFilter(Raster src, WritableRaster dst) {
+ // TODO: make correct interpolation
+ // TODO: what if there are different data types?
+
+ Rectangle srcBounds = src.getBounds();
+ Rectangle dstBounds = dst.getBounds();
+ Rectangle normDstBounds = new Rectangle(0, 0, dstBounds.width, dstBounds.height);
+ Rectangle bounds = getBounds2D(src).getBounds().intersection(normDstBounds);
+
+ AffineTransform inv = null;
+ try {
+ inv = at.createInverse();
+ } catch (NoninvertibleTransformException e) {
+ return -1;
+ }
+
+ double[] m = new double[6];
+ inv.getMatrix(m);
+
+ int minSrcX = srcBounds.x;
+ int minSrcY = srcBounds.y;
+ int maxSrcX = srcBounds.x + srcBounds.width;
+ int maxSrcY = srcBounds.y + srcBounds.height;
+
+ int minX = bounds.x + dstBounds.x;
+ int minY = bounds.y + dstBounds.y;
+ int maxX = minX + bounds.width;
+ int maxY = minY + bounds.height;
+
+ int hx = (int)(m[0] * 256);
+ int hy = (int)(m[1] * 256);
+ int vx = (int)(m[2] * 256);
+ int vy = (int)(m[3] * 256);
+ int sx = (int)(m[4] * 256) + hx * bounds.x + vx * bounds.y + (srcBounds.x) * 256;
+ int sy = (int)(m[5] * 256) + hy * bounds.x + vy * bounds.y + (srcBounds.y) * 256;
+
+ vx -= hx * bounds.width;
+ vy -= hy * bounds.width;
+
+ if (src.getTransferType() == dst.getTransferType()) {
+ for (int y = minY; y < maxY; y++) {
+ for (int x = minX; x < maxX; x++) {
+ int px = sx >> 8;
+ int py = sy >> 8;
+ if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) {
+ Object val = src.getDataElements(px , py , null);
+ dst.setDataElements(x, y, val);
+ }
+ sx += hx;
+ sy += hy;
+ }
+ sx += vx;
+ sy += vy;
+ }
+ } else {
+ float pixel[] = null;
+ for (int y = minY; y < maxY; y++) {
+ for (int x = minX; x < maxX; x++) {
+ int px = sx >> 8;
+ int py = sy >> 8;
+ if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) {
+ pixel = src.getPixel(px, py, pixel);
+ dst.setPixel(x, y, pixel);
+ }
+ sx += hx;
+ sy += hy;
+ }
+ sx += vx;
+ sy += vy;
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * Ipp affine transform.
+ *
+ * @param m00 the m00
+ * @param m01 the m01
+ * @param m02 the m02
+ * @param m10 the m10
+ * @param m11 the m11
+ * @param m12 the m12
+ * @param src the src
+ * @param srcWidth the src width
+ * @param srcHeight the src height
+ * @param srcStride the src stride
+ * @param dst the dst
+ * @param dstWidth the dst width
+ * @param dstHeight the dst height
+ * @param dstStride the dst stride
+ * @param iType the i type
+ * @param channels the channels
+ * @param skipChannel the skip channel
+ * @param offsets the offsets
+ *
+ * @return the int
+ */
+ private native int ippAffineTransform(
+ double m00, double m01,
+ double m02, double m10,
+ double m11, double m12,
+ Object src, int srcWidth, int srcHeight, int srcStride,
+ Object dst, int dstWidth, int dstHeight, int dstStride,
+ int iType, int channels, boolean skipChannel,
+ int offsets[]);
+} \ No newline at end of file
diff --git a/awt/java/awt/image/AreaAveragingScaleFilter.java b/awt/java/awt/image/AreaAveragingScaleFilter.java
new file mode 100644
index 0000000..f4933db
--- /dev/null
+++ b/awt/java/awt/image/AreaAveragingScaleFilter.java
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Arrays;
+
+
+/**
+ * The AreaAveragingScaleFilter class scales the source image using
+ * area averaging algorithm. This algorithm provides a source image
+ * with a new image containing the resampled image.
+ */
+public class AreaAveragingScaleFilter extends ReplicateScaleFilter {
+
+ /** The Constant rgbCM. */
+ private static final ColorModel rgbCM = ColorModel.getRGBdefault();
+
+ /** The Constant averagingFlags. */
+ private static final int averagingFlags = (ImageConsumer.TOPDOWNLEFTRIGHT |
+ ImageConsumer.COMPLETESCANLINES);
+
+ /** The reset. */
+ private boolean reset = true; // Flag for used superclass filter
+
+ /** The inited. */
+ private boolean inited = false; // All data inited
+
+ /** The sum_r. */
+ private int sum_r[]; // Array for average Red samples
+
+ /** The sum_g. */
+ private int sum_g[]; // Array for average Green samples
+
+ /** The sum_b. */
+ private int sum_b[]; // Array for average Blue samples
+
+ /** The sum_a. */
+ private int sum_a[]; // Array for average Alpha samples
+
+ /** The buff. */
+ private int buff[]; // Stride buffer
+
+ /** The avg factor. */
+ private int avgFactor; // Global averaging factor
+
+ /** The cached dy. */
+ private int cachedDY; // Cached number of the destination scanline
+
+ /** The cached dv rest. */
+ private int cachedDVRest; // Cached value of rest src scanlines for sum
+ // pixel samples
+ // Because data if transfering by whole scanlines
+ // we are caching only Y coordinate values
+
+ /**
+ * Instantiates a new AreaAveragingScaleFilter object which scales
+ * a source image with the specified width and height.
+ *
+ * @param width the scaled width of the image.
+ * @param height the scaled height of the image.
+ */
+ public AreaAveragingScaleFilter(int width, int height) {
+ super(width, height);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) {
+ if(reset) {
+ super.setPixels(x, y, w, h, model, pixels, off, scansize);
+ } else {
+ setFilteredPixels(x, y, w, h, model, pixels, off, scansize);
+ }
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) {
+ if(reset) {
+ super.setPixels(x, y, w, h, model, pixels, off, scansize);
+ } else {
+ setFilteredPixels(x, y, w, h, model, pixels, off, scansize);
+ }
+ }
+
+ @Override
+ public void setHints(int hints) {
+ super.setHints(hints);
+ reset = ((hints & averagingFlags) != averagingFlags);
+ }
+
+ /**
+ * This method implements the Area Averaging Scale filter.
+ * The description of algorithm is presented in Java API Specification.
+ *
+ * Arrays sum_r, sum_g, sum_b, sum_a have length equals width of destination
+ * image. In each array's element is accumulating pixel's component values,
+ * proportional to the area which source pixels will occupy in destination
+ * image. Then that values will divide by Global averaging
+ * factor (area of the destination image) for receiving
+ * average values of destination pixels.
+ *
+ * @param x - Src pixels X coordinate
+ * @param y - Src pixels Y coordinate
+ * @param w - width of the area of Src pixels
+ * @param h - height of the area of Src pixels
+ * @param model - Color Model of Src pixels
+ * @param pixels - array of Src pixels
+ * @param off - offset into the Src pixels array
+ * @param scansize - length of scanline in the pixels array
+ */
+ private void setFilteredPixels(int x, int y, int w, int h, ColorModel model, Object pixels, int off, int scansize){
+ if(!inited){
+ initialize();
+ }
+
+ int srcX, srcY, dx, dy;
+ int svRest, dvRest, shRest, dhRest, vDif, hDif;
+
+ if(y == 0){
+ dy = 0;
+ dvRest = srcHeight;
+ }else{
+ dy = cachedDY;
+ dvRest = cachedDVRest;
+ }
+
+ srcY = y;
+ svRest = destHeight;
+
+ int srcOff = off;
+ while (srcY < y + h) {
+ if (svRest < dvRest) {
+ vDif = svRest;
+ } else {
+ vDif = dvRest;
+ }
+
+ srcX = 0;
+ dx = 0;
+ shRest = destWidth;
+ dhRest = srcWidth;
+ while (srcX < w) {
+ if (shRest < dhRest) {
+ hDif = shRest;
+ } else {
+ hDif = dhRest;
+ }
+ int avg = hDif * vDif; // calculation of contribution factor
+
+ int rgb, pix;
+ if (pixels instanceof int[]) {
+ pix = ((int[]) pixels)[srcOff + srcX];
+ } else {
+ pix = ((byte[]) pixels)[srcOff + srcX] & 0xff;
+ }
+
+ rgb = model.getRGB(pix);
+ int a = rgb >>> 24;
+ int r = (rgb >> 16) & 0xff;
+ int g = (rgb >> 8) & 0xff;
+ int b = rgb & 0xff;
+
+ // accumulating pixel's component values
+ sum_a[dx] += a * avg;
+ sum_r[dx] += r * avg;
+ sum_g[dx] += g * avg;
+ sum_b[dx] += b * avg;
+
+ shRest -= hDif;
+ dhRest -= hDif;
+
+ if (shRest == 0) {
+ srcX++;
+ shRest = destWidth;
+ }
+
+ if (dhRest == 0) {
+ dx++;
+ dhRest = srcWidth;
+ }
+ }
+
+ svRest -= vDif;
+ dvRest -= vDif;
+
+ if (svRest == 0) {
+ svRest = destHeight;
+ srcY++;
+ srcOff += scansize;
+ }
+
+ if (dvRest == 0) {
+ // averaging destination pixel's values
+ for(int i = 0; i < destWidth; i++){
+ int a = (sum_a[i] / avgFactor) & 0xff;
+ int r = (sum_r[i] / avgFactor) & 0xff;
+ int g = (sum_g[i] / avgFactor) & 0xff;
+ int b = (sum_b[i] / avgFactor) & 0xff;
+ int frgb = (a << 24) | (r << 16) | (g << 8) | b;
+ buff[i] = frgb;
+ }
+ consumer.setPixels(0, dy, destWidth, 1, rgbCM, buff, 0,
+ destWidth);
+ dy++;
+ dvRest = srcHeight;
+ Arrays.fill(sum_a, 0);
+ Arrays.fill(sum_r, 0);
+ Arrays.fill(sum_g, 0);
+ Arrays.fill(sum_b, 0);
+ }
+
+ }
+
+ cachedDY = dy;
+ cachedDVRest = dvRest;
+
+ }
+
+ /**
+ * Initialization of the auxiliary data.
+ */
+ private void initialize(){
+
+ sum_a = new int[destWidth];
+ sum_r = new int[destWidth];
+ sum_g = new int[destWidth];
+ sum_b = new int[destWidth];
+
+ buff = new int[destWidth];
+ outpixbuf = buff;
+ avgFactor = srcWidth * srcHeight;
+
+ inited = true;
+ }
+}
+
diff --git a/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java
new file mode 100644
index 0000000..ce85ddd
--- /dev/null
+++ b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 23.11.2005
+ *
+ */
+package java.awt.image;
+
+import java.awt.Image;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferDouble;
+import java.awt.image.DataBufferFloat;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DataBufferShort;
+import java.awt.image.DataBufferUShort;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.gl.GLVolatileImage;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class not part of public API. It useful for receiving package private
+ * data from other packages.
+ */
+class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor {
+
+ static void init(){
+ inst = new AwtImageBackdoorAccessorImpl();
+ }
+
+ @Override
+ public Surface getImageSurface(Image image) {
+ if (image instanceof BufferedImage){
+ return ((BufferedImage)image).getImageSurface();
+ } else if (image instanceof GLVolatileImage){
+ return ((GLVolatileImage)image).getImageSurface();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isGrayPallete(IndexColorModel icm){
+ return icm.isGrayPallete();
+ }
+
+ @Override
+ public Object getData(DataBuffer db) {
+ if (db instanceof DataBufferByte){
+ return ((DataBufferByte)db).getData();
+ } else if (db instanceof DataBufferUShort){
+ return ((DataBufferUShort)db).getData();
+ } else if (db instanceof DataBufferShort){
+ return ((DataBufferShort)db).getData();
+ } else if (db instanceof DataBufferInt){
+ return ((DataBufferInt)db).getData();
+ } else if (db instanceof DataBufferFloat){
+ return ((DataBufferFloat)db).getData();
+ } else if (db instanceof DataBufferDouble){
+ return ((DataBufferDouble)db).getData();
+ } else {
+ // awt.235=Wrong Data Buffer type : {0}
+ throw new IllegalArgumentException(Messages.getString("awt.235", //$NON-NLS-1$
+ db.getClass()));
+ }
+ }
+
+ @Override
+ public int[] getDataInt(DataBuffer db) {
+ if (db instanceof DataBufferInt){
+ return ((DataBufferInt)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public byte[] getDataByte(DataBuffer db) {
+ if (db instanceof DataBufferByte){
+ return ((DataBufferByte)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public short[] getDataShort(DataBuffer db) {
+ if (db instanceof DataBufferShort){
+ return ((DataBufferShort)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public short[] getDataUShort(DataBuffer db) {
+ if (db instanceof DataBufferUShort){
+ return ((DataBufferUShort)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public double[] getDataDouble(DataBuffer db) {
+ if (db instanceof DataBufferDouble){
+ return ((DataBufferDouble)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public float[] getDataFloat(DataBuffer db) {
+ if (db instanceof DataBufferFloat){
+ return ((DataBufferFloat)db).getData();
+ }
+ return null;
+ }
+
+ @Override
+ public void addDataBufferListener(DataBuffer db, DataBufferListener listener) {
+ db.addDataBufferListener(listener);
+ }
+
+ @Override
+ public void removeDataBufferListener(DataBuffer db) {
+ db.removeDataBufferListener();
+ }
+
+ @Override
+ public void validate(DataBuffer db) {
+ db.validate();
+ }
+
+ @Override
+ public void releaseData(DataBuffer db) {
+ db.releaseData();
+ }
+}
diff --git a/awt/java/awt/image/BandCombineOp.java b/awt/java/awt/image/BandCombineOp.java
new file mode 100644
index 0000000..cd77a21
--- /dev/null
+++ b/awt/java/awt/image/BandCombineOp.java
@@ -0,0 +1,610 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Sep 20, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.*;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The BandCombineOp class translates coordinates from
+ * coordinates in the source Raster to coordinates in
+ * the destination Raster by an arbitrary linear combination
+ * of the bands in a source Raster, using a specified matrix.
+ * The number of bands in the matrix should equal to
+ * the number of bands in the source Raster plus 1.
+ */
+public class BandCombineOp implements RasterOp {
+
+ /** The Constant offsets3c. */
+ static final int offsets3c[] = {16, 8, 0};
+
+ /** The Constant offsets4ac. */
+ static final int offsets4ac[] = {16, 8, 0, 24};
+
+ /** The Constant masks3c. */
+ static final int masks3c[] = {0xFF0000, 0xFF00, 0xFF};
+
+ /** The Constant masks4ac. */
+ static final int masks4ac[] = {0xFF0000, 0xFF00, 0xFF, 0xFF000000};
+
+ /** The Constant piOffsets. */
+ private static final int piOffsets[] = {0, 1, 2};
+
+ /** The Constant piInvOffsets. */
+ private static final int piInvOffsets[] = {2, 1, 0};
+
+ /** The Constant TYPE_BYTE3C. */
+ private static final int TYPE_BYTE3C = 0;
+
+ /** The Constant TYPE_BYTE4AC. */
+ private static final int TYPE_BYTE4AC = 1;
+
+ /** The Constant TYPE_USHORT3C. */
+ private static final int TYPE_USHORT3C = 2;
+
+ /** The Constant TYPE_SHORT3C. */
+ private static final int TYPE_SHORT3C = 3;
+
+ /** The mx width. */
+ private int mxWidth;
+
+ /** The mx height. */
+ private int mxHeight;
+
+ /** The matrix. */
+ private float matrix[][];
+
+ /** The r hints. */
+ private RenderingHints rHints;
+
+ static {
+ // XXX - todo
+ //System.loadLibrary("imageops");
+ }
+
+ /**
+ * Instantiates a new BandCombineOp object with the specified
+ * matrix.
+ *
+ * @param matrix the specified matrix for band combining.
+ * @param hints the RenderingHints.
+ */
+ public BandCombineOp(float matrix[][], RenderingHints hints) {
+ this.mxHeight = matrix.length;
+ this.mxWidth = matrix[0].length;
+ this.matrix = new float[mxHeight][mxWidth];
+
+ for (int i=0; i<mxHeight; i++){
+ System.arraycopy(matrix[i], 0, this.matrix[i], 0, mxWidth);
+ }
+
+ this.rHints = hints;
+ }
+
+ public final RenderingHints getRenderingHints(){
+ return this.rHints;
+ }
+
+ /**
+ * Gets the matrix associated with this BandCombineOp object.
+ *
+ * @return the matrix associated with this BandCombineOp object.
+ */
+ public final float[][] getMatrix() {
+ float res[][] = new float[mxHeight][mxWidth];
+
+ for (int i=0; i<mxHeight; i++) {
+ System.arraycopy(matrix[i], 0, res[i], 0, mxWidth);
+ }
+
+ return res;
+ }
+
+ public final Point2D getPoint2D (Point2D srcPoint, Point2D dstPoint) {
+ if (dstPoint == null) {
+ dstPoint = new Point2D.Float();
+ }
+
+ dstPoint.setLocation(srcPoint);
+ return dstPoint;
+ }
+
+ public final Rectangle2D getBounds2D(Raster src){
+ return src.getBounds();
+ }
+
+ public WritableRaster createCompatibleDestRaster (Raster src) {
+ int numBands = src.getNumBands();
+ if (mxWidth != numBands && mxWidth != (numBands+1) || numBands != mxHeight) {
+ // awt.254=Number of bands in the source raster ({0}) is
+ // incompatible with the matrix [{1}x{2}]
+ throw new IllegalArgumentException(Messages.getString("awt.254", //$NON-NLS-1$
+ new Object[]{numBands, mxWidth, mxHeight}));
+ }
+
+ return src.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+ }
+
+ public WritableRaster filter(Raster src, WritableRaster dst) {
+ int numBands = src.getNumBands();
+
+ if (mxWidth != numBands && mxWidth != (numBands+1)) {
+ // awt.254=Number of bands in the source raster ({0}) is
+ // incompatible with the matrix [{1}x{2}]
+ throw new IllegalArgumentException(
+ Messages.getString("awt.254", //$NON-NLS-1$
+ new Object[]{numBands, mxWidth, mxHeight}));
+ }
+
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else if (dst.getNumBands() != mxHeight) {
+ // awt.255=Number of bands in the destination raster ({0}) is incompatible with the matrix [{1}x{2}]
+ throw new IllegalArgumentException(Messages.getString("awt.255", //$NON-NLS-1$
+ new Object[]{dst.getNumBands(), mxWidth, mxHeight}));
+ }
+
+ // XXX - todo
+ //if (ippFilter(src, dst) != 0)
+ if (verySlowFilter(src, dst) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ return dst;
+ }
+
+ /**
+ * The Class SampleModelInfo.
+ */
+ private static final class SampleModelInfo {
+
+ /** The channels. */
+ int channels;
+
+ /** The channels order. */
+ int channelsOrder[];
+
+ /** The stride. */
+ int stride;
+ }
+
+ /**
+ * Check sample model.
+ *
+ * @param sm the sm
+ *
+ * @return the sample model info
+ */
+ private final SampleModelInfo checkSampleModel(SampleModel sm) {
+ SampleModelInfo ret = new SampleModelInfo();
+
+ if (sm instanceof PixelInterleavedSampleModel) {
+ // Check PixelInterleavedSampleModel
+ if (sm.getDataType() != DataBuffer.TYPE_BYTE) {
+ return null;
+ }
+
+ ret.channels = sm.getNumBands();
+ ret.stride = ((ComponentSampleModel) sm).getScanlineStride();
+ ret.channelsOrder = ((ComponentSampleModel) sm).getBandOffsets();
+
+ } else if (sm instanceof SinglePixelPackedSampleModel) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) sm;
+
+ ret.channels = sppsm1.getNumBands();
+ if (sppsm1.getDataType() != DataBuffer.TYPE_INT) {
+ return null;
+ }
+
+ // Check sample models
+ for (int i=0; i<ret.channels; i++) {
+ if (sppsm1.getSampleSize(i) != 8) {
+ return null;
+ }
+ }
+
+ ret.channelsOrder = new int[ret.channels];
+ int bitOffsets[] = sppsm1.getBitOffsets();
+ for (int i=0; i<ret.channels; i++) {
+ if (bitOffsets[i] % 8 != 0) {
+ return null;
+ }
+
+ ret.channelsOrder[i] = bitOffsets[i] / 8;
+ }
+
+ ret.channels = 4;
+ ret.stride = sppsm1.getScanlineStride() * 4;
+ } else {
+ return null;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the int
+ */
+ private final int slowFilter(Raster src, WritableRaster dst) {
+ int res = 0;
+
+ SampleModelInfo srcInfo, dstInfo;
+ int offsets[] = null;
+
+ srcInfo = checkSampleModel(src.getSampleModel());
+ dstInfo = checkSampleModel(dst.getSampleModel());
+ if (srcInfo == null || dstInfo == null) {
+ return verySlowFilter(src, dst);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+
+ int rmxWidth = (srcInfo.channels+1); // width of the reordered matrix
+ float reorderedMatrix[] = new float[rmxWidth*dstInfo.channels];
+ for (int j=0; j<dstInfo.channels; j++) {
+ if (j >= dstInfo.channelsOrder.length) {
+ continue;
+ }
+
+ for (int i=0; i<srcInfo.channels; i++) {
+ if (i >= srcInfo.channelsOrder.length) {
+ break;
+ }
+
+ reorderedMatrix[dstInfo.channelsOrder[j]*rmxWidth + srcInfo.channelsOrder[i]] =
+ matrix[j][i];
+ }
+ if (mxWidth == rmxWidth) {
+ reorderedMatrix[(dstInfo.channelsOrder[j]+1)*rmxWidth - 1] = matrix[j][mxWidth-1];
+ }
+ }
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ simpleCombineBands(
+ srcData, src.getWidth(), src.getHeight(), srcInfo.stride, srcInfo.channels,
+ dstData, dstInfo.stride, dstInfo.channels,
+ reorderedMatrix, offsets
+ );
+
+ return res;
+ }
+
+ /**
+ * Very slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the int
+ */
+ private int verySlowFilter(Raster src, WritableRaster dst) {
+ int numBands = src.getNumBands();
+
+ int srcMinX = src.getMinX();
+ int srcY = src.getMinY();
+
+ int dstMinX = dst.getMinX();
+ int dstY = dst.getMinY();
+
+ int dX = src.getWidth();//< dst.getWidth() ? src.getWidth() : dst.getWidth();
+ int dY = src.getHeight();//< dst.getHeight() ? src.getHeight() : dst.getHeight();
+
+ float sample;
+ int srcPixels[] = new int[numBands*dX*dY];
+ int dstPixels[] = new int[mxHeight*dX*dY];
+
+ srcPixels = src.getPixels(srcMinX, srcY, dX, dY, srcPixels);
+
+ if (numBands == mxWidth) {
+ for (int i=0, j=0; i<srcPixels.length; i+=numBands) {
+ for (int dstB = 0; dstB < mxHeight; dstB++) {
+ sample = 0f;
+ for (int srcB = 0; srcB < numBands; srcB++) {
+ sample += matrix[dstB][srcB] * srcPixels[i+srcB];
+ }
+ dstPixels[j++] = (int) sample;
+ }
+ }
+ } else {
+ for (int i=0, j=0; i<srcPixels.length; i+=numBands) {
+ for (int dstB = 0; dstB < mxHeight; dstB++) {
+ sample = 0f;
+ for (int srcB = 0; srcB < numBands; srcB++) {
+ sample += matrix[dstB][srcB] * srcPixels[i+srcB];
+ }
+ dstPixels[j++] = (int) (sample + matrix[dstB][numBands]);
+ }
+ }
+ }
+
+ dst.setPixels(dstMinX, dstY, dX, dY, dstPixels);
+
+ return 0;
+ }
+
+ //TODO remove when method is used
+ /**
+ * Ipp filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the int
+ */
+ @SuppressWarnings("unused")
+ private int ippFilter(Raster src, WritableRaster dst) {
+ boolean invertChannels;
+ boolean inPlace = (src == dst);
+ int type;
+ int srcStride, dstStride;
+ int offsets[] = null;
+
+ int srcBands = src.getNumBands();
+ int dstBands = dst.getNumBands();
+
+ if (
+ dstBands != 3 ||
+ (srcBands != 3 &&
+ !(srcBands == 4 &&
+ matrix[0][3] == 0 &&
+ matrix[1][3] == 0 &&
+ matrix[2][3] == 0)
+ )
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+
+ if (
+ srcSM instanceof SinglePixelPackedSampleModel &&
+ dstSM instanceof SinglePixelPackedSampleModel
+ ) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM;
+ SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM;
+
+ if (
+ sppsm1.getDataType() != DataBuffer.TYPE_INT ||
+ sppsm2.getDataType() != DataBuffer.TYPE_INT
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ // Check sample models
+ if (
+ !Arrays.equals(sppsm2.getBitOffsets(), offsets3c) ||
+ !Arrays.equals(sppsm2.getBitMasks(), masks3c)
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ if (srcBands == 3) {
+ if (
+ !Arrays.equals(sppsm1.getBitOffsets(), offsets3c) ||
+ !Arrays.equals(sppsm1.getBitMasks(), masks3c)
+ ) {
+ return slowFilter(src, dst);
+ }
+ } else if (srcBands == 4) {
+ if (
+ !Arrays.equals(sppsm1.getBitOffsets(), offsets4ac) ||
+ !Arrays.equals(sppsm1.getBitMasks(), masks4ac)
+ ) {
+ return slowFilter(src, dst);
+ }
+ }
+
+ type = TYPE_BYTE4AC;
+ invertChannels = true;
+
+ srcStride = sppsm1.getScanlineStride() * 4;
+ dstStride = sppsm2.getScanlineStride() * 4;
+ } else if (
+ srcSM instanceof PixelInterleavedSampleModel &&
+ dstSM instanceof PixelInterleavedSampleModel
+ ) {
+ if (srcBands != 3) {
+ return slowFilter(src, dst);
+ }
+
+ int srcDataType = srcSM.getDataType();
+
+ switch (srcDataType) {
+ case DataBuffer.TYPE_BYTE:
+ type = TYPE_BYTE3C;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ type = TYPE_USHORT3C;
+ break;
+ case DataBuffer.TYPE_SHORT:
+ type = TYPE_SHORT3C;
+ break;
+ default:
+ return slowFilter(src, dst);
+ }
+
+ // Check PixelInterleavedSampleModel
+ PixelInterleavedSampleModel pism1 = (PixelInterleavedSampleModel) srcSM;
+ PixelInterleavedSampleModel pism2 = (PixelInterleavedSampleModel) dstSM;
+
+ if (
+ srcDataType != pism2.getDataType() ||
+ pism1.getPixelStride() != 3 ||
+ pism2.getPixelStride() != 3 ||
+ !Arrays.equals(pism1.getBandOffsets(), pism2.getBandOffsets())
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ if (Arrays.equals(pism1.getBandOffsets(), piInvOffsets)) {
+ invertChannels = true;
+ } else if (Arrays.equals(pism1.getBandOffsets(), piOffsets)) {
+ invertChannels = false;
+ } else {
+ return slowFilter(src, dst);
+ }
+
+ int dataTypeSize = DataBuffer.getDataTypeSize(srcDataType) / 8;
+
+ srcStride = pism1.getScanlineStride() * dataTypeSize;
+ dstStride = pism2.getScanlineStride() * dataTypeSize;
+ } else { // XXX - todo - IPP allows support for planar data also
+ return slowFilter(src, dst);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ float ippMatrix[] = new float[12];
+
+ if (invertChannels) {
+ // IPP treats big endian integers like BGR, so we have to
+ // swap columns 1 and 3 and rows 1 and 3
+ for (int i = 0; i < mxHeight; i++) {
+ ippMatrix[i*4] = matrix[2-i][2];
+ ippMatrix[i*4+1] = matrix[2-i][1];
+ ippMatrix[i*4+2] = matrix[2-i][0];
+
+ if (mxWidth == 4) {
+ ippMatrix[i*4+3] = matrix[2-i][3];
+ } else if (mxWidth == 5) {
+ ippMatrix[i*4+3] = matrix[2-i][4];
+ }
+ }
+ } else {
+ for (int i = 0; i < mxHeight; i++) {
+ ippMatrix[i*4] = matrix[i][0];
+ ippMatrix[i*4+1] = matrix[i][1];
+ ippMatrix[i*4+2] = matrix[i][2];
+
+ if (mxWidth == 4) {
+ ippMatrix[i*4+3] = matrix[i][3];
+ } else if (mxWidth == 5) {
+ ippMatrix[i*4+3] = matrix[i][4];
+ }
+ }
+ }
+
+ return ippColorTwist(
+ srcData, src.getWidth(), src.getHeight(), srcStride,
+ dstData, dst.getWidth(), dst.getHeight(), dstStride,
+ ippMatrix, type, offsets, inPlace);
+ }
+
+ /**
+ * Ipp color twist.
+ *
+ * @param srcData the src data
+ * @param srcWidth the src width
+ * @param srcHeight the src height
+ * @param srcStride the src stride
+ * @param dstData the dst data
+ * @param dstWidth the dst width
+ * @param dstHeight the dst height
+ * @param dstStride the dst stride
+ * @param ippMatrix the ipp matrix
+ * @param type the type
+ * @param offsets the offsets
+ * @param inPlace the in place
+ *
+ * @return the int
+ */
+ private final native int ippColorTwist(
+ Object srcData, int srcWidth, int srcHeight, int srcStride,
+ Object dstData, int dstWidth, int dstHeight, int dstStride,
+ float ippMatrix[], int type, int offsets[], boolean inPlace
+ );
+
+ /**
+ * Simple combine bands.
+ *
+ * @param srcData the src data
+ * @param srcWidth the src width
+ * @param srcHeight the src height
+ * @param srcStride the src stride
+ * @param srcChannels the src channels
+ * @param dstData the dst data
+ * @param dstStride the dst stride
+ * @param dstChannels the dst channels
+ * @param m the m
+ * @param offsets the offsets
+ *
+ * @return the int
+ */
+ private final native int simpleCombineBands(
+ Object srcData, int srcWidth, int srcHeight, int srcStride, int srcChannels,
+ Object dstData, int dstStride, int dstChannels,
+ float m[], int offsets[]
+ );
+}
diff --git a/awt/java/awt/image/BandedSampleModel.java b/awt/java/awt/image/BandedSampleModel.java
new file mode 100644
index 0000000..392e44c
--- /dev/null
+++ b/awt/java/awt/image/BandedSampleModel.java
@@ -0,0 +1,426 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The BandedSampleModel class provides samples of pixels in an image
+ * which is stored in a band interleaved method. Each pixel's sample
+ * takes one data element of the DataBuffer. The pixel stride for a
+ * BandedSampleModel is one.
+ */
+public final class BandedSampleModel extends ComponentSampleModel {
+
+ /**
+ * Creates the indices.
+ *
+ * @param numBands the num bands
+ *
+ * @return the int[]
+ */
+ private static int[] createIndices(int numBands) {
+ int indices[] = new int[numBands];
+ for (int i = 0; i < numBands; i++) {
+ indices[i] = i;
+ }
+ return indices;
+ }
+
+ /**
+ * Creates the offsets.
+ *
+ * @param numBands the num bands
+ *
+ * @return the int[]
+ */
+ private static int[] createOffsets(int numBands) {
+ int offsets[] = new int[numBands];
+ for (int i = 0; i < numBands; i++) {
+ offsets[i] = 0;
+ }
+ return offsets;
+ }
+
+ /**
+ * Instantiates a new BandedSampleModel object with the specified
+ * data type of samples, the width, height and bands number
+ * of image data.
+ *
+ * @param dataType the data type of samples.
+ * @param w the width of image data.
+ * @param h the height of image data.
+ * @param numBands the number of bands.
+ */
+ public BandedSampleModel(int dataType, int w, int h, int numBands) {
+ this(dataType, w, h, w, BandedSampleModel.createIndices(numBands),
+ BandedSampleModel.createOffsets(numBands));
+ }
+
+ /**
+ * Instantiates a new BandedSampleModel object with the specified
+ * data type of samples, the width, height and bands number
+ * of image data.
+ *
+ * @param dataType the data type of samples.
+ * @param w the width of image data.
+ * @param h the height of image data.
+ * @param scanlineStride the scanline stride of the of the image data.
+ * @param bankIndices the array of the bank indecies.
+ * @param bandOffsets the array of the band offsets.
+ */
+ public BandedSampleModel(int dataType, int w, int h, int scanlineStride,
+ int bankIndices[], int bandOffsets[]) {
+ super(dataType, w, h, 1, scanlineStride, bankIndices, bandOffsets);
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ return new BandedSampleModel(dataType, w, h, w, bankIndices,
+ bandOffsets);
+ }
+
+ @Override
+ public DataBuffer createDataBuffer() {
+ DataBuffer data = null;
+ int size = scanlineStride * height;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(size, numBanks);
+ break;
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferShort(size, numBanks);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(size, numBanks);
+ break;
+ case DataBuffer.TYPE_FLOAT:
+ data = new DataBufferFloat(size, numBanks);
+ break;
+ case DataBuffer.TYPE_DOUBLE:
+ data = new DataBufferDouble(size, numBanks);
+ break;
+ }
+
+ return data;
+
+ }
+
+ @Override
+ public SampleModel createSubsetSampleModel(int[] bands) {
+ if (bands.length > numBands) {
+ // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model
+ throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
+ }
+
+ int indices[] = new int[bands.length];
+ int offsets[] = new int[bands.length];
+
+ for (int i = 0; i < bands.length; i++) {
+ indices[i] = bankIndices[bands[i]];
+ offsets[i] = bandOffsets[bands[i]];
+ }
+
+ return new BandedSampleModel(dataType, width, height, scanlineStride,
+ indices, offsets);
+ }
+
+ @Override
+ public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE: {
+ byte bdata[];
+
+ if (obj == null) {
+ bdata = new byte[numBands];
+ } else {
+ bdata = (byte[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ bdata[i] = (byte) getSample(x, y, i, data);
+ }
+
+ obj = bdata;
+ break;
+ }
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT: {
+ short sdata[];
+
+ if (obj == null) {
+ sdata = new short[numBands];
+ } else {
+ sdata = (short[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ sdata[i] = (short) getSample(x, y, i, data);
+ }
+
+ obj = sdata;
+ break;
+ }
+ case DataBuffer.TYPE_INT: {
+ int idata[];
+
+ if (obj == null) {
+ idata = new int[numBands];
+ } else {
+ idata = (int[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ idata[i] = getSample(x, y, i, data);
+ }
+
+ obj = idata;
+ break;
+ }
+ case DataBuffer.TYPE_FLOAT: {
+ float fdata[];
+
+ if (obj == null) {
+ fdata = new float[numBands];
+ } else {
+ fdata = (float[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ fdata[i] = getSampleFloat(x, y, i, data);
+ }
+
+ obj = fdata;
+ break;
+ }
+ case DataBuffer.TYPE_DOUBLE: {
+ double ddata[];
+
+ if (obj == null) {
+ ddata = new double[numBands];
+ } else {
+ ddata = (double[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ ddata[i] = getSampleDouble(x, y, i, data);
+ }
+
+ obj = ddata;
+ break;
+ }
+ }
+
+ return obj;
+ }
+
+ @Override
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ int pixel[];
+ if (iArray == null) {
+ pixel = new int[numBands];
+ } else {
+ pixel = iArray;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ pixel[i] = getSample(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ @Override
+ public int getSample(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElem(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b]);
+ }
+
+ @Override
+ public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElemDouble(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b]);
+ }
+
+ @Override
+ public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElemFloat(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b]);
+ }
+
+ @Override
+ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ int samples[];
+ int idx = 0;
+
+ if (iArray == null) {
+ samples = new int[w * h];
+ } else {
+ samples = iArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSample(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = super.hashCode();
+ int tmp = hash >>> 8;
+ hash <<= 8;
+ hash |= tmp;
+
+ return hash ^ 0x55;
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[] = (byte[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, bdata[i] & 0xff, data);
+ }
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short sdata[] = (short[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, sdata[i] & 0xffff, data);
+ }
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int idata[] = (int[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, idata[i], data);
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fdata[] = (float[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, fdata[i], data);
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double ddata[] = (double[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, ddata[i], data);
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, iArray[i], data);
+ }
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ int idx = 0;
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ setSample(j, i, n, iArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, double s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElemDouble(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b], s);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, float s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElemFloat(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b], s);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElem(bankIndices[b], y * scanlineStride + x +
+ bandOffsets[b], s);
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ int idx = 0;
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(j, i, b, iArray[idx++], data);
+ }
+ }
+
+ }
+
+}
+
diff --git a/awt/java/awt/image/BufferStrategy.java b/awt/java/awt/image/BufferStrategy.java
new file mode 100644
index 0000000..e0508f0
--- /dev/null
+++ b/awt/java/awt/image/BufferStrategy.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.BufferCapabilities;
+import java.awt.Graphics;
+
+/**
+ * The BufferStrategy abstract class provides an opportunity
+ * to organize the buffers for a Canvas or Window. The BufferStrategy
+ * implementation depends on hardware and software limitations.
+ * These limitations are detectible through the capabilities
+ * object which can be obtained by the GraphicsConfiguration of the Canvas
+ * or Window.
+ */
+public abstract class BufferStrategy {
+
+ /**
+ * Returns true if the drawing buffer was lost since the last call
+ * of getDrawGraphics.
+ *
+ * @return true if the drawing buffer was lost since the last call
+ * of getDrawGraphics, false otherwise.
+ */
+ public abstract boolean contentsLost();
+
+ /**
+ * Returns true if the drawing buffer is restored from a lost state.
+ *
+ * @return true if the drawing buffer is restored from a lost state,
+ * false otherwise.
+ */
+ public abstract boolean contentsRestored();
+
+ /**
+ * Gets the BufferCapabilities of BufferStrategy.
+ *
+ * @return the BufferCapabilities of BufferStrategy.
+ */
+ public abstract BufferCapabilities getCapabilities();
+
+ /**
+ * Gets the Graphics object to use to draw to the buffer.
+ *
+ * @return the Graphics object to use to draw to the buffer.
+ */
+ public abstract Graphics getDrawGraphics();
+
+ /**
+ * Shows the next available buffer.
+ */
+ public abstract void show();
+
+}
diff --git a/awt/java/awt/image/BufferedImage.java b/awt/java/awt/image/BufferedImage.java
new file mode 100644
index 0000000..d305d66
--- /dev/null
+++ b/awt/java/awt/image/BufferedImage.java
@@ -0,0 +1,931 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.image.BufferedImageSource;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * The BufferedImage class describes an Image which contains a buffer
+ * of image data and includes a ColorModel and a Raster for this data.
+ * This class provides methods for obtaining and setting the Raster
+ * and for manipulating the ColorModel parameters.
+ */
+public class BufferedImage extends
+Image implements WritableRenderedImage, Transparency{
+
+ /**
+ * The Constant TYPE_CUSTOM indicates that Image type
+ * is unknown.
+ */
+ public static final int TYPE_CUSTOM = 0;
+
+ /**
+ * The Constant TYPE_INT_RGB indicates an image with
+ * 8 bit RGB color components, it has a DirectColorModel
+ * without alpha.
+ */
+ public static final int TYPE_INT_RGB = 1;
+
+ /**
+ * The Constant TYPE_INT_ARGB indicates an image with
+ * 8 bit RGBA color components, it has a DirectColorModel
+ * with alpha.
+ */
+ public static final int TYPE_INT_ARGB = 2;
+
+ /**
+ * The Constant TYPE_INT_ARGB_PRE indicates an image with
+ * 8 bit RGBA color components, it has a DirectColorModel
+ * with alpha, and image data is premultiplied by alpha.
+ */
+ public static final int TYPE_INT_ARGB_PRE = 3;
+
+ /**
+ * The Constant TYPE_INT_BGR indicates an image with
+ * 8 bit RGB color components, BGR color model
+ * (with the colors Blue, Green, and Red). There is no
+ * alpha. The image has a DirectColorModel.
+ */
+ public static final int TYPE_INT_BGR = 4;
+
+ /**
+ * The Constant TYPE_3BYTE_BGR indicates an image with
+ * 8 bit RGB color components, BGR color model
+ * (with the colors Blue, Green, and Red stored in 3 bytes).
+ * There is no alpha. The image has a ComponentColorModel.
+ */
+ public static final int TYPE_3BYTE_BGR = 5;
+
+ /**
+ * The Constant TYPE_4BYTE_ABGR indicates an image with
+ * 8 bit RGBA color components stored in 3 bytes and 1 byte of alpha.
+ * It has a ComponentColorModel with alpha.
+ */
+ public static final int TYPE_4BYTE_ABGR = 6;
+
+ /**
+ * The Constant TYPE_4BYTE_ABGR_PRE indicates an image with
+ * 8 bit RGBA color components stored in 3 bytes and 1 byte
+ * for alpha. The image has a ComponentColorModel with alpha.
+ * The color data is premultiplied with alpha.
+ */
+ public static final int TYPE_4BYTE_ABGR_PRE = 7;
+
+ /**
+ * The Constant TYPE_USHORT_565_RGB indicates an image with
+ * 565 RGB color components (5-bits red, 6-bits green, 5-bits blue)
+ * with no alpha. This image has a DirectColorModel.
+ */
+ public static final int TYPE_USHORT_565_RGB = 8;
+
+ /**
+ * The Constant TYPE_USHORT_555_RGB indicates an image with
+ * 555 RGB color components (5-bits red, 5-bits green, 5-bits blue)
+ * with no alpha. This image has a DirectColorModel.
+ */
+ public static final int TYPE_USHORT_555_RGB = 9;
+
+ /**
+ * The Constant TYPE_BYTE_GRAY indicates a unsigned byte
+ * image. This image has a ComponentColorModel with
+ * a CS_GRAY ColorSpace.
+ */
+ public static final int TYPE_BYTE_GRAY = 10;
+
+ /**
+ * The Constant TYPE_USHORT_GRAY indicates an unsigned short
+ * image. This image has a ComponentColorModel with a CS_GRAY
+ * ColorSpace.
+ */
+ public static final int TYPE_USHORT_GRAY = 11;
+
+ /**
+ * The Constant TYPE_BYTE_BINARY indicates an opaque byte-packed
+ * 1, 2 or 4 bit image. The image has an IndexColorModel without
+ * alpha.
+ */
+ public static final int TYPE_BYTE_BINARY = 12;
+
+ /**
+ * The Constant TYPE_BYTE_INDEXED indicates an indexed byte image.
+ */
+ public static final int TYPE_BYTE_INDEXED = 13;
+
+ /** The Constant ALPHA_MASK. */
+ private static final int ALPHA_MASK = 0xff000000;
+
+ /** The Constant RED_MASK. */
+ private static final int RED_MASK = 0x00ff0000;
+
+ /** The Constant GREEN_MASK. */
+ private static final int GREEN_MASK = 0x0000ff00;
+
+ /** The Constant BLUE_MASK. */
+ private static final int BLUE_MASK = 0x000000ff;
+
+ /** The Constant RED_BGR_MASK. */
+ private static final int RED_BGR_MASK = 0x000000ff;
+
+ /** The Constant GREEN_BGR_MASK. */
+ private static final int GREEN_BGR_MASK = 0x0000ff00;
+
+ /** The Constant BLUE_BGR_MASK. */
+ private static final int BLUE_BGR_MASK = 0x00ff0000;
+
+ /** The Constant RED_565_MASK. */
+ private static final int RED_565_MASK = 0xf800;
+
+ /** The Constant GREEN_565_MASK. */
+ private static final int GREEN_565_MASK = 0x07e0;
+
+ /** The Constant BLUE_565_MASK. */
+ private static final int BLUE_565_MASK = 0x001f;
+
+ /** The Constant RED_555_MASK. */
+ private static final int RED_555_MASK = 0x7c00;
+
+ /** The Constant GREEN_555_MASK. */
+ private static final int GREEN_555_MASK = 0x03e0;
+
+ /** The Constant BLUE_555_MASK. */
+ private static final int BLUE_555_MASK = 0x001f;
+
+ /** The cm. */
+ private ColorModel cm;
+
+ /** The raster. */
+ private final WritableRaster raster;
+
+ /** The image type. */
+ private final int imageType;
+
+ /** The properties. */
+ private Hashtable<?, ?> properties;
+
+ // Surface of the Buffered Image - used for blitting one Buffered Image
+ // on the other one or on the Component
+ /** The image surf. */
+ private final ImageSurface imageSurf;
+
+ /**
+ * Instantiates a new BufferedImage with the specified ColorModel,
+ * and WritableRaster objects. The Raster data can be
+ * be divided or multiplied by alpha. It depends on the
+ * alphaPremultiplied state in the ColorModel.
+ *
+ * @param cm the ColorModel of the new image.
+ * @param raster the WritableRaster of the new image.
+ * @param isRasterPremultiplied if true the data of the specified
+ * Raster is premultiplied by alpha.
+ * @param properties the properties of new Image.
+ */
+ public BufferedImage(ColorModel cm, WritableRaster raster,
+ boolean isRasterPremultiplied, Hashtable<?, ?> properties) {
+ if (!cm.isCompatibleRaster(raster)) {
+ // awt.4D=The raster is incompatible with this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+ }
+
+ if (raster.getMinX() != 0 || raster.getMinY() != 0) {
+ // awt.228=minX or minY of this raster not equal to zero
+ throw new IllegalArgumentException(Messages.getString("awt.228")); //$NON-NLS-1$
+ }
+
+ this.cm = cm;
+ this.raster = raster;
+ this.properties = properties;
+
+ coerceData(isRasterPremultiplied);
+
+ imageType = Surface.getType(cm, raster);
+
+ imageSurf = createImageSurface(imageType);
+ }
+
+ /**
+ * Instantiates a new BufferedImage with the specified width, height
+ * predefined image type (TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED)
+ * and the specified IndexColorModel.
+ *
+ * @param width the width of new image.
+ * @param height the height of new image.
+ * @param imageType the predefined image type.
+ * @param cm the specified IndexColorModel.
+ */
+ public BufferedImage(int width, int height, int imageType,
+ IndexColorModel cm) {
+ switch (imageType) {
+ case TYPE_BYTE_BINARY:
+ if (cm.hasAlpha()) {
+ // awt.227=This image type can't have alpha
+ throw new IllegalArgumentException(Messages.getString("awt.227")); //$NON-NLS-1$
+ }
+ int pixel_bits = 0;
+ int mapSize = cm.getMapSize();
+ if (mapSize <= 2) {
+ pixel_bits = 1;
+ } else if (mapSize <= 4) {
+ pixel_bits = 2;
+ } else if (mapSize <= 16) {
+ pixel_bits = 4;
+ } else {
+ // awt.221=The imageType is TYPE_BYTE_BINARY and the color map has more than 16 entries
+ throw new IllegalArgumentException(Messages.getString("awt.221")); //$NON-NLS-1$
+ }
+
+ raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width,
+ height, 1, pixel_bits, null);
+ break;
+
+ case TYPE_BYTE_INDEXED:
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height, 1, null);
+ break;
+
+ default:
+ // awt.222=The imageType is not TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED
+ throw new IllegalArgumentException(Messages.getString("awt.222")); //$NON-NLS-1$
+
+ }
+
+ if (!cm.isCompatibleRaster(raster)) {
+ // awt.223=The imageType is not compatible with ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.223")); //$NON-NLS-1$
+ }
+
+ this.cm = cm;
+ this.imageType = imageType;
+ imageSurf = createImageSurface(imageType);
+
+ }
+
+ /**
+ * Instantiates a new BufferedImage with the specified width, height
+ * and predefined image type.
+ *
+ * @param width the width of new image.
+ * @param height the height of new image.
+ * @param imageType the predefined image type.
+ */
+ public BufferedImage(int width, int height, int imageType) {
+
+ switch (imageType) {
+ case TYPE_INT_RGB:
+ cm = new DirectColorModel(24, RED_MASK, GREEN_MASK, BLUE_MASK);
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_INT_ARGB:
+ cm = ColorModel.getRGBdefault();
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_INT_ARGB_PRE:
+ cm = new DirectColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ 32,
+ RED_MASK,
+ GREEN_MASK,
+ BLUE_MASK,
+ ALPHA_MASK,
+ true,
+ DataBuffer.TYPE_INT);
+
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_INT_BGR:
+ cm = new DirectColorModel(24,
+ RED_BGR_MASK,
+ GREEN_BGR_MASK,
+ BLUE_BGR_MASK);
+
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_3BYTE_BGR: {
+ int bits[] = { 8, 8, 8 };
+ int bandOffsets[] = { 2, 1, 0 };
+ cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ bits,
+ false,
+ false,
+ Transparency.OPAQUE,
+ DataBuffer.TYPE_BYTE);
+
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height, width * 3, 3, bandOffsets, null);
+ }
+ break;
+
+ case TYPE_4BYTE_ABGR: {
+ int bits[] = { 8, 8, 8, 8 };
+ int bandOffsets[] = { 3, 2, 1, 0 };
+ cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ bits,
+ true,
+ false,
+ Transparency.TRANSLUCENT,
+ DataBuffer.TYPE_BYTE);
+
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height, width * 4, 4, bandOffsets, null);
+ }
+ break;
+
+ case TYPE_4BYTE_ABGR_PRE: {
+ int bits[] = { 8, 8, 8, 8 };
+ int bandOffsets[] = { 3, 2, 1, 0 };
+ cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ bits,
+ true,
+ true,
+ Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
+
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height, width * 4, 4, bandOffsets, null);
+ }
+ break;
+
+ case TYPE_USHORT_565_RGB:
+ cm = new DirectColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ 16,
+ RED_565_MASK,
+ GREEN_565_MASK,
+ BLUE_565_MASK,
+ 0,
+ false,
+ DataBuffer.TYPE_USHORT);
+
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_USHORT_555_RGB:
+ cm = new DirectColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ 15,
+ RED_555_MASK,
+ GREEN_555_MASK,
+ BLUE_555_MASK,
+ 0,
+ false,
+ DataBuffer.TYPE_USHORT);
+
+ raster = cm.createCompatibleWritableRaster(width, height);
+ break;
+
+ case TYPE_BYTE_GRAY: {
+ int bits[] = { 8 };
+ cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ bits,
+ false,
+ false,
+ Transparency.OPAQUE,
+ DataBuffer.TYPE_BYTE);
+
+ raster = cm.createCompatibleWritableRaster(width, height);
+ }
+ break;
+
+ case TYPE_USHORT_GRAY: {
+ int bits[] = { 16 };
+ cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ bits,
+ false,
+ false,
+ Transparency.OPAQUE,
+ DataBuffer.TYPE_USHORT);
+ raster = cm.createCompatibleWritableRaster(width, height);
+ }
+ break;
+
+ case TYPE_BYTE_BINARY: {
+ int colorMap[] = { 0, 0xffffff };
+ cm = new IndexColorModel(1, 2, colorMap, 0, false, -1,
+ DataBuffer.TYPE_BYTE);
+
+ raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width,
+ height, 1, 1, null);
+ }
+ break;
+
+ case TYPE_BYTE_INDEXED: {
+ int colorMap[] = new int[256];
+ int i = 0;
+ for (int r = 0; r < 256; r += 51) {
+ for (int g = 0; g < 256; g += 51) {
+ for (int b = 0; b < 256; b += 51) {
+ colorMap[i] = (r << 16) | (g << 8) | b;
+ i++;
+ }
+ }
+ }
+
+ int gray = 0x12;
+ for (; i < 256; i++, gray += 6) {
+ colorMap[i] = (gray << 16) | (gray << 8) | gray;
+ }
+ cm = new IndexColorModel(8, 256, colorMap, 0, false, -1,
+ DataBuffer.TYPE_BYTE);
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ width, height, 1, null);
+
+ }
+ break;
+ default:
+ // awt.224=Unknown image type
+ throw new IllegalArgumentException(Messages.getString("awt.224")); //$NON-NLS-1$
+ }
+ this.imageType = imageType;
+ imageSurf = createImageSurface(imageType);
+ }
+
+ @Override
+ public Object getProperty(String name, ImageObserver observer) {
+ return getProperty(name);
+ }
+
+ public Object getProperty(String name) {
+ if(name == null) {
+ // awt.225=Property name is null
+ throw new NullPointerException(Messages.getString("awt.225")); //$NON-NLS-1$
+ }
+ if (properties == null) {
+ return Image.UndefinedProperty;
+ }
+ Object property = properties.get(name);
+ if (property == null) {
+ property = Image.UndefinedProperty;
+ }
+ return property;
+ }
+
+ public WritableRaster copyData(WritableRaster outRaster) {
+ if (outRaster == null) {
+ outRaster = Raster.createWritableRaster(raster.getSampleModel(),
+ new Point(raster.getSampleModelTranslateX(),
+ raster.getSampleModelTranslateY()));
+ }
+
+ int w = outRaster.getWidth();
+ int h = outRaster.getHeight();
+ int minX = outRaster.getMinX();
+ int minY = outRaster.getMinY();
+
+ Object data = null;
+
+ data = raster.getDataElements(minX, minY, w, h, data);
+ outRaster.setDataElements(minX, minY, w, h, data);
+
+ return outRaster;
+ }
+
+ public Raster getData(Rectangle rect) {
+ int minX = rect.x;
+ int minY = rect.y;
+ int w = rect.width;
+ int h = rect.height;
+
+ SampleModel sm = raster.getSampleModel();
+ SampleModel nsm = sm.createCompatibleSampleModel(w, h);
+ WritableRaster outr = Raster.createWritableRaster(nsm,
+ rect.getLocation());
+ Object data = null;
+
+ data = raster.getDataElements(minX, minY, w, h, data);
+ outr.setDataElements(minX, minY, w, h, data);
+ return outr;
+ }
+
+ public Vector<RenderedImage> getSources() {
+ return null;
+ }
+
+ public String[] getPropertyNames() {
+ if (properties == null) {
+ return null;
+ }
+ Vector<String> v = new Vector<String>();
+ for (Enumeration<?> e = properties.keys(); e.hasMoreElements();) {
+ try {
+ v.add((String) e.nextElement());
+ } catch (ClassCastException ex) {
+ }
+ }
+ int size = v.size();
+ if (size > 0) {
+ String names[] = new String[size];
+ for (int i = 0; i < size; i++) {
+ names[i] = v.elementAt(i);
+ }
+ return names;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the string representation of this BufferedImage object.
+ *
+ * @return the string representation of this BufferedImage object.
+ */
+ @Override
+ public String toString() {
+ return "BufferedImage@" + Integer.toHexString(hashCode()) + //$NON-NLS-1$
+ ": type = " + imageType + " " + cm + " " + raster; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ public WritableRaster getWritableTile(int tileX, int tileY) {
+ return raster;
+ }
+
+ /**
+ * Gets the WritableRaster of this BufferedImage.
+ *
+ * @return the WritableRaster of this BufferedImage.
+ */
+ public WritableRaster getRaster() {
+ return raster;
+ }
+
+ /**
+ * Gets a WritableRaster object which contains the alpha channel of
+ * BufferedImage object with ColorModel objects that supports
+ * a separate alpha channel such as ComponentColorModel
+ * or DirectColorModel.
+ *
+ * @return the WritableRaster object which contains the alpha
+ * channel of this BufferedImage.
+ */
+ public WritableRaster getAlphaRaster() {
+ return cm.getAlphaRaster(raster);
+ }
+
+ public void removeTileObserver(TileObserver to) {
+ }
+
+ public void addTileObserver(TileObserver to) {
+ }
+
+ public SampleModel getSampleModel() {
+ return raster.getSampleModel();
+ }
+
+ public void setData(Raster r) {
+
+ Rectangle from = r.getBounds();
+ Rectangle to = raster.getBounds();
+ Rectangle intersection = to.intersection(from);
+
+ int minX = intersection.x;
+ int minY = intersection.y;
+ int w = intersection.width;
+ int h = intersection.height;
+
+ Object data = null;
+
+ data = r.getDataElements(minX, minY, w, h, data);
+ raster.setDataElements(minX, minY, w, h, data);
+ }
+
+ public Raster getTile(int tileX, int tileY) {
+ if (tileX == 0 && tileY == 0) {
+ return raster;
+ }
+ // awt.226=Both tileX and tileY are not equal to 0
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$
+ }
+
+ public Raster getData() {
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+ int minX = raster.getMinX();
+ int minY = raster.getMinY();
+
+ WritableRaster outr = Raster.createWritableRaster(
+ raster.getSampleModel(),
+ new Point(raster.getSampleModelTranslateX(),
+ raster.getSampleModelTranslateY()));
+
+ Object data = null;
+
+ data = raster.getDataElements(minX, minY, w, h, data);
+ outr.setDataElements(minX, minY, w, h, data);
+
+ return outr;
+ }
+
+ @Override
+ public ImageProducer getSource() {
+ return new BufferedImageSource(this, properties);
+ }
+
+ @Override
+ public int getWidth(ImageObserver observer) {
+ return raster.getWidth();
+ }
+
+ @Override
+ public int getHeight(ImageObserver observer) {
+ return raster.getHeight();
+ }
+
+ public ColorModel getColorModel() {
+ return cm;
+ }
+
+ /**
+ * Gets the rectangular area of this BufferedImage as a subimage.
+ *
+ * @param x the x coordinate.
+ * @param y the y coordinate.
+ * @param w the width of the subimage.
+ * @param h the height of the subimage.
+ *
+ * @return the BufferedImage.
+ */
+ public BufferedImage getSubimage(int x, int y, int w, int h) {
+ WritableRaster wr = raster.createWritableChild(x, y, w, h, 0, 0, null);
+ return new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), properties);
+ }
+
+ public Point[] getWritableTileIndices() {
+ Point points[] = new Point[1];
+ points[0] = new Point(0, 0);
+ return points;
+ }
+
+ /**
+ * Creates the Graphics2D object which allows to draw into
+ * this BufferedImage.
+ *
+ * @return the graphics2D object.
+ */
+ public Graphics2D createGraphics() {
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ //return ge.createGraphics(this);
+ //???AWT hack, FIXME
+ //return AndroidGraphics2D.getInstance();
+ //throw new RuntimeException("Not implemented!");
+ return null;
+ }
+
+ @Override
+ public Graphics getGraphics() {
+ return createGraphics();
+ }
+
+ /**
+ * Coerces the data to achieve the state which is specified by
+ * the isAlphaPremultiplied variable.
+ *
+ * @param isAlphaPremultiplied the is alpha premultiplied state.
+ */
+ public void coerceData(boolean isAlphaPremultiplied) {
+ if (cm.hasAlpha() &&
+ cm.isAlphaPremultiplied() != isAlphaPremultiplied) {
+ cm = cm.coerceData(raster, isAlphaPremultiplied);
+ }
+ }
+
+ /**
+ * Gets an array of colors in the TYPE_INT_ARGB color model and
+ * default sRGB colorspace of the specified area of this
+ * BufferedImage. The result array is composed by the following
+ * algirithm:
+ * <p>
+ * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]
+ *
+ * @param startX the start X area coordinate.
+ * @param startY the start Y area coordinate.
+ * @param w the width of the area.
+ * @param h the height of the area.
+ * @param rgbArray the result array will be stored to this array.
+ * @param offset the offset of the rgbArray array.
+ * @param scansize the scanline stride for the rgbArray.
+ *
+ * @return an array of colors for the specified area.
+ */
+ public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray,
+ int offset, int scansize) {
+ if (rgbArray == null) {
+ rgbArray = new int[offset + h * scansize];
+ }
+
+ int off = offset;
+ for (int y = startY; y < startY + h; y++, off += scansize) {
+ int i = off;
+ for (int x = startX; x < startX + w; x++, i++) {
+ rgbArray[i] = cm.getRGB(raster.getDataElements(x, y, null));
+ }
+ }
+ return rgbArray;
+ }
+
+ /**
+ * Sets RGB values from the specified array to the specified
+ * BufferedImage area. The pixels are in the default RGB color model
+ * (TYPE_INT_ARGB) and default sRGB color space.
+ *
+ * @param startX the start X coordinate.
+ * @param startY the start Y coordinate.
+ * @param w the width of the BufferedImage area.
+ * @param h the height of the BufferedImage area.
+ * @param rgbArray the array of RGB values.
+ * @param offset the offset of the rgbArray array.
+ * @param scansize the scanline stride for the rgbArray.
+ */
+ public void setRGB(int startX, int startY, int w, int h, int[] rgbArray,
+ int offset, int scansize) {
+ int off = offset;
+ for (int y = startY; y < startY + h; y++, off += scansize) {
+ int i = off;
+ for (int x = startX; x < startX + w; x++, i++) {
+ raster.setDataElements(x, y,
+ cm.getDataElements(rgbArray[i], null));
+ }
+ }
+ }
+
+ /**
+ * Sets a the specified RGB value to the specified pixel of
+ * this BufferedImage. The pixel should be in the default
+ * RGB color model (TYPE_INT_ARGB) and default sRGB color space.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param rgb the RGB value to be set.
+ */
+ public synchronized void setRGB(int x, int y, int rgb) {
+ raster.setDataElements(x, y, cm.getDataElements(rgb, null));
+ }
+
+ public boolean isTileWritable(int tileX, int tileY) {
+ if (tileX == 0 && tileY == 0) {
+ return true;
+ }
+ // awt.226=Both tileX and tileY are not equal to 0
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$
+ }
+
+ public void releaseWritableTile(int tileX, int tileY) {
+ }
+
+ /**
+ * Gets a color in the TYPE_INT_ARGB color model and default
+ * sRGB colorspace of the specified pixel.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ *
+ * @return the color of the specified pixel in the TYPE_INT_ARGB
+ * color model and default sRGB colorspace.
+ */
+ public int getRGB(int x, int y) {
+ return cm.getRGB(raster.getDataElements(x, y, null));
+ }
+
+ /**
+ * Returnes true if alpha is premultiplied,
+ * false if alpha is not premultiplied or there is no alpha.
+ *
+ * @return true if alpha is premultiplied,
+ * false if alpha is not premultiplied or there is no alpha.
+ */
+ public boolean isAlphaPremultiplied() {
+ return cm.isAlphaPremultiplied();
+ }
+
+ public boolean hasTileWriters() {
+ return true;
+ }
+
+ @Override
+ public void flush() {
+ imageSurf.dispose();
+ }
+
+ public int getWidth() {
+ return raster.getWidth();
+ }
+
+ /**
+ * Gets the image type.
+ *
+ * @return the image type.
+ */
+ public int getType() {
+ return imageType;
+ }
+
+ public int getTileWidth() {
+ return raster.getWidth();
+ }
+
+ public int getTileHeight() {
+ return raster.getHeight();
+ }
+
+ public int getTileGridYOffset() {
+ return raster.getSampleModelTranslateY();
+ }
+
+ public int getTileGridXOffset() {
+ return raster.getSampleModelTranslateX();
+ }
+
+ public int getNumYTiles() {
+ return 1;
+ }
+
+ public int getNumXTiles() {
+ return 1;
+ }
+
+ public int getMinY() {
+ return raster.getMinY();
+ }
+
+ public int getMinX() {
+ return raster.getMinX();
+ }
+
+ public int getMinTileY() {
+ return 0;
+ }
+
+ public int getMinTileX() {
+ return 0;
+ }
+
+ public int getHeight() {
+ return raster.getHeight();
+ }
+
+ /**
+ * Creates the image surface.
+ *
+ * @param type the type
+ *
+ * @return the image surface
+ */
+ private ImageSurface createImageSurface(int type) {
+ return new ImageSurface(getColorModel(), getRaster(), type);
+ }
+
+ /**
+ * Gets the image surface.
+ *
+ * @return the image surface
+ */
+ ImageSurface getImageSurface() {
+ return imageSurf;
+ }
+
+ public int getTransparency() {
+ return cm.getTransparency();
+ }
+}
+
diff --git a/awt/java/awt/image/BufferedImageFilter.java b/awt/java/awt/image/BufferedImageFilter.java
new file mode 100644
index 0000000..44b3c2e
--- /dev/null
+++ b/awt/java/awt/image/BufferedImageFilter.java
@@ -0,0 +1,375 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The BufferedImageFilter class provides filtering operations to
+ * the BufferedImage objects using operators which implement
+ * BufferedImageOp interface.
+ */
+public class BufferedImageFilter extends ImageFilter implements Cloneable {
+
+ /** The Constant accessor. */
+ private static final AwtImageBackdoorAccessor accessor = AwtImageBackdoorAccessor.getInstance();
+
+ /** The op. */
+ private BufferedImageOp op;
+
+ /** The raster. */
+ private WritableRaster raster;
+
+ /** The i data. */
+ private int iData[];
+
+ /** The b data. */
+ private byte bData[];
+
+ /** The width. */
+ private int width;
+
+ /** The height. */
+ private int height;
+
+ /** The cm. */
+ private ColorModel cm;
+
+ /** The forced rgb. */
+ private boolean forcedRGB = false;
+
+ /** The transfer type. */
+ private int transferType = DataBuffer.TYPE_UNDEFINED;
+
+ /**
+ * Instantiates a new BufferedImageFilter with the specified
+ * BufferedImageOp operator.
+ *
+ * @param op the specified BufferedImageOp operator.
+ *
+ * @throws NullPointerException if BufferedImageOp is null.
+ */
+ public BufferedImageFilter(BufferedImageOp op) {
+ if (op == null) {
+ throw new NullPointerException(Messages.getString("awt.05")); //$NON-NLS-1$
+ }
+ this.op = op;
+ }
+
+ /**
+ * Gets the BufferedImageOp operator associated with this
+ * BufferedImageFilter object.
+ *
+ * @return the BufferedImageOp associated with this
+ * BufferedImageFilter object.
+ */
+ public BufferedImageOp getBufferedImageOp() {
+ return op;
+ }
+
+ @Override
+ public void setDimensions(int width, int height) {
+ this.width = width;
+ this.height = height;
+ // Stop image consuming if no pixels expected.
+ if (width <= 0 || height <= 0) {
+ consumer.imageComplete(ImageConsumer.STATICIMAGEDONE);
+ reset();
+ }
+ }
+
+ @Override
+ public void setColorModel(ColorModel model) {
+ if (this.cm != null && this.cm != model && raster != null) {
+ forceRGB();
+ } else {
+ this.cm = model;
+ }
+ }
+
+ @Override
+ public void setPixels(
+ int x, int y, int
+ w, int h,
+ ColorModel model, byte[] pixels,
+ int off, int scansize
+ ) {
+ setPixels(x, y, w, h, model, pixels, off, scansize, true);
+ }
+
+ @Override
+ public void setPixels(
+ int x, int y,
+ int w, int h,
+ ColorModel model, int[] pixels,
+ int off, int scansize
+ ) {
+ setPixels(x, y, w, h, model, pixels, off, scansize, false);
+ }
+
+ @Override
+ public void imageComplete(int status) {
+ if (status == STATICIMAGEDONE || status == SINGLEFRAMEDONE) {
+ BufferedImage bim = new BufferedImage(cm, raster, cm.isAlphaPremultiplied, null);
+ bim = op.filter(bim, null);
+ DataBuffer dstDb = bim.getRaster().getDataBuffer();
+ ColorModel dstCm = bim.getColorModel();
+ int dstW = bim.getWidth();
+ int dstH = bim.getHeight();
+
+ consumer.setDimensions(dstW, dstH);
+
+ if (dstDb.getDataType() == DataBuffer.TYPE_INT) {
+ consumer.setColorModel(dstCm);
+ consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataInt(dstDb), 0, dstW);
+ } else if (dstDb.getDataType() == DataBuffer.TYPE_BYTE) {
+ consumer.setColorModel(dstCm);
+ consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataByte(dstDb), 0, dstW);
+ } else {
+ int dstData[] = bim.getRGB(0, 0, dstW, dstH, null, 0, dstW);
+ dstCm = ColorModel.getRGBdefault();
+ consumer.setColorModel(dstCm);
+ consumer.setPixels(0, 0, dstW, dstH, dstCm, dstData, 0, dstW);
+ }
+ } else if (status == IMAGEERROR || status == IMAGEABORTED) {
+ reset();
+ }
+
+ consumer.imageComplete(status);
+ }
+
+ /**
+ * Sets the pixels.
+ *
+ * @param x the x
+ * @param y the y
+ * @param w the w
+ * @param h the h
+ * @param model the model
+ * @param pixels the pixels
+ * @param off the off
+ * @param scansize the scansize
+ * @param isByteData the is byte data
+ */
+ private void setPixels(
+ int x, int y,
+ int w, int h,
+ ColorModel model, Object pixels,
+ int off, int scansize, boolean isByteData
+ ) {
+ // Check bounds
+ // Need to copy only the pixels that will fit into the destination area
+ if (x < 0) {
+ w -= x;
+ off += x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h -= y;
+ off += y * scansize;
+ y = 0;
+ }
+
+ if (x + w > width) {
+ w = width - x;
+ }
+
+ if (y + h > height) {
+ h = height - y;
+ }
+
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ // Check model
+ if (this.cm == null) {
+ setColorModel(model);
+ } else if (model == null) {
+ model = this.cm;
+ } else if (!model.equals(this.cm)) {
+ forceRGB();
+ }
+
+ boolean canArraycopy;
+ // Process pixels
+ switch(transferType) {
+ case DataBuffer.TYPE_UNDEFINED: {
+ if (isByteData) {
+ transferType = DataBuffer.TYPE_BYTE;
+ createRaster(transferType);
+ //bData = new byte[width*height];
+ canArraycopy = !forcedRGB;
+ break;
+ }
+ transferType = DataBuffer.TYPE_INT;
+ createRaster(transferType);
+ //iData = new int[width*height];
+ canArraycopy = !forcedRGB || model.equals(ColorModel.getRGBdefault());
+ break;
+ } // And proceed to copy the pixels
+ case DataBuffer.TYPE_INT: {
+ if (isByteData) { // There are int data already but the new data are bytes
+ forceRGB();
+ canArraycopy = false;
+ break;
+ } else if (!forcedRGB || model.equals(ColorModel.getRGBdefault())) {
+ canArraycopy = true;
+ break;
+ } // Else fallback to the RGB conversion
+ }
+ case DataBuffer.TYPE_BYTE: {
+ if (isByteData && !forcedRGB) {
+ canArraycopy = true;
+ break;
+ }
+
+ // RGB conversion
+ canArraycopy = false;
+ break;
+ } default: {
+ throw new IllegalStateException(Messages.getString("awt.06")); //$NON-NLS-1$
+ }
+ }
+
+ off += x;
+ int maxOffset = off + h * scansize;
+ int dstOffset = x + y * width;
+
+ if (canArraycopy) {
+ Object dstArray = isByteData ? (Object) bData : (Object) iData;
+ for (; off < maxOffset; off += scansize, dstOffset += width) {
+ System.arraycopy(pixels, off, dstArray, dstOffset, w);
+ }
+ } else {
+ // RGB conversion
+ for (; off < maxOffset; off += scansize, dstOffset += width) {
+ int srcPos = off;
+ int dstPos = dstOffset;
+ int maxDstPos = dstOffset + w;
+ for (; dstPos < maxDstPos; dstPos++, srcPos++) {
+ iData[dstPos] = model.getRGB(
+ isByteData ?
+ ((byte[])pixels)[srcPos] :
+ ((int[])pixels)[srcPos]
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * Force rgb.
+ */
+ private void forceRGB() {
+ if (!forcedRGB) {
+ forcedRGB = true;
+ int size = width*height;
+ int rgbData[] = new int[size];
+
+ if (bData != null) {
+ for (int i=0; i<size; i++) {
+ rgbData[i] = cm.getRGB(bData[i]);
+ }
+ } else if (iData != null) {
+ for (int i=0; i<size; i++) {
+ rgbData[i] = cm.getRGB(iData[i]);
+ }
+ }
+
+ cm = ColorModel.getRGBdefault();
+ DataBufferInt db = new DataBufferInt(rgbData, size);
+ int masks[] = new int[] {0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000};
+ raster = Raster.createPackedRaster(db, width, height, width, masks, null);
+ iData = accessor.getDataInt(db);
+ bData = null;
+ transferType = DataBuffer.TYPE_INT;
+ }
+ }
+
+ /**
+ * Reset.
+ */
+ private void reset() {
+ width = 0;
+ height = 0;
+ forcedRGB = false;
+ cm = null;
+ iData = null;
+ bData = null;
+ transferType = DataBuffer.TYPE_UNDEFINED;
+ raster = null;
+ }
+
+ /**
+ * Creates the raster.
+ *
+ * @param dataType the data type
+ */
+ private void createRaster(int dataType) {
+ boolean createdValidBuffer = false;
+ try{
+ raster = cm.createCompatibleWritableRaster(width, height);
+ int rasterType = raster.getDataBuffer().getDataType();
+ if (rasterType == dataType) {
+ switch (rasterType) {
+ case DataBuffer.TYPE_INT: {
+ iData = accessor.getDataInt(raster.getDataBuffer());
+ if (iData != null) {
+ createdValidBuffer = true;
+ }
+ break;
+ }
+ case DataBuffer.TYPE_BYTE: {
+ bData = accessor.getDataByte(raster.getDataBuffer());
+ if (bData != null) {
+ createdValidBuffer = true;
+ }
+ break;
+ }
+ default:
+ createdValidBuffer = false;
+ }
+
+ if(cm == ColorModel.getRGBdefault()){
+ forcedRGB = true;
+ }
+ } else {
+ createdValidBuffer = false;
+ }
+ } catch(Exception e) {
+ createdValidBuffer = false;
+ }
+
+ if (createdValidBuffer == false) {
+ cm = ColorModel.getRGBdefault();
+ raster = cm.createCompatibleWritableRaster(width, height);
+ iData = accessor.getDataInt(raster.getDataBuffer());
+ bData = null;
+ forcedRGB = true;
+ }
+ }
+}
diff --git a/awt/java/awt/image/BufferedImageOp.java b/awt/java/awt/image/BufferedImageOp.java
new file mode 100644
index 0000000..85b9f4e
--- /dev/null
+++ b/awt/java/awt/image/BufferedImageOp.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.RenderingHints;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The BufferedImageOp interface provides methods for performing transformations
+ * from source data to destination data for BufferedImage objects. An object
+ * implementing this interface can be passed into a BufferedImageFilter
+ * to operate on a BufferedImage.
+ */
+public interface BufferedImageOp {
+
+ /**
+ * Creates a destination image with the specified BufferedImage and
+ * ColorModel; this destination image is empty and has the correct size
+ * and number of bands.
+ *
+ * @param src the source BufferedImage.
+ * @param destCM the destination ColorModel.
+ *
+ * @return the BufferedImage.
+ */
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM);
+
+ /**
+ * Performs a filter operation on the source BufferedImage and stores
+ * the resulting BufferedImage to the destination BufferedImage. If
+ * the destination BufferedImage is null, a BufferedImage with an
+ * appropriate ColorModel is created.
+ *
+ * @param src the source BufferedImage.
+ * @param dest the destination BufferedImage, where the result is stored.
+ *
+ * @return the filtered BufferedImage.
+ */
+ public BufferedImage filter(BufferedImage src, BufferedImage dest);
+
+ /**
+ * Gets the bounds of filtered image.
+ *
+ * @param src the source BufferedImage to be filtered.
+ *
+ * @return the rectangle bounds of filtered image.
+ */
+ public Rectangle2D getBounds2D(BufferedImage src);
+
+ /**
+ * Gets the point of the destination image which corresponds
+ * to the specified point in the source image.
+ *
+ * @param srcPt the point of the source image.
+ * @param dstPt the point where the result will be stored.
+ *
+ * @return the destination point.
+ */
+ public Point2D getPoint2D(Point2D srcPt, Point2D dstPt);
+
+ /**
+ * Gets the RenderingHints of the BufferedImageOp.
+ *
+ * @return the RenderingHints of the BufferedImageOp.
+ */
+ public RenderingHints getRenderingHints();
+}
diff --git a/awt/java/awt/image/ByteLookupTable.java b/awt/java/awt/image/ByteLookupTable.java
new file mode 100644
index 0000000..043b533
--- /dev/null
+++ b/awt/java/awt/image/ByteLookupTable.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+/**
+ * The ByteLookupTable class provides functionality for lookup operations,
+ * and is defined by an input byte array for bands or components of
+ * image and an offset value.
+ * The offset value will be subtracted from the input values before
+ * indexing the input arrays. The output of a lookup operation is
+ * represented as an array of unsigned bytes.
+ */
+public class ByteLookupTable extends LookupTable {
+
+ /** The data. */
+ private byte data[][];
+
+ /**
+ * Instantiates a new ByteLookupTable with the specified offset value
+ * and the specified byte array which represents the lookup table for
+ * all bands.
+ *
+ * @param offset the offset value.
+ * @param data the data array of bytes.
+ */
+ public ByteLookupTable(int offset, byte[] data) {
+ super(offset, 1);
+ if (data.length < 1)
+ throw new IllegalArgumentException("Length of data should not be less then one");
+ this.data = new byte[1][data.length];
+ // The data array stored as a reference
+ this.data[0] = data;
+ }
+
+ /**
+ * Instantiates a new ByteLookupTable with the specified offset value
+ * and the specified byte array of arrays which represents the lookup table
+ * for each band.
+ *
+ * @param offset the offset value.
+ * @param data the data array of bytes array for each band.
+ */
+ public ByteLookupTable(int offset, byte[][] data) {
+ super(offset, data.length);
+ this.data = new byte[data.length][data[0].length];
+ for (int i = 0; i < data.length; i++) {
+ // The data array for each band stored as a reference
+ this.data[i] = data[i];
+ }
+ }
+
+ /**
+ * Gets the lookup table of this ByteLookupTable object. If
+ * this ByteLookupTable object has one byte array for all bands,
+ * the returned array length is one.
+ *
+ * @return the lookup table of this ByteLookupTable object.
+ */
+ public final byte[][] getTable() {
+ // Returns data by reference
+ return data;
+ }
+
+ @Override
+ public int[] lookupPixel(int[] src, int[] dst) {
+ if (dst == null) {
+ dst = new int[src.length];
+ }
+
+ int offset = getOffset();
+ if (getNumComponents() == 1) {
+ for (int i = 0; i < src.length; i++) {
+ dst[i] = data[0][src[i]-offset];
+ }
+ } else {
+ for (int i = 0; i < getNumComponents(); i++) {
+ dst[i] = data[i][src[i]-offset];
+ }
+ }
+
+ return dst;
+ }
+
+ /**
+ * Returns a byte array which contains samples of the specified
+ * pixel which is translated with the lookup table of this
+ * ByteLookupTable object. The resulted array is stored to
+ * the dst array.
+ *
+ * @param src the source array.
+ * @param dst the destination array where the result can be stored.
+ *
+ * @return the byte array of translated samples of a pixel.
+ */
+ public byte[] lookupPixel(byte[] src, byte[] dst) {
+ if (dst == null) {
+ dst = new byte[src.length];
+ }
+
+ int offset = getOffset();
+ if (getNumComponents() == 1) {
+ for (int i = 0; i < src.length; i++) {
+ dst[i] = data[0][src[i]-offset];
+ }
+ } else {
+ for (int i = 0; i < getNumComponents(); i++) {
+ dst[i] = data[i][src[i]-offset];
+ }
+ }
+
+ return dst;
+ }
+}
diff --git a/awt/java/awt/image/ColorConvertOp.java b/awt/java/awt/image/ColorConvertOp.java
new file mode 100644
index 0000000..6d503d7
--- /dev/null
+++ b/awt/java/awt/image/ColorConvertOp.java
@@ -0,0 +1,711 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package java.awt.image;
+
+
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.RenderingHints;
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.gl.color.ColorConverter;
+import org.apache.harmony.awt.gl.color.ColorScaler;
+import org.apache.harmony.awt.gl.color.ICC_Transform;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ColorConvertOp class converts the pixels of the data in the
+ * source image with the specified ColorSpace objects or an array
+ * of ICC_Profile objects. The result pixels are scaled to the precision
+ * of the destination image.
+ */
+public class ColorConvertOp implements BufferedImageOp, RasterOp {
+ // Unused but required by interfaces
+ /** The rendering hints. */
+ RenderingHints renderingHints;
+
+ // Sequence consisting of ColorSpace and ICC_Profile elements
+ /** The conversion sequence. */
+ Object conversionSequence[] = new ICC_Profile[0]; // To eliminate checks for null
+
+ // Not null if ColorConvertOp is constructed from the array of ICC profiles
+ /** The mid profiles. */
+ private ICC_Profile midProfiles[];
+
+ /** The cc. */
+ private final ColorConverter cc = new ColorConverter();
+
+ /** The t creator. */
+ private final ICC_TransfomCreator tCreator = new ICC_TransfomCreator();
+
+ /** The is icc. */
+ private boolean isICC = true;
+
+
+ // Cached ICC_Transform
+ /**
+ * The Class ICC_TransfomCreator.
+ */
+ private class ICC_TransfomCreator {
+
+ /** The transform. */
+ private ICC_Transform transform;
+
+ /** The max components. */
+ private int maxComponents;
+
+ /**
+ * For the full ICC case.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param convSeq the conv seq
+ *
+ * @return the transform
+ */
+ public ICC_Transform getTransform(ICC_Profile src, ICC_Profile dst, ICC_Profile convSeq[]) {
+ if (transform != null &&
+ src == transform.getSrc() &&
+ dst == transform.getDst()) {
+ return transform;
+ }
+
+ int length = convSeq.length;
+ int srcFlg = 0, dstFlg = 0;
+
+ if (length == 0 || src != convSeq[0]) {
+ if (src != null) {
+ srcFlg = 1; // need src profile
+ }
+ }
+ if (length == 0 || dst != convSeq[length-1]) {
+ if (dst != null) {
+ dstFlg = 1; // need dst profile
+ }
+ }
+
+ ICC_Profile profiles[];
+ int nProfiles = length + srcFlg + dstFlg;
+ if (nProfiles == length) {
+ profiles = convSeq;
+ } else {
+ profiles = new ICC_Profile[nProfiles];
+ int pos = 0;
+ if (srcFlg != 0) {
+ profiles[pos++] = src;
+ }
+ for (int i=0; i<length; i++) {
+ profiles[pos++] = convSeq[i];
+ }
+ if (dstFlg != 0) {
+ profiles[pos++] = dst;
+ }
+ }
+
+ return transform = new ICC_Transform(profiles);
+ }
+
+ /**
+ * Used only when there are non-ICC color spaces.
+ * Returns sequence of non-ICC color spaces and ICC transforms
+ * made from src, dst and conversionSequence.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the sequence
+ */
+ public Object[] getSequence(Object src, Object dst) {
+ ArrayList<Object> profiles = new ArrayList<Object>(10);
+ ArrayList<Object> sequence = new ArrayList<Object>(10);
+
+ // We need this profile anyway
+ ICC_Profile xyzProfile = ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ);
+
+ Object conversionFirst = null, conversionLast = null;
+ int conversionLength = conversionSequence.length;
+ if (conversionLength > 0) {
+ conversionFirst = conversionSequence[0];
+ conversionLast = conversionSequence[conversionLength-1];
+ }
+
+ boolean iccSequenceStarted = false;
+
+ if (src != conversionFirst && src != null) {
+ if (src instanceof ICC_Profile) {
+ profiles.add(src);
+ iccSequenceStarted = true;
+ } else {
+ profiles.add(xyzProfile);
+ sequence.add(src); // Add non-ICC color space to the sequence
+ }
+ } else {
+ profiles.add(xyzProfile);
+ }
+
+ for (int i=0; i<conversionLength; i++) {
+ if (conversionSequence[i] instanceof ICC_Profile) {
+ profiles.add(conversionSequence[i]);
+ iccSequenceStarted = true;
+ } else if (iccSequenceStarted) {
+ profiles.add(xyzProfile);
+
+ // Eliminate same profiles if there are any
+ // (e.g. xyzProfile may occur several times)
+ Object prev = profiles.get(0);
+ for (int k=1; k<profiles.size(); k++) {
+ if (prev == profiles.get(k)) {
+ k--;
+ profiles.remove(k);
+ }
+ prev = profiles.get(k);
+ }
+
+ // If only one profile left we skip the transform -
+ // it can be only CIEXYZ
+ if (profiles.size() > 1) {
+ sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0])));
+
+ // Add non-ICC color space to the sequence
+ sequence.add(conversionSequence[i]);
+ }
+
+ profiles.clear();
+ profiles.add(xyzProfile);
+ iccSequenceStarted = false; // Sequence of ICC profiles is processed
+ } else { // Add non-ICC color space to the sequence
+ sequence.add(conversionSequence[i]);
+ }
+ }
+
+ if (dst != conversionLast && dst != null) { // Add last profile if needed
+ if (dst instanceof ICC_Profile) {
+ profiles.add(dst);
+ iccSequenceStarted = true;
+ } else if (iccSequenceStarted) {
+ profiles.add(xyzProfile);
+ } else {
+ sequence.add(dst); // Add last non-ICC color space to the sequence
+ }
+ }
+
+ if (iccSequenceStarted) { // Make last transform if needed
+ sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0])));
+ if (dst != null && !(dst instanceof ICC_Profile)) {
+ sequence.add(dst); // Add last non-ICC color space to the
+ // sequence
+ }
+ }
+
+ // Calculate max number of components
+ // This number will be used for memory allocation
+ maxComponents = 0;
+ Object o;
+ for (int i=0, size = sequence.size(); i<size; i++) {
+ o = sequence.get(i);
+ if (o instanceof ICC_Transform) {
+ ICC_Transform t = (ICC_Transform) o;
+ maxComponents =
+ (maxComponents > t.getNumInputChannels() + 1) ?
+ maxComponents :
+ t.getNumInputChannels() + 1;
+ maxComponents =
+ (maxComponents > t.getNumOutputChannels() + 1) ?
+ maxComponents :
+ t.getNumOutputChannels() + 1;
+ } else {
+ ColorSpace cs = (ColorSpace) o;
+ maxComponents =
+ (maxComponents > cs.getNumComponents() + 1) ?
+ maxComponents :
+ cs.getNumComponents() + 1;
+ }
+ }
+
+ return sequence.toArray();
+ }
+ }
+
+ /**
+ * Instantiates a new ColorConvertOp object using two specified
+ * ColorSpace objects.
+ *
+ * @param srcCS the source ColorSpace.
+ * @param dstCS the destination ColorSpace.
+ * @param hints the RenderingHints object used for
+ * the color conversion, or null.
+ */
+ public ColorConvertOp(ColorSpace srcCS, ColorSpace dstCS, RenderingHints hints) {
+ if (srcCS == null || dstCS == null) {
+ throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$
+ }
+
+ renderingHints = hints;
+
+ boolean srcICC = srcCS instanceof ICC_ColorSpace;
+ boolean dstICC = dstCS instanceof ICC_ColorSpace;
+
+ if (srcICC && dstICC) {
+ conversionSequence = new ICC_Profile[2];
+ } else {
+ conversionSequence = new Object[2];
+ isICC = false;
+ }
+
+ if (srcICC) {
+ conversionSequence[0] = ((ICC_ColorSpace) srcCS).getProfile();
+ } else {
+ conversionSequence[0] = srcCS;
+ }
+
+ if (dstICC) {
+ conversionSequence[1] = ((ICC_ColorSpace) dstCS).getProfile();
+ } else {
+ conversionSequence[1] = dstCS;
+ }
+ }
+
+ /**
+ * Instantiates a new ColorConvertOp object from the specified
+ * ICC_Profile objects.
+ *
+ * @param profiles the array of ICC_Profile objects.
+ * @param hints the RenderingHints object used for
+ * the color conversion, or null.
+ */
+ public ColorConvertOp(ICC_Profile profiles[], RenderingHints hints) {
+ if (profiles == null) {
+ throw new NullPointerException(Messages.getString("awt.25C")); //$NON-NLS-1$
+ }
+
+ renderingHints = hints;
+
+ // This array is not used in the program logic, so don't need to copy it
+ // Store it only to return back
+ midProfiles = profiles;
+
+ conversionSequence = new ICC_Profile[midProfiles.length];
+
+ // Add profiles to the conversion sequence
+ for (int i=0, length=midProfiles.length; i<length; i++) {
+ conversionSequence[i] = midProfiles[i];
+ }
+ }
+
+ /**
+ * Instantiates a new ColorConvertOp object using the specified
+ * ColorSpace object.
+ *
+ * @param cs the destination ColorSpace or an intermediate ColorSpace.
+ * @param hints the RenderingHints object used for
+ * the color conversion, or null.
+ */
+ public ColorConvertOp(ColorSpace cs, RenderingHints hints) {
+ if (cs == null) {
+ throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$
+ }
+
+ renderingHints = hints;
+
+ if (cs instanceof ICC_ColorSpace) {
+ conversionSequence = new ICC_Profile[1];
+ conversionSequence[0] = ((ICC_ColorSpace) cs).getProfile();
+ } else {
+ conversionSequence = new Object[1];
+ conversionSequence[0] = cs;
+ isICC = false;
+ }
+ }
+
+ /**
+ * Instantiates a new ColorConvertOp object which converts from
+ * a source color space to a destination color space.
+ *
+ * @param hints the RenderingHints object used for
+ * the color conversion, or null.
+ */
+ public ColorConvertOp(RenderingHints hints) {
+ renderingHints = hints;
+ }
+
+ public final WritableRaster filter(Raster src, WritableRaster dst) {
+ if (conversionSequence.length < 2) {
+ throw new IllegalArgumentException(Messages.getString("awt.25D")); //$NON-NLS-1$
+ }
+
+ ICC_Profile srcPf = null, dstPf = null; // unused if isICC is false
+ int nSrcColorComps, nDstColorComps;
+ Object first = conversionSequence[0];
+ Object last = conversionSequence[conversionSequence.length - 1];
+
+ // Get the number of input/output color components
+ if (isICC) {
+ srcPf = (ICC_Profile) first;
+ dstPf = (ICC_Profile) last;
+ nSrcColorComps = srcPf.getNumComponents();
+ nDstColorComps = dstPf.getNumComponents();
+ } else {
+ if (first instanceof ICC_Profile) {
+ srcPf = (ICC_Profile) first;
+ nSrcColorComps = srcPf.getNumComponents();
+ } else {
+ nSrcColorComps = ((ColorSpace) first).getNumComponents();
+ }
+
+ if (last instanceof ICC_Profile) {
+ dstPf = (ICC_Profile) last;
+ nDstColorComps = dstPf.getNumComponents();
+ } else {
+ nDstColorComps = ((ColorSpace) last).getNumComponents();
+ }
+ }
+
+ // Check that source and destination rasters are compatible with
+ // transforms and with each other
+ if (src.getNumBands() != nSrcColorComps) {
+ // awt.25E=Incorrect number of source raster bands. Should be equal
+ // to the number of color components of source colorspace.
+ throw new IllegalArgumentException(Messages.getString("awt.25E")); //$NON-NLS-1$
+ }
+
+ if (dst != null) { // Check destination raster
+ if (dst.getNumBands() !=
+ nDstColorComps) {
+ // awt.25F=Incorrect number of destination raster bands. Should
+ // be equal to the number of color components of destination
+ // colorspace.
+ throw new IllegalArgumentException(Messages.getString("awt.25F")); //$NON-NLS-1$
+ }
+
+ if (src.getWidth() != dst.getWidth() ||
+ src.getHeight() != dst.getHeight()) {
+ throw new IllegalArgumentException(Messages.getString("awt.260")); //$NON-NLS-1$
+ }
+
+ } else {
+ dst = createCompatibleDestRaster(src);
+ }
+
+ if (isICC) {
+ // Create transform
+ ICC_Transform t = tCreator.getTransform(srcPf, dstPf,
+ (ICC_Profile[])conversionSequence);
+ cc.translateColor(t, src, dst);
+ } else {
+ Object[] sequence = tCreator.getSequence(null, null);
+
+ // Get data from the source raster
+ ColorScaler scaler = new ColorScaler();
+ scaler.loadScalingData(src, null);
+ float tmpData[][] = scaler.scaleNormalize(src);
+
+ // Get source and destination color spaces
+ ColorSpace srcCS = (srcPf == null) ?
+ (ColorSpace) first:
+ new ICC_ColorSpace(srcPf);
+ ColorSpace dstCS = (dstPf == null) ?
+ (ColorSpace) last:
+ new ICC_ColorSpace(dstPf);
+
+ applySequence(sequence, tmpData, srcCS, dstCS);
+
+ scaler.loadScalingData(dst, null);
+ scaler.unscaleNormalized(dst, tmpData);
+ }
+
+ return dst;
+ }
+
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
+ // If destination color model is passed only one line needed
+ if (destCM != null) {
+ return new BufferedImage(destCM,
+ destCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()),
+ destCM.isAlphaPremultiplied(),
+ null);
+ }
+
+ int nSpaces = conversionSequence.length;
+
+ if (nSpaces < 1) {
+ throw new IllegalArgumentException(Messages.getString("awt.261")); //$NON-NLS-1$
+ }
+
+ // Get destination color space
+ Object destination = conversionSequence[nSpaces-1];
+ ColorSpace dstCS =
+ (destination instanceof ColorSpace) ?
+ (ColorSpace) destination :
+ new ICC_ColorSpace((ICC_Profile) destination);
+
+ ColorModel srcCM = src.getColorModel();
+ ColorModel dstCM = new ComponentColorModel(dstCS,
+ srcCM.hasAlpha(),
+ srcCM.isAlphaPremultiplied(),
+ srcCM.getTransparency(),
+ srcCM.getTransferType());
+
+ return new BufferedImage(dstCM,
+ destCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()),
+ destCM.isAlphaPremultiplied(),
+ null);
+ }
+
+ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ if (dst == null && conversionSequence.length < 1) {
+ throw new IllegalArgumentException(Messages.getString("awt.262")); //$NON-NLS-1$
+ }
+
+ ColorModel srcCM = src.getColorModel();
+ // First handle index color model
+ if (srcCM instanceof IndexColorModel) {
+ src = ((IndexColorModel) srcCM).convertToIntDiscrete(src.getRaster(), false);
+ }
+ ColorSpace srcCS = srcCM.getColorSpace();
+
+ BufferedImage res;
+ boolean isDstIndex = false;
+ if (dst != null) {
+
+ if (src.getWidth() != dst.getWidth() ||
+ src.getHeight() != dst.getHeight()) {
+ throw new IllegalArgumentException(Messages.getString("awt.263")); //$NON-NLS-1$
+ }
+
+ if (dst.getColorModel() instanceof IndexColorModel) {
+ isDstIndex = true;
+ res = createCompatibleDestImage(src, null);
+ } else {
+ res = dst;
+ }
+ } else {
+ res = createCompatibleDestImage(src, null);
+ }
+ ColorModel dstCM = res.getColorModel();
+ ColorSpace dstCS = dstCM.getColorSpace();
+
+ ICC_Profile srcPf = null, dstPf = null;
+ if (srcCS instanceof ICC_ColorSpace) {
+ srcPf = ((ICC_ColorSpace)srcCS).getProfile();
+ }
+ if (dstCS instanceof ICC_ColorSpace) {
+ dstPf = ((ICC_ColorSpace)dstCS).getProfile();
+ }
+
+ boolean isFullICC = isICC && srcPf != null && dstPf != null;
+
+ if (isFullICC) {
+ ICC_Transform t =
+ tCreator.getTransform(srcPf, dstPf, (ICC_Profile[]) conversionSequence);
+ cc.translateColor(t, src, res);
+ } else { // Perform non-ICC transform
+ Object sequence[] = tCreator.getSequence(
+ srcPf == null ? (Object) srcCS : srcPf,
+ dstPf == null ? (Object) dstCS : dstPf);
+
+ int srcW = src.getWidth();
+ int srcH = src.getHeight();
+ int numPixels = srcW*srcH;
+
+ // Load all pixel data into array tmpData
+ float tmpData[][] =
+ new float[numPixels][tCreator.maxComponents];
+ for (int row=0, dataPos=0; row<srcW; row++) {
+ for (int col=0; col<srcH; col++) {
+ tmpData[dataPos] =
+ srcCM.getNormalizedComponents(
+ src.getRaster().getDataElements(row, col, null),
+ tmpData[dataPos], 0);
+ dataPos++;
+ }
+ }
+
+ // Copy alpha channel if needed
+ float alpha[] = null;
+ int alphaIdx = srcCM.numComponents - 1;
+ if (srcCM.hasAlpha() && dstCM.hasAlpha()) {
+ alpha = new float[numPixels];
+ for (int i=0; i<numPixels; i++) {
+ alpha[i] = tmpData[i][alphaIdx];
+ }
+ }
+
+ // Translate colors
+ applySequence(sequence, tmpData, srcCS, dstCS);
+
+ // Copy alpha if needed
+ if (dstCM.hasAlpha()) {
+ alphaIdx = dstCM.numComponents - 1;
+ if (alpha != null) {
+ for (int i=0; i<numPixels; i++) {
+ tmpData[i][alphaIdx] = alpha[i];
+ }
+ } else {
+ for (int i=0; i<numPixels; i++) {
+ tmpData[i][alphaIdx] = 1f;
+ }
+ }
+ }
+
+ // Store data back to the image
+ for (int row=0, dataPos=0; row<srcW; row++) {
+ for (int col=0; col<srcH; col++) {
+ res.getRaster().setDataElements(row, col,
+ dstCM.getDataElements(tmpData[dataPos++], 0 , null));
+ }
+ }
+ }
+
+ if (isDstIndex) { // Convert image into indexed color
+ Graphics2D g2d = dst.createGraphics();
+ g2d.drawImage(res, 0, 0, null);
+ g2d.dispose();
+ return dst;
+ }
+
+ return res;
+ }
+
+ /**
+ * Apply sequence.
+ *
+ * @param sequence the sequence
+ * @param tmpData the tmp data
+ * @param srcCS the src cs
+ * @param dstCS the dst cs
+ */
+ private void applySequence(
+ Object sequence[],
+ float tmpData[][],
+ ColorSpace srcCS,
+ ColorSpace dstCS
+ ) {
+ ColorSpace xyzCS = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
+
+ int numPixels = tmpData.length;
+
+ // First transform...
+ if (sequence[0] instanceof ICC_Transform) { // ICC
+ ICC_Transform t = (ICC_Transform)sequence[0];
+ cc.translateColor(t, tmpData, srcCS, xyzCS, numPixels);
+ } else { // non ICC
+ for (int k=0; k<numPixels; k++) {
+ tmpData[k] = srcCS.toCIEXYZ(tmpData[k]);
+ }
+ cc.loadScalingData(xyzCS); // prepare for scaling XYZ
+ }
+
+ for (Object element : sequence) {
+ if (element instanceof ICC_Transform) {
+ ICC_Transform t = (ICC_Transform)element;
+ cc.translateColor(t, tmpData, null, null, numPixels);
+ } else {
+ ColorSpace cs = (ColorSpace) element;
+ for (int k=0; k<numPixels; k++) {
+ tmpData[k] = cs.fromCIEXYZ(tmpData[k]);
+ tmpData[k] = cs.toCIEXYZ(tmpData[k]);
+ }
+ }
+ }
+
+ // Last transform...
+ if (sequence[sequence.length-1] instanceof ICC_Transform) { // ICC
+ ICC_Transform t = (ICC_Transform)sequence[sequence.length-1];
+ cc.translateColor(t, tmpData, xyzCS, dstCS, numPixels);
+ } else { // non ICC
+ for (int k=0; k<numPixels; k++) {
+ tmpData[k] = dstCS.fromCIEXYZ(tmpData[k]);
+ }
+ }
+ }
+
+ public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+ if (dstPt != null) {
+ dstPt.setLocation(srcPt);
+ return dstPt;
+ }
+ return new Point2D.Float((float) srcPt.getX(), (float) srcPt.getY());
+ }
+
+ public WritableRaster createCompatibleDestRaster(Raster src) {
+ int nComps = 0;
+ int nSpaces = conversionSequence.length;
+
+ if (nSpaces < 2) {
+ throw new IllegalArgumentException(Messages.getString("awt.261")); //$NON-NLS-1$
+ }
+
+ Object lastCS = conversionSequence[nSpaces-1];
+ if (lastCS instanceof ColorSpace) {
+ nComps = ((ColorSpace) lastCS).getNumComponents();
+ } else {
+ nComps = ((ICC_Profile) lastCS).getNumComponents();
+ }
+
+ // Calculate correct data type
+ int dstDataType = src.getDataBuffer().getDataType();
+ if (dstDataType != DataBuffer.TYPE_BYTE &&
+ dstDataType != DataBuffer.TYPE_SHORT) {
+ dstDataType = DataBuffer.TYPE_SHORT;
+ }
+
+ return Raster.createInterleavedRaster(
+ dstDataType,
+ src.getWidth(),
+ src.getHeight(),
+ nComps,
+ new Point(src.getMinX(), src.getMinY())
+ );
+ }
+
+ public final Rectangle2D getBounds2D(Raster src) {
+ return src.getBounds();
+ }
+
+ public final Rectangle2D getBounds2D(BufferedImage src) {
+ return src.getRaster().getBounds();
+ }
+
+ /**
+ * Gets an array of ICC_Profiles objects which constructs
+ * this ColorConvertOp object or returns null if this ColorConvertOp
+ * is not constructed from array of ICC_Profiles.
+ *
+ * @return an array of ICC_Profiles objects which constructs
+ * this ColorConvertOp object or returns null if this ColorConvertOp
+ * is not constructed from array of ICC_Profiles.
+ */
+ public final ICC_Profile[] getICC_Profiles() {
+ if (midProfiles != null) {
+ return midProfiles;
+ }
+ return null;
+ }
+
+ public final RenderingHints getRenderingHints() {
+ return renderingHints;
+ }
+}
diff --git a/awt/java/awt/image/ColorModel.java b/awt/java/awt/image/ColorModel.java
new file mode 100644
index 0000000..945c087
--- /dev/null
+++ b/awt/java/awt/image/ColorModel.java
@@ -0,0 +1,911 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class ColorModel.
+ */
+public abstract class ColorModel implements Transparency {
+
+ /** The pixel_bits. */
+ protected int pixel_bits; // Pixel length in bits
+
+ /** The transfer type. */
+ protected int transferType;
+
+ /** The cs. */
+ ColorSpace cs;
+
+ /** The has alpha. */
+ boolean hasAlpha;
+
+ /** The is alpha premultiplied. */
+ boolean isAlphaPremultiplied;
+
+ /** The transparency. */
+ int transparency;
+
+ /** The num color components. */
+ int numColorComponents;
+
+ /** The num components. */
+ int numComponents;
+
+ /** The bits. */
+ int[] bits; // Array of components masks
+
+ /** The max values. */
+ int[] maxValues = null; // Max values that may be represent by color
+ // components
+
+ /** The max bit length. */
+ int maxBitLength; // Max length color components in bits
+
+ /** The RG bdefault. */
+ private static ColorModel RGBdefault;
+
+ /**
+ * Instantiates a new color model with the specified values.
+ *
+ * @param pixel_bits the pixel length in bits
+ * @param bits the array of component masks
+ * @param cspace the colorspace
+ * @param hasAlpha whether the color model has alpha
+ * @param isAlphaPremultiplied whether the alpha is premultiplied
+ * @param transparency the transparency strategy, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ */
+ protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace,
+ boolean hasAlpha, boolean isAlphaPremultiplied, int transparency,
+ int transferType) {
+
+ if (pixel_bits < 1) {
+ // awt.26B=The number of bits in the pixel values is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.26B")); //$NON-NLS-1$
+ }
+
+ if (bits == null) {
+ // awt.26C=bits is null
+ throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$
+ }
+
+ int sum = 0;
+ for (int element : bits) {
+ if (element < 0) {
+ // awt.26D=The elements in bits is less than 0
+ throw new IllegalArgumentException(Messages.getString("awt.26D")); //$NON-NLS-1$
+ }
+ sum += element;
+ }
+
+ if (sum < 1) {
+ // awt.26E=The sum of the number of bits in bits is less than 1
+ throw new NullPointerException(Messages.getString("awt.26E")); //$NON-NLS-1$
+ }
+
+ if (cspace == null) {
+ // awt.26F=The cspace is null
+ throw new IllegalArgumentException(Messages.getString("awt.26F")); //$NON-NLS-1$
+ }
+
+ if (transparency < Transparency.OPAQUE ||
+ transparency > Transparency.TRANSLUCENT) {
+ // awt.270=The transparency is not a valid value
+ throw new IllegalArgumentException(Messages.getString("awt.270")); //$NON-NLS-1$
+ }
+
+ this.pixel_bits = pixel_bits;
+ this.bits = bits.clone();
+
+ maxValues = new int[bits.length];
+ maxBitLength = 0;
+ for (int i = 0; i < maxValues.length; i++) {
+ maxValues[i] = (1 << bits[i]) - 1;
+ if (bits[i] > maxBitLength) {
+ maxBitLength = bits[i];
+ }
+ }
+
+ cs = cspace;
+ this.hasAlpha = hasAlpha;
+ this.isAlphaPremultiplied = isAlphaPremultiplied;
+ numColorComponents = cs.getNumComponents();
+
+ if (hasAlpha) {
+ numComponents = numColorComponents + 1;
+ } else {
+ numComponents = numColorComponents;
+ }
+
+ this.transparency = transparency;
+ this.transferType = transferType;
+
+ }
+
+ /**
+ * Instantiates a new color model with the specified pixel bit depth.
+ * The transferType is chosen based on the pixel bits, and the other
+ * data fields are given default values.
+ *
+ * @param bits the array of component masks
+ */
+ public ColorModel(int bits) {
+
+ if (bits < 1) {
+ // awt.271=The number of bits in bits is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.271")); //$NON-NLS-1$
+ }
+
+ pixel_bits = bits;
+ transferType = getTransferType(bits);
+ cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+ hasAlpha = true;
+ isAlphaPremultiplied = false;
+ transparency = Transparency.TRANSLUCENT;
+
+ numColorComponents = 3;
+ numComponents = 4;
+
+ this.bits = null;
+ }
+
+ /**
+ * Gets the data elements from the specified component array, transforming
+ * them according to rules of the color model.
+ *
+ * @param components the components
+ * @param offset the offset in the normComponents array
+ * @param obj the array that the result is written to: an array of values
+ * whose length must be the number of components used by the color model and
+ * whose type depends on the transfer type (based on the pixel bit depth),
+ * or null to have the appropriate array created
+ *
+ * @return the array of data elements
+ */
+ public Object getDataElements(int[] components, int offset, Object obj) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the data elements from the specified array of normalized components.
+ *
+ * @param normComponents the array normalized components
+ * @param normOffset the offset in the normComponents array
+ * @param obj the array that the result is written to: an array of values
+ * whose length must be the number of components used by the color model and
+ * whose type depends on the transfer type (based on the pixel bit depth),
+ * or null to have the appropriate array created
+ *
+ * @return the array of data elements
+ */
+ public Object getDataElements(float[] normComponents, int normOffset,
+ Object obj) {
+ int unnormComponents[] = getUnnormalizedComponents(normComponents,
+ normOffset, null, 0);
+ return getDataElements(unnormComponents, 0, obj);
+ }
+
+ /**
+ * Gets the data elements corresponding to the pixel determined by the
+ * RGB data.
+ *
+ * @param rgb the rgb int that defines the pixel
+ * @param pixel the array that the result is written to: an array of values
+ * whose length must be the number of components used by the color model and
+ * whose type depends on the transfer type (based on the pixel bit depth),
+ * or null to have the appropriate array created
+ *
+ * @return the array of data elements
+ */
+ public Object getDataElements(int rgb, Object pixel) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the child raster corresponding to the alpha channel of the
+ * specified writable raster, or null if alpha is not supported.
+ *
+ * @param raster the raster
+ *
+ * @return the alpha raster
+ */
+ public WritableRaster getAlphaRaster(WritableRaster raster) {
+ return null;
+ }
+
+ /**
+ * Creates a new color model by coercing the data in the writable raster
+ * in accordance with the alpha strategy of this color model.
+ *
+ * @param raster the raster
+ * @param isAlphaPremultiplied whether the alpha is premultiplied in this
+ * color model
+ *
+ * @return the new color model
+ */
+ public ColorModel coerceData(WritableRaster raster,
+ boolean isAlphaPremultiplied) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour.
+ // It could be reveled such way:
+ // ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB,
+ // false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
+ // System.out.println(cm.toString());
+ return "ColorModel: Color Space = " + cs.toString() + "; has alpha = " //$NON-NLS-1$ //$NON-NLS-2$
+ + hasAlpha + "; is alpha premultipied = " //$NON-NLS-1$
+ + isAlphaPremultiplied + "; transparency = " + transparency //$NON-NLS-1$
+ + "; number color components = " + numColorComponents //$NON-NLS-1$
+ + "; pixel bits = " + pixel_bits + "; transfer type = " //$NON-NLS-1$ //$NON-NLS-2$
+ + transferType;
+ }
+
+ /**
+ * Gets the components of the pixel determined by the data array.
+ *
+ * @param pixel the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ * @param components the the array where the resulting components
+ * are written (or null to prompt the method to create the return array)
+ * @param offset the offset that tells where the results should be written
+ * in the return array
+ *
+ * @return the array of components
+ */
+ public int[] getComponents(Object pixel, int[] components, int offset) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the normalized components of the pixel determined by the data array.
+ *
+ * @param pixel the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ * @param normComponents the array where the resulting normalised components
+ * are written (or null to prompt the method to create the return array)
+ * @param normOffset the offset that tells where the results should be written
+ * in the return array
+ *
+ * @return the array of normalized components
+ */
+ public float[] getNormalizedComponents(Object pixel,
+ float[] normComponents, int normOffset) {
+
+ if (pixel == null) {
+ // awt.294=pixel is null
+ throw new NullPointerException(Messages.getString("awt.294")); //$NON-NLS-1$
+ }
+
+ int unnormComponents[] = getComponents(pixel, null, 0);
+ return getNormalizedComponents(unnormComponents, 0, normComponents,
+ normOffset);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ColorModel)) {
+ return false;
+ }
+ ColorModel cm = (ColorModel) obj;
+
+ return (pixel_bits == cm.getPixelSize() &&
+ transferType == cm.getTransferType() &&
+ cs.getType() == cm.getColorSpace().getType() &&
+ hasAlpha == cm.hasAlpha() &&
+ isAlphaPremultiplied == cm.isAlphaPremultiplied() &&
+ transparency == cm.getTransparency() &&
+ numColorComponents == cm.getNumColorComponents() &&
+ numComponents == cm.getNumComponents() &&
+ Arrays.equals(bits, cm.getComponentSize()));
+ }
+
+ /**
+ * Gets the red component of the pixel determined by the data array.
+ *
+ * @param inData the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ *
+ * @return the red
+ */
+ public int getRed(Object inData) {
+ return getRed(constructPixel(inData));
+ }
+
+ /**
+ * Gets the RGB int corresponding to the pixel defined by the data array.
+ *
+ * @param inData the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ *
+ * @return the int that gives the pixel's colors in RGB format
+ */
+ public int getRGB(Object inData) {
+ return (getAlpha(inData) << 24 | getRed(inData) << 16 |
+ getGreen(inData) << 8 | getBlue(inData));
+ }
+
+ /**
+ * Gets the green component of the pixel defined by the data array.
+ *
+ * @param inData the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ *
+ * @return the green
+ */
+ public int getGreen(Object inData) {
+ return getGreen(constructPixel(inData));
+ }
+
+ /**
+ * Gets the blue component of the pixel defined by the data array.
+ *
+ * @param inData the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ *
+ * @return the blue
+ */
+ public int getBlue(Object inData) {
+ return getBlue(constructPixel(inData));
+ }
+
+ /**
+ * Gets the alpha component of the pixel defined by the data array.
+ *
+ * @param inData the data array that defines the pixel (whose
+ * primitive type corresponds to the pixel length in bits,
+ * @see ColorModel#getTransferType()
+ *
+ * @return the alpha
+ */
+ public int getAlpha(Object inData) {
+ return getAlpha(constructPixel(inData));
+ }
+
+ /**
+ * Creates a compatible writable raster.
+ *
+ * @param w the width of the desired writable raster
+ * @param h the height of the desired writable raster
+ *
+ * @return the writable raster
+ */
+ public WritableRaster createCompatibleWritableRaster(int w, int h) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if the sample model is compatible with this color model.
+ *
+ * @param sm the sample model
+ *
+ * @return true, if the sample model is compatible with this color model
+ */
+ public boolean isCompatibleSampleModel(SampleModel sm) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates the compatible sample model.
+ *
+ * @param w the width of the desired sample model
+ * @param h the height of the desired sample model
+ *
+ * @return the sample model
+ */
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Checks if the specified raster is compatible with this color model.
+ *
+ * @param raster the raster to inspect
+ *
+ * @return true, if the raster is compatible with this color model
+ */
+ public boolean isCompatibleRaster(Raster raster) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the color space of this color model.
+ *
+ * @return the color space
+ */
+ public final ColorSpace getColorSpace() {
+ return cs;
+ }
+
+ /**
+ * Gets the normalized components corresponding to the specified
+ * unnormalized components.
+ *
+ * @param components the array of unnormalized components
+ * @param offset the offset where the components should be read
+ * from the array of unnormalized components
+ * @param normComponents the array where the resulting normalised components
+ * are written (or null to prompt the method to create the return array)
+ * @param normOffset the offset that tells where the results should be written
+ * in the return array
+ *
+ * @return the normalized components
+ */
+ public float[] getNormalizedComponents(int[] components, int offset,
+ float normComponents[], int normOffset) {
+ if (bits == null) {
+ // awt.26C=bits is null
+ throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$
+ }
+
+ if (normComponents == null) {
+ normComponents = new float[numComponents + normOffset];
+ }
+
+ if (hasAlpha && isAlphaPremultiplied) {
+ float normAlpha =
+ (float) components[offset + numColorComponents] /
+ maxValues[numColorComponents];
+ if (normAlpha != 0.0f) {
+ for (int i = 0; i < numColorComponents; i++) {
+ normComponents[normOffset + i] =
+ components[offset + i] /
+ (normAlpha * maxValues[i]);
+ }
+ normComponents[normOffset + numColorComponents] = normAlpha;
+ } else {
+ for (int i = 0; i < numComponents; i++) {
+ normComponents[normOffset + i] = 0.0f;
+ }
+ }
+ } else {
+ for (int i = 0; i < numComponents; i++) {
+ normComponents[normOffset + i] =
+ (float) components[offset + i] /
+ maxValues[i];
+ }
+ }
+
+ return normComponents;
+ }
+
+ /**
+ * Gets the data element corresponding to the unnormalized components.
+ *
+ * @param components the components
+ * @param offset the offset to start reading the components from the
+ * array of components
+ *
+ * @return the data element
+ */
+ public int getDataElement(int[] components, int offset) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the unnormalized components corresponding to the specified
+ * normalized components.
+ *
+ * @param normComponents the array of normalized components
+ * @param normOffset the offset where the components should be read
+ * from the array of normalized components
+ * @param components the array where the resulting unnormalised components
+ * are written (or null to prompt the method to create the return array)
+ * @param offset the offset that tells where the results should be written
+ * in the return array
+ *
+ * @return the unnormalized components
+ */
+ public int[] getUnnormalizedComponents(float normComponents[],
+ int normOffset, int components[], int offset) {
+
+ if (bits == null) {
+ // awt.26C=bits is null
+ throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$
+ }
+
+ if (normComponents.length - normOffset < numComponents) {
+ // awt.273=The length of normComponents minus normOffset is less than numComponents
+ throw new IllegalArgumentException(Messages.getString("awt.273")); //$NON-NLS-1$
+ }
+
+ if (components == null) {
+ components = new int[numComponents + offset];
+ } else {
+ if (components.length - offset < numComponents) {
+ // awt.272=The length of components minus offset is less than numComponents
+ throw new IllegalArgumentException(Messages.getString("awt.272")); //$NON-NLS-1$
+ }
+ }
+
+ if (hasAlpha && isAlphaPremultiplied) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ components[offset + i] = (int) (normComponents[normOffset + i]
+ * maxValues[i] * alpha + 0.5f);
+ }
+ components[offset + numColorComponents] =
+ (int) (normComponents[normOffset + numColorComponents] *
+ maxValues[numColorComponents] + 0.5f);
+ } else {
+ for (int i = 0; i < numComponents; i++) {
+ components[offset + i] =
+ (int) (normComponents[normOffset + i] *
+ maxValues[i] + 0.5f);
+ }
+ }
+
+ return components;
+ }
+
+ /**
+ * Gets the data element corresponding to the normalized components.
+ *
+ * @param normComponents the normalized components
+ * @param normOffset the offset where the normalized components should
+ * be read from the normalized component array
+ *
+ * @return the data element
+ */
+ public int getDataElement(float normComponents[], int normOffset) {
+ int unnormComponents[] = getUnnormalizedComponents(normComponents,
+ normOffset, null, 0);
+ return getDataElement(unnormComponents, 0);
+ }
+
+ /**
+ * Takes a pixel whose data is defined by an int, and writes the
+ * corresponding components into the components array, starting
+ * from the index offset.
+ *
+ * @param pixel the pixel data
+ * @param components the data array to write the components to (or
+ * null to have the method create the return array)
+ * @param offset the offset that determines where the results are
+ * written in the components array
+ *
+ * @return the array of components corresponding to the pixel
+ */
+ public int[] getComponents(int pixel, int components[], int offset) {
+ throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$
+ "supported by this ColorModel"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the red component of the pixel determined by the pixel data.
+ *
+ * @param pixel the pixel data
+ *
+ * @return the red component of the pixel
+ */
+ public abstract int getRed(int pixel);
+
+ /**
+ * Takes the pixel data and returns the int corresponding
+ * to the pixel's color in RGB format.
+ *
+ * @param pixel the pixel data
+ *
+ * @return the corresponding RGB int
+ */
+ public int getRGB(int pixel) {
+ return (getAlpha(pixel) << 24 | getRed(pixel) << 16
+ | getGreen(pixel) << 8 | getBlue(pixel));
+ }
+
+ /**
+ * Gets the green component of the pixel determined by the pixel data.
+ *
+ * @param pixel the pixel data
+ *
+ * @return the green component of the pixel
+ */
+ public abstract int getGreen(int pixel);
+
+ /**
+ * Gets the size of the desired component of this color model.
+ *
+ * @param componentIdx the index that determines which component size to get
+ *
+ * @return the component size corresponding to the index
+ *
+ * @throws NullPointerException if this color model doesn't support
+ * an array of separate components.
+ * @throws ArrayIndexOutOfBoundsException if the index is negative or
+ * greater than or equal to the number of components
+ */
+ public int getComponentSize(int componentIdx) {
+ if (bits == null) {
+ // awt.26C=bits is null
+ throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$
+ }
+
+ if (componentIdx < 0 || componentIdx >= bits.length) {
+ // awt.274=componentIdx is greater than the number of components or less than zero
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.274")); //$NON-NLS-1$
+ }
+
+ return bits[componentIdx];
+ }
+
+ /**
+ * Gets the blue component of the pixel determined by the pixel data.
+ *
+ * @param pixel the pixel
+ *
+ * @return the blue component of the pixel
+ */
+ public abstract int getBlue(int pixel);
+
+ /**
+ * Gets the alpha component of the pixel determined by the pixel data.
+ *
+ * @param pixel the pixel
+ *
+ * @return the alpha component of the pixel
+ */
+ public abstract int getAlpha(int pixel);
+
+ /**
+ * Gets the array of sizes of the different components.
+ *
+ * @return the array of sizes of the different components
+ */
+ public int[] getComponentSize() {
+ if (bits != null) {
+ return bits.clone();
+ }
+ return null;
+ }
+
+ /**
+ * Checks if the alpha component is premultiplied.
+ *
+ * @return true, if the alpha component is premultiplied
+ */
+ public final boolean isAlphaPremultiplied() {
+ return isAlphaPremultiplied;
+ }
+
+ /**
+ * Checks whether this color model supports alpha.
+ *
+ * @return true, if this color model has alpha
+ */
+ public final boolean hasAlpha() {
+ return hasAlpha;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ int tmp;
+
+ if (hasAlpha) {
+ hash ^= 1;
+ hash <<= 8;
+ }
+ if (isAlphaPremultiplied) {
+ hash ^= 1;
+ hash <<= 8;
+ }
+
+ tmp = hash >>> 24;
+ hash ^= numColorComponents;
+ hash <<= 8;
+ hash |= tmp;
+
+ tmp = hash >>> 24;
+ hash ^= transparency;
+ hash <<= 8;
+ hash |= tmp;
+
+ tmp = hash >>> 24;
+ hash ^= cs.getType();
+ hash <<= 8;
+ hash |= tmp;
+
+ tmp = hash >>> 24;
+ hash ^= pixel_bits;
+ hash <<= 8;
+ hash |= tmp;
+
+ tmp = hash >>> 24;
+ hash ^= transferType;
+ hash <<= 8;
+ hash |= tmp;
+
+ if (bits != null) {
+
+ for (int element : bits) {
+ tmp = hash >>> 24;
+ hash ^= element;
+ hash <<= 8;
+ hash |= tmp;
+ }
+
+ }
+
+ return hash;
+ }
+
+ public int getTransparency() {
+ return transparency;
+ }
+
+ /**
+ * Gets the transfer type, which is the type of Java primitive
+ * value that corresponds to the bit length per pixel: either
+ * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT},
+ * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}.
+ *
+ * @return the transfer type
+ */
+ public final int getTransferType() {
+ return transferType;
+ }
+
+ /**
+ * Gets the pixel size in bits.
+ *
+ * @return the pixel size
+ */
+ public int getPixelSize() {
+ return pixel_bits;
+ }
+
+ /**
+ * Gets the number of components of this color model.
+ *
+ * @return the number of components
+ */
+ public int getNumComponents() {
+ return numComponents;
+ }
+
+ /**
+ * Gets the number of color components of this color model.
+ *
+ * @return the number color components
+ */
+ public int getNumColorComponents() {
+ return numColorComponents;
+ }
+
+ /**
+ * Gets the default RGB color model.
+ *
+ * @return the default RGB color model
+ */
+ public static ColorModel getRGBdefault() {
+ if (RGBdefault == null) {
+ RGBdefault = new DirectColorModel(32, 0x00ff0000, 0x0000ff00,
+ 0x000000ff, 0xff000000);
+ }
+ return RGBdefault;
+ }
+
+ /*
+ * Construct INT pixel representation from Object
+ * @param obj
+ *
+ * @return
+ */
+ /**
+ * Construct pixel.
+ *
+ * @param obj the obj
+ *
+ * @return the int
+ */
+ private int constructPixel(Object obj) {
+ int pixel = 0;
+
+ switch (getTransferType()) {
+
+ case DataBuffer.TYPE_BYTE:
+ byte[] bPixel = (byte[]) obj;
+ if(bPixel.length > 1) {
+ // awt.275=This pixel representation is not suuported by tis Color Model
+ throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$
+ }
+ pixel = bPixel[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short[] sPixel = (short[]) obj;
+ if(sPixel.length > 1) {
+ // awt.275=This pixel representation is not suuported by tis Color Model
+ throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$
+ }
+ pixel = sPixel[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int[] iPixel = (int[]) obj;
+ if(iPixel.length > 1) {
+ // awt.275=This pixel representation is not suuported by tis Color Model
+ throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$
+ }
+ pixel = iPixel[0];
+ break;
+
+ default:
+ // awt.22D=This transferType ( {0} ) is not supported by this color model
+ throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$
+ transferType));
+
+ }
+ return pixel;
+ }
+
+ /**
+ * Gets the transfer type, which is the type of Java primitive
+ * value that corresponds to the bit length per pixel: either
+ * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT},
+ * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}.
+ *
+ * @param bits the array of component masks
+ *
+ * @return the transfer type
+ */
+ static int getTransferType(int bits) {
+ if (bits <= 8) {
+ return DataBuffer.TYPE_BYTE;
+ } else if (bits <= 16) {
+ return DataBuffer.TYPE_USHORT;
+ } else if (bits <= 32) {
+ return DataBuffer.TYPE_INT;
+ } else {
+ return DataBuffer.TYPE_UNDEFINED;
+ }
+ }
+
+ @Override
+ public void finalize() {
+ // This method is added for the API compatibility
+ // Don't need to call super since Object's finalize is always empty
+ }
+}
diff --git a/awt/java/awt/image/ComponentColorModel.java b/awt/java/awt/image/ComponentColorModel.java
new file mode 100644
index 0000000..a152f55
--- /dev/null
+++ b/awt/java/awt/image/ComponentColorModel.java
@@ -0,0 +1,1471 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.color.ColorSpace;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class ComponentColorModel represents a color model that is defined
+ * in terms of its components.
+ */
+public class ComponentColorModel extends ColorModel {
+
+ /** The signed. */
+ private boolean signed; // Pixel samples are signed.
+ // Samples with TransferType DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT -
+ // unsigned. Samples with others TransferType -
+ // signed.
+
+ /** The integral. */
+ private boolean integral; // Pixel samples are integral.
+ // Samples with TransferType DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT, DataBuffer.Short and
+ // DataBuffer.TYPE_INT - integral.
+
+ /** The scale factors. */
+ private float scaleFactors[]; // Array of factors for reduction components
+ // values into the form scaled from 0 to 255
+
+ /** The donot support unnormalized. */
+ private boolean donotSupportUnnormalized; // This Color Model don't support
+ // unnormolized form
+
+ /** The need alpha divide. */
+ private boolean needAlphaDivide; // hasAlpha && isAlphaPremultiplied
+
+ /** The calc value. */
+ private boolean calcValue; // Value was culculated
+
+ /** The need scale. */
+ private boolean needScale; // Normalized value need to scale
+
+ /** The min vals. */
+ private float minVals[]; // Array of Min normalized values
+
+ /** The ranges. */
+ private float ranges[]; // Array of range normalized values
+
+ /** The alpha lut. */
+ private byte alphaLUT[]; // Lookup table for scale alpha value
+
+ /** The color lu ts. */
+ private byte colorLUTs[][]; // Lookup tables for scale color values
+
+ /** The from_ linea r_ rg b_ lut. */
+ private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from
+ // Linear RGB Color Space into sRGB
+
+ /** The to_ linea r_8 rg b_ lut. */
+ private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from
+ // sRGB Color Space into Linear RGB
+ // 8 bit
+
+ /** The to_ linea r_16 rg b_ lut. */
+ private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from
+ // sRGB Color Space into Linear RGB
+ // 16 bit
+
+ /** The LINEA r_ rg b_ length. */
+ private int LINEAR_RGB_Length; // Linear RGB bit length
+
+ /** The factor. */
+ private float fFactor; // Scale factor
+
+ /** The is_s rgb. */
+ private boolean is_sRGB; // ColorModel has sRGB ColorSpace
+
+ /** The is_ linea r_ rgb. */
+ private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color
+ // Space
+
+ /**
+ * Instantiates a new component color model.
+ *
+ * @param colorSpace the color space
+ * @param bits the array of component masks
+ * @param hasAlpha whether the color model has alpha
+ * @param isAlphaPremultiplied whether the alpha is premultiplied
+ * @param transparency the transparency strategy, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ */
+ public ComponentColorModel(ColorSpace colorSpace, int bits[],
+ boolean hasAlpha, boolean isAlphaPremultiplied, int transparency,
+ int transferType) {
+ super(createPixelBits(colorSpace, hasAlpha, transferType),
+ validateBits(bits, colorSpace, hasAlpha, transferType),
+ colorSpace, hasAlpha, isAlphaPremultiplied, transparency,
+ transferType);
+
+ needScale = false;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ signed = false;
+ integral = true;
+ donotSupportUnnormalized = false;
+ scaleFactors = new float[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ scaleFactors[i] = 1.0f / maxValues[i];
+ if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) {
+ donotSupportUnnormalized = true;
+ }
+ }
+ if (hasAlpha) {
+ maxValues[numColorComponents] =
+ (1 << bits[numColorComponents]) - 1;
+ scaleFactors[numColorComponents] =
+ 1.0f / maxValues[numColorComponents];
+ }
+ break;
+ case DataBuffer.TYPE_SHORT:
+ signed = true;
+ integral = true;
+ donotSupportUnnormalized = true;
+ scaleFactors = new float[numComponents];
+ for (int i = 0; i < numComponents; i++) {
+ maxValues[i] = Short.MAX_VALUE;
+ scaleFactors[i] = 1.0f / maxValues[i];
+ if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) {
+ needScale = true;
+ }
+ }
+ if (needScale) {
+ minVals = new float[numColorComponents];
+ ranges = new float[numColorComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ minVals[i] = cs.getMinValue(i);
+ ranges[i] = cs.getMaxValue(i) - minVals[i];
+ }
+ }
+ break;
+ case DataBuffer.TYPE_FLOAT:
+ case DataBuffer.TYPE_DOUBLE:
+ signed = true;
+ integral = false;
+ donotSupportUnnormalized = true;
+ break;
+ default:
+ // awt.215=transferType is not one of DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT,
+ // DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or
+ // DataBuffer.TYPE_DOUBLE
+ throw new IllegalArgumentException(Messages.getString("awt.215")); //$NON-NLS-1$
+ }
+
+ needAlphaDivide = hasAlpha && isAlphaPremultiplied;
+ initLUTs();
+ }
+
+ /**
+ * Instantiates a new component color model.
+ *
+ * @param colorSpace the color space
+ * @param hasAlpha whether the color model has alpha
+ * @param isAlphaPremultiplied whether the alpha is premultiplied
+ * @param transparency the transparency strategy, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ */
+ public ComponentColorModel(ColorSpace colorSpace, boolean hasAlpha,
+ boolean isAlphaPremultiplied, int transparency, int transferType) {
+
+ this(colorSpace,
+ createPixelBitsArray(colorSpace, hasAlpha, transferType),
+ hasAlpha,
+ isAlphaPremultiplied,
+ transparency,
+ transferType);
+ }
+
+ /**
+ * Validate bits.
+ *
+ * @param bits the bits
+ * @param colorSpace the color space
+ * @param hasAlpha the has alpha
+ * @param transferType the transfer type
+ *
+ * @return the int[]
+ */
+ private static int[] validateBits(int bits[], ColorSpace colorSpace,
+ boolean hasAlpha, int transferType) {
+ if (bits != null) {
+ return bits;
+ }
+
+ int numComponents = colorSpace.getNumComponents();
+ if (hasAlpha) {
+ numComponents++;
+ }
+ bits = new int[numComponents];
+
+ int componentLength = DataBuffer.getDataTypeSize(transferType);
+
+ for (int i = 0; i < numComponents; i++) {
+ bits[i] = componentLength;
+ }
+
+ return bits;
+ }
+
+ /**
+ * Creates the pixel bits.
+ *
+ * @param colorSpace the color space
+ * @param hasAlpha the has alpha
+ * @param transferType the transfer type
+ *
+ * @return the int
+ */
+ private static int createPixelBits(ColorSpace colorSpace, boolean hasAlpha,
+ int transferType) {
+ int numComponents = colorSpace.getNumComponents();
+ if (hasAlpha) {
+ numComponents++;
+ }
+ int componentLength = DataBuffer.getDataTypeSize(transferType);
+ return numComponents * componentLength;
+ }
+
+ /**
+ * Creates the pixel bits array.
+ *
+ * @param colorSpace the color space
+ * @param hasAlpha the has alpha
+ * @param transferType the transfer type
+ *
+ * @return the int[]
+ */
+ private static int[] createPixelBitsArray(ColorSpace colorSpace,
+ boolean hasAlpha, int transferType) {
+
+ int numComponents = colorSpace.getNumComponents();
+ if (hasAlpha) {
+ numComponents++;
+ }
+
+ int bits[] = new int[numComponents];
+ for(int i = 0; i < numComponents; i++){
+ bits[i] = DataBuffer.getDataTypeSize(transferType);
+ }
+ return bits;
+ }
+
+ @Override
+ public Object getDataElements(int components[], int offset, Object obj) {
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+
+ if (offset + numComponents > components.length) {
+ // awt.216=The components array is not large enough to hold all the color and alpha components
+ throw new IllegalArgumentException(Messages.getString("awt.216")); //$NON-NLS-1$
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[];
+ if (obj == null) {
+ ba = new byte[numComponents];
+ } else {
+ ba = (byte[]) obj;
+ }
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ ba[i] = (byte) components[idx];
+ }
+ return ba;
+ case DataBuffer.TYPE_USHORT:
+ short sa[];
+ if (obj == null) {
+ sa = new short[numComponents];
+ } else {
+ sa = (short[]) obj;
+ }
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ sa[i] = (short) components[idx];
+ }
+ return sa;
+ case DataBuffer.TYPE_INT:
+ int ia[];
+ if (obj == null) {
+ ia = new int[numComponents];
+ } else {
+ ia = (int[]) obj;
+ }
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ ia[i] = components[idx];
+ }
+ return ia;
+ default:
+ // awt.217=The transfer type of this ComponentColorModel is not one
+ // of the following transfer types: DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+ throw new UnsupportedOperationException(Messages
+ .getString("awt.217")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Object getDataElements(float normComponents[], int normOffset,
+ Object obj) {
+ if (needScale) {
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ normComponents[idx] =
+ (normComponents[idx] - minVals[i]) / ranges[i];
+ }
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[];
+ if (obj == null) {
+ ba = new byte[numComponents];
+ } else {
+ ba = (byte[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = normOffset; i < numColorComponents;
+ i++, idx++) {
+ ba[i] = (byte) (normComponents[idx] * alpha *
+ maxValues[i] + 0.5f);
+ }
+ ba[numColorComponents] =
+ (byte) (normComponents[normOffset + numColorComponents] *
+ maxValues[numColorComponents] + 0.5f);
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ ba[idx] =
+ (byte) (normComponents[idx] * maxValues[i] + 0.5f);
+ }
+ }
+ return ba;
+
+ case DataBuffer.TYPE_USHORT:
+ short usa[];
+ if (obj == null) {
+ usa = new short[numComponents];
+ } else {
+ usa = (short[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ usa[i] = (short) (normComponents[idx] * alpha *
+ maxValues[i] + 0.5f);
+ }
+ usa[numColorComponents] = (short) (alpha *
+ maxValues[numColorComponents] + 0.5f);
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ usa[i] = (short) (normComponents[idx] *
+ maxValues[i] + 0.5f);
+ }
+ }
+ return usa;
+
+ case DataBuffer.TYPE_INT:
+ int ia[];
+ if (obj == null) {
+ ia = new int[numComponents];
+ } else {
+ ia = (int[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ ia[i] = (int) (normComponents[idx] * alpha *
+ maxValues[i] + 0.5f);
+ }
+ ia[numColorComponents] = (int) (alpha *
+ maxValues[numColorComponents] + 0.5f);
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ ia[i] = (int) (normComponents[idx] * maxValues[i] + 0.5f);
+ }
+ }
+ return ia;
+
+ case DataBuffer.TYPE_SHORT:
+ short sa[];
+ if (obj == null) {
+ sa = new short[numComponents];
+ } else {
+ sa = (short[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ sa[i] = (short) (normComponents[idx] * alpha *
+ maxValues[i] + 0.5f);
+ }
+ sa[numColorComponents] = (short) (alpha *
+ maxValues[numColorComponents] + 0.5f);
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ sa[i] = (short) (normComponents[idx] *
+ maxValues[i] + 0.5f);
+ }
+ }
+ return sa;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fa[];
+ if (obj == null) {
+ fa = new float[numComponents];
+ } else {
+ fa = (float[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ fa[i] = normComponents[idx] * alpha;
+ }
+ fa[numColorComponents] = alpha;
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ fa[i] = normComponents[idx];
+ }
+ }
+ return fa;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double da[];
+ if (obj == null) {
+ da = new double[numComponents];
+ } else {
+ da = (double[]) obj;
+ }
+
+ if (needAlphaDivide) {
+ double alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) {
+ da[i] = normComponents[idx] * alpha;
+ }
+ da[numColorComponents] = alpha;
+ } else {
+ for (int i = 0, idx = normOffset; i < numComponents;
+ i++, idx++) {
+ da[i] = normComponents[idx];
+ }
+ }
+ return da;
+
+ default:
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Object getDataElements(int rgb, Object pixel) {
+ float normComp[];
+ float comp[];
+
+ int red = (rgb >> 16) & 0xff;
+ int green = (rgb >> 8) & 0xff;
+ int blue = rgb & 0xff;
+ int alpha = (rgb >> 24) & 0xff;
+
+ comp = new float[3];
+ if (is_sRGB || is_LINEAR_RGB) {
+ if (is_LINEAR_RGB) {
+ if (LINEAR_RGB_Length == 8) {
+ red = to_LINEAR_8RGB_LUT[red] & 0xff;
+ green = to_LINEAR_8RGB_LUT[green] & 0xff;
+ blue = to_LINEAR_8RGB_LUT[blue] & 0xff;
+ } else {
+ red = to_LINEAR_16RGB_LUT[red] & 0xffff;
+ green = to_LINEAR_16RGB_LUT[green] & 0xffff;
+ blue = to_LINEAR_16RGB_LUT[blue] & 0xffff;
+ }
+ }
+ comp[0] = red / fFactor;
+ comp[1] = green / fFactor;
+ comp[2] = blue / fFactor;
+ if (!hasAlpha) {
+ normComp = comp;
+ } else {
+ float normAlpha = alpha / 255.0f;
+ normComp = new float[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ normComp[i] = comp[i];
+ }
+ normComp[numColorComponents] = normAlpha;
+ }
+ } else {
+ comp[0] = red / fFactor;
+ comp[1] = green / fFactor;
+ comp[2] = blue / fFactor;
+ float[] defComp = cs.fromRGB(comp);
+ if (!hasAlpha) {
+ normComp = defComp;
+ } else {
+ float normAlpha = alpha / 255.0f;
+ normComp = new float[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ normComp[i] = defComp[i];
+ }
+ normComp[numColorComponents] = normAlpha;
+ }
+ }
+ if(hasAlpha && isAlphaPremultiplied){
+ normComp[0] *= normComp[numColorComponents];
+ normComp[1] *= normComp[numColorComponents];
+ normComp[2] *= normComp[numColorComponents];
+ }
+
+ return getDataElements(normComp, 0, pixel);
+ }
+
+ @Override
+ public WritableRaster getAlphaRaster(WritableRaster raster) {
+ if(!hasAlpha) {
+ return null;
+ }
+
+ int x = raster.getMinX();
+ int y = raster.getMinY();
+ int bandList[] = new int[1];
+ bandList[0] = raster.getNumBands() - 1;
+
+ return raster.createWritableChild(x, y, raster.getWidth(),
+ raster.getHeight(), x, y, bandList);
+ }
+
+ @Override
+ public ColorModel coerceData(WritableRaster raster,
+ boolean isAlphaPremultiplied) {
+ if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) {
+ return this;
+ }
+
+ int minX = raster.getMinX();
+ int minY = raster.getMinY();
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+
+ if (isAlphaPremultiplied) {
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ float alphaFactor = maxValues[numColorComponents];
+ int iComponents[] = null;
+ int iTransparentComponents[] = new int[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ iComponents = raster.getPixel(x, minY,
+ iComponents);
+ if (iComponents[numColorComponents] == 0) {
+ raster.setPixel(x, minY, iTransparentComponents);
+ } else {
+ float alpha =
+ iComponents[numColorComponents] /
+ alphaFactor;
+ for (int n = 0; n < numColorComponents; n++) {
+ iComponents[n] =
+ (int) (alpha * iComponents[n] + 0.5f);
+ }
+ raster.setPixel(x, minY, iComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ float sAlphaFactor = maxValues[numColorComponents];
+ short sComponents[] = null;
+ short sTransparentComponents[] = new short[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ sComponents = (short[]) raster.getDataElements(x, minY,
+ sComponents);
+ if (sComponents[numColorComponents] == 0) {
+ raster.setDataElements(x, minY,
+ sTransparentComponents);
+ } else {
+ float alpha =
+ sComponents[numColorComponents] /
+ sAlphaFactor;
+ for (int n = 0; n < numColorComponents; n++) {
+ sComponents[n] =
+ (byte) (alpha * sComponents[n] + 0.5f);
+ }
+ raster.setDataElements(x, minY, sComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fComponents[] = null;
+ float fTransparentComponents[] = new float[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ fComponents = raster.getPixel(x, minY, fComponents);
+ if (fComponents[numColorComponents] == 0.0f) {
+ raster.setDataElements(x, minY,
+ fTransparentComponents);
+ } else {
+ float alpha = fComponents[numColorComponents];
+ for (int n = 0; n < numColorComponents; n++) {
+ fComponents[n] = fComponents[n] * alpha;
+ }
+ raster.setPixel(x, minY, fComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double dComponents[] = null;
+ double dTransparentComponents[] = new double[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ dComponents = raster.getPixel(x, minY, dComponents);
+ if (dComponents[numColorComponents] == 0.0) {
+ raster.setPixel(x, minY, dTransparentComponents);
+ } else {
+ double alpha = dComponents[numColorComponents];
+ for (int n = 0; n < numColorComponents; n++) {
+ dComponents[n] = dComponents[n] * alpha;
+ }
+ raster.setPixel(x, minY, dComponents);
+ }
+ }
+
+ }
+ break;
+
+ default:
+ // awt.219=This transferType is not supported by this color model
+ throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$
+ }
+ } else {
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ float alphaFactor = maxValues[numColorComponents];
+ int iComponents[] = null;
+ int iTransparentComponents[] = new int[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ iComponents = raster.getPixel(x, minY,
+ iComponents);
+ if (iComponents[numColorComponents] == 0) {
+ raster.setPixel(x, minY, iTransparentComponents);
+ } else {
+ float alpha =
+ iComponents[numColorComponents] /
+ alphaFactor;
+ for (int n = 0; n < numColorComponents; n++) {
+ iComponents[n] =
+ (int) (iComponents[n] /
+ alpha + 0.5f);
+ }
+ raster.setPixel(x, minY, iComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ float sAlphaFactor = maxValues[numColorComponents];
+ short sComponents[] = null;
+ short sTransparentComponents[] = new short[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ sComponents = (short[]) raster.getDataElements(x, minY,
+ sComponents);
+ if (sComponents[numColorComponents] == 0) {
+ raster.setDataElements(x, minY,
+ sTransparentComponents);
+ } else {
+ float alpha =
+ sComponents[numColorComponents] /
+ sAlphaFactor;
+ for (int n = 0; n < numColorComponents; n++) {
+ sComponents[n] =
+ (byte) (sComponents[n] /
+ alpha + 0.5f);
+ }
+ raster.setDataElements(x, minY, sComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fComponents[] = null;
+ float fTransparentComponents[] = new float[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ fComponents = raster.getPixel(x, minY, fComponents);
+ if (fComponents[numColorComponents] == 0.0f) {
+ raster.setDataElements(x, minY,
+ fTransparentComponents);
+ } else {
+ float alpha = fComponents[numColorComponents];
+ for (int n = 0; n < numColorComponents; n++) {
+ fComponents[n] = fComponents[n] / alpha;
+ }
+ raster.setPixel(x, minY, fComponents);
+ }
+ }
+
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double dComponents[] = null;
+ double dTransparentComponents[] = new double[numComponents];
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ dComponents = raster.getPixel(x, minY, dComponents);
+ if (dComponents[numColorComponents] == 0.0) {
+ raster.setPixel(x, minY, dTransparentComponents);
+ } else {
+ double alpha = dComponents[numColorComponents];
+ for (int n = 0; n < numColorComponents; n++) {
+ dComponents[n] = dComponents[n] / alpha;
+ }
+ raster.setPixel(x, minY, dComponents);
+ }
+ }
+
+ }
+ break;
+ default:
+ // awt.219=This transferType is not supported by this color model
+ throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$
+ }
+ }
+
+ if (!signed) {
+ return new ComponentColorModel(cs, bits, hasAlpha,
+ isAlphaPremultiplied, transparency, transferType);
+ }
+
+ return new ComponentColorModel(cs, null, hasAlpha,
+ isAlphaPremultiplied, transparency, transferType);
+ }
+
+ @Override
+ public int[] getComponents(Object pixel, int[] components, int offset) {
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+
+ if (components == null) {
+ components = new int[offset + numComponents];
+ } else if (offset + numComponents > components.length) {
+ // awt.218=The components array is not large enough to hold all the color and alpha components
+ throw new IllegalArgumentException(Messages.getString("awt.218")); //$NON-NLS-1$
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) pixel;
+
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ components[idx] = ba[i] & 0xff;
+ }
+ return components;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) pixel;
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ components[idx] = sa[i] & 0xffff;
+ }
+ return components;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) pixel;
+ for (int i = 0, idx = offset; i < numComponents; i++, idx++) {
+ components[idx] = ia[i];
+ }
+ return components;
+
+ default:
+ // awt.217=The transfer type of this ComponentColorModel is not one
+ // of the following transfer types: DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+ throw new UnsupportedOperationException(Messages
+ .getString("awt.217")); //$NON-NLS-1$
+ }
+
+ }
+
+ @Override
+ public float[] getNormalizedComponents(Object pixel,
+ float normComponents[], int normOffset) {
+
+ if (normComponents == null) {
+ normComponents = new float[numComponents + normOffset];
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = (ba[i] & 0xff) * scaleFactors[i];
+ }
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short usa[] = (short[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = (usa[i] & 0xffff)
+ * scaleFactors[i];
+ }
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = ia[i] * scaleFactors[i];
+ }
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ short sa[] = (short[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = sa[i] * scaleFactors[i];
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fa[] = (float[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = fa[i];
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double da[] = (double[]) pixel;
+ for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) {
+ normComponents[idx] = (float) da[i];
+ }
+ break;
+
+ default:
+ // awt.21A=This ComponentColorModel does not support this transferType
+ throw new IllegalArgumentException(Messages.getString("awt.21A")); //$NON-NLS-1$
+ }
+
+ if (needAlphaDivide) {
+ float alpha = normComponents[normOffset + numColorComponents];
+ for (int i = 0, idx = normOffset; i < numColorComponents;
+ i++, idx++) {
+ normComponents[idx] /= alpha;
+ }
+ }
+
+ if (needScale) {
+ for (int i = 0, idx = normOffset; i < numColorComponents;
+ i++, idx++) {
+ normComponents[idx] = minVals[i] +
+ ranges[i] * normComponents[idx];
+ }
+ }
+ return normComponents;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ComponentColorModel)) {
+ return false;
+ }
+ return super.equals(obj);
+ }
+
+ @Override
+ public int getRed(Object inData) {
+ return getRGBComponent(inData, 0);
+ }
+
+ @Override
+ public int getRGB(Object inData) {
+ int alpha = getAlpha(inData);
+ if (cs.getType() == ColorSpace.TYPE_GRAY) {
+ int gray = getRed(inData);
+ return (alpha << 24 | gray << 16 | gray << 8 | gray);
+ }
+ return (alpha << 24 | getRed(inData) << 16 | getGreen(inData) << 8 |
+ getBlue(inData));
+ }
+
+ @Override
+ public int getGreen(Object inData) {
+ return getRGBComponent(inData, 1);
+ }
+
+ @Override
+ public int getBlue(Object inData) {
+ return getRGBComponent(inData, 2);
+ }
+
+ @Override
+ public int getAlpha(Object inData) {
+ if (!hasAlpha) {
+ return 255;
+ }
+ int alpha = 0;
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE: {
+ byte ba[] = (byte[]) inData;
+ alpha = ba[numColorComponents] & 0xff;
+ if (bits[numColorComponents] != 8) {
+ return alphaLUT[alpha] & 0xff;
+ }
+ return alpha;
+ }
+ case DataBuffer.TYPE_USHORT: {
+ short usa[] = (short[]) inData;
+ alpha = usa[numColorComponents] & 0xffff;
+ if (bits[numColorComponents] != 8) {
+ return alphaLUT[alpha] & 0xff;
+ }
+ return alpha;
+ }
+ case DataBuffer.TYPE_INT: {
+ int ia[] = (int[]) inData;
+ alpha = ia[numColorComponents];
+ if (bits[numColorComponents] != 8) {
+ return alphaLUT[alpha] & 0xff;
+ }
+ return alpha;
+ }
+ case DataBuffer.TYPE_SHORT: {
+ short sa[] = (short[]) inData;
+ alpha = sa[numColorComponents];
+ if (bits[numColorComponents] != 8) {
+ return alphaLUT[alpha] & 0xff;
+ }
+ return alpha;
+ }
+ case DataBuffer.TYPE_FLOAT: {
+ float fa[] = (float[]) inData;
+ return (int) (fa[numColorComponents] * 255.0f + 0.5f);
+ }
+ case DataBuffer.TYPE_DOUBLE: {
+ double da[] = (double[]) inData;
+ return (int) (da[numColorComponents] * 255.0 + 0.5);
+ }
+ default: {
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ @Override
+ public WritableRaster createCompatibleWritableRaster(int w, int h) {
+ SampleModel sm = createCompatibleSampleModel(w, h);
+ DataBuffer db = sm.createDataBuffer();
+ return Raster.createWritableRaster(sm, db, null);
+ }
+
+ @Override
+ public boolean isCompatibleSampleModel(SampleModel sm) {
+ if (!(sm instanceof ComponentSampleModel)) {
+ return false;
+ }
+ if (numComponents != sm.getNumBands()) {
+ return false;
+ }
+ if (transferType != sm.getTransferType()) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ int bandOffsets[] = new int[numComponents];
+ for (int i = 0; i < numComponents; i++) {
+ bandOffsets[i] = i;
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ return new PixelInterleavedSampleModel(transferType, w, h,
+ numComponents, w * numComponents, bandOffsets);
+
+ default:
+ return new ComponentSampleModel(transferType, w, h, numComponents,
+ w * numComponents, bandOffsets);
+ }
+ }
+
+ @Override
+ public boolean isCompatibleRaster(Raster raster) {
+ SampleModel sm = raster.getSampleModel();
+ if (!(sm instanceof ComponentSampleModel)) {
+ return false;
+ }
+
+ if (sm.getNumBands() != numComponents) {
+ return false;
+ }
+ if (raster.getTransferType() != transferType) {
+ return false;
+ }
+
+ int sampleSizes[] = sm.getSampleSize();
+ for (int i = 0; i < numComponents; i++) {
+ if (bits[i] != sampleSizes[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public float[] getNormalizedComponents(int components[], int offset,
+ float normComponents[], int normOffset) {
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+
+ return super.getNormalizedComponents(components, offset,
+ normComponents, normOffset);
+ }
+
+ @Override
+ public int getDataElement(int[] components, int offset) {
+ if (numComponents > 1) {
+ // awt.212=There is more than one component in this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+ }
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+ return components[offset];
+ }
+
+ @Override
+ public int[] getUnnormalizedComponents(float[] normComponents,
+ int normOffset, int[] components, int offset) {
+
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+
+ if (normComponents.length - normOffset < numComponents) {
+ // awt.21B=The length of normComponents minus normOffset is less than numComponents
+ throw new IllegalArgumentException(Messages.getString("awt.21B")); //$NON-NLS-1$
+ }
+
+ return super.getUnnormalizedComponents(normComponents, normOffset,
+ components, offset);
+ }
+
+ @Override
+ public int getDataElement(float normComponents[], int normOffset) {
+ if (numComponents > 1) {
+ // awt.212=There is more than one component in this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+ }
+ if (signed) {
+ // awt.210=The component value for this ColorModel is signed
+ throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$
+ }
+
+ Object pixel = getDataElements(normComponents, normOffset, null);
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) pixel;
+ return ba[0] & 0xff;
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) pixel;
+ return sa[0] & 0xffff;
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) pixel;
+ return ia[0];
+ default:
+ // awt.211=Pixel values for this ColorModel are not conveniently
+ // representable as a single int
+ throw new IllegalArgumentException(Messages.getString("awt.211")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public int[] getComponents(int pixel, int components[], int offset) {
+ if (numComponents > 1) {
+ // awt.212=There is more than one component in this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+ }
+ if (donotSupportUnnormalized) {
+ // awt.213=This ComponentColorModel does not support the unnormalized form
+ throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$
+ }
+
+ if (components == null) {
+ components = new int[offset + 1];
+ }
+
+ components[offset] = pixel & maxValues[0];
+ return components;
+ }
+
+ @Override
+ public int getRed(int pixel) {
+ float rgb[] = toRGB(pixel);
+ return (int) (rgb[0] * 255.0f + 0.5f);
+ }
+
+ @Override
+ public int getRGB(int pixel) {
+ return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) |
+ (getGreen(pixel) << 8) | getBlue(pixel);
+ }
+
+ @Override
+ public int getGreen(int pixel) {
+ float rgb[] = toRGB(pixel);
+ return (int) (rgb[1] * 255.0f + 0.5f);
+ }
+
+ @Override
+ public int getBlue(int pixel) {
+ float rgb[] = toRGB(pixel);
+ return (int) (rgb[2] * 255.0f + 0.5f);
+ }
+
+ @Override
+ public int getAlpha(int pixel) {
+
+ // This method throw IllegalArgumentException according to
+ // Java API Spacification
+ if (signed) {
+ // awt.210=The component value for this ColorModel is signed
+ throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$
+ }
+
+ if (numComponents > 1) {
+ // awt.212=There is more than one component in this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+ }
+
+ return 255;
+ }
+
+ /**
+ * Initialization of Lookup tables.
+ */
+ private void initLUTs() {
+ is_sRGB = cs.isCS_sRGB();
+ is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS);
+
+ if (hasAlpha && bits[numColorComponents] != 8 && integral) {
+ alphaLUT = new byte[maxValues[numColorComponents] + 1];
+ for (int i = 0; i <= maxValues[numColorComponents]; i++) {
+ alphaLUT[i] = (byte) (scaleFactors[numColorComponents] * i +
+ 0.5f);
+ }
+ }
+
+ if (is_LINEAR_RGB) {
+ if (maxBitLength > 8) {
+ LINEAR_RGB_Length = 16;
+ from_LINEAR_RGB_LUT =
+ LUTColorConverter.getFrom16lRGBtosRGB_LUT();
+ to_LINEAR_16RGB_LUT =
+ LUTColorConverter.getFromsRGBto16lRGB_LUT();
+ } else {
+ LINEAR_RGB_Length = 8;
+ from_LINEAR_RGB_LUT =
+ LUTColorConverter.getFrom8lRGBtosRGB_LUT();
+ to_LINEAR_8RGB_LUT =
+ LUTColorConverter.getFromsRGBto8lRGB_LUT();
+ }
+ fFactor = ((1 << LINEAR_RGB_Length) - 1);
+ } else {
+ fFactor = 255.0f;
+ }
+
+ if (!isAlphaPremultiplied && integral) {
+ colorLUTs = new byte[3][];
+
+ if (is_sRGB) {
+ for (int i = 0; i < numColorComponents; i++) {
+ if (bits[i] != 8) {
+ for (int j = 0; j < i; j++) {
+ if (bits[i] == bits[j]) {
+ colorLUTs[i] = colorLUTs[j];
+ break;
+ }
+ }
+ colorLUTs[i] = new byte[maxValues[i] + 1];
+ for (int j = 0; j <= maxValues[0]; j++) {
+ colorLUTs[i][j] =
+ (byte) (scaleFactors[i] * j + 0.5f);
+ }
+ }
+ }
+ }
+
+ if (is_LINEAR_RGB) {
+
+ for (int i = 0; i < numColorComponents; i++) {
+ if (bits[i] != LINEAR_RGB_Length) {
+ for (int j = 0; j < i; j++) {
+ if (bits[i] == bits[j]) {
+ colorLUTs[i] = colorLUTs[j];
+ break;
+ }
+ }
+ colorLUTs[i] = new byte[maxValues[i] + 1];
+ for (int j = 0; j <= maxValues[0]; j++) {
+ int idx;
+ if (LINEAR_RGB_Length == 8) {
+ idx = (int) (scaleFactors[i] * j + 0.5f);
+ } else {
+ idx = (int) (scaleFactors[i] * j * 257.0f +
+ 0.5f);
+ }
+ colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx];
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * To rgb.
+ *
+ * @param pixel - int representation of pixel
+ *
+ * @return - array of normalized sRGB components
+ */
+ private float[] toRGB(int pixel) {
+
+ // This method throw IllegalArgumentException according to
+ // Java API Spacification
+ if (signed) {
+ // awt.210=The component value for this ColorModel is signed
+ throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$
+ }
+
+ if (numComponents > 1) {
+ // awt.212=There is more than one component in this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$
+ }
+
+ Object obj = null;
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = new byte[1];
+ ba[0] = (byte) pixel;
+ obj = ba;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = new short[1];
+ sa[0] = (short) pixel;
+ obj = sa;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = new int[1];
+ ia[0] = pixel;
+ obj = ia;
+ break;
+
+ }
+
+ return cs.toRGB(getNormalizedComponents(obj, null, 0));
+ }
+
+ /**
+ * Gets the rgb component.
+ *
+ * @param pixel - pixel
+ * @param idx - index of component
+ *
+ * @return - RGB value from 0 to 255 pixel's component
+ */
+ private int getRGBComponent(Object pixel, int idx) {
+ if (is_sRGB) {
+ int comp = getDefComponent(pixel, idx);
+ if (calcValue || bits[idx] == 8) {
+ return comp;
+ }
+ return colorLUTs[idx][comp] & 0xff;
+ } else if (is_LINEAR_RGB) {
+ int comp = getDefComponent(pixel, idx);
+ if (calcValue || bits[idx] == LINEAR_RGB_Length) {
+ return from_LINEAR_RGB_LUT[comp] & 0xff;
+ }
+ return colorLUTs[idx][comp] & 0xff;
+ }
+
+ float normComp[] = getNormalizedComponents(pixel, null, 0);
+ float rgbComp[] = cs.toRGB(normComp);
+ return (int) (rgbComp[idx] * 255.0f + 0.5f);
+ }
+
+ /**
+ * Gets the def component.
+ *
+ * @param pixel - pixel
+ * @param idx - index of component
+ *
+ * @return - tentative value of the pixel component
+ */
+ private int getDefComponent(Object pixel, int idx) {
+ int comp = 0;
+ calcValue = false;
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) pixel;
+ comp = ba[idx] & 0xff;
+ if (needAlphaDivide) {
+ int alpha = ba[numColorComponents] & 0xff;
+ if (alpha == 0) {
+ comp = 0;
+ } else {
+ float normAlpha = scaleFactors[numColorComponents] * alpha;
+ comp = (int) (comp * fFactor / normAlpha + 0.5f);
+ }
+ calcValue = true;
+ }
+ return comp;
+
+ case DataBuffer.TYPE_USHORT:
+ short usa[] = (short[]) pixel;
+ comp = usa[idx] & 0xffff;
+ if (needAlphaDivide) {
+ int alpha = usa[numColorComponents] & 0xffff;
+ if (alpha == 0) {
+ comp = 0;
+ } else {
+ float normAlpha = scaleFactors[numColorComponents] * alpha;
+ comp = (int) (comp * fFactor / normAlpha + 0.5f);
+ }
+ calcValue = true;
+ }
+ return comp;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) pixel;
+ comp = ia[idx];
+ if (needAlphaDivide) {
+ int alpha = ia[numColorComponents];
+ if (alpha == 0) {
+ comp = 0;
+ } else {
+ float normAlpha = scaleFactors[numColorComponents] * alpha;
+ comp = (int) (comp * fFactor / normAlpha + 0.5f);
+ }
+ calcValue = true;
+ }
+ return comp;
+
+ case DataBuffer.TYPE_SHORT:
+ short sa[] = (short[]) pixel;
+ comp = sa[idx];
+ if (needAlphaDivide) {
+ int alpha = sa[numColorComponents];
+ if (alpha == 0) {
+ comp = 0;
+ } else {
+ float normAlpha = scaleFactors[numColorComponents] * alpha;
+ comp = (int) (comp * fFactor / normAlpha + 0.5f);
+ }
+ calcValue = true;
+ }
+ return comp;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fa[] = (float[]) pixel;
+ if (needAlphaDivide) {
+ float alpha = fa[numColorComponents];
+ if (fa[numColorComponents] == 0.0f) {
+ comp = 0;
+ } else {
+ comp = (int) (fa[idx] * fFactor / alpha + 0.5f);
+ }
+ } else {
+ comp = (int) (fa[idx] * fFactor + 0.5f);
+ }
+ calcValue = true;
+ return comp;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double da[] = (double[]) pixel;
+ if (needAlphaDivide) {
+ if (da[numColorComponents] == 0.0) {
+ comp = 0;
+ } else {
+ comp = (int) (da[idx] * fFactor / da[numColorComponents] +
+ 0.5);
+ }
+ } else {
+ comp = (int) (da[idx] * fFactor + 0.5);
+ }
+ calcValue = true;
+ return comp;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/image/ComponentSampleModel.java b/awt/java/awt/image/ComponentSampleModel.java
new file mode 100644
index 0000000..2ff4f1a
--- /dev/null
+++ b/awt/java/awt/image/ComponentSampleModel.java
@@ -0,0 +1,690 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ComponentSampleModel class represents a set of image data whose
+ * each element - the sample of a pixel - takes one data element of
+ * the DataBuffer.
+ * <p>
+ * The Bank indices denote the correspondence between the bank of data
+ * buffers and a band of image data. The Pixel stride is the number of data
+ * array elements between two samples for the same band on the same
+ * scanline. The pixel stride for a BandedSampleModel is one. The Scanline
+ * stride represents the number of data array elements between a
+ * specified sample and the corresponding sample in the same column in
+ * the next scanline. The array of band offsets gives the starting
+ * offsets within each data banks of the in the DataBuffer. The bank
+ * indices represents the indices within each bank of the DataBuffer
+ * corresponding to a band of image data.
+ */
+public class ComponentSampleModel extends SampleModel {
+
+ /** The band offsets array of this ComponentSampleModel. */
+ protected int bandOffsets[];
+
+ /** The bank indices array of this ComponentSampleModel. */
+ protected int bankIndices[];
+
+ /** The number of bands in this ComponentSampleModel. */
+ protected int numBands;
+
+ /** The number banks of this ComponentSampleModel. */
+ protected int numBanks;
+
+ /** The scanline stride of this ComponentSampleModel. */
+ protected int scanlineStride;
+
+ /** The pixel stride of this ComponentSampleModel. */
+ protected int pixelStride;
+
+ /**
+ * Instantiates a new ComponentSampleModel with the specified
+ * properties.
+ *
+ * @param dataType the data type of samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param pixelStride the pixel stride of the image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param bankIndices the array of the bank indices.
+ * @param bandOffsets the array of the band offsets.
+ */
+ public ComponentSampleModel(int dataType, int w, int h, int pixelStride,
+ int scanlineStride, int bankIndices[], int bandOffsets[]) {
+
+ super(dataType, w, h, bandOffsets.length);
+
+ if (pixelStride < 0) {
+ // awt.24B=Pixel stride must be >= 0
+ throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$
+ }
+
+ if (scanlineStride < 0) {
+ // awt.24C=Scanline stride must be >= 0
+ throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$
+ }
+
+ if (bankIndices.length != bandOffsets.length) {
+ // awt.24D=Bank Indices length must be equal Bank Offsets length
+ throw new IllegalArgumentException(Messages.getString("awt.24D")); //$NON-NLS-1$
+ }
+
+ this.pixelStride = pixelStride;
+ this.scanlineStride = scanlineStride;
+ this.bandOffsets = bandOffsets.clone();
+ this.bankIndices = bankIndices.clone();
+ this.numBands = bandOffsets.length;
+
+ int maxBank = 0;
+ for (int i = 0; i < bankIndices.length; i++) {
+ if (bankIndices[i] < 0) {
+ // awt.24E=Index of {0} bank must be >= 0
+ throw new IllegalArgumentException(Messages.getString("awt.24E", i)); //$NON-NLS-1$
+ }
+ if (bankIndices[i] > maxBank) {
+ maxBank = bankIndices[i];
+ }
+ }
+ this.numBanks = maxBank + 1;
+
+ }
+
+ /**
+ * Instantiates a new ComponentSampleModel with the specified
+ * properties.
+ *
+ * @param dataType the data type of the samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param pixelStride the pixel stride of the image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param bandOffsets the band offsets.
+ */
+ public ComponentSampleModel(int dataType, int w, int h, int pixelStride,
+ int scanlineStride, int bandOffsets[]) {
+
+ super(dataType, w, h, bandOffsets.length);
+ if (pixelStride < 0) {
+ // awt.24B=Pixel stride must be >= 0
+ throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$
+ }
+
+ if (scanlineStride < 0) {
+ // awt.24C=Scanline stride must be >= 0
+ throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$
+ }
+
+ this.pixelStride = pixelStride;
+ this.scanlineStride = scanlineStride;
+ this.bandOffsets = bandOffsets.clone();
+ this.numBands = bandOffsets.length;
+ this.numBanks = 1;
+
+ this.bankIndices = new int[numBands];
+ for (int i = 0; i < numBands; i++) {
+ bankIndices[i] = 0;
+ }
+ }
+
+ @Override
+ public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[];
+ if (obj == null) {
+ bdata = new byte[numBands];
+ } else {
+ bdata = (byte[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ bdata[i] = (byte) getSample(x, y, i, data);
+ }
+
+ obj = bdata;
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short sdata[];
+ if (obj == null) {
+ sdata = new short[numBands];
+ } else {
+ sdata = (short[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ sdata[i] = (short) getSample(x, y, i, data);
+ }
+
+ obj = sdata;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int idata[];
+ if (obj == null) {
+ idata = new int[numBands];
+ } else {
+ idata = (int[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ idata[i] = getSample(x, y, i, data);
+ }
+
+ obj = idata;
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fdata[];
+ if (obj == null) {
+ fdata = new float[numBands];
+ } else {
+ fdata = (float[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ fdata[i] = getSampleFloat(x, y, i, data);
+ }
+
+ obj = fdata;
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double ddata[];
+ if (obj == null) {
+ ddata = new double[numBands];
+ } else {
+ ddata = (double[]) obj;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ ddata[i] = getSampleDouble(x, y, i, data);
+ }
+
+ obj = ddata;
+ break;
+ }
+
+ return obj;
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ byte barr[] = (byte[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, barr[i] & 0xff, data);
+ }
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short sarr[] = (short[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, sarr[i] & 0xffff, data);
+ }
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int iarr[] = (int[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, iarr[i], data);
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float farr[] = (float[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, farr[i], data);
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double darr[] = (double[]) obj;
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, darr[i], data);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Compares this ComponentSampleModel with the specified Object.
+ *
+ * @param o the Object.
+ *
+ * @return true, if the object is a ComponentSampleModel with
+ * identical data values to this ComponentSampleModel, false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if ((o == null) || !(o instanceof ComponentSampleModel)) {
+ return false;
+ }
+ ComponentSampleModel model = (ComponentSampleModel) o;
+ return this.width == model.width && this.height == model.height &&
+ this.numBands == model.numBands &&
+ this.dataType == model.dataType &&
+ Arrays.equals(this.bandOffsets, model.bandOffsets) &&
+ Arrays.equals(this.bankIndices, model.bankIndices) &&
+ this.numBands == model.numBands &&
+ this.numBanks == model.numBanks &&
+ this.scanlineStride == model.scanlineStride &&
+ this.pixelStride == model.pixelStride;
+ }
+
+ /**
+ * @see java.awt.image.SampleModel#createSubsetSampleModel(int[])
+ */
+ @Override
+ public SampleModel createSubsetSampleModel(int bands[]) {
+ if (bands.length > this.numBands) {
+ // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model
+ throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
+ }
+
+ int indices[] = new int[bands.length];
+ int offsets[] = new int[bands.length];
+
+ for (int i = 0; i < bands.length; i++) {
+ indices[i] = bankIndices[bands[i]];
+ offsets[i] = bandOffsets[bands[i]];
+ }
+
+ return new ComponentSampleModel(dataType, width, height, pixelStride,
+ scanlineStride, indices, offsets);
+
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ return new ComponentSampleModel(dataType, w, h, pixelStride,
+ pixelStride * w, bankIndices, bandOffsets);
+ }
+
+ @Override
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ int pixel[];
+
+ if (iArray == null) {
+ pixel = new int[numBands];
+ } else {
+ pixel = iArray;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ pixel[i] = getSample(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ @Override
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, iArray[i], data);
+ }
+ }
+
+ @Override
+ public int getSample(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElem(bankIndices[b], y * scanlineStride +
+ x * pixelStride + bandOffsets[b]);
+ }
+
+ @Override
+ public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElemFloat(bankIndices[b], y * scanlineStride +
+ x * pixelStride + bandOffsets[b]);
+ }
+
+ @Override
+ public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ return data.getElemDouble(bankIndices[b], y * scanlineStride +
+ x * pixelStride + bandOffsets[b]);
+ }
+
+ @Override
+ public int[] getPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x > this.width || x + w > this.width
+ || y > this.height || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int pixels[] = null;
+ int idx = 0;
+
+ if (iArray == null) {
+ pixels = new int[w * h * numBands];
+ } else {
+ pixels = iArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ pixels[idx++] = getSample(j, i, n, data);
+ }
+ }
+ }
+
+ return pixels;
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ setSample(j, i, n, iArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElem(bankIndices[b], y * scanlineStride + x * pixelStride
+ + bandOffsets[b], s);
+ }
+
+ @Override
+ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int samples[];
+ int idx = 0;
+
+ if (iArray == null) {
+ samples = new int[w * h];
+ } else {
+ samples = iArray;
+ }
+
+ if (data == null) {
+ // awt.295=data is null
+ throw new NullPointerException(Messages.getString("awt.295")); //$NON-NLS-1$
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSample(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(j, i, b, iArray[idx++], data);
+ }
+ }
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, float s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElemFloat(bankIndices[b], y * scanlineStride +
+ x * pixelStride + bandOffsets[b], s);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, double s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ data.setElemDouble(bankIndices[b], y * scanlineStride +
+ x * pixelStride + bandOffsets[b], s);
+ }
+
+ @Override
+ public DataBuffer createDataBuffer() {
+ DataBuffer data = null;
+
+ int maxOffset = bandOffsets[0];
+ for (int i = 1; i < bandOffsets.length; i++) {
+ if (bandOffsets[i] > maxOffset) {
+ maxOffset = bandOffsets[i];
+ }
+ }
+ int size = (height - 1) * scanlineStride +
+ (width - 1) * pixelStride + maxOffset + 1;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(size, numBanks);
+ break;
+ case DataBuffer.TYPE_SHORT:
+ data = new DataBufferShort(size, numBanks);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(size, numBanks);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(size, numBanks);
+ break;
+ case DataBuffer.TYPE_FLOAT:
+ data = new DataBufferFloat(size, numBanks);
+ break;
+ case DataBuffer.TYPE_DOUBLE:
+ data = new DataBufferDouble(size, numBanks);
+ break;
+ }
+
+ return data;
+
+ }
+
+ /**
+ * Gets the offset of the specified band of the specified pixel.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the band.
+ *
+ * @return the offset of the specified band of the specified pixel.
+ */
+ public int getOffset(int x, int y, int b) {
+ return y * scanlineStride + x * pixelStride + bandOffsets[b];
+ }
+
+ /**
+ * Gets the offset of the first band of the specified pixel.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ *
+ * @return the offset of the first band of the specified pixel.
+ */
+ public int getOffset(int x, int y) {
+ return y * scanlineStride + x * pixelStride + bandOffsets[0];
+ }
+
+ @Override
+ public final int getSampleSize(int band) {
+ return DataBuffer.getDataTypeSize(dataType);
+ }
+
+ @Override
+ public final int[] getSampleSize() {
+ int sampleSizes[] = new int[numBands];
+ int size = DataBuffer.getDataTypeSize(dataType);
+
+ for (int i = 0; i < numBands; i++) {
+ sampleSizes[i] = size;
+ }
+ return sampleSizes;
+ }
+
+ /**
+ * Gets an array of bank indices corresponding to this
+ * ComponentSampleModel.
+ *
+ * @return the array of bank indices.
+ */
+ public final int[] getBankIndices() {
+ return bankIndices.clone();
+ }
+
+ /**
+ * Gets an array of the band offsets corresponding to this
+ * ComponentSampleModel.
+ *
+ * @return the array of band offsets.
+ */
+ public final int[] getBandOffsets() {
+ return bandOffsets.clone();
+ }
+
+ /**
+ * Gets a hash code of this ComponentSampleModel object.
+ *
+ * @return a hash code of this ComponentSampleModel object.
+ */
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ int tmp = 0;
+
+ hash = width;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= height;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= numBands;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= dataType;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ for (int element : bandOffsets) {
+ hash ^= element;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ }
+ for (int element : bankIndices) {
+ hash ^= element;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ }
+ hash ^= pixelStride;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+
+ hash ^= scanlineStride;
+ return hash;
+ }
+
+ /**
+ * Gets the scanline stride of this ComponentSampleModel.
+ *
+ * @return the scanline stride of this ComponentSampleModel.
+ */
+ public final int getScanlineStride() {
+ return scanlineStride;
+ }
+
+ /**
+ * Gets the pixel stride.
+ *
+ * @return the pixel stride
+ */
+ public final int getPixelStride() {
+ return pixelStride;
+ }
+
+ @Override
+ public final int getNumDataElements() {
+ return numBands;
+ }
+
+}
+
+
+
diff --git a/awt/java/awt/image/ConvolveOp.java b/awt/java/awt/image/ConvolveOp.java
new file mode 100644
index 0000000..bb588bc
--- /dev/null
+++ b/awt/java/awt/image/ConvolveOp.java
@@ -0,0 +1,545 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Sep 29, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.*;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The ConvolveOp class convolves from the source data
+ * to the destination using a convolution kernel.
+ * Each output pixel is represented as the result of multiplying
+ * the kernel and the surround of the input pixel.
+ */
+public class ConvolveOp implements BufferedImageOp, RasterOp {
+
+ /**
+ * The Constant EDGE_ZERO_FILL indicates that pixels at the edge of
+ * the destination image are set to zero.
+ */
+ public static final int EDGE_ZERO_FILL = 0;
+
+ /**
+ * The Constant EDGE_NO_OP indicates that pixels at the edge of
+ * the source image are converted to the edge pixels in the
+ * destination without modification.
+ */
+ public static final int EDGE_NO_OP = 1;
+
+ /** The kernel. */
+ private Kernel kernel;
+
+ /** The edge cond. */
+ private int edgeCond;
+
+ /** The rhs. */
+ private RenderingHints rhs = null;
+
+ static {
+ // TODO
+ //System.loadLibrary("imageops");
+ }
+
+ /**
+ * Instantiates a new ConvolveOp object with the specified Kernel
+ * and specified edges condition.
+ *
+ * @param kernel the specified Kernel.
+ * @param edgeCondition the specified edge condition.
+ * @param hints the RenderingHints object, or null.
+ */
+ public ConvolveOp(Kernel kernel, int edgeCondition, RenderingHints hints) {
+ this.kernel = kernel;
+ this.edgeCond = edgeCondition;
+ this.rhs = hints;
+ }
+
+ /**
+ * Instantiates a new ConvolveOp object with the specified Kernel
+ * and EDGE_ZERO_FILL edge condition.
+ *
+ * @param kernel the specified Kernel.
+ */
+ public ConvolveOp(Kernel kernel) {
+ this.kernel = kernel;
+ this.edgeCond = EDGE_ZERO_FILL;
+ }
+
+ /**
+ * Gets the Kernel object of this ConvolveOp.
+ *
+ * @return the Kernel object of this ConvolveOp.
+ */
+ public final Kernel getKernel() {
+ return (Kernel) kernel.clone();
+ }
+
+ public final RenderingHints getRenderingHints() {
+ return rhs;
+ }
+
+ /**
+ * Gets the edge condition of this ConvolveOp.
+ *
+ * @return the edge condition: EDGE_NO_OP or EDGE_ZERO_FILL.
+ */
+ public int getEdgeCondition() {
+ return edgeCond;
+ }
+
+ public final Rectangle2D getBounds2D(Raster src) {
+ return src.getBounds();
+ }
+
+ public final Rectangle2D getBounds2D(BufferedImage src) {
+ return getBounds2D(src.getRaster());
+ }
+
+ public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+ if (dstPt == null) {
+ dstPt = new Point2D.Float();
+ }
+
+ dstPt.setLocation(srcPt);
+ return dstPt;
+ }
+
+ public WritableRaster createCompatibleDestRaster(Raster src) {
+ return src.createCompatibleWritableRaster();
+ }
+
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
+ if (dstCM == null) {
+ dstCM = src.getColorModel();
+ }
+
+ if (dstCM instanceof IndexColorModel) {
+ dstCM = ColorModel.getRGBdefault();
+ }
+
+ WritableRaster r =
+ dstCM.isCompatibleSampleModel(src.getSampleModel()) ?
+ src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) :
+ dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+
+ return new BufferedImage(
+ dstCM,
+ r,
+ dstCM.isAlphaPremultiplied(),
+ null
+ );
+ }
+
+ public final WritableRaster filter(Raster src, WritableRaster dst) {
+ if (src == null) { // Should throw according to spec
+ // awt.256=Source raster is null
+ throw new NullPointerException(Messages.getString("awt.256")); //$NON-NLS-1$
+ }
+
+ if (src == dst){
+ // awt.257=Source raster is equal to destination
+ throw new IllegalArgumentException(Messages.getString("awt.257")); //$NON-NLS-1$
+ }
+
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else if (src.getNumBands() != dst.getNumBands()) {
+ // awt.258=Number of source bands ({0}) is not equal to number of destination bands ({1})
+ throw new IllegalArgumentException(
+ Messages.getString("awt.258", src.getNumBands(), dst.getNumBands())); //$NON-NLS-1$
+ }
+
+ // TODO
+ //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0)
+ if (slowFilter(src, dst) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ return dst;
+ }
+
+ /**
+ * Slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ *
+ * @return the int
+ */
+ private int slowFilter(Raster src, WritableRaster dst) {
+ try {
+ SampleModel sm = src.getSampleModel();
+
+ int numBands = src.getNumBands();
+ int srcHeight = src.getHeight();
+ int srcWidth = src.getWidth();
+
+ int xOrigin = kernel.getXOrigin();
+ int yOrigin = kernel.getYOrigin();
+ int kWidth = kernel.getWidth();
+ int kHeight = kernel.getHeight();
+ float[] data = kernel.getKernelData(null);
+
+ int srcMinX = src.getMinX();
+ int srcMinY = src.getMinY();
+ int dstMinX = dst.getMinX();
+ int dstMinY = dst.getMinY();
+
+ int srcConvMaxX = srcWidth - (kWidth - xOrigin - 1);
+ int srcConvMaxY = srcHeight - (kHeight - yOrigin - 1);
+
+ int[] maxValues = new int[numBands];
+ int[] masks = new int[numBands];
+ int[] sampleSizes = sm.getSampleSize();
+
+ for (int i=0; i < numBands; i++){
+ maxValues[i] = (1 << sampleSizes[i]) - 1;
+ masks[i] = ~(maxValues[i]);
+ }
+
+ // Processing bounds
+ float[] pixels = null;
+ pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels);
+ float[] newPixels = new float[pixels.length];
+ int rowLength = srcWidth*numBands;
+ if (this.edgeCond == ConvolveOp.EDGE_NO_OP){
+ // top
+ int start = 0;
+ int length = yOrigin*rowLength;
+ System.arraycopy(pixels, start, newPixels, start, length);
+ // bottom
+ start = (srcHeight - (kHeight - yOrigin - 1))*rowLength;
+ length = (kHeight - yOrigin - 1)*rowLength;
+ System.arraycopy(pixels, start, newPixels, start, length);
+ // middle
+ length = xOrigin*numBands;
+ int length1 = (kWidth - xOrigin - 1)*numBands;
+ start = yOrigin*rowLength;
+ int start1 = (yOrigin+1)*rowLength - length1;
+ for (int i = yOrigin; i < (srcHeight - (kHeight - yOrigin - 1)); i ++) {
+ System.arraycopy(pixels, start, newPixels, start, length);
+ System.arraycopy(pixels, start1, newPixels, start1, length1);
+ start +=rowLength;
+ start1 +=rowLength;
+ }
+
+ }
+
+ // Cycle over pixels to be calculated
+ for (int i = yOrigin; i < srcConvMaxY; i++){
+ for (int j = xOrigin; j < srcConvMaxX; j++){
+
+ // Take kernel data in backward direction, convolution
+ int kernelIdx = data.length - 1;
+
+ int pixelIndex = i * rowLength + j * numBands;
+ for (int hIdx = 0, rasterHIdx = i - yOrigin;
+ hIdx < kHeight;
+ hIdx++, rasterHIdx++
+ ){
+ for (int wIdx = 0, rasterWIdx = j - xOrigin;
+ wIdx < kWidth;
+ wIdx++, rasterWIdx++
+ ){
+ int curIndex = rasterHIdx * rowLength + rasterWIdx * numBands;
+ for (int idx=0; idx < numBands; idx++){
+ newPixels[pixelIndex+idx] += data[kernelIdx] * pixels[curIndex+idx];
+ }
+ kernelIdx--;
+ }
+ }
+
+ // Check for overflow now
+ for (int idx=0; idx < numBands; idx++){
+ if (((int)newPixels[pixelIndex+idx] & masks[idx]) != 0) {
+ if (newPixels[pixelIndex+idx] < 0) {
+ newPixels[pixelIndex+idx] = 0;
+ } else {
+ newPixels[pixelIndex+idx] = maxValues[idx];
+ }
+ }
+ }
+ }
+ }
+
+ dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, newPixels);
+ } catch (Exception e) { // Something goes wrong, signal error
+ return 1;
+ }
+ return 0;
+ }
+
+ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ if (src == null) {
+ // awt.259=Source image is null
+ throw new NullPointerException(Messages.getString("awt.259")); //$NON-NLS-1$
+ }
+
+ if (src == dst){
+ // awt.25A=Source equals to destination
+ throw new IllegalArgumentException(Messages.getString("awt.25A")); //$NON-NLS-1$
+ }
+
+ ColorModel srcCM = src.getColorModel();
+ BufferedImage finalDst = null;
+
+ if (srcCM instanceof IndexColorModel) {
+ src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true);
+ srcCM = src.getColorModel();
+ }
+
+ if (dst == null) {
+ dst = createCompatibleDestImage(src, srcCM);
+ } else {
+ if (!srcCM.equals(dst.getColorModel())) {
+ // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same
+ if (
+ !((src.getType() == BufferedImage.TYPE_INT_RGB ||
+ src.getType() == BufferedImage.TYPE_INT_ARGB) &&
+ (dst.getType() == BufferedImage.TYPE_INT_RGB ||
+ dst.getType() == BufferedImage.TYPE_INT_ARGB))
+ ) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, srcCM);
+ }
+ }
+ }
+
+ // Skip alpha channel for TYPE_INT_RGB images
+ // TODO
+ //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0)
+ if (slowFilter(src.getRaster(), dst.getRaster()) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ if (finalDst != null) {
+ Graphics2D g = finalDst.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.drawImage(dst, 0, 0, null);
+ } else {
+ finalDst = dst;
+ }
+
+ return finalDst;
+ }
+
+ // TODO remove when this method is used
+ /**
+ * Ipp filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param imageType the image type
+ *
+ * @return the int
+ */
+ @SuppressWarnings("unused")
+ private int ippFilter(Raster src, WritableRaster dst, int imageType) {
+ int srcStride, dstStride;
+ boolean skipChannel = false;
+ int channels;
+ int offsets[] = null;
+
+ switch (imageType) {
+ case BufferedImage.TYPE_INT_RGB:
+ case BufferedImage.TYPE_INT_BGR: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ skipChannel = true;
+ break;
+ }
+
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_GRAY: {
+ channels = 1;
+ srcStride = src.getWidth();
+ dstStride = dst.getWidth();
+ break;
+ }
+
+ case BufferedImage.TYPE_3BYTE_BGR: {
+ channels = 3;
+ srcStride = src.getWidth()*3;
+ dstStride = dst.getWidth()*3;
+ break;
+ }
+
+ case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in native code?
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ case BufferedImage.TYPE_BYTE_BINARY: {
+ return slowFilter(src, dst);
+ }
+
+ default: {
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+
+ if (
+ srcSM instanceof PixelInterleavedSampleModel &&
+ dstSM instanceof PixelInterleavedSampleModel
+ ) {
+ // Check PixelInterleavedSampleModel
+ if (
+ srcSM.getDataType() != DataBuffer.TYPE_BYTE ||
+ dstSM.getDataType() != DataBuffer.TYPE_BYTE
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels
+ if (!(channels == 1 || channels == 3 || channels == 4)) {
+ return slowFilter(src, dst);
+ }
+
+ srcStride = ((ComponentSampleModel) srcSM).getScanlineStride();
+ dstStride = ((ComponentSampleModel) dstSM).getScanlineStride();
+ } else if (
+ srcSM instanceof SinglePixelPackedSampleModel &&
+ dstSM instanceof SinglePixelPackedSampleModel
+ ) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM;
+ SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM;
+
+ channels = sppsm1.getNumBands();
+
+ // TYPE_INT_RGB, TYPE_INT_ARGB...
+ if (
+ sppsm1.getDataType() != DataBuffer.TYPE_INT ||
+ sppsm2.getDataType() != DataBuffer.TYPE_INT ||
+ !(channels == 3 || channels == 4)
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ // Check compatibility of sample models
+ if (
+ !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) ||
+ !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())
+ ) {
+ return slowFilter(src, dst);
+ }
+
+ for (int i=0; i<channels; i++) {
+ if (sppsm1.getSampleSize(i) != 8) {
+ return slowFilter(src, dst);
+ }
+ }
+
+ if (channels == 3) { // Cannot skip channel, don't know which is alpha...
+ channels = 4;
+ }
+
+ srcStride = sppsm1.getScanlineStride() * 4;
+ dstStride = sppsm2.getScanlineStride() * 4;
+ } else {
+ return slowFilter(src, dst);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (
+ src.getSampleModelTranslateX() != 0 ||
+ src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 ||
+ dst.getSampleModelTranslateY() != 0
+ ) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+ }
+ }
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ return ippFilter32f(
+ kernel.data, kernel.getWidth(), kernel.getHeight(),
+ kernel.getXOrigin(), kernel.getYOrigin(), edgeCond,
+ srcData, src.getWidth(), src.getHeight(), srcStride,
+ dstData, dst.getWidth(), dst.getHeight(), dstStride,
+ channels, skipChannel, offsets
+ );
+ }
+
+ /**
+ * Ipp filter32f.
+ *
+ * @param kernel the kernel
+ * @param kWidth the k width
+ * @param kHeight the k height
+ * @param anchorX the anchor x
+ * @param anchorY the anchor y
+ * @param borderType the border type
+ * @param src the src
+ * @param srcWidth the src width
+ * @param srcHeight the src height
+ * @param srcStride the src stride
+ * @param dst the dst
+ * @param dstWidth the dst width
+ * @param dstHeight the dst height
+ * @param dstStride the dst stride
+ * @param channels the channels
+ * @param skipChannel the skip channel
+ * @param offsets the offsets
+ *
+ * @return the int
+ */
+ private native int ippFilter32f(
+ float kernel[], int kWidth, int kHeight,
+ int anchorX, int anchorY, int borderType,
+ Object src, int srcWidth, int srcHeight, int srcStride,
+ Object dst, int dstWidth, int dstHeight, int dstStride,
+ int channels, boolean skipChannel, int offsets[]
+ );
+}
+
diff --git a/awt/java/awt/image/CropImageFilter.java b/awt/java/awt/image/CropImageFilter.java
new file mode 100644
index 0000000..e90c44a
--- /dev/null
+++ b/awt/java/awt/image/CropImageFilter.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+
+/**
+ * The CropImageFilter class crops a rectangular region of an source
+ * Image and provides a source for a new image containing the extracted
+ * region.
+ */
+public class CropImageFilter extends ImageFilter {
+
+ /** The HEIGHT. */
+ private final int X, Y, WIDTH, HEIGHT;
+
+ /**
+ * Instantiates a new CropImageFilter object with the specified
+ * rectangular area.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ */
+ public CropImageFilter(int x, int y, int w, int h) {
+ X = x;
+ Y = y;
+ WIDTH = w;
+ HEIGHT = h;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void setProperties(Hashtable<?, ?> props) {
+ Hashtable<Object, Object> fprops;
+ if(props == null) {
+ fprops = new Hashtable<Object, Object>();
+ } else {
+ fprops = (Hashtable<Object, Object>) props.clone();
+ }
+ String propName = "Crop Filters"; //$NON-NLS-1$
+ String prop = "x=" + X + "; y=" + Y + "; width=" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ WIDTH + "; height=" + HEIGHT; //$NON-NLS-1$
+ Object o = fprops.get(propName);
+ if(o != null){
+ if(o instanceof String){
+ prop = (String)o + "; " + prop; //$NON-NLS-1$
+ }else{
+ prop = o.toString() + "; " + prop; //$NON-NLS-1$
+ }
+ }
+ fprops.put(propName, prop);
+ consumer.setProperties(fprops);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) {
+
+ if(x + w < X || X + WIDTH < x ||
+ y + h < Y || Y + HEIGHT < y) {
+ return;
+ }
+
+ int destX, destY, destWidth, destHeight, endX, endY,
+ srcEndX, srcEndY;
+
+ int newOffset = off;
+
+ endX = X + WIDTH;
+ endY = Y + HEIGHT;
+
+ srcEndX = x + w;
+ srcEndY = y + h;
+
+ if(x <= X){
+ destX = 0;
+ newOffset += X;
+ if(endX >= srcEndX){
+ destWidth = srcEndX - X;
+ }else{
+ destWidth = WIDTH;
+ }
+ }else{
+ destX = x - X;
+ if(endX >= srcEndX){
+ destWidth = w;
+ }else{
+ destWidth = endX - x;
+ }
+ }
+
+
+ if(y <= Y){
+ newOffset += scansize * (Y - y);
+ destY = 0;
+ if(endY >= srcEndY){
+ destHeight = srcEndY - Y;
+ }else{
+ destHeight = HEIGHT;
+ }
+ }else{
+ destY = y - Y;
+ if(endY >= srcEndY){
+ destHeight = h;
+ }else{
+ destHeight = endY - y;
+ }
+ }
+ consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) {
+
+ if(x + w < X || X + WIDTH < x ||
+ y + h < Y || Y + HEIGHT < y) {
+ return;
+ }
+
+ int destX, destY, destWidth, destHeight, endX, endY,
+ srcEndX, srcEndY;
+
+ int newOffset = off;
+
+ endX = X + WIDTH;
+ endY = Y + HEIGHT;
+
+ srcEndX = x + w;
+ srcEndY = y + h;
+
+ if(x <= X){
+ destX = 0;
+ newOffset += X;
+ if(endX >= srcEndX){
+ destWidth = srcEndX - X;
+ }else{
+ destWidth = WIDTH;
+ }
+ }else{
+ destX = x - X;
+ if(endX >= srcEndX){
+ destWidth = w;
+ }else{
+ destWidth = endX - x;
+ }
+ }
+
+
+ if(y <= Y){
+ newOffset += scansize * (Y - y);
+ destY = 0;
+ if(endY >= srcEndY){
+ destHeight = srcEndY - Y;
+ }else{
+ destHeight = HEIGHT;
+ }
+ }else{
+ destY = y - Y;
+ if(endY >= srcEndY){
+ destHeight = h;
+ }else{
+ destHeight = endY - y;
+ }
+ }
+ consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize);
+ }
+
+ @Override
+ public void setDimensions(int w, int h) {
+ consumer.setDimensions(WIDTH, HEIGHT);
+ }
+
+}
+
diff --git a/awt/java/awt/image/DataBuffer.java b/awt/java/awt/image/DataBuffer.java
new file mode 100644
index 0000000..6856aee
--- /dev/null
+++ b/awt/java/awt/image/DataBuffer.java
@@ -0,0 +1,442 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class DataBuffer is a wrapper class for a data array
+ * to be used for the situation where a suite of functionality
+ * acts on a set of data in a consistent way even though the
+ * primitive type of the data may vary from one use to the next.
+ */
+public abstract class DataBuffer {
+
+ /** The Constant TYPE_BYTE. */
+ public static final int TYPE_BYTE = 0;
+
+ /** The Constant TYPE_USHORT. */
+ public static final int TYPE_USHORT = 1;
+
+ /** The Constant TYPE_SHORT. */
+ public static final int TYPE_SHORT = 2;
+
+ /** The Constant TYPE_INT. */
+ public static final int TYPE_INT = 3;
+
+ /** The Constant TYPE_FLOAT. */
+ public static final int TYPE_FLOAT = 4;
+
+ /** The Constant TYPE_DOUBLE. */
+ public static final int TYPE_DOUBLE = 5;
+
+ /** The Constant TYPE_UNDEFINED. */
+ public static final int TYPE_UNDEFINED = 32;
+
+ /** The data type indicates the primitive type of the
+ * data in this DataBuffer. */
+ protected int dataType;
+
+ /** The number of data arrays in this DataBuffer. */
+ protected int banks;
+
+ /** The starting index for reading the
+ * data from the first (or only) internal data array. */
+ protected int offset;
+
+ /** The length (number of elements) of the data arrays. */
+ protected int size;
+
+ /** The starting indices for reading the
+ * data from the internal data arrays. */
+ protected int offsets[];
+
+ /** The data changed. */
+ boolean dataChanged = true;
+
+ /** The data taken. */
+ boolean dataTaken = false;
+
+ /** The listener. */
+ DataBufferListener listener;
+
+ static {
+ AwtImageBackdoorAccessorImpl.init();
+ }
+
+ /**
+ * Instantiates a new data buffer.
+ *
+ * @param dataType the data type
+ * @param size the length (number of elements) of the data arrays
+ * @param numBanks the number of data arrays to create
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) {
+ this.dataType = dataType;
+ this.size = size;
+ this.banks = numBanks;
+ this.offsets = offsets.clone();
+ this.offset = offsets[0];
+ }
+
+ /**
+ * Instantiates a new data buffer with all of the
+ * data arrays starting at the same index.
+ *
+ * @param dataType the data type
+ * @param size the length (number of elements) of the data arrays
+ * @param numBanks the number of data arrays to create
+ * @param offset the offset to use for all of the data arrays
+ */
+ protected DataBuffer(int dataType, int size, int numBanks, int offset) {
+ this.dataType = dataType;
+ this.size = size;
+ this.banks = numBanks;
+ this.offset = offset;
+ this.offsets = new int[numBanks];
+ int i = 0;
+ while (i < numBanks) {
+ offsets[i++] = offset;
+ }
+ }
+
+ /**
+ * Instantiates a new data buffer with all of the
+ * data arrays read from the beginning (at offset zero).
+ *
+ * @param dataType the data type
+ * @param size the length (number of elements) of the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ protected DataBuffer(int dataType, int size, int numBanks) {
+ this.dataType = dataType;
+ this.size = size;
+ this.banks = numBanks;
+ this.offset = 0;
+ this.offsets = new int[numBanks];
+ }
+
+ /**
+ * Instantiates a new data buffer with one internal data array
+ * read from the beginning (at offset zero).
+ *
+ * @param dataType the data type
+ * @param size the length (number of elements) of the data arrays
+ */
+ protected DataBuffer(int dataType, int size) {
+ this.dataType = dataType;
+ this.size = size;
+ this.banks = 1;
+ this.offset = 0;
+ this.offsets = new int[1];
+ }
+
+ /**
+ * Sets the data value in the specified array at the
+ * specified index.
+ *
+ * @param bank the internal array to the data to
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public abstract void setElem(int bank, int i, int val);
+
+ /**
+ * Sets the float data value in the specified array at the
+ * specified index.
+ *
+ * @param bank the internal array to the data to
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public void setElemFloat(int bank, int i, float val) {
+ setElem(bank, i, (int) val);
+ }
+
+ /**
+ * Sets the double data value in the specified array at the
+ * specified index.
+ *
+ * @param bank the internal array to the data to
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public void setElemDouble(int bank, int i, double val) {
+ setElem(bank, i, (int) val);
+ }
+
+ /**
+ * Sets the data value in the first array at the
+ * specified index.
+ *
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public void setElem(int i, int val) {
+ setElem(0, i, val);
+ }
+
+ /**
+ * Gets the data value from the specified data array at the
+ * specified index.
+ *
+ * @param bank the data array to read from
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public abstract int getElem(int bank, int i);
+
+ /**
+ * Gets the float-type data value from the specified
+ * data array at the specified index.
+ *
+ * @param bank the data array to read from
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public float getElemFloat(int bank, int i) {
+ return getElem(bank, i);
+ }
+
+ /**
+ * Gets the double-type data value from the specified
+ * data array at the specified index.
+ *
+ * @param bank the data array to read from
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public double getElemDouble(int bank, int i) {
+ return getElem(bank, i);
+ }
+
+ /**
+ * Sets the float data value in the first array at the
+ * specified index.
+ *
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public void setElemFloat(int i, float val) {
+ setElemFloat(0, i, val);
+ }
+
+ /**
+ * Sets the double data value in the first array at the
+ * specified index.
+ *
+ * @param i the index within the array where the data
+ * should be written
+ * @param val the value to write into the array
+ */
+ public void setElemDouble(int i, double val) {
+ setElemDouble(0, i, val);
+ }
+
+ /**
+ * Gets the data value from the first
+ * data array at the specified index and returns it
+ * as an int.
+ *
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public int getElem(int i) {
+ return getElem(0, i);
+ }
+
+ /**
+ * Gets the data value from the first
+ * data array at the specified index and returns it
+ * as a float.
+ *
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public float getElemFloat(int i) {
+ return getElem(0, i);
+ }
+
+ /**
+ * Gets the data value from the first
+ * data array at the specified index and returns it
+ * as a double.
+ *
+ * @param i the index within the array where the data
+ * should be read
+ *
+ * @return the data element
+ */
+ public double getElemDouble(int i) {
+ return getElem(i);
+ }
+
+ /**
+ * Gets the array giving the offsets corresponding
+ * to the internal data arrays.
+ *
+ * @return the array of offsets
+ */
+ public int[] getOffsets() {
+ return offsets;
+ }
+
+ /**
+ * Gets the size in bits of the primitive data type.
+ *
+ * @return the size in bits of the primitive data type
+
+ */
+ public int getSize() {
+ return size;
+ }
+
+ /**
+ * Gets the offset corresponding to the first internal
+ * data array.
+ *
+ * @return the offset
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Gets the number of data arrays in this DataBuffer.
+ *
+ * @return the number of data arrays
+ */
+ public int getNumBanks() {
+ return banks;
+ }
+
+ /**
+ * Gets the primitive type of this buffer's data.
+ *
+ * @return the data type
+ */
+ public int getDataType() {
+ return this.dataType;
+ }
+
+ /**
+ * Gets the size in bits of the primitive data type.
+ *
+ * @param type the primitive type
+ *
+ * @return the size in bits of the primitive data type
+ */
+ public static int getDataTypeSize(int type) {
+ switch (type) {
+
+ case TYPE_BYTE:
+ return 8;
+
+ case TYPE_USHORT:
+ case TYPE_SHORT:
+ return 16;
+
+ case TYPE_INT:
+ case TYPE_FLOAT:
+ return 32;
+
+ case TYPE_DOUBLE:
+ return 64;
+
+ default:
+ // awt.22C=Unknown data type {0}
+ throw new IllegalArgumentException(Messages.getString("awt.22C", type)); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Notifies the listener that the data has changed.
+ */
+ void notifyChanged(){
+ if(listener != null && !dataChanged){
+ dataChanged = true;
+ listener.dataChanged();
+ }
+ }
+
+ /**
+ * Notifies the listener that the data has been released.
+ */
+ void notifyTaken(){
+ if(listener != null && !dataTaken){
+ dataTaken = true;
+ listener.dataTaken();
+ }
+ }
+
+ /**
+ * Release the data.
+ */
+ void releaseData(){
+ if(listener != null && dataTaken){
+ dataTaken = false;
+ listener.dataReleased();
+ }
+ }
+
+ /**
+ * Adds the data buffer listener.
+ *
+ * @param listener the listener
+ */
+ void addDataBufferListener(DataBufferListener listener){
+ this.listener = listener;
+ }
+
+ /**
+ * Removes the data buffer listener.
+ */
+ void removeDataBufferListener(){
+ listener = null;
+ }
+
+ /**
+ * Validate.
+ */
+ void validate(){
+ dataChanged = false;
+ }
+
+}
+
diff --git a/awt/java/awt/image/DataBufferByte.java b/awt/java/awt/image/DataBufferByte.java
new file mode 100644
index 0000000..4d29c9c
--- /dev/null
+++ b/awt/java/awt/image/DataBufferByte.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+/**
+ * The Class DataBufferByte is the subclass of DataBuffer
+ * for the case where the underlying data is of type byte.
+ */
+public final class DataBufferByte extends DataBuffer {
+
+ /** The data. */
+ byte data[][];
+
+ /**
+ * Instantiates a new data buffer of type unsigned short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferByte(byte dataArrays[][], int size, int offsets[]) {
+ super(TYPE_BYTE, size, dataArrays.length, offsets);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferByte(byte dataArrays[][], int size) {
+ super(TYPE_BYTE, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+ */
+ public DataBufferByte(byte dataArray[], int size, int offset) {
+ super(TYPE_BYTE, size, 1, offset);
+ data = new byte[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferByte(byte dataArray[], int size) {
+ super(TYPE_BYTE, size);
+ data = new byte[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type unsigned short
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferByte(int size, int numBanks) {
+ super(TYPE_BYTE, size, numBanks);
+ data = new byte[numBanks][];
+ int i = 0;
+ while (i < numBanks) {
+ data[i++] = new byte[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type unsigned short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferByte(int size) {
+ super(TYPE_BYTE, size);
+ data = new byte[1][];
+ data[0] = new byte[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = (byte) val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = (byte) val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return (data[bank][offsets[bank] + i]) & 0xff;
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired data array
+ *
+ * @return the data
+ */
+ public byte[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return (data[0][offset + i]) & 0xff;
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public byte[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public byte[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+
+}
+
diff --git a/awt/java/awt/image/DataBufferDouble.java b/awt/java/awt/image/DataBufferDouble.java
new file mode 100644
index 0000000..fa3d324
--- /dev/null
+++ b/awt/java/awt/image/DataBufferDouble.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+/**
+ * The Class DataBufferDouble is the subclass of DataBuffer
+ * for the case where the underlying data is of type double.
+ */
+public final class DataBufferDouble extends DataBuffer {
+
+ /** The data. */
+ double data[][];
+
+ /**
+ * Instantiates a new data buffer of type double.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferDouble(double dataArrays[][], int size, int offsets[]) {
+ super(TYPE_DOUBLE, size, dataArrays.length, offsets);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type double.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferDouble(double dataArrays[][], int size) {
+ super(TYPE_DOUBLE, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type double
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+ */
+ public DataBufferDouble(double dataArray[], int size, int offset) {
+ super(TYPE_DOUBLE, size, 1, offset);
+ data = new double[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type double
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferDouble(double dataArray[], int size) {
+ super(TYPE_DOUBLE, size);
+ data = new double[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type double
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferDouble(int size, int numBanks) {
+ super(TYPE_DOUBLE, size, numBanks);
+ data = new double[numBanks][];
+ int i = 0;
+ while (i < numBanks) {
+ data[i++] = new double[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type double
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferDouble(int size) {
+ super(TYPE_DOUBLE, size);
+ data = new double[1][];
+ data[0] = new double[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemFloat(int bank, int i, float val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemDouble(int bank, int i, double val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return (int) (data[bank][offsets[bank] + i]);
+ }
+
+ @Override
+ public float getElemFloat(int bank, int i) {
+ return (float) (data[bank][offsets[bank] + i]);
+ }
+
+ @Override
+ public double getElemDouble(int bank, int i) {
+ return data[bank][offsets[bank] + i];
+ }
+
+ @Override
+ public void setElemFloat(int i, float val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemDouble(int i, double val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired data array
+ *
+ * @return the data
+ */
+ public double[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return (int) (data[0][offset + i]);
+ }
+
+ @Override
+ public float getElemFloat(int i) {
+ return (float) (data[0][offset + i]);
+ }
+
+ @Override
+ public double getElemDouble(int i) {
+ return data[0][offset + i];
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public double[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public double[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+}
+
diff --git a/awt/java/awt/image/DataBufferFloat.java b/awt/java/awt/image/DataBufferFloat.java
new file mode 100644
index 0000000..e34245c
--- /dev/null
+++ b/awt/java/awt/image/DataBufferFloat.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+/**
+ * The Class DataBufferFloat is the subclass of DataBuffer
+ * for the case where the underlying data is float.
+ */
+public final class DataBufferFloat extends DataBuffer {
+
+ /** The data. */
+ float data[][];
+
+ /**
+ * Instantiates a new data buffer of type float.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferFloat(float dataArrays[][], int size, int offsets[]) {
+ super(TYPE_FLOAT, size, dataArrays.length, offsets);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type float.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferFloat(float dataArrays[][], int size) {
+ super(TYPE_FLOAT, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type float
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+ */
+ public DataBufferFloat(float dataArray[], int size, int offset) {
+ super(TYPE_FLOAT, size, 1, offset);
+ data = new float[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type float
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferFloat(float dataArray[], int size) {
+ super(TYPE_FLOAT, size);
+ data = new float[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type float
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferFloat(int size, int numBanks) {
+ super(TYPE_FLOAT, size, numBanks);
+ data = new float[numBanks][];
+ int i = 0;
+ while (i < numBanks) {
+ data[i++] = new float[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type float
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferFloat(int size) {
+ super(TYPE_FLOAT, size);
+ data = new float[1][];
+ data[0] = new float[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemFloat(int bank, int i, float val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemDouble(int bank, int i, double val) {
+ data[bank][offsets[bank] + i] = (float) val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return (int) (data[bank][offsets[bank] + i]);
+ }
+
+ @Override
+ public float getElemFloat(int bank, int i) {
+ return data[bank][offsets[bank] + i];
+ }
+
+ @Override
+ public double getElemDouble(int bank, int i) {
+ return data[bank][offsets[bank] + i];
+ }
+
+ @Override
+ public void setElemFloat(int i, float val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElemDouble(int i, double val) {
+ data[0][offset + i] = (float) val;
+ notifyChanged();
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired array
+ *
+ * @return the data
+ */
+ public float[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return (int) (data[0][offset + i]);
+ }
+
+ @Override
+ public float getElemFloat(int i) {
+ return data[0][offset + i];
+ }
+
+ @Override
+ public double getElemDouble(int i) {
+ return data[0][offset + i];
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public float[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public float[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+}
+
diff --git a/awt/java/awt/image/DataBufferInt.java b/awt/java/awt/image/DataBufferInt.java
new file mode 100644
index 0000000..43dc188
--- /dev/null
+++ b/awt/java/awt/image/DataBufferInt.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+/**
+ * The Class DataBufferInt is the subclass of DataBuffer
+ * for the case where the underlying data is of type int.
+ */
+public final class DataBufferInt extends DataBuffer {
+
+ /** The data. */
+ int data[][];
+
+ /**
+ * Instantiates a new data buffer of type int.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferInt(int dataArrays[][], int size, int offsets[]) {
+ super(TYPE_INT, size, dataArrays.length, offsets);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type int.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferInt(int dataArrays[][], int size) {
+ super(TYPE_INT, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type int
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+ */
+ public DataBufferInt(int dataArray[], int size, int offset) {
+ super(TYPE_INT, size, 1, offset);
+ data = new int[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type int
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferInt(int dataArray[], int size) {
+ super(TYPE_INT, size);
+ data = new int[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type int
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferInt(int size, int numBanks) {
+ super(TYPE_INT, size, numBanks);
+ data = new int[numBanks][];
+ int i = 0;
+ while (i < numBanks) {
+ data[i++] = new int[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type int
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferInt(int size) {
+ super(TYPE_INT, size);
+ data = new int[1][];
+ data[0] = new int[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return data[bank][offsets[bank] + i];
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired data array
+ *
+ * @return the data
+ */
+ public int[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return data[0][offset + i];
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public int[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public int[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+}
+
diff --git a/awt/java/awt/image/DataBufferShort.java b/awt/java/awt/image/DataBufferShort.java
new file mode 100644
index 0000000..819ba4a
--- /dev/null
+++ b/awt/java/awt/image/DataBufferShort.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+/**
+ * The Class DataBufferShort is the subclass of DataBuffer
+ * for the case where the underlying data is short.
+ */
+public final class DataBufferShort extends DataBuffer {
+
+ /** The data. */
+ short data[][];
+
+ /**
+ * Instantiates a new data buffer of type short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferShort(short dataArrays[][], int size, int offsets[]) {
+ super(TYPE_SHORT, size, dataArrays.length, offsets);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferShort(short dataArrays[][], int size) {
+ super(TYPE_SHORT, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type short
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+
+ */
+ public DataBufferShort(short dataArray[], int size, int offset) {
+ super(TYPE_SHORT, size, 1, offset);
+ data = new short[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+
+ */
+ public DataBufferShort(short dataArray[], int size) {
+ super(TYPE_SHORT, size);
+ data = new short[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type short
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferShort(int size, int numBanks) {
+ super(TYPE_SHORT, size, numBanks);
+ data = new short[numBanks][];
+ int i = 0;
+ while (i < numBanks) {
+ data[i++] = new short[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferShort(int size) {
+ super(TYPE_SHORT, size);
+ data = new short[1][];
+ data[0] = new short[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = (short) val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = (short) val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return (data[bank][offsets[bank] + i]);
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired data array
+ *
+ * @return the data
+ */
+ public short[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return (data[0][offset + i]);
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public short[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public short[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+}
+
diff --git a/awt/java/awt/image/DataBufferUShort.java b/awt/java/awt/image/DataBufferUShort.java
new file mode 100644
index 0000000..7982678
--- /dev/null
+++ b/awt/java/awt/image/DataBufferUShort.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class DataBufferUShort is the subclass of DataBuffer
+ * for the case where the underlying data is unsigned short.
+ */
+public final class DataBufferUShort extends DataBuffer {
+
+ /** The data. */
+ short data[][];
+
+ /**
+ * Instantiates a new data buffer of type unsigned short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param offsets the starting indices for reading the
+ * data from the internal data arrays
+ */
+ public DataBufferUShort(short dataArrays[][], int size, int offsets[]) {
+ super(TYPE_USHORT, size, dataArrays.length, offsets);
+ for(int i = 0; i < dataArrays.length; i++){
+ if(dataArrays[i].length < offsets[i] + size){
+ // awt.28d=Length of dataArray[{0}] is less than size + offset[{1}]
+ throw new IllegalArgumentException(Messages.getString("awt.28D", i, i)); //$NON-NLS-1$
+ }
+ }
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short.
+ *
+ * @param dataArrays the data arrays to copy the data from
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ */
+ public DataBufferUShort(short dataArrays[][], int size) {
+ super(TYPE_USHORT, size, dataArrays.length);
+ data = dataArrays.clone();
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short
+ * with a single underlying array of data.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ * @param offset the starting index to use when reading the data
+ */
+ public DataBufferUShort(short dataArray[], int size, int offset) {
+ super(TYPE_USHORT, size, 1, offset);
+ if(dataArray.length < size + offset){
+ // awt.28E=Length of dataArray is less than size + offset
+ throw new IllegalArgumentException(Messages.getString("awt.28E")); //$NON-NLS-1$
+ }
+ data = new short[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new data buffer of type unsigned short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param dataArray the data array to copy the data from
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferUShort(short dataArray[], int size) {
+ super(TYPE_USHORT, size);
+ data = new short[1][];
+ data[0] = dataArray;
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type unsigned short
+ * with offsets equal to zero.
+ *
+ * @param size the length (number of elements) to use
+ * from the data arrays
+ * @param numBanks the number of data arrays to create
+ */
+ public DataBufferUShort(int size, int numBanks) {
+ super(TYPE_USHORT, size, numBanks);
+ data = new short[numBanks][];
+ int i= 0;
+ while( i < numBanks) {
+ data[i++] = new short[size];
+ }
+ }
+
+ /**
+ * Instantiates a new empty data buffer of type unsigned short
+ * with a single underlying array of data starting at
+ * index 0.
+ *
+ * @param size the length (number of elements) to use
+ */
+ public DataBufferUShort(int size) {
+ super(TYPE_USHORT, size);
+ data = new short[1][];
+ data[0] = new short[size];
+ }
+
+ @Override
+ public void setElem(int bank, int i, int val) {
+ data[bank][offsets[bank] + i] = (short)val;
+ notifyChanged();
+ }
+
+ @Override
+ public void setElem(int i, int val) {
+ data[0][offset + i] = (short)val;
+ notifyChanged();
+ }
+
+ @Override
+ public int getElem(int bank, int i) {
+ return (data[bank][offsets[bank] + i]) & 0xffff;
+ }
+
+ /**
+ * Gets the data of the specified internal data array.
+ *
+ * @param bank the index of the desired data array
+ *
+ * @return the data
+ */
+ public short[] getData(int bank) {
+ notifyTaken();
+ return data[bank];
+ }
+
+ @Override
+ public int getElem(int i) {
+ return (data[0][offset + i]) & 0xffff;
+ }
+
+ /**
+ * Gets the bank data.
+ *
+ * @return the bank data
+ */
+ public short[][] getBankData() {
+ notifyTaken();
+ return data.clone();
+ }
+
+ /**
+ * Gets the data of the first data array.
+ *
+ * @return the data
+ */
+ public short[] getData() {
+ notifyTaken();
+ return data[0];
+ }
+}
+
diff --git a/awt/java/awt/image/DirectColorModel.java b/awt/java/awt/image/DirectColorModel.java
new file mode 100644
index 0000000..7a287c0
--- /dev/null
+++ b/awt/java/awt/image/DirectColorModel.java
@@ -0,0 +1,862 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.color.ColorSpace;
+import java.awt.Transparency;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class DirectColorModel represents a standard (packed) RGB
+ * color model with additional support for converting between sRGB
+ * color space and 8 or 16 bit linear RGB color space using lookup tables.
+ */
+public class DirectColorModel extends PackedColorModel {
+
+ /** The from_ linea r_ rg b_ lut. */
+ private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from
+ // Linear RGB Color Space into sRGB
+
+ /** The to_ linea r_8 rg b_ lut. */
+ private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from
+ // sRGB Color Space into Linear RGB
+ // 8 bit
+
+ /** The to_ linea r_16 rg b_ lut. */
+ private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from
+ // sRGB Color Space into Linear RGB
+ // 16 bit
+
+ /** The alpha lut. */
+ private byte alphaLUT[]; // Lookup table for scale alpha value
+
+ /** The color lu ts. */
+ private byte colorLUTs[][]; // Lookup tables for scale color values
+
+ /** The is_s rgb. */
+ private boolean is_sRGB; // ColorModel has sRGB ColorSpace
+
+ /** The is_ linea r_ rgb. */
+ private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color
+ // Space
+
+ /** The LINEA r_ rg b_ length. */
+ private int LINEAR_RGB_Length; // Linear RGB bit length
+
+ /** The factor. */
+ private float fFactor; // Scale factor
+
+ /**
+ * Instantiates a new direct color model.
+ *
+ * @param space the color space
+ * @param bits the array of component masks
+ * @param rmask the bitmask corresponding to the red band
+ * @param gmask the bitmask corresponding to the green band
+ * @param bmask the bitmask corresponding to the blue band
+ * @param amask the bitmask corresponding to the alpha band
+ * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ *
+ * @throws IllegalArgumentException if the number of bits in the combined
+ * bitmasks for the color bands is less than one or greater than 32
+ */
+ public DirectColorModel(ColorSpace space, int bits, int rmask, int gmask,
+ int bmask, int amask, boolean isAlphaPremultiplied,
+ int transferType) {
+
+ super(space, bits, rmask, gmask, bmask, amask, isAlphaPremultiplied,
+ (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT),
+ transferType);
+
+ initLUTs();
+ }
+
+ /**
+ * Instantiates a new direct color model, determining the transfer
+ * type from the bits array, the transparency from the alpha mask,
+ * and the default color space {@link ColorSpace#CS_sRGB}.
+ *
+ * @param bits the array of component masks
+ * @param rmask the bitmask corresponding to the red band
+ * @param gmask the bitmask corresponding to the green band
+ * @param bmask the bitmask corresponding to the blue band
+ * @param amask the bitmask corresponding to the alpha band
+ */
+ public DirectColorModel(int bits, int rmask, int gmask, int bmask,
+ int amask) {
+
+ super(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, rmask, gmask,
+ bmask, amask, false,
+ (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT),
+ ColorModel.getTransferType(bits));
+
+ initLUTs();
+ }
+
+ /**
+ * Instantiates a new direct color model with no alpha channel,
+ * determining the transfer type from the bits array,
+ * the default color space {@link ColorSpace#CS_sRGB},
+ * and with the transparency set to {@link Transparency#OPAQUE}.
+ *
+ * @param bits the array of component masks
+ * @param rmask the bitmask corresponding to the red band
+ * @param gmask the bitmask corresponding to the green band
+ * @param bmask the bitmask corresponding to the blue band
+ */
+ public DirectColorModel(int bits, int rmask, int gmask, int bmask) {
+ this(bits, rmask, gmask, bmask, 0);
+ }
+
+ @Override
+ public Object getDataElements(int components[], int offset, Object obj) {
+ int pixel = 0;
+ for (int i = 0; i < numComponents; i++) {
+ pixel |= (components[offset + i] << offsets[i]) & componentMasks[i];
+ }
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[];
+ if (obj == null) {
+ ba = new byte[1];
+ } else {
+ ba = (byte[]) obj;
+ }
+ ba[0] = (byte) pixel;
+ obj = ba;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[];
+ if (obj == null) {
+ sa = new short[1];
+ } else {
+ sa = (short[]) obj;
+ }
+ sa[0] = (short) pixel;
+ obj = sa;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[];
+ if (obj == null) {
+ ia = new int[1];
+ } else {
+ ia = (int[]) obj;
+ }
+ ia[0] = pixel;
+ obj = ia;
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+
+ return obj;
+ }
+
+ @Override
+ public Object getDataElements(int rgb, Object pixel) {
+ if (equals(ColorModel.getRGBdefault())) {
+ int ia[];
+ if (pixel == null) {
+ ia = new int[1];
+ } else {
+ ia = (int[]) pixel;
+ }
+ ia[0] = rgb;
+ return ia;
+ }
+
+ int alpha = (rgb >> 24) & 0xff;
+ int red = (rgb >> 16) & 0xff;
+ int green = (rgb >> 8) & 0xff;
+ int blue = rgb & 0xff;
+
+ float comp[] = new float[numColorComponents];
+ float normComp[] = null;
+
+ if (is_sRGB || is_LINEAR_RGB) {
+ if (is_LINEAR_RGB) {
+ if (LINEAR_RGB_Length == 8) {
+ red = to_LINEAR_8RGB_LUT[red] & 0xff;
+ green = to_LINEAR_8RGB_LUT[green] & 0xff;
+ blue = to_LINEAR_8RGB_LUT[blue] & 0xff;
+ } else {
+ red = to_LINEAR_16RGB_LUT[red] & 0xffff;
+ green = to_LINEAR_16RGB_LUT[green] & 0xffff;
+ blue = to_LINEAR_16RGB_LUT[blue] & 0xffff;
+ }
+ }
+ comp[0] = red / fFactor;
+ comp[1] = green / fFactor;
+ comp[2] = blue / fFactor;
+ if (!hasAlpha) {
+ normComp = comp;
+ } else {
+ float normAlpha = alpha / 255.0f;
+ normComp = new float[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ normComp[i] = comp[i];
+ }
+ normComp[numColorComponents] = normAlpha;
+ }
+ } else {
+ comp[0] = red / fFactor;
+ comp[1] = green / fFactor;
+ comp[2] = blue / fFactor;
+ float rgbComp[] = cs.fromRGB(comp);
+ if (!hasAlpha) {
+ normComp = rgbComp;
+ } else {
+ float normAlpha = alpha / 255.0f;
+ normComp = new float[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ normComp[i] = rgbComp[i];
+ }
+ normComp[numColorComponents] = normAlpha;
+ }
+ }
+
+ int pxl = 0;
+ if (hasAlpha) {
+ float normAlpha = normComp[numColorComponents];
+ alpha = (int) (normAlpha * maxValues[numColorComponents] + 0.5f);
+ if (isAlphaPremultiplied) {
+ red = (int) (normComp[0] * normAlpha * maxValues[0] + 0.5f);
+ green = (int) (normComp[1] * normAlpha * maxValues[1] + 0.5f);
+ blue = (int) (normComp[2] * normAlpha * maxValues[2] + 0.5f);
+ } else {
+ red = (int) (normComp[0] * maxValues[0] + 0.5f);
+ green = (int) (normComp[1] * maxValues[1] + 0.5f);
+ blue = (int) (normComp[2] * maxValues[2] + 0.5f);
+ }
+ pxl = (alpha << offsets[3]) & componentMasks[3];
+ } else {
+ red = (int) (normComp[0] * maxValues[0] + 0.5f);
+ green = (int) (normComp[1] * maxValues[1] + 0.5f);
+ blue = (int) (normComp[2] * maxValues[2] + 0.5f);
+ }
+
+ pxl |= ((red << offsets[0]) & componentMasks[0]) |
+ ((green << offsets[1]) & componentMasks[1]) |
+ ((blue << offsets[2]) & componentMasks[2]);
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[];
+ if (pixel == null) {
+ ba = new byte[1];
+ } else {
+ ba = (byte[]) pixel;
+ }
+ ba[0] = (byte) pxl;
+ return ba;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[];
+ if (pixel == null) {
+ sa = new short[1];
+ } else {
+ sa = (short[]) pixel;
+ }
+ sa[0] = (short) pxl;
+ return sa;
+
+ case DataBuffer.TYPE_INT:
+ int ia[];
+ if (pixel == null) {
+ ia = new int[1];
+ } else {
+ ia = (int[]) pixel;
+ }
+ ia[0] = pxl;
+ return ia;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public final ColorModel coerceData(WritableRaster raster,
+ boolean isAlphaPremultiplied) {
+
+ if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) {
+ return this;
+ }
+
+ int minX = raster.getMinX();
+ int minY = raster.getMinY();
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+
+ int components[] = null;
+ int transparentComponents[] = new int[numComponents];
+
+ float alphaFactor = maxValues[numColorComponents];
+
+ if (isAlphaPremultiplied) {
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ components = raster.getPixel(x, minY, components);
+ if (components[numColorComponents] == 0) {
+ raster.setPixel(x, minY, transparentComponents);
+ } else {
+ float alpha =
+ components[numColorComponents] /
+ alphaFactor;
+ for (int n = 0; n < numColorComponents; n++) {
+ components[n] =
+ (int) (alpha * components[n] + 0.5f);
+ }
+ raster.setPixel(x, minY, components);
+ }
+ }
+
+ }
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ } else {
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ for (int i = 0; i < h; i++, minY++) {
+ for (int j = 0, x = minX; j < w; j++, x++) {
+ components = raster.getPixel(x, minY, components);
+ if (components[numColorComponents] != 0) {
+ float alpha =
+ alphaFactor / components[numColorComponents];
+ for (int n = 0; n < numColorComponents; n++) {
+ components[n] =
+ (int) (alpha * components[n] + 0.5f);
+ }
+ raster.setPixel(x, minY, components);
+ }
+ }
+
+ }
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+
+ }
+
+ return new DirectColorModel(cs, pixel_bits, componentMasks[0],
+ componentMasks[1], componentMasks[2], componentMasks[3],
+ isAlphaPremultiplied, transferType);
+ }
+
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour.
+ // It could be reveled such way:
+ // BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+ // ColorModel cm = bi.getColorModel();
+ // System.out.println(cm.toString());
+ String str = "DirectColorModel:" + " rmask = " + //$NON-NLS-1$ //$NON-NLS-2$
+ Integer.toHexString(componentMasks[0]) + " gmask = " + //$NON-NLS-1$
+ Integer.toHexString(componentMasks[1]) + " bmask = " + //$NON-NLS-1$
+ Integer.toHexString(componentMasks[2]) + " amask = " + //$NON-NLS-1$
+ (!hasAlpha ? "0" : Integer.toHexString(componentMasks[3])); //$NON-NLS-1$
+
+ return str;
+ }
+
+ @Override
+ public final int[] getComponents(Object pixel, int components[],
+ int offset) {
+
+ if (components == null) {
+ components = new int[numComponents + offset];
+ }
+
+ int intPixel = 0;
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) pixel;
+ intPixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) pixel;
+ intPixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) pixel;
+ intPixel = ia[0];
+ break;
+
+ default:
+ // awt.22D=This transferType ( {0} ) is not supported by this color model
+ throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$
+ transferType));
+ }
+
+ return getComponents(intPixel, components, offset);
+ }
+
+ @Override
+ public int getRed(Object inData) {
+ int pixel = 0;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) inData;
+ pixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) inData;
+ pixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) inData;
+ pixel = ia[0];
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ return getRed(pixel);
+ }
+
+ @Override
+ public int getRGB(Object inData) {
+ int pixel = 0;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) inData;
+ pixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) inData;
+ pixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) inData;
+ pixel = ia[0];
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ return getRGB(pixel);
+ }
+
+ @Override
+ public int getGreen(Object inData) {
+ int pixel = 0;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) inData;
+ pixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) inData;
+ pixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) inData;
+ pixel = ia[0];
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ return getGreen(pixel);
+ }
+
+ @Override
+ public int getBlue(Object inData) {
+ int pixel = 0;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) inData;
+ pixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) inData;
+ pixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) inData;
+ pixel = ia[0];
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ return getBlue(pixel);
+ }
+
+ @Override
+ public int getAlpha(Object inData) {
+ int pixel = 0;
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) inData;
+ pixel = ba[0] & 0xff;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) inData;
+ pixel = sa[0] & 0xffff;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ia[] = (int[]) inData;
+ pixel = ia[0];
+ break;
+
+ default:
+ // awt.214=This Color Model doesn't support this transferType
+ throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$
+ }
+ return getAlpha(pixel);
+ }
+
+ @Override
+ public final WritableRaster createCompatibleWritableRaster(int w, int h) {
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ int bandMasks[] = componentMasks.clone();
+
+ if (pixel_bits > 16) {
+ return Raster.createPackedRaster(DataBuffer.TYPE_INT, w, h,
+ bandMasks, null);
+ } else if (pixel_bits > 8) {
+ return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, w, h,
+ bandMasks, null);
+ } else {
+ return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h,
+ bandMasks, null);
+ }
+ }
+
+ @Override
+ public boolean isCompatibleRaster(Raster raster) {
+ SampleModel sm = raster.getSampleModel();
+ if (!(sm instanceof SinglePixelPackedSampleModel)) {
+ return false;
+ }
+
+ SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+
+ if (sppsm.getNumBands() != numComponents) {
+ return false;
+ }
+ if (raster.getTransferType() != transferType) {
+ return false;
+ }
+
+ int maskBands[] = sppsm.getBitMasks();
+ return Arrays.equals(maskBands, componentMasks);
+ }
+
+ @Override
+ public int getDataElement(int components[], int offset) {
+ int pixel = 0;
+ for (int i = 0; i < numComponents; i++) {
+ pixel |= (components[offset + i] << offsets[i]) & componentMasks[i];
+ }
+ return pixel;
+ }
+
+ @Override
+ public final int[] getComponents(int pixel, int components[], int offset) {
+ if (components == null) {
+ components = new int[numComponents + offset];
+ }
+ for (int i = 0; i < numComponents; i++) {
+ components[offset + i] = (pixel & componentMasks[i]) >> offsets[i];
+ }
+ return components;
+ }
+
+ @Override
+ public final int getRed(int pixel) {
+ if (is_sRGB) {
+ return getComponentFrom_sRGB(pixel, 0);
+ }
+ if (is_LINEAR_RGB) {
+ return getComponentFrom_LINEAR_RGB(pixel, 0);
+ }
+ return getComponentFrom_RGB(pixel, 0);
+ }
+
+ @Override
+ public final int getRGB(int pixel) {
+ return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) |
+ (getGreen(pixel) << 8) | getBlue(pixel);
+ }
+
+ @Override
+ public final int getGreen(int pixel) {
+ if (is_sRGB) {
+ return getComponentFrom_sRGB(pixel, 1);
+ }
+ if (is_LINEAR_RGB) {
+ return getComponentFrom_LINEAR_RGB(pixel, 1);
+ }
+ return getComponentFrom_RGB(pixel, 1);
+ }
+
+ @Override
+ public final int getBlue(int pixel) {
+ if (is_sRGB) {
+ return getComponentFrom_sRGB(pixel, 2);
+ }
+ if (is_LINEAR_RGB) {
+ return getComponentFrom_LINEAR_RGB(pixel, 2);
+ }
+ return getComponentFrom_RGB(pixel, 2);
+ }
+
+ @Override
+ public final int getAlpha(int pixel) {
+ if (!hasAlpha) {
+ return 255;
+ }
+ int a = (pixel & componentMasks[3]) >>> offsets[3];
+ if (bits[3] == 8) {
+ return a;
+ }
+ return alphaLUT[a] & 0xff;
+ }
+
+ /**
+ * Gets the red mask.
+ *
+ * @return the red mask
+ */
+ public final int getRedMask() {
+ return componentMasks[0];
+ }
+
+ /**
+ * Gets the green mask.
+ *
+ * @return the green mask
+ */
+ public final int getGreenMask() {
+ return componentMasks[1];
+ }
+
+ /**
+ * Gets the blue mask.
+ *
+ * @return the blue mask
+ */
+ public final int getBlueMask() {
+ return componentMasks[2];
+ }
+
+ /**
+ * Gets the alpha mask.
+ *
+ * @return the alpha mask
+ */
+ public final int getAlphaMask() {
+ if (hasAlpha) {
+ return componentMasks[3];
+ }
+ return 0;
+ }
+
+ /**
+ * Initialization of Lookup tables.
+ */
+ private void initLUTs() {
+ is_sRGB = cs.isCS_sRGB();
+ is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS);
+
+ if (is_LINEAR_RGB) {
+ if (maxBitLength > 8) {
+ LINEAR_RGB_Length = 16;
+ from_LINEAR_RGB_LUT =
+ LUTColorConverter.getFrom16lRGBtosRGB_LUT();
+ to_LINEAR_16RGB_LUT =
+ LUTColorConverter.getFromsRGBto16lRGB_LUT();
+ } else {
+ LINEAR_RGB_Length = 8;
+ from_LINEAR_RGB_LUT =
+ LUTColorConverter.getFrom8lRGBtosRGB_LUT();
+ to_LINEAR_8RGB_LUT =
+ LUTColorConverter.getFromsRGBto8lRGB_LUT();
+ }
+ fFactor = ((1 << LINEAR_RGB_Length) - 1);
+ } else {
+ fFactor = 255.0f;
+ }
+
+ if (hasAlpha && bits[3] != 8) {
+ alphaLUT = new byte[maxValues[3] + 1];
+ for (int i = 0; i <= maxValues[3]; i++) {
+ alphaLUT[i] = (byte) (scales[3] * i + 0.5f);
+ }
+
+ }
+
+ if (!isAlphaPremultiplied) {
+ colorLUTs = new byte[3][];
+
+ if (is_sRGB) {
+ for (int i = 0; i < numColorComponents; i++) {
+ if (bits[i] != 8) {
+ for (int j = 0; j < i; j++) {
+ if (bits[i] == bits[j]) {
+ colorLUTs[i] = colorLUTs[j];
+ break;
+ }
+ }
+ colorLUTs[i] = new byte[maxValues[i] + 1];
+ for (int j = 0; j <= maxValues[i]; j++) {
+ colorLUTs[i][j] = (byte) (scales[i] * j + 0.5f);
+ }
+ }
+ }
+ }
+
+ if (is_LINEAR_RGB) {
+ for (int i = 0; i < numColorComponents; i++) {
+ if (bits[i] != LINEAR_RGB_Length) {
+ for (int j = 0; j < i; j++) {
+ if (bits[i] == bits[j]) {
+ colorLUTs[i] = colorLUTs[j];
+ break;
+ }
+ }
+ colorLUTs[i] = new byte[maxValues[i] + 1];
+ for (int j = 0; j <= maxValues[0]; j++) {
+ int idx;
+ if (LINEAR_RGB_Length == 8) {
+ idx = (int) (scales[i] * j + 0.5f);
+ } else {
+ idx = (int) (scales[i] * j * 257.0f + 0.5f);
+ }
+ colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx];
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * This method return RGB component value if Color Model has
+ * sRGB ColorSpace.
+ *
+ * @param pixel - INT representation of pixel
+ * @param idx - index of pixel component
+ *
+ * @return - value of the pixel component scaled fro 0 to 255
+ */
+ private int getComponentFrom_sRGB(int pixel, int idx) {
+ int comp = (pixel & componentMasks[idx]) >> offsets[idx];
+ if (isAlphaPremultiplied) {
+ int alpha = (pixel & componentMasks[3]) >>> offsets[3];
+ comp = alpha == 0 ? 0 : (int) (scales[idx] * comp * 255.0f /
+ (scales[3] * alpha) + 0.5f);
+ } else if (bits[idx] != 8) {
+ comp = colorLUTs[idx][comp] & 0xff;
+ }
+ return comp;
+ }
+
+ /**
+ * This method return RGB component value if Color Model has
+ * Linear RGB ColorSpace.
+ *
+ * @param pixel - INT representation of pixel
+ * @param idx - index of pixel component
+ *
+ * @return - value of the pixel component scaled fro 0 to 255
+ */
+ private int getComponentFrom_LINEAR_RGB(int pixel, int idx) {
+ int comp = (pixel & componentMasks[idx]) >> offsets[idx];
+ if (isAlphaPremultiplied) {
+ float factor = ((1 << LINEAR_RGB_Length) - 1);
+ int alpha = (pixel & componentMasks[3]) >> offsets[3];
+ comp = alpha == 0 ? 0 : (int) (scales[idx] * comp * factor /
+ (scales[3] * alpha) + 0.5f);
+ } else if (bits[idx] != LINEAR_RGB_Length) {
+ comp = colorLUTs[idx][comp] & 0xff;
+ } else {
+ comp = from_LINEAR_RGB_LUT[comp] & 0xff;
+ }
+ return comp;
+ }
+
+ /**
+ * This method return RGB component value if Color Model has
+ * arbitrary RGB ColorSapce.
+ *
+ * @param pixel - INT representation of pixel
+ * @param idx - index of pixel component
+ *
+ * @return - value of the pixel component scaled fro 0 to 255
+ */
+ private int getComponentFrom_RGB(int pixel, int idx) {
+ int components[] = getComponents(pixel, null, 0);
+ float[] normComponents = getNormalizedComponents(components, 0, null, 0);
+ float[] sRGBcomponents = cs.toRGB(normComponents);
+ return (int) (sRGBcomponents[idx] * 255.0f + 0.5f);
+ }
+
+}
+
diff --git a/awt/java/awt/image/FilteredImageSource.java b/awt/java/awt/image/FilteredImageSource.java
new file mode 100644
index 0000000..6a41fa7
--- /dev/null
+++ b/awt/java/awt/image/FilteredImageSource.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+
+
+/**
+ * The FilteredImageSource class is used for producing image data for a new
+ * filtered version of the original image using the specified filter object.
+ */
+public class FilteredImageSource implements ImageProducer {
+
+ /** The source. */
+ private final ImageProducer source;
+
+ /** The filter. */
+ private final ImageFilter filter;
+
+ /** The cons table. */
+ private final Hashtable<ImageConsumer, ImageConsumer> consTable = new Hashtable<ImageConsumer, ImageConsumer>();
+
+ /**
+ * Instantiates a new FilteredImageSource object with
+ * the specified ImageProducer and the ImageFilter objects.
+ *
+ * @param orig the specified ImageProducer.
+ * @param imgf the specified ImageFilter.
+ */
+ public FilteredImageSource(ImageProducer orig, ImageFilter imgf) {
+ source = orig;
+ filter = imgf;
+ }
+
+ public synchronized boolean isConsumer(ImageConsumer ic) {
+ if(ic != null) {
+ return consTable.containsKey(ic);
+ }
+ return false;
+ }
+
+ public void startProduction(ImageConsumer ic) {
+ addConsumer(ic);
+ ImageConsumer fic = consTable.get(ic);
+ source.startProduction(fic);
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer ic) {
+ if(ic != null && isConsumer(ic)){
+ ImageFilter fic = (ImageFilter) consTable.get(ic);
+ fic.resendTopDownLeftRight(source);
+ }
+ }
+
+ public synchronized void removeConsumer(ImageConsumer ic) {
+ if(ic != null && isConsumer(ic)){
+ ImageConsumer fic = consTable.get(ic);
+ source.removeConsumer(fic);
+ consTable.remove(ic);
+ }
+ }
+
+ public synchronized void addConsumer(ImageConsumer ic) {
+ if(ic != null && !isConsumer(ic)){
+ ImageConsumer fic = filter.getFilterInstance(ic);
+ source.addConsumer(fic);
+ consTable.put(ic, fic);
+ }
+ }
+}
diff --git a/awt/java/awt/image/ImageConsumer.java b/awt/java/awt/image/ImageConsumer.java
new file mode 100644
index 0000000..2eba290
--- /dev/null
+++ b/awt/java/awt/image/ImageConsumer.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+
+/**
+ * The ImageConsumer interface provides the data about the image
+ * and about how its data is delivered. A ImageProducer provides
+ * all of the information about the image using
+ * the methods defined in this interface.
+ */
+public interface ImageConsumer {
+
+ /**
+ * The Constant RANDOMPIXELORDER indicates that the pixels are
+ * delivered in a random order.
+ */
+ public static final int RANDOMPIXELORDER = 1;
+
+ /**
+ * The Constant TOPDOWNLEFTRIGHT indicates that the pixels are
+ * delivered in top-down, left-to-right order.
+ */
+ public static final int TOPDOWNLEFTRIGHT = 2;
+
+ /**
+ * The Constant COMPLETESCANLINES indicates that the pixels are
+ * delivered in complete scanline.
+ */
+ public static final int COMPLETESCANLINES = 4;
+
+ /**
+ * The Constant SINGLEPASS indicates that pixels are delivered
+ * in a single pass.
+ */
+ public static final int SINGLEPASS = 8;
+
+ /**
+ * The Constant SINGLEFRAME indicates that image consists of
+ * single frame.
+ */
+ public static final int SINGLEFRAME = 16;
+
+ /**
+ * The Constant IMAGEERROR indicates an image error during image producing.
+ */
+ public static final int IMAGEERROR = 1;
+
+ /**
+ * The Constant SINGLEFRAMEDONE indicates that only one of the
+ * image's frames is completed.
+ */
+ public static final int SINGLEFRAMEDONE = 2;
+
+ /**
+ * The Constant STATICIMAGEDONE indicates that the image is completed.
+ */
+ public static final int STATICIMAGEDONE = 3;
+
+ /**
+ * The Constant IMAGEABORTED indicates that the image producing
+ * process is aborted.
+ */
+ public static final int IMAGEABORTED = 4;
+
+ /**
+ * Sets the properties for the image associated with this ImageConsumer.
+ *
+ * @param props the properties for the image associated with
+ * this ImageConsumer.
+ */
+ public void setProperties(Hashtable<?, ?> props);
+
+ /**
+ * Sets the ColorModel object.
+ *
+ * @param model the new ColorModel.
+ */
+ public void setColorModel(ColorModel model);
+
+ /**
+ * Sets the pixels for the specified rectangular area of the image.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ * @param model the specified ColorModel to be used for pixels
+ * converting.
+ * @param pixels the array of pixels.
+ * @param off the offset of pixels array.
+ * @param scansize the distance from the one row of pixels
+ * to the next row in the specified array.
+ */
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ int[] pixels, int off, int scansize);
+
+ /**
+ * Sets the pixels for the specified rectangular area of the image.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ * @param model the specified ColorModel to be used for pixels
+ * converting.
+ * @param pixels the array of pixels.
+ * @param off the offset of pixels array.
+ * @param scansize the distance from the one row of pixels
+ * to the next row in the specified array.
+ */
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ byte[] pixels, int off, int scansize);
+
+ /**
+ * Sets the dimensions of a source image.
+ *
+ * @param width the width of the image.
+ * @param height the height of the image.
+ */
+ public void setDimensions(int width, int height);
+
+ /**
+ * Sets the hint flags of pixels order, which is used by
+ * the ImageConsumer for obtaining pixels from the ImageProducer
+ * for which this ImageConsumer is added.
+ *
+ * @param hintflags the mask of hint flags.
+ */
+ public void setHints(int hintflags);
+
+ /**
+ * THis method is called in the one of the following cases:
+ * <ul>
+ * <li>The ImageProducer (for which this ImageConsumer is added)
+ * has been delivered all pixels of the source image. </li>
+ * <li>A one frame of an animation has been completed. </li>
+ * <li> An error while loading or producing of the image has occured.
+ * </ul>
+ *
+ * @param status the status of image producing.
+ */
+ public void imageComplete(int status);
+
+}
+
diff --git a/awt/java/awt/image/ImageFilter.java b/awt/java/awt/image/ImageFilter.java
new file mode 100644
index 0000000..e386d65
--- /dev/null
+++ b/awt/java/awt/image/ImageFilter.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+
+/**
+ * The ImageFilter class provides a filter for delivering image data
+ * from an ImageProducer to an ImageConsumer.
+ */
+public class ImageFilter implements ImageConsumer, Cloneable {
+
+ /** The consumer. */
+ protected ImageConsumer consumer;
+
+ /**
+ * Instantiates a new ImageFilter.
+ */
+ public ImageFilter() {
+ super();
+ }
+
+ /**
+ * Gets an instance of an ImageFilter object which performs
+ * the filtering for the specified ImageConsumer.
+ *
+ * @param ic the specified ImageConsumer.
+ *
+ * @return an ImageFilter used to perform the filtering for
+ * the specified ImageConsumer.
+ */
+ public ImageFilter getFilterInstance(ImageConsumer ic) {
+ ImageFilter filter = (ImageFilter) clone();
+ filter.consumer = ic;
+ return filter;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void setProperties(Hashtable<?, ?> props) {
+ Hashtable<Object, Object> fprops;
+ if (props == null) {
+ fprops = new Hashtable<Object, Object>();
+ } else {
+ fprops = (Hashtable<Object, Object>) props.clone();
+ }
+ String propName = "Filters"; //$NON-NLS-1$
+ String prop = "Null filter"; //$NON-NLS-1$
+ Object o = fprops.get(propName);
+ if (o != null) {
+ if (o instanceof String) {
+ prop = (String) o + "; " + prop; //$NON-NLS-1$
+ } else {
+ prop = o.toString() + "; " + prop; //$NON-NLS-1$
+ }
+ }
+ fprops.put(propName, prop);
+ consumer.setProperties(fprops);
+ }
+
+ /**
+ * Returns a copy of this ImageFilter.
+ *
+ * @return a copy of this ImageFilter.
+ */
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Responds to a request for a Top-Down-Left-Right ordered
+ * resend of the pixel data from an ImageConsumer.
+ *
+ * @param ip the ImageProducer that provides this instance of
+ * the filter.
+ */
+ public void resendTopDownLeftRight(ImageProducer ip) {
+ ip.requestTopDownLeftRightResend(this);
+ }
+
+ public void setColorModel(ColorModel model) {
+ consumer.setColorModel(model);
+ }
+
+ public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off,
+ int scansize) {
+ consumer.setPixels(x, y, w, h, model, pixels, off, scansize);
+ }
+
+ public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off,
+ int scansize) {
+ consumer.setPixels(x, y, w, h, model, pixels, off, scansize);
+ }
+
+ public void setDimensions(int width, int height) {
+ consumer.setDimensions(width, height);
+ }
+
+ public void setHints(int hints) {
+ consumer.setHints(hints);
+ }
+
+ public void imageComplete(int status) {
+ consumer.imageComplete(status);
+ }
+
+}
diff --git a/awt/java/awt/image/ImageObserver.java b/awt/java/awt/image/ImageObserver.java
new file mode 100644
index 0000000..418bd07
--- /dev/null
+++ b/awt/java/awt/image/ImageObserver.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Image;
+
+/**
+ * the ImageObserver interface is an asynchronous update interface
+ * for receiving notifications about Image construction status.
+ */
+public interface ImageObserver {
+
+ /**
+ * The Constant WIDTH indicates that the width of the image is
+ * available.
+ */
+ public static final int WIDTH = 1;
+
+ /**
+ * The Constant HEIGHT indicates that the width of the image is
+ * available.
+ */
+ public static final int HEIGHT = 2;
+
+ /**
+ * The Constant PROPERTIES indicates that the properties of the image
+ * are available.
+ */
+ public static final int PROPERTIES = 4;
+
+ /**
+ * The Constant SOMEBITS indicates that more bits needed for
+ * drawing a scaled variation of the image pixels are available.
+ */
+ public static final int SOMEBITS = 8;
+
+ /**
+ * The Constant FRAMEBITS indicates that complete frame of
+ * a image which was previously drawn is now available
+ * for drawing again.
+ */
+ public static final int FRAMEBITS = 16;
+
+ /**
+ * The Constant ALLBITS indicates that an image which
+ * was previously drawn is now complete and can be drawn again.
+ */
+ public static final int ALLBITS = 32;
+
+ /**
+ * The Constant ERROR indicates that error occured.
+ */
+ public static final int ERROR = 64;
+
+ /**
+ * The Constant ABORT indicates that the image producing is
+ * aborted.
+ */
+ public static final int ABORT = 128;
+
+ /**
+ * This method is called when information about an Image
+ * interface becomes available. This method returns true
+ * if further updates are needed, false if not.
+ *
+ * @param img the image to be observed.
+ * @param infoflags the bitwise OR combination of information flags:
+ * ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS,
+ * WIDTH.
+ * @param x the X coordinate.
+ * @param y the Y coordinate.
+ * @param width the width.
+ * @param height the height.
+ *
+ * @return true if further updates are needed, false if not.
+ */
+ public boolean imageUpdate(Image img, int infoflags, int x, int y,
+ int width, int height);
+
+}
+
diff --git a/awt/java/awt/image/ImageProducer.java b/awt/java/awt/image/ImageProducer.java
new file mode 100644
index 0000000..557ae08
--- /dev/null
+++ b/awt/java/awt/image/ImageProducer.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+
+/**
+ * The ImageProducer provides an interface for objects which produce
+ * the image data. ImageProducer is used for reconstructing the
+ * image. Each image contains an ImageProducer.
+ */
+public interface ImageProducer {
+
+ /**
+ * Checks if the specified ImageConsumer is registered with this
+ * ImageProvider or not.
+ *
+ * @param ic the ImageConsumer to be checked.
+ *
+ * @return true, if the specified ImageConsumer is registered with this
+ * ImageProvider, false otherwise.
+ */
+ public boolean isConsumer(ImageConsumer ic);
+
+ /**
+ * Starts a reconstruction of the image data which will
+ * be delivered to this consumer. This method addes the
+ * specified ImageConsumer before reconstructing the image.
+ *
+ * @param ic the specified ImageConsumer.
+ */
+ public void startProduction(ImageConsumer ic);
+
+ /**
+ * Requests the ImageProducer to resend the image data
+ * in ImageConsumer.TOPDOWNLEFTRIGHT order.
+ *
+ * @param ic the specified ImageConsumer.
+ */
+ public void requestTopDownLeftRightResend(ImageConsumer ic);
+
+ /**
+ * Deregisters the specified ImageConsumer.
+ *
+ * @param ic the specified ImageConsumer.
+ */
+ public void removeConsumer(ImageConsumer ic);
+
+ /**
+ * Adds the specified ImageConsumer object to this ImageProducer.
+ *
+ * @param ic the specified ImageConsumer.
+ */
+ public void addConsumer(ImageConsumer ic);
+
+}
+
diff --git a/awt/java/awt/image/ImagingOpException.java b/awt/java/awt/image/ImagingOpException.java
new file mode 100644
index 0000000..ebcaba4
--- /dev/null
+++ b/awt/java/awt/image/ImagingOpException.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 5, 2005
+ */
+
+package java.awt.image;
+
+/**
+ * The ImagingOpException class provides error notification when
+ * the BufferedImageOp or RasterOp filter methods can not perform
+ * the desired filter operation.
+ */
+public class ImagingOpException extends RuntimeException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 8026288481846276658L;
+
+ /**
+ * Instantiates a new ImagingOpException with a detail message.
+ *
+ * @param s the detail message.
+ */
+ public ImagingOpException(String s) {
+ super(s);
+ }
+}
diff --git a/awt/java/awt/image/IndexColorModel.java b/awt/java/awt/image/IndexColorModel.java
new file mode 100644
index 0000000..a7043f4
--- /dev/null
+++ b/awt/java/awt/image/IndexColorModel.java
@@ -0,0 +1,1020 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.math.BigInteger;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class IndexColorModel represents a color model in which the
+ * color values of the pixels are read from a palette.
+ */
+public class IndexColorModel extends ColorModel {
+
+ /** The color map. */
+ private int colorMap[]; // Color Map
+
+ /** The map size. */
+ private int mapSize; // Color Map size
+
+ /** The transparent index. */
+ private int transparentIndex; // Index of fully transparent pixel
+
+ /** The gray palette. */
+ private boolean grayPalette; // Color Model has Color Map with Gray Pallete
+
+ /** The valid bits. */
+ private BigInteger validBits; // Specify valid Color Map values
+
+ /** The Constant CACHESIZE. */
+ private static final int CACHESIZE = 20; // Cache size. Cache used for
+ // improving performace of selection
+ // nearest color in Color Map
+
+ /** The cachetable. */
+ private final int cachetable[] = new int[CACHESIZE * 2]; // Cache table - used for
+ // storing RGB values and that appropriate indices
+ // in the Color Map
+
+
+ /** The next insert idx. */
+ private int nextInsertIdx = 0; // Next index for insertion into Cache table
+
+ /** The total inserted. */
+ private int totalInserted = 0; // Number of inserted values into Cache table
+
+ /**
+ * Instantiates a new index color model.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param cmap the array that gives the color mapping
+ * @param start the start index of the color mapping data within the cmap array
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ * @param validBits a list of which bits represent valid colormap
+ * values, or null if all are valid
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ */
+ public IndexColorModel(int bits, int size, int cmap[], int start,
+ int transferType, BigInteger validBits) {
+
+ super(bits, IndexColorModel.createBits(true),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false,
+ Transparency.OPAQUE, validateTransferType(transferType));
+
+ if (size < 1) {
+ // awt.264=Size of the color map is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+ }
+
+ mapSize = size;
+ colorMap = new int[mapSize];
+ transparentIndex = -1;
+
+ if (validBits != null) {
+ for (int i = 0; i < mapSize; i++) {
+ if (!validBits.testBit(i)) {
+ this.validBits = validBits;
+ }
+ break;
+ }
+ }
+
+ transparency = Transparency.OPAQUE;
+ int alphaMask = 0xff000000;
+ int alpha = 0;
+
+ for (int i = 0; i < mapSize; i++, start++) {
+ colorMap[i] = cmap[start];
+ alpha = cmap[start] & alphaMask;
+
+ if (alpha == alphaMask) {
+ continue;
+ }
+ if (alpha == 0) {
+ if (transparentIndex < 0) {
+ transparentIndex = i;
+ }
+ if (transparency == Transparency.OPAQUE) {
+ transparency = Transparency.BITMASK;
+ }
+ } else if (alpha != alphaMask &&
+ transparency != Transparency.TRANSLUCENT) {
+ transparency = Transparency.TRANSLUCENT;
+ }
+
+ }
+ checkPalette();
+
+ }
+
+ /**
+ * Instantiates a new index color model.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param cmap the array that gives the color mapping
+ * @param start the start index of the color mapping data within the cmap array
+ * @param hasalpha whether this color model uses alpha
+ * @param trans the transparency supported, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ */
+ public IndexColorModel(int bits, int size, int cmap[], int start,
+ boolean hasalpha, int trans, int transferType) {
+
+ super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ (hasalpha || (trans >= 0)), false, Transparency.OPAQUE,
+ validateTransferType(transferType));
+
+ if (size < 1) {
+ // awt.264=Size of the color map is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+ }
+
+ mapSize = size;
+ colorMap = new int[mapSize];
+ if (trans >= 0 && trans < mapSize) {
+ transparentIndex = trans;
+ transparency = Transparency.BITMASK;
+ } else {
+ transparentIndex = -1;
+ transparency = Transparency.OPAQUE;
+ }
+
+ int alphaMask = 0xff000000;
+ int alpha = 0;
+
+ for (int i = 0; i < mapSize; i++, start++) {
+ if (transparentIndex == i) {
+ colorMap[i] = cmap[start] & 0x00ffffff;
+ continue;
+ }
+ if (hasalpha) {
+ alpha = cmap[start] & alphaMask;
+ colorMap[i] = cmap[start];
+
+ if (alpha == alphaMask) {
+ continue;
+ }
+ if (alpha == 0) {
+ if (trans < 0) {
+ trans = i;
+ }
+ if (transparency == Transparency.OPAQUE) {
+ transparency = Transparency.BITMASK;
+ }
+ } else if (alpha != 0
+ && transparency != Transparency.TRANSLUCENT) {
+ transparency = Transparency.TRANSLUCENT;
+ }
+ } else {
+ colorMap[i] = alphaMask | cmap[start];
+ }
+ }
+ checkPalette();
+
+ }
+
+ /**
+ * Instantiates a new index color model by building the color map
+ * from arrays of red, green, blue, and alpha values.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param r the array giving the red components of the entries in the color map
+ * @param g the array giving the green components of the entries in the color map
+ * @param b the array giving the blue components of the entries in the color map
+ * @param a the array giving the alpha components of the entries in the color map
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ * @throws ArrayIndexOutOfBoundsException if the size of one of the
+ * component arrays is less than the size of the color map
+ */
+ public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[],
+ byte a[]) {
+
+ super(bits, IndexColorModel.createBits(true),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false,
+ Transparency.OPAQUE,
+ validateTransferType(ColorModel.getTransferType(bits)));
+
+ createColorMap(size, r, g, b, a, -1);
+ checkPalette();
+ }
+
+ /**
+ * Instantiates a new index color model by building the color map
+ * from arrays of red, green, and blue values.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param r the array giving the red components of the entries in the color map
+ * @param g the array giving the green components of the entries in the color map
+ * @param b the array giving the blue components of the entries in the color map
+ * @param trans the transparency supported, @see java.awt.Transparency
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ * @throws ArrayIndexOutOfBoundsException if the size of one of the
+ * component arrays is less than the size of the color map
+ */
+ public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[],
+ int trans) {
+
+ super(bits, IndexColorModel.createBits((trans >= 0)),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB), (trans >= 0), false,
+ Transparency.OPAQUE,
+ validateTransferType(ColorModel.getTransferType(bits)));
+
+ createColorMap(size, r, g, b, null, trans);
+ checkPalette();
+ }
+
+ /**
+ * Instantiates a new index color model by building the color map
+ * from arrays of red, green, and blue values.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param r the array giving the red components of the entries in the color map
+ * @param g the array giving the green components of the entries in the color map
+ * @param b the array giving the blue components of the entries in the color map
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ * @throws ArrayIndexOutOfBoundsException if the size of one of the
+ * component arrays is less than the size of the color map
+ */
+ public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[]) {
+ super(bits, IndexColorModel.createBits(false),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false,
+ Transparency.OPAQUE,
+ validateTransferType(ColorModel.getTransferType(bits)));
+
+ createColorMap(size, r, g, b, null, -1);
+ checkPalette();
+ }
+
+ /**
+ * Instantiates a new index color model.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param cmap the array that gives the color mapping
+ * @param start the start index of the color mapping data within the cmap array
+ * @param hasalpha whether this color model uses alpha
+ * @param trans the transparency supported, @see java.awt.Transparency
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ */
+ public IndexColorModel(int bits, int size, byte cmap[], int start,
+ boolean hasalpha, int trans) {
+
+ super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)),
+ ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ (hasalpha || (trans >= 0)), false, Transparency.OPAQUE,
+ validateTransferType(ColorModel.getTransferType(bits)));
+
+ if (size < 1) {
+ // awt.264=Size of the color map is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+ }
+
+ mapSize = size;
+ colorMap = new int[mapSize];
+ transparentIndex = -1;
+
+ transparency = Transparency.OPAQUE;
+ int alpha = 0xff000000;
+
+ for (int i = 0; i < mapSize; i++) {
+ colorMap[i] = (cmap[start++] & 0xff) << 16 |
+ (cmap[start++] & 0xff) << 8 | (cmap[start++] & 0xff);
+ if (trans == i) {
+ if (transparency == Transparency.OPAQUE) {
+ transparency = Transparency.BITMASK;
+ }
+ if(hasalpha) {
+ start++;
+ }
+ continue;
+ }
+ if (hasalpha) {
+ alpha = cmap[start++] & 0xff;
+ if (alpha == 0) {
+ if (transparency == Transparency.OPAQUE) {
+ transparency = Transparency.BITMASK;
+ if (trans < 0) {
+ trans = i;
+ }
+ }
+ } else {
+ if (alpha != 0xff &&
+ transparency != Transparency.TRANSLUCENT) {
+ transparency = Transparency.TRANSLUCENT;
+ }
+ }
+ alpha <<= 24;
+ }
+ colorMap[i] |= alpha;
+ }
+
+ if (trans >= 0 && trans < mapSize) {
+ transparentIndex = trans;
+ }
+ checkPalette();
+
+ }
+
+ /**
+ * Instantiates a new index color model.
+ *
+ * @param bits the array of component masks
+ * @param size the size of the color map
+ * @param cmap the array that gives the color mapping
+ * @param start the start index of the color mapping data within the cmap array
+ * @param hasalpha whether this color model uses alpha
+ *
+ * @throws IllegalArgumentException if the size of the color map is
+ * less than one
+ */
+ public IndexColorModel(int bits, int size, byte cmap[], int start,
+ boolean hasalpha) {
+
+ this(bits, size, cmap, start, hasalpha, -1);
+ }
+
+ @Override
+ public Object getDataElements(int[] components, int offset, Object pixel) {
+ int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 |
+ components[offset + 2];
+ if (hasAlpha) {
+ rgb |= components[offset + 3] << 24;
+ } else {
+ rgb |= 0xff000000;
+ }
+ return getDataElements(rgb, pixel);
+ }
+
+ @Override
+ public synchronized Object getDataElements(int rgb, Object pixel) {
+ int red = (rgb >> 16) & 0xff;
+ int green = (rgb >> 8) & 0xff;
+ int blue = rgb & 0xff;
+ int alpha = rgb >>> 24;
+ int pixIdx = 0;
+
+ for (int i = 0; i < totalInserted; i++) {
+ int idx = i * 2;
+ if (rgb == cachetable[idx]) {
+ return createDataObject(cachetable[idx + 1], pixel);
+ }
+ }
+
+ if (!hasAlpha && grayPalette) {
+ int grey = (red * 77 + green * 150 + blue * 29 + 128) >>> 8;
+ int minError = 255;
+ int error = 0;
+
+ for (int i = 0; i < mapSize; i++) {
+ error = Math.abs((colorMap[i] & 0xff) - grey);
+ if (error < minError) {
+ pixIdx = i;
+ if (error == 0) {
+ break;
+ }
+ minError = error;
+ }
+ }
+ } else if (alpha == 0 && transparentIndex > -1) {
+ pixIdx = transparentIndex;
+ } else {
+ int minAlphaError = 255;
+ int minError = 195075; // 255^2 + 255^2 + 255^2
+ int alphaError;
+ int error = 0;
+
+ for (int i = 0; i < mapSize; i++) {
+ int pix = colorMap[i];
+ if (rgb == pix) {
+ pixIdx = i;
+ break;
+ }
+ alphaError = Math.abs(alpha - (pix >>> 24));
+ if (alphaError <= minAlphaError) {
+ minAlphaError = alphaError;
+
+ int buf = ((pix >> 16) & 0xff) - red;
+ error = buf * buf;
+
+ if (error < minError) {
+ buf = ((pix >> 8) & 0xff) - green;
+ error += buf * buf;
+
+ if (error < minError) {
+ buf = (pix & 0xff) - blue;
+ error += buf * buf;
+
+ if (error < minError) {
+ pixIdx = i;
+ minError = error;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ cachetable[nextInsertIdx] = rgb;
+ cachetable[nextInsertIdx + 1] = pixIdx;
+
+ nextInsertIdx = (nextInsertIdx + 2) % (CACHESIZE * 2);
+ if (totalInserted < CACHESIZE) {
+ totalInserted++;
+ }
+
+ return createDataObject(pixIdx, pixel);
+ }
+
+ /**
+ * Converts an image from indexed to RGB format.
+ *
+ * @param raster the raster containing the source image
+ * @param forceARGB whether to use the default RGB color model
+ *
+ * @return the buffered image
+ *
+ * @throws IllegalArgumentException if the raster is not compatible with
+ * this color model
+ */
+ public BufferedImage convertToIntDiscrete(Raster raster,
+ boolean forceARGB) {
+
+ if (!isCompatibleRaster(raster)) {
+ // awt.265=The raster argument is not compatible with this IndexColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.265")); //$NON-NLS-1$
+ }
+
+ ColorModel model;
+ if (forceARGB || transparency == Transparency.TRANSLUCENT) {
+ model = ColorModel.getRGBdefault();
+ } else if (transparency == Transparency.BITMASK) {
+ model = new DirectColorModel(25, 0x00ff0000, 0x0000ff00,
+ 0x000000ff, 0x01000000);
+ } else {
+ model = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
+ }
+
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+
+ WritableRaster distRaster = model.createCompatibleWritableRaster(w, h);
+
+ int minX = raster.getMinX();
+ int minY = raster.getMinY();
+
+ Object obj = null;
+ int pixels[] = null;
+
+ for (int i = 0; i < h; i++, minY++) {
+ obj = raster.getDataElements(minX, minY, w, 1, obj);
+ if (obj instanceof byte[]) {
+ byte ba[] = (byte[]) obj;
+ if (pixels == null) {
+ pixels = new int[ba.length];
+ }
+ for (int j = 0; j < ba.length; j++) {
+ pixels[j] = colorMap[ba[j] & 0xff];
+ }
+ } else if (obj instanceof short[]) {
+ short sa[] = (short[]) obj;
+ if (pixels == null) {
+ pixels = new int[sa.length];
+ }
+ for (int j = 0; j < sa.length; j++) {
+ pixels[j] = colorMap[sa[j] & 0xffff];
+ }
+ }
+ if (obj instanceof int[]) {
+ int ia[] = (int[]) obj;
+ if (pixels == null) {
+ pixels = new int[ia.length];
+ }
+ for (int j = 0; j < ia.length; j++) {
+ pixels[j] = colorMap[ia[j]];
+ }
+ }
+
+ distRaster.setDataElements(0, i, w, 1, pixels);
+ }
+
+ return new BufferedImage(model, distRaster, false, null);
+ }
+
+ /**
+ * Gets the valid pixels.
+ *
+ * @return the valid pixels
+ */
+ public BigInteger getValidPixels() {
+ return validBits;
+ }
+
+ @Override
+ public String toString() {
+ // The output format based on 1.5 release behaviour.
+ // It could be reveled such way:
+ // BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED);
+ // ColorModel cm = bi.getColorModel();
+ // System.out.println(cm.toString());
+ String str = "IndexColorModel: #pixel_bits = " + pixel_bits + //$NON-NLS-1$
+ " numComponents = " + numComponents + " color space = " + cs + //$NON-NLS-1$ //$NON-NLS-2$
+ " transparency = "; //$NON-NLS-1$
+
+ if (transparency == Transparency.OPAQUE) {
+ str = str + "Transparency.OPAQUE"; //$NON-NLS-1$
+ } else if (transparency == Transparency.BITMASK) {
+ str = str + "Transparency.BITMASK"; //$NON-NLS-1$
+ } else {
+ str = str + "Transparency.TRANSLUCENT"; //$NON-NLS-1$
+ }
+
+ str = str + " transIndex = " + transparentIndex + " has alpha = " + //$NON-NLS-1$ //$NON-NLS-2$
+ hasAlpha + " isAlphaPre = " + isAlphaPremultiplied; //$NON-NLS-1$
+
+ return str;
+ }
+
+ @Override
+ public int[] getComponents(Object pixel, int components[], int offset) {
+ int pixIdx = -1;
+ if (pixel instanceof byte[]) {
+ byte ba[] = (byte[]) pixel;
+ pixIdx = ba[0] & 0xff;
+ } else if (pixel instanceof short[]) {
+ short sa[] = (short[]) pixel;
+ pixIdx = sa[0] & 0xffff;
+ } else if (pixel instanceof int[]) {
+ int ia[] = (int[]) pixel;
+ pixIdx = ia[0];
+ } else {
+ // awt.219=This transferType is not supported by this color model
+ throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$
+ }
+
+ return getComponents(pixIdx, components, offset);
+ }
+
+ @Override
+ public WritableRaster createCompatibleWritableRaster(int w, int h) {
+ WritableRaster raster;
+ if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
+ raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1,
+ pixel_bits, null);
+ } else if (pixel_bits <= 8) {
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h,
+ 1, null);
+ } else if (pixel_bits <= 16) {
+ raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w,
+ h, 1, null);
+ } else {
+ // awt.266=The number of bits in a pixel is greater than 16
+ throw new UnsupportedOperationException(Messages.getString("awt.266")); //$NON-NLS-1$
+ }
+
+ return raster;
+ }
+
+ @Override
+ public boolean isCompatibleSampleModel(SampleModel sm) {
+ if (sm == null) {
+ return false;
+ }
+
+ if (!(sm instanceof MultiPixelPackedSampleModel)
+ && !(sm instanceof ComponentSampleModel)) {
+ return false;
+ }
+
+ if (sm.getTransferType() != transferType) {
+ return false;
+ }
+ if (sm.getNumBands() != 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
+ return new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h,
+ pixel_bits);
+ }
+ int bandOffsets[] = new int[1];
+ bandOffsets[0] = 0;
+ return new ComponentSampleModel(transferType, w, h, 1, w,
+ bandOffsets);
+
+ }
+
+ @Override
+ public boolean isCompatibleRaster(Raster raster) {
+ int sampleSize = raster.getSampleModel().getSampleSize(0);
+ return (raster.getTransferType() == transferType &&
+ raster.getNumBands() == 1 && (1 << sampleSize) >= mapSize);
+ }
+
+ @Override
+ public int getDataElement(int components[], int offset) {
+ int rgb = (components[offset] << 16) | (components[offset + 1]) << 8
+ | components[offset + 2];
+
+ if (hasAlpha) {
+ rgb |= components[offset + 3] << 24;
+ } else {
+ rgb |= 0xff000000;
+ }
+
+ int pixel;
+
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte ba[] = (byte[]) getDataElements(rgb, null);
+ pixel = ba[0] & 0xff;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short sa[] = (short[]) getDataElements(rgb, null);
+ pixel = sa[0] & 0xffff;
+ break;
+ default:
+ // awt.267=The transferType is invalid
+ throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$
+ }
+
+ return pixel;
+ }
+
+ /**
+ * Gets the color map.
+ *
+ * @param rgb the destination array where the color map is written
+ */
+ public final void getRGBs(int rgb[]) {
+ System.arraycopy(colorMap, 0, rgb, 0, mapSize);
+ }
+
+ /**
+ * Gets the red component of the color map.
+ *
+ * @param r the destination array
+ */
+ public final void getReds(byte r[]) {
+ for (int i = 0; i < mapSize; i++) {
+ r[i] = (byte) (colorMap[i] >> 16);
+ }
+ }
+
+ /**
+ * Gets the green component of the color map.
+ *
+ * @param g the destination array
+ */
+ public final void getGreens(byte g[]) {
+ for (int i = 0; i < mapSize; i++) {
+ g[i] = (byte) (colorMap[i] >> 8);
+ }
+ }
+
+ /**
+ * Gets the blue component of the color map.
+ *
+ * @param b the destination array
+ */
+ public final void getBlues(byte b[]) {
+ for (int i = 0; i < mapSize; i++) {
+ b[i] = (byte) colorMap[i];
+ }
+ }
+
+ /**
+ * Gets the alpha component of the color map.
+ *
+ * @param a the destination array
+ */
+ public final void getAlphas(byte a[]) {
+ for (int i = 0; i < mapSize; i++) {
+ a[i] = (byte) (colorMap[i] >> 24);
+ }
+ }
+
+ @Override
+ public int[] getComponents(int pixel, int components[], int offset) {
+ if (components == null) {
+ components = new int[offset + numComponents];
+ }
+
+ components[offset + 0] = getRed(pixel);
+ components[offset + 1] = getGreen(pixel);
+ components[offset + 2] = getBlue(pixel);
+ if (hasAlpha && (components.length - offset) > 3) {
+ components[offset + 3] = getAlpha(pixel);
+ }
+
+ return components;
+ }
+
+ /**
+ * Checks if the specified pixel is valid for this color model.
+ *
+ * @param pixel the pixel
+ *
+ * @return true, if the pixel is valid
+ */
+ public boolean isValid(int pixel) {
+ if (validBits == null) {
+ return (pixel >= 0 && pixel < mapSize);
+ }
+ return (pixel < mapSize && validBits.testBit(pixel));
+ }
+
+ @Override
+ public final int getRed(int pixel) {
+ return (colorMap[pixel] >> 16) & 0xff;
+ }
+
+ @Override
+ public final int getRGB(int pixel) {
+ return colorMap[pixel];
+ }
+
+ @Override
+ public final int getGreen(int pixel) {
+ return (colorMap[pixel] >> 8) & 0xff;
+ }
+
+ @Override
+ public final int getBlue(int pixel) {
+ return colorMap[pixel] & 0xff;
+ }
+
+ @Override
+ public final int getAlpha(int pixel) {
+ return (colorMap[pixel] >> 24) & 0xff;
+ }
+
+ @Override
+ public int[] getComponentSize() {
+ return bits.clone();
+ }
+
+ /**
+ * Checks if this color model validates pixels.
+ *
+ * @return true, if all pixels are valid, otherwise false
+ */
+ public boolean isValid() {
+ return (validBits == null);
+ }
+
+ @Override
+ public void finalize() {
+ // TODO: implement
+ return;
+ }
+
+ /**
+ * Gets the index that represents the transparent pixel.
+ *
+ * @return the index that represents the transparent pixel
+ */
+ public final int getTransparentPixel() {
+ return transparentIndex;
+ }
+
+ @Override
+ public int getTransparency() {
+ return transparency;
+ }
+
+ /**
+ * Gets the size of the color map.
+ *
+ * @return the map size
+ */
+ public final int getMapSize() {
+ return mapSize;
+ }
+
+ /**
+ * Creates the color map.
+ *
+ * @param size the size
+ * @param r the r
+ * @param g the g
+ * @param b the b
+ * @param a the a
+ * @param trans the trans
+ */
+ private void createColorMap(int size, byte r[], byte g[], byte b[],
+ byte a[], int trans) {
+ if (size < 1) {
+ // awt.264=Size of the color map is less than 1
+ throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
+ }
+
+ mapSize = size;
+ colorMap = new int[mapSize];
+ if (trans >= 0 && trans < mapSize) {
+ transparency = Transparency.BITMASK;
+ transparentIndex = trans;
+ } else {
+ transparency = Transparency.OPAQUE;
+ transparentIndex = -1;
+ }
+ int alpha = 0;
+
+ for (int i = 0; i < mapSize; i++) {
+ colorMap[i] = ((r[i] & 0xff) << 16) | ((g[i] & 0xff) << 8) |
+ (b[i] & 0xff);
+
+ if (trans == i) {
+ continue;
+ }
+
+ if (a == null) {
+ colorMap[i] |= 0xff000000;
+ } else {
+ alpha = a[i] & 0xff;
+ if (alpha == 0xff) {
+ colorMap[i] |= 0xff000000;
+ } else if (alpha == 0) {
+ if (transparency == Transparency.OPAQUE) {
+ transparency = Transparency.BITMASK;
+ }
+ if (transparentIndex < 0) {
+ transparentIndex = i;
+ }
+ } else {
+ colorMap[i] |= (a[i] & 0xff) << 24;
+ if (transparency != Transparency.TRANSLUCENT) {
+ transparency = Transparency.TRANSLUCENT;
+ }
+ }
+ }
+
+ }
+
+ }
+
+ /**
+ * This method checking, if Color Map has Gray Palette.
+ */
+ private void checkPalette() {
+ grayPalette = false;
+ if (transparency > Transparency.OPAQUE) {
+ return;
+ }
+ int rgb = 0;
+
+ for (int i = 0; i < mapSize; i++) {
+ rgb = colorMap[i];
+ if (((rgb >> 16) & 0xff) != ((rgb >> 8) & 0xff) ||
+ ((rgb >> 8) & 0xff) != (rgb & 0xff)) {
+ return;
+ }
+ }
+ grayPalette = true;
+ }
+
+ /**
+ * Construction an array pixel representation.
+ *
+ * @param colorMapIdx - index into Color Map
+ * @param pixel - pixel
+ *
+ * @return - an array pixel representation
+ */
+ private Object createDataObject(int colorMapIdx, Object pixel) {
+ if (pixel == null) {
+ switch (transferType) {
+ case DataBuffer.TYPE_BYTE:
+ byte[] ba = new byte[1];
+ ba[0] = (byte) colorMapIdx;
+ pixel = ba;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short[] sa = new short[1];
+ sa[0] = (short) colorMapIdx;
+ pixel = sa;
+ break;
+ default:
+ // awt.267=The transferType is invalid
+ throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$
+ }
+ } else if (pixel instanceof byte[]
+ && transferType == DataBuffer.TYPE_BYTE) {
+ byte ba[] = (byte[]) pixel;
+ ba[0] = (byte) colorMapIdx;
+ pixel = ba;
+ } else if (pixel instanceof short[]&&
+ transferType == DataBuffer.TYPE_USHORT) {
+ short[] sa = (short[]) pixel;
+ sa[0] = (short) colorMapIdx;
+ pixel = sa;
+ } else if (pixel instanceof int[]) {
+ int ia[] = (int[]) pixel;
+ ia[0] = colorMapIdx;
+ pixel = ia;
+ } else {
+ // awt.268=The pixel is not a primitive array of type transferType
+ throw new ClassCastException(Messages.getString("awt.268")); //$NON-NLS-1$
+ }
+ return pixel;
+ }
+
+ /**
+ * Creates the bits.
+ *
+ * @param hasAlpha the has alpha
+ *
+ * @return the int[]
+ */
+ private static int[] createBits(boolean hasAlpha) {
+
+ int numChannels;
+ if (hasAlpha) {
+ numChannels = 4;
+ } else {
+ numChannels = 3;
+ }
+
+ int bits[] = new int[numChannels];
+ for (int i = 0; i < numChannels; i++) {
+ bits[i] = 8;
+ }
+
+ return bits;
+
+ }
+
+ /**
+ * Validate transfer type.
+ *
+ * @param transferType the transfer type
+ *
+ * @return the int
+ */
+ private static int validateTransferType(int transferType) {
+ if (transferType != DataBuffer.TYPE_BYTE &&
+ transferType != DataBuffer.TYPE_USHORT) {
+ // awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT
+ throw new IllegalArgumentException(Messages.getString("awt.269")); //$NON-NLS-1$
+ }
+ return transferType;
+ }
+
+ /**
+ * Checks if is gray pallete.
+ *
+ * @return true, if is gray pallete
+ */
+ boolean isGrayPallete(){
+ return grayPalette;
+ }
+
+}
+
+
diff --git a/awt/java/awt/image/Kernel.java b/awt/java/awt/image/Kernel.java
new file mode 100644
index 0000000..c6f00e2
--- /dev/null
+++ b/awt/java/awt/image/Kernel.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Sep 28, 2005
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Kernel class provides a matrix. This matrix is stored as a float array
+ * which describes how a specified pixel affects the value calculated for
+ * the pixel's position in the output image of a filtering operation.
+ * The X, Y origins indicate the kernel matrix element which corresponds to
+ * the pixel position for which an output value is being calculated.
+ */
+public class Kernel implements Cloneable {
+
+ /** The x origin. */
+ private final int xOrigin;
+
+ /** The y origin. */
+ private final int yOrigin;
+
+ /** The width. */
+ private int width;
+
+ /** The height. */
+ private int height;
+
+ /** The data. */
+ float data[];
+
+ /**
+ * Instantiates a new Kernel with the specified float array.
+ * The width*height elements of the data array are copied.
+ *
+ * @param width the width of the Kernel.
+ * @param height the height of the Kernel.
+ * @param data the data of Kernel.
+ */
+ public Kernel(int width, int height, float[] data) {
+ int dataLength = width*height;
+ if (data.length < dataLength) {
+ // awt.22B=Length of data should not be less than width*height
+ throw new IllegalArgumentException(Messages.getString("awt.22B")); //$NON-NLS-1$
+ }
+
+ this.width = width;
+ this.height = height;
+
+ this.data = new float[dataLength];
+ System.arraycopy(data, 0, this.data, 0, dataLength);
+
+ xOrigin = (width-1)/2;
+ yOrigin = (height-1)/2;
+ }
+
+ /**
+ * Gets the width of this Kernel.
+ *
+ * @return the width of this Kernel.
+ */
+ public final int getWidth() {
+ return width;
+ }
+
+ /**
+ * Gets the height of this Kernel.
+ *
+ * @return the height of this Kernel.
+ */
+ public final int getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the float data array of this Kernel.
+ *
+ * @param data the float array where the resulted data will be stored.
+ *
+ * @return the float data array of this Kernel.
+ */
+ public final float[] getKernelData(float[] data) {
+ if (data == null) {
+ data = new float[this.data.length];
+ }
+ System.arraycopy(this.data, 0, data, 0, this.data.length);
+
+ return data;
+ }
+
+ /**
+ * Gets the X origin of this Kernel.
+ *
+ * @return the X origin of this Kernel.
+ */
+ public final int getXOrigin() {
+ return xOrigin;
+ }
+
+ /**
+ * Gets the Y origin of this Kernel.
+ *
+ * @return the Y origin of this Kernel.
+ */
+ public final int getYOrigin() {
+ return yOrigin;
+ }
+
+ /**
+ * Returns a copy of this Kernel object.
+ *
+ * @return the copy of this Kernel object.
+ */
+ @Override
+ public Object clone() {
+ return new Kernel(width, height, data);
+ }
+}
diff --git a/awt/java/awt/image/LookupOp.java b/awt/java/awt/image/LookupOp.java
new file mode 100644
index 0000000..f9bd2c7
--- /dev/null
+++ b/awt/java/awt/image/LookupOp.java
@@ -0,0 +1,647 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Point2D;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The LookupOp class perfoms a lookup operation which transforms a
+ * source image by filtering each band using a table of data.
+ * The table may contain a single array or it may contain a
+ * different data array for each band of the image.
+ */
+public class LookupOp implements BufferedImageOp, RasterOp {
+
+ /** The lut. */
+ private final LookupTable lut;
+
+ /** The hints. */
+ private RenderingHints hints;
+
+ // TODO remove when this field is used
+ /** The can use ipp. */
+ @SuppressWarnings("unused")
+ private final boolean canUseIpp;
+
+ // We don't create levels/values when it is possible to reuse old
+ /** The cached levels. */
+ private int cachedLevels[];
+
+ /** The cached values. */
+ private int cachedValues[];
+ // Number of channels for which cache is valid.
+ // If negative number of channels is same as positive but skipAlpha was specified
+ /** The valid for channels. */
+ private int validForChannels;
+
+ /** The level initializer. */
+ static int levelInitializer[] = new int[0x10000];
+
+ static {
+ // TODO
+ // System.loadLibrary("imageops");
+
+ for (int i=1; i<=0x10000; i++) {
+ levelInitializer[i-1] = i;
+ }
+ }
+
+ /**
+ * Instantiates a new LookupOp object from the specified
+ * LookupTable object and a RenderingHints object.
+ *
+ * @param lookup the specified LookupTable object.
+ * @param hints the RenderingHints object or null.
+ */
+ public LookupOp(LookupTable lookup, RenderingHints hints) {
+ if (lookup == null){
+ throw new NullPointerException(Messages.getString("awt.01", "lookup")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ lut = lookup;
+ this.hints = hints;
+ canUseIpp = lut instanceof ByteLookupTable || lut instanceof ShortLookupTable;
+ }
+
+ /**
+ * Gets the LookupTable of the specified Object.
+ *
+ * @return the LookupTable of the specified Object.
+ */
+ public final LookupTable getTable() {
+ return lut;
+ }
+
+ public final RenderingHints getRenderingHints() {
+ return hints;
+ }
+
+ public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+ if (dstPt == null) {
+ dstPt = new Point2D.Float();
+ }
+
+ dstPt.setLocation(srcPt);
+ return dstPt;
+ }
+
+ public final Rectangle2D getBounds2D(Raster src) {
+ return src.getBounds();
+ }
+
+ public final Rectangle2D getBounds2D(BufferedImage src) {
+ return getBounds2D(src.getRaster());
+ }
+
+ public WritableRaster createCompatibleDestRaster(Raster src) {
+ return src.createCompatibleWritableRaster();
+ }
+
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
+ if (dstCM == null) {
+ dstCM = src.getColorModel();
+
+ // Sync transfer type with LUT for component color model
+ if (dstCM instanceof ComponentColorModel) {
+ int transferType = dstCM.getTransferType();
+ if (lut instanceof ByteLookupTable) {
+ transferType = DataBuffer.TYPE_BYTE;
+ } else if (lut instanceof ShortLookupTable) {
+ transferType = DataBuffer.TYPE_SHORT;
+ }
+
+ dstCM = new ComponentColorModel(
+ dstCM.cs,
+ dstCM.hasAlpha(),
+ dstCM.isAlphaPremultiplied,
+ dstCM.transparency,
+ transferType
+ );
+ }
+ }
+
+ WritableRaster r =
+ dstCM.isCompatibleSampleModel(src.getSampleModel()) ?
+ src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) :
+ dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+
+ return new BufferedImage(
+ dstCM,
+ r,
+ dstCM.isAlphaPremultiplied(),
+ null
+ );
+ }
+
+ public final WritableRaster filter(Raster src, WritableRaster dst) {
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else {
+ if (src.getNumBands() != dst.getNumBands()) {
+ throw new IllegalArgumentException(Messages.getString("awt.237")); //$NON-NLS-1$ }
+ }
+ if (src.getWidth() != dst.getWidth()){
+ throw new IllegalArgumentException(Messages.getString("awt.28F")); //$NON-NLS-1$ }
+ }
+ if (src.getHeight() != dst.getHeight()){
+ throw new IllegalArgumentException(Messages.getString("awt.290")); //$NON-NLS-1$ }
+ }
+ }
+
+ if (lut.getNumComponents() != 1 && lut.getNumComponents() != src.getNumBands()) {
+ // awt.238=The number of arrays in the LookupTable does not meet the restrictions
+ throw new IllegalArgumentException(Messages.getString("awt.238")); //$NON-NLS-1$
+ }
+
+ // TODO
+ // if (!canUseIpp || ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0)
+ if (slowFilter(src, dst, false) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ return dst;
+ }
+
+ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ ColorModel srcCM = src.getColorModel();
+
+ if (srcCM instanceof IndexColorModel) {
+ // awt.220=Source should not have IndexColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$
+ }
+
+ // Check if the number of scaling factors matches the number of bands
+ int nComponents = srcCM.getNumComponents();
+ int nLUTComponents = lut.getNumComponents();
+ boolean skipAlpha;
+ if (srcCM.hasAlpha()) {
+ if (nLUTComponents == 1 || nLUTComponents == nComponents-1) {
+ skipAlpha = true;
+ } else if (nLUTComponents == nComponents) {
+ skipAlpha = false;
+ } else {
+ // awt.229=Number of components in the LUT does not match the number of bands
+ throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$
+ }
+ } else if (nLUTComponents == 1 || nLUTComponents == nComponents) {
+ skipAlpha = false;
+ } else {
+ // awt.229=Number of components in the LUT does not match the number of bands
+ throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$
+ }
+
+ BufferedImage finalDst = null;
+ if (dst == null) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, null);
+ } else {
+ if (src.getWidth() != dst.getWidth()){
+ throw new IllegalArgumentException(Messages.getString("awt.291")); //$NON-NLS-1$
+ }
+
+ if (src.getHeight() != dst.getHeight()){
+ throw new IllegalArgumentException(Messages.getString("awt.292")); //$NON-NLS-1$
+ }
+
+ if (!srcCM.equals(dst.getColorModel())) {
+ // Treat BufferedImage.TYPE_INT_RGB and
+ // BufferedImage.TYPE_INT_ARGB as same
+ if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src
+ .getType() == BufferedImage.TYPE_INT_ARGB) && (dst
+ .getType() == BufferedImage.TYPE_INT_RGB || dst
+ .getType() == BufferedImage.TYPE_INT_ARGB))) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, null);
+ }
+ }
+ }
+
+ // TODO
+ //if (!canUseIpp || ippFilter(src.getRaster(), dst.getRaster(), src.getType(), skipAlpha) != 0)
+ if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ if (finalDst != null) {
+ Graphics2D g = finalDst.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.drawImage(dst, 0, 0, null);
+ } else {
+ finalDst = dst;
+ }
+
+ return dst;
+ }
+
+ /**
+ * Slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param skipAlpha the skip alpha
+ *
+ * @return the int
+ */
+ private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) {
+ int minSrcX = src.getMinX();
+ int minDstX = dst.getMinX();
+ int minSrcY = src.getMinY();
+ int minDstY = dst.getMinY();
+
+ int skippingChannels = skipAlpha ? 1 : 0;
+ int numBands2Process = src.getNumBands() - skippingChannels;
+
+ int numBands = src.getNumBands();
+ int srcHeight = src.getHeight();
+ int srcWidth = src.getWidth();
+
+ int[] pixels = null;
+ int offset = lut.getOffset();
+
+ if (lut instanceof ByteLookupTable){
+ byte[][] byteData = ((ByteLookupTable)lut).getTable();
+ pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels);
+
+ if (lut.getNumComponents() != 1){
+ for (int i=0; i < pixels.length; i+= numBands){
+ for (int b = 0; b < numBands2Process; b++){
+ pixels[i+b] = byteData[b][pixels[i+b]-offset] & 0xFF;
+ }
+ }
+ } else {
+ for (int i=0; i < pixels.length; i+= numBands){
+ for (int b = 0; b < numBands2Process; b++){
+ pixels[i+b] = byteData[0][pixels[i+b]-offset] & 0xFF;
+ }
+ }
+ }
+
+ dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels);
+ } else if (lut instanceof ShortLookupTable){
+ short[][] shortData = ((ShortLookupTable)lut).getTable();
+ pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels);
+
+ if (lut.getNumComponents() != 1){
+ for (int i=0; i < pixels.length; i+= numBands){
+ for (int b = 0; b < numBands2Process; b++){
+ pixels[i+b] = shortData[b][pixels[i+b]-offset] & 0xFFFF;
+ }
+ }
+ } else {
+ for (int i=0; i < pixels.length; i+= numBands){
+ for (int b = 0; b < numBands2Process; b++){
+ pixels[i+b] = shortData[0][pixels[i+b]-offset] & 0xFFFF;
+ }
+ }
+ }
+
+ dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels);
+ } else {
+ int pixel[] = new int[src.getNumBands()];
+ int maxY = minSrcY + srcHeight;
+ int maxX = minSrcX + srcWidth;
+ for (int srcY=minSrcY, dstY = minDstY; srcY < maxY; srcY++, dstY++){
+ for (int srcX=minSrcX, dstX = minDstX; srcX < maxX; srcX++, dstX++){
+ src.getPixel(srcX, srcY, pixel);
+ lut.lookupPixel(pixel, pixel);
+ dst.setPixel(dstX, dstY, pixel);
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * Creates the byte levels.
+ *
+ * @param channels the channels
+ * @param skipAlpha the skip alpha
+ * @param levels the levels
+ * @param values the values
+ * @param channelsOrder the channels order
+ */
+ private final void createByteLevels(
+ int channels, boolean skipAlpha,
+ int levels[], int values[], int channelsOrder[]
+ ) {
+ byte data[][] = ((ByteLookupTable)lut).getTable();
+ int nLevels = data[0].length;
+ int offset = lut.getOffset();
+
+ // Use one data array for all channels or use several data arrays
+ int dataIncrement = data.length > 1 ? 1 : 0;
+
+ for (int ch = 0, dataIdx = 0; ch<channels; dataIdx+=dataIncrement, ch++) {
+ int channelOffset = channelsOrder == null ? ch : channelsOrder[ch];
+ int channelBase = nLevels * channelOffset;
+
+ // Skip last channel if needed, zero values are OK -
+ // no changes to the channel information will be done in IPP
+ if ((channelOffset == channels-1 && skipAlpha) || (dataIdx >= data.length)) {
+ continue;
+ }
+
+ System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels);
+ for (int from=0, to=channelBase; from<nLevels; from++, to++) {
+ values[to] = data[dataIdx][from] & 0xFF;
+ }
+ }
+ }
+
+ /**
+ * Creates the short levels.
+ *
+ * @param channels the channels
+ * @param skipAlpha the skip alpha
+ * @param levels the levels
+ * @param values the values
+ * @param channelsOrder the channels order
+ */
+ private final void createShortLevels(
+ int channels, boolean skipAlpha,
+ int levels[], int values[], int channelsOrder[]
+ ) {
+ short data[][] = ((ShortLookupTable)lut).getTable();
+ int nLevels = data[0].length;
+ int offset = lut.getOffset();
+
+ // Use one data array for all channels or use several data arrays
+ int dataIncrement = data.length > 1 ? 1 : 0;
+
+ for (int ch = 0, dataIdx = 0; ch<channels; dataIdx+=dataIncrement, ch++) {
+ int channelOffset = channelsOrder == null ? ch : channelsOrder[ch];
+
+ // Skip last channel if needed, zero values are OK -
+ // no changes to the channel information will be done in IPP
+ if ((channelOffset == channels-1 && skipAlpha) || (dataIdx >= data.length)) {
+ continue;
+ }
+
+ int channelBase = nLevels * channelOffset;
+ System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels);
+ for (int from=0, to=channelBase; from<nLevels; from++, to++) {
+ values[to] = data[dataIdx][from] & 0xFFFF;
+ }
+ }
+ }
+
+ // TODO remove when this method is used
+ /**
+ * Ipp filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param imageType the image type
+ * @param skipAlpha the skip alpha
+ *
+ * @return the int
+ */
+ @SuppressWarnings("unused")
+ private final int ippFilter(
+ Raster src, WritableRaster dst,
+ int imageType, boolean skipAlpha
+ ) {
+ int res;
+
+ int srcStride, dstStride;
+ int channels;
+ int offsets[] = null;
+ int channelsOrder[] = null;
+
+ switch (imageType) {
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ case BufferedImage.TYPE_INT_RGB: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ channelsOrder = new int[] {2, 1, 0, 3};
+ break;
+ }
+
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+ case BufferedImage.TYPE_INT_BGR: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_GRAY: {
+ channels = 1;
+ srcStride = src.getWidth();
+ dstStride = dst.getWidth();
+ break;
+ }
+
+ case BufferedImage.TYPE_3BYTE_BGR: {
+ channels = 3;
+ srcStride = src.getWidth()*3;
+ dstStride = dst.getWidth()*3;
+ channelsOrder = new int[] {2, 1, 0};
+ break;
+ }
+
+ case BufferedImage.TYPE_USHORT_GRAY:
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ case BufferedImage.TYPE_BYTE_BINARY: {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ default: {
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+
+ if (
+ srcSM instanceof PixelInterleavedSampleModel &&
+ dstSM instanceof PixelInterleavedSampleModel
+ ) {
+ // Check PixelInterleavedSampleModel
+ if (
+ srcSM.getDataType() != DataBuffer.TYPE_BYTE ||
+ dstSM.getDataType() != DataBuffer.TYPE_BYTE
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ // Have IPP functions for 1, 3 and 4 channels
+ channels = srcSM.getNumBands();
+ if (!(channels == 1 || channels == 3 || channels == 4)) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ srcStride = ((ComponentSampleModel) srcSM).getScanlineStride();
+ dstStride = ((ComponentSampleModel) dstSM).getScanlineStride();
+
+ channelsOrder = ((ComponentSampleModel) srcSM).getBandOffsets();
+ } else if (
+ srcSM instanceof SinglePixelPackedSampleModel &&
+ dstSM instanceof SinglePixelPackedSampleModel
+ ) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 =
+ (SinglePixelPackedSampleModel) srcSM;
+ SinglePixelPackedSampleModel sppsm2 =
+ (SinglePixelPackedSampleModel) dstSM;
+
+ channels = sppsm1.getNumBands();
+
+ // TYPE_INT_RGB, TYPE_INT_ARGB...
+ if (
+ sppsm1.getDataType() != DataBuffer.TYPE_INT ||
+ sppsm2.getDataType() != DataBuffer.TYPE_INT ||
+ !(channels == 3 || channels == 4)
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ // Check compatibility of sample models
+ if (
+ !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) ||
+ !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ for (int i=0; i<channels; i++) {
+ if (sppsm1.getSampleSize(i) != 8) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+ }
+
+ channelsOrder = new int[channels];
+ int bitOffsets[] = sppsm1.getBitOffsets();
+ for (int i=0; i<channels; i++) {
+ channelsOrder[i] = bitOffsets[i] / 8;
+ }
+
+ if (channels == 3) { // Don't skip channel now, could be optimized
+ channels = 4;
+ }
+
+ srcStride = sppsm1.getScanlineStride() * 4;
+ dstStride = sppsm2.getScanlineStride() * 4;
+ } else {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (
+ src.getSampleModelTranslateX() != 0 ||
+ src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 ||
+ dst.getSampleModelTranslateY() != 0
+ ) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+ }
+ }
+
+ int levels[] = null, values[] = null;
+ int channelMultiplier = skipAlpha ? -1 : 1;
+ if (channelMultiplier*channels == validForChannels) { // use existing levels/values
+ levels = cachedLevels;
+ values = cachedValues;
+ } else { // create new levels/values
+ if (lut instanceof ByteLookupTable) {
+ byte data[][] = ((ByteLookupTable)lut).getTable();
+ levels = new int[channels*data[0].length];
+ values = new int[channels*data[0].length];
+ createByteLevels(channels, skipAlpha, levels, values, channelsOrder);
+ } else if (lut instanceof ShortLookupTable) {
+ short data[][] = ((ShortLookupTable)lut).getTable();
+ levels = new int[channels*data[0].length];
+ values = new int[channels*data[0].length];
+ createShortLevels(channels, skipAlpha, levels, values, channelsOrder);
+ }
+
+ // cache levels/values
+ validForChannels = channelMultiplier*channels;
+ cachedLevels = levels;
+ cachedValues = values;
+ }
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ res = ippLUT(
+ srcData, src.getWidth(), src.getHeight(), srcStride,
+ dstData, dst.getWidth(), dst.getHeight(), dstStride,
+ levels, values,
+ channels, offsets,
+ false
+ );
+
+ return res;
+ }
+
+ /**
+ * Ipp lut.
+ *
+ * @param src the src
+ * @param srcWidth the src width
+ * @param srcHeight the src height
+ * @param srcStride the src stride
+ * @param dst the dst
+ * @param dstWidth the dst width
+ * @param dstHeight the dst height
+ * @param dstStride the dst stride
+ * @param levels the levels
+ * @param values the values
+ * @param channels the channels
+ * @param offsets the offsets
+ * @param linear the linear
+ *
+ * @return the int
+ */
+ final static native int ippLUT(
+ Object src, int srcWidth, int srcHeight, int srcStride,
+ Object dst, int dstWidth, int dstHeight, int dstStride,
+ int levels[], int values[],
+ int channels, int offsets[],
+ boolean linear
+ );
+}
diff --git a/awt/java/awt/image/LookupTable.java b/awt/java/awt/image/LookupTable.java
new file mode 100644
index 0000000..d15f23c
--- /dev/null
+++ b/awt/java/awt/image/LookupTable.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This abstract LookupTable class represents lookup table which
+ * is defined with the number of components and offset value.
+ * ByteLookupTable and ShortLookupTable classes are subclasses of
+ * LookupTable which contains byte and short data tables as
+ * an input arrays for bands or components of image.
+ */
+public abstract class LookupTable {
+
+ /** The offset. */
+ private int offset;
+
+ /** The num components. */
+ private int numComponents;
+
+ /**
+ * Instantiates a new LookupTable with the specified offset value
+ * and number of components.
+ *
+ * @param offset the offset value.
+ * @param numComponents the number of components.
+ */
+ protected LookupTable(int offset, int numComponents) {
+ if (offset < 0) {
+ // awt.232=Offset should be not less than zero
+ throw new IllegalArgumentException(Messages.getString("awt.232")); //$NON-NLS-1$
+ }
+ if (numComponents < 1) {
+ // awt.233=Number of components should be positive
+ throw new IllegalArgumentException(Messages.getString("awt.233")); //$NON-NLS-1$
+ }
+
+ this.offset = offset;
+ this.numComponents = numComponents;
+ }
+
+ /**
+ * Gets the offset value of this Lookup table.
+ *
+ * @return the offset value of this Lookup table.
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Gets the number of components of this Lookup table.
+ *
+ * @return the number components of this Lookup table.
+ */
+ public int getNumComponents() {
+ return numComponents;
+ }
+
+ /**
+ * Returns a int array which contains samples of the specified
+ * pixel which is translated with the lookup table of this
+ * LookupTable. The resulted array is stored to the dst array.
+ *
+ * @param src the source array.
+ * @param dst the destination array where the result can be stored.
+ *
+ * @return the int array of translated samples of a pixel.
+ */
+ public abstract int[] lookupPixel(int[] src, int[] dst);
+}
diff --git a/awt/java/awt/image/MemoryImageSource.java b/awt/java/awt/image/MemoryImageSource.java
new file mode 100644
index 0000000..983f19e
--- /dev/null
+++ b/awt/java/awt/image/MemoryImageSource.java
@@ -0,0 +1,512 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The MemoryImageSource class is used to produces pixels of an image from
+ * an array. This class can manage a memory image which
+ * contains an animation or custom rendering.
+ */
+public class MemoryImageSource implements ImageProducer {
+
+ /** The width. */
+ int width;
+
+ /** The height. */
+ int height;
+
+ /** The cm. */
+ ColorModel cm;
+
+ /** The b data. */
+ byte bData[];
+
+ /** The i data. */
+ int iData[];
+
+ /** The offset. */
+ int offset;
+
+ /** The scanline. */
+ int scanline;
+
+ /** The properties. */
+ Hashtable<?, ?> properties;
+
+ /** The consumers. */
+ Vector<ImageConsumer> consumers;
+
+ /** The animated. */
+ boolean animated;
+
+ /** The fullbuffers. */
+ boolean fullbuffers;
+
+ /** The data type. */
+ int dataType;
+
+ /** The Constant DATA_TYPE_BYTE. */
+ static final int DATA_TYPE_BYTE = 0;
+
+ /** The Constant DATA_TYPE_INT. */
+ static final int DATA_TYPE_INT = 1;
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param cm the specified ColorModel.
+ * @param pix the pixel array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ * @param props the set of properties to be used for image
+ * processing.
+ */
+ public MemoryImageSource(int w, int h, ColorModel cm, int pix[],
+ int off, int scan, Hashtable<?, ?> props) {
+ init(w, h, cm, pix, off, scan, props);
+ }
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param cm the specified ColorModel.
+ * @param pix the pixel array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ * @param props the set of properties to be used for image
+ * processing.
+ */
+ public MemoryImageSource(int w, int h, ColorModel cm, byte pix[],
+ int off, int scan, Hashtable<?, ?> props) {
+ init(w, h, cm, pix, off, scan, props);
+ }
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters and default RGB ColorModel.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param pix the pixel array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ * @param props the set of properties to be used for image
+ * processing.
+ */
+ public MemoryImageSource(int w, int h, int pix[], int off, int scan,
+ Hashtable<?, ?> props) {
+ init(w, h, ColorModel.getRGBdefault(), pix, off, scan, props);
+ }
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param cm the specified ColorModel.
+ * @param pix the pixel array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ */
+ public MemoryImageSource(int w, int h, ColorModel cm, int pix[],
+ int off, int scan) {
+ init(w, h, cm, pix, off, scan, null);
+ }
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param cm the specified ColorModel.
+ * @param pix the pixel array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ */
+ public MemoryImageSource(int w, int h, ColorModel cm, byte pix[],
+ int off, int scan) {
+ init(w, h, cm, pix, off, scan, null);
+ }
+
+ /**
+ * Instantiates a new MemoryImageSource with the specified
+ * parameters and default RGB ColorModel.
+ *
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param pix the pixels array.
+ * @param off the offset in the pixel array.
+ * @param scan the distance from one pixel's row to the next
+ * in the pixel array.
+ */
+ public MemoryImageSource(int w, int h, int pix[], int off, int scan) {
+ init(w, h, ColorModel.getRGBdefault(), pix, off, scan, null);
+ }
+
+ public synchronized boolean isConsumer(ImageConsumer ic) {
+ return consumers.contains(ic);
+ }
+
+ public void startProduction(ImageConsumer ic) {
+ if(!isConsumer(ic) && ic != null) {
+ consumers.addElement(ic);
+ }
+ try{
+ setHeader(ic);
+ setPixels(ic, 0, 0, width, height);
+ if(animated){
+ ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }else{
+ ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
+ if(isConsumer(ic)) {
+ removeConsumer(ic);
+ }
+ }
+ }catch(Exception e){
+ if(isConsumer(ic)) {
+ ic.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ if(isConsumer(ic)) {
+ removeConsumer(ic);
+ }
+ }
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer ic) {
+ }
+
+ public synchronized void removeConsumer(ImageConsumer ic) {
+ consumers.removeElement(ic);
+ }
+
+ public synchronized void addConsumer(ImageConsumer ic) {
+ if(ic == null || consumers.contains(ic)) {
+ return;
+ }
+ consumers.addElement(ic);
+ }
+
+ /**
+ * Replaces the pixel data with a new pixel array for holding
+ * the pixels for this image. If an animation
+ * flag is set to true value by the setAnimated() method,
+ * the new pixels will be immediately delivered to the ImageConsumers.
+ *
+ * @param newpix the new pixel array.
+ * @param newmodel the new ColorModel.
+ * @param offset the offset in the array.
+ * @param scansize the distance from one row of pixels to the next row
+ * in the pixel array
+ */
+ public synchronized void newPixels(int newpix[], ColorModel newmodel,
+ int offset, int scansize) {
+ this.dataType = DATA_TYPE_INT;
+ this.iData = newpix;
+ this.cm = newmodel;
+ this.offset = offset;
+ this.scanline = scansize;
+ newPixels();
+ }
+
+ /**
+ * Replaces the pixel data with a new pixel array for holding
+ * the pixels for this image. If an animation
+ * flag is set to true value by the setAnimated() method,
+ * the new pixels will be immediately delivered to the ImageConsumers.
+ *
+ * @param newpix the new pixel array.
+ * @param newmodel the new ColorModel.
+ * @param offset the offset in the array.
+ * @param scansize the distance from one row of pixels to the next row
+ * in the pixel array
+ */
+ public synchronized void newPixels(byte newpix[], ColorModel newmodel,
+ int offset, int scansize) {
+ this.dataType = DATA_TYPE_BYTE;
+ this.bData = newpix;
+ this.cm = newmodel;
+ this.offset = offset;
+ this.scanline = scansize;
+ newPixels();
+ }
+
+ /**
+ * Sets the full buffer updates flag to true. If this is an
+ * animated image, the image consumers hints are updated
+ * accordingly.
+ *
+ * @param fullbuffers the true if the pixel buffer should be sent always.
+ */
+ public synchronized void setFullBufferUpdates(boolean fullbuffers) {
+ if(this.fullbuffers == fullbuffers) {
+ return;
+ }
+ this.fullbuffers = fullbuffers;
+ if(animated){
+ Object consAr[] = consumers.toArray();
+ for (Object element : consAr) {
+ ImageConsumer con = (ImageConsumer)element;
+ try{
+ if(fullbuffers){
+ con.setHints(ImageConsumer.TOPDOWNLEFTRIGHT |
+ ImageConsumer.COMPLETESCANLINES);
+ }else{
+ con.setHints(ImageConsumer.RANDOMPIXELORDER);
+ }
+ }catch(Exception e){
+ if(isConsumer(con)) {
+ con.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ if(isConsumer(con)) {
+ removeConsumer(con);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the flag that tells whether this memory image has more
+ * than one frame (for animation): true for multiple frames,
+ * false if this class represents a single frame image.
+ *
+ * @param animated whether this image represents an animation.
+ */
+ public synchronized void setAnimated(boolean animated) {
+ if(this.animated == animated) {
+ return;
+ }
+ Object consAr[] = consumers.toArray();
+ for (Object element : consAr) {
+ ImageConsumer con = (ImageConsumer)element;
+ try{
+ con.imageComplete(ImageConsumer.STATICIMAGEDONE);
+ }catch(Exception e){
+ if(isConsumer(con)) {
+ con.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ }
+ if(isConsumer(con)){
+ removeConsumer(con);
+ }
+ }
+ this.animated = animated;
+ }
+
+ /**
+ * Sends the specified rectangular area of the buffer to
+ * ImageConsumers and notifies them that an animation frame
+ * is completed only if framenotify parameter is true.
+ * That works only if the animated flag has been set to true
+ * by the setAnimated() method. If the full buffer update flag
+ * has been set to true by the setFullBufferUpdates() method,
+ * then the entire buffer will always be sent ignoring parameters.
+ *
+ * @param x the X coordinate of the rectangular area.
+ * @param y the Y coordinate of rthe ectangular area.
+ * @param w the width of the rectangular area.
+ * @param h the height of the rectangular area.
+ * @param framenotify true if a SINGLEFRAMEDONE notification
+ * should be sent to the registered consumers, false otherwise.
+ */
+ public synchronized void newPixels(int x, int y, int w, int h,
+ boolean framenotify) {
+ if(animated){
+ if(fullbuffers){
+ x = 0;
+ y = 0;
+ w = width;
+ h = height;
+ }else{
+ if(x < 0){
+ w += x;
+ x = 0;
+ }
+ if(w > width) {
+ w = width - x;
+ }
+ if(y < 0){
+ h += y;
+ y = 0;
+ }
+ }
+ if(h > height) {
+ h = height - y;
+ }
+ Object consAr[] = consumers.toArray();
+ for (Object element : consAr) {
+ ImageConsumer con = (ImageConsumer)element;
+ try{
+ if(w > 0 && h > 0) {
+ setPixels(con, x, y, w, h);
+ }
+ if(framenotify) {
+ con.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }
+ }catch(Exception ex){
+ if(isConsumer(con)) {
+ con.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ if(isConsumer(con)) {
+ removeConsumer(con);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sends the specified rectangular area of the buffer to
+ * the ImageConsumers and notifies them that an animation frame
+ * is completed if the animated flag has been set to true
+ * by the setAnimated() method. If the full buffer update flag
+ * has been set to true by the setFullBufferUpdates() method,
+ * then the entire buffer will always be sent ignoring parameters.
+ *
+ * @param x the X coordinate of the rectangular area.
+ * @param y the Y coordinate of the rectangular area.
+ * @param w the width of the rectangular area.
+ * @param h the height of the rectangular area.
+ */
+ public synchronized void newPixels(int x, int y, int w, int h) {
+ newPixels(x, y, w, h, true);
+ }
+
+ /**
+ * Sends a new buffer of pixels to the ImageConsumers
+ * and notifies them that an animation frame is completed if
+ * the animated flag has been set to true by the setAnimated() method.
+ */
+ public void newPixels() {
+ newPixels(0, 0, width, height, true);
+ }
+
+ /**
+ * Inits the.
+ *
+ * @param width the width
+ * @param height the height
+ * @param model the model
+ * @param pixels the pixels
+ * @param off the off
+ * @param scan the scan
+ * @param prop the prop
+ */
+ private void init(int width, int height, ColorModel model, byte pixels[],
+ int off, int scan, Hashtable<?, ?> prop){
+
+ this.width = width;
+ this.height = height;
+ this.cm = model;
+ this.bData = pixels;
+ this.offset = off;
+ this.scanline = scan;
+ this.properties = prop;
+ this.dataType = DATA_TYPE_BYTE;
+ this.consumers = new Vector<ImageConsumer>();
+
+ }
+
+ /**
+ * Inits the.
+ *
+ * @param width the width
+ * @param height the height
+ * @param model the model
+ * @param pixels the pixels
+ * @param off the off
+ * @param scan the scan
+ * @param prop the prop
+ */
+ private void init(int width, int height, ColorModel model, int pixels[],
+ int off, int scan, Hashtable<?, ?> prop){
+
+ this.width = width;
+ this.height = height;
+ this.cm = model;
+ this.iData = pixels;
+ this.offset = off;
+ this.scanline = scan;
+ this.properties = prop;
+ this.dataType = DATA_TYPE_INT;
+ this.consumers = new Vector<ImageConsumer>();
+ }
+
+ /**
+ * Sets the pixels.
+ *
+ * @param con the con
+ * @param x the x
+ * @param y the y
+ * @param w the w
+ * @param h the h
+ */
+ private void setPixels(ImageConsumer con, int x, int y, int w, int h){
+ int pixelOff = scanline * y + offset + x;
+
+ switch(dataType){
+ case DATA_TYPE_BYTE:
+ con.setPixels(x, y, w, h, cm, bData, pixelOff, scanline);
+ break;
+ case DATA_TYPE_INT:
+ con.setPixels(x, y, w, h, cm, iData, pixelOff, scanline);
+ break;
+ default:
+ // awt.22A=Wrong type of pixels array
+ throw new IllegalArgumentException(Messages.getString("awt.22A")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Sets the header.
+ *
+ * @param con the new header
+ */
+ private synchronized void setHeader(ImageConsumer con){
+ con.setDimensions(width, height);
+ con.setProperties(properties);
+ con.setColorModel(cm);
+ con.setHints(animated ? (fullbuffers ? (ImageConsumer.TOPDOWNLEFTRIGHT |
+ ImageConsumer.COMPLETESCANLINES) : ImageConsumer.RANDOMPIXELORDER) :
+ (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES |
+ ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME));
+ }
+
+}
+
diff --git a/awt/java/awt/image/MultiPixelPackedSampleModel.java b/awt/java/awt/image/MultiPixelPackedSampleModel.java
new file mode 100644
index 0000000..dd44b49
--- /dev/null
+++ b/awt/java/awt/image/MultiPixelPackedSampleModel.java
@@ -0,0 +1,454 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The MultiPixelPackedSampleModel class represents image data with one
+ * band. This class packs multiple pixels with one sample in one data
+ * element and supports the following data types: DataBuffer.TYPE_BYTE,
+ * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT.
+ */
+public class MultiPixelPackedSampleModel extends SampleModel {
+
+ /** The pixel bit stride. */
+ private int pixelBitStride;
+
+ /** The scanline stride. */
+ private int scanlineStride;
+
+ /** The data bit offset. */
+ private int dataBitOffset;
+
+ /** The bit mask. */
+ private int bitMask;
+
+ /** The data element size. */
+ private int dataElementSize;
+
+ /** The pixels per data element. */
+ private int pixelsPerDataElement;
+
+ /**
+ * Instantiates a new MultiPixelPackedSampleModel with the specified
+ * parameters.
+ *
+ * @param dataType the data type of the samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param numberOfBits the number of bits per pixel.
+ * @param scanlineStride the scanline stride of the of the image data.
+ * @param dataBitOffset the array of the band offsets.
+ */
+ public MultiPixelPackedSampleModel(int dataType, int w, int h,
+ int numberOfBits, int scanlineStride, int dataBitOffset) {
+
+ super(dataType, w, h, 1);
+ if (dataType != DataBuffer.TYPE_BYTE &&
+ dataType != DataBuffer.TYPE_USHORT &&
+ dataType != DataBuffer.TYPE_INT) {
+ // awt.61=Unsupported data type: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$
+ dataType));
+ }
+
+ this.scanlineStride = scanlineStride;
+ if(numberOfBits == 0) {
+ // awt.20C=Number of Bits equals to zero
+ throw new RasterFormatException(Messages.getString("awt.20C")); //$NON-NLS-1$
+ }
+ this.pixelBitStride = numberOfBits;
+ this.dataElementSize = DataBuffer.getDataTypeSize(dataType);
+ if(dataElementSize % pixelBitStride != 0) {
+ // awt.20D=The number of bits per pixel is not a power of 2 or pixels span data element boundaries
+ throw new RasterFormatException(Messages.getString("awt.20D")); //$NON-NLS-1$
+ }
+
+ if(dataBitOffset % numberOfBits != 0) {
+ // awt.20E=Data Bit offset is not a multiple of pixel bit stride
+ throw new RasterFormatException(Messages.getString("awt.20E")); //$NON-NLS-1$
+ }
+ this.dataBitOffset = dataBitOffset;
+
+ this.pixelsPerDataElement = dataElementSize / pixelBitStride;
+ this.bitMask = (1 << numberOfBits) - 1;
+ }
+
+ /**
+ * Instantiates a new MultiPixelPackedSampleModel with the specified
+ * parameters.
+ *
+ * @param dataType the data type of the samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param numberOfBits the number of bits per pixel.
+ */
+ public MultiPixelPackedSampleModel(int dataType, int w, int h,
+ int numberOfBits) {
+
+ this(dataType, w, h, numberOfBits, (numberOfBits * w +
+ DataBuffer.getDataTypeSize(dataType) - 1) /
+ DataBuffer.getDataTypeSize(dataType), 0);
+ }
+
+ @Override
+ public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[];
+ if (obj == null) {
+ bdata = new byte[1];
+ } else {
+ bdata = (byte[]) obj;
+ }
+ bdata[0] = (byte) getSample(x, y, 0, data);
+ obj = bdata;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short sdata[];
+ if (obj == null) {
+ sdata = new short[1];
+ } else {
+ sdata = (short[]) obj;
+ }
+ sdata[0] = (short) getSample(x, y, 0, data);
+ obj = sdata;
+ break;
+ case DataBuffer.TYPE_INT:
+ int idata[];
+ if (obj == null) {
+ idata = new int[1];
+ } else {
+ idata = (int[]) obj;
+ }
+ idata[0] = getSample(x, y, 0, data);
+ obj = idata;
+ break;
+ }
+
+ return obj;
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+ setSample(x, y, obj, data, 1, 0);
+ }
+
+ /**
+ * Compares this MultiPixelPackedSampleModel object with
+ * the specified object.
+ *
+ * @param o the Object to be compared.
+ *
+ * @return true, if the object is a MultiPixelPackedSampleModel
+ * with the same data parameter values as this MultiPixelPackedSampleModel,
+ * false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) {
+ return false;
+ }
+
+ MultiPixelPackedSampleModel model = (MultiPixelPackedSampleModel) o;
+ return this.width == model.width &&
+ this.height == model.height &&
+ this.numBands == model.numBands &&
+ this.dataType == model.dataType &&
+ this.pixelBitStride == model.pixelBitStride &&
+ this.bitMask == model.bitMask &&
+ this.pixelsPerDataElement == model.pixelsPerDataElement &&
+ this.dataElementSize == model.dataElementSize &&
+ this.dataBitOffset == model.dataBitOffset &&
+ this.scanlineStride == model.scanlineStride;
+ }
+
+ @Override
+ public SampleModel createSubsetSampleModel(int bands[]) {
+ if (bands != null && bands.length != 1) {
+ // awt.20F=Number of bands must be only 1
+ throw new RasterFormatException(Messages.getString("awt.20F")); //$NON-NLS-1$
+ }
+ return createCompatibleSampleModel(width, height);
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ return new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride);
+ }
+
+ @Override
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int pixel[];
+ if (iArray == null) {
+ pixel = new int[numBands];
+ } else {
+ pixel = iArray;
+ }
+
+ pixel[0] = getSample(x, y, 0, data);
+ return pixel;
+ }
+
+ @Override
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ setSample(x, y, iArray, data, 2, 0);
+ }
+
+ @Override
+ public int getSample(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height || b != 0) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int bitnum = dataBitOffset + x * pixelBitStride;
+ int elem = data.getElem(y * scanlineStride + bitnum / dataElementSize);
+ int shift = dataElementSize - (bitnum & (dataElementSize - 1)) -
+ pixelBitStride;
+
+ return (elem >> shift) & bitMask;
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s, DataBuffer data) {
+ if (b != 0) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ setSample(x, y, null, data, 3, s);
+ }
+
+ @Override
+ public DataBuffer createDataBuffer() {
+ DataBuffer dataBuffer = null;
+ int size = scanlineStride * height;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ dataBuffer = new DataBufferByte(size + (dataBitOffset + 7) / 8);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ dataBuffer = new DataBufferUShort(size + (dataBitOffset + 15) / 16);
+ break;
+ case DataBuffer.TYPE_INT:
+ dataBuffer = new DataBufferInt(size + (dataBitOffset + 31) / 32);
+ break;
+ }
+ return dataBuffer;
+ }
+
+ /**
+ * Gets the offset of the specified pixel in the data array.
+ *
+ * @param x the X coordinate of the specified pixel.
+ * @param y the Y coordinate of the specified pixel.
+ *
+ * @return the offset of the specified pixel.
+ */
+ public int getOffset(int x, int y) {
+ return y * scanlineStride + (x * pixelBitStride + dataBitOffset) /
+ dataElementSize;
+ }
+
+ @Override
+ public int getSampleSize(int band) {
+ return pixelBitStride;
+ }
+
+ /**
+ * Gets the bit offset in the data element which
+ * is stored for the specified pixel of a scanline.
+ *
+ * @param x the pixel.
+ *
+ * @return the bit offset of the pixel in the data element.
+ */
+ public int getBitOffset(int x) {
+ return (x * pixelBitStride + dataBitOffset) % dataElementSize;
+ }
+
+ @Override
+ public int[] getSampleSize() {
+ int sampleSizes[] = { pixelBitStride };
+ return sampleSizes;
+ }
+
+ /**
+ * Returns a hash code of this MultiPixelPackedSampleModel class.
+ *
+ * @return the hash code of this MultiPixelPackedSampleModel class.
+ */
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ int tmp = 0;
+
+ hash = width;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= height;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= numBands;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= dataType;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= scanlineStride;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= pixelBitStride;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= dataBitOffset;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= bitMask;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= dataElementSize;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= pixelsPerDataElement;
+ return hash;
+ }
+
+ @Override
+ public int getTransferType() {
+ if (pixelBitStride > 16) {
+ return DataBuffer.TYPE_INT;
+ } else if (pixelBitStride > 8) {
+ return DataBuffer.TYPE_USHORT;
+ } else {
+ return DataBuffer.TYPE_BYTE;
+ }
+ }
+
+ /**
+ * Gets the scanline stride of this MultiPixelPackedSampleModel.
+ *
+ * @return the scanline stride of this MultiPixelPackedSampleModel.
+ */
+ public int getScanlineStride() {
+ return scanlineStride;
+ }
+
+ /**
+ * Gets the pixel bit stride of this MultiPixelPackedSampleModel.
+ *
+ * @return the pixel bit stride of this MultiPixelPackedSampleModel.
+ */
+ public int getPixelBitStride() {
+ return pixelBitStride;
+ }
+
+ @Override
+ public int getNumDataElements() {
+ return 1;
+ }
+
+ /**
+ * Gets the data bit offset.
+ *
+ * @return the data bit offset.
+ */
+ public int getDataBitOffset() {
+ return dataBitOffset;
+ }
+
+ /**
+ * This method is used by other methods of this class. The behaviour of
+ * this method depends on the method which has been invoke this one. The
+ * argument methodId is used to choose valid behaviour in a particular case.
+ * If methodId is equal to 1 it means that this method has been invoked by
+ * the setDataElements() method, 2 - means setPixel(), and setSample() in
+ * any other cases.
+ *
+ * @param x the x
+ * @param y the y
+ * @param obj the obj
+ * @param data the data
+ * @param methodId the method id
+ * @param s the s
+ */
+ private void setSample(final int x, final int y, final Object obj,
+ final DataBuffer data, final int methodId, int s) {
+ if ((x < 0) || (y < 0) || (x >= this.width) || (y >= this.height)) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages
+ .getString("awt.63")); //$NON-NLS-1$
+ }
+
+ final int bitnum = dataBitOffset + x * pixelBitStride;
+ final int idx = y * scanlineStride + bitnum / dataElementSize;
+ final int shift = dataElementSize - (bitnum & (dataElementSize - 1))
+ - pixelBitStride;
+ final int mask = ~(bitMask << shift);
+ int elem = data.getElem(idx);
+
+ switch (methodId) {
+ case 1: { // Invoked from setDataElements()
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ s = ((byte[]) obj)[0] & 0xff;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ s = ((short[]) obj)[0] & 0xffff;
+ break;
+ case DataBuffer.TYPE_INT:
+ s = ((int[]) obj)[0];
+ break;
+ }
+ break;
+ }
+ case 2: { // Invoked from setPixel()
+ s = ((int[]) obj)[0];
+ break;
+ }
+ }
+
+ elem &= mask;
+ elem |= (s & bitMask) << shift;
+ data.setElem(idx, elem);
+ }
+}
+
diff --git a/awt/java/awt/image/PackedColorModel.java b/awt/java/awt/image/PackedColorModel.java
new file mode 100644
index 0000000..7aaefbf
--- /dev/null
+++ b/awt/java/awt/image/PackedColorModel.java
@@ -0,0 +1,383 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class PackedColorModel represents a color model where the
+ * components are just the red, green, and blue bands, plus an alpha
+ * band if alpha is supported.
+ */
+public abstract class PackedColorModel extends ColorModel {
+
+ /** The component masks. */
+ int componentMasks[];
+
+ /** The offsets. */
+ int offsets[];
+
+ /** The scales. */
+ float scales[];
+
+ /**
+ * Instantiates a new packed color model.
+ *
+ * @param space the color space
+ * @param bits the array of component masks
+ * @param colorMaskArray the array that gives the bitmask corresponding
+ * to each color band (red, green, and blue)
+ * @param alphaMask the bitmask corresponding to the alpha band
+ * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model
+ * @param trans the transparency strategy, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ *
+ * @throws IllegalArgumentException if the number of bits in the combined
+ * bitmasks for the color bands is less than one or greater than 32
+ */
+ public PackedColorModel(ColorSpace space, int bits, int colorMaskArray[],
+ int alphaMask, boolean isAlphaPremultiplied, int trans,
+ int transferType) {
+
+ super(bits, createBits(colorMaskArray, alphaMask), space,
+ (alphaMask == 0 ? false : true), isAlphaPremultiplied, trans,
+ validateTransferType(transferType));
+
+ if (pixel_bits < 1 || pixel_bits > 32) {
+ // awt.236=The bits is less than 1 or greater than 32
+ throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$
+ }
+
+ componentMasks = new int[numComponents];
+ for (int i = 0; i < numColorComponents; i++) {
+ componentMasks[i] = colorMaskArray[i];
+ }
+
+ if (hasAlpha) {
+ componentMasks[numColorComponents] = alphaMask;
+ if (this.bits[numColorComponents] == 1) {
+ transparency = Transparency.BITMASK;
+ }
+ }
+
+ parseComponents();
+ }
+
+ /**
+ * Instantiates a new packed color model.
+ *
+ * @param space the color space
+ * @param bits the array of component masks
+ * @param rmask the bitmask corresponding to the red band
+ * @param gmask the bitmask corresponding to the green band
+ * @param bmask the bitmask corresponding to the blue band
+ * @param amask the bitmask corresponding to the alpha band
+ * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model
+ * @param trans the transparency strategy, @see java.awt.Transparency
+ * @param transferType the transfer type (primitive java type
+ * to use for the components)
+ *
+ * @throws IllegalArgumentException if the number of bits in the combined
+ * bitmasks for the color bands is less than one or greater than 32
+ */
+ public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask,
+ int bmask, int amask, boolean isAlphaPremultiplied, int trans,
+ int transferType) {
+
+ super(bits, createBits(rmask, gmask, bmask, amask), space,
+ (amask == 0 ? false : true), isAlphaPremultiplied, trans,
+ validateTransferType(transferType));
+
+ if (pixel_bits < 1 || pixel_bits > 32) {
+ // awt.236=The bits is less than 1 or greater than 32
+ throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$
+ }
+
+ if (cs.getType() != ColorSpace.TYPE_RGB) {
+ // awt.239=The space is not a TYPE_RGB space
+ throw new IllegalArgumentException(Messages.getString("awt.239")); //$NON-NLS-1$
+ }
+
+ for (int i = 0; i < numColorComponents; i++) {
+ if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) {
+ // awt.23A=The min/max normalized component values are not 0.0/1.0
+ throw new IllegalArgumentException(Messages.getString("awt.23A")); //$NON-NLS-1$
+ }
+ }
+ componentMasks = new int[numComponents];
+ componentMasks[0] = rmask;
+ componentMasks[1] = gmask;
+ componentMasks[2] = bmask;
+
+ if (hasAlpha) {
+ componentMasks[3] = amask;
+ if (this.bits[3] == 1) {
+ transparency = Transparency.BITMASK;
+ }
+ }
+
+ parseComponents();
+ }
+
+ @Override
+ public WritableRaster getAlphaRaster(WritableRaster raster) {
+ if(!hasAlpha) {
+ return null;
+ }
+
+ int x = raster.getMinX();
+ int y = raster.getMinY();
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+ int band[] = new int[1];
+ band[0] = raster.getNumBands() - 1;
+ return raster.createWritableChild(x, y, w, h, x, y, band);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof PackedColorModel)) {
+ return false;
+ }
+ PackedColorModel cm = (PackedColorModel) obj;
+
+ return (pixel_bits == cm.getPixelSize() &&
+ transferType == cm.getTransferType() &&
+ cs.getType() == cm.getColorSpace().getType() &&
+ hasAlpha == cm.hasAlpha() &&
+ isAlphaPremultiplied == cm.isAlphaPremultiplied() &&
+ transparency == cm.getTransparency() &&
+ numColorComponents == cm.getNumColorComponents()&&
+ numComponents == cm.getNumComponents() &&
+ Arrays.equals(bits, cm.getComponentSize()) &&
+ Arrays.equals(componentMasks, cm.getMasks()));
+ }
+
+ @Override
+ public boolean isCompatibleSampleModel(SampleModel sm) {
+ if (sm == null) {
+ return false;
+ }
+ if (!(sm instanceof SinglePixelPackedSampleModel)) {
+ return false;
+ }
+ SinglePixelPackedSampleModel esm = (SinglePixelPackedSampleModel) sm;
+
+ return ((esm.getNumBands() == numComponents) &&
+ (esm.getTransferType() == transferType) &&
+ Arrays.equals(esm.getBitMasks(), componentMasks));
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ return new SinglePixelPackedSampleModel(transferType, w, h,
+ componentMasks);
+ }
+
+ /**
+ * Gets the bitmask corresponding to the specified color component.
+ *
+ * @param index the index of the desired color
+ *
+ * @return the mask
+ */
+ public final int getMask(int index) {
+ return componentMasks[index];
+ }
+
+ /**
+ * Gets the bitmasks of the components.
+ *
+ * @return the masks
+ */
+ public final int[] getMasks() {
+ return (componentMasks.clone());
+ }
+
+ /**
+ * Creates the bits.
+ *
+ * @param colorMaskArray the color mask array
+ * @param alphaMask the alpha mask
+ *
+ * @return the int[]
+ */
+ private static int[] createBits(int colorMaskArray[], int alphaMask) {
+ int bits[];
+ int numComp;
+ if (alphaMask == 0) {
+ numComp = colorMaskArray.length;
+ } else {
+ numComp = colorMaskArray.length + 1;
+ }
+
+ bits = new int[numComp];
+ int i = 0;
+ for (; i < colorMaskArray.length; i++) {
+ bits[i] = countCompBits(colorMaskArray[i]);
+ if (bits[i] < 0) {
+ // awt.23B=The mask of the {0} component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23B", i)); //$NON-NLS-1$
+ }
+ }
+
+ if (i < numComp) {
+ bits[i] = countCompBits(alphaMask);
+
+ if (bits[i] < 0) {
+ // awt.23C=The mask of the alpha component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$
+ }
+ }
+
+ return bits;
+ }
+
+ /**
+ * Creates the bits.
+ *
+ * @param rmask the rmask
+ * @param gmask the gmask
+ * @param bmask the bmask
+ * @param amask the amask
+ *
+ * @return the int[]
+ */
+ private static int[] createBits(int rmask, int gmask, int bmask,
+ int amask) {
+
+ int numComp;
+ if (amask == 0) {
+ numComp = 3;
+ } else {
+ numComp = 4;
+ }
+ int bits[] = new int[numComp];
+
+ bits[0] = countCompBits(rmask);
+ if (bits[0] < 0) {
+ // awt.23D=The mask of the red component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23D")); //$NON-NLS-1$
+ }
+
+ bits[1] = countCompBits(gmask);
+ if (bits[1] < 0) {
+ // awt.23E=The mask of the green component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23E")); //$NON-NLS-1$
+ }
+
+ bits[2] = countCompBits(bmask);
+ if (bits[2] < 0) {
+ // awt.23F=The mask of the blue component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23F")); //$NON-NLS-1$
+ }
+
+ if (amask != 0) {
+ bits[3] = countCompBits(amask);
+ if (bits[3] < 0) {
+ // awt.23C=The mask of the alpha component is not contiguous
+ throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$
+ }
+ }
+
+ return bits;
+ }
+
+ /**
+ * Count comp bits.
+ *
+ * @param compMask the comp mask
+ *
+ * @return the int
+ */
+ private static int countCompBits(int compMask) {
+ int bits = 0;
+ if (compMask != 0) {
+ // Deleting final zeros
+ while ((compMask & 1) == 0) {
+ compMask >>>= 1;
+ }
+ // Counting component bits
+ while ((compMask & 1) == 1) {
+ compMask >>>= 1;
+ bits++;
+ }
+ }
+
+ if (compMask != 0) {
+ return -1;
+ }
+
+ return bits;
+ }
+
+ /**
+ * Validate transfer type.
+ *
+ * @param transferType the transfer type
+ *
+ * @return the int
+ */
+ private static int validateTransferType(int transferType) {
+ if (transferType != DataBuffer.TYPE_BYTE &&
+ transferType != DataBuffer.TYPE_USHORT &&
+ transferType != DataBuffer.TYPE_INT) {
+ // awt.240=The transferType not is one of DataBuffer.TYPE_BYTE,
+ // DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT
+ throw new IllegalArgumentException(Messages.getString("awt.240")); //$NON-NLS-1$
+ }
+ return transferType;
+}
+
+ /**
+ * Parses the components.
+ */
+ private void parseComponents() {
+ offsets = new int[numComponents];
+ scales = new float[numComponents];
+ for (int i = 0; i < numComponents; i++) {
+ int off = 0;
+ int mask = componentMasks[i];
+ while ((mask & 1) == 0) {
+ mask >>>= 1;
+ off++;
+ }
+ offsets[i] = off;
+ if (bits[i] == 0) {
+ scales[i] = 256.0f; // May be any value different from zero,
+ // because will dividing by zero
+ } else {
+ scales[i] = 255.0f / maxValues[i];
+ }
+ }
+
+ }
+
+}
+
diff --git a/awt/java/awt/image/PixelGrabber.java b/awt/java/awt/image/PixelGrabber.java
new file mode 100644
index 0000000..cecd5c8
--- /dev/null
+++ b/awt/java/awt/image/PixelGrabber.java
@@ -0,0 +1,408 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Image;
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class PixelGrabber implements ImageConsumer {
+
+ int width;
+ int height;
+ int X;
+ int Y;
+ int offset;
+ int scanline;
+ ImageProducer producer;
+
+ byte bData[];
+ int iData[];
+ ColorModel cm;
+
+ private int grabberStatus;
+ private int dataType;
+ private boolean isGrabbing;
+ private boolean isRGB;
+
+
+ private static final int DATA_TYPE_BYTE = 0;
+ private static final int DATA_TYPE_INT = 1;
+ private static final int DATA_TYPE_UNDEFINED = 2;
+
+ private static final int ALL_BITS = (ImageObserver.FRAMEBITS |
+ ImageObserver.ALLBITS);
+
+ private static final int GRABBING_STOP = ALL_BITS | ImageObserver.ERROR;
+
+
+
+ public PixelGrabber(ImageProducer ip, int x, int y, int w, int h, int[] pix,
+ int off, int scansize) {
+ initialize(ip, x, y, w, h, pix, off, scansize, true);
+ }
+
+ public PixelGrabber(Image img, int x, int y, int w, int h, int[] pix,
+ int off, int scansize) {
+ initialize(img.getSource(), x, y, w, h, pix, off, scansize, true);
+ }
+
+ public PixelGrabber(Image img, int x, int y, int w, int h, boolean forceRGB) {
+ initialize(img.getSource(), x, y, w, h, null, 0, 0, forceRGB);
+ }
+
+ public void setProperties(Hashtable<?, ?> props) {
+ return;
+ }
+
+ public synchronized Object getPixels() {
+ switch(dataType){
+ case DATA_TYPE_BYTE:
+ return bData;
+ case DATA_TYPE_INT:
+ return iData;
+ default:
+ return null;
+ }
+ }
+
+ public void setColorModel(ColorModel model) {
+ return;
+ }
+
+ public void setPixels(int srcX, int srcY, int srcW, int srcH,
+ ColorModel model, byte[] pixels, int srcOff, int srcScan) {
+ if(srcY < Y){
+ int delta = Y - srcY;
+ if(delta >= height) {
+ return;
+ }
+ srcY += delta;
+ srcH -= delta;
+ srcOff += srcScan * delta;
+ }
+
+ if(srcY + srcH > Y + height){
+ srcH = Y + height - srcY;
+ if(srcH <= 0) {
+ return;
+ }
+ }
+
+ if(srcX < X){
+ int delta = X - srcX;
+ if(delta >= width) {
+ return;
+ }
+ srcW -= delta;
+ srcX += delta;
+ srcOff += delta;
+ }
+
+ if(srcX + srcW > X + width){
+ srcW = X + width - srcX;
+ if(srcW <= 0) {
+ return;
+ }
+ }
+ if(scanline == 0) {
+ scanline = width;
+ }
+ int realOff = offset + (srcY - Y) * scanline + (srcX - X);
+ switch(dataType){
+ case DATA_TYPE_UNDEFINED:
+ cm = model;
+ if(model != ColorModel.getRGBdefault()){
+ bData = new byte[width * height];
+ isRGB = false;
+ dataType = DATA_TYPE_BYTE;
+ }else{
+ iData = new int[width * height];
+ isRGB = true;
+ dataType = DATA_TYPE_INT;
+ }
+ case DATA_TYPE_BYTE:
+ if(!isRGB && cm == model){
+ for(int y = 0; y < srcH; y++){
+ System.arraycopy(pixels, srcOff, bData, realOff, srcW);
+ srcOff += srcScan;
+ realOff += scanline;
+ }
+ break;
+ }
+ forceToRGB();
+ case DATA_TYPE_INT:
+ for(int y = 0; y < srcH; y++){
+ for(int x = 0; x < srcW; x++){
+ iData[realOff + x] = cm.getRGB(pixels[srcOff + x] & 0xff);
+ }
+ srcOff += srcScan;
+ realOff += scanline;
+ }
+ }
+
+ return;
+ }
+
+ public void setPixels(int srcX, int srcY, int srcW, int srcH,
+ ColorModel model, int[] pixels, int srcOff, int srcScan) {
+
+ if(srcY < Y){
+ int delta = Y - srcY;
+ if(delta >= height) {
+ return;
+ }
+ srcY += delta;
+ srcH -= delta;
+ srcOff += srcScan * delta;
+ }
+
+ if(srcY + srcH > Y + height){
+ srcH = Y + height - srcY;
+ if(srcH <= 0) {
+ return;
+ }
+ }
+
+ if(srcX < X){
+ int delta = X - srcX;
+ if(delta >= width) {
+ return;
+ }
+ srcW -= delta;
+ srcX += delta;
+ srcOff += delta;
+ }
+
+ if(srcX + srcW > X + width){
+ srcW = X + width - srcX;
+ if(srcW <= 0) {
+ return;
+ }
+ }
+ if(scanline == 0) {
+ scanline = width;
+ }
+ int realOff = offset + (srcY - Y) * scanline + (srcX - X);
+
+ int mask = 0xFF;
+
+ switch(dataType){
+ case DATA_TYPE_UNDEFINED:
+ cm = model;
+ iData = new int[width * height];
+ dataType = DATA_TYPE_INT;
+ isRGB = (cm == ColorModel.getRGBdefault());
+
+ case DATA_TYPE_INT:
+ if(cm == model){
+ for(int y = 0; y < srcH; y++){
+ System.arraycopy(pixels, srcOff, iData, realOff, srcW);
+ srcOff += srcScan;
+ realOff += scanline;
+ }
+ break;
+ }
+ mask = 0xFFFFFFFF;
+
+ case DATA_TYPE_BYTE:
+ forceToRGB();
+ for(int y = 0; y < srcH; y++){
+ for(int x = 0; x < srcW; x++){
+ iData[realOff+x] = cm.getRGB(pixels[srcOff+x] & mask);
+ }
+ srcOff += srcScan;
+ realOff += scanline;
+ }
+ }
+ }
+
+ public synchronized ColorModel getColorModel() {
+ return cm;
+ }
+
+ public synchronized boolean grabPixels(long ms)
+ throws InterruptedException {
+ if((grabberStatus & GRABBING_STOP) != 0){
+ return ((grabberStatus & ALL_BITS) != 0);
+ }
+
+ long start = System.currentTimeMillis();
+
+ if(!isGrabbing){
+ isGrabbing = true;
+ grabberStatus &= ~ImageObserver.ABORT;
+ producer.startProduction(this);
+ }
+ while((grabberStatus & GRABBING_STOP) == 0){
+ if(ms != 0){
+ ms = start + ms - System.currentTimeMillis();
+ if(ms <= 0) {
+ break;
+ }
+ }
+ wait(ms);
+ }
+
+ return ((grabberStatus & ALL_BITS) != 0);
+ }
+
+ public void setDimensions(int w, int h) {
+ if(width < 0) {
+ width = w - X;
+ }
+ if(height < 0) {
+ height = h - Y;
+ }
+
+ grabberStatus |= ImageObserver.WIDTH | ImageObserver.HEIGHT;
+
+ if(width <=0 || height <=0){
+ imageComplete(STATICIMAGEDONE);
+ return;
+ }
+
+ if(isRGB && dataType == DATA_TYPE_UNDEFINED){
+ iData = new int[width * height];
+ dataType = DATA_TYPE_INT;
+ scanline = width;
+ }
+ }
+
+ public void setHints(int hints) {
+ return;
+ }
+
+ public synchronized void imageComplete(int status) {
+ switch(status){
+ case IMAGEABORTED:
+ grabberStatus |= ImageObserver.ABORT;
+ break;
+ case IMAGEERROR:
+ grabberStatus |= ImageObserver.ERROR | ImageObserver.ABORT;
+ break;
+ case SINGLEFRAMEDONE:
+ grabberStatus |= ImageObserver.FRAMEBITS;
+ break;
+ case STATICIMAGEDONE:
+ grabberStatus |= ImageObserver.ALLBITS;
+ break;
+ default:
+ // awt.26A=Incorrect ImageConsumer completion status
+ throw new IllegalArgumentException(Messages.getString("awt.26A")); //$NON-NLS-1$
+ }
+ isGrabbing = false;
+ producer.removeConsumer(this);
+ notifyAll();
+ }
+
+ public boolean grabPixels() throws InterruptedException {
+ return grabPixels(0);
+ }
+
+ public synchronized void startGrabbing() {
+ if((grabberStatus & GRABBING_STOP) != 0){
+ return;
+ }
+ if(!isGrabbing){
+ isGrabbing = true;
+ grabberStatus &= ~ImageObserver.ABORT;
+ producer.startProduction(this);
+ }
+ }
+
+ public synchronized void abortGrabbing() {
+ imageComplete(IMAGEABORTED);
+ }
+
+ public synchronized int status() {
+ return grabberStatus;
+ }
+
+ public synchronized int getWidth() {
+ if(width < 0) {
+ return -1;
+ }
+ return width;
+ }
+
+ public synchronized int getStatus() {
+ return grabberStatus;
+ }
+
+ public synchronized int getHeight() {
+ if(height < 0) {
+ return -1;
+ }
+ return height;
+ }
+
+ private void initialize(ImageProducer ip, int x, int y, int w, int h,
+ int pixels[], int off, int scansize, boolean forceRGB){
+
+ producer = ip;
+ X = x;
+ Y = y;
+ width = w;
+ height = h;
+ iData = pixels;
+ dataType = (pixels == null) ? DATA_TYPE_UNDEFINED : DATA_TYPE_INT;
+ offset = off;
+ scanline = scansize;
+ if(forceRGB){
+ cm = ColorModel.getRGBdefault();
+ isRGB = true;
+ }
+ }
+
+ /**
+ * Force pixels to INT RGB mode
+ */
+ private void forceToRGB(){
+ if (isRGB)
+ return;
+
+ switch(dataType){
+ case DATA_TYPE_BYTE:
+ iData = new int[width * height];
+ for(int i = 0; i < iData.length; i++){
+ iData[i] = cm.getRGB(bData[i] & 0xff);
+ }
+ dataType = DATA_TYPE_INT;
+ bData = null;
+ break;
+
+ case DATA_TYPE_INT:
+ int buff[] = new int[width * height];
+ for(int i = 0; i < iData.length; i++){
+ buff[i] = cm.getRGB(iData[i]);
+ }
+ iData = buff;
+ break;
+ }
+ offset = 0;
+ scanline = width;
+ cm = ColorModel.getRGBdefault();
+ isRGB = true;
+ }
+
+}
diff --git a/awt/java/awt/image/PixelInterleavedSampleModel.java b/awt/java/awt/image/PixelInterleavedSampleModel.java
new file mode 100644
index 0000000..e41473e
--- /dev/null
+++ b/awt/java/awt/image/PixelInterleavedSampleModel.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The PixelInterleavedSampleModel class represents image data
+ * as represented as interleaved pixels and for which each sample of
+ * a pixel takes one data element of the DataBuffer.
+ */
+public class PixelInterleavedSampleModel extends ComponentSampleModel {
+
+ /**
+ * Instantiates a new PixelInterleavedSampleModel with the
+ * specified parameters.
+ *
+ * @param dataType the data type of the samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param pixelStride the pixel stride of the image data.
+ * @param scanlineStride the scanline stride of the of the image data.
+ * @param bandOffsets the array of the band offsets.
+ */
+ public PixelInterleavedSampleModel(int dataType, int w, int h,
+ int pixelStride, int scanlineStride, int bandOffsets[]) {
+
+ super(dataType, w, h, pixelStride, scanlineStride, bandOffsets);
+
+ int maxOffset = bandOffsets[0];
+ int minOffset = bandOffsets[0];
+ for (int i = 1; i < bandOffsets.length; i++) {
+ if (bandOffsets[i] > maxOffset) {
+ maxOffset = bandOffsets[i];
+ }
+ if (bandOffsets[i] < minOffset) {
+ minOffset = bandOffsets[i];
+ }
+ }
+
+ maxOffset -= minOffset;
+
+ if (maxOffset > scanlineStride) {
+ // awt.241=Any offset between bands is greater than the Scanline stride
+ throw new IllegalArgumentException(Messages.getString("awt.241")); //$NON-NLS-1$
+ }
+
+ if (maxOffset > pixelStride) {
+ // awt.242=Pixel stride is less than any offset between bands
+ throw new IllegalArgumentException(Messages.getString("awt.242")); //$NON-NLS-1$
+ }
+
+ if (pixelStride * w > scanlineStride) {
+ // awt.243=Product of Pixel stride and w is greater than Scanline stride
+ throw new IllegalArgumentException(Messages.getString("awt.243")); //$NON-NLS-1$
+ }
+
+ }
+
+ @Override
+ public SampleModel createSubsetSampleModel(int bands[]) {
+ int newOffsets[] = new int[bands.length];
+ for (int i = 0; i < bands.length; i++) {
+ newOffsets[i] = bandOffsets[bands[i]];
+ }
+
+ return new PixelInterleavedSampleModel(dataType, width, height,
+ pixelStride, scanlineStride, newOffsets);
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ int newOffsets[];
+ int minOffset = bandOffsets[0];
+
+ for (int i = 1; i < numBands; i++) {
+ if (bandOffsets[i] < minOffset) {
+ minOffset = bandOffsets[i];
+ }
+ }
+
+ if (minOffset > 0) {
+ newOffsets = new int[numBands];
+ for (int i = 0; i < numBands; i++) {
+ newOffsets[i] = bandOffsets[i] - minOffset;
+ }
+ } else {
+ newOffsets = bandOffsets;
+ }
+
+ return new PixelInterleavedSampleModel(dataType, w, h, pixelStride,
+ pixelStride * w, newOffsets);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = super.hashCode();
+ int tmp = hash >>> 8;
+ hash <<= 8;
+ hash |= tmp;
+
+ return hash ^ 0x66;
+ }
+
+}
+
diff --git a/awt/java/awt/image/RGBImageFilter.java b/awt/java/awt/image/RGBImageFilter.java
new file mode 100644
index 0000000..9a76997
--- /dev/null
+++ b/awt/java/awt/image/RGBImageFilter.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+
+/**
+ * The RGBImageFilter class represents a filter which modifies
+ * pixels of an image in the default RGB ColorModel.
+ */
+public abstract class RGBImageFilter extends ImageFilter {
+
+ /**
+ * The origmodel is the ColorModel to be replaced by newmodel
+ * when substituteColorModel is called.
+ */
+ protected ColorModel origmodel;
+
+ /**
+ * The newmodel is the ColorModel with which to replace origmodel
+ * when substituteColorModel is called.
+ */
+ protected ColorModel newmodel;
+
+ /**
+ * The canFilterIndexColorModel indicates if it is
+ * acceptable to apply the color filtering of the filterRGB
+ * method to the color table entries of an IndexColorModel
+ * object.
+ * */
+ protected boolean canFilterIndexColorModel;
+
+ /**
+ * Instantiates a new RGBImageFilter.
+ */
+ public RGBImageFilter() {}
+
+ /**
+ * Filters an IndexColorModel object by calling filterRGB function for
+ * each entry of IndexColorModel.
+ *
+ * @param icm the IndexColorModel to be filtered.
+ *
+ * @return the IndexColorModel.
+ */
+ public IndexColorModel filterIndexColorModel(IndexColorModel icm) {
+ int transferType = icm.getTransferType();
+ int bits = icm.getPixelSize();
+ int mapSize = icm.getMapSize();
+ int colorMap[] = new int[mapSize];
+ int filteredColorMap[] = new int[mapSize];
+ icm.getRGBs(colorMap);
+ int trans = -1;
+ boolean hasAlpha = false;
+ for(int i = 0; i < mapSize; i++){
+ filteredColorMap[i] = filterRGB(-1, -1, colorMap[i]);
+ int alpha = filteredColorMap[i] >>> 24;
+ if(alpha != 0xff){
+ if(!hasAlpha) {
+ hasAlpha = true;
+ }
+ if(alpha == 0 && trans < 0) {
+ trans = i;
+ }
+ }
+ }
+
+ return new IndexColorModel(bits, mapSize, filteredColorMap, 0,
+ hasAlpha, trans, transferType);
+ }
+
+ /**
+ * Replaces the original color model and the new one.
+ *
+ * @param oldcm the old ColorModel.
+ * @param newcm the new ColorModel.
+ */
+ public void substituteColorModel(ColorModel oldcm, ColorModel newcm) {
+ origmodel = oldcm;
+ newmodel = newcm;
+ }
+
+ @Override
+ public void setColorModel(ColorModel model) {
+ if(model instanceof IndexColorModel &&
+ canFilterIndexColorModel){
+ IndexColorModel icm = (IndexColorModel) model;
+ ColorModel filteredModel = filterIndexColorModel(icm);
+ substituteColorModel(model, filteredModel);
+ consumer.setColorModel(filteredModel);
+ }else{
+ consumer.setColorModel(ColorModel.getRGBdefault());
+ }
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ int[] pixels, int off, int scansize) {
+
+ if(model == null || model == origmodel){
+ consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
+ }else{
+ int rgbPixels[] = new int[w];
+ for(int sy = y, pixelsOff = off; sy < y + h;
+ sy++, pixelsOff += scansize){
+
+ for(int sx = x, idx = 0; sx < x + w; sx++, idx++){
+ rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx]);
+ }
+ filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w);
+ }
+ }
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ byte[] pixels, int off, int scansize) {
+
+ if(model == null || model == origmodel){
+ consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
+ }else{
+ int rgbPixels[] = new int[w];
+ for(int sy = y, pixelsOff = off; sy < y + h;
+ sy++, pixelsOff += scansize){
+
+ for(int sx = x, idx = 0; sx < x + w; sx++, idx++){
+ rgbPixels[idx] =
+ model.getRGB(pixels[pixelsOff + idx] & 0xff);
+ }
+ filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w);
+ }
+ }
+ }
+
+ /**
+ * Filters a region of pixels in the default RGB ColorModel
+ * by calling the filterRGB method for them.
+ *
+ * @param x the X coordinate of region.
+ * @param y the Y coordinate of region.
+ * @param w the width ofregion.
+ * @param h the height of region.
+ * @param pixels the pixels array.
+ * @param off the offset of array.
+ * @param scansize the distance between rows of pixels in the array.
+ */
+ public void filterRGBPixels(int x, int y, int w, int h,
+ int[] pixels, int off, int scansize) {
+
+ for(int sy = y, lineOff = off; sy < y + h; sy++, lineOff += scansize){
+ for(int sx = x, idx = 0; sx < x + w; sx++, idx++){
+ pixels[lineOff + idx] =
+ filterRGB(sx, sy, pixels[lineOff + idx]);
+ }
+ }
+ consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(),
+ pixels, off, scansize);
+ }
+
+ /**
+ * Coverts a single input pixel in the default RGB ColorModel
+ * to a single output pixel.
+ *
+ * @param x the X pixel's coordinate.
+ * @param y the Y pixel's coordinate.
+ * @param rgb a pixel in the default RGB color model.
+ *
+ * @return a filtered pixel in the default RGB color model.
+ */
+ public abstract int filterRGB(int x, int y, int rgb);
+
+}
+
diff --git a/awt/java/awt/image/Raster.java b/awt/java/awt/image/Raster.java
new file mode 100644
index 0000000..4b2426e
--- /dev/null
+++ b/awt/java/awt/image/Raster.java
@@ -0,0 +1,1412 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.gl.image.OrdinaryWritableRaster;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Raster class represents a rectangular area of pixels.
+ * This class is defined by DataBuffer and SampleModel objects.
+ * The DataBuffer object stores sample values and DSampleModel defines
+ * the location of sample in this DataBuffer.
+ */
+public class Raster {
+
+ /** The DataBuffer of this Raster. */
+ protected DataBuffer dataBuffer;
+
+ /** The height of this Raster. */
+ protected int height;
+
+ /** The X coordinate of the upper left pixel in this Raster. */
+ protected int minX;
+
+ /** The Y coordinate of the upper left pixel in this Raster. */
+ protected int minY;
+
+ /** The number of bands in this Raster. */
+ protected int numBands;
+
+ /** The number of data elements. */
+ protected int numDataElements;
+
+ /** The parent of this Raster. */
+ protected Raster parent;
+
+ /** The SampleModel of this Raster. */
+ protected SampleModel sampleModel;
+
+ /**
+ * The X translation from the coordinate space of the
+ * SampleModel of this Raster.
+ */
+ protected int sampleModelTranslateX;
+
+ /**
+ * The Y translation from the coordinate space of the
+ * SampleModel of this Raster.
+ */
+ protected int sampleModelTranslateY;
+
+ /** The width of this Raster. */
+ protected int width;
+
+ /**
+ * Creates a Raster object with a BandedSampleModel and the specified
+ * DataBuffer. The number of bands is defined by the length of bandOffsets
+ * or bankIndices arrays.
+ *
+ * @param dataBuffer the specified DataBuffer.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bankIndices the bank indices of bands.
+ * @param bandOffsets the band offsets of bands.
+ * @param location the location which defines the upper left corner
+ * of Raster.
+ *
+ * @return the WritableRaster object.
+ */
+ public static WritableRaster createBandedRaster(DataBuffer dataBuffer,
+ int w, int h, int scanlineStride, int bankIndices[],
+ int bandOffsets[], Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bankIndices == null || bandOffsets == null) {
+ // awt.277=bankIndices or bandOffsets is null
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer == null) {
+ // awt.278=dataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+ }
+
+ int dataType = dataBuffer.getDataType();
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ BandedSampleModel sampleModel = new BandedSampleModel(dataType, w, h,
+ scanlineStride, bankIndices, bandOffsets);
+
+ return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+ }
+
+ /**
+ * Creates a Raster object with a BandedSampleModel and the specified
+ * data type. The Data type can be one of the following values:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ *
+ * @param dataType the data type of the samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param bankIndices the bank indices of bands.
+ * @param bandOffsets the band offsets of bands.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster object.
+ */
+ public static WritableRaster createBandedRaster(int dataType, int w, int h,
+ int scanlineStride, int bankIndices[], int bandOffsets[],
+ Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bankIndices == null || bandOffsets == null) {
+ // awt.277=bankIndices or bandOffsets is null
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$
+ }
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ int maxOffset = bandOffsets[0];
+ int maxBank = bankIndices[0];
+
+ for (int i = 0; i < bankIndices.length; i++) {
+ if (bandOffsets[i] > maxOffset) {
+ maxOffset = bandOffsets[i];
+ }
+ if (bankIndices[i] > maxBank) {
+ maxBank = bankIndices[i];
+ }
+ }
+
+ int numBanks = maxBank + 1;
+ int dataSize = scanlineStride * (h - 1) + w + maxOffset;
+
+ DataBuffer data = null;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(dataSize, numBanks);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(dataSize, numBanks);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(dataSize, numBanks);
+ break;
+ }
+ return createBandedRaster(data, w, h, scanlineStride, bankIndices,
+ bandOffsets, location);
+ }
+
+ /**
+ * Creates a Raster object with a BandedSampleModel and the specified
+ * data type. The Data type can be one of the following values:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ *
+ * @param dataType the data type of the samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bands the number of bands.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster object.
+ */
+ public static WritableRaster createBandedRaster(int dataType, int w, int h,
+ int bands, Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bands < 1) {
+ // awt.279=bands is less than 1
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.279")); //$NON-NLS-1$
+ }
+
+ int bandOffsets[] = new int[bands];
+ int bankIndices[] = new int[bands];
+
+ for (int i = 0; i < bands; i++) {
+ bandOffsets[i] = 0;
+ bankIndices[i] = i;
+ }
+ return createBandedRaster(dataType, w, h, w, bankIndices, bandOffsets,
+ location);
+ }
+
+ /**
+ * Creates a Raster object with a PixelInterleavedSampleModel
+ * and the specified DataBuffer.
+ *
+ * @param dataBuffer the DataBuffer.
+ * @param w the width of image data.
+ * @param h the height of image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param pixelStride the pixel stride of image data.
+ * @param bandOffsets the band offsets of bands.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster object.
+ */
+ public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer,
+ int w, int h, int scanlineStride, int pixelStride,
+ int bandOffsets[], Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer == null) {
+ // awt.278=dataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+ }
+
+ int dataType = dataBuffer.getDataType();
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer.getNumBanks() > 1) {
+ // awt.27A=dataBuffer has more than one bank
+ throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$
+ }
+
+ if (bandOffsets == null) {
+ // awt.27B=bandOffsets is null
+ throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$
+ }
+
+ PixelInterleavedSampleModel sampleModel =
+ new PixelInterleavedSampleModel(dataType, w, h,
+ pixelStride, scanlineStride, bandOffsets);
+
+ return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+
+ }
+
+ /**
+ * Creates a Raster object with a PixelInterleavedSampleModel
+ * and the specified data type. The Data type can be one of the
+ * following values:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ *
+ * @param dataType the data type of the samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of image data.
+ * @param h the height of image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param pixelStride the pixel stride of image data.
+ * @param bandOffsets the band offsets of bands.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster object.
+ */
+ public static WritableRaster createInterleavedRaster(int dataType, int w,
+ int h, int scanlineStride, int pixelStride, int bandOffsets[],
+ Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ if (bandOffsets == null) {
+ // awt.27B=bandOffsets is null
+ throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$
+ }
+
+ int minOffset = bandOffsets[0];
+ for (int i = 1; i < bandOffsets.length; i++) {
+ if (bandOffsets[i] < minOffset) {
+ minOffset = bandOffsets[i];
+ }
+ }
+ int size = (h - 1) * scanlineStride + w * pixelStride + minOffset;
+ DataBuffer data = null;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(size);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(size);
+ break;
+ }
+
+ return createInterleavedRaster(data, w, h, scanlineStride, pixelStride,
+ bandOffsets, location);
+ }
+
+ /**
+ * Creates a Raster object with a PixelInterleavedSampleModel
+ * and the specified data type. The Data type can be one of the
+ * following values:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ *
+ * @param dataType the data type of samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of image data.
+ * @param h the height of image data.
+ * @param bands the number of bands.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createInterleavedRaster(int dataType, int w,
+ int h, int bands, Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ int bandOffsets[] = new int[bands];
+ for (int i = 0; i < bands; i++) {
+ bandOffsets[i] = i;
+ }
+
+ return createInterleavedRaster(dataType, w, h, w * bands, bands,
+ bandOffsets, location);
+ }
+
+ /**
+ * Creates a Raster object with a SinglePixelPackedSampleModel
+ * and the specified DataBuffer.
+ *
+ * @param dataBuffer the DataBuffer.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param scanlineStride the scanline stride of the image data.
+ * @param bandMasks the band masks.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createPackedRaster(DataBuffer dataBuffer,
+ int w, int h, int scanlineStride, int bandMasks[], Point location) {
+ if (dataBuffer == null) {
+ // awt.278=dataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+ }
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bandMasks == null) {
+ // awt.27C=bandMasks is null
+ throw new RasterFormatException(Messages.getString("awt.27C")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer.getNumBanks() > 1) {
+ // awt.27A=dataBuffer has more than one bank
+ throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$
+ }
+
+ int dataType = dataBuffer.getDataType();
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ SinglePixelPackedSampleModel sampleModel =
+ new SinglePixelPackedSampleModel(dataType, w, h,
+ scanlineStride, bandMasks);
+
+ return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+ }
+
+ /**
+ * Creates a Raster object with a MultiPixelPackedSampleModel
+ * and the specified DataBuffer.
+ *
+ * @param dataBuffer the DataBuffer.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bitsPerPixel the number of bits per pixel.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createPackedRaster(DataBuffer dataBuffer,
+ int w, int h, int bitsPerPixel, Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer == null) {
+ // awt.278=dataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$
+ }
+
+ if (dataBuffer.getNumBanks() > 1) {
+ // awt.27A=dataBuffer has more than one bank
+ throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$
+ }
+
+ int dataType = dataBuffer.getDataType();
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ MultiPixelPackedSampleModel sampleModel =
+ new MultiPixelPackedSampleModel(dataType, w, h, bitsPerPixel);
+
+ return new OrdinaryWritableRaster(sampleModel, dataBuffer, location);
+
+ }
+
+ /**
+ * Creates a Raster object with a MultiPixelPackedSampleModel
+ * and the specified DataBuffer.
+ *
+ * @param dataType the data type of samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bands the number of bands.
+ * @param bitsPerBand the number of bits per band.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createPackedRaster(int dataType, int w, int h,
+ int bands, int bitsPerBand, Point location) {
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bands < 1 || bitsPerBand < 1) {
+ // awt.27D=bitsPerBand or bands is not greater than zero
+ throw new IllegalArgumentException(Messages.getString("awt.27D")); //$NON-NLS-1$
+ }
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ if (bitsPerBand * bands > DataBuffer.getDataTypeSize(dataType)) {
+ // awt.27E=The product of bitsPerBand and bands is greater than the number of bits held by dataType
+ throw new IllegalArgumentException(Messages.getString("awt.27E")); //$NON-NLS-1$
+ }
+
+ if (bands > 1) {
+
+ int bandMasks[] = new int[bands];
+ int mask = (1 << bitsPerBand) - 1;
+
+ for (int i = 0; i < bands; i++) {
+ bandMasks[i] = mask << (bitsPerBand * (bands - 1 - i));
+ }
+
+ return createPackedRaster(dataType, w, h, bandMasks, location);
+ }
+ DataBuffer data = null;
+ int size = ((bitsPerBand * w +
+ DataBuffer.getDataTypeSize(dataType) - 1) /
+ DataBuffer.getDataTypeSize(dataType)) * h;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(size);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(size);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(size);
+ break;
+ }
+ return createPackedRaster(data, w, h, bitsPerBand, location);
+ }
+
+ /**
+ * Creates a Raster object with a SinglePixelPackedSampleModel
+ * and the specified DataBuffer.
+ *
+ * @param dataType the data type of samples:
+ * TYPE_BYTE, TYPE_USHORT, or TYPE_INT.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bandMasks the band masks.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createPackedRaster(int dataType, int w, int h,
+ int bandMasks[], Point location) {
+
+ if (dataType != DataBuffer.TYPE_BYTE
+ && dataType != DataBuffer.TYPE_USHORT
+ && dataType != DataBuffer.TYPE_INT) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ if ((long) location.x + w > Integer.MAX_VALUE
+ || (long) location.y + h > Integer.MAX_VALUE) {
+ // awt.276=location.x + w or location.y + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$
+ }
+
+ if (bandMasks == null) {
+ // awt.27C=bandMasks is null
+ throw new NullPointerException(Messages.getString("awt.27C")); //$NON-NLS-1$
+ }
+
+ DataBuffer data = null;
+
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(w * h);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(w * h);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(w * h);
+ break;
+ }
+
+ return createPackedRaster(data, w, h, w, bandMasks, location);
+ }
+
+ /**
+ * Creates a Raster object with the specified DataBuffer and SampleModel.
+ *
+ * @param sm the specified SampleModel.
+ * @param db the specified DataBuffer.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the Raster.
+ */
+ public static Raster createRaster(SampleModel sm, DataBuffer db,
+ Point location) {
+
+ if (sm == null || db == null) {
+ // awt.27F=SampleModel or DataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ return new Raster(sm, db, location);
+ }
+
+ /**
+ * Creates a WritableRaster with the specified SampleModel and DataBuffer.
+ *
+ * @param sm the specified SampleModel.
+ * @param db the specified DataBuffer.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createWritableRaster(SampleModel sm,
+ DataBuffer db, Point location) {
+
+ if (sm == null || db == null) {
+ // awt.27F=SampleModel or DataBuffer is null
+ throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ return new OrdinaryWritableRaster(sm, db, location);
+ }
+
+ /**
+ * Creates a WritableRaster with the specified SampleModel.
+ *
+ * @param sm the specified SampleModel.
+ * @param location the location which defines the upper left corner
+ * of the Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public static WritableRaster createWritableRaster(SampleModel sm,
+ Point location) {
+
+ if (sm == null) {
+ // awt.280=SampleModel is null
+ throw new NullPointerException(Messages.getString("awt.280")); //$NON-NLS-1$
+ }
+
+ if (location == null) {
+ location = new Point(0, 0);
+ }
+
+ return createWritableRaster(sm, sm.createDataBuffer(), location);
+ }
+
+ /**
+ * Instantiates a new Raster object with the specified SampleModel and
+ * DataBuffer.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param dataBuffer the specified DataBuffer.
+ * @param origin the specified origin.
+ */
+ protected Raster(SampleModel sampleModel, DataBuffer dataBuffer,
+ Point origin) {
+
+ this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y,
+ sampleModel.getWidth(), sampleModel.getHeight()), origin, null);
+ }
+
+ /**
+ * Instantiates a new Raster object with the specified SampleModel,
+ * DataBuffer, rectangular region and parent Raster.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param dataBuffer the specified DataBuffer.
+ * @param aRegion the a rectangular region which defines the new image bounds.
+ * @param sampleModelTranslate this point defines the translation point
+ * from the SampleModel coordinates to the new Raster coordinates.
+ * @param parent the parent of this Raster.
+ */
+ protected Raster(SampleModel sampleModel, DataBuffer dataBuffer,
+ Rectangle aRegion, Point sampleModelTranslate, Raster parent) {
+
+ if (sampleModel == null || dataBuffer == null || aRegion == null
+ || sampleModelTranslate == null) {
+ // awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate is null
+ throw new NullPointerException(Messages.getString("awt.281")); //$NON-NLS-1$
+ }
+
+ if (aRegion.width <= 0 || aRegion.height <= 0) {
+ // awt.282=aRegion has width or height less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.282")); //$NON-NLS-1$
+ }
+
+ if ((long) aRegion.x + (long) aRegion.width > Integer.MAX_VALUE) {
+ // awt.283=Overflow X coordinate of Raster
+ throw new RasterFormatException(Messages.getString("awt.283")); //$NON-NLS-1$
+ }
+
+ if ((long) aRegion.y + (long) aRegion.height > Integer.MAX_VALUE) {
+ // awt.284=Overflow Y coordinate of Raster
+ throw new RasterFormatException(Messages.getString("awt.284")); //$NON-NLS-1$
+ }
+
+ if (sampleModel instanceof ComponentSampleModel) {
+ validateDataBuffer(dataBuffer, aRegion.width, aRegion.height,
+ ((ComponentSampleModel) sampleModel).getScanlineStride());
+ } else if (sampleModel instanceof MultiPixelPackedSampleModel) {
+ validateDataBuffer(dataBuffer, aRegion.width, aRegion.height,
+ ((MultiPixelPackedSampleModel) sampleModel)
+ .getScanlineStride());
+ } else if (sampleModel instanceof SinglePixelPackedSampleModel) {
+ validateDataBuffer(dataBuffer, aRegion.width, aRegion.height,
+ ((SinglePixelPackedSampleModel) sampleModel)
+ .getScanlineStride());
+ }
+
+ this.sampleModel = sampleModel;
+ this.dataBuffer = dataBuffer;
+ this.minX = aRegion.x;
+ this.minY = aRegion.y;
+ this.width = aRegion.width;
+ this.height = aRegion.height;
+ this.sampleModelTranslateX = sampleModelTranslate.x;
+ this.sampleModelTranslateY = sampleModelTranslate.y;
+ this.parent = parent;
+ this.numBands = sampleModel.getNumBands();
+ this.numDataElements = sampleModel.getNumDataElements();
+
+ }
+
+ /**
+ * Instantiates a new Raster with the specified SampleModel.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param origin the origin.
+ */
+ protected Raster(SampleModel sampleModel, Point origin) {
+ this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(
+ origin.x, origin.y, sampleModel.getWidth(), sampleModel
+ .getHeight()), origin, null);
+ }
+
+ /**
+ * Creates the child of this Raster by sharing the specified rectangular
+ * area in this Raste. The parentX, parentY, width
+ * and height parameters specify the rectangular area to be shared.
+ *
+ * @param parentX the X coordinate of the upper left corner of this Raster.
+ * @param parentY the Y coordinate of the upper left corner of this Raster.
+ * @param width the width of the child area.
+ * @param height the height of the child area.
+ * @param childMinX the X coordinate of child area mapped to the parentX
+ * coordinate.
+ * @param childMinY the Y coordinate of child area mapped to the parentY
+ * coordinate.
+ * @param bandList the array of band indicies.
+ *
+ * @return the Raster.
+ */
+ public Raster createChild(int parentX, int parentY, int width, int height,
+ int childMinX, int childMinY, int bandList[]) {
+ if (width <= 0 || height <= 0) {
+ // awt.285=Width or Height of child Raster is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.285")); //$NON-NLS-1$
+ }
+
+ if (parentX < this.minX || parentX + width > this.minX + this.width) {
+ // awt.286=parentX disposes outside Raster
+ throw new RasterFormatException(Messages.getString("awt.286")); //$NON-NLS-1$
+ }
+
+ if (parentY < this.minY || parentY + height > this.minY + this.height) {
+ // awt.287=parentY disposes outside Raster
+ throw new RasterFormatException(Messages.getString("awt.287")); //$NON-NLS-1$
+ }
+
+ if ((long) parentX + width > Integer.MAX_VALUE) {
+ // awt.288=parentX + width results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.288")); //$NON-NLS-1$
+ }
+
+ if ((long) parentY + height > Integer.MAX_VALUE) {
+ // awt.289=parentY + height results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.289")); //$NON-NLS-1$
+ }
+
+ if ((long) childMinX + width > Integer.MAX_VALUE) {
+ // awt.28A=childMinX + width results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.28A")); //$NON-NLS-1$
+ }
+
+ if ((long) childMinY + height > Integer.MAX_VALUE) {
+ // awt.28B=childMinY + height results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.28B")); //$NON-NLS-1$
+ }
+
+ SampleModel childModel;
+
+ if (bandList == null) {
+ childModel = sampleModel;
+ } else {
+ childModel = sampleModel.createSubsetSampleModel(bandList);
+ }
+
+ int childTranslateX = childMinX - parentX;
+ int childTranslateY = childMinY - parentY;
+
+ return new Raster(childModel, dataBuffer, new Rectangle(childMinX,
+ childMinY, width, height), new Point(childTranslateX
+ + sampleModelTranslateX, childTranslateY
+ + sampleModelTranslateY), this);
+ }
+
+ /**
+ * Create a compatible WritableRaster with the same parameters
+ * as this Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createCompatibleWritableRaster() {
+ return new OrdinaryWritableRaster(sampleModel, new Point(0, 0));
+ }
+
+ /**
+ * Create a compatible WritableRaster with the same parameters
+ * as this Raster and the specified size.
+ *
+ * @param w the width of the new WritableRaster.
+ * @param h the height of the new WritableRaster.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createCompatibleWritableRaster(int w, int h) {
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ SampleModel sm = sampleModel.createCompatibleSampleModel(w, h);
+
+ return new OrdinaryWritableRaster(sm, new Point(0, 0));
+ }
+
+ /**
+ * Create a compatible WritableRaster with the same parameters
+ * as this Raster and the specified size and location.
+ *
+ * @param x the X coordinate of the new WritableRaster.
+ * @param y the Y coordinate of the new WritableRaster.
+ * @param w the width of the new WritableRaster.
+ * @param h the height of the new WritableRaster.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createCompatibleWritableRaster(int x, int y, int w,
+ int h) {
+
+ WritableRaster raster = createCompatibleWritableRaster(w, h);
+
+ return raster.createWritableChild(0, 0, w, h, x, y, null);
+ }
+
+ /**
+ * Create a compatible WritableRaster with the same parameters
+ * as this Raster and the specified rectangle which determines
+ * new WritableRaster's location and size.
+ *
+ * @param rect the specified Rectangle.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createCompatibleWritableRaster(Rectangle rect) {
+ if (rect == null) {
+ // awt.28C=Rect is null
+ throw new NullPointerException(Messages.getString("awt.28C")); //$NON-NLS-1$
+ }
+
+ return createCompatibleWritableRaster(rect.x, rect.y, rect.width,
+ rect.height);
+ }
+
+ /**
+ * Creates the translated child of this Raster. The New Raster
+ * object is a reference to the this Raster with a
+ * different location.
+ *
+ * @param childMinX the X coordinate of the new Raster.
+ * @param childMinY the Y coordinate of the new Raster.
+ *
+ * @return the Raster.
+ */
+ public Raster createTranslatedChild(int childMinX, int childMinY) {
+ return createChild(minX, minY, width, height, childMinX, childMinY,
+ null);
+ }
+
+ /**
+ * Gets the bounds of this Raster as a rectangle.
+ *
+ * @return the bounds of this Raster.
+ */
+ public Rectangle getBounds() {
+ return new Rectangle(minX, minY, width, height);
+ }
+
+ /**
+ * Gets the DataBuffer associated with this Raster.
+ *
+ * @return the DataBuffer associated with this Raster.
+ */
+ public DataBuffer getDataBuffer() {
+ return dataBuffer;
+ }
+
+ /**
+ * Gets the data elements which represent the pixel data of the specified
+ * rectangle area as a primitive array. The following image data types
+ * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
+ * or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param outData the resulting array.
+ *
+ * @return the data elements of the specified area of this Raster.
+ */
+ public Object getDataElements(int x, int y, int w, int h, Object outData) {
+ return sampleModel.getDataElements(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, outData, dataBuffer);
+ }
+
+ /**
+ * Gets the data elements which represent the specified pixel of
+ * this Raster as a primitive array. The following image data types
+ * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
+ * or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param outData the resulting data.
+ *
+ * @return the data elements of the specified pixel of this Raster.
+ */
+ public Object getDataElements(int x, int y, Object outData) {
+ return sampleModel.getDataElements(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, outData, dataBuffer);
+ }
+
+ /**
+ * Gets the height of this Raster.
+ *
+ * @return the height of this Raster.
+ */
+ public final int getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the minimum X coordinate of this Raster.
+ *
+ * @return the minimum X coordinate of this Raster.
+ */
+ public final int getMinX() {
+ return minX;
+ }
+
+ /**
+ * Gets the minimum Y coordinate of this Raster.
+ *
+ * @return the minimum Y coordinate of this Raster.
+ */
+ public final int getMinY() {
+ return minY;
+ }
+
+ /**
+ * Gets the number of bands in this Raster.
+ *
+ * @return the number of bands in this Raster.
+ */
+ public final int getNumBands() {
+ return numBands;
+ }
+
+ /**
+ * Gets the number of data elements for one pixel.
+ *
+ * @return the number of data elements for one pixel.
+ */
+ public final int getNumDataElements() {
+ return numDataElements;
+ }
+
+ /**
+ * Gets the parent Raster for this Raster object.
+ *
+ * @return the parent Raster for this Raster object.
+ */
+ public Raster getParent() {
+ return parent;
+ }
+
+ /**
+ * Gets a double array of samples for the specified pixel in this Raster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param dArray the double array where result array will be stored.
+ *
+ * @return the double array of samples for the specified pixel in
+ * this Raster.
+ */
+ public double[] getPixel(int x, int y, double dArray[]) {
+ return sampleModel.getPixel(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, dArray, dataBuffer);
+ }
+
+ /**
+ * Gets a float array of samples for the specified pixel in this Raster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param fArray the float array where the result array will be stored.
+ *
+ * @return the float array of samples for the specified pixel in
+ * this Raster.
+ */
+ public float[] getPixel(int x, int y, float fArray[]) {
+ return sampleModel.getPixel(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, fArray, dataBuffer);
+ }
+
+ /**
+ * Gets an int array of samples for the specified pixel in this Raster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param iArray the int array where the result array will be stored.
+ *
+ * @return the int array of samples for the specified pixel in
+ * this Raster.
+ */
+ public int[] getPixel(int x, int y, int iArray[]) {
+ return sampleModel.getPixel(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, iArray, dataBuffer);
+ }
+
+ /**
+ * Gets an double array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param dArray the resulting array.
+ *
+ * @return the double array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ */
+ public double[] getPixels(int x, int y, int w, int h, double dArray[]) {
+ return sampleModel.getPixels(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, dArray, dataBuffer);
+ }
+
+ /**
+ * Gets an float array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param fArray the resulting array.
+ *
+ * @return the float array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ */
+ public float[] getPixels(int x, int y, int w, int h, float fArray[]) {
+ return sampleModel.getPixels(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, fArray, dataBuffer);
+ }
+
+ /**
+ * Gets an int array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of pixel's the area of pixels.
+ * @param h the height of pixel's the area of pixels.
+ * @param iArray the resulting array.
+ *
+ * @return the int array of samples for the specified rectangular
+ * area of pixels in this Raster.
+ */
+ public int[] getPixels(int x, int y, int w, int h, int iArray[]) {
+ return sampleModel.getPixels(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, iArray, dataBuffer);
+ }
+
+ /**
+ * Gets the sample for the specified band of the specified
+ * pixel as an int.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the band.
+ *
+ * @return the sample for the specified band of the specified
+ * pixel as an int.
+ */
+ public int getSample(int x, int y, int b) {
+ return sampleModel.getSample(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, b, dataBuffer);
+ }
+
+ /**
+ * Gets the sample for the specified band of the specified
+ * pixel as a double.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the band.
+ *
+ * @return the sample for the specified band of the specified
+ * pixel as a double.
+ */
+ public double getSampleDouble(int x, int y, int b) {
+ return sampleModel.getSampleDouble(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, b, dataBuffer);
+ }
+
+ /**
+ * Gets the sample for the specified band of the specified
+ * pixel as a float.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the band.
+ *
+ * @return the sample for the specified band of the specified
+ * pixel as a float.
+ */
+ public float getSampleFloat(int x, int y, int b) {
+ return sampleModel.getSampleFloat(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, b, dataBuffer);
+ }
+
+ /**
+ * Gets the SampleModel associated with this Raster.
+ *
+ * @return the SampleModel associated with this Raster.
+ */
+ public SampleModel getSampleModel() {
+ return sampleModel;
+ }
+
+ /**
+ * Gets the translation of the X coordinate from the SampleModel
+ * coordinate system to the Rasters's coordinate system.
+ *
+ * @return the value of the translation of the X coordinate from
+ * the SampleModel coordinate system to the Rasters's
+ * coordinate system.
+ */
+ public final int getSampleModelTranslateX() {
+ return sampleModelTranslateX;
+ }
+
+ /**
+ * Gets the translation of the Y coordinate from the SampleModel
+ * coordinate system to the Rasters's coordinate system.
+ *
+ * @return the value of the translation of the Y coordinate from
+ * the SampleModel coordinate system to the Rasters's
+ * coordinate system.
+
+ */
+ public final int getSampleModelTranslateY() {
+ return sampleModelTranslateY;
+ }
+
+ /**
+ * Gets the double array of samples for the specified band
+ * of the specified rectangular area of pixels in this Raster
+ * as a double array.
+ *
+ * @param x the X coordinate of the rectangular area of pixels.
+ * @param y the Y coordinate of the rectangular area of pixels.
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param b the band.
+ * @param dArray the resulting double array.
+ *
+ * @return the double array of samples for the specified band
+ * of the specified rectangular area of pixels.
+ */
+ public double[] getSamples(int x, int y, int w, int h, int b,
+ double dArray[]) {
+
+ return sampleModel.getSamples(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, b, dArray, dataBuffer);
+ }
+
+ /**
+ * Gets the float array of samples for the specified band
+ * of the specified rectangular area of pixels in this Raster
+ * as a float array.
+ *
+ * @param x the X coordinate of the rectangular area of pixels.
+ * @param y the Y coordinate of the rectangular area of pixels.
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param b the band.
+ * @param fArray the resulting float array.
+ *
+ * @return the float array of samples for the specified band
+ * of the specified rectangular area of pixels.
+ */
+ public float[] getSamples(int x, int y, int w, int h, int b, float fArray[]) {
+
+ return sampleModel.getSamples(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, b, fArray, dataBuffer);
+ }
+
+ /**
+ * Gets the int array of samples for the specified band
+ * of the specified rectangular area of pixels in this Raster
+ * as a int array.
+ *
+ * @param x the X coordinate of the rectangular area of pixels.
+ * @param y the Y coordinate of the rectangular area of pixels.
+ * @param w the width of the rectangular area of pixels.
+ * @param h the height of the rectangular area of pixels.
+ * @param b the band.
+ * @param iArray the resulting int array.
+ *
+ * @return the int array of samples for the specified band
+ * of the specified rectangular area of pixels.
+ */
+ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[]) {
+ return sampleModel.getSamples(x - sampleModelTranslateX, y
+ - sampleModelTranslateY, w, h, b, iArray, dataBuffer);
+ }
+
+ /**
+ * Gets the transfer type for pixels of this Raster.
+ * @see SampleModel#getTransferType()
+ *
+ * @return the transfer type for pixels of this Raster.
+ */
+ public final int getTransferType() {
+ return sampleModel.getTransferType();
+ }
+
+ /**
+ * Gets the width of this Raster.
+ *
+ * @return the width of this Raster.
+ */
+ public final int getWidth() {
+ return width;
+ }
+
+ /**
+ * Validate data buffer.
+ *
+ * @param dataBuffer the data buffer
+ * @param w the w
+ * @param h the h
+ * @param scanlineStride the scanline stride
+ */
+ private static void validateDataBuffer(final DataBuffer dataBuffer, final int w,
+ final int h, final int scanlineStride) {
+ if (dataBuffer.getSize() < (scanlineStride * (h - 1) + w - 1)) {
+ // awt.298=dataBuffer is too small
+ throw new RasterFormatException(Messages.getString("awt.298")); //$NON-NLS-1$
+ }
+ }
+}
+
+
diff --git a/awt/java/awt/image/RasterFormatException.java b/awt/java/awt/image/RasterFormatException.java
new file mode 100644
index 0000000..8577dad
--- /dev/null
+++ b/awt/java/awt/image/RasterFormatException.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+
+/**
+ * The RasterFormatException class represents the exception
+ * that is thrown when there's an invalid layout
+ * in the Raster.
+ */
+public class RasterFormatException extends RuntimeException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 96598996116164315L;
+
+ /**
+ * Instantiates a new RasterFormatException with the
+ * specified detail message.
+ *
+ * @param s the detail message.
+ */
+ public RasterFormatException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/awt/java/awt/image/RasterOp.java b/awt/java/awt/image/RasterOp.java
new file mode 100644
index 0000000..e8933ee
--- /dev/null
+++ b/awt/java/awt/image/RasterOp.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.RenderingHints;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The RasterOp interface provides methods for performing transformations
+ * from source data to destination data for Raster objects. The source and
+ * destination objects should contain the appropriate number of bands for
+ * the particular classes which implement this interface.
+ */
+public interface RasterOp {
+
+ /**
+ * Creates a destination WritableRaster with the specified Raster;
+ * this destination image data is empty and has the correct size
+ * and number of bands.
+ *
+ * @param src the source Raster.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createCompatibleDestRaster(Raster src);
+
+ /**
+ * Performs a filter operation on the source Raster and stores the resulting
+ * image data to the destination WritableRaster.
+ *
+ * @param src the source Raster.
+ * @param dst the destination WritableRaster, where the result is stored.
+ *
+ * @return the filtered WritableRaster.
+ */
+ public WritableRaster filter(Raster src, WritableRaster dst);
+
+ /**
+ * Gets the bounds of the filtered Raster.
+ *
+ * @param src the source Raster to be filtered.
+ *
+ * @return the rectangle bounds of the filtered Raster.
+ */
+ public Rectangle2D getBounds2D(Raster src);
+
+ /**
+ * Gets the point of the destination image which corresponds
+ * to the specified point in the source raster.
+ *
+ * @param srcPoint the point of the source raster.
+ * @param dstPoint the point where the result will be stored.
+ *
+ * @return the destination point.
+ */
+ public Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint);
+
+ /**
+ * Gets the RenderingHints of the RasterOp.
+ *
+ * @return the RenderingHints of the RasterOp.
+ */
+ public RenderingHints getRenderingHints();
+}
diff --git a/awt/java/awt/image/RenderedImage.java b/awt/java/awt/image/RenderedImage.java
new file mode 100644
index 0000000..db3a4c8
--- /dev/null
+++ b/awt/java/awt/image/RenderedImage.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Rectangle;
+import java.util.Vector;
+
+/**
+ * The RenderedImage interface should be implemented by all objects which
+ * contains image data. The image data is represented as a single tile or
+ * an array of tiles.
+ */
+public interface RenderedImage {
+
+ /**
+ * Gets the property with the specified name from the property set
+ * of this RenderedImage.
+ *
+ * @param name the property's name.
+ *
+ * @return the property value corresponded to this property's name.
+ */
+ public Object getProperty(String name);
+
+ /**
+ * Copies the region of this RenderedImage to the specified
+ * WritableRaster. The bounds of the region are the bounds of the
+ * WritableRaster.
+ *
+ * @param raster the WritableRaster.
+ *
+ * @return the created WritableRaster.
+ */
+ public WritableRaster copyData(WritableRaster raster);
+
+ /**
+ * Gets the image data of the image's region as one tile.
+ *
+ * @param rect the rectangular region of RenderedImage.
+ *
+ * @return the image data of the image's region as one tile.
+ */
+ public Raster getData(Rectangle rect);
+
+ /**
+ * Gets all RenderedImage objects which are the source of this
+ * RenderedImage object.
+ *
+ * @return a Vector of RenderedImage objects which are the source
+ * of this RenderedImage object or null, if there is no information
+ * about them.
+ */
+ public Vector<RenderedImage> getSources();
+
+ /**
+ * Gets the set of all property names for this RenderedImage.
+ *
+ * @return the array of all property names for this RenderedImage.
+ */
+ public String[] getPropertyNames();
+
+ /**
+ * Gets the SampleModel of this RenderedImage.
+ *
+ * @return the SampleModel of this RenderedImage.
+ */
+ public SampleModel getSampleModel();
+
+ /**
+ * Gets the tile corresponded to the specified indices in the tile
+ * array.
+ *
+ * @param tileX the X index of the tile.
+ * @param tileY the Y index of the tile.
+ *
+ * @return the tile corresponded to the specified indices in the tile
+ * array.
+ */
+ public Raster getTile(int tileX, int tileY);
+
+ /**
+ * Gets the image data of this image as one tile.
+ *
+ * @return the image data of this image as one tile.
+ */
+ public Raster getData();
+
+ /**
+ * Gets the ColorModel of this RenderedImage.
+ *
+ * @return the ColorModel of this RenderedImage.
+ */
+ public ColorModel getColorModel();
+
+ /**
+ * Gets the width of the RenderedImage.
+ *
+ * @return the width of the RenderedImage.
+ */
+ public int getWidth();
+
+ /**
+ * Gets the tile width.
+ *
+ * @return the tile width in pixels.
+ */
+ public int getTileWidth();
+
+ /**
+ * Gets the tile height.
+ *
+ * @return the tile height in pixels.
+ */
+ public int getTileHeight();
+
+ /**
+ * Gets the Y offset of the tile grid.
+ *
+ * @return the Y offset of the tile grid.
+ */
+ public int getTileGridYOffset();
+
+ /**
+ * Gets the X offset of the tile grid.
+ *
+ * @return the X offset of the tile grid.
+ */
+ public int getTileGridXOffset();
+
+ /**
+ * Gets the number of tiles along Y direction.
+ *
+ * @return the number of tiles along Y direction.
+ */
+ public int getNumYTiles();
+
+ /**
+ * Gets the number of tiles along X direction.
+ *
+ * @return the number of tiles along X direction.
+ */
+ public int getNumXTiles();
+
+ /**
+ * Gets the minimum Y coordinate of this RenderedImage.
+ *
+ * @return the minimum Y coordinate of this RenderedImage.
+ */
+ public int getMinY();
+
+ /**
+ * Gets the minimum X coordinate of this RenderedImage.
+ *
+ * @return the minimum X coordinate of this RenderedImage.
+ */
+ public int getMinX();
+
+ /**
+ * Gets the minimum tile's index along the Y direction.
+ *
+ * @return the minimum tile's index along the Y direction.
+ */
+ public int getMinTileY();
+
+ /**
+ * Gets the minimum tile's index along the X direction.
+ *
+ * @return the minimum tile's index along the X direction.
+ */
+ public int getMinTileX();
+
+ /**
+ * Gets the height of the RenderedImage.
+ *
+ * @return the height of the RenderedImage.
+ */
+ public int getHeight();
+
+}
+
diff --git a/awt/java/awt/image/ReplicateScaleFilter.java b/awt/java/awt/image/ReplicateScaleFilter.java
new file mode 100644
index 0000000..9298125
--- /dev/null
+++ b/awt/java/awt/image/ReplicateScaleFilter.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * The ReplicateScaleFilter class scales an source image
+ * by replicating rows and columns of pixels to scale up or
+ * omitting rows and columns of pixels to scale down.
+ */
+public class ReplicateScaleFilter extends ImageFilter {
+
+ /** The width of a source image. */
+ protected int srcWidth;
+
+ /** The height of a source image. */
+ protected int srcHeight;
+
+ /** The width of a destination image. */
+ protected int destWidth;
+
+ /** The height of a destination image. */
+ protected int destHeight;
+
+ /** The int array of source rows. */
+ protected int[] srcrows;
+
+ /** The int array of source columns. */
+ protected int[] srccols;
+
+ /**
+ * An Object (byte array with a destination width) provides
+ * a row of pixel data to the ImageConsumer.
+ */
+ protected Object outpixbuf;
+
+ /**
+ * Instantiates a new ReplicateScaleFilter that filters
+ * the image with the specified width and height.
+ *
+ * @param width the width of scaled image.
+ * @param height the height of scaled image.
+ */
+ public ReplicateScaleFilter(int width, int height) {
+ if(width == 0 || height == 0) {
+ // awt.234=Width or Height equals zero
+ throw new IllegalArgumentException(Messages.getString("awt.234")); //$NON-NLS-1$
+ }
+
+ this.destWidth = width;
+ this.destHeight = height;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void setProperties(Hashtable<?, ?> props) {
+ Hashtable<Object, Object> fprops;
+ if(props == null) {
+ fprops = new Hashtable<Object, Object>();
+ } else {
+ fprops = (Hashtable<Object, Object>) props.clone();
+ }
+ String propName = "Rescale Filters"; //$NON-NLS-1$
+ String prop = "destWidth=" + destWidth + "; " + //$NON-NLS-1$ //$NON-NLS-2$
+ "destHeight=" + destHeight; //$NON-NLS-1$
+ Object o = fprops.get(propName);
+ if(o != null){
+ if(o instanceof String){
+ prop = (String)o + "; " + prop; //$NON-NLS-1$
+ }else{
+ prop = o.toString() + "; " + prop; //$NON-NLS-1$
+ }
+ }
+ fprops.put(propName, prop);
+ consumer.setProperties(fprops);
+ }
+
+ // setPixels methods produce pixels according to Java API Spacification
+
+ @Override
+ public void setPixels(int x, int y, int w, int h,
+ ColorModel model, int[] pixels, int off, int scansize) {
+
+ if(srccols == null) {
+ initArrays();
+ }
+ int buff[];
+ if(outpixbuf == null || !(outpixbuf instanceof int[])){
+ buff = new int[destWidth];
+ outpixbuf = buff;
+ }else{
+ buff = (int[])outpixbuf;
+ }
+
+ int wa = (srcWidth - 1) >>> 1;
+ int ha = (srcHeight - 1) >>> 1;
+ int dstX = (x * destWidth + wa) / srcWidth;
+ int dstY = (y * destHeight + ha) / srcHeight;
+
+ int sx, sy, dx, dy;
+ dy = dstY;
+ while((dy < destHeight) && ((sy = srcrows[dy]) < y + h)){
+ dx = dstX;
+ int srcOff = off + (sy - y) * scansize;
+ while((dx < destWidth) && ((sx = srccols[dx]) < x + w)){
+ buff[dx] = pixels[srcOff + (sx - x)];
+ dx++;
+ }
+
+ consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff,
+ dstX, destWidth);
+ dy++;
+ }
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h,
+ ColorModel model, byte[] pixels, int off, int scansize) {
+
+ if(srccols == null) {
+ initArrays();
+ }
+ byte buff[];
+ if(outpixbuf == null || !(outpixbuf instanceof byte[])){
+ buff = new byte[destWidth];
+ outpixbuf = buff;
+ }else{
+ buff = (byte[])outpixbuf;
+ }
+
+ int wa = (srcWidth - 1) >>> 1;
+ int ha = (srcHeight - 1) >>> 1;
+ int dstX = (x * destWidth + wa) / srcWidth;
+ int dstY = (y * destHeight + ha) / srcHeight;
+
+ int sx, sy, dx, dy;
+ dy = dstY;
+ while((dy < destHeight) && ((sy = srcrows[dy]) < y + h)){
+ dx = dstX;
+ int srcOff = off + (sy - y) * scansize;
+ while((dx < destWidth) && ((sx = srccols[dx]) < x + w)){
+ buff[dx] = pixels[srcOff + (sx - x)];
+ dx++;
+ }
+
+ consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff,
+ dstX, destWidth);
+ dy++;
+ }
+ }
+
+ @Override
+ public void setDimensions(int w, int h) {
+ srcWidth = w;
+ srcHeight = h;
+
+ if(destWidth < 0 && destHeight < 0){
+ destWidth = srcWidth;
+ destHeight = srcHeight;
+ }else if(destWidth < 0){
+ destWidth = destHeight * srcWidth / srcHeight;
+ }else if(destHeight < 0){
+ destHeight = destWidth * srcHeight / srcWidth;
+ }
+ consumer.setDimensions(destWidth, destHeight);
+ }
+
+ /**
+ * Initialization of srccols and srcrows arrays.
+ */
+ private void initArrays(){
+ if ((destWidth < 0) || (destHeight < 0)) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ srccols = new int[destWidth];
+ int ca = srcWidth >>> 1;
+ for(int i = 0; i < destWidth; i++){
+ srccols[i] = (i * srcWidth + ca) / destWidth;
+ }
+
+ srcrows = new int[destHeight];
+ int ra = srcHeight >>> 1;
+ for(int i = 0; i < destHeight; i++){
+ srcrows[i] = (i * srcHeight + ra) / destHeight;
+ }
+ }
+
+}
+
+
diff --git a/awt/java/awt/image/RescaleOp.java b/awt/java/awt/image/RescaleOp.java
new file mode 100644
index 0000000..0e96031
--- /dev/null
+++ b/awt/java/awt/image/RescaleOp.java
@@ -0,0 +1,659 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 6, 2005
+ */
+
+package java.awt.image;
+
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.*;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class RescaleOp performs rescaling of the source image data
+ * by multiplying the pixel values with a scale factor
+ * and then adding an offset.
+ */
+public class RescaleOp implements BufferedImageOp, RasterOp {
+
+ /** The scale factors. */
+ private float scaleFactors[];
+
+ /** The offsets. */
+ private float offsets[];
+
+ /** The hints. */
+ private RenderingHints hints;
+
+ static {
+ // TODO
+ //System.loadLibrary("imageops");
+ }
+
+ /**
+ * Instantiates a new RescaleOp object with the specified
+ * scale factors and offsets.
+ *
+ * @param scaleFactors the array of scale factor values.
+ * @param offsets the array of offset values.
+ * @param hints the RenderingHints or null.
+ */
+ public RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints) {
+ int numFactors = Math.min(scaleFactors.length, offsets.length);
+
+ this.scaleFactors = new float[numFactors];
+ this.offsets = new float[numFactors];
+
+ System.arraycopy(scaleFactors, 0, this.scaleFactors, 0, numFactors);
+ System.arraycopy(offsets, 0, this.offsets, 0, numFactors);
+
+ this.hints = hints;
+ }
+
+ /**
+ * Instantiates a new RescaleOp object with the specified
+ * scale factor and offset.
+ *
+ * @param scaleFactor the scale factor.
+ * @param offset the offset.
+ * @param hints the RenderingHints or null.
+ */
+ public RescaleOp(float scaleFactor, float offset, RenderingHints hints) {
+ scaleFactors = new float[1];
+ offsets = new float[1];
+
+ scaleFactors[0] = scaleFactor;
+ offsets[0] = offset;
+
+ this.hints = hints;
+ }
+
+ /**
+ * Gets the number of scaling factors.
+ *
+ * @return the number of scaling factors.
+ */
+ public final int getNumFactors() {
+ return scaleFactors.length;
+ }
+
+ public final RenderingHints getRenderingHints() {
+ return hints;
+ }
+
+ /**
+ * Gets the scale factors of this RescaleOp.
+ *
+ * @param scaleFactors the desired scale factors array will be copied
+ * to this array.
+ *
+ * @return the scale factors array.
+ */
+ public final float[] getScaleFactors(float[] scaleFactors) {
+ if (scaleFactors == null) {
+ scaleFactors = new float[this.scaleFactors.length];
+ }
+
+ int minLength = Math.min(scaleFactors.length, this.scaleFactors.length);
+ System.arraycopy(this.scaleFactors, 0, scaleFactors, 0, minLength);
+ return scaleFactors;
+ }
+
+ /**
+ * Gets the offsets array of this RescaleOp.
+ *
+ * @param offsets the desired offsets array will be copied to this array.
+ *
+ * @return the offsets array of this RescaleOp.
+ */
+ public final float[] getOffsets(float[] offsets) {
+ if (offsets == null) {
+ offsets = new float[this.offsets.length];
+ }
+
+ int minLength = Math.min(offsets.length, this.offsets.length);
+ System.arraycopy(this.offsets, 0, offsets, 0, minLength);
+ return offsets;
+ }
+
+ public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+ if (dstPt == null) {
+ dstPt = new Point2D.Float();
+ }
+
+ dstPt.setLocation(srcPt);
+ return dstPt;
+ }
+
+ public final Rectangle2D getBounds2D(Raster src) {
+ return src.getBounds();
+ }
+
+ public final Rectangle2D getBounds2D(BufferedImage src) {
+ return getBounds2D(src.getRaster());
+ }
+
+ public WritableRaster createCompatibleDestRaster(Raster src) {
+ return src.createCompatibleWritableRaster();
+ }
+
+ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
+ if (dstCM == null) {
+ dstCM = src.getColorModel();
+ }
+
+ if (dstCM instanceof IndexColorModel) {
+ dstCM = ColorModel.getRGBdefault();
+ }
+
+ WritableRaster r =
+ dstCM.isCompatibleSampleModel(src.getSampleModel()) ?
+ src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) :
+ dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
+
+ return new BufferedImage(
+ dstCM,
+ r,
+ dstCM.isAlphaPremultiplied(),
+ null
+ );
+ }
+
+ public final WritableRaster filter(Raster src, WritableRaster dst) {
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else {
+ if (src.getNumBands() != dst.getNumBands()) {
+ // awt.21D=Number of src bands ({0}) does not match number of dst bands ({1})
+ throw new IllegalArgumentException(Messages.getString("awt.21D", //$NON-NLS-1$
+ src.getNumBands(), dst.getNumBands()));
+ }
+ }
+
+ if (
+ this.scaleFactors.length != 1 &&
+ this.scaleFactors.length != src.getNumBands()
+ ) {
+ // awt.21E=Number of scaling constants is not equal to the number of bands
+ throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$
+ }
+
+ // TODO
+ //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0)
+ if (slowFilter(src, dst, false) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ return dst;
+ }
+
+ /**
+ * Slow filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param skipAlpha the skip alpha
+ *
+ * @return the int
+ */
+ private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) {
+ SampleModel sm = src.getSampleModel();
+
+ int numBands = src.getNumBands();
+ int srcHeight = src.getHeight();
+ int srcWidth = src.getWidth();
+
+ int srcMinX = src.getMinX();
+ int srcMinY = src.getMinY();
+ int dstMinX = dst.getMinX();
+ int dstMinY = dst.getMinY();
+
+ int[] maxValues = new int[numBands];
+ int[] masks = new int[numBands];
+ int[] sampleSizes = sm.getSampleSize();
+
+ for (int i=0; i < numBands; i++){
+ maxValues[i] = (1 << sampleSizes[i]) - 1;
+ masks[i] = ~(maxValues[i]);
+ }
+
+ // Processing bounds
+ float[] pixels = null;
+ pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels);
+
+ // Cycle over pixels to be calculated
+ if (skipAlpha) { // Always suppose that alpha channel is the last band
+ if (scaleFactors.length > 1) {
+ for (int i = 0; i < pixels.length; ){
+ for (int bandIdx = 0; bandIdx < numBands-1; bandIdx++, i++){
+ pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx];
+ // Check for overflow now
+ if (((int)pixels[i] & masks[bandIdx]) != 0) {
+ if (pixels[i] < 0) {
+ pixels[i] = 0;
+ } else {
+ pixels[i] = maxValues[bandIdx];
+ }
+ }
+ }
+
+ i++;
+ }
+ } else {
+ for (int i = 0; i < pixels.length; ){
+ for (int bandIdx = 0; bandIdx < numBands-1; bandIdx++, i++){
+ pixels[i] = pixels[i] * scaleFactors[0] + offsets[0];
+ // Check for overflow now
+ if (((int)pixels[i] & masks[bandIdx]) != 0) {
+ if (pixels[i] < 0) {
+ pixels[i] = 0;
+ } else {
+ pixels[i] = maxValues[bandIdx];
+ }
+ }
+ }
+
+ i++;
+ }
+ }
+ } else {
+ if (scaleFactors.length > 1) {
+ for (int i = 0; i < pixels.length; ){
+ for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++){
+ pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx];
+ // Check for overflow now
+ if (((int)pixels[i] & masks[bandIdx]) != 0) {
+ if (pixels[i] < 0) {
+ pixels[i] = 0;
+ } else {
+ pixels[i] = maxValues[bandIdx];
+ }
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < pixels.length; ){
+ for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++){
+ pixels[i] = pixels[i] * scaleFactors[0] + offsets[0];
+ // Check for overflow now
+ if (((int)pixels[i] & masks[bandIdx]) != 0) {
+ if (pixels[i] < 0) {
+ pixels[i] = 0;
+ } else {
+ pixels[i] = maxValues[bandIdx];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, pixels);
+
+ return 0;
+ }
+
+ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ ColorModel srcCM = src.getColorModel();
+
+ if (srcCM instanceof IndexColorModel) {
+ // awt.220=Source should not have IndexColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$
+ }
+
+ // Check if the number of scaling factors matches the number of bands
+ int nComponents = srcCM.getNumComponents();
+ boolean skipAlpha;
+ if (srcCM.hasAlpha()) {
+ if (scaleFactors.length == 1 || scaleFactors.length == nComponents-1) {
+ skipAlpha = true;
+ } else if (scaleFactors.length == nComponents) {
+ skipAlpha = false;
+ } else {
+ // awt.21E=Number of scaling constants is not equal to the number of bands
+ throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$
+ }
+ } else if (scaleFactors.length == 1 || scaleFactors.length == nComponents) {
+ skipAlpha = false;
+ } else {
+ // awt.21E=Number of scaling constants is not equal to the number of bands
+ throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$
+ }
+
+ BufferedImage finalDst = null;
+ if (dst == null) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, srcCM);
+ } else if (!srcCM.equals(dst.getColorModel())) {
+ // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same
+ if (
+ !((src.getType() == BufferedImage.TYPE_INT_RGB ||
+ src.getType() == BufferedImage.TYPE_INT_ARGB) &&
+ (dst.getType() == BufferedImage.TYPE_INT_RGB ||
+ dst.getType() == BufferedImage.TYPE_INT_ARGB))
+ ) {
+ finalDst = dst;
+ dst = createCompatibleDestImage(src, srcCM);
+ }
+ }
+
+ // TODO
+ //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType(), skipAlpha) != 0)
+ if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) {
+ // awt.21F=Unable to transform source
+ throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$
+ }
+
+ if (finalDst != null) {
+ Graphics2D g = finalDst.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.drawImage(dst, 0, 0, null);
+ } else {
+ finalDst = dst;
+ }
+
+ return finalDst;
+ }
+
+ // Don't forget to pass allocated arrays for levels and values, size should be numBands*4
+ /**
+ * Creates the levels.
+ *
+ * @param sm the sm
+ * @param numBands the num bands
+ * @param skipAlpha the skip alpha
+ * @param levels the levels
+ * @param values the values
+ * @param channelsOrder the channels order
+ */
+ private final void createLevels(
+ SampleModel sm, int numBands, boolean skipAlpha,
+ int levels[], int values[], int channelsOrder[]
+ ) {
+ // Suppose same sample size for all channels, otherwise use slow filter
+ int maxValue = (1 << sm.getSampleSize(0)) - 1;
+
+ // For simplicity introduce these arrays
+ float extScaleFactors[] = new float[numBands];
+ float extOffsets[] = new float[numBands];
+
+ if (scaleFactors.length != 1) {
+ System.arraycopy(scaleFactors, 0, extScaleFactors, 0, scaleFactors.length);
+ System.arraycopy(offsets, 0, extOffsets, 0, scaleFactors.length);
+ } else {
+ for (int i = 0; i < numBands; i++) {
+ extScaleFactors[i] = scaleFactors[0];
+ extOffsets[i] = offsets[0];
+ }
+ }
+
+ if (skipAlpha) {
+ extScaleFactors[numBands-1] = 1;
+ extOffsets[numBands-1] = 0;
+ }
+
+ // Create a levels
+ for (int i=0; i<numBands; i++) {
+ if (extScaleFactors[i] == 0) {
+ levels[i*4] = 0;
+ levels[i*4+1] = 0;
+ levels[i*4+2] = maxValue+1;
+ levels[i*4+3] = maxValue+1;
+ }
+
+ float minLevel = -extOffsets[i] / extScaleFactors[i];
+ float maxLevel = (maxValue - extOffsets[i]) / extScaleFactors[i];
+
+ if (minLevel < 0) {
+ minLevel = 0;
+ } else if (minLevel > maxValue){
+ minLevel = maxValue;
+ }
+
+ if (maxLevel < 0) {
+ maxLevel = 0;
+ } else if (maxLevel > maxValue){
+ maxLevel = maxValue;
+ }
+
+ levels[i*4] = 0;
+ if (minLevel > maxLevel) {
+ levels[i*4+1] = (int) maxLevel;
+ levels[i*4+2] = (int) minLevel;
+ } else {
+ levels[i*4+1] = (int) minLevel;
+ levels[i*4+2] = (int) maxLevel;
+ }
+ levels[i*4+3] = maxValue+1;
+
+ // Fill values
+ for (int k=0; k<4; k++) {
+ int idx = i*4+k;
+ values[idx] = (int) (extScaleFactors[i] * levels[idx] + extOffsets[i]);
+ if (values[idx] < 0) {
+ values[idx] = 0;
+ } else if (values[idx] > maxValue){
+ values[idx] = maxValue;
+ }
+ }
+ }
+
+ // Reorder data if channels are stored in different order
+ if (channelsOrder != null) {
+ int len = numBands*4;
+ int savedLevels[] = new int[len];
+ int savedValues[] = new int[len];
+ System.arraycopy(levels, 0, savedLevels, 0, len);
+ System.arraycopy(values, 0, savedValues, 0, len);
+ for (int i = 0; i < channelsOrder.length; i++) {
+ System.arraycopy(savedLevels, i*4, levels, channelsOrder[i]*4, 4);
+ System.arraycopy(savedValues, i*4, values, channelsOrder[i]*4, 4);
+ }
+ }
+ }
+
+ // TODO remove when this method is used
+ /**
+ * Ipp filter.
+ *
+ * @param src the src
+ * @param dst the dst
+ * @param imageType the image type
+ * @param skipAlpha the skip alpha
+ *
+ * @return the int
+ */
+ @SuppressWarnings("unused")
+ private final int ippFilter(
+ Raster src, WritableRaster dst,
+ int imageType, boolean skipAlpha
+ ) {
+ int res;
+
+ int srcStride, dstStride;
+ int channels;
+ int offsets[] = null;
+ int channelsOrder[] = null;
+
+ switch (imageType) {
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ case BufferedImage.TYPE_INT_RGB: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ channelsOrder = new int[] {2, 1, 0, 3};
+ break;
+ }
+
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+ case BufferedImage.TYPE_INT_BGR: {
+ channels = 4;
+ srcStride = src.getWidth()*4;
+ dstStride = dst.getWidth()*4;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_GRAY: {
+ channels = 1;
+ srcStride = src.getWidth();
+ dstStride = dst.getWidth();
+ break;
+ }
+
+ case BufferedImage.TYPE_3BYTE_BGR: {
+ channels = 3;
+ srcStride = src.getWidth()*3;
+ dstStride = dst.getWidth()*3;
+ channelsOrder = new int[] {2, 1, 0};
+ break;
+ }
+
+ case BufferedImage.TYPE_USHORT_GRAY:
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ case BufferedImage.TYPE_BYTE_BINARY: {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ default: {
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+
+ if (
+ srcSM instanceof PixelInterleavedSampleModel &&
+ dstSM instanceof PixelInterleavedSampleModel
+ ) {
+ // Check PixelInterleavedSampleModel
+ if (
+ srcSM.getDataType() != DataBuffer.TYPE_BYTE ||
+ dstSM.getDataType() != DataBuffer.TYPE_BYTE
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels
+ if (!(channels == 1 || channels == 3 || channels == 4)) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ srcStride = ((ComponentSampleModel) srcSM).getScanlineStride();
+ dstStride = ((ComponentSampleModel) dstSM).getScanlineStride();
+
+ channelsOrder = ((ComponentSampleModel) srcSM).getBandOffsets();
+ } else if (
+ srcSM instanceof SinglePixelPackedSampleModel &&
+ dstSM instanceof SinglePixelPackedSampleModel
+ ) {
+ // Check SinglePixelPackedSampleModel
+ SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM;
+ SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM;
+
+ channels = sppsm1.getNumBands();
+
+ // TYPE_INT_RGB, TYPE_INT_ARGB...
+ if (
+ sppsm1.getDataType() != DataBuffer.TYPE_INT ||
+ sppsm2.getDataType() != DataBuffer.TYPE_INT ||
+ !(channels == 3 || channels == 4)
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ // Check compatibility of sample models
+ if (
+ !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) ||
+ !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())
+ ) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ for (int i=0; i<channels; i++) {
+ if (sppsm1.getSampleSize(i) != 8) {
+ return slowFilter(src, dst, skipAlpha);
+ }
+ }
+
+ channelsOrder = new int[channels];
+ int bitOffsets[] = sppsm1.getBitOffsets();
+ for (int i=0; i<channels; i++) {
+ channelsOrder[i] = bitOffsets[i] / 8;
+ }
+
+ if (channels == 3) { // Don't skip channel now, could be optimized
+ channels = 4;
+ }
+
+ srcStride = sppsm1.getScanlineStride() * 4;
+ dstStride = sppsm2.getScanlineStride() * 4;
+ } else {
+ return slowFilter(src, dst, skipAlpha);
+ }
+
+ // Fill offsets if there's a child raster
+ if (src.getParent() != null || dst.getParent() != null) {
+ if (
+ src.getSampleModelTranslateX() != 0 ||
+ src.getSampleModelTranslateY() != 0 ||
+ dst.getSampleModelTranslateX() != 0 ||
+ dst.getSampleModelTranslateY() != 0
+ ) {
+ offsets = new int[4];
+ offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
+ offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
+ offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
+ offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
+ }
+ }
+ }
+ }
+
+ int levels[] = new int[4*channels];
+ int values[] = new int[4*channels];
+
+ createLevels(src.getSampleModel(), channels, skipAlpha, levels, values, channelsOrder);
+
+ Object srcData, dstData;
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ srcData = dbAccess.getData(src.getDataBuffer());
+ dstData = dbAccess.getData(dst.getDataBuffer());
+ } catch (IllegalArgumentException e) {
+ return -1; // Unknown data buffer type
+ }
+
+ res = LookupOp.ippLUT(
+ srcData, src.getWidth(), src.getHeight(), srcStride,
+ dstData, dst.getWidth(), dst.getHeight(), dstStride,
+ levels, values,
+ channels, offsets,
+ true
+ );
+
+ return res;
+ }
+}
diff --git a/awt/java/awt/image/SampleModel.java b/awt/java/awt/image/SampleModel.java
new file mode 100644
index 0000000..44059a0
--- /dev/null
+++ b/awt/java/awt/image/SampleModel.java
@@ -0,0 +1,1053 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The SampleModel class is abstract class for retrieving pixel's samples
+ * in the data of an image. Each pixel contains several samples. A
+ * sample is the set of values of the bands for single pixel.
+ * For example, each pixel in the RGB model contains three samples
+ * and there are three corresponding bands in the image
+ * data of such pixels representing red, green and blue components.
+ * <p>
+ * The image data is represented as a Raster with a DataBuffer
+ * and a SampleModel. The SampleModel allows access to the samples in the
+ * DataBuffer.
+ */
+public abstract class SampleModel {
+
+ /** The width of the image data which this SampleModel describes. */
+ protected int width;
+
+ /** The height of the image data which this SampleModel describes. */
+ protected int height;
+
+ /** The number of bands of image data which this SampleModel describes. */
+ protected int numBands;
+
+ /** The data type of the image data which this SampleModel describes. */
+ protected int dataType;
+
+ /**
+ * Instantiates a new SampleModel with the specified data type,
+ * width, height and number of bands.
+ *
+ * @param dataType the data type of the image data.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param numBands the number of bands of the image data.
+ */
+ public SampleModel(int dataType, int w, int h, int numBands) {
+ if (w <= 0 || h <= 0) {
+ // awt.22E=w or h is less than or equal to zero
+ throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$
+ }
+
+ double squre = ((double) w) * ((double) h);
+ if (squre >= Integer.MAX_VALUE) {
+ // awt.22F=The product of w and h is greater than Integer.MAX_VALUE
+ throw new IllegalArgumentException(Messages.getString("awt.22F")); //$NON-NLS-1$
+ }
+
+ if (dataType < DataBuffer.TYPE_BYTE ||
+ dataType > DataBuffer.TYPE_DOUBLE &&
+ dataType != DataBuffer.TYPE_UNDEFINED) {
+ // awt.230=dataType is not one of the supported data types
+ throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$
+ }
+
+ if (numBands < 1) {
+ // awt.231=Number of bands must be more then 0
+ throw new IllegalArgumentException(Messages.getString("awt.231")); //$NON-NLS-1$
+ }
+
+ this.dataType = dataType;
+ this.width = w;
+ this.height = h;
+ this.numBands = numBands;
+
+ }
+
+ /**
+ * Gets the data array for the specified pixel of the specified
+ * DataBuffer with one of the following types:
+ * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+ * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param obj the Object is a data where the result will be stored.
+ * @param data the image data.
+ *
+ * @return the data array for the specified pixel of the specified
+ * DataBuffer.
+ */
+ public abstract Object getDataElements(int x, int y, Object obj,
+ DataBuffer data);
+
+ /**
+ * Gets the array of pixel data for the specified rectangular
+ * area of pixels of the specified DataBuffer with one of
+ * the following types:
+ * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+ * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+ *
+ *
+ * @param x the X coordinate of the rectangular pixel area.
+ * @param y the Y coordinate of the rectangular pixel area.
+ * @param w the width of the rectangular pixel area.
+ * @param h the height of the rectangular pixel area.
+ * @param obj the Object is an array with the primitive type,
+ * where the result array will be stored.
+ * @param data the image data.
+ *
+ * @return the array of pixel data for the specified rectangular
+ * area of pixels of the specified DataBuffer object.
+ */
+ public Object getDataElements(int x, int y, int w, int h, Object obj,
+ DataBuffer data) {
+ int numDataElements = getNumDataElements();
+ int idx = 0;
+
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[];
+ byte bbuf[] = null;
+
+ if (obj == null) {
+ bdata = new byte[numDataElements * w * h];
+ } else {
+ bdata = (byte[]) obj;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ bbuf = (byte[]) getDataElements(j, i, bbuf, data);
+ for (int n = 0; n < numDataElements; n++) {
+ bdata[idx++] = bbuf[n];
+ }
+ }
+ }
+ obj = bdata;
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short sdata[];
+ short sbuf[] = null;
+
+ if (obj == null) {
+ sdata = new short[numDataElements * w * h];
+ } else {
+ sdata = (short[]) obj;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ sbuf = (short[]) getDataElements(j, i, sbuf, data);
+ for (int n = 0; n < numDataElements; n++) {
+ sdata[idx++] = sbuf[n];
+ }
+ }
+ }
+ obj = sdata;
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int idata[];
+ int ibuf[] = null;
+
+ if (obj == null) {
+ idata = new int[numDataElements * w * h];
+ } else {
+ idata = (int[]) obj;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ ibuf = (int[]) getDataElements(j, i, ibuf, data);
+ for (int n = 0; n < numDataElements; n++) {
+ idata[idx++] = ibuf[n];
+ }
+ }
+ }
+ obj = idata;
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fdata[];
+ float fbuf[] = null;
+
+ if (obj == null) {
+ fdata = new float[numDataElements * w * h];
+ } else {
+ fdata = (float[]) obj;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ fbuf = (float[]) getDataElements(j, i, fbuf, data);
+ for (int n = 0; n < numDataElements; n++) {
+ fdata[idx++] = fbuf[n];
+ }
+ }
+ }
+ obj = fdata;
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double ddata[];
+ double dbuf[] = null;
+
+ if (obj == null) {
+ ddata = new double[numDataElements * w * h];
+ } else {
+ ddata = (double[]) obj;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ dbuf = (double[]) getDataElements(j, i, dbuf, data);
+ for (int n = 0; n < numDataElements; n++) {
+ ddata[idx++] = dbuf[n];
+ }
+ }
+ }
+ obj = ddata;
+ break;
+
+ }
+
+ return obj;
+ }
+
+ /**
+ * Sets the data for a single pixel in the specified DataBuffer
+ * from a primitive array with one of the following types:
+ * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+ * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param obj the Object - the array of primitive pixel data
+ * to be set.
+ * @param data the image data.
+ */
+ public abstract void setDataElements(int x, int y, Object obj,
+ DataBuffer data);
+
+ /**
+ * Sets the data elements for a rectangular area of pixels in
+ * the specified DataBuffer from a primitive array with one of
+ * the following types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+ * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of the specified rectangular area.
+ * @param y the Y coordinate of the specified rectangular area.
+ * @param w the width of rectangle.
+ * @param h the height of rectangle.
+ * @param obj the Object - the array of primitive pixel data
+ * to be set.
+ * @param data the image data.
+ */
+ public void setDataElements(int x, int y, int w, int h, Object obj,
+ DataBuffer data) {
+ int numDataElements = getNumDataElements();
+ int idx = 0;
+
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ byte bbuf[] = new byte[numDataElements];
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numDataElements; n++) {
+ bbuf[n] = ((byte[]) obj)[idx++];
+ }
+ setDataElements(j, i, bbuf, data);
+ }
+ }
+
+ break;
+
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short sbuf[] = new short[numDataElements];
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numDataElements; n++) {
+ sbuf[n] = ((short[]) obj)[idx++];
+ }
+ setDataElements(j, i, sbuf, data);
+ }
+ }
+ break;
+
+ case DataBuffer.TYPE_INT:
+ int ibuf[] = new int[numDataElements];
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numDataElements; n++) {
+ ibuf[n] = ((int[]) obj)[idx++];
+ }
+ setDataElements(j, i, ibuf, data);
+ }
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fbuf[] = new float[numDataElements];
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numDataElements; n++) {
+ fbuf[n] = ((float[]) obj)[idx++];
+ }
+ setDataElements(j, i, fbuf, data);
+ }
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double dbuf[] = new double[numDataElements];
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numDataElements; n++) {
+ dbuf[n] = ((double[]) obj)[idx++];
+ }
+ setDataElements(j, i, dbuf, data);
+ }
+ }
+ break;
+
+ }
+ }
+
+ /**
+ * Creates a new SampleModel with the specified bands of
+ * this SampleModel.
+ *
+ * @param bands the array of bands from this SampleModel.
+ *
+ * @return the SampleModel with the specified bands of
+ * this SampleModel.
+ */
+ public abstract SampleModel createSubsetSampleModel(int bands[]);
+
+ /**
+ * Creates the SampleModel which has the same data as in
+ * this SampleModel with a different width and height.
+ *
+ * @param a0 the width of the image data.
+ * @param a1 the height of the image data.
+ *
+ * @return the SampleModel which has the same data as in
+ * this SampleModel with a different width and height.
+ */
+ public abstract SampleModel createCompatibleSampleModel(int a0, int a1);
+
+ /**
+ * Gets the samples of the specified pixel as a int array.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param iArray the int array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the int array with the samples of the specified pixel.
+
+ */
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int pixel[];
+
+ if (iArray == null) {
+ pixel = new int[numBands];
+ } else {
+ pixel = iArray;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ pixel[i] = getSample(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ /**
+ * Sets a pixel of the DataBuffer from a int array of samples.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param iArray the int array.
+ * @param data the image data.
+ */
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, iArray[i], data);
+ }
+ }
+
+ /**
+ * Gets the samples of the specified pixel as a float array.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param fArray the float array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the float array with the samples of the specified pixel.
+ */
+ public float[] getPixel(int x, int y, float fArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ float pixel[];
+
+ if (fArray == null) {
+ pixel = new float[numBands];
+ } else {
+ pixel = fArray;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ pixel[i] = getSampleFloat(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ /**
+ * Sets a pixel of the DataBuffer from a float array of samples.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param fArray the float array.
+ * @param data the image data.
+ */
+ public void setPixel(int x, int y, float fArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, fArray[i], data);
+ }
+ }
+
+ /**
+ * Gets the samples of the specified pixel as a double array.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param dArray the double array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the double array with the samples of the specified pixel.
+ */
+ public double[] getPixel(int x, int y, double dArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ double pixel[];
+
+ if (dArray == null) {
+ pixel = new double[numBands];
+ } else {
+ pixel = dArray;
+ }
+
+ for (int i = 0; i < numBands; i++) {
+ pixel[i] = getSampleDouble(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ /**
+ * Sets a pixel of the DataBuffer from a double array of samples.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param dArray the double array.
+ * @param data the image data.
+ */
+ public void setPixel(int x, int y, double dArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ for (int i = 0; i < numBands; i++) {
+ setSample(x, y, i, dArray[i], data);
+ }
+ }
+
+ /**
+ * Gets the sample of a specified band for the specified pixel
+ * as an int.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param b the specified band.
+ * @param data the image data.
+ *
+ * @return the sample of a specified band for the specified pixel.
+ */
+ public abstract int getSample(int x, int y, int b, DataBuffer data);
+
+ /**
+ * Gets the sample of a specified band for the specified pixel
+ * as a float.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param b the specified band.
+ * @param data the image data.
+ *
+ * @return the sample of a specified band for the specified pixel.
+
+ */
+ public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+ return getSample(x, y, b, data);
+ }
+
+ /**
+ * Gets the sample of a specified band for the specified pixel
+ * as a double.
+ *
+ * @param x the X coordinate of pixel.
+ * @param y the Y coordinate of pixel.
+ * @param b the specified band.
+ * @param data the image data.
+ *
+ * @return the sample of a specified band for the specified pixel.
+ */
+ public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+ return getSample(x, y, b, data);
+ }
+
+ /**
+ * Gets the samples of the specified rectangular area of pixels
+ * as a int array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param iArray the int array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the int array with the samples of the specified
+ * rectangular area of pixels.
+ */
+ public int[] getPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int pixels[];
+ int idx = 0;
+
+ if (iArray == null) {
+ pixels = new int[w * h * numBands];
+ } else {
+ pixels = iArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ pixels[idx++] = getSample(j, i, n, data);
+ }
+ }
+ }
+ return pixels;
+ }
+
+ /**
+ * Sets all of the samples for a rectangular area of pixels of the DataBuffer
+ * from an int array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param iArray the int array.
+ * @param data the image data.
+ */
+ public void setPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ setSample(j, i, n, iArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the samples of the specified rectangular area of pixels
+ * as a float array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param fArray the float array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the float array with the samples of the specified
+ * rectangular area of pixels.
+ */
+ public float[] getPixels(int x, int y, int w, int h, float fArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ float pixels[];
+ int idx = 0;
+
+ if (fArray == null) {
+ pixels = new float[w * h * numBands];
+ } else {
+ pixels = fArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ pixels[idx++] = getSampleFloat(j, i, n, data);
+ }
+ }
+ }
+ return pixels;
+ }
+
+ /**
+ * Sets all of the samples for a rectangular area of pixels of the DataBuffer
+ * from a float array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param fArray the float array.
+ * @param data the image data.
+ */
+ public void setPixels(int x, int y, int w, int h, float fArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ setSample(j, i, n, fArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the samples of the specified rectangular area of pixels
+ * as a double array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param dArray the double array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the double array with the samples of the specified
+ * rectangular area of pixels.
+ */
+ public double[] getPixels(int x, int y, int w, int h, double dArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ double pixels[];
+ int idx = 0;
+
+ if (dArray == null) {
+ pixels = new double[w * h * numBands];
+ } else {
+ pixels = dArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ pixels[idx++] = getSampleDouble(j, i, n, data);
+ }
+ }
+ }
+ return pixels;
+ }
+
+ /**
+ * Sets all of the samples for a rectangular area of pixels of the DataBuffer
+ * from a double array.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param dArray the double array.
+ * @param data the image data.
+ */
+ public void setPixels(int x, int y, int w, int h, double dArray[],
+ DataBuffer data) {
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < numBands; n++) {
+ setSample(j, i, n, dArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets a sample of the specified band for the specified pixel
+ * in the DataBuffer as int value.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample as an int value.
+ * @param data the image data.
+ */
+ public abstract void setSample(int x, int y, int b, int s, DataBuffer data);
+
+ /**
+ * Gets the samples of a specified band for a specified rectangular
+ * area of pixels as a int array.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param iArray the int array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the samples of a specified band for a specified rectangular
+ * area of pixels.
+ */
+ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ int samples[];
+ int idx = 0;
+
+ if (iArray == null) {
+ samples = new int[w * h];
+ } else {
+ samples = iArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSample(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ /**
+ * Sets the samples from an int array in the specified band for
+ * the specified rectangle of pixels.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param iArray the int array.
+ * @param data the image data.
+ */
+ public void setSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(j, i, b, iArray[idx++], data);
+ }
+ }
+ }
+
+ /**
+ * Gets the samples of a specified band for a specified rectangular
+ * area of pixels as a float array.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param fArray the float array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the samples of a specified band for a specified rectangular
+ * area of pixels.
+ */
+ public float[] getSamples(int x, int y, int w, int h, int b,
+ float fArray[], DataBuffer data) {
+ float samples[];
+ int idx = 0;
+
+ if (fArray == null) {
+ samples = new float[w * h];
+ } else {
+ samples = fArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSampleFloat(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ /**
+ * Sets the samples from an float array in the specified band for
+ * the specified rectangle of pixels.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param fArray the float array
+ * @param data the image data.
+ */
+ public void setSamples(int x, int y, int w, int h, int b, float fArray[],
+ DataBuffer data) {
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(j, i, b, fArray[idx++], data);
+ }
+ }
+ }
+
+ /**
+ * Gets the samples of a specified band for a specified rectangular
+ * area of pixels as a double array.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param dArray the double array where result will be stored.
+ * @param data the image data.
+ *
+ * @return the samples of a specified band for a specified rectangular
+ * area of pixels.
+ */
+ public double[] getSamples(int x, int y, int w, int h, int b,
+ double dArray[], DataBuffer data) {
+ double samples[];
+ int idx = 0;
+
+ if (dArray == null) {
+ samples = new double[w * h];
+ } else {
+ samples = dArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSampleDouble(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ /**
+ * Sets the samples from an double array in the specified band for
+ * the specified rectangle of pixels.
+ *
+ * @param x the X coordinate of the rectangle.
+ * @param y the Y coordinate of the rectangle.
+ * @param w the width of the rectangle.
+ * @param h the height of the rectangle.
+ * @param b the specified band.
+ * @param dArray the double array
+ * @param data the image data.
+ */
+ public void setSamples(int x, int y, int w, int h, int b, double dArray[],
+ DataBuffer data) {
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(j, i, b, dArray[idx++], data);
+ }
+ }
+ }
+
+ /**
+ * Sets a sample of the specified band for the specified pixel
+ * in the DataBuffer as float value.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample as float value.
+ * @param data the image data.
+ */
+ public void setSample(int x, int y, int b, float s, DataBuffer data) {
+ setSample(x, y, b, (int) s, data);
+ }
+
+ /**
+ * Sets a sample of the specified band for the specified pixel
+ * in the DataBuffer as double value.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample as double value.
+ * @param data the image data.
+ */
+ public void setSample(int x, int y, int b, double s, DataBuffer data) {
+ setSample(x, y, b, (int) s, data);
+ }
+
+ /**
+ * Creates a DataBuffer object which corresponds to the SampleModel.
+ *
+ * @return the DataBuffer object which corresponds to
+ * the SampleModel.
+ */
+ public abstract DataBuffer createDataBuffer();
+
+ /**
+ * Gets the sample size in bits for the specified band.
+ *
+ * @param band the specified band.
+ *
+ * @return the sample size in bits for the specified band.
+ */
+ public abstract int getSampleSize(int band);
+
+ /**
+ * Gets an array of the sample size in bits for all bands.
+ *
+ * @return an array of the sample size in bits for all bands.
+ */
+ public abstract int[] getSampleSize();
+
+ /**
+ * Gets the width of the image data of this SampleModel object.
+ *
+ * @return the width of the image data of this SampleModel object.
+ */
+ public final int getWidth() {
+ return width;
+ }
+
+ /**
+ * Gets the transfer type used to transfer pixels via
+ * the getDataElements and setDataElements methods.
+ * Transfer type value can be one of the predefined type
+ * from DataBuffer class or not.
+ *
+ * @return the transfer type.
+ */
+ public int getTransferType() {
+ return dataType;
+ }
+
+ /**
+ * Returns the number of data elements for pixel transfering
+ * via the getDataElements and setDataElements methods.
+ *
+ * @return the number of data elements for pixel transfering
+ * via the getDataElements and setDataElements methods.
+ */
+ public abstract int getNumDataElements();
+
+ /**
+ * Gets the number of bands in the image data of this
+ * SampleModel object.
+ *
+ * @return the number of bands in the image data of this
+ * SampleModel object.
+ */
+ public final int getNumBands() {
+ return numBands;
+ }
+
+ /**
+ * Gets the height of the image data of this SampleModel object.
+ *
+ * @return the height of the image data of this SampleModel object.
+ */
+ public final int getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the data type of image data of this SampleModel object.
+ *
+ * @return the data type of image data of this SampleModel object.
+ */
+ public final int getDataType() {
+ return dataType;
+ }
+
+}
+
diff --git a/awt/java/awt/image/ShortLookupTable.java b/awt/java/awt/image/ShortLookupTable.java
new file mode 100644
index 0000000..77c9c45
--- /dev/null
+++ b/awt/java/awt/image/ShortLookupTable.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Oct 14, 2005
+ */
+
+package java.awt.image;
+
+
+/**
+ * The ShortLookupTable class provides provides functionality for
+ * lookup operations, and is defined by an input short array for
+ * bands or components of image and an offset value.
+ * The offset value will be subtracted from the input values before
+ * indexing the input arrays. The output of a lookup operation is
+ * represented as an unsigned short array.
+ */
+public class ShortLookupTable extends LookupTable {
+
+ /** The data. */
+ private short data[][];
+
+ /**
+ * Instantiates a new ShortLookupTable with the specified offset value
+ * and the specified short array which represents lookup table for
+ * all bands.
+ *
+ * @param offset the offset value.
+ * @param data the data array.
+ */
+ public ShortLookupTable(int offset, short[] data) {
+ super(offset, 1);
+ this.data = new short[1][data.length];
+ // The data array stored as a reference
+ this.data[0] = data;
+ }
+
+ /**
+ * Instantiates a new ShortLookupTable with the specified offset value
+ * and the specified short array of arrays which represents lookup table
+ * for each band.
+ *
+ * @param offset the offset value.
+ * @param data the data array of arrays for each band.
+ */
+ public ShortLookupTable(int offset, short[][] data) {
+ super(offset, data.length);
+ this.data = new short[data.length][data[0].length];
+ for (int i = 0; i < data.length; i++) {
+ // The data array for each band stored as a reference
+ this.data[i] = data[i];
+ }
+ }
+
+ /**
+ * Gets the lookup table of this ShortLookupTable object. If
+ * this ShortLookupTable object has one short array for all bands,
+ * the returned array length is one.
+ *
+ * @return the lookup table of this ShortLookupTable object.
+ */
+ public final short[][] getTable() {
+ return data;
+ }
+
+ /**
+ * Returns a short array which contains samples of the specified
+ * pixel which is translated with the lookup table of this
+ * ShortLookupTable object. The resulted array is stored to
+ * the dst array.
+ *
+ * @param src the source array.
+ * @param dst the destination array where the result can be stored.
+ *
+ * @return the short array of translated samples of a pixel.
+ */
+ public short[] lookupPixel(short[] src, short[] dst) {
+ if (dst == null) {
+ dst = new short[src.length];
+ }
+
+ int offset = getOffset();
+ if (getNumComponents() == 1) {
+ for (int i = 0; i < src.length; i++) {
+ dst[i] = data[0][src[i]-offset];
+ }
+ } else {
+ for (int i = 0; i < getNumComponents(); i++) {
+ dst[i] = data[i][src[i]-offset];
+ }
+ }
+
+ return dst;
+ }
+
+ @Override
+ public int[] lookupPixel(int[] src, int[] dst) {
+ if (dst == null) {
+ dst = new int[src.length];
+ }
+
+ int offset = getOffset();
+ if (getNumComponents() == 1) {
+ for (int i = 0; i < src.length; i++) {
+ dst[i] = data[0][src[i]-offset];
+ }
+ } else {
+ for (int i = 0; i < getNumComponents(); i++) {
+ dst[i] = data[i][src[i]-offset];
+ }
+ }
+
+ return dst;
+ }
+}
diff --git a/awt/java/awt/image/SinglePixelPackedSampleModel.java b/awt/java/awt/image/SinglePixelPackedSampleModel.java
new file mode 100644
index 0000000..311395a
--- /dev/null
+++ b/awt/java/awt/image/SinglePixelPackedSampleModel.java
@@ -0,0 +1,508 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The SinglePixelPackedSampleModel class represents pixel data
+ * where several samples combine to create a single pixel and
+ * are stored in a single data array element. This class
+ * supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data types.
+ */
+public class SinglePixelPackedSampleModel extends SampleModel {
+
+ /** The bit masks. */
+ private int bitMasks[];
+
+ /** The bit offsets. */
+ private int bitOffsets[];
+
+ /** The bit sizes. */
+ private int bitSizes[];
+
+ /** The scanline stride. */
+ private int scanlineStride;
+
+ /** The max bit size. */
+ private int maxBitSize;
+
+ /**
+ * Instantiates a new SinglePixelPackedSampleModel with the specified
+ * parameters.
+ *
+ * @param dataType the data type of samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param bitMasks the bit masks for all the bands.
+ */
+ public SinglePixelPackedSampleModel(int dataType, int w, int h,
+ int bitMasks[]) {
+ this(dataType, w, h, w, bitMasks);
+ }
+
+ /**
+ * Instantiates a new SinglePixelPackedSampleModel with the specified
+ * parameters.
+ *
+ * @param dataType the data type of the samples.
+ * @param w the width of the image data.
+ * @param h the height of the image data.
+ * @param scanlineStride The scanline stride of the image data.
+ * @param bitMasks the bit masks for all the bands.
+ */
+ public SinglePixelPackedSampleModel(int dataType, int w, int h,
+ int scanlineStride, int bitMasks[]) {
+
+ super(dataType, w, h, bitMasks.length);
+
+ if (dataType != DataBuffer.TYPE_BYTE &&
+ dataType != DataBuffer.TYPE_USHORT &&
+ dataType != DataBuffer.TYPE_INT) {
+ // awt.61=Unsupported data type: {0}
+ throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$
+ dataType));
+ }
+
+ this.scanlineStride = scanlineStride;
+ this.bitMasks = bitMasks.clone();
+ this.bitOffsets = new int[this.numBands];
+ this.bitSizes = new int[this.numBands];
+
+ this.maxBitSize = 0;
+
+ for (int i = 0; i < this.numBands; i++) {
+ int offset = 0;
+ int size = 0;
+ int mask = bitMasks[i];
+
+ if (mask != 0) {
+ while ((mask & 1) == 0) {
+ mask >>>= 1;
+ offset++;
+ }
+
+ while ((mask & 1) == 1) {
+ mask >>>= 1;
+ size++;
+ }
+
+ if (mask != 0) {
+ // awt.62=Wrong mask : {0}
+ throw new IllegalArgumentException(Messages.getString(
+ "awt.62", bitMasks[i])); //$NON-NLS-1$
+ }
+ }
+
+ this.bitOffsets[i] = offset;
+ this.bitSizes[i] = size;
+
+ if (this.maxBitSize < size) {
+ this.maxBitSize = size;
+ }
+
+ }
+
+ }
+
+ @Override
+ public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ byte bdata[];
+ if (obj == null) {
+ bdata = new byte[1];
+ } else {
+ bdata = (byte[]) obj;
+ }
+
+ bdata[0] = (byte) data.getElem(y * scanlineStride + x);
+ obj = bdata;
+ break;
+ case DataBuffer.TYPE_USHORT:
+ short sdata[];
+ if (obj == null) {
+ sdata = new short[1];
+ } else {
+ sdata = (short[]) obj;
+ }
+
+ sdata[0] = (short) data.getElem(y * scanlineStride + x);
+ obj = sdata;
+ break;
+ case DataBuffer.TYPE_INT:
+ int idata[];
+ if (obj == null) {
+ idata = new int[1];
+ } else {
+ idata = (int[]) obj;
+ }
+
+ idata[0] = data.getElem(y * scanlineStride + x);
+ obj = idata;
+ break;
+ }
+ return obj;
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ switch (getTransferType()) {
+ case DataBuffer.TYPE_BYTE:
+ data.setElem(y * scanlineStride + x, ((byte[]) obj)[0] & 0xff);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data.setElem(y * scanlineStride + x, ((short[]) obj)[0] & 0xffff);
+ break;
+ case DataBuffer.TYPE_INT:
+ data.setElem(y * scanlineStride + x, ((int[]) obj)[0]);
+ break;
+ }
+ }
+
+ /**
+ * Compares this SinglePixelPackedSampleModel object with
+ * the specified object.
+ *
+ * @param o the Object to be compared.
+ *
+ * @return true, if this SinglePixelPackedSampleModel object is
+ * equal to the specified object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) {
+ return false;
+ }
+
+ SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel) o;
+ return this.width == model.width &&
+ this.height == model.height &&
+ this.numBands == model.numBands &&
+ this.dataType == model.dataType &&
+ Arrays.equals(this.bitMasks, model.bitMasks) &&
+ Arrays.equals(this.bitOffsets, model.bitOffsets) &&
+ Arrays.equals(this.bitSizes, model.bitSizes) &&
+ this.scanlineStride == model.scanlineStride;
+ }
+
+ @Override
+ public SampleModel createSubsetSampleModel(int bands[]) {
+ if (bands.length > this.numBands) {
+ // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model
+ throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
+ }
+
+ int masks[] = new int[bands.length];
+ for (int i = 0; i < bands.length; i++) {
+ masks[i] = this.bitMasks[bands[i]];
+ }
+ return new SinglePixelPackedSampleModel(this.dataType, this.width,
+ this.height, this.scanlineStride, masks);
+ }
+
+ @Override
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ return new SinglePixelPackedSampleModel(this.dataType, w, h,
+ this.bitMasks);
+ }
+
+ @Override
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int pixel[];
+ if (iArray == null) {
+ pixel = new int[this.numBands];
+ } else {
+ pixel = iArray;
+ }
+
+ for (int i = 0; i < this.numBands; i++) {
+ pixel[i] = getSample(x, y, i, data);
+ }
+
+ return pixel;
+ }
+
+ @Override
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ for (int i = 0; i < this.numBands; i++) {
+ setSample(x, y, i, iArray[i], data);
+ }
+ }
+
+ @Override
+ public int getSample(int x, int y, int b, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int sample = data.getElem(y * scanlineStride + x);
+ return ((sample & this.bitMasks[b]) >>> this.bitOffsets[b]);
+ }
+
+ @Override
+ public int[] getPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width)
+ || ((long) y + (long) h > this.height)) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int pixels[];
+
+ if (iArray == null) {
+ pixels = new int[w * h * this.numBands];
+ } else {
+ pixels = iArray;
+ }
+
+ int idx = 0;
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < this.numBands; n++) {
+ pixels[idx++] = getSample(j, i, n, data);
+ }
+ }
+ }
+ return pixels;
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, int iArray[],
+ DataBuffer data) {
+ if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width)
+ || ((long) y + (long) h > this.height)) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages
+ .getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int idx = 0;
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ for (int n = 0; n < this.numBands; n++) {
+ setSample(j, i, n, iArray[idx++], data);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s, DataBuffer data) {
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+ int tmp = data.getElem(y * scanlineStride + x);
+ tmp &= ~this.bitMasks[b];
+ tmp |= (s << this.bitOffsets[b]) & this.bitMasks[b];
+ data.setElem(y * scanlineStride + x, tmp);
+ }
+
+ @Override
+ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width)
+ || ((long) y + (long) h > this.height)) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages
+ .getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int samples[];
+ int idx = 0;
+
+ if (iArray == null) {
+ samples = new int[w * h];
+ } else {
+ samples = iArray;
+ }
+
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ samples[idx++] = getSample(j, i, b, data);
+ }
+ }
+
+ return samples;
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, int iArray[],
+ DataBuffer data) {
+ if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width)
+ || ((long) y + (long) h > this.height)) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int idx = 0;
+ for (int i = y; i < y + h; i++) {
+ for (int j = x; j < x + w; j++) {
+ setSample(x + j, y + i, b, iArray[idx++], data);
+ }
+ }
+ }
+
+ @Override
+ public DataBuffer createDataBuffer() {
+ DataBuffer data = null;
+ int size = (this.height - 1) * scanlineStride + width;
+
+ switch (this.dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new DataBufferByte(size);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new DataBufferUShort(size);
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new DataBufferInt(size);
+ break;
+ }
+ return data;
+ }
+
+ /**
+ * Gets the offset of the specified pixel in the data array.
+ *
+ * @param x the X coordinate of the specified pixel.
+ * @param y the Y coordinate of the specified pixel.
+ *
+ * @return the offset of the specified pixel.
+ */
+ public int getOffset(int x, int y) {
+ return (y * scanlineStride + x);
+ }
+
+ @Override
+ public int getSampleSize(int band) {
+ return bitSizes[band];
+ }
+
+ @Override
+ public int[] getSampleSize() {
+ return bitSizes.clone();
+ }
+
+ /**
+ * Gets an array of the bit offsets of the data array elements.
+ *
+ * @return an array of the bit offsets.
+ */
+ public int[] getBitOffsets() {
+ return bitOffsets.clone();
+ }
+
+ /**
+ * Gets an array of the bit masks for all bands.
+ *
+ * @return an array of the bit masks for all bands.
+ */
+ public int[] getBitMasks() {
+ return bitMasks.clone();
+ }
+
+ /**
+ * Returns a hash code of this MultiPixelPackedSampleModel class.
+ *
+ * @return the hash code of this MultiPixelPackedSampleModel class.
+ */
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ int tmp = 0;
+
+ hash = width;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= height;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= numBands;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ hash ^= dataType;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ for (int element : bitMasks) {
+ hash ^= element;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ }
+ for (int element : bitOffsets) {
+ hash ^= element;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ }
+ for (int element : bitSizes) {
+ hash ^= element;
+ tmp = hash >>> 24;
+ hash <<= 8;
+ hash |= tmp;
+ }
+ hash ^= scanlineStride;
+ return hash;
+ }
+
+ /**
+ * Gets the scanline stride.
+ *
+ * @return the scanline stride
+ */
+ public int getScanlineStride() {
+ return this.scanlineStride;
+ }
+
+ @Override
+ public int getNumDataElements() {
+ return 1;
+ }
+
+}
+
diff --git a/awt/java/awt/image/TileObserver.java b/awt/java/awt/image/TileObserver.java
new file mode 100644
index 0000000..39ded02
--- /dev/null
+++ b/awt/java/awt/image/TileObserver.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+
+/**
+ * An asynchronous update interface for receiving notifications
+ * about tile information when tiles of a WritableRenderedImage
+ * become modifiable or unmodifiable.
+ */
+public interface TileObserver {
+
+ /**
+ * This method is called when information about a tile
+ * update is available.
+ *
+ * @param source the source image.
+ * @param tileX the X index of the tile.
+ * @param tileY the Y index of the tile.
+ * @param willBeWritable parameter which indicates whether
+ * the tile will be grabbed for writing or be released.
+ */
+ public void tileUpdate(WritableRenderedImage source, int tileX, int tileY, boolean willBeWritable);
+
+}
+
diff --git a/awt/java/awt/image/VolatileImage.java b/awt/java/awt/image/VolatileImage.java
new file mode 100644
index 0000000..3b0cfb2
--- /dev/null
+++ b/awt/java/awt/image/VolatileImage.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.ImageCapabilities;
+import java.awt.Transparency;
+
+/**
+ * The VolatileImage abstract class represents an image which can lose
+ * its contents at any point. VolatileImage objects are device specific.
+ * This class provies methods for checking if operation of this image
+ * are compatible for the GraphicsConfiguration.
+ */
+public abstract class VolatileImage extends Image
+ // Volatile image implements Transparency since 1.5
+ implements Transparency {
+
+ /**
+ * The Constant IMAGE_INCOMPATIBLE indicates that this VolatileImage
+ * is not applicable for the GraphicsConfiguration object.
+ */
+ public static final int IMAGE_INCOMPATIBLE = 2;
+
+ /**
+ * The Constant IMAGE_OK indicates that VolatileImage is ready
+ * for using.
+ */
+ public static final int IMAGE_OK = 0;
+
+ /**
+ * The Constant IMAGE_RESTORED indicates that VolatileImage
+ * will be ready to use after restoring.
+ */
+ public static final int IMAGE_RESTORED = 1;
+
+ /**
+ * The transparency value of this image.
+ */
+ protected int transparency = OPAQUE;
+
+ /**
+ * Instantiates a new VolatileImage object.
+ */
+ public VolatileImage() {
+ super();
+ }
+
+ /**
+ * Returns true if rendering data is lost during validating.
+ * This method should be called after rendering operation of image.
+ *
+ * @return true, if contents lost during validating, false otherwise.
+ */
+
+ public abstract boolean contentsLost();
+
+ /**
+ * Creates a Graphics2D used to draw in this VolatileImage.
+ *
+ * @return the Graphics2D object.
+ */
+ public abstract Graphics2D createGraphics();
+
+ /**
+ * Gets the ImageCapabilities of this VolatileImage.
+ *
+ * @return the ImageCapabilities of this VolatileImage.
+ */
+ public abstract ImageCapabilities getCapabilities();
+
+ /**
+ * Gets the height of this VolatileImage.
+ *
+ * @return the height of this VolatileImage.
+ */
+ public abstract int getHeight();
+
+ /**
+ * Gets a BufferedImage representation of current VolatileImage that
+ * won't be affected by any changes to this VolatileImage.
+ *
+ * @return a BufferedImage representation of current VolatileImage.
+ */
+ public abstract BufferedImage getSnapshot();
+
+ /**
+ * Gets the width of this VolatileImage.
+ *
+ * @return the width of this VolatileImage.
+ */
+ public abstract int getWidth();
+
+ /**
+ * Validates the drawing surface of the image if the surface had been
+ * lost and if the spacified GraphicsConfiguration object is
+ * applicable to this image.
+ *
+ * @param gc GraphicsConfiguration object.
+ *
+ * @return one of the image status constants: IMAGE_OK, IMAGE_RESTORED or
+ * IMAGE_INCOMPATIBLE.
+ */
+ public abstract int validate(GraphicsConfiguration gc);
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public Graphics getGraphics() {
+ return createGraphics();
+ }
+
+ @Override
+ public ImageProducer getSource() {
+ return getSnapshot().getSource();
+ }
+
+ public int getTransparency() {
+ return transparency;
+ }
+}
diff --git a/awt/java/awt/image/WritableRaster.java b/awt/java/awt/image/WritableRaster.java
new file mode 100644
index 0000000..0893915
--- /dev/null
+++ b/awt/java/awt/image/WritableRaster.java
@@ -0,0 +1,516 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The WritableRaster class provides functionality for
+ * writing samples and pixel capabilities to the Raster.
+ */
+public class WritableRaster extends Raster {
+
+ /**
+ * Instantiates a new WritableRaster object with the specified
+ * SampleModel, DataBuffer, rectangular region and parent
+ * WritableRaster.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param dataBuffer the specified DataBuffer.
+ * @param aRegion the rectangular region which defines the new image bounds.
+ * @param sampleModelTranslate this point defines the translation point
+ * from the SampleModel to the new WritableRaster coordinates.
+ * @param parent the parent of this WritableRaster.
+ */
+ protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer,
+ Rectangle aRegion, Point sampleModelTranslate,
+ WritableRaster parent) {
+ super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent);
+ }
+
+ /**
+ * Instantiates a new WritableRaster object with the specified
+ * SampleModel which defines a layout of this WritableRaster and
+ * DataBuffer objects which defines the image data.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param dataBuffer the specified DataBuffer.
+ * @param origin the point of origin.
+ */
+ protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer,
+ Point origin) {
+ this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y,
+ sampleModel.width, sampleModel.height), origin, null);
+ }
+
+ /**
+ * Instantiates a new WritableRaster with the specified SampleModel.
+ *
+ * @param sampleModel the specified SampleModel.
+ * @param origin the origin.
+ */
+ protected WritableRaster(SampleModel sampleModel, Point origin) {
+ this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(
+ origin.x, origin.y, sampleModel.width, sampleModel.height),
+ origin, null);
+ }
+
+ /**
+ * Sets the data for a single pixel from an input Object which
+ * represents an array of primitive types: DataBuffer.TYPE_BYTE,
+ * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+ * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param inData the input data.
+ */
+ public void setDataElements(int x, int y, Object inData) {
+ sampleModel.setDataElements(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, inData, dataBuffer);
+ }
+
+ /**
+ * Sets the data elements which represent pixel data to the specified
+ * rectangle area as a primitive array. The following image data types
+ * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
+ * or DataBuffer.TYPE_DOUBLE.
+ *
+ * @param x the X coordinate of the rectangle of pixels.
+ * @param y the Y coordinate of the rectangle of pixels.
+ * @param w the width of the rectangle of pixels.
+ * @param h the height of the rectangle of pixels.
+ * @param inData the array of primitive type data to be set to the
+ * specified area.
+ */
+ public void setDataElements(int x, int y, int w, int h, Object inData) {
+ sampleModel.setDataElements(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, inData, dataBuffer);
+ }
+
+ /**
+ * Creates the child of this WritableRaster by sharing the specified
+ * rectangular area in this WritableRaster.
+ * The parentX, parentY, width and height parameters specify rectangular
+ * area to be shared.
+ *
+ * @param parentX the X coordinate of the upper left corner of
+ * the shared rectangle with respect to this WritableRaster' coordinates.
+ * @param parentY the Y coordinate of the upper left corner of
+ * the shared rectangle with respect to this WritableRaster' coordinates.
+ * @param w the width of the child area.
+ * @param h the height of the child area.
+ * @param childMinX the X coordinate of child area mapped to the parentX
+ * coordinate.
+ * @param childMinY the Y coordinate of child area mapped to the parentY
+ * coordinate.
+ * @param bandList the array of band indicies.
+ *
+ * @return the child WritableRaster.
+ */
+ public WritableRaster createWritableChild(int parentX, int parentY, int w,
+ int h, int childMinX, int childMinY, int bandList[]) {
+ if (w <= 0 || h <= 0) {
+ // awt.244=Width or Height of child Raster is less than or equal to zero
+ throw new RasterFormatException(Messages.getString("awt.244")); //$NON-NLS-1$
+ }
+
+ if (parentX < this.minX || parentX + w > this.minX + this.width) {
+ // awt.245=parentX disposes outside Raster
+ throw new RasterFormatException(Messages.getString("awt.245")); //$NON-NLS-1$
+ }
+
+ if (parentY < this.minY || parentY + h > this.minY + this.height) {
+ // awt.246=parentY disposes outside Raster
+ throw new RasterFormatException(Messages.getString("awt.246")); //$NON-NLS-1$
+ }
+
+ if ((long) parentX + w > Integer.MAX_VALUE) {
+ // awt.247=parentX + w results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.247")); //$NON-NLS-1$
+ }
+
+ if ((long) parentY + h > Integer.MAX_VALUE) {
+ // awt.248=parentY + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.248")); //$NON-NLS-1$
+ }
+
+ if ((long) childMinX + w > Integer.MAX_VALUE) {
+ // awt.249=childMinX + w results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.249")); //$NON-NLS-1$
+ }
+
+ if ((long) childMinY + h > Integer.MAX_VALUE) {
+ // awt.24A=childMinY + h results in integer overflow
+ throw new RasterFormatException(Messages.getString("awt.24A")); //$NON-NLS-1$
+ }
+
+ SampleModel childModel;
+
+ if (bandList == null) {
+ childModel = sampleModel;
+ } else {
+ childModel = sampleModel.createSubsetSampleModel(bandList);
+ }
+
+ int childTranslateX = childMinX - parentX;
+ int childTranslateY = childMinY - parentY;
+
+ return new WritableRaster(childModel, dataBuffer,
+ new Rectangle(childMinX, childMinY, w, h),
+ new Point(childTranslateX + sampleModelTranslateX,
+ childTranslateY + sampleModelTranslateY),
+ this);
+ }
+
+ /**
+ * Creates the translated child of this WritableRaster.
+ * New WritableRaster object is a reference to the this
+ * WritableRaster and with different location.
+ *
+ * @param childMinX the X coordinate of the new WritableRaster.
+ * @param childMinY the Y coordinate of the new WritableRaster.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster createWritableTranslatedChild(int childMinX,
+ int childMinY) {
+ return createWritableChild(minX, minY, width, height, childMinX,
+ childMinY, null);
+ }
+
+ /**
+ * Gets the parent WritableRaster for this WritableRaster object.
+ *
+ * @return the parent WritableRaster for this WritableRaster object.
+ */
+ public WritableRaster getWritableParent() {
+ return (WritableRaster) parent;
+ }
+
+ /**
+ * Sets pixels from the specified source Raster srcRaster to this
+ * WritableRaster.
+ *
+ * @param srcRaster the source Raster.
+ */
+ public void setRect(Raster srcRaster) {
+ setRect(0, 0, srcRaster);
+ }
+
+ /**
+ * Sets pixels from the specified source Raster srcRaster to this
+ * WritableRaster. Each pixel with (x, y) coordinates from the source
+ * Raster is copied to pixel with (x+dx, y+dy) coordinates in this
+ * WritableRaster. The pixels with (x+dx, y+dy) coordinates which
+ * are out the bounds of this raster are ignored.
+ *
+ * @param dx the distance the pixel's X coordinate in the source
+ * Raster is translated when writtien to this WritableRaster.
+ * @param dy the distance the pixel's Y coordinate in the source
+ * Raster is translated when writtien to this WritableRaster.
+ * @param srcRaster the source Raster.
+ */
+ public void setRect(int dx, int dy, Raster srcRaster) {
+ int w = srcRaster.getWidth();
+ int h = srcRaster.getHeight();
+
+ int srcX = srcRaster.getMinX();
+ int srcY = srcRaster.getMinY();
+
+ int dstX = srcX + dx;
+ int dstY = srcY + dy;
+
+ if (dstX < this.minX) {
+ int minOffX = this.minX - dstX;
+ w -= minOffX;
+ dstX = this.minX;
+ srcX += minOffX;
+ }
+
+ if (dstY < this.minY) {
+ int minOffY = this.minY - dstY;
+ h -= minOffY;
+ dstY = this.minY;
+ srcY += minOffY;
+ }
+
+ if (dstX + w > this.minX + this.width) {
+ int maxOffX = (dstX + w) - (this.minX + this.width);
+ w -= maxOffX;
+ }
+
+ if (dstY + h > this.minY + this.height) {
+ int maxOffY = (dstY + h) - (this.minY + this.height);
+ h -= maxOffY;
+ }
+
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ switch (sampleModel.getDataType()) {
+ case DataBuffer.TYPE_BYTE:
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_INT:
+ int iPixelsLine[] = null;
+ for (int i = 0; i < h; i++) {
+ iPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1,
+ iPixelsLine);
+ setPixels(dstX, dstY + i, w, 1, iPixelsLine);
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+ float fPixelsLine[] = null;
+ for (int i = 0; i < h; i++) {
+ fPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1,
+ fPixelsLine);
+ setPixels(dstX, dstY + i, w, 1, fPixelsLine);
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+ double dPixelsLine[] = null;
+ for (int i = 0; i < h; i++) {
+ dPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1,
+ dPixelsLine);
+ setPixels(dstX, dstY + i, w, 1, dPixelsLine);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Sets the data for a rectangle of pixels from an input Raster to
+ * this WritableRaster.
+ *
+ * @param x the X coordinate of the point where the data of
+ * the input Raster is to be written.
+ * @param y the Y coordinate of the point where the data of
+ * the input Raster is to be written.
+ * @param inRaster the input Raster.
+ */
+ public void setDataElements(int x, int y, Raster inRaster) {
+ int dstX = x + inRaster.getMinX();
+ int dstY = y + inRaster.getMinY();
+
+ int w = inRaster.getWidth();
+ int h = inRaster.getHeight();
+
+ if (dstX < this.minX || dstX + w > this.minX + this.width ||
+ dstY < this.minY || dstY + h > this.minY + this.height) {
+ // awt.63=Coordinates are not in bounds
+ throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
+ }
+
+ int srcX = inRaster.getMinX();
+ int srcY = inRaster.getMinY();
+ Object line = null;
+
+ for (int i = 0; i < h; i++) {
+ line = inRaster.getDataElements(srcX, srcY + i, w, 1, line);
+ setDataElements(dstX, dstY + i, w, 1, line);
+ }
+ }
+
+ /**
+ * Sets a int array of samples for the specified pixel
+ * in this WritableRaster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param iArray the int array of samples.
+ */
+ public void setPixel(int x, int y, int iArray[]) {
+ sampleModel.setPixel(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, iArray, dataBuffer);
+ }
+
+ /**
+ * Sets a float array of samples for the specified pixel
+ * in this WritableRaster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param fArray the float array of samples.
+ */
+ public void setPixel(int x, int y, float fArray[]) {
+ sampleModel.setPixel(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, fArray, dataBuffer);
+ }
+
+ /**
+ * Sets a double array of samples for the specified pixel
+ * in this WritableRaster.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param dArray the double array of samples.
+ */
+ public void setPixel(int x, int y, double dArray[]) {
+ sampleModel.setPixel(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, dArray, dataBuffer);
+ }
+
+ /**
+ * Sets a int array of samples for the specified rectangular area
+ * of pixels in this WritableRaster.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ * @param iArray the int array of samples.
+ */
+ public void setPixels(int x, int y, int w, int h, int iArray[]) {
+ sampleModel.setPixels(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, iArray, dataBuffer);
+ }
+
+ /**
+ * Sets a float array of samples for the specified rectangular area
+ * of pixels in this WritableRaster.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ * @param fArray the float array of samples.
+ */
+ public void setPixels(int x, int y, int w, int h, float fArray[]) {
+ sampleModel.setPixels(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, fArray, dataBuffer);
+ }
+
+ /**
+ * Sets a double array of samples for the specified rectangular area
+ * of pixels in this WritableRaster.
+ *
+ * @param x the X coordinate of rectangular area.
+ * @param y the Y coordinate of rectangular area.
+ * @param w the width of rectangular area.
+ * @param h the height of rectangular area.
+ * @param dArray the double array of samples.
+ */
+ public void setPixels(int x, int y, int w, int h, double dArray[]) {
+ sampleModel.setPixels(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, dArray, dataBuffer);
+ }
+
+ /**
+ * Sets the samples for the specified band and the specified
+ * rectangular area of pixels with an int array of samples.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param b the specified band.
+ * @param iArray the int array of samples.
+
+ */
+ public void setSamples(int x, int y, int w, int h, int b, int iArray[]) {
+ sampleModel.setSamples(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, b, iArray, dataBuffer);
+ }
+
+ /**
+ * Sets the samples for the specified band and the specified
+ * rectangular area of pixels with a float array of samples.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param b the specified band.
+ * @param fArray the float array of samples.
+ */
+ public void setSamples(int x, int y, int w, int h, int b, float fArray[]) {
+ sampleModel.setSamples(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, b, fArray, dataBuffer);
+ }
+
+ /**
+ * Sets the samples for the specified band and the specified
+ * rectangular area of pixels with a double array of samples.
+ *
+ * @param x the X coordinate of the area of pixels.
+ * @param y the Y coordinate of the area of pixels.
+ * @param w the width of the area of pixels.
+ * @param h the height of the area of pixels.
+ * @param b the specified band.
+ * @param dArray the double array of samples.
+ */
+ public void setSamples(int x, int y, int w, int h, int b, double dArray[]) {
+ sampleModel.setSamples(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, w, h, b, dArray, dataBuffer);
+ }
+
+ /**
+ * Sets the sample for the specified band and the specified
+ * pixel with an int sample.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample to be set.
+ */
+ public void setSample(int x, int y, int b, int s) {
+ sampleModel.setSample(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, b, s, dataBuffer);
+ }
+
+ /**
+ * Sets the sample for the specified band and the specified
+ * pixel with a float sample.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample to be set.
+ */
+ public void setSample(int x, int y, int b, float s) {
+ sampleModel.setSample(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, b, s, dataBuffer);
+ }
+
+ /**
+ * Sets the sample for the specified band and the specified
+ * pixel with a int sample.
+ *
+ * @param x the X coordinate of the pixel.
+ * @param y the Y coordinate of the pixel.
+ * @param b the specified band.
+ * @param s the sample to be set.
+ */
+ public void setSample(int x, int y, int b, double s) {
+ sampleModel.setSample(x - sampleModelTranslateX,
+ y - sampleModelTranslateY, b, s, dataBuffer);
+ }
+
+}
+
diff --git a/awt/java/awt/image/WritableRenderedImage.java b/awt/java/awt/image/WritableRenderedImage.java
new file mode 100644
index 0000000..ee1cb9e
--- /dev/null
+++ b/awt/java/awt/image/WritableRenderedImage.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image;
+
+import java.awt.Point;
+
+/**
+ * The WriteableRenderedImage interface is interface for objects which
+ * contains Raster data of one or several tiles. This interface provides
+ * notification mehanism for obtaining tile's writing status.
+ */
+public interface WritableRenderedImage extends RenderedImage {
+
+ /**
+ * Gets and checks out the writable tile for writing.
+ *
+ * @param tileX the X index of the tile.
+ * @param tileY the Y index of the tile.
+ *
+ * @return the WritableRaster.
+ */
+ public WritableRaster getWritableTile(int tileX, int tileY);
+
+ /**
+ * Removes the registered TileObserver.
+ *
+ * @param to the TileObserver which is registered for this
+ * WritableRenderedImage.
+ */
+ public void removeTileObserver(TileObserver to);
+
+ /**
+ * Adds the specified TileObserver to this WritableRenderedImage.
+ *
+ * @param to the TileObserver object to be added.
+ */
+ public void addTileObserver(TileObserver to);
+
+ /**
+ * Sets this image to the contents of the specified Raster.
+ *
+ * @param r the specified Raster.
+ */
+ public void setData(Raster r);
+
+ /**
+ * Gets the array of points wich represent indices of tiles which
+ * are check out for writing.
+ *
+ * @return the array of Points.
+ */
+ public Point[] getWritableTileIndices();
+
+ /**
+ * Checks if the specified tile is writable or not.
+ *
+ * @param tileX the X index of tile.
+ * @param tileY the Y index of tile.
+ *
+ * @return true, if the specified tile is writable,
+ * false otherwise.
+ */
+ public boolean isTileWritable(int tileX, int tileY);
+
+ /**
+ * Release the specified writable tile. This method removes the writer
+ * from the tile.
+ *
+ * @param tileX the X index of the tile.
+ * @param tileY the Y index of the tile.
+ */
+ public void releaseWritableTile(int tileX, int tileY);
+
+ /**
+ * Checks if there is a tile which is checked out for writing.
+ *
+ * @return true, if any tile is checked out for writing, false if there
+ * is no such tile.
+ */
+ public boolean hasTileWriters();
+
+}
+
diff --git a/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java
new file mode 100644
index 0000000..3e96637
--- /dev/null
+++ b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.geom.Rectangle2D;
+import java.awt.image.RenderedImage;
+
+/**
+ * A factory for creating ContextualRenderedImage objects with utilities
+ * for manipulating the properties in the parameter block.
+ */
+public interface ContextualRenderedImageFactory extends RenderedImageFactory {
+
+ /**
+ * Maps a render context to a parameter block and a renderable image.
+ *
+ * @param a0 the index
+ * @param a1 the RenderContext
+ * @param a2 the ParameterBlock
+ * @param a3 the RenderableImage
+ *
+ * @return the render context
+ */
+ public RenderContext mapRenderContext(int a0, RenderContext a1, ParameterBlock a2, RenderableImage a3);
+
+ /**
+ * Gets the value of the property from the parameter block.
+ *
+ * @param a0 the parameter block to examine to find the property
+ * @param a1 the name of the property
+ *
+ * @return the value of the property
+ */
+ public Object getProperty(ParameterBlock a0, String a1);
+
+ /**
+ * Creates the rendered image determined by the render context and
+ * parameter block.
+ *
+ * @param a0 the RenderContext
+ * @param a1 the ParameterBlock
+ *
+ * @return the rendered image
+ */
+ public RenderedImage create(RenderContext a0, ParameterBlock a1);
+
+ /**
+ * Gets the bounding rectangle from the parameter block.
+ *
+ * @param a0 the parameter block to read the bounds from
+ *
+ * @return the bounding rectangle
+ */
+ public Rectangle2D getBounds2D(ParameterBlock a0);
+
+ /**
+ * Gets the names of all of the supported properties.
+ *
+ * @return the property names
+ */
+ public String[] getPropertyNames();
+
+ /**
+ * Checks if this image factory is dynamic.
+ *
+ * @return true, if this image factory is dynamic
+ */
+ public boolean isDynamic();
+
+}
+
diff --git a/awt/java/awt/image/renderable/ParameterBlock.java b/awt/java/awt/image/renderable/ParameterBlock.java
new file mode 100644
index 0000000..1555f45
--- /dev/null
+++ b/awt/java/awt/image/renderable/ParameterBlock.java
@@ -0,0 +1,548 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.image.RenderedImage;
+import java.io.Serializable;
+import java.util.Vector;
+
+/**
+ * The Class ParameterBlock groups an indexed set of parameter data
+ * with a set of renderable (source) images. The mapping between
+ * the indexed parameters and their property names is provided
+ * by a {@link ContextualRenderedImageFactory}
+ */
+public class ParameterBlock implements Cloneable, Serializable {
+
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -7577115551785240750L;
+
+ /** The sources (renderable images). */
+ protected Vector<Object> sources = new Vector<Object>();
+
+ /** The parameters. */
+ protected Vector<Object> parameters = new Vector<Object>();
+
+ /**
+ * Instantiates a new parameter block.
+ *
+ * @param sources the vector of source images
+ * @param parameters the vector of parameters
+ */
+ public ParameterBlock(Vector<Object> sources, Vector<Object> parameters) {
+ setSources(sources);
+ setParameters(parameters);
+ }
+
+ /**
+ * Instantiates a new parameter block with no parameters.
+ *
+ * @param sources the vector of source images
+ */
+ public ParameterBlock(Vector<Object> sources) {
+ setSources(sources);
+ }
+
+ /**
+ * Instantiates a new parameter block with no image or parameter vectors.
+ */
+ public ParameterBlock() {}
+
+ /**
+ * Sets the source image at the specified index.
+ *
+ * @param source the source image
+ * @param index the index where the source will be placed
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock setSource(Object source, int index) {
+ if(sources.size() < index + 1){
+ sources.setSize(index + 1);
+ }
+ sources.setElementAt(source, index);
+ return this;
+ }
+
+ /**
+ * Sets the parameter value object at the specified index.
+ *
+ * @param obj the parameter value to place at the desired index
+ * @param index the index where the object is to be placed in the
+ * vector of parameters
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(Object obj, int index) {
+ if(parameters.size() < index + 1){
+ parameters.setSize(index + 1);
+ }
+ parameters.setElementAt(obj, index);
+ return this;
+ }
+
+ /**
+ * Adds a source to the vector of sources.
+ *
+ * @param source the source to add
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock addSource(Object source) {
+ sources.addElement(source);
+ return this;
+ }
+
+ /**
+ * Adds the object to the vector of parameter values
+ *
+ * @param obj the obj to add
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(Object obj) {
+ parameters.addElement(obj);
+ return this;
+ }
+
+ /**
+ * Sets the vector of sources, replacing the existing
+ * vector of sources, if any.
+ *
+ * @param sources the new sources
+ */
+ public void setSources(Vector<Object> sources) {
+ this.sources = sources;
+ }
+
+ /**
+ * Sets the vector of parameters, replacing the existing
+ * vector of parameters, if any.
+ *
+ * @param parameters the new parameters
+ */
+ public void setParameters(Vector<Object> parameters) {
+ this.parameters = parameters;
+ }
+
+ /**
+ * Gets the vector of sources.
+ *
+ * @return the sources
+ */
+ public Vector<Object> getSources() {
+ return sources;
+ }
+
+ /**
+ * Gets the vector of parameters.
+ *
+ * @return the parameters
+ */
+ public Vector<Object> getParameters() {
+ return parameters;
+ }
+
+ /**
+ * Gets the source at the specified index.
+ *
+ * @param index the index
+ *
+ * @return the source object found at the specified index
+ */
+ public Object getSource(int index) {
+ return sources.elementAt(index);
+ }
+
+ /**
+ * Gets the object parameter found at the specified index.
+ *
+ * @param index the index
+ *
+ * @return the parameter object found at the specified index
+ */
+ public Object getObjectParameter(int index) {
+ return parameters.elementAt(index);
+ }
+
+ /**
+ * Shallow clone (clones using the superclass clone method).
+ *
+ * @return the clone of this object
+ */
+ public Object shallowClone() {
+ try{
+ return super.clone();
+ }catch(Exception e){
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object clone() {
+ ParameterBlock replica;
+ try{
+ replica = (ParameterBlock)super.clone();
+ }catch(Exception e){
+ return null;
+ }
+ if(sources != null){
+ replica.setSources((Vector<Object>)(sources.clone()));
+ }
+ if(parameters != null){
+ replica.setParameters((Vector<Object>)(parameters.clone()));
+ }
+ return replica;
+ }
+
+ /**
+ * Gets an array of classes corresponding to all of the parameter
+ * values found in the array of parameters, in order.
+ *
+ * @return the parameter classes
+ */
+ public Class[] getParamClasses() {
+ int count = parameters.size();
+ Class paramClasses[] = new Class[count];
+
+ for(int i = 0; i < count; i++){
+ paramClasses[i] = parameters.elementAt(i).getClass();
+ }
+ return paramClasses;
+ }
+
+ /**
+ * Gets the renderable source image found at the specified index
+ * in the source array.
+ *
+ * @param index the index
+ *
+ * @return the renderable source image
+ */
+ public RenderableImage getRenderableSource(int index) {
+ return (RenderableImage)sources.elementAt(index);
+ }
+
+ /**
+ * Wraps the short value in a Short and places it in the
+ * parameter block at the specified index.
+ *
+ * @param s the short value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(short s, int index) {
+ return set(new Short(s), index);
+ }
+
+ /**
+ * Wraps the short value in a Short and adds it to the
+ * parameter block.
+ *
+ * @param s the short value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(short s) {
+ return add(new Short(s));
+ }
+
+ /**
+ * Wraps the long value in a Long and places it in the
+ * parameter block at the specified index.
+ *
+ * @param l the long value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(long l, int index) {
+ return set(new Long(l), index);
+ }
+
+ /**
+ * Wraps the long value in a Long and adds it to the
+ * parameter block.
+ *
+ * @param l the long value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(long l) {
+ return add(new Long(l));
+ }
+
+ /**
+ * Wraps the int value in an Integer and places it in the
+ * parameter block at the specified index.
+ *
+ * @param i the int value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(int i, int index) {
+ return set(new Integer(i), index);
+ }
+
+ /**
+ * Wraps the int value in an Integer and adds it to the
+ * parameter block.
+ *
+ * @param i the int value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(int i) {
+ return add(new Integer(i));
+ }
+
+ /**
+ * Wraps the float value in a Float and places it in the
+ * parameter block at the specified index.
+ *
+ * @param f the float value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(float f, int index) {
+ return set(new Float(f), index);
+ }
+
+ /**
+ * Wraps the float value in a Float and adds it to the
+ * parameter block.
+ *
+ * @param f the float value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(float f) {
+ return add(new Float(f));
+ }
+
+ /**
+ * Wraps the double value in a Double and places it in the
+ * parameter block at the specified index.
+ *
+ * @param d the double value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(double d, int index) {
+ return set(new Double(d), index);
+ }
+
+ /**
+ * Wraps the double value in a Double and adds it to the
+ * parameter block.
+ *
+ * @param d the double value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(double d) {
+ return add(new Double(d));
+ }
+
+ /**
+ * Wraps the char value in a Character and places it in the
+ * parameter block at the specified index.
+ *
+ * @param c the char value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(char c, int index) {
+ return set(new Character(c), index);
+ }
+
+ /**
+ * Wraps the char value in a Character and adds it to the
+ * parameter block.
+ *
+ * @param c the char value of the parameter
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock add(char c) {
+ return add(new Character(c));
+ }
+
+ /**
+ * Wraps the byte value in a Byte and places it in the
+ * parameter block at the specified index.
+ *
+ * @param b the byte value of the parameter
+ * @param index the index
+ *
+ * @return this parameter block
+ */
+ public ParameterBlock set(byte b, int index) {
+ return set(new Byte(b), index);
+ }
+
+ /**
+ * Wraps the byte value in a Byte and adds it to the
+ * parameter block.
+ *
+ * @param b the byte value of the parameter
+ *
+ * @return the parameter block
+ */
+ public ParameterBlock add(byte b) {
+ return add(new Byte(b));
+ }
+
+ /**
+ * Gets the RenderedImage at the specified index from the
+ * vector of source images.
+ *
+ * @param index the index
+ *
+ * @return the rendered image
+ */
+ public RenderedImage getRenderedSource(int index) {
+ return (RenderedImage)sources.elementAt(index);
+ }
+
+ /**
+ * Gets the short-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the short parameter
+ */
+ public short getShortParameter(int index) {
+ return ((Short)parameters.elementAt(index)).shortValue();
+ }
+
+ /**
+ * Gets the long-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the long parameter
+ */
+ public long getLongParameter(int index) {
+ return ((Long)parameters.elementAt(index)).longValue();
+ }
+
+ /**
+ * Gets the int-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the int parameter
+ */
+ public int getIntParameter(int index) {
+ return ((Integer)parameters.elementAt(index)).intValue();
+ }
+
+ /**
+ * Gets the float-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the float parameter
+ */
+ public float getFloatParameter(int index) {
+ return ((Float)parameters.elementAt(index)).floatValue();
+ }
+
+ /**
+ * Gets the double-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the double parameter
+ */
+ public double getDoubleParameter(int index) {
+ return ((Double)parameters.elementAt(index)).doubleValue();
+ }
+
+ /**
+ * Gets the char-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the char parameter
+ */
+ public char getCharParameter(int index) {
+ return ((Character)parameters.elementAt(index)).charValue();
+ }
+
+ /**
+ * Gets the byte-valued parameter found at the desired index
+ * in the vector of parameter values.
+ *
+ * @param index the index
+ *
+ * @return the byte parameter
+ */
+ public byte getByteParameter(int index) {
+ return ((Byte)parameters.elementAt(index)).byteValue();
+ }
+
+ /**
+ * Clears the vector of sources.
+ */
+ public void removeSources() {
+ sources.removeAllElements();
+ }
+
+ /**
+ * Clears the vector of parameters.
+ */
+ public void removeParameters() {
+ parameters.removeAllElements();
+ }
+
+ /**
+ * Gets the number of elements in the vector of sources.
+ *
+ * @return the number of elements in the vector of sources
+ */
+ public int getNumSources() {
+ return sources.size();
+ }
+
+ /**
+ * Gets the number of elements in the vector of parameters.
+ *
+ * @return the number of elements in the vector of parameters
+ */
+ public int getNumParameters() {
+ return parameters.size();
+ }
+}
diff --git a/awt/java/awt/image/renderable/RenderContext.java b/awt/java/awt/image/renderable/RenderContext.java
new file mode 100644
index 0000000..3a3b93c
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderContext.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+
+/**
+ * The Class RenderContext stores data on how an image is to be
+ * rendered: the affine transform, the area of interest, and
+ * the rendering hints.
+ */
+public class RenderContext implements Cloneable {
+
+ /** The affine transform. */
+ AffineTransform transform;
+
+ /** The area of interest. */
+ Shape aoi;
+
+ /** The rendering hints. */
+ RenderingHints hints;
+
+ /**
+ * Instantiates a new render context.
+ *
+ * @param usr2dev the affine transform
+ * @param aoi the area of interest
+ * @param hints the rendering hints
+ */
+ public RenderContext(AffineTransform usr2dev, Shape aoi, RenderingHints hints) {
+ this.transform = (AffineTransform)usr2dev.clone();
+ this.aoi = aoi;
+ this.hints = hints;
+ }
+
+ /**
+ * Instantiates a new render context with no specified hints.
+ *
+ * @param usr2dev the affine transform
+ * @param aoi the area of interest
+ */
+ public RenderContext(AffineTransform usr2dev, Shape aoi) {
+ this(usr2dev, aoi, null);
+ }
+
+ /**
+ * Instantiates a new render context with no specified area of interest.
+ *
+ * @param usr2dev the affine transform
+ * @param hints the rendering hints
+ */
+ public RenderContext(AffineTransform usr2dev, RenderingHints hints) {
+ this(usr2dev, null, hints);
+ }
+
+ /**
+ * Instantiates a new render context with no rendering hints or
+ * area of interest.
+ *
+ * @param usr2dev the affine transform
+ */
+ public RenderContext(AffineTransform usr2dev) {
+ this(usr2dev, null, null);
+ }
+
+ @Override
+ public Object clone() {
+ return new RenderContext(transform, aoi, hints);
+ }
+
+ /**
+ * Sets the affine transform for this render context.
+ *
+ * @param newTransform the new affine transform
+ */
+ public void setTransform(AffineTransform newTransform) {
+ transform = (AffineTransform)newTransform.clone();
+ }
+
+ /**
+ * Concatenates the current transform with the specified transform
+ * (so they are applied with the specified transform acting first)
+ * and sets the resulting transform as the affine transform of
+ * this rendering context.
+ *
+ * @param modTransform the new transform which modifies the
+ * current transform
+ *
+ * @deprecated use {@link RenderContext#preConcatenateTransform(AffineTransform)}
+ */
+ @Deprecated
+ public void preConcetenateTransform(AffineTransform modTransform) {
+ preConcatenateTransform(modTransform);
+ }
+
+ /**
+ * Concatenates the current transform with the specified transform
+ * (so they are applied with the specified transform acting first)
+ * and sets the resulting transform as the affine transform of
+ * this rendering context.
+ *
+ * @param modTransform the new transform which modifies the
+ * current transform
+ */
+ public void preConcatenateTransform(AffineTransform modTransform) {
+ transform.preConcatenate(modTransform);
+ }
+
+ /**
+ * Concatenate the specified transform with the current transform.
+ *
+ * @param modTransform the new transform which modifies the
+ * current transform
+ *
+ * @deprecated use {@link RenderContext#concatenateTransform(AffineTransform)}
+ */
+ @Deprecated
+ public void concetenateTransform(AffineTransform modTransform) {
+ concatenateTransform(modTransform);
+ }
+
+ /**
+ * Concatenate the specified transform with the current transform.
+ *
+ * @param modTransform the new transform which modifies the
+ * current transform
+ */
+ public void concatenateTransform(AffineTransform modTransform) {
+ transform.concatenate(modTransform);
+ }
+
+ /**
+ * Gets the transform.
+ *
+ * @return the transform
+ */
+ public AffineTransform getTransform() {
+ return (AffineTransform)transform.clone();
+ }
+
+ /**
+ * Sets the area of interest.
+ *
+ * @param newAoi the new area of interest
+ */
+ public void setAreaOfInterest(Shape newAoi) {
+ aoi = newAoi;
+ }
+
+ /**
+ * Gets the area of interest.
+ *
+ * @return the area of interest
+ */
+ public Shape getAreaOfInterest() {
+ return aoi;
+ }
+
+ /**
+ * Sets the rendering hints.
+ *
+ * @param hints the new rendering hints
+ */
+ public void setRenderingHints(RenderingHints hints) {
+ this.hints = hints;
+ }
+
+ /**
+ * Gets the rendering hints.
+ *
+ * @return the rendering hints
+ */
+ public RenderingHints getRenderingHints() {
+ return hints;
+ }
+}
diff --git a/awt/java/awt/image/renderable/RenderableImage.java b/awt/java/awt/image/renderable/RenderableImage.java
new file mode 100644
index 0000000..885dc06
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderableImage.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.image.RenderedImage;
+import java.util.Vector;
+
+/**
+ * The Interface RenderableImage is implemented by an object that
+ * collects all of the image-specific data that defines a single image
+ * that could be rendered to different rendering targets.
+ */
+public interface RenderableImage {
+
+ /** The Constant HINTS_OBSERVED indicates that the rendering
+ * hints are applied rather than ignored. */
+ public static final String HINTS_OBSERVED = "HINTS_OBSERVED"; //$NON-NLS-1$
+
+ /**
+ * Gets the property from the RenderableImage's parameter block.
+ *
+ * @param name the name of the property to get.
+ *
+ * @return the value of the property
+ */
+ public Object getProperty(String name);
+
+ /**
+ * Creates the rendered image based on the information contained
+ * in the parameters and the render context.
+ *
+ * @param renderContext the render context giving rendering specifications
+ * such as transformations
+ *
+ * @return the rendered image
+ */
+ public RenderedImage createRendering(RenderContext renderContext);
+
+ /**
+ * Creates the scaled rendered image based on the information contained
+ * in the parameters and the render context.
+ *
+ * @param w the desired width after scaling or zero if the scaling
+ * should be proportional, based on the height
+ * @param h the desired height after scaling or zero if the scaling
+ * should be proportional, based on the width
+ * @param hints the rendering hints to use
+ *
+ * @return the rendered image
+ *
+ * @throws IllegalArgumentException if both the height and width are zero
+ */
+ public RenderedImage createScaledRendering(int w, int h, RenderingHints hints);
+
+ /**
+ * Gets the vector of sources from the parameter block.
+ *
+ * @return the sources
+ */
+ public Vector<RenderableImage> getSources();
+
+ /**
+ * Gets the names of all of the supported properties in the current context.
+ *
+ * @return the property names
+ */
+ public String[] getPropertyNames();
+
+ /**
+ * Creates the default rendering (using the identity transform
+ * and default render context).
+ *
+ * @return the rendered image
+ */
+ public RenderedImage createDefaultRendering();
+
+ /**
+ * Checks if this context supports dynamic rendering.
+ *
+ * @return true, if this context supports dynamic rendering
+ */
+ public boolean isDynamic();
+
+ /**
+ * Gets the width of the image.
+ *
+ * @return the width of the image
+ */
+ public float getWidth();
+
+ /**
+ * Gets the y coordinate of the upper left corner.
+ *
+ * @return the y coordinate of the upper left corner
+ */
+ public float getMinY();
+
+ /**
+ * Gets the x coordinate of the upper left corner.
+ *
+ * @return the x coordinate of the upper left corner
+ */
+ public float getMinX();
+
+ /**
+ * Gets the height of the image.
+ *
+ * @return the height of the image
+ */
+ public float getHeight();
+
+}
+
diff --git a/awt/java/awt/image/renderable/RenderableImageOp.java b/awt/java/awt/image/renderable/RenderableImageOp.java
new file mode 100644
index 0000000..993ba5f
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderableImageOp.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.RenderedImage;
+import java.util.Vector;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * The Class RenderableImageOp is a basic implementation of RenderableImage,
+ * with methods to access the parameter data and perform rendering
+ * operations.
+ */
+public class RenderableImageOp implements RenderableImage {
+
+ /** The CRIF. */
+ ContextualRenderedImageFactory CRIF;
+
+ /** The param block. */
+ ParameterBlock paramBlock;
+
+ /** The height. */
+ float minX, minY, width, height;
+
+ /**
+ * Instantiates a new renderable image op.
+ *
+ * @param CRIF the cRIF
+ * @param paramBlock the param block
+ */
+ public RenderableImageOp(ContextualRenderedImageFactory CRIF, ParameterBlock paramBlock) {
+ this.CRIF = CRIF;
+ this.paramBlock = (ParameterBlock) paramBlock.clone();
+ Rectangle2D r = CRIF.getBounds2D(paramBlock);
+ minX = (float) r.getMinX();
+ minY = (float) r.getMinY();
+ width = (float) r.getWidth();
+ height = (float) r.getHeight();
+ }
+
+ public Object getProperty(String name) {
+ return CRIF.getProperty(paramBlock, name);
+ }
+
+ /**
+ * Sets the parameter block.
+ *
+ * @param paramBlock the param block
+ *
+ * @return the parameter block
+ */
+ public ParameterBlock setParameterBlock(ParameterBlock paramBlock) {
+ ParameterBlock oldParam = this.paramBlock;
+ this.paramBlock = (ParameterBlock) paramBlock.clone();
+ return oldParam;
+ }
+
+ public RenderedImage createRendering(RenderContext renderContext) {
+
+ Vector<RenderableImage> sources = getSources();
+ ParameterBlock rdParam = (ParameterBlock) paramBlock.clone();
+
+ if (sources != null) {
+ Vector<Object> rdSources = new Vector<Object>();
+ int i = 0;
+ while (i < sources.size()) {
+ RenderContext newContext = CRIF.mapRenderContext(i, renderContext, paramBlock,
+ this);
+ RenderedImage rdim = sources.elementAt(i).createRendering(newContext);
+
+ if (rdim != null) {
+ rdSources.addElement(rdim);
+ }
+ i++;
+ }
+ if (rdSources.size() > 0) {
+ rdParam.setSources(rdSources);
+ }
+ }
+ return CRIF.create(renderContext, rdParam);
+ }
+
+ public RenderedImage createScaledRendering(int w, int h, RenderingHints hints) {
+ if(w == 0 && h == 0) {
+ // awt.60=Width and Height mustn't be equal zero both
+ throw new IllegalArgumentException(Messages.getString("awt.60")); //$NON-NLS-1$
+ }
+ if(w == 0){
+ w = Math.round(h*(getWidth()/getHeight()));
+ }
+
+ if(h == 0){
+ h = Math.round(w*(getHeight()/getWidth()));
+ }
+
+ double sx = (double)w/getWidth();
+ double sy = (double)h/getHeight();
+
+ AffineTransform at = AffineTransform.getScaleInstance(sx, sy);
+ RenderContext context = new RenderContext(at, hints);
+ return createRendering(context);
+ }
+
+ public Vector<RenderableImage> getSources() {
+ if(paramBlock.getNumSources() == 0) {
+ return null;
+ }
+ Vector<RenderableImage> v = new Vector<RenderableImage>();
+ int i = 0;
+ while(i < paramBlock.getNumSources()){
+ Object o = paramBlock.getSource(i);
+ if(o instanceof RenderableImage){
+ v.addElement((RenderableImage) o);
+ }
+ i++;
+ }
+ return v;
+ }
+
+ public String[] getPropertyNames() {
+ return CRIF.getPropertyNames();
+ }
+
+ /**
+ * Gets the parameter block.
+ *
+ * @return the parameter block
+ */
+ public ParameterBlock getParameterBlock() {
+ return paramBlock;
+ }
+
+ public RenderedImage createDefaultRendering() {
+ AffineTransform at = new AffineTransform();
+ RenderContext context = new RenderContext(at);
+ return createRendering(context);
+ }
+
+ public boolean isDynamic() {
+ return CRIF.isDynamic();
+ }
+
+ public float getWidth() {
+ return width;
+ }
+
+ public float getMinY() {
+ return minY;
+ }
+
+ public float getMinX() {
+ return minX;
+ }
+
+ public float getHeight() {
+ return height;
+ }
+
+}
+
diff --git a/awt/java/awt/image/renderable/RenderableImageProducer.java b/awt/java/awt/image/renderable/RenderableImageProducer.java
new file mode 100644
index 0000000..7fda98c
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderableImageProducer.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.util.Vector;
+
+/**
+ * The Class RenderableImageProducer provides the implementation for
+ * the image rendering.
+ */
+public class RenderableImageProducer implements ImageProducer, Runnable {
+
+ /** The rbl. */
+ RenderableImage rbl;
+
+ /** The rc. */
+ RenderContext rc;
+
+ /** The consumers. */
+ Vector<ImageConsumer> consumers = new Vector<ImageConsumer>();
+
+ /**
+ * Instantiates a new renderable image producer.
+ *
+ * @param rdblImage the rdbl image
+ * @param rc the rc
+ */
+ public RenderableImageProducer(RenderableImage rdblImage, RenderContext rc) {
+ this.rbl = rdblImage;
+ this.rc = rc;
+ }
+
+ /**
+ * Sets the render context.
+ *
+ * @param rc the new render context
+ */
+ public synchronized void setRenderContext(RenderContext rc) {
+ this.rc = rc;
+ }
+
+ public synchronized boolean isConsumer(ImageConsumer ic) {
+ return consumers.contains(ic);
+ }
+
+ public synchronized void startProduction(ImageConsumer ic) {
+ addConsumer(ic);
+ Thread t = new Thread(this, "RenderableImageProducer thread"); //$NON-NLS-1$
+ t.start();
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer ic) {}
+
+ public synchronized void removeConsumer(ImageConsumer ic) {
+ if(ic != null) {
+ consumers.removeElement(ic);
+ }
+ }
+
+ public synchronized void addConsumer(ImageConsumer ic) {
+ if(ic != null && !consumers.contains(ic)){
+ consumers.addElement(ic);
+ }
+ }
+
+ /**
+ * Creates the rendered image in a new thread.
+ */
+ public void run() {
+ if(rbl == null) {
+ return;
+ }
+
+ RenderedImage rd;
+ if(rc != null) {
+ rd = rbl.createRendering(rc);
+ } else {
+ rd = rbl.createDefaultRendering();
+ }
+
+ ColorModel cm = rd.getColorModel();
+ if(cm == null) {
+ cm = ColorModel.getRGBdefault();
+ }
+
+ Raster r = rd.getData();
+ int w = r.getWidth();
+ int h = r.getHeight();
+
+ for (ImageConsumer c : consumers) {
+ c.setDimensions(w, h);
+ c.setHints(ImageConsumer.TOPDOWNLEFTRIGHT |
+ ImageConsumer.COMPLETESCANLINES |
+ ImageConsumer.SINGLEFRAME |
+ ImageConsumer.SINGLEPASS);
+ }
+
+ int scanLine[] = new int[w];
+ int pixel[] = null;
+
+ for(int y = 0; y < h; y++){
+ for(int x = 0; x < w; x++){
+ pixel = r.getPixel(x, y, pixel);
+ scanLine[x] = cm.getDataElement(pixel, 0);
+ }
+
+ for (ImageConsumer c : consumers) {
+ c.setPixels(0, y, w, 1, cm, scanLine, 0, w);
+ }
+ }
+
+ for (ImageConsumer c : consumers) {
+ c.imageComplete(ImageConsumer.STATICIMAGEDONE);
+ }
+ }
+
+}
+
diff --git a/awt/java/awt/image/renderable/RenderedImageFactory.java b/awt/java/awt/image/renderable/RenderedImageFactory.java
new file mode 100644
index 0000000..345d82c
--- /dev/null
+++ b/awt/java/awt/image/renderable/RenderedImageFactory.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package java.awt.image.renderable;
+
+import java.awt.RenderingHints;
+import java.awt.image.RenderedImage;
+
+/**
+ * A factory for creating RenderedImage objects based on parameters
+ * and rendering hints.
+ */
+public interface RenderedImageFactory {
+
+ /**
+ * Creates the rendered image.
+ *
+ * @param a0 the ParameterBlock
+ * @param a1 the RenderingHints
+ *
+ * @return the rendered image
+ */
+ public RenderedImage create(ParameterBlock a0, RenderingHints a1);
+
+}
+
diff --git a/awt/java/awt/peer/ButtonPeer.java b/awt/java/awt/peer/ButtonPeer.java
new file mode 100644
index 0000000..cc45b49
--- /dev/null
+++ b/awt/java/awt/peer/ButtonPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ButtonPeer {
+
+}
diff --git a/awt/java/awt/peer/CanvasPeer.java b/awt/java/awt/peer/CanvasPeer.java
new file mode 100644
index 0000000..e276366
--- /dev/null
+++ b/awt/java/awt/peer/CanvasPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface CanvasPeer {
+
+}
diff --git a/awt/java/awt/peer/CheckboxMenuItemPeer.java b/awt/java/awt/peer/CheckboxMenuItemPeer.java
new file mode 100644
index 0000000..296f422
--- /dev/null
+++ b/awt/java/awt/peer/CheckboxMenuItemPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface CheckboxMenuItemPeer {
+
+}
diff --git a/awt/java/awt/peer/CheckboxPeer.java b/awt/java/awt/peer/CheckboxPeer.java
new file mode 100644
index 0000000..e9f8dd1
--- /dev/null
+++ b/awt/java/awt/peer/CheckboxPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface CheckboxPeer {
+
+}
diff --git a/awt/java/awt/peer/ChoicePeer.java b/awt/java/awt/peer/ChoicePeer.java
new file mode 100644
index 0000000..57b7629
--- /dev/null
+++ b/awt/java/awt/peer/ChoicePeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ChoicePeer {
+
+}
diff --git a/awt/java/awt/peer/ComponentPeer.java b/awt/java/awt/peer/ComponentPeer.java
new file mode 100644
index 0000000..bc26791
--- /dev/null
+++ b/awt/java/awt/peer/ComponentPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ComponentPeer {
+
+}
diff --git a/awt/java/awt/peer/DialogPeer.java b/awt/java/awt/peer/DialogPeer.java
new file mode 100644
index 0000000..8ae3049
--- /dev/null
+++ b/awt/java/awt/peer/DialogPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface DialogPeer {
+
+}
diff --git a/awt/java/awt/peer/FileDialogPeer.java b/awt/java/awt/peer/FileDialogPeer.java
new file mode 100644
index 0000000..0d15e48
--- /dev/null
+++ b/awt/java/awt/peer/FileDialogPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface FileDialogPeer {
+
+}
diff --git a/awt/java/awt/peer/FontPeer.java b/awt/java/awt/peer/FontPeer.java
new file mode 100644
index 0000000..fd9815f
--- /dev/null
+++ b/awt/java/awt/peer/FontPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface FontPeer {
+
+}
diff --git a/awt/java/awt/peer/FramePeer.java b/awt/java/awt/peer/FramePeer.java
new file mode 100644
index 0000000..9cfc40b
--- /dev/null
+++ b/awt/java/awt/peer/FramePeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface FramePeer {
+
+}
diff --git a/awt/java/awt/peer/LabelPeer.java b/awt/java/awt/peer/LabelPeer.java
new file mode 100644
index 0000000..052ca9d
--- /dev/null
+++ b/awt/java/awt/peer/LabelPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface LabelPeer {
+
+}
diff --git a/awt/java/awt/peer/LightweightPeer.java b/awt/java/awt/peer/LightweightPeer.java
new file mode 100644
index 0000000..1dee905
--- /dev/null
+++ b/awt/java/awt/peer/LightweightPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface LightweightPeer {
+
+}
diff --git a/awt/java/awt/peer/ListPeer.java b/awt/java/awt/peer/ListPeer.java
new file mode 100644
index 0000000..0a27885
--- /dev/null
+++ b/awt/java/awt/peer/ListPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ListPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuBarPeer.java b/awt/java/awt/peer/MenuBarPeer.java
new file mode 100644
index 0000000..3ad2c16
--- /dev/null
+++ b/awt/java/awt/peer/MenuBarPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuBarPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuComponentPeer.java b/awt/java/awt/peer/MenuComponentPeer.java
new file mode 100644
index 0000000..3ac3b34
--- /dev/null
+++ b/awt/java/awt/peer/MenuComponentPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuComponentPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuItemPeer.java b/awt/java/awt/peer/MenuItemPeer.java
new file mode 100644
index 0000000..b133897
--- /dev/null
+++ b/awt/java/awt/peer/MenuItemPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuItemPeer {
+
+}
diff --git a/awt/java/awt/peer/MenuPeer.java b/awt/java/awt/peer/MenuPeer.java
new file mode 100644
index 0000000..d643ce7
--- /dev/null
+++ b/awt/java/awt/peer/MenuPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MenuPeer {
+
+}
diff --git a/awt/java/awt/peer/MouseInfoPeer.java b/awt/java/awt/peer/MouseInfoPeer.java
new file mode 100644
index 0000000..9173a62
--- /dev/null
+++ b/awt/java/awt/peer/MouseInfoPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface MouseInfoPeer {
+
+}
diff --git a/awt/java/awt/peer/PanelPeer.java b/awt/java/awt/peer/PanelPeer.java
new file mode 100644
index 0000000..1faa1fe
--- /dev/null
+++ b/awt/java/awt/peer/PanelPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface PanelPeer {
+
+}
diff --git a/awt/java/awt/peer/PopupMenuPeer.java b/awt/java/awt/peer/PopupMenuPeer.java
new file mode 100644
index 0000000..cf1ef61
--- /dev/null
+++ b/awt/java/awt/peer/PopupMenuPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface PopupMenuPeer {
+
+}
diff --git a/awt/java/awt/peer/ScrollPanePeer.java b/awt/java/awt/peer/ScrollPanePeer.java
new file mode 100644
index 0000000..df3de83
--- /dev/null
+++ b/awt/java/awt/peer/ScrollPanePeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ScrollPanePeer {
+
+}
diff --git a/awt/java/awt/peer/ScrollbarPeer.java b/awt/java/awt/peer/ScrollbarPeer.java
new file mode 100644
index 0000000..eec8961
--- /dev/null
+++ b/awt/java/awt/peer/ScrollbarPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface ScrollbarPeer {
+
+}
diff --git a/awt/java/awt/peer/TextAreaPeer.java b/awt/java/awt/peer/TextAreaPeer.java
new file mode 100644
index 0000000..636707f
--- /dev/null
+++ b/awt/java/awt/peer/TextAreaPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface TextAreaPeer {
+
+}
diff --git a/awt/java/awt/peer/TextFieldPeer.java b/awt/java/awt/peer/TextFieldPeer.java
new file mode 100644
index 0000000..2b8232a
--- /dev/null
+++ b/awt/java/awt/peer/TextFieldPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface TextFieldPeer {
+
+}
diff --git a/awt/java/awt/peer/WindowPeer.java b/awt/java/awt/peer/WindowPeer.java
new file mode 100644
index 0000000..384646f
--- /dev/null
+++ b/awt/java/awt/peer/WindowPeer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package java.awt.peer;
+
+public interface WindowPeer {
+
+}
diff --git a/awt/java/beans/FeatureDescriptor.java b/awt/java/beans/FeatureDescriptor.java
new file mode 100644
index 0000000..2945c65
--- /dev/null
+++ b/awt/java/beans/FeatureDescriptor.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.beans;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * Common base class for Descriptors.
+ */
+public class FeatureDescriptor {
+
+ private Map<String, Object> values;
+
+ boolean preferred, hidden, expert;
+
+ String shortDescription;
+
+ String name;
+
+ String displayName;
+
+ /**
+ * <p>
+ * Constructs an instance.
+ * </p>
+ */
+ public FeatureDescriptor() {
+ this.values = new HashMap<String, Object>();
+ }
+
+ /**
+ * <p>
+ * Sets the value for the named attribute.
+ * </p>
+ *
+ * @param attributeName
+ * The name of the attribute to set a value with.
+ * @param value
+ * The value to set.
+ */
+ public void setValue(String attributeName, Object value) {
+ if (attributeName == null || value == null) {
+ throw new NullPointerException();
+ }
+ values.put(attributeName, value);
+ }
+
+ /**
+ * <p>
+ * Gets the value associated with the named attribute.
+ * </p>
+ *
+ * @param attributeName
+ * The name of the attribute to get a value for.
+ * @return The attribute's value.
+ */
+ public Object getValue(String attributeName) {
+ Object result = null;
+ if (attributeName != null) {
+ result = values.get(attributeName);
+ }
+ return result;
+ }
+
+ /**
+ * <p>
+ * Enumerates the attribute names.
+ * </p>
+ *
+ * @return An instance of {@link Enumeration}.
+ */
+ public Enumeration<String> attributeNames() {
+ // Create a new list, so that the references are copied
+ return Collections.enumeration(new LinkedList<String>(values.keySet()));
+ }
+
+ /**
+ * <p>
+ * Sets the short description.
+ * </p>
+ *
+ * @param text
+ * The description to set.
+ */
+ public void setShortDescription(String text) {
+ this.shortDescription = text;
+ }
+
+ /**
+ * <p>
+ * Sets the name.
+ * </p>
+ *
+ * @param name
+ * The name to set.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * <p>
+ * Sets the display name.
+ * </p>
+ *
+ * @param displayName
+ * The display name to set.
+ */
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ /**
+ * <p>
+ * Gets the short description or {@link #getDisplayName()} if not set.
+ * </p>
+ *
+ * @return The description.
+ */
+ public String getShortDescription() {
+ return shortDescription == null ? getDisplayName() : shortDescription;
+ }
+
+ /**
+ * <p>
+ * Gets the name.
+ * </p>
+ *
+ * @return The name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * <p>
+ * Gets the display name or {@link #getName()} if not set.
+ * </p>
+ *
+ * @return The display name.
+ */
+ public String getDisplayName() {
+ return displayName == null ? getName() : displayName;
+ }
+
+ /**
+ * <p>
+ * Sets the preferred indicator.
+ * </p>
+ *
+ * @param preferred
+ * <code>true</code> if preferred, <code>false</code>
+ * otherwise.
+ */
+ public void setPreferred(boolean preferred) {
+ this.preferred = preferred;
+ }
+
+ /**
+ * <p>
+ * Sets the hidden indicator.
+ * </p>
+ *
+ * @param hidden
+ * <code>true</code> if hidden, <code>false</code> otherwise.
+ */
+ public void setHidden(boolean hidden) {
+ this.hidden = hidden;
+ }
+
+ /**
+ * <p>
+ * Sets the expert indicator.
+ * </p>
+ *
+ * @param expert
+ * <code>true</code> if expert, <code>false</code> otherwise.
+ */
+ public void setExpert(boolean expert) {
+ this.expert = expert;
+ }
+
+ /**
+ * <p>
+ * Indicates if this feature is preferred.
+ * </p>
+ *
+ * @return <code>true</code> if preferred, <code>false</code> otherwise.
+ */
+ public boolean isPreferred() {
+ return preferred;
+ }
+
+ /**
+ * <p>
+ * Indicates if this feature is hidden.
+ * </p>
+ *
+ * @return <code>true</code> if hidden, <code>false</code> otherwise.
+ */
+ public boolean isHidden() {
+ return hidden;
+ }
+
+ /**
+ * <p>
+ * Indicates if this feature is an expert feature.
+ * </p>
+ *
+ * @return <code>true</code> if hidden, <code>false</code> otherwise.
+ */
+ public boolean isExpert() {
+ return expert;
+ }
+}
diff --git a/awt/java/beans/IndexedPropertyChangeEvent.java b/awt/java/beans/IndexedPropertyChangeEvent.java
new file mode 100644
index 0000000..c9084c6
--- /dev/null
+++ b/awt/java/beans/IndexedPropertyChangeEvent.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package java.beans;
+
+/**
+ * A type of {@link PropertyChangeEvent} that indicates that an indexed property
+ * has changed.
+ *
+ * @since 1.5
+ */
+public class IndexedPropertyChangeEvent extends PropertyChangeEvent {
+
+ private static final long serialVersionUID = -320227448495806870L;
+
+ private final int index;
+
+ /**
+ * Creates a new property changed event with an indication of the property
+ * index.
+ *
+ * @param source
+ * the changed bean.
+ * @param propertyName
+ * the changed property, or <code>null</code> to indicate an
+ * unspecified set of the properties have changed.
+ * @param oldValue
+ * the previous value of the property, or <code>null</code> if
+ * the <code>propertyName</code> is <code>null</code> or the
+ * previous value is unknown.
+ * @param newValue
+ * the new value of the property, or <code>null</code> if the
+ * <code>propertyName</code> is <code>null</code> or the new
+ * value is unknown..
+ * @param index
+ * the index of the property.
+ */
+ public IndexedPropertyChangeEvent(Object source, String propertyName,
+ Object oldValue, Object newValue, int index) {
+ super(source, propertyName, oldValue, newValue);
+ this.index = index;
+ }
+
+ /**
+ * Answer the index of the property that was changed in this event.
+ *
+ * @return The property element index.
+ */
+ public int getIndex() {
+ return index;
+ }
+}
diff --git a/awt/java/beans/IndexedPropertyDescriptor.java b/awt/java/beans/IndexedPropertyDescriptor.java
new file mode 100644
index 0000000..25667d9
--- /dev/null
+++ b/awt/java/beans/IndexedPropertyDescriptor.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class IndexedPropertyDescriptor extends PropertyDescriptor {
+ private Method indexedGetter;
+
+ private Method indexedSetter;
+
+ public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass,
+ String getterName, String setterName, String indexedGetterName,
+ String indexedSetterName) throws IntrospectionException {
+ super(propertyName, beanClass, getterName, setterName);
+
+ // RI behaves like this
+ if (indexedGetterName == null && indexedSetterName == null &&
+ (getterName != null || setterName != null)) {
+ throw new IntrospectionException(Messages.getString("beans.50"));
+ }
+ setIndexedReadMethod(beanClass, indexedGetterName);
+ setIndexedWriteMethod(beanClass, indexedSetterName);
+ }
+
+ public IndexedPropertyDescriptor(String propertyName, Method getter, Method setter,
+ Method indexedGetter, Method indexedSetter) throws IntrospectionException {
+ super(propertyName, getter, setter);
+
+ // we need this in order to be compatible with RI
+ if (indexedGetter == null && indexedSetter == null &&
+ (getter != null || setter != null)) {
+ throw new IntrospectionException(Messages.getString("beans.50"));
+ }
+ setIndexedReadMethod(indexedGetter);
+ setIndexedWriteMethod(indexedSetter);
+ }
+
+ public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass)
+ throws IntrospectionException {
+ super(propertyName, beanClass, null, null);
+ String getterName;
+ String setterName;
+ String indexedGetterName;
+ String indexedSetterName;
+
+ // array getter
+ getterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
+ if (hasMethod(beanClass, getterName)) {
+ setReadMethod(beanClass, getterName);
+ }
+ // array setter
+ setterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
+ if (hasMethod(beanClass, setterName)) {
+ setWriteMethod(beanClass, setterName);
+ }
+ // indexed getter
+ indexedGetterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
+ if (hasMethod(beanClass, indexedGetterName)) {
+ setIndexedReadMethod(beanClass, indexedGetterName);
+ }
+ // indexed setter
+ indexedSetterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
+ if (hasMethod(beanClass, indexedSetterName)) {
+ setIndexedWriteMethod(beanClass, indexedSetterName);
+ }
+ // RI seems to behave a bit differently
+ if (indexedGetter == null && indexedSetter == null &&
+ getReadMethod() == null && getWriteMethod() == null) {
+ throw new IntrospectionException(
+ Messages.getString("beans.01", propertyName)); //$NON-NLS-1$
+ }
+ if (indexedGetter == null && indexedSetter == null) {
+ // not an indexed property indeed
+ throw new IntrospectionException(Messages.getString("beans.50"));
+ }
+ }
+
+ public void setIndexedReadMethod(Method indexedGetter) throws IntrospectionException {
+ if (indexedGetter != null) {
+ int modifiers = indexedGetter.getModifiers();
+ Class<?>[] parameterTypes;
+ Class<?> returnType;
+ Class<?> indexedPropertyType;
+
+ if (!Modifier.isPublic(modifiers)) {
+ throw new IntrospectionException(Messages.getString("beans.21")); //$NON-NLS-1$
+ }
+ parameterTypes = indexedGetter.getParameterTypes();
+ if (parameterTypes.length != 1) {
+ throw new IntrospectionException(Messages.getString("beans.22")); //$NON-NLS-1$
+ }
+ if (!parameterTypes[0].equals(int.class)) {
+ throw new IntrospectionException(Messages.getString("beans.23")); //$NON-NLS-1$
+ }
+ returnType = indexedGetter.getReturnType();
+ indexedPropertyType = getIndexedPropertyType();
+ if ((indexedPropertyType != null) && !returnType.equals(indexedPropertyType)) {
+ throw new IntrospectionException(Messages.getString("beans.24")); //$NON-NLS-1$
+ }
+ }
+ this.indexedGetter = indexedGetter;
+ }
+
+ public void setIndexedWriteMethod(Method indexedSetter) throws IntrospectionException {
+ if (indexedSetter != null) {
+ int modifiers = indexedSetter.getModifiers();
+ Class<?>[] parameterTypes;
+ Class<?> firstParameterType;
+ Class<?> secondParameterType;
+ Class<?> propType;
+
+ if (!Modifier.isPublic(modifiers)) {
+ throw new IntrospectionException(Messages.getString("beans.25")); //$NON-NLS-1$
+ }
+ parameterTypes = indexedSetter.getParameterTypes();
+ if (parameterTypes.length != 2) {
+ throw new IntrospectionException(Messages.getString("beans.26")); //$NON-NLS-1$
+ }
+ firstParameterType = parameterTypes[0];
+ if (!firstParameterType.equals(int.class)) {
+ throw new IntrospectionException(Messages.getString("beans.27")); //$NON-NLS-1$
+ }
+ secondParameterType = parameterTypes[1];
+ propType = getIndexedPropertyType();
+ if (propType != null && !secondParameterType.equals(propType)) {
+ throw new IntrospectionException(Messages.getString("beans.28")); //$NON-NLS-1$
+ }
+ }
+ this.indexedSetter = indexedSetter;
+ }
+
+ public Method getIndexedWriteMethod() {
+ return indexedSetter;
+ }
+
+ public Method getIndexedReadMethod() {
+ return indexedGetter;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ boolean result = super.equals(obj);
+
+ if (result) {
+ IndexedPropertyDescriptor pd = (IndexedPropertyDescriptor) obj;
+
+ if (indexedGetter != null) {
+ result = indexedGetter.equals(pd.getIndexedReadMethod());
+ } else if (result && indexedGetter == null) {
+ result = pd.getIndexedReadMethod() == null;
+ }
+
+ if (result) {
+ if (indexedSetter != null) {
+ result = indexedSetter.equals(pd.getIndexedWriteMethod());
+ } else if (indexedSetter == null) {
+ result = pd.getIndexedWriteMethod() == null;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public Class<?> getIndexedPropertyType() {
+ Class<?> result = null;
+
+ if (indexedGetter != null) {
+ result = indexedGetter.getReturnType();
+ } else if (indexedSetter != null) {
+ Class<?>[] parameterTypes = indexedSetter.getParameterTypes();
+
+ result = parameterTypes[1];
+ }
+ return result;
+ }
+
+ private void setIndexedReadMethod(Class<?> beanClass, String indexedGetterName) {
+ Method[] getters = findMethods(beanClass, indexedGetterName);
+ boolean result = false;
+
+ for (Method element : getters) {
+ try {
+ setIndexedReadMethod(element);
+ result = true;
+ } catch (IntrospectionException ie) {}
+
+ if (result) {
+ break;
+ }
+ }
+ }
+
+ private void setIndexedWriteMethod(Class<?> beanClass, String indexedSetterName) {
+ Method[] setters = findMethods(beanClass, indexedSetterName);
+ boolean result = false;
+
+ for (Method element : setters) {
+ try {
+ setIndexedWriteMethod(element);
+ result = true;
+ } catch (IntrospectionException ie) {}
+
+ if (result) {
+ break;
+ }
+ }
+ }
+}
diff --git a/awt/java/beans/IntrospectionException.java b/awt/java/beans/IntrospectionException.java
new file mode 100644
index 0000000..c895afe
--- /dev/null
+++ b/awt/java/beans/IntrospectionException.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+public class IntrospectionException extends Exception {
+
+ static final long serialVersionUID = -3728150539969542619L;
+
+ public IntrospectionException(String message) {
+ super(message);
+ }
+}
diff --git a/awt/java/beans/PropertyChangeEvent.java b/awt/java/beans/PropertyChangeEvent.java
new file mode 100644
index 0000000..97c703a
--- /dev/null
+++ b/awt/java/beans/PropertyChangeEvent.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.util.EventObject;
+
+public class PropertyChangeEvent extends EventObject {
+
+ private static final long serialVersionUID = 7042693688939648123L;
+
+ String propertyName;
+
+ Object oldValue;
+
+ Object newValue;
+
+ Object propagationId;
+
+ public PropertyChangeEvent(Object source, String propertyName,
+ Object oldValue, Object newValue) {
+ super(source);
+
+ this.propertyName = propertyName;
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ public void setPropagationId(Object propagationId) {
+ this.propagationId = propagationId;
+ }
+
+ public Object getPropagationId() {
+ return propagationId;
+ }
+
+ public Object getOldValue() {
+ return oldValue;
+ }
+
+ public Object getNewValue() {
+ return newValue;
+ }
+}
diff --git a/awt/java/beans/PropertyChangeListener.java b/awt/java/beans/PropertyChangeListener.java
new file mode 100644
index 0000000..94422c0
--- /dev/null
+++ b/awt/java/beans/PropertyChangeListener.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.util.EventListener;
+
+public interface PropertyChangeListener extends EventListener {
+
+ public void propertyChange(PropertyChangeEvent event);
+}
diff --git a/awt/java/beans/PropertyChangeListenerProxy.java b/awt/java/beans/PropertyChangeListenerProxy.java
new file mode 100644
index 0000000..f4f3aec
--- /dev/null
+++ b/awt/java/beans/PropertyChangeListenerProxy.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.util.EventListenerProxy;
+
+public class PropertyChangeListenerProxy extends EventListenerProxy implements
+ PropertyChangeListener {
+
+ String propertyName;
+
+ public PropertyChangeListenerProxy(String propertyName,
+ PropertyChangeListener listener) {
+ super(listener);
+ this.propertyName = propertyName;
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ public void propertyChange(PropertyChangeEvent event) {
+ PropertyChangeListener listener = (PropertyChangeListener) getListener();
+ listener.propertyChange(event);
+ }
+}
diff --git a/awt/java/beans/PropertyChangeSupport.java b/awt/java/beans/PropertyChangeSupport.java
new file mode 100644
index 0000000..d56e63a
--- /dev/null
+++ b/awt/java/beans/PropertyChangeSupport.java
@@ -0,0 +1,351 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class PropertyChangeSupport implements Serializable {
+
+ private static final long serialVersionUID = 6401253773779951803l;
+
+ private transient Object sourceBean;
+
+ private transient List<PropertyChangeListener> allPropertiesChangeListeners =
+ new ArrayList<PropertyChangeListener>();
+
+ private transient Map<String, List<PropertyChangeListener>>
+ selectedPropertiesChangeListeners =
+ new HashMap<String, List<PropertyChangeListener>>();
+
+ // fields for serialization compatibility
+ private Hashtable<String, List<PropertyChangeListener>> children;
+
+ private Object source;
+
+ private int propertyChangeSupportSerializedDataVersion = 1;
+
+ public PropertyChangeSupport(Object sourceBean) {
+ if (sourceBean == null) {
+ throw new NullPointerException();
+ }
+ this.sourceBean = sourceBean;
+ }
+
+ public void firePropertyChange(String propertyName, Object oldValue,
+ Object newValue) {
+ PropertyChangeEvent event = createPropertyChangeEvent(propertyName,
+ oldValue, newValue);
+ doFirePropertyChange(event);
+ }
+
+ public void fireIndexedPropertyChange(String propertyName, int index,
+ Object oldValue, Object newValue) {
+
+ // nulls and equals check done in doFire...
+ doFirePropertyChange(new IndexedPropertyChangeEvent(sourceBean,
+ propertyName, oldValue, newValue, index));
+ }
+
+ public synchronized void removePropertyChangeListener(String propertyName,
+ PropertyChangeListener listener) {
+ if ((propertyName != null) && (listener != null)) {
+ List<PropertyChangeListener> listeners =
+ selectedPropertiesChangeListeners.get(propertyName);
+
+ if (listeners != null) {
+ listeners.remove(listener);
+ }
+ }
+ }
+
+ public synchronized void addPropertyChangeListener(String propertyName,
+ PropertyChangeListener listener) {
+ if ((listener != null) && (propertyName != null)) {
+ List<PropertyChangeListener> listeners =
+ selectedPropertiesChangeListeners.get(propertyName);
+
+ if (listeners == null) {
+ listeners = new ArrayList<PropertyChangeListener>();
+ selectedPropertiesChangeListeners.put(propertyName, listeners);
+ }
+
+ // RI compatibility
+ if (listener instanceof PropertyChangeListenerProxy) {
+ PropertyChangeListenerProxy proxy =
+ (PropertyChangeListenerProxy) listener;
+
+ listeners.add(new PropertyChangeListenerProxy(
+ proxy.getPropertyName(),
+ (PropertyChangeListener) proxy.getListener()));
+ } else {
+ listeners.add(listener);
+ }
+ }
+ }
+
+ public synchronized PropertyChangeListener[] getPropertyChangeListeners(
+ String propertyName) {
+ List<PropertyChangeListener> listeners = null;
+
+ if (propertyName != null) {
+ listeners = selectedPropertiesChangeListeners.get(propertyName);
+ }
+
+ return (listeners == null) ? new PropertyChangeListener[] {}
+ : listeners.toArray(
+ new PropertyChangeListener[listeners.size()]);
+ }
+
+ public void firePropertyChange(String propertyName, boolean oldValue,
+ boolean newValue) {
+ PropertyChangeEvent event = createPropertyChangeEvent(propertyName,
+ oldValue, newValue);
+ doFirePropertyChange(event);
+ }
+
+ public void fireIndexedPropertyChange(String propertyName, int index,
+ boolean oldValue, boolean newValue) {
+
+ if (oldValue != newValue) {
+ fireIndexedPropertyChange(propertyName, index, Boolean
+ .valueOf(oldValue), Boolean.valueOf(newValue));
+ }
+ }
+
+ public void firePropertyChange(String propertyName, int oldValue,
+ int newValue) {
+ PropertyChangeEvent event = createPropertyChangeEvent(propertyName,
+ oldValue, newValue);
+ doFirePropertyChange(event);
+ }
+
+ public void fireIndexedPropertyChange(String propertyName, int index,
+ int oldValue, int newValue) {
+
+ if (oldValue != newValue) {
+ fireIndexedPropertyChange(propertyName, index,
+ new Integer(oldValue), new Integer(newValue));
+ }
+ }
+
+ public synchronized boolean hasListeners(String propertyName) {
+ boolean result = allPropertiesChangeListeners.size() > 0;
+ if (!result && (propertyName != null)) {
+ List<PropertyChangeListener> listeners =
+ selectedPropertiesChangeListeners.get(propertyName);
+ if (listeners != null) {
+ result = listeners.size() > 0;
+ }
+ }
+ return result;
+ }
+
+ public synchronized void removePropertyChangeListener(
+ PropertyChangeListener listener) {
+ if (listener != null) {
+ if (listener instanceof PropertyChangeListenerProxy) {
+ String name = ((PropertyChangeListenerProxy) listener)
+ .getPropertyName();
+ PropertyChangeListener lst = (PropertyChangeListener)
+ ((PropertyChangeListenerProxy) listener).getListener();
+
+ removePropertyChangeListener(name, lst);
+ } else {
+ allPropertiesChangeListeners.remove(listener);
+ }
+ }
+ }
+
+ public synchronized void addPropertyChangeListener(
+ PropertyChangeListener listener) {
+ if (listener != null) {
+ if (listener instanceof PropertyChangeListenerProxy) {
+ String name = ((PropertyChangeListenerProxy) listener)
+ .getPropertyName();
+ PropertyChangeListener lst = (PropertyChangeListener)
+ ((PropertyChangeListenerProxy) listener).getListener();
+ addPropertyChangeListener(name, lst);
+ } else {
+ allPropertiesChangeListeners.add(listener);
+ }
+ }
+ }
+
+ public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
+ ArrayList<PropertyChangeListener> result =
+ new ArrayList<PropertyChangeListener>(
+ allPropertiesChangeListeners);
+
+ for (String propertyName : selectedPropertiesChangeListeners.keySet()) {
+ List<PropertyChangeListener> selectedListeners =
+ selectedPropertiesChangeListeners.get(propertyName);
+
+ if (selectedListeners != null) {
+
+ for (PropertyChangeListener listener : selectedListeners) {
+ result.add(new PropertyChangeListenerProxy(propertyName,
+ listener));
+ }
+ }
+ }
+
+ return result.toArray(new PropertyChangeListener[result.size()]);
+ }
+
+ private void writeObject(ObjectOutputStream oos) throws IOException {
+ List<PropertyChangeListener> allSerializedPropertiesChangeListeners =
+ new ArrayList<PropertyChangeListener>();
+
+ for (PropertyChangeListener pcl : allPropertiesChangeListeners) {
+ if (pcl instanceof Serializable) {
+ allSerializedPropertiesChangeListeners.add(pcl);
+ }
+ }
+
+ Map<String, List<PropertyChangeListener>>
+ selectedSerializedPropertiesChangeListeners =
+ new HashMap<String, List<PropertyChangeListener>>();
+
+ for (String propertyName : selectedPropertiesChangeListeners.keySet()) {
+ List<PropertyChangeListener> keyValues =
+ selectedPropertiesChangeListeners.get(propertyName);
+
+ if (keyValues != null) {
+ List<PropertyChangeListener> serializedPropertiesChangeListeners
+ = new ArrayList<PropertyChangeListener>();
+
+ for (PropertyChangeListener pcl : keyValues) {
+ if (pcl instanceof Serializable) {
+ serializedPropertiesChangeListeners.add(pcl);
+ }
+ }
+
+ if (!serializedPropertiesChangeListeners.isEmpty()) {
+ selectedSerializedPropertiesChangeListeners.put(
+ propertyName, serializedPropertiesChangeListeners);
+ }
+ }
+ }
+
+ children = new Hashtable<String, List<PropertyChangeListener>>(
+ selectedSerializedPropertiesChangeListeners);
+ children.put("", allSerializedPropertiesChangeListeners); //$NON-NLS-1$
+ oos.writeObject(children);
+
+ Object source = null;
+ if (sourceBean instanceof Serializable) {
+ source = sourceBean;
+ }
+ oos.writeObject(source);
+
+ oos.writeInt(propertyChangeSupportSerializedDataVersion);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void readObject(ObjectInputStream ois) throws IOException,
+ ClassNotFoundException {
+ children = (Hashtable<String, List<PropertyChangeListener>>) ois
+ .readObject();
+
+ selectedPropertiesChangeListeners = new HashMap<String, List<PropertyChangeListener>>(
+ children);
+ allPropertiesChangeListeners = selectedPropertiesChangeListeners
+ .remove(""); //$NON-NLS-1$
+ if (allPropertiesChangeListeners == null) {
+ allPropertiesChangeListeners = new ArrayList<PropertyChangeListener>();
+ }
+
+ sourceBean = ois.readObject();
+ propertyChangeSupportSerializedDataVersion = ois.readInt();
+ }
+
+ public void firePropertyChange(PropertyChangeEvent event) {
+ doFirePropertyChange(event);
+ }
+
+ private PropertyChangeEvent createPropertyChangeEvent(String propertyName,
+ Object oldValue, Object newValue) {
+ return new PropertyChangeEvent(sourceBean, propertyName, oldValue,
+ newValue);
+ }
+
+ private PropertyChangeEvent createPropertyChangeEvent(String propertyName,
+ boolean oldValue, boolean newValue) {
+ return new PropertyChangeEvent(sourceBean, propertyName, oldValue,
+ newValue);
+ }
+
+ private PropertyChangeEvent createPropertyChangeEvent(String propertyName,
+ int oldValue, int newValue) {
+ return new PropertyChangeEvent(sourceBean, propertyName, oldValue,
+ newValue);
+ }
+
+ private void doFirePropertyChange(PropertyChangeEvent event) {
+ String propertyName = event.getPropertyName();
+ Object oldValue = event.getOldValue();
+ Object newValue = event.getNewValue();
+
+ if ((newValue != null) && (oldValue != null)
+ && newValue.equals(oldValue)) {
+ return;
+ }
+
+ /*
+ * Copy the listeners collections so they can be modified while we fire
+ * events.
+ */
+
+ // Listeners to all property change events
+ PropertyChangeListener[] listensToAll;
+ // Listens to a given property change
+ PropertyChangeListener[] listensToOne = null;
+ synchronized (this) {
+ listensToAll = allPropertiesChangeListeners
+ .toArray(new PropertyChangeListener[allPropertiesChangeListeners
+ .size()]);
+
+ List<PropertyChangeListener> listeners = selectedPropertiesChangeListeners
+ .get(propertyName);
+ if (listeners != null) {
+ listensToOne = listeners
+ .toArray(new PropertyChangeListener[listeners.size()]);
+ }
+ }
+
+ // Fire the listeners
+ for (PropertyChangeListener listener : listensToAll) {
+ listener.propertyChange(event);
+ }
+ if (listensToOne != null) {
+ for (PropertyChangeListener listener : listensToOne) {
+ listener.propertyChange(event);
+ }
+ }
+ }
+
+}
diff --git a/awt/java/beans/PropertyDescriptor.java b/awt/java/beans/PropertyDescriptor.java
new file mode 100644
index 0000000..9389152
--- /dev/null
+++ b/awt/java/beans/PropertyDescriptor.java
@@ -0,0 +1,300 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Vector;
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class PropertyDescriptor extends FeatureDescriptor {
+ private Method getter;
+
+ private Method setter;
+
+ private Class<?> propertyEditorClass;
+
+ private boolean constrained;
+
+ private boolean bound;
+
+ public PropertyDescriptor(String propertyName, Class<?> beanClass, String getterName,
+ String setterName) throws IntrospectionException {
+ super();
+ if (beanClass == null) {
+ throw new IntrospectionException(Messages.getString("beans.03")); //$NON-NLS-1$
+ }
+ if (propertyName == null || propertyName.length() == 0) {
+ throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$
+ }
+ this.setName(propertyName);
+ this.setDisplayName(propertyName);
+ if (setterName != null) {
+ if (hasMethod(beanClass, setterName)) {
+ setWriteMethod(beanClass, setterName);
+ } else {
+ throw new IntrospectionException(Messages.getString("beans.20")); //$NON-NLS-1$
+ }
+ }
+ if (getterName != null) {
+ if (hasMethod(beanClass, getterName)) {
+ setReadMethod(beanClass, getterName);
+ } else {
+ throw new IntrospectionException(Messages.getString("beans.1F")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ public PropertyDescriptor(String propertyName, Method getter, Method setter)
+ throws IntrospectionException {
+ super();
+ if (propertyName == null || propertyName.length() == 0) {
+ throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$
+ }
+ this.setName(propertyName);
+ this.setDisplayName(propertyName);
+ setWriteMethod(setter);
+ setReadMethod(getter);
+ }
+
+ public PropertyDescriptor(String propertyName, Class<?> beanClass)
+ throws IntrospectionException {
+ String getterName;
+ String setterName;
+ if (beanClass == null) {
+ throw new IntrospectionException(Messages.getString("beans.03")); //$NON-NLS-1$
+ }
+ if (propertyName == null || propertyName.length() == 0) {
+ throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$
+ }
+ this.setName(propertyName);
+ this.setDisplayName(propertyName);
+ getterName = createDefaultMethodName(propertyName, "is"); //$NON-NLS-1$
+ if (hasMethod(beanClass, getterName)) {
+ setReadMethod(beanClass, getterName);
+ } else {
+ getterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$
+ if (hasMethod(beanClass, getterName)) {
+ setReadMethod(beanClass, getterName);
+ }
+ }
+ setterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$
+ if (hasMethod(beanClass, setterName)) {
+ setWriteMethod(beanClass, setterName);
+ }
+ if (getter == null && setter == null) {
+ throw new IntrospectionException(Messages.getString("beans.01", propertyName)); //$NON-NLS-1$
+ }
+ }
+
+ public void setWriteMethod(Method setter) throws IntrospectionException {
+ if (setter != null) {
+ int modifiers = setter.getModifiers();
+ if (!Modifier.isPublic(modifiers)) {
+ throw new IntrospectionException(Messages.getString("beans.05")); //$NON-NLS-1$
+ }
+ Class<?>[] parameterTypes = setter.getParameterTypes();
+ if (parameterTypes.length != 1) {
+ throw new IntrospectionException(Messages.getString("beans.06")); //$NON-NLS-1$
+ }
+ Class<?> parameterType = parameterTypes[0];
+ Class<?> propertyType = getPropertyType();
+ if (propertyType != null && !propertyType.equals(parameterType)) {
+ throw new IntrospectionException(Messages.getString("beans.07")); //$NON-NLS-1$
+ }
+ }
+ this.setter = setter;
+ }
+
+ public void setReadMethod(Method getter) throws IntrospectionException {
+ if (getter != null) {
+ int modifiers = getter.getModifiers();
+ if (!Modifier.isPublic(modifiers)) {
+ throw new IntrospectionException(Messages.getString("beans.0A")); //$NON-NLS-1$
+ }
+ Class<?>[] parameterTypes = getter.getParameterTypes();
+ if (parameterTypes.length != 0) {
+ throw new IntrospectionException(Messages.getString("beans.08")); //$NON-NLS-1$
+ }
+ Class<?> returnType = getter.getReturnType();
+ if (returnType.equals(Void.TYPE)) {
+ throw new IntrospectionException(Messages.getString("beans.33")); //$NON-NLS-1$
+ }
+ Class<?> propertyType = getPropertyType();
+ if ((propertyType != null) && !returnType.equals(propertyType)) {
+ throw new IntrospectionException(Messages.getString("beans.09")); //$NON-NLS-1$
+ }
+ }
+ this.getter = getter;
+ }
+
+ public Method getWriteMethod() {
+ return setter;
+ }
+
+ public Method getReadMethod() {
+ return getter;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ boolean result = (object != null && object instanceof PropertyDescriptor);
+ if (result) {
+ PropertyDescriptor pd = (PropertyDescriptor) object;
+ boolean gettersAreEqual = (this.getter == null) && (pd.getReadMethod() == null)
+ || (this.getter != null) && (this.getter.equals(pd.getReadMethod()));
+ boolean settersAreEqual = (this.setter == null) && (pd.getWriteMethod() == null)
+ || (this.setter != null) && (this.setter.equals(pd.getWriteMethod()));
+ boolean propertyTypesAreEqual = this.getPropertyType() == pd.getPropertyType();
+ boolean propertyEditorClassesAreEqual = this.getPropertyEditorClass() == pd
+ .getPropertyEditorClass();
+ boolean boundPropertyAreEqual = this.isBound() == pd.isBound();
+ boolean constrainedPropertyAreEqual = this.isConstrained() == pd.isConstrained();
+ result = gettersAreEqual && settersAreEqual && propertyTypesAreEqual
+ && propertyEditorClassesAreEqual && boundPropertyAreEqual
+ && constrainedPropertyAreEqual;
+ }
+ return result;
+ }
+
+ public void setPropertyEditorClass(Class<?> propertyEditorClass) {
+ this.propertyEditorClass = propertyEditorClass;
+ }
+
+ public Class<?> getPropertyType() {
+ Class<?> result = null;
+ if (getter != null) {
+ result = getter.getReturnType();
+ } else if (setter != null) {
+ Class<?>[] parameterTypes = setter.getParameterTypes();
+ result = parameterTypes[0];
+ }
+ return result;
+ }
+
+ public Class<?> getPropertyEditorClass() {
+ return propertyEditorClass;
+ }
+
+ public void setConstrained(boolean constrained) {
+ this.constrained = constrained;
+ }
+
+ public void setBound(boolean bound) {
+ this.bound = bound;
+ }
+
+ public boolean isConstrained() {
+ return constrained;
+ }
+
+ public boolean isBound() {
+ return bound;
+ }
+
+ boolean hasMethod(Class<?> beanClass, String methodName) {
+ Method[] methods = findMethods(beanClass, methodName);
+ return (methods.length > 0);
+ }
+
+ String createDefaultMethodName(String propertyName, String prefix) {
+ String result = null;
+ if (propertyName != null) {
+ String bos = propertyName.substring(0, 1).toUpperCase();
+ String eos = propertyName.substring(1, propertyName.length());
+ result = prefix + bos + eos;
+ }
+ return result;
+ }
+
+ Method[] findMethods(Class<?> aClass, String methodName) {
+ Method[] allMethods = aClass.getMethods();
+ Vector<Method> matchedMethods = new Vector<Method>();
+ Method[] result;
+ for (Method method : allMethods) {
+ if (method.getName().equals(methodName)) {
+ matchedMethods.add(method);
+ }
+ }
+ result = new Method[matchedMethods.size()];
+ for (int j = 0; j < matchedMethods.size(); ++j) {
+ result[j] = matchedMethods.elementAt(j);
+ }
+ return result;
+ }
+
+ void setReadMethod(Class<?> beanClass, String getterName) {
+ boolean result = false;
+ Method[] getters = findMethods(beanClass, getterName);
+ for (Method element : getters) {
+ try {
+ setReadMethod(element);
+ result = true;
+ } catch (IntrospectionException ie) {
+ }
+ if (result) {
+ break;
+ }
+ }
+ }
+
+ void setWriteMethod(Class<?> beanClass, String setterName) throws IntrospectionException {
+ boolean result = false;
+ Method[] setters = findMethods(beanClass, setterName);
+ for (Method element : setters) {
+ try {
+ setWriteMethod(element);
+ result = true;
+ } catch (IntrospectionException ie) {
+ }
+ if (result) {
+ break;
+ }
+ }
+ }
+
+ public PropertyEditor createPropertyEditor(Object bean) {
+ PropertyEditor editor;
+ if (propertyEditorClass == null) {
+ return null;
+ }
+ if (!PropertyEditor.class.isAssignableFrom(propertyEditorClass)) {
+ // beans.48=Property editor is not assignable from the
+ // PropertyEditor interface
+ throw new ClassCastException(Messages.getString("beans.48")); //$NON-NLS-1$
+ }
+ try {
+ Constructor<?> constr;
+ try {
+ // try to look for the constructor with single Object argument
+ constr = propertyEditorClass.getConstructor(Object.class);
+ editor = (PropertyEditor) constr.newInstance(bean);
+ } catch (NoSuchMethodException e) {
+ // try no-argument constructor
+ constr = propertyEditorClass.getConstructor();
+ editor = (PropertyEditor) constr.newInstance();
+ }
+ } catch (Exception e) {
+ // beans.47=Unable to instantiate property editor
+ RuntimeException re = new RuntimeException(Messages.getString("beans.47"), e); //$NON-NLS-1$
+ throw re;
+ }
+ return editor;
+ }
+}
diff --git a/awt/java/beans/PropertyEditor.java b/awt/java/beans/PropertyEditor.java
new file mode 100644
index 0000000..65bedea
--- /dev/null
+++ b/awt/java/beans/PropertyEditor.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+
+public interface PropertyEditor {
+
+ public void paintValue(Graphics gfx, Rectangle box);
+
+ public void setAsText(String text) throws IllegalArgumentException;
+
+ public String[] getTags();
+
+ public String getJavaInitializationString();
+
+ public String getAsText();
+
+ public void setValue(Object value);
+
+ public Object getValue();
+
+ public void removePropertyChangeListener(PropertyChangeListener listener);
+
+ public void addPropertyChangeListener(PropertyChangeListener listener);
+
+ public Component getCustomEditor();
+
+ public boolean supportsCustomEditor();
+
+ public boolean isPaintable();
+}
diff --git a/awt/java/beans/PropertyEditorManager.java b/awt/java/beans/PropertyEditorManager.java
new file mode 100644
index 0000000..ed55829
--- /dev/null
+++ b/awt/java/beans/PropertyEditorManager.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class PropertyEditorManager {
+
+ private static String[] path = { "org.apache.harmony.beans.editors" }; //$NON-NLS-1$
+
+ private static final Map<Class<?>, Class<?>> registeredEditors = new HashMap<Class<?>, Class<?>>();
+
+ public PropertyEditorManager() {
+ }
+
+ public static void registerEditor(Class<?> targetType, Class<?> editorClass) {
+ if (targetType == null) {
+ throw new NullPointerException();
+ }
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPropertiesAccess();
+ }
+ if (editorClass != null) {
+ registeredEditors.put(targetType, editorClass);
+ } else {
+ registeredEditors.remove(targetType);
+ }
+ }
+
+ public static synchronized PropertyEditor findEditor(Class<?> targetType) {
+ if (targetType == null) {
+ throw new NullPointerException();
+ }
+
+ Class<?> editorClass = null;
+ PropertyEditor editor = null;
+
+ editorClass = registeredEditors.get(targetType);
+
+ if (editorClass == null) {
+ String editorClassName = targetType.getName() + "Editor"; //$NON-NLS-1$
+ ClassLoader loader = targetType.getClassLoader();
+
+ if (loader == null) {
+ loader = Thread.currentThread().getContextClassLoader();
+ }
+
+ try {
+ editorClass = Class.forName(editorClassName, true, loader);
+ } catch (ClassNotFoundException cnfe) {
+ String shortEditorClassName = editorClassName
+ .substring(editorClassName.lastIndexOf(".") + 1); //$NON-NLS-1$
+
+ if (targetType.isPrimitive()) {
+ shortEditorClassName = shortEditorClassName.substring(0, 1)
+ .toUpperCase()
+ + shortEditorClassName.substring(1);
+ }
+
+ for (String element : path) {
+ editorClassName = element + "." + shortEditorClassName; //$NON-NLS-1$
+
+ try {
+ editorClass = Class.forName(editorClassName, true,
+ loader);
+ break;
+ } catch (Exception e) {
+ }
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ if (editorClass != null) {
+ try {
+ editor = (PropertyEditor) editorClass.newInstance();
+ } catch (Exception e) {
+ }
+ }
+
+ return editor;
+ }
+
+ public static synchronized void setEditorSearchPath(String[] apath) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPropertiesAccess();
+ }
+
+ path = apath;
+ }
+
+ public static synchronized String[] getEditorSearchPath() {
+ return path;
+ }
+}
diff --git a/awt/java/beans/PropertyEditorSupport.java b/awt/java/beans/PropertyEditorSupport.java
new file mode 100644
index 0000000..c3929a1
--- /dev/null
+++ b/awt/java/beans/PropertyEditorSupport.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package java.beans;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.beans.internal.nls.Messages;
+
+public class PropertyEditorSupport implements PropertyEditor {
+
+ Object source = null;
+
+ List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
+
+ Object oldValue = null;
+
+ Object newValue = null;
+
+ public PropertyEditorSupport(Object source) {
+ if (source == null) {
+ throw new NullPointerException(Messages.getString("beans.0C")); //$NON-NLS-1$
+ }
+ this.source = source;
+ }
+
+ public PropertyEditorSupport() {
+ source = this;
+ }
+
+ public void paintValue(Graphics gfx, Rectangle box) {
+ }
+
+ public void setAsText(String text) throws IllegalArgumentException {
+ if (newValue instanceof String) {
+ setValue(text);
+ } else {
+ throw new IllegalArgumentException(text);
+ }
+ }
+
+ public String[] getTags() {
+ return null;
+ }
+
+ public String getJavaInitializationString() {
+ return "???"; //$NON-NLS-1$
+ }
+
+ public String getAsText() {
+ return newValue == null ? "null" : newValue.toString(); //$NON-NLS-1$
+ }
+
+ public void setValue(Object value) {
+ this.oldValue = this.newValue;
+ this.newValue = value;
+ firePropertyChange();
+ }
+
+ public Object getValue() {
+ return newValue;
+ }
+
+ public void setSource(Object source) {
+ if (source == null) {
+ throw new NullPointerException(Messages.getString("beans.0C")); //$NON-NLS-1$
+ }
+ this.source = source;
+ }
+
+ public Object getSource() {
+ return source;
+ }
+
+ public synchronized void removePropertyChangeListener(
+ PropertyChangeListener listener) {
+ if (listeners != null) {
+ listeners.remove(listener);
+ }
+ }
+
+ public synchronized void addPropertyChangeListener(
+ PropertyChangeListener listener) {
+ listeners.add(listener);
+ }
+
+ public Component getCustomEditor() {
+ return null;
+ }
+
+ public boolean supportsCustomEditor() {
+ return false;
+ }
+
+ public boolean isPaintable() {
+ return false;
+ }
+
+ public void firePropertyChange() {
+ if (listeners.size() > 0) {
+ PropertyChangeEvent event = new PropertyChangeEvent(source, null,
+ oldValue, newValue);
+ Iterator<PropertyChangeListener> iterator = listeners.iterator();
+
+ while (iterator.hasNext()) {
+ PropertyChangeListener listener = iterator.next();
+ listener.propertyChange(event);
+ }
+ }
+ }
+}
diff --git a/awt/java/beans/PropertyVetoException.java b/awt/java/beans/PropertyVetoException.java
new file mode 100644
index 0000000..c7f092a
--- /dev/null
+++ b/awt/java/beans/PropertyVetoException.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.beans;
+
+/**
+ * Indicates that a proposed property change is unacceptable.
+ */
+public class PropertyVetoException extends Exception {
+
+ private static final long serialVersionUID = 129596057694162164L;
+
+ private final PropertyChangeEvent evt;
+
+ /**
+ * <p>
+ * Constructs an instance with a message and the change event.
+ * </p>
+ *
+ * @param message
+ * A description of the veto.
+ * @param event
+ * The event that was vetoed.
+ */
+ public PropertyVetoException(String message, PropertyChangeEvent event) {
+ super(message);
+ this.evt = event;
+ }
+
+ /**
+ * <p>
+ * Gets the property change event.
+ * </p>
+ *
+ * @return An instance of {@link PropertyChangeEvent}
+ */
+ public PropertyChangeEvent getPropertyChangeEvent() {
+ return evt;
+ }
+}
diff --git a/awt/javax/imageio/IIOException.java b/awt/javax/imageio/IIOException.java
new file mode 100644
index 0000000..fbfeb42
--- /dev/null
+++ b/awt/javax/imageio/IIOException.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import java.io.IOException;
+
+/**
+ * The IIOException class indicates errors in reading/writing operations.
+ */
+public class IIOException extends IOException {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -3216210718638985251L;
+
+ /**
+ * Instantiates a new IIOException.
+ *
+ * @param message the detailed message.
+ */
+ public IIOException(String message) {
+ super(message);
+ }
+
+ /**
+ * Instantiates a new IIOException.
+ *
+ * @param message the detailed message.
+ * @param cause the cause of this exception.
+ */
+ public IIOException(String message, Throwable cause) {
+ super(message);
+ initCause(cause);
+ }
+}
diff --git a/awt/javax/imageio/IIOImage.java b/awt/javax/imageio/IIOImage.java
new file mode 100644
index 0000000..e17a9fc
--- /dev/null
+++ b/awt/javax/imageio/IIOImage.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import javax.imageio.metadata.IIOMetadata;
+import java.awt.image.RenderedImage;
+import java.awt.image.Raster;
+import java.awt.image.BufferedImage;
+import java.util.List;
+
+/**
+ * The IIOImage class combines the image, image's thumbnail and image's metadata.
+ * The image can be presented as RenderedImage or Raster object.
+ */
+public class IIOImage {
+
+ /** The image of this IIOImage. */
+ protected RenderedImage image;
+
+ /** The raster of this IIOImage. */
+ protected Raster raster;
+
+ /** The list with thumbnails associated with the image. */
+ protected List<? extends BufferedImage> thumbnails;
+
+ /** The metadata associated with the image. */
+ protected IIOMetadata metadata;
+
+ /**
+ * Instantiates a new IIOImage with the specified RenderedImage,
+ * list of thumbnails and metadata.
+ *
+ * @param image the image specified by RenderedImage.
+ * @param thumbnails the list of BufferedImage objects which
+ * represent the thumbnails of the image.
+ * @param metadata the metadata of the image.
+ */
+ public IIOImage(RenderedImage image, List<? extends BufferedImage> thumbnails, IIOMetadata metadata) {
+ if (image == null) {
+ throw new IllegalArgumentException("image should not be NULL");
+ }
+ this.raster = null;
+ this.image = image;
+ this.thumbnails = thumbnails;
+ this.metadata = metadata;
+ }
+
+ /**
+ * Instantiates a new IIOImage with the specified Raster, list of
+ * thumbnails and metadata.
+ *
+ * @param raster the Raster.
+ * @param thumbnails the list of BufferedImage objects which
+ * represent the thumbnails of Raster data.
+ * @param metadata the metadata.
+ */
+ public IIOImage(Raster raster, List<? extends BufferedImage> thumbnails, IIOMetadata metadata) {
+ if (raster == null) {
+ throw new IllegalArgumentException("raster should not be NULL");
+ }
+ this.image = null;
+ this.raster = raster;
+ this.thumbnails = thumbnails;
+ this.metadata = metadata;
+ }
+
+ /**
+ * Gets the RenderedImage object or returns null if this IIOImage
+ * object is associated with a Raster.
+ *
+ * @return the RenderedImage object or null if this IIOImage
+ * object is associated with a Raster.
+ */
+ public RenderedImage getRenderedImage() {
+ return image;
+ }
+
+ /**
+ * Sets the RenderedImage to this IIOImage object.
+ *
+ * @param image the RenderedImage to be set to this IIOImage.
+ */
+ public void setRenderedImage(RenderedImage image) {
+ if (image == null) {
+ throw new IllegalArgumentException("image should not be NULL");
+ }
+ raster = null;
+ this.image = image;
+ }
+
+ /**
+ * Returns true if the IIOImage object associated with a Raster, or
+ * false if it's associated with a RenderedImage.
+ *
+ * @return true if the IIOImage object associated with a Raster, or
+ * false if it's associated with a RenderedImage.
+ */
+ public boolean hasRaster() {
+ return raster != null;
+ }
+
+ /**
+ * Gets the Raster object or returns null if this IIOImage object is
+ * associated with a RenderedImage.
+ *
+ * @return the Raster or null if this IIOImage object
+ * is associated with a RenderedImage.
+ */
+ public Raster getRaster() {
+ return raster;
+ }
+
+ /**
+ * Sets the Raster to the IIOImage.
+ *
+ * @param raster the new Raster to the IIOImage.
+ */
+ public void setRaster(Raster raster) {
+ if (raster == null) {
+ throw new IllegalArgumentException("raster should not be NULL");
+ }
+ image = null;
+ this.raster = raster;
+ }
+
+ /**
+ * Gets the number of thumbnails for this IIOImage.
+ *
+ * @return the number of thumbnails for this IIOImage.
+ */
+ public int getNumThumbnails() {
+ return thumbnails != null ? thumbnails.size() : 0;
+ }
+
+ /**
+ * Gets the thumbnail with the specified index in the list.
+ *
+ * @param index the index of the thumbnail in the list.
+ *
+ * @return the thumbnail with the specified index in the list.
+ */
+ public BufferedImage getThumbnail(int index) {
+ if (thumbnails != null) {
+ return thumbnails.get(index);
+ }
+ throw new IndexOutOfBoundsException("no thumbnails were set");
+ }
+
+ /**
+ * Gets the list of thumbnails.
+ *
+ * @return the list of thumbnails.
+ */
+ public List<? extends BufferedImage> getThumbnails() {
+ return thumbnails;
+ }
+
+ /**
+ * Sets the list of thumbnails images to this IIOImage object.
+ *
+ * @param thumbnails the list of BufferedImage which represent
+ * thumbnails.
+ */
+ public void setThumbnails(List<? extends BufferedImage> thumbnails) {
+ this.thumbnails = thumbnails;
+ }
+
+ /**
+ * Gets the metadata of this IIOImage.
+ *
+ * @return the metadata of this IIOImage.
+ */
+ public IIOMetadata getMetadata() {
+ return metadata;
+ }
+
+ /**
+ * Sets the metadata to this IIOImage object.
+ *
+ * @param metadata the IIOMetadata, or null.
+ */
+ public void setMetadata(IIOMetadata metadata) {
+ this.metadata = metadata;
+ }
+}
diff --git a/awt/javax/imageio/IIOParam.java b/awt/javax/imageio/IIOParam.java
new file mode 100644
index 0000000..d998b6e
--- /dev/null
+++ b/awt/javax/imageio/IIOParam.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import java.awt.*;
+
+/**
+ * The IIOParam abstract class is superclass for
+ * ImageReadParam and ImageWriteParam classes and provides
+ * methods and variables which they share.
+ */
+public abstract class IIOParam {
+
+ /** The source region. */
+ protected Rectangle sourceRegion;
+
+ /** The source x subsampling. */
+ protected int sourceXSubsampling = 1;
+
+ /** The source y subsampling. */
+ protected int sourceYSubsampling = 1;
+
+ /** The subsampling x offset. */
+ protected int subsamplingXOffset;
+
+ /** The subsampling y offset. */
+ protected int subsamplingYOffset;
+
+ /** The source bands. */
+ protected int[] sourceBands;
+
+ /** The destination type. */
+ protected ImageTypeSpecifier destinationType;
+
+ /** The destination offset. */
+ protected Point destinationOffset = new Point(0, 0);
+
+ /** The default controller. */
+ protected IIOParamController defaultController;
+
+ /** The controller. */
+ protected IIOParamController controller;
+
+ /**
+ * Instantiates a new IIOParam.
+ */
+ protected IIOParam() {}
+
+ /**
+ * Sets the source region as a Rectangle object.
+ *
+ * @param sourceRegion the Rectangle which specifies the source region.
+ */
+ public void setSourceRegion(Rectangle sourceRegion) {
+ if (sourceRegion != null) {
+ if (sourceRegion.x < 0) {
+ throw new IllegalArgumentException("x < 0");
+ }
+ if (sourceRegion.y < 0) {
+ throw new IllegalArgumentException("y < 0");
+ }
+ if (sourceRegion.width <= 0) {
+ throw new IllegalArgumentException("width <= 0");
+ }
+ if (sourceRegion.height <= 0) {
+ throw new IllegalArgumentException("height <= 0");
+ }
+
+ if (sourceRegion.width <= subsamplingXOffset) {
+ throw new IllegalArgumentException("width <= subsamplingXOffset");
+ }
+
+ if (sourceRegion.height <= subsamplingYOffset) {
+ throw new IllegalArgumentException("height <= subsamplingXOffset");
+ }
+ //-- clone it to avoid unexpected modifications
+ this.sourceRegion = (Rectangle) sourceRegion.clone();
+ } else {
+ this.sourceRegion = null;
+ }
+ }
+
+ /**
+ * Gets the source region.
+ *
+ * @return the source region as Rectangle.
+ */
+ public Rectangle getSourceRegion() {
+ if (sourceRegion == null) {
+ return null;
+ }
+ //-- clone it to avoid unexpected modifications
+ return (Rectangle) sourceRegion.clone();
+ }
+
+ /**
+ * Sets the source subsampling. The sourceXSubsampling and
+ * sourceYSubsampling parameters specify the number of rows
+ * and columns to advance after every source pixel.
+ *
+ * @param sourceXSubsampling the source X subsampling.
+ * @param sourceYSubsampling the source Y subsampling.
+ * @param subsamplingXOffset the subsampling X offset.
+ * @param subsamplingYOffset the subsampling Y offset.
+ */
+ public void setSourceSubsampling(int sourceXSubsampling,
+ int sourceYSubsampling,
+ int subsamplingXOffset,
+ int subsamplingYOffset) {
+
+ if (sourceXSubsampling <= 0) {
+ throw new IllegalArgumentException("sourceXSubsampling <= 0");
+ }
+ if (sourceYSubsampling <= 0) {
+ throw new IllegalArgumentException("sourceYSubsampling <= 0");
+ }
+
+ if (subsamplingXOffset <= 0 || subsamplingXOffset >= sourceXSubsampling) {
+ throw new IllegalArgumentException("subsamplingXOffset is wrong");
+ }
+
+ if (subsamplingYOffset <= 0 || subsamplingYOffset >= sourceYSubsampling) {
+ throw new IllegalArgumentException("subsamplingYOffset is wrong");
+ }
+
+ //-- does region contain pixels
+ if (sourceRegion != null) {
+ if (sourceRegion.width <= subsamplingXOffset ||
+ sourceRegion.height <= subsamplingYOffset) {
+ throw new IllegalArgumentException("there are no pixels in region");
+ }
+ }
+
+ this.sourceXSubsampling = sourceXSubsampling;
+ this.sourceYSubsampling = sourceYSubsampling;
+ this.subsamplingXOffset = subsamplingXOffset;
+ this.subsamplingYOffset = subsamplingYOffset;
+ }
+
+ /**
+ * Gets the source X subsampling - the number of source
+ * columns to advance for each pixel.
+ *
+ * @return the source X subsampling.
+ */
+ public int getSourceXSubsampling() {
+ return sourceXSubsampling;
+ }
+
+ /**
+ * Gets the source Y subsampling - the number of source
+ * rows to advance for each pixel.
+ *
+ * @return the source Y subsampling.
+ */
+ public int getSourceYSubsampling() {
+ return sourceYSubsampling;
+ }
+
+ /**
+ * Gets the horizontal offset of the subsampling grid.
+ *
+ * @return the horizontal offset of the subsampling grid.
+ */
+ public int getSubsamplingXOffset() {
+ return subsamplingXOffset;
+ }
+
+ /**
+ * Gets the vertical offset of the subsampling grid.
+ *
+ * @return the vertical offset of the subsampling grid.
+ */
+ public int getSubsamplingYOffset() {
+ return subsamplingYOffset;
+ }
+
+ /**
+ * Sets the indices of the source bands.
+ *
+ * @param sourceBands the indices of the source bands.
+ */
+ public void setSourceBands(int[] sourceBands) {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Gets the array of source bands.
+ *
+ * @return the array of source bands.
+ */
+ public int[] getSourceBands() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Sets the specified ImageTypeSpecifier for the destination image.
+ *
+ * @param destinationType the ImageTypeSpecifier.
+ */
+ public void setDestinationType(ImageTypeSpecifier destinationType) {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Gets the type of the destination image as an ImageTypeSpecifier. .
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public ImageTypeSpecifier getDestinationType() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Sets the offset in the destination image where
+ * the decoded pixels are placed as a result of reading,
+ * or specified an area to be written while writing operation.
+ *
+ * @param destinationOffset the destination offset.
+ */
+ public void setDestinationOffset(Point destinationOffset) {
+ if (destinationOffset == null) {
+ throw new IllegalArgumentException("destinationOffset == null!");
+ }
+
+ this.destinationOffset = (Point) destinationOffset.clone();
+ }
+
+ /**
+ * Gets the offset in the destination image for placing pixels.
+ *
+ * @return the offset in the destination image.
+ */
+ public Point getDestinationOffset() {
+ return (Point) destinationOffset.clone();
+ }
+
+ /**
+ * Sets the IIOParamController to this IIOParam object for
+ * providing settings to this IIOParam.
+ *
+ * @param controller the new IIOParamController.
+ */
+ public void setController(IIOParamController controller) {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Gets the current IIOParamController controller
+ * for this IIOParam.
+ *
+ * @return the current IIOParamController controller
+ * for this IIOParam.
+ */
+ public IIOParamController getController() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Gets the default IIOParamController controller
+ * for this IIOParam.
+ *
+ * @return the default IIOParamController controller
+ * for this IIOParam, or null.
+ */
+ public IIOParamController getDefaultController() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Returns true if IIOParamController is installed for
+ * this IIOParam.
+ *
+ * @return true if IIOParamController is installed for
+ * this IIOParam, false otherwise.
+ */
+ public boolean hasController() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ /**
+ * Activates the controller.
+ *
+ * @return true, if successful, false otherwise.
+ */
+ public boolean activateController() {
+ // TODO implement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+}
diff --git a/awt/javax/imageio/IIOParamController.java b/awt/javax/imageio/IIOParamController.java
new file mode 100644
index 0000000..31522c1
--- /dev/null
+++ b/awt/javax/imageio/IIOParamController.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOParamController specifies an activate method that invokes the
+ * controller.
+ */
+public interface IIOParamController {
+
+ /**
+ * Activates the controller.
+ *
+ * @param param the IIOParam.
+ *
+ * @return true if the IIOParam has been modified, false otherwise.
+ */
+ boolean activate(IIOParam param);
+}
+
diff --git a/awt/javax/imageio/ImageIO.java b/awt/javax/imageio/ImageIO.java
new file mode 100644
index 0000000..d4cd1dd
--- /dev/null
+++ b/awt/javax/imageio/ImageIO.java
@@ -0,0 +1,777 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.spi.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.net.URL;
+
+/**
+ * The ImageIO class provides static methods to perfom
+ * reading and writing operations using registered
+ * ImageReader and ImageWriter objects.
+ */
+public final class ImageIO {
+
+ /** The Constant registry. */
+ private static final IIORegistry registry = IIORegistry.getDefaultInstance();
+
+ /**
+ * Instantiates a new image io.
+ */
+ private ImageIO() {}
+
+
+ /**
+ * Scans for plug-ins in the class path,
+ * loads spi classes, and registers them with the IIORegistry.
+ */
+ public static void scanForPlugins() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Sets flag which indicates whether a cache file is used when
+ * creating ImageInputStreams and ImageOutputStreams or not.
+ *
+ * @param useCache the use cache flag.
+ */
+ public static void setUseCache(boolean useCache) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the flag which indicates whether a cache file is used when
+ * creating ImageInputStreams and ImageOutputStreams or not.
+ * This method returns the current value which is set by setUseCache
+ * method.
+ *
+ * @return the use cache flag.
+ */
+ public static boolean getUseCache() {
+ // TODO implement
+ return false;
+ }
+
+ /**
+ * Sets the cache directory.
+ *
+ * @param cacheDirectory the File which specifies a cache directory.
+ */
+ public static void setCacheDirectory(File cacheDirectory) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the directory where cache files are created, returned
+ * the file which is set by setCacheDirectory method, or null.
+ *
+ * @return the File object which is set by setCacheDirectory method,
+ * or null.
+ */
+ public static File getCacheDirectory() {
+ // TODO implement
+ //-- null indicates system-dep default temporary directory
+ return null;
+ }
+
+ /**
+ * Creates an ImageInputStream from the specified Object.
+ * The specified Object should obtain the input source
+ * such as File, or InputStream.
+ *
+ * @param input the input Object such as File, or InputStream.
+ *
+ * @return the ImageInputStream object, or null.
+ *
+ * @throws IOException signals that an I/O exception has occurred.
+ */
+ public static ImageInputStream createImageInputStream(Object input)
+ throws IOException {
+
+ if (input == null) {
+ throw new IllegalArgumentException("input source cannot be NULL");
+ }
+
+ Iterator<ImageInputStreamSpi> it = registry.getServiceProviders(ImageInputStreamSpi.class, true);
+
+ while (it.hasNext()) {
+ ImageInputStreamSpi spi = it.next();
+ if (spi.getInputClass().isInstance(input)) {
+ return spi.createInputStreamInstance(input);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates an ImageOutputStream using the specified Object.
+ * The specified Object should obtain the output source
+ * such as File, or OutputStream.
+ *
+ * @param output the output Object such as File, or OutputStream.
+ *
+ * @return the ImageOutputStream object, or null.
+ *
+ * @throws IOException signals that an I/O exception has occurred.
+ */
+ public static ImageOutputStream createImageOutputStream(Object output)
+ throws IOException {
+ if (output == null) {
+ throw new IllegalArgumentException("output destination cannot be NULL");
+ }
+
+ Iterator<ImageOutputStreamSpi> it = registry.getServiceProviders(ImageOutputStreamSpi.class, true);
+
+ while (it.hasNext()) {
+ ImageOutputStreamSpi spi = it.next();
+ if (spi.getOutputClass().isInstance(output)) {
+ // todo - use getUseCache and getCacheDir here
+ return spi.createOutputStreamInstance(output);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the array of format names as String which can be
+ * decoded by registered ImageReader objects.
+ *
+ * @return the array of format names.
+ */
+ public static String[] getReaderFormatNames() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the array of MIME types as String which can be
+ * decoded by registered ImageReader objects.
+ *
+ * @return the array of MIME types.
+ */
+ public static String[] getReaderMIMETypes() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the Iterator of registered ImageReader which are able to
+ * decode an imput data specified by input Object.
+ *
+ * @param input the input Object with encoded data such as
+ * ImageInputStream object.
+ *
+ * @return the Iterator of registered ImageReader.
+ */
+ public static Iterator<ImageReader> getImageReaders(Object input) {
+ if (input == null) {
+ throw new NullPointerException("input cannot be NULL");
+ }
+
+ Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+ new CanReadFilter(input), true);
+
+ return new SpiIteratorToReadersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator of registered ImageReader which are able to
+ * decode the specified format.
+ *
+ * @param formatName the format name such as "jpeg", or "gif".
+ *
+ * @return the Iterator of registered ImageReader.
+ */
+ public static Iterator<ImageReader> getImageReadersByFormatName(String formatName) {
+ if (formatName == null) {
+ throw new NullPointerException("format name cannot be NULL");
+ }
+
+ Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+ new FormatFilter(formatName), true);
+
+ return new SpiIteratorToReadersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator which lists the registered ImageReader objects that
+ * are able to decode files with the specified suffix.
+ *
+ * @param fileSuffix the file suffix such as "jpg".
+ *
+ * @return the Iterator of registered ImageReaders.
+ */
+ public static Iterator<ImageReader> getImageReadersBySuffix(String fileSuffix) {
+ if (fileSuffix == null) {
+ throw new NullPointerException("suffix cannot be NULL");
+ }
+ Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+ new SuffixFilter(fileSuffix), true);
+
+ return new SpiIteratorToReadersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator of registered ImageReader objects that
+ * are able to decode files with the specified MIME type.
+ *
+ * @param MIMEType the MIME type such as "image/jpeg".
+ *
+ * @return the Iterator of registered ImageReaders.
+ */
+ public static Iterator<ImageReader> getImageReadersByMIMEType(String MIMEType) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an array of Strings giving the names of the formats supported
+ * by registered ImageWriter objects.
+ *
+ * @return the array of format names.
+ */
+ public static String[] getWriterFormatNames() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an array of Strings giving the MIME types of the formats supported
+ * by registered ImageWriter objects.
+ *
+ * @return the array of MIME types.
+ */
+ public static String[] getWriterMIMETypes() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the Iterator which lists the registered ImageReader objects that
+ * are able to encode the specified image format.
+ *
+ * @param formatName the image format name such as "jpeg".
+ *
+ * @return the Iterator of registered ImageWriter.
+ */
+ public static Iterator<ImageWriter> getImageWritersByFormatName(String formatName) {
+ if (formatName == null) {
+ throw new NullPointerException("format name cannot be NULL");
+ }
+
+ Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+ new FormatFilter(formatName), true);
+
+ return new SpiIteratorToWritersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator which lists the registered ImageReader objects that
+ * are able to encode the specified suffix.
+ *
+ * @param fileSuffix the file suffix such as "jpg".
+ *
+ * @return the Iterator of registered ImageWriter.
+ */
+ public static Iterator<ImageWriter> getImageWritersBySuffix(String fileSuffix) {
+ if (fileSuffix == null) {
+ throw new NullPointerException("suffix cannot be NULL");
+ }
+ Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+ new SuffixFilter(fileSuffix), true);
+ return new SpiIteratorToWritersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator which lists the registered ImageReader objects that
+ * are able to encode the specified MIME type.
+ *
+ * @param MIMEType the MIME type such as "image/jpeg".
+ *
+ * @return the Iterator of registered ImageWriter.
+ */
+ public static Iterator<ImageWriter> getImageWritersByMIMEType(String MIMEType) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an ImageWriter object which corresponds to the
+ * specified ImageReader, or returns null if the specified
+ * ImageReader is not registered.
+ *
+ * @param reader the specified ImageReader.
+ *
+ * @return the ImageWriter, or null.
+ */
+ public static ImageWriter getImageWriter(ImageReader reader) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an ImageReader object which corresponds to the
+ * specified ImageWriter, or returns null if the specified
+ * ImageWriter is not registered.
+ *
+ * @param writer the registered ImageWriter object.
+ *
+ * @return the ImageReader.
+ */
+ public static ImageReader getImageReader(ImageWriter writer) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the Iterator of ImageWriter objects which are able to
+ * encode images with the specified ImageTypeSpecifier and
+ * format.
+ *
+ * @param type the ImageTypeSpecifier, which defines layout.
+ * @param formatName the format name.
+ *
+ * @return the Iterator of ImageWriter objects.
+ */
+ public static Iterator<ImageWriter> getImageWriters(ImageTypeSpecifier type,
+ String formatName) {
+ if (type == null) {
+ throw new NullPointerException("type cannot be NULL");
+ }
+
+ if (formatName == null) {
+ throw new NullPointerException("format name cannot be NULL");
+ }
+
+ Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+ new FormatAndEncodeFilter(type, formatName), true);
+
+ return new SpiIteratorToWritersIteratorWrapper(it);
+ }
+
+ /**
+ * Gets the Iterator of registered ImageTranscoders which
+ * are able to transcode the metadata of the specified
+ * ImageReader object to a suitable object for encoding
+ * by the specified ImageWriter.
+ *
+ * @param reader the specified ImageReader.
+ * @param writer the specified ImageWriter.
+ *
+ * @return the Iterator of registered ImageTranscoders.
+ */
+ public static Iterator<ImageTranscoder> getImageTranscoders(ImageReader reader,
+ ImageWriter writer) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Reads image data from the specified File and decodes it using
+ * the appropriate registered ImageReader object.
+ * The File is wrapped in an ImageInputStream.
+ *
+ * @param input the File to be read.
+ *
+ * @return the BufferedImage decoded from the specified File, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static BufferedImage read(File input) throws IOException {
+ if (input == null) {
+ throw new IllegalArgumentException("input == null!");
+ }
+
+ ImageInputStream stream = createImageInputStream(input);
+ return read(stream);
+ }
+
+ /**
+ * Reads image data from the specified InputStream and decodes it
+ * using an appropriate registered an ImageReader object.
+ *
+ * @param input the InputStream.
+ *
+ * @return the BufferedImage decoded from the specified InputStream,
+ * or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static BufferedImage read(InputStream input) throws IOException {
+ if (input == null) {
+ throw new IllegalArgumentException("input == null!");
+ }
+
+ ImageInputStream stream = createImageInputStream(input);
+ return read(stream);
+ }
+
+ /**
+ * Reads image data from the specified URL and decodes it using
+ * the appropriate registered ImageReader object.
+ *
+ * @param input the URL to be read.
+ *
+ * @return the BufferedImage decoded from the specified URL, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static BufferedImage read(URL input) throws IOException {
+ if (input == null) {
+ throw new IllegalArgumentException("input == null!");
+ }
+
+ InputStream stream = input.openStream();
+ BufferedImage res = read(stream);
+ stream.close();
+
+ return res;
+ }
+
+ /**
+ * Reads image data from the specified ImageInputStream and decodes it
+ * using appropriate registered an ImageReader object.
+ *
+ * @param stream the ImageInputStream.
+ *
+ * @return the BufferedImage decoded from the specified ImageInputStream,
+ * or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static BufferedImage read(ImageInputStream stream) throws IOException {
+ if (stream == null) {
+ throw new IllegalArgumentException("stream == null!");
+ }
+
+ Iterator<ImageReader> imageReaders = getImageReaders(stream);
+ if (!imageReaders.hasNext()) {
+ return null;
+ }
+
+ ImageReader reader = imageReaders.next();
+ reader.setInput(stream, false, true);
+ BufferedImage res = reader.read(0);
+ reader.dispose();
+
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // Stream could be already closed, proceed silently in this case
+ }
+
+ return res;
+ }
+
+ /**
+ * Writes the specified image in the specified format (using an
+ * appropriate ImageWriter) to the specified ImageOutputStream.
+ *
+ * @param im the RenderedImage.
+ * @param formatName the format name.
+ * @param output the ImageOutputStream where Image to be written.
+ *
+ * @return true, if Image is written successfully, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static boolean write(RenderedImage im,
+ String formatName,
+ ImageOutputStream output)
+ throws IOException {
+
+ if (im == null) {
+ throw new IllegalArgumentException("image cannot be NULL");
+ }
+ if (formatName == null) {
+ throw new IllegalArgumentException("format name cannot be NULL");
+ }
+ if (output == null) {
+ throw new IllegalArgumentException("output cannot be NULL");
+ }
+
+ Iterator<ImageWriter> it = getImageWriters(ImageTypeSpecifier.createFromRenderedImage(im), formatName);
+ if (it.hasNext()) {
+ ImageWriter writer = it.next();
+ writer.setOutput(output);
+ writer.write(im);
+ output.flush();
+ writer.dispose();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Writes the specified image in the specified format (using an
+ * appropriate ImageWriter) to the specified File.
+ *
+ * @param im the RenderedImage.
+ * @param formatName the format name.
+ * @param output the output File where Image to be written.
+ *
+ * @return true, if Image is written successfully, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static boolean write(RenderedImage im,
+ String formatName,
+ File output)
+ throws IOException {
+
+ if (output == null) {
+ throw new IllegalArgumentException("output cannot be NULL");
+ }
+
+ if (output.exists()) {
+ output.delete();
+ }
+
+ ImageOutputStream ios = createImageOutputStream(output);
+ boolean rt = write(im, formatName, ios);
+ ios.close();
+ return rt;
+ }
+
+ /**
+ * Writes the specified image in the specified format (using an
+ * appropriate ImageWriter) to the specified OutputStream.
+ *
+ * @param im the RenderedImage.
+ * @param formatName the format name.
+ * @param output the OutputStream where Image is to be written.
+ *
+ * @return true, if Image is written successfully, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public static boolean write(RenderedImage im,
+ String formatName,
+ OutputStream output)
+ throws IOException {
+
+ if (output == null) {
+ throw new IllegalArgumentException("output cannot be NULL");
+ }
+
+ ImageOutputStream ios = createImageOutputStream(output);
+ boolean rt = write(im, formatName, ios);
+ ios.close();
+ return rt;
+ }
+
+
+ /**
+ * Filter to match spi by format name.
+ */
+ static class FormatFilter implements ServiceRegistry.Filter {
+
+ /** The name. */
+ private String name;
+
+ /**
+ * Instantiates a new format filter.
+ *
+ * @param name the name
+ */
+ public FormatFilter(String name) {
+ this.name = name;
+ }
+
+ public boolean filter(Object provider) {
+ ImageReaderWriterSpi spi = (ImageReaderWriterSpi) provider;
+ return Arrays.asList(spi.getFormatNames()).contains(name);
+ }
+ }
+
+ /**
+ * Filter to match spi by format name and encoding possibility.
+ */
+ static class FormatAndEncodeFilter extends FormatFilter {
+
+ /** The type. */
+ private ImageTypeSpecifier type;
+
+ /**
+ * Instantiates a new format and encode filter.
+ *
+ * @param type the type
+ * @param name the name
+ */
+ public FormatAndEncodeFilter(ImageTypeSpecifier type, String name) {
+ super(name);
+ this.type = type;
+ }
+
+ @Override
+ public boolean filter(Object provider) {
+ ImageWriterSpi spi = (ImageWriterSpi) provider;
+ return super.filter(provider) && spi.canEncodeImage(type);
+ }
+ }
+
+ /**
+ * Filter to match spi by suffix.
+ */
+ static class SuffixFilter implements ServiceRegistry.Filter {
+
+ /** The suf. */
+ private String suf;
+
+ /**
+ * Instantiates a new suffix filter.
+ *
+ * @param suf the suf
+ */
+ public SuffixFilter(String suf) {
+ this.suf = suf;
+ }
+
+ public boolean filter(Object provider) {
+ ImageReaderWriterSpi spi = (ImageReaderWriterSpi) provider;
+ return Arrays.asList(spi.getFileSuffixes()).contains(suf);
+ }
+ }
+
+ /**
+ * Filter to match spi by decoding possibility.
+ */
+ static class CanReadFilter implements ServiceRegistry.Filter {
+
+ /** The input. */
+ private Object input;
+
+ /**
+ * Instantiates a new can read filter.
+ *
+ * @param input the input
+ */
+ public CanReadFilter(Object input) {
+ this.input = input;
+ }
+
+ public boolean filter(Object provider) {
+ ImageReaderSpi spi = (ImageReaderSpi) provider;
+ try {
+ return spi.canDecodeInput(input);
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Wraps Spi's iterator to ImageWriter iterator.
+ */
+ static class SpiIteratorToWritersIteratorWrapper implements Iterator<ImageWriter> {
+
+ /** The backend. */
+ private Iterator<ImageWriterSpi> backend;
+
+ /**
+ * Instantiates a new spi iterator to writers iterator wrapper.
+ *
+ * @param backend the backend
+ */
+ public SpiIteratorToWritersIteratorWrapper(Iterator<ImageWriterSpi> backend) {
+ this.backend = backend;
+ }
+
+ /**
+ * Next.
+ *
+ * @return the image writer
+ */
+ public ImageWriter next() {
+ try {
+ return backend.next().createWriterInstance();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Checks for next.
+ *
+ * @return true, if successful
+ */
+ public boolean hasNext() {
+ return backend.hasNext();
+ }
+
+ /**
+ * Removes the.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("Use deregisterServiceprovider instead of Iterator.remove()");
+ }
+ }
+
+ /**
+ * Wraps spi's iterator to ImageReader iterator.
+ */
+ static class SpiIteratorToReadersIteratorWrapper implements Iterator<ImageReader> {
+
+ /** The backend. */
+ private Iterator<ImageReaderSpi> backend;
+
+ /**
+ * Instantiates a new spi iterator to readers iterator wrapper.
+ *
+ * @param backend the backend
+ */
+ public SpiIteratorToReadersIteratorWrapper(Iterator<ImageReaderSpi> backend) {
+ this.backend = backend;
+ }
+
+ /**
+ * Next.
+ *
+ * @return the image reader
+ */
+ public ImageReader next() {
+ try {
+ return backend.next().createReaderInstance();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Checks for next.
+ *
+ * @return true, if successful
+ */
+ public boolean hasNext() {
+ return backend.hasNext();
+ }
+
+ /**
+ * Removes the.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("Use deregisterServiceprovider instead of Iterator.remove()");
+ }
+ }
+}
diff --git a/awt/javax/imageio/ImageReadParam.java b/awt/javax/imageio/ImageReadParam.java
new file mode 100644
index 0000000..e67ed7d
--- /dev/null
+++ b/awt/javax/imageio/ImageReadParam.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The ImageReadParam class provides information to the ImageReader about
+ * how an image is to be decoded.
+ */
+
+public class ImageReadParam extends IIOParam {
+
+ /**
+ * This flag indicates if this ImageReadParam supports setting the source
+ * rendering size.
+ */
+ protected boolean canSetSourceRenderSize;
+
+ /**
+ * The destination BufferedImage.
+ */
+ protected BufferedImage destination;
+
+ /** The destination bands. */
+ protected int[] destinationBands;
+
+ /**
+ * The minimum progressive pass.
+ */
+ protected int minProgressivePass;
+
+ /**
+ * The number of progressive passes.
+ */
+ protected int numProgressivePasses;
+
+ /** The source render size. */
+ protected Dimension sourceRenderSize;
+
+ /**
+ * Returns true if this ImageReaderParam supports rendering a
+ * source image at an arbitrary size.
+ *
+ * @return true if this ImageReaderParam supports rendering a
+ * source image at an arbitrary size, false otherwise.
+ */
+ public boolean canSetSourceRenderSize() {
+ return canSetSourceRenderSize;
+ }
+
+ /**
+ * Gets the current destination image as BufferedImage.
+ *
+ * @return the BufferedImage which represents the destination.
+ */
+ public BufferedImage getDestination() {
+ return destination;
+ }
+
+ /**
+ * Gets the indices of destination bands.
+ *
+ * @return the array of destination bands.
+ */
+ public int[] getDestinationBands() {
+ return destinationBands;
+ }
+
+ /**
+ * Gets the index of the maximum pass to be decoded.
+ * This method returns Integer.MAX_VALUE, if
+ * getSourceNumProgressivePasses() method returns value
+ * that is equal to Integer.MAX_VALUE. Otherwise
+ * this method returns
+ * getSourceMinProgressivePass() + getSourceNumProgressivePasses() - 1.
+ *
+ * @return the index of the maximum pass to be decoded.
+ */
+ public int getSourceMaxProgressivePass() {
+ if (getSourceNumProgressivePasses() == Integer.MAX_VALUE) {
+ return Integer.MAX_VALUE;
+ }
+ return getSourceMinProgressivePass() + getSourceNumProgressivePasses() - 1;
+ }
+
+ /**
+ * Gets the index of the minimum progressive pass that is decoded,
+ * default is 0.
+ *
+ * @return the index of the minimum progressive pass that is decoded,
+ * default is 0.
+ */
+ public int getSourceMinProgressivePass() {
+ return minProgressivePass;
+ }
+
+ /**
+ * Gets the number of progressive passes.
+ * The default value is Integer.MAX_VALUE.
+ *
+ * @return the number of progressive passes.
+ */
+ public int getSourceNumProgressivePasses() {
+ return numProgressivePasses;
+ }
+
+ /**
+ * Gets the dimension of source image which will be rendered
+ * during decoding process.
+ *
+ * @return the source render size.
+ */
+ public Dimension getSourceRenderSize() {
+ return sourceRenderSize;
+ }
+
+ /**
+ * Sets the specified destination image.
+ * This image will be used by read, readAll, and readRaster methods,
+ * and a reference to it will be returned by those methods.
+ *
+ * @param destination the destination image.
+ */
+ public void setDestination(BufferedImage destination) {
+ this.destination = destination;
+ }
+
+ /**
+ * Sets the indices of the destination bands.
+ *
+ * @param destinationBands the indices of the destination bands.
+ */
+ public void setDestinationBands(int[] destinationBands) {
+ this.destinationBands = destinationBands;
+ }
+
+ @Override
+ public void setDestinationType(ImageTypeSpecifier destinationType) {
+ this.destinationType = destinationType;
+ }
+
+ /**
+ * Sets the source progressive passes.
+ *
+ * @param minPass the index of the minimum pass to be decoded.
+ * @param numPasses the number of passes to be decoded.
+ */
+ public void setSourceProgressivePasses(int minPass, int numPasses) {
+ minProgressivePass = minPass;
+ numProgressivePasses = numPasses;
+ }
+
+ /**
+ * Sets the dimension size of source image if an
+ * image can be rendered at an arbitrary size.
+ *
+ * @param size the size of rendered image.
+ *
+ * @throws UnsupportedOperationException the unsupported operation exception
+ */
+ public void setSourceRenderSize(Dimension size) throws UnsupportedOperationException {
+ if (!canSetSourceRenderSize) {
+ throw new UnsupportedOperationException("can't set source renderer size");
+ }
+ sourceRenderSize = size;
+ }
+}
+
diff --git a/awt/javax/imageio/ImageReader.java b/awt/javax/imageio/ImageReader.java
new file mode 100644
index 0000000..780de26
--- /dev/null
+++ b/awt/javax/imageio/ImageReader.java
@@ -0,0 +1,1100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.event.IIOReadWarningListener;
+import javax.imageio.event.IIOReadProgressListener;
+import javax.imageio.event.IIOReadUpdateListener;
+import java.util.Locale;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Set;
+import java.io.IOException;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.*;
+
+/**
+ * The ImageReader class is an abstract class for decoding images.
+ * ImageReader objects are instantiated by the service provider
+ * interface, ImageReaderSpi class, for the specific format.
+ * ImageReaderSpi class should be registered with the IIORegistry,
+ * which uses them for format recognition and presentation of available
+ * format readers and writers.
+ */
+public abstract class ImageReader {
+
+ /** The originating provider. */
+ protected ImageReaderSpi originatingProvider;
+
+ /** The input object such as ImageInputStream. */
+ protected Object input;
+
+ /** The seek forward only. */
+ protected boolean seekForwardOnly;
+
+ /**
+ * The ignore metadata flag indicates whether current input source
+ * has been marked as metadata is allowed to be ignored by setInput.
+ */
+ protected boolean ignoreMetadata;
+
+ /** The minimum index. */
+ protected int minIndex;
+
+ /** The available locales. */
+ protected Locale[] availableLocales;
+
+ /** The locale. */
+ protected Locale locale;
+
+ /** The list of warning listeners. */
+ protected List<IIOReadWarningListener> warningListeners;
+
+ /** The list of warning locales. */
+ protected List<Locale> warningLocales;
+
+ /** The list of progress listeners. */
+ protected List<IIOReadProgressListener> progressListeners;
+
+ /** The list of update listeners. */
+ protected List<IIOReadUpdateListener> updateListeners;
+
+ /**
+ * Instantiates a new ImageReader.
+ *
+ * @param originatingProvider the ImageReaderSpi which
+ * instanties this ImageReader.
+ */
+ protected ImageReader(ImageReaderSpi originatingProvider) {
+ this.originatingProvider = originatingProvider;
+ }
+
+ /**
+ * Gets the format name of this input source.
+ *
+ * @return the format name of this input source.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public String getFormatName() throws IOException {
+ return originatingProvider.getFormatNames()[0];
+ }
+
+ /**
+ * Gets the ImageReaderSpi which instantiated this ImageReader.
+ *
+ * @return the ImageReaderSpi.
+ */
+ public ImageReaderSpi getOriginatingProvider() {
+ return originatingProvider;
+ }
+
+ /**
+ * Sets the specified Object as the input source of this ImageReader.
+ *
+ * @param input the input source, it can
+ * be an ImageInputStream or other supported objects.
+ * @param seekForwardOnly indicates whether the stream must
+ * be read sequentially from its current starting point.
+ * @param ignoreMetadata parameter which indicates
+ * if metadata may be ignored during reads or not.
+ */
+ public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
+ if (input != null) {
+ if (!isSupported(input) && !(input instanceof ImageInputStream)) {
+ throw new IllegalArgumentException("input " + input + " is not supported");
+ }
+ }
+ this.minIndex = 0;
+ this.seekForwardOnly = seekForwardOnly;
+ this.ignoreMetadata = ignoreMetadata;
+ this.input = input;
+ }
+
+ /**
+ * Checks if is supported.
+ *
+ * @param input the input
+ *
+ * @return true, if is supported
+ */
+ private boolean isSupported(Object input) {
+ ImageReaderSpi spi = getOriginatingProvider();
+ if (null != spi) {
+ Class[] outTypes = spi.getInputTypes();
+ for (Class<?> element : outTypes) {
+ if (element.isInstance(input)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Sets the specified Object as the input source of this ImageReader.
+ * Metadata is not ignored.
+ *
+ * @param input the input source, it can
+ * be an ImageInputStream or other supported objects.
+ * @param seekForwardOnly indicates whether the stream must
+ * be read sequentially from its current starting point.
+ */
+ public void setInput(Object input, boolean seekForwardOnly) {
+ setInput(input, seekForwardOnly, false);
+ }
+
+ /**
+ * Sets the specified Object as the input source of this ImageReader.
+ * Metadata is not ignored and forward seeking is not required.
+ *
+ * @param input the input source, it can
+ * be ImageInputStream or other objects.
+ */
+ public void setInput(Object input) {
+ setInput(input, false, false);
+ }
+
+ /**
+ * Gets the input source object of this ImageReader, or returns null.
+ *
+ * @return the the input source object such as ImageInputStream,
+ * or null.
+ */
+ public Object getInput() {
+ return input;
+ }
+
+ /**
+ * Checks if the input source supports only forward reading, or not.
+ *
+ * @return true, if the input source supports only forward reading,
+ * false otherwise.
+ */
+ public boolean isSeekForwardOnly() {
+ return seekForwardOnly;
+ }
+
+ /**
+ * Returns true if the current input source allows
+ * to metadata to be ignored by passing true as
+ * the ignoreMetadata argument to the setInput method.
+ *
+ * @return true, if true if the current input source allows
+ * to metadata to be ignored by passing true as
+ * the ignoreMetadata argument to the setInput method.
+ */
+ public boolean isIgnoringMetadata() {
+ return ignoreMetadata;
+ }
+
+ /**
+ * Gets the minimum valid index for reading an image, thumbnail,
+ * or image metadata.
+ *
+ * @return the minimum valid index for reading an image, thumbnail,
+ * or image metadata.
+ */
+ public int getMinIndex() {
+ return minIndex;
+ }
+
+ /**
+ * Gets the available locales.
+ *
+ * @return an array of the available locales.
+ */
+ public Locale[] getAvailableLocales() {
+ return availableLocales;
+ }
+
+ /**
+ * Sets the locale to this ImageReader.
+ *
+ * @param locale the Locale.
+ */
+ public void setLocale(Locale locale) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Gets the locale of this ImageReader.
+ *
+ * @return the locale of this ImageReader.
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Gets the number of images available in the current input source.
+ *
+ * @param allowSearch the parameter which indicates what
+ * a search is required; if false, the reader may return -1
+ * without searching.
+ *
+ * @return the number of images.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract int getNumImages(boolean allowSearch) throws IOException;
+
+ /**
+ * Gets the width of the specified image in input source.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return the width in pixels.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract int getWidth(int imageIndex) throws IOException;
+
+ /**
+ * Gets the height of the specified image in input source.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return the height in pixels.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract int getHeight(int imageIndex) throws IOException;
+
+ /**
+ * Checks if the storage format of the specified image places
+ * an impediment on random pixels access or not.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return true, if the storage format of the specified image places
+ * an impediment on random pixels access, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean isRandomAccessEasy(int imageIndex) throws IOException {
+ return false; //def
+ }
+
+ /**
+ * Gets the aspect ratio (width devided by height) of the image.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return the aspect ratio of the image.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public float getAspectRatio(int imageIndex) throws IOException {
+ return (float) getWidth(imageIndex) / getHeight(imageIndex);
+ }
+
+ /**
+ * Gets an ImageTypeSpecifier which indicates the type of the
+ * specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the ImageTypeSpecifier.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Gets an Iterator of ImageTypeSpecifier objects which are associated
+ * with image types that may be used when decoding specified image.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return an Iterator of ImageTypeSpecifier objects.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException;
+
+ /**
+ * Gets the default ImageReadParam object.
+ *
+ * @return the ImageReadParam object.
+ */
+ public ImageReadParam getDefaultReadParam() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Gets an IIOMetadata object for this input source.
+ *
+ * @return the IIOMetadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract IIOMetadata getStreamMetadata() throws IOException;
+
+ /**
+ * Gets an IIOMetadata object for this input source.
+ *
+ * @param formatName the desired metadata format to be used in the
+ * returned IIOMetadata object.
+ * @param nodeNames the node names of the document.
+ *
+ * @return the IIOMetadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public IIOMetadata getStreamMetadata(String formatName, Set<String> nodeNames)
+ throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Gets the image metadata of the specified image in input source.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return the IIOMetadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract IIOMetadata getImageMetadata(int imageIndex) throws IOException;
+
+ /**
+ * Gets the image metadata of the specified image input source.
+ *
+ * @param imageIndex the image index.
+ * @param formatName the desired metadata format to be used in the
+ * returned IIOMetadata object.
+ * @param nodeNames the node names which can be contained in
+ * the document.
+ *
+ * @return the IIOMetadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public IIOMetadata getImageMetadata(int imageIndex, String formatName,
+ Set<String> nodeNames) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Reads the specified image and returns it as a BufferedImage
+ * using the default ImageReadParam.
+ *
+ * @param imageIndex the image index.
+ *
+ * @return the BufferedImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public BufferedImage read(int imageIndex) throws IOException {
+ return read(imageIndex, null);
+ }
+
+ /**
+ * Reads the specified image and returns it as a BufferedImage
+ * using the specified ImageReadParam.
+ *
+ * @param imageIndex the image index.
+ * @param param the ImageReadParam.
+ *
+ * @return the BufferedImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract BufferedImage read(int imageIndex, ImageReadParam param) throws IOException;
+
+ /**
+ * Reads the specified image and returns an IIOImage with this image,
+ * thumbnails, and metadata for this image, using
+ * the specified ImageReadParam.
+ *
+ * @param imageIndex the image index.
+ * @param param the ImageReadParam.
+ *
+ * @return the IIOImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public IIOImage readAll(int imageIndex, ImageReadParam param) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Returns an Iterator of IIOImages from the input source.
+ *
+ * @param params the Iterator of ImageReadParam objects.
+ *
+ * @return the iterator of IIOImages.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public Iterator<IIOImage> readAll(Iterator<? extends ImageReadParam> params) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Checks whether or not this plug-in supports reading a Raster.
+ *
+ * @return true, if this plug-in supports reading a Raster,
+ * false otherwise.
+ */
+ public boolean canReadRaster() {
+ return false; //def
+ }
+
+ /**
+ * Reads a new Raster object which contains the raw pixel data from
+ * the image.
+ *
+ * @param imageIndex the image index.
+ * @param param the ImageReadParam.
+ *
+ * @return the Raster.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public Raster readRaster(int imageIndex, ImageReadParam param) throws IOException {
+ throw new UnsupportedOperationException("Unsupported");
+ }
+
+ /**
+ * Checks if the specified image has tiles or not.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return true, if the specified image has tiles,
+ * false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean isImageTiled(int imageIndex) throws IOException {
+ return false; //def
+ }
+
+ /**
+ * Gets the tile width in the specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the tile width.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getTileWidth(int imageIndex) throws IOException {
+ return getWidth(imageIndex); //def
+ }
+
+ /**
+ * Gets the tile height in the specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the tile height.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getTileHeight(int imageIndex) throws IOException {
+ return getHeight(imageIndex); //def
+ }
+
+ /**
+ * Gets the X coordinate of the upper left corner of the tile grid in the
+ * specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the X coordinate of the upper left corner of the tile grid.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getTileGridXOffset(int imageIndex) throws IOException {
+ return 0; //def
+ }
+
+ /**
+ * Gets the Y coordinate of the upper left corner of the tile grid in the
+ * specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the Y coordinate of the upper left corner of the tile grid.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getTileGridYOffset(int imageIndex) throws IOException {
+ return 0; //def
+ }
+
+ /**
+ * Reads the tile specified by the tileX and tileY parameters
+ * of the specified image and returns it as a BufferedImage.
+ *
+ * @param imageIndex the image index.
+ * @param tileX the X index of tile.
+ * @param tileY the Y index of tile.
+ *
+ * @return the BufferedImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public BufferedImage readTile(int imageIndex, int tileX, int tileY) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Reads the tile specified by the tileX and tileY parameters
+ * of the specified image and returns it as a Raster.
+ *
+ * @param imageIndex the image index.
+ * @param tileX the X index of tile.
+ * @param tileY the Y index of tile.
+ *
+ * @return the Raster.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public Raster readTileRaster(int imageIndex, int tileX, int tileY) throws IOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Reads the specified image using the specified
+ * ImageReadParam and returns it as a RenderedImage.
+ *
+ * @param imageIndex the image index.
+ * @param param the ImageReadParam.
+ *
+ * @return the RenderedImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public RenderedImage readAsRenderedImage(int imageIndex, ImageReadParam param) throws IOException {
+ return read(imageIndex, param);
+ }
+
+ /**
+ * Returns true if the image format supported by this reader
+ * supports thumbnail preview images.
+ *
+ * @return true if the image format supported by this reader
+ * supports thumbnail preview images, false otherwise.
+ */
+ public boolean readerSupportsThumbnails() {
+ return false; //def
+ }
+
+ /**
+ * Checks if the specified image has thumbnails or not.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return true, if the specified image has thumbnails,
+ * false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean hasThumbnails(int imageIndex) throws IOException {
+ return getNumThumbnails(imageIndex) > 0; //def
+ }
+
+ /**
+ * Gets the number of thumbnails for the specified image.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return the number of thumbnails.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getNumThumbnails(int imageIndex) throws IOException {
+ return 0; //def
+ }
+
+ /**
+ * Gets the width of the specified thumbnail for the specified image.
+ *
+ * @param imageIndex the image's index.
+ * @param thumbnailIndex the thumbnail's index.
+ *
+ * @return the thumbnail width.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getThumbnailWidth(int imageIndex, int thumbnailIndex) throws IOException {
+ return readThumbnail(imageIndex, thumbnailIndex).getWidth(); //def
+ }
+
+ /**
+ * Gets the height of the specified thumbnail for the specified image.
+ *
+ * @param imageIndex the image's index.
+ * @param thumbnailIndex the thumbnail's index.
+ *
+ * @return the thumbnail height.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public int getThumbnailHeight(int imageIndex, int thumbnailIndex) throws IOException {
+ return readThumbnail(imageIndex, thumbnailIndex).getHeight(); //def
+ }
+
+ /**
+ * Reads the thumbnail image for the specified image
+ * as a BufferedImage.
+ *
+ * @param imageIndex the image index.
+ * @param thumbnailIndex the thumbnail index.
+ *
+ * @return the BufferedImage.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
+ throw new UnsupportedOperationException("Unsupported"); //def
+ }
+
+ /**
+ * Requests an abort operation for current reading operation.
+ */
+ public void abort() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Checks whether or not a request to abort the current read operation
+ * has been made successfully.
+ *
+ * @return true, if the request to abort the current read operation
+ * has been made successfully, false otherwise.
+ */
+ protected boolean abortRequested() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Clears all previous abort request, and abortRequested returns false
+ * after calling this method.
+ */
+ protected void clearAbortRequest() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Adds the IIOReadWarningListener.
+ *
+ * @param listener the IIOReadWarningListener.
+ */
+ public void addIIOReadWarningListener(IIOReadWarningListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes the specified IIOReadWarningListener.
+ *
+ * @param listener the IIOReadWarningListener to be removed.
+ */
+ public void removeIIOReadWarningListener(IIOReadWarningListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes all registered IIOReadWarningListeners.
+ */
+ public void removeAllIIOReadWarningListeners() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Adds the IIOReadProgressListener.
+ *
+ * @param listener the IIOReadProgressListener.
+ */
+ public void addIIOReadProgressListener(IIOReadProgressListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes the specified IIOReadProgressListener.
+ *
+ * @param listener the IIOReadProgressListener to be removed.
+ */
+ public void removeIIOReadProgressListener(IIOReadProgressListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes registered IIOReadProgressListeners.
+ */
+ public void removeAllIIOReadProgressListeners() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Adds the IIOReadUpdateListener.
+ *
+ * @param listener the IIOReadUpdateListener.
+ */
+ public void addIIOReadUpdateListener(IIOReadUpdateListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes the specified IIOReadUpdateListener.
+ *
+ * @param listener the IIOReadUpdateListener to be removed.
+ */
+ public void removeIIOReadUpdateListener(IIOReadUpdateListener listener) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Removes registered IIOReadUpdateListeners.
+ */
+ public void removeAllIIOReadUpdateListeners() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the start of an sequence of image reads
+ * by calling the sequenceStarted method on all registered
+ * IIOReadProgressListeners.
+ *
+ * @param minIndex the minimum index.
+ */
+ protected void processSequenceStarted(int minIndex) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the completion of an sequence of image reads
+ * by calling sequenceComplete method on all registered
+ * IIOReadProgressListeners.
+ */
+ protected void processSequenceComplete() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the start of an image read by calling the imageStarted
+ * method on all registered IIOReadProgressListeners.
+ *
+ * @param imageIndex the image index.
+ */
+ protected void processImageStarted(int imageIndex) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the current percentage of image completion by calling
+ * the imageProgress method on all registered IIOReadProgressListeners.
+ *
+ * @param percentageDone the percentage done.
+ */
+ protected void processImageProgress(float percentageDone) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes image completion by calling the imageComplete method
+ * on all registered IIOReadProgressListeners.
+ */
+ protected void processImageComplete() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the start of a thumbnail read by calling the
+ * thumbnailStarted method on all registered IIOReadProgressListeners.
+ *
+ * @param imageIndex the image index.
+ * @param thumbnailIndex the thumbnail index.
+ */
+ protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the current percentage of thumbnail completion
+ * by calling the thumbnailProgress method on all registered
+ * IIOReadProgressListeners.
+ *
+ * @param percentageDone the percentage done.
+ */
+ protected void processThumbnailProgress(float percentageDone) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the completion of a thumbnail read
+ * by calling the thumbnailComplete method
+ * on all registered IIOReadProgressListeners.
+ */
+ protected void processThumbnailComplete() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes a read aborted event by calling the readAborted
+ * method on all registered IIOReadProgressListeners.
+ */
+ protected void processReadAborted() {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the beginning of a progressive pass by calling
+ * the passStarted method on all registered IIOReadUpdateListeners.
+ *
+ * @param theImage the image to be updated.
+ * @param pass the current pass index.
+ * @param minPass the minimum pass index.
+ * @param maxPass the maximum pass index.
+ * @param minX the X coordinate of of the upper left pixel.
+ * @param minY the Y coordinate of of the upper left pixel.
+ * @param periodX the horizontal separation between pixels.
+ * @param periodY the vertical separation between pixels.
+ * @param bands the number of affected bands.
+ */
+ protected void processPassStarted(BufferedImage theImage,
+ int pass,
+ int minPass,
+ int maxPass,
+ int minX,
+ int minY,
+ int periodX,
+ int periodY,
+ int[] bands) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the update of a set of samples by calling
+ * the imageUpdate method on all registered IIOReadUpdateListeners.
+ *
+ * @param theImage the image to be updated.
+ * @param minX the X coordinate of the upper left pixel.
+ * @param minY the Y coordinate of the upper left pixel.
+ * @param width the width of updated area.
+ * @param height the height of updated area.
+ * @param periodX the horizontal separation between pixels.
+ * @param periodY the vertical separation between pixels.
+ * @param bands the number of affected bands.
+ */
+ protected void processImageUpdate(BufferedImage theImage,
+ int minX,
+ int minY,
+ int width,
+ int height,
+ int periodX,
+ int periodY,
+ int[] bands) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the end of a progressive pass by calling passComplete
+ * method of registered IIOReadUpdateListeners.
+ *
+ * @param theImage the image to be updated.
+ */
+ protected void processPassComplete(BufferedImage theImage) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the beginning of a thumbnail progressive pass
+ * by calling the thumbnailPassStarted method on all
+ * registered IIOReadUpdateListeners.
+ *
+ * @param theThumbnail the the thumbnail to be updated.
+ * @param pass the current pass index.
+ * @param minPass the minimum pass index.
+ * @param maxPass the maximum pass index.
+ * @param minX the X coordinate of the upper left pixel.
+ * @param minY the Y coordinate of the upper left pixel.
+ * @param periodX the horizontal separation between pixels.
+ * @param periodY the vertical separation between pixels.
+ * @param bands the number of affected bands.
+ */
+ protected void processThumbnailPassStarted(BufferedImage theThumbnail,
+ int pass,
+ int minPass,
+ int maxPass,
+ int minX,
+ int minY,
+ int periodX,
+ int periodY,
+ int[] bands) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the update of a set of samples in a thumbnail
+ * image by calling the thumbnailUpdate method on all
+ * registered IIOReadUpdateListeners.
+ *
+ * @param theThumbnail the the thumbnail to be updated.
+ * @param minX the X coordinate of the upper left pixel.
+ * @param minY the Y coordinate of the upper left pixel.
+ * @param periodX the horizontal separation between pixels.
+ * @param periodY the vertical separation between pixels.
+ * @param bands the number of affected bands.
+ */
+ protected void processThumbnailUpdate(BufferedImage theThumbnail,
+ int minX,
+ int minY,
+ int width,
+ int height,
+ int periodX,
+ int periodY,
+ int[] bands) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes the end of a thumbnail progressive pass
+ * by calling the thumbnailPassComplete method
+ * on all registered IIOReadUpdateListeners.
+ *
+ * @param theThumbnail the thumbnail to be updated.
+ */
+ protected void processThumbnailPassComplete(BufferedImage theThumbnail) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes a warning message by calling warningOccurred method
+ * of registered IIOReadWarningListeners.
+ *
+ * @param warning the warning.
+ */
+ protected void processWarningOccurred(String warning) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Processes a warning by calling the warningOccurred method
+ * of on all registered IIOReadWarningListeners.
+ *
+ * @param baseName the base name of ResourceBundles.
+ * @param keyword the keyword to index the warning among ResourceBundles.
+ */
+ protected void processWarningOccurred(String baseName, String keyword) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Resets this ImageReader.
+ */
+ public void reset() {
+ // def
+ setInput(null, false);
+ setLocale(null);
+ removeAllIIOReadUpdateListeners();
+ removeAllIIOReadWarningListeners();
+ removeAllIIOReadProgressListeners();
+ clearAbortRequest();
+ }
+
+ /**
+ * Disposes of any resources.
+ */
+ public void dispose() {
+ // do nothing by def
+ }
+
+ /**
+ * Gets the region of source image that should be read with the
+ * specified width, height and ImageReadParam.
+ *
+ * @param param the ImageReadParam object, or null.
+ * @param srcWidth the source image's width.
+ * @param srcHeight the source image's height.
+ *
+ * @return the Rectangle of source region.
+ */
+ protected static Rectangle getSourceRegion(ImageReadParam param, int srcWidth, int srcHeight) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Computes the specified source region and the specified destination
+ * region with the specified the width and height of the source image,
+ * an optional destination image, and an ImageReadParam.
+ *
+ * @param param the an ImageReadParam object, or null.
+ * @param srcWidth the source image's width.
+ * @param srcHeight the source image's height.
+ * @param image the destination image.
+ * @param srcRegion the source region.
+ * @param destRegion the destination region.
+ */
+ protected static void computeRegions(ImageReadParam param,
+ int srcWidth,
+ int srcHeight,
+ BufferedImage image,
+ Rectangle srcRegion,
+ Rectangle destRegion) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Checks the validity of the source and destination band and is called
+ * when the reader knows the number of bands of the source image and
+ * the number of bands of the destination image.
+ *
+ * @param param the ImageReadParam for reading the Image.
+ * @param numSrcBands the number of bands in the source.
+ * @param numDstBands the number of bands in the destination.
+ */
+ protected static void checkReadParamBandSettings(ImageReadParam param,
+ int numSrcBands,
+ int numDstBands) {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Gets the destination image where the decoded data is written.
+ *
+ * @param param the ImageReadParam.
+ * @param imageTypes the iterator of ImageTypeSpecifier objects.
+ * @param width the width of the image being decoded.
+ * @param height the height of the image being decoded.
+ *
+ * @return the BufferedImage where decoded pixels should be written.
+ *
+ * @throws IIOException the IIOException is thrown if
+ * there is no suitable ImageTypeSpecifier.
+ */
+ protected static BufferedImage getDestination(ImageReadParam param, Iterator<ImageTypeSpecifier> imageTypes,
+ int width,
+ int height)
+ throws IIOException {
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+}
diff --git a/awt/javax/imageio/ImageTranscoder.java b/awt/javax/imageio/ImageTranscoder.java
new file mode 100644
index 0000000..1a0de76
--- /dev/null
+++ b/awt/javax/imageio/ImageTranscoder.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.ImageTypeSpecifier;
+
+/**
+ * The ImageTranscoder interface is to be implemented by classes that
+ * perform image transcoding operations, that is, take images written
+ * in one format and write them in another format using
+ * read/write operations. Some image data can be lost in such processes.
+ * The ImageTranscoder interface converts metadata objects (IIOMetadata)
+ * of ImageReader to apropriate metadata object for ImageWriter.
+ */
+public interface ImageTranscoder {
+
+ /**
+ * Converts the specified IIOMetadata object using the specified
+ * ImageWriteParam for obtaining writer's metadata structure.
+ *
+ * @param inData the IIOMetadata.
+ * @param param the ImageWriteParam.
+ *
+ * @return the IIOMetadata, or null.
+ */
+ IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param);
+
+ /**
+ * Converts the specified IIOMetadata object using the specified
+ * ImageWriteParam for obtaining writer's metadata structure
+ * and ImageTypeSpecifier object for obtaining the layout and
+ * color information of the image for this metadata.
+ *
+ * @param inData the IIOMetadata.
+ * @param imageType the ImageTypeSpecifier.
+ * @param param the ImageWriteParam.
+ *
+ * @return the IIOMetadata, or null.
+ */
+ IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param);
+}
diff --git a/awt/javax/imageio/ImageTypeSpecifier.java b/awt/javax/imageio/ImageTypeSpecifier.java
new file mode 100644
index 0000000..c93f269
--- /dev/null
+++ b/awt/javax/imageio/ImageTypeSpecifier.java
@@ -0,0 +1,339 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import java.awt.image.ColorModel;
+import java.awt.image.SampleModel;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.awt.color.ColorSpace;
+
+/**
+ * The ImageTypeSpecifier class performs conversion operations
+ * on the SampleModel and the ColorModel of an image.
+ */
+public class ImageTypeSpecifier {
+
+ /**
+ * The ColorModel of this ImageTypeSpecifier.
+ */
+ protected ColorModel colorModel;
+
+ /**
+ * The SampleModel of this ImageTypeSpecifier.
+ */
+ protected SampleModel sampleModel;
+
+ /**
+ * Instantiates a new ImageTypeSpecifier with the specified
+ * ColorModel and SampleModel objects.
+ *
+ * @param colorModel the ColorModel.
+ * @param sampleModel the SampleModel.
+ */
+ public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) {
+ if (colorModel == null) {
+ throw new IllegalArgumentException("color model should not be NULL");
+ }
+ if (sampleModel == null) {
+ throw new IllegalArgumentException("sample model should not be NULL");
+ }
+ if (!colorModel.isCompatibleSampleModel(sampleModel)) {
+ throw new IllegalArgumentException("color and sample models are not compatible");
+ }
+
+ this.colorModel = colorModel;
+ this.sampleModel = sampleModel;
+ }
+
+ /**
+ * Instantiates a new ImageTypeSpecifier using the specified
+ * RenderedImage.
+ *
+ * @param renderedImage the RenderedImage.
+ */
+ public ImageTypeSpecifier(RenderedImage renderedImage) {
+ if (renderedImage == null) {
+ throw new IllegalArgumentException("image should not be NULL");
+ }
+ this.colorModel = renderedImage.getColorModel();
+ this.sampleModel = renderedImage.getSampleModel();
+ }
+
+ /**
+ * Creates an ImageTypeSpecifier with the specified
+ * DirectColorModel and a packed SampleModel.
+ *
+ * @param colorSpace the ColorSpace.
+ * @param redMask the red mask.
+ * @param greenMask the green mask.
+ * @param blueMask the blue mask.
+ * @param alphaMask the alpha mask.
+ * @param transferType the transfer type.
+ * @param isAlphaPremultiplied the parameter indicates
+ * if the color channel is premultiplied by alpha.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createPacked(ColorSpace colorSpace,
+ int redMask,
+ int greenMask,
+ int blueMask,
+ int alphaMask,
+ int transferType,
+ boolean isAlphaPremultiplied) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates an ImageTypeSpecifier with specified
+ * ComponentColorModel and a PixelInterleavedSampleModel.
+ *
+ * @param colorSpace the ColorSpace.
+ * @param bandOffsets the band offsets.
+ * @param dataType the data type.
+ * @param hasAlpha the parameter indicates if alpha channel
+ * is needed.
+ * @param isAlphaPremultiplied the parameter indicates
+ * if the color channel is premultiplied by alpha.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createInterleaved(ColorSpace colorSpace,
+ int[] bandOffsets,
+ int dataType,
+ boolean hasAlpha,
+ boolean isAlphaPremultiplied) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+
+ /**
+ * Creates a ImageTypeSpecifier for a image with a
+ * BandedSampleModel and a ComponentColorModel.
+ *
+ * @param colorSpace the ColorSpace.
+ * @param bankIndices the bank indices.
+ * @param bandOffsets the band offsets.
+ * @param dataType the data type.
+ * @param hasAlpha the parameter indicates a presence of alpha channel.
+ * @param isAlphaPremultiplied the parameter indicates whether
+ * or not color channel is alpha premultiplied.
+ *
+ * @return the image type specifier
+ */
+ public static ImageTypeSpecifier createBanded(ColorSpace colorSpace,
+ int[] bankIndices,
+ int[] bandOffsets,
+ int dataType,
+ boolean hasAlpha,
+ boolean isAlphaPremultiplied) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates a ImageTypeSpecifier for a grayscale image.
+ *
+ * @param bits the number of bits per gray value.
+ * @param dataType the data type.
+ * @param isSigned a signed flag.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createGrayscale(int bits,
+ int dataType,
+ boolean isSigned) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates a ImageTypeSpecifier for a grayscale image.
+ *
+ * @param bits the number of bits per gray value.
+ * @param dataType the data type.
+ * @param isSigned a signed flag.
+ * @param isAlphaPremultiplied the parameter indicates
+ * if color channel is premultiplied by alpha, or not.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createGrayscale(int bits,
+ int dataType,
+ boolean isSigned,
+ boolean isAlphaPremultiplied) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates a ImageTypeSpecifier with the indexed image format.
+ *
+ * @param redLUT the red values of indecies.
+ * @param greenLUT the green values of indecies.
+ * @param blueLUT the blue values of indecies.
+ * @param alphaLUT the alpha values of indecies.
+ * @param bits the bits number for each index.
+ * @param dataType the data type.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createIndexed(byte[] redLUT,
+ byte[] greenLUT,
+ byte[] blueLUT,
+ byte[] alphaLUT,
+ int bits,
+ int dataType) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates the ImageTypeSpecifier from
+ * the specified buffered image type.
+ *
+ * @param bufferedImageType the buffered image type.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Creates the ImageTypeSpecifier from
+ * the specified RenderedImage.
+ *
+ * @param image the RenderedImage.
+ *
+ * @return the ImageTypeSpecifier.
+ */
+ public static ImageTypeSpecifier createFromRenderedImage(RenderedImage image) {
+ if (null == image) {
+ throw new IllegalArgumentException("image should not be NULL");
+ }
+ return new ImageTypeSpecifier(image);
+ }
+
+ /**
+ * Gets the BufferedImage type.
+ *
+ * @return the BufferedImage type.
+ */
+ public int getBufferedImageType() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the number of components.
+ *
+ * @return the number of components
+ */
+ public int getNumComponents() {
+ return colorModel.getNumComponents();
+ }
+
+ /**
+ * Gets the number of bands.
+ *
+ * @return the number of bands
+ */
+ public int getNumBands() {
+ return sampleModel.getNumBands();
+ }
+
+ /**
+ * Gets the number of bits per the specified band.
+ *
+ * @param band the index of band.
+ *
+ * @return the number of bits per the specified band.
+ */
+ public int getBitsPerBand(int band) {
+ if (band < 0 || band >= getNumBands()) {
+ throw new IllegalArgumentException();
+ }
+ return sampleModel.getSampleSize(band);
+ }
+
+ /**
+ * Gets the SampleModel associated with this ImageTypeSpecifier.
+ *
+ * @return the SampleModel associated with this ImageTypeSpecifier.
+ */
+ public SampleModel getSampleModel() {
+ return sampleModel;
+ }
+
+ /**
+ * Gets a compatible SampleModel with the specified width and height.
+ *
+ * @param width the width.
+ * @param height the height.
+ *
+ * @return the SampleModel.
+ */
+ public SampleModel getSampleModel(int width, int height) {
+ if ((long)width*height > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("width * height > Integer.MAX_VALUE");
+ }
+ return sampleModel.createCompatibleSampleModel(width, height);
+ }
+
+ /**
+ * Gets the ColorModel associated with this ImageTypeSpecifier.
+ *
+ * @return the ColorModel associated with this ImageTypeSpecifier.
+ */
+ public ColorModel getColorModel() {
+ return colorModel;
+ }
+
+ /**
+ * Creates the BufferedImage with the specified width and height
+ * and the ColorMadel and SampleModel which are specified by this
+ * ImageTypeSpecifier.
+ *
+ * @param width the width of the BufferedImage.
+ * @param height the height of the BufferedImage.
+ *
+ * @return the BufferedImage.
+ */
+ public BufferedImage createBufferedImage(int width, int height) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Compares this ImageTypeSpecifier object with the specified
+ * object.
+ *
+ * @param o the Object to be compared.
+ *
+ * @return true, if the object is an ImageTypeSpecifier with the same
+ * data as this ImageTypeSpecifier, false otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ boolean rt = false;
+ if (o instanceof ImageTypeSpecifier) {
+ ImageTypeSpecifier ts = (ImageTypeSpecifier) o;
+ rt = colorModel.equals(ts.colorModel) && sampleModel.equals(ts.sampleModel);
+ }
+ return rt;
+ }
+} \ No newline at end of file
diff --git a/awt/javax/imageio/ImageWriteParam.java b/awt/javax/imageio/ImageWriteParam.java
new file mode 100644
index 0000000..d32fa59
--- /dev/null
+++ b/awt/javax/imageio/ImageWriteParam.java
@@ -0,0 +1,633 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import java.util.Locale;
+import java.awt.*;
+
+/**
+ * The ImageWriteParam class provides information to an ImageWriter
+ * about how an image is to be encoded.
+ */
+public class ImageWriteParam extends IIOParam {
+
+ /**
+ * The Constant MODE_DISABLED indicates that
+ * stream is not tiled, progressive, or compressed.
+ */
+ public static final int MODE_DISABLED = 0;
+
+ /**
+ * The Constant MODE_DEFAULT indicates that the stream will be tiled,
+ * progressive, or compressed according to the plug-in's default.
+ */
+ public static final int MODE_DEFAULT = 1;
+
+ /**
+ * The Constant MODE_EXPLICIT indicates that the stream will be tiled,
+ * progressive, or compressed according to current settings
+ * which are defined by set methods.
+ */
+ public static final int MODE_EXPLICIT = 2;
+
+ /**
+ * The Constant MODE_COPY_FROM_METADATA indicates that the stream
+ * will be tiled, progressive, or compressed according to
+ * stream or image metadata.
+ */
+ public static final int MODE_COPY_FROM_METADATA = 3;
+
+ /** Whether the ImageWriter can write tiles. */
+ protected boolean canWriteTiles = false;
+
+ /** The tiling mode. */
+ protected int tilingMode = MODE_COPY_FROM_METADATA;
+
+ /** The preferred tile sizes. */
+ protected Dimension[] preferredTileSizes = null;
+
+ /** The tiling set. */
+ protected boolean tilingSet = false;
+
+ /** The tile width. */
+ protected int tileWidth = 0;
+
+ /** The tile height. */
+ protected int tileHeight = 0;
+
+ /** Whether the ImageWriter can offset tiles. */
+ protected boolean canOffsetTiles = false;
+
+ /** The tile grid x offset. */
+ protected int tileGridXOffset = 0;
+
+ /** The tile grid y offset. */
+ protected int tileGridYOffset = 0;
+
+ /** Whether the ImageWriter can write in progressive mode. */
+ protected boolean canWriteProgressive = false;
+
+ /** The progressive mode. */
+ protected int progressiveMode = MODE_COPY_FROM_METADATA;
+
+ /** Whether the ImageWriter can write in compressed mode. */
+ protected boolean canWriteCompressed = false;
+
+ /** The compression mode. */
+ protected int compressionMode = MODE_COPY_FROM_METADATA;
+
+ /** The compression types. */
+ protected String[] compressionTypes = null;
+
+ /** The compression type. */
+ protected String compressionType = null;
+
+ /** The compression quality. */
+ protected float compressionQuality = 1.0f;
+
+ /** The locale. */
+ protected Locale locale = null;
+
+ /**
+ * Instantiates a new ImageWriteParam.
+ */
+ protected ImageWriteParam() {}
+
+ /**
+ * Instantiates a new ImageWriteParam with the specified Locale.
+ *
+ * @param locale the Locale.
+ */
+ public ImageWriteParam(Locale locale) {
+ this.locale = locale;
+
+ }
+
+ /**
+ * Gets the mode for writing the stream in a progressive sequence.
+ *
+ * @return the current progressive mode.
+ */
+ public int getProgressiveMode() {
+ if (canWriteProgressive()) {
+ return progressiveMode;
+ }
+ throw new UnsupportedOperationException("progressive mode is not supported");
+ }
+
+ /**
+ * Returns true if images can be written using
+ * increasing quality passes by progressive.
+ *
+ * @return true if images can be written using
+ * increasing quality passes by progressive, false otherwise.
+ */
+ public boolean canWriteProgressive() {
+ return canWriteProgressive;
+ }
+
+ /**
+ * Sets the progressive mode which defines whether the stream
+ * contains a progressive sequence of increasing quality
+ * during writing. The progressive mode should be one of
+ * the following values: MODE_DISABLED, MODE_DEFAULT, or
+ * MODE_COPY_FROM_METADATA.
+ *
+ * @param mode the new progressive mode.
+ */
+ public void setProgressiveMode(int mode) {
+ if (canWriteProgressive()) {
+ if (mode < MODE_DISABLED || mode > MODE_COPY_FROM_METADATA || mode == MODE_EXPLICIT) {
+ throw new IllegalArgumentException("mode is not supported");
+ }
+ this.progressiveMode = mode;
+ }
+ throw new UnsupportedOperationException("progressive mode is not supported");
+ }
+
+ /**
+ * Returns true if the writer can use tiles with non zero
+ * grid offsets while writing.
+ *
+ * @return true if the writer can use tiles with non zero
+ * grid offsets while writing, false otherwise.
+ */
+ public boolean canOffsetTiles() {
+ return canOffsetTiles;
+ }
+
+ /**
+ * Returns true if this writer can write images with
+ * compression.
+ *
+ * @return true, true if this writer can write images with
+ * compression, false otherwise.
+ */
+ public boolean canWriteCompressed() {
+ return canWriteCompressed;
+ }
+
+ /**
+ * Returns true if the writer can write tiles.
+ *
+ * @return true if the writer can write tiles, false otherwise.
+ */
+ public boolean canWriteTiles() {
+ return canWriteTiles;
+ }
+
+ /**
+ * Check write compressed.
+ */
+ private final void checkWriteCompressed() {
+ if (!canWriteCompressed()) {
+ throw new UnsupportedOperationException("Compression not supported.");
+ }
+ }
+
+ /**
+ * Check compression mode.
+ */
+ private final void checkCompressionMode() {
+ if (getCompressionMode() != MODE_EXPLICIT) {
+ throw new IllegalStateException("Compression mode not MODE_EXPLICIT!");
+ }
+ }
+
+ /**
+ * Check compression type.
+ */
+ private final void checkCompressionType() {
+ if (getCompressionTypes() != null && getCompressionType() == null) {
+ throw new IllegalStateException("No compression type set!");
+ }
+ }
+
+ /**
+ * Gets the compression mode.
+ *
+ * @return the compression mode if it's supported.
+ */
+ public int getCompressionMode() {
+ checkWriteCompressed();
+ return compressionMode;
+ }
+
+ /**
+ * Gets the an array of supported compression types.
+ *
+ * @return the an array of supported compression types.
+ */
+ public String[] getCompressionTypes() {
+ checkWriteCompressed();
+ if (compressionTypes != null) {
+ return compressionTypes.clone();
+ }
+ return null;
+ }
+
+ /**
+ * Gets the current compression type, or returns null.
+ *
+ * @return the current compression type, or returns null
+ * if it is not set.
+ */
+ public String getCompressionType() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ return compressionType;
+ }
+
+ /**
+ * Gets a bit rate which represents an estimate of the number of bits
+ * of output data for each bit of input image data with the specified
+ * quality.
+ *
+ * @param quality the quality.
+ *
+ * @return an estimate of the bit rate, or -1.0F if there is no
+ * estimate.
+ */
+ public float getBitRate(float quality) {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ if (quality < 0 || quality > 1) {
+ throw new IllegalArgumentException("Quality out-of-bounds!");
+ }
+ return -1.0f;
+ }
+
+ /**
+ * Gets the compression quality.
+ *
+ * @return the compression quality.
+ */
+ public float getCompressionQuality() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ return compressionQuality;
+ }
+
+ /**
+ * Gets the array of compression quality descriptions.
+ *
+ * @return the string array of compression quality descriptions.
+ */
+ public String[] getCompressionQualityDescriptions() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ return null;
+ }
+
+ /**
+ * Gets an array of floats which decribe
+ * compression quality levels.
+ *
+ * @return the array of compression quality values.
+ */
+ public float[] getCompressionQualityValues() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ return null;
+ }
+
+ /**
+ * Gets the locale of this ImageWriteParam.
+ *
+ * @return the locale of this ImageWriteParam.
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Gets the current compression type using the current Locale.
+ *
+ * @return the current compression type using the current Locale.
+ */
+ public String getLocalizedCompressionTypeName() {
+ checkWriteCompressed();
+ checkCompressionMode();
+
+ String compressionType = getCompressionType();
+ if (compressionType == null) {
+ throw new IllegalStateException("No compression type set!");
+ }
+ return compressionType;
+
+ }
+
+ /**
+ * Check tiling.
+ */
+ private final void checkTiling() {
+ if (!canWriteTiles()) {
+ throw new UnsupportedOperationException("Tiling not supported!");
+ }
+ }
+
+ /**
+ * Check tiling mode.
+ */
+ private final void checkTilingMode() {
+ if (getTilingMode() != MODE_EXPLICIT) {
+ throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
+ }
+ }
+
+ /**
+ * Check tiling params.
+ */
+ private final void checkTilingParams() {
+ if (!tilingSet) {
+ throw new IllegalStateException("Tiling parameters not set!");
+ }
+ }
+
+ /**
+ * Gets the tiling mode if tiling is supported.
+ *
+ * @return the tiling mode if tiling is supported.
+ */
+ public int getTilingMode() {
+ checkTiling();
+ return tilingMode;
+ }
+
+ /**
+ * Gets an array of Dimensions giving the sizes of the tiles as
+ * they are encoded in the output file or stream.
+ *
+ * @return the preferred tile sizes.
+ */
+ public Dimension[] getPreferredTileSizes() {
+ checkTiling();
+ if (preferredTileSizes == null) {
+ return null;
+ }
+
+ Dimension[] retval = new Dimension[preferredTileSizes.length];
+ for (int i = 0; i < preferredTileSizes.length; i++) {
+ retval[i] = new Dimension(retval[i]);
+ }
+ return retval;
+ }
+
+ /**
+ * Gets the tile grid X offset for encoding.
+ *
+ * @return the tile grid X offset for encoding.
+ */
+ public int getTileGridXOffset() {
+ checkTiling();
+ checkTilingMode();
+ checkTilingParams();
+ return tileGridXOffset;
+ }
+
+ /**
+ * Gets the tile grid Y offset for encoding.
+ *
+ * @return the tile grid Y offset for encoding.
+ */
+ public int getTileGridYOffset() {
+ checkTiling();
+ checkTilingMode();
+ checkTilingParams();
+ return tileGridYOffset;
+ }
+
+ /**
+ * Gets the tile height in an image as it is written to the
+ * output stream.
+ *
+ * @return the tile height in an image as it is written to the
+ * output stream.
+ */
+ public int getTileHeight() {
+ checkTiling();
+ checkTilingMode();
+ checkTilingParams();
+ return tileHeight;
+ }
+
+ /**
+ * Gets the tile width in an image as it is written to the
+ * output stream.
+ *
+ * @return the tile width in an image as it is written to the
+ * output stream.
+ */
+ public int getTileWidth() {
+ checkTiling();
+ checkTilingMode();
+ checkTilingParams();
+ return tileWidth;
+ }
+
+ /**
+ * Checks if the current compression type has lossless
+ * compression or not.
+ *
+ * @return true, if the current compression type has lossless
+ * compression, false otherwise.
+ */
+ public boolean isCompressionLossless() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ return true;
+ }
+
+ /**
+ * Removes current compression type.
+ */
+ public void unsetCompression() {
+ checkWriteCompressed();
+ checkCompressionMode();
+ compressionType = null;
+ compressionQuality = 1;
+ }
+
+ /**
+ * Sets the compression mode to the specified value.
+ * The specified mode can be one of the predefined
+ * constants: MODE_DEFAULT, MODE_DISABLED, MODE_EXPLICIT,
+ * or MODE_COPY_FROM_METADATA.
+ *
+ * @param mode the new compression mode to be set.
+ */
+ public void setCompressionMode(int mode) {
+ checkWriteCompressed();
+ switch (mode) {
+ case MODE_EXPLICIT: {
+ compressionMode = mode;
+ unsetCompression();
+ break;
+ }
+ case MODE_COPY_FROM_METADATA:
+ case MODE_DISABLED:
+ case MODE_DEFAULT: {
+ compressionMode = mode;
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("Illegal value for mode!");
+ }
+ }
+ }
+
+ /**
+ * Sets the compression quality. The value should be between 0 and 1.
+ *
+ * @param quality the new compression quality,
+ * float value between 0 and 1.
+ */
+ public void setCompressionQuality(float quality) {
+ checkWriteCompressed();
+ checkCompressionMode();
+ checkCompressionType();
+ if (quality < 0 || quality > 1) {
+ throw new IllegalArgumentException("Quality out-of-bounds!");
+ }
+ compressionQuality = quality;
+ }
+
+ /**
+ * Sets the compression type. The specified string
+ * should be one of the values returned
+ * by getCompressionTypes method.
+ *
+ * @param compressionType the new compression type.
+ */
+ public void setCompressionType(String compressionType) {
+ checkWriteCompressed();
+ checkCompressionMode();
+
+ if (compressionType == null) { // Don't check anything
+ this.compressionType = null;
+ } else {
+ String[] compressionTypes = getCompressionTypes();
+ if (compressionTypes == null) {
+ throw new UnsupportedOperationException("No settable compression types");
+ }
+
+ for (int i = 0; i < compressionTypes.length; i++) {
+ if (compressionTypes[i].equals(compressionType)) {
+ this.compressionType = compressionType;
+ return;
+ }
+ }
+
+ // Compression type is not in the list.
+ throw new IllegalArgumentException("Unknown compression type!");
+ }
+ }
+
+ /**
+ * Sets the instruction that tiling should be performed for
+ * the image in the output stream with the specified parameters.
+ *
+ * @param tileWidth the tile's width.
+ * @param tileHeight the tile's height.
+ * @param tileGridXOffset the tile grid's x offset.
+ * @param tileGridYOffset the tile grid's y offset.
+ */
+ public void setTiling(int tileWidth, int tileHeight, int tileGridXOffset, int tileGridYOffset) {
+ checkTiling();
+ checkTilingMode();
+
+ if (!canOffsetTiles() && (tileGridXOffset != 0 || tileGridYOffset != 0)) {
+ throw new UnsupportedOperationException("Can't offset tiles!");
+ }
+
+ if (tileWidth <=0 || tileHeight <= 0) {
+ throw new IllegalArgumentException("tile dimensions are non-positive!");
+ }
+
+ Dimension preferredTileSizes[] = getPreferredTileSizes();
+ if (preferredTileSizes != null) {
+ for (int i = 0; i < preferredTileSizes.length; i+=2) {
+ Dimension minSize = preferredTileSizes[i];
+ Dimension maxSize = preferredTileSizes[i+1];
+ if (
+ tileWidth < minSize.width || tileWidth > maxSize.width ||
+ tileHeight < minSize.height || tileHeight > maxSize.height
+ ) {
+ throw new IllegalArgumentException("Illegal tile size!");
+ }
+ }
+ }
+
+ tilingSet = true;
+ this.tileWidth = tileWidth;
+ this.tileHeight = tileHeight;
+ this.tileGridXOffset = tileGridXOffset;
+ this.tileGridYOffset = tileGridYOffset;
+ }
+
+ /**
+ * Clears all tiling settings.
+ */
+ public void unsetTiling() {
+ checkTiling();
+ checkTilingMode();
+
+ tilingSet = false;
+ tileWidth = 0;
+ tileHeight = 0;
+ tileGridXOffset = 0;
+ tileGridYOffset = 0;
+ }
+
+ /**
+ * Sets the tiling mode. The specified mode should be one of the
+ * following values: MODE_DISABLED, MODE_DEFAULT, MODE_EXPLICIT,
+ * or MODE_COPY_FROM_METADATA.
+ *
+ * @param mode the new tiling mode.
+ */
+ public void setTilingMode(int mode) {
+ checkTiling();
+
+ switch (mode) {
+ case MODE_EXPLICIT: {
+ tilingMode = mode;
+ unsetTiling();
+ break;
+ }
+ case MODE_COPY_FROM_METADATA:
+ case MODE_DISABLED:
+ case MODE_DEFAULT: {
+ tilingMode = mode;
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("Illegal value for mode!");
+ }
+ }
+ }
+}
+
diff --git a/awt/javax/imageio/ImageWriter.java b/awt/javax/imageio/ImageWriter.java
new file mode 100644
index 0000000..d6119b0
--- /dev/null
+++ b/awt/javax/imageio/ImageWriter.java
@@ -0,0 +1,951 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.imageio.event.IIOWriteProgressListener;
+import javax.imageio.event.IIOWriteWarningListener;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageWriterSpi;
+
+/**
+ * The ImageWriter class is an abstract class for encoding images.
+ * ImageWriter objects are instantiated by the service provider
+ * interface, ImageWriterSpi class, for the specific format.
+ * ImageWriterSpi class should be registered with the IIORegistry,
+ * which uses them for format recognition and presentation of available
+ * format readers and writers.
+ */
+public abstract class ImageWriter implements ImageTranscoder {
+
+ /** The available locales. */
+ protected Locale[] availableLocales;
+
+ /** The locale. */
+ protected Locale locale;
+
+ /** The originating provider. */
+ protected ImageWriterSpi originatingProvider;
+
+ /** The output. */
+ protected Object output;
+
+ /** The progress listeners. */
+ protected List<IIOWriteProgressListener> progressListeners;
+
+ /** The warning listeners. */
+ protected List<IIOWriteWarningListener> warningListeners;
+
+ /** The warning locales. */
+ protected List<Locale> warningLocales;
+
+ // Indicates that abort operation is requested
+ // Abort mechanism should be thread-safe
+ /** The aborted. */
+ private boolean aborted;
+
+ /**
+ * Instantiates a new ImageWriter.
+ *
+ * @param originatingProvider the ImageWriterSpi which
+ * instanties this ImageWriter.
+ */
+ protected ImageWriter(ImageWriterSpi originatingProvider) {
+ this.originatingProvider = originatingProvider;
+ }
+
+ public abstract IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata,
+ ImageWriteParam imageWriteParam);
+
+ public abstract IIOMetadata convertImageMetadata(IIOMetadata iioMetadata,
+ ImageTypeSpecifier imageTypeSpecifier,
+ ImageWriteParam imageWriteParam);
+
+ /**
+ * Gets the ImageWriterSpi which instantiated this ImageWriter.
+ *
+ * @return the ImageWriterSpi.
+ */
+ public ImageWriterSpi getOriginatingProvider() {
+ return originatingProvider;
+ }
+
+ /**
+ * Processes the start of an image read by calling their imageStarted
+ * method of registered IIOWriteProgressListeners.
+ *
+ * @param imageIndex the image index.
+ */
+ protected void processImageStarted(int imageIndex) {
+ if (null != progressListeners) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.imageStarted(this, imageIndex);
+ }
+ }
+ }
+
+ /**
+ * Processes the current percentage of image completion by calling
+ * imageProgress method of registered IIOWriteProgressListener.
+ *
+ * @param percentageDone the percentage done.
+ */
+ protected void processImageProgress(float percentageDone) {
+ if (null != progressListeners) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.imageProgress(this, percentageDone);
+ }
+ }
+ }
+
+ /**
+ * Processes image completion by calling imageComplete method
+ * of registered IIOWriteProgressListeners.
+ */
+ protected void processImageComplete() {
+ if (null != progressListeners) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.imageComplete(this);
+ }
+ }
+ }
+
+ /**
+ * Processes a warning message by calling warningOccurred method
+ * of registered IIOWriteWarningListeners.
+ *
+ * @param imageIndex the image index.
+ * @param warning the warning.
+ */
+ protected void processWarningOccurred(int imageIndex, String warning) {
+ if (null == warning) {
+ throw new NullPointerException("warning message should not be NULL");
+ }
+ if (null != warningListeners) {
+ for (IIOWriteWarningListener listener : warningListeners) {
+ listener.warningOccurred(this, imageIndex, warning);
+ }
+ }
+ }
+
+ /**
+ * Processes a warning message by calling warningOccurred method
+ * of registered IIOWriteWarningListeners with string from
+ * ResourceBundle.
+ *
+ * @param imageIndex the image index.
+ * @param bundle the name of ResourceBundle.
+ * @param key the keyword.
+ */
+ protected void processWarningOccurred(int imageIndex, String bundle, String key) {
+ if (warningListeners != null) { // Don't check the parameters
+ return;
+ }
+
+ if (bundle == null) {
+ throw new IllegalArgumentException("baseName == null!");
+ }
+ if (key == null) {
+ throw new IllegalArgumentException("keyword == null!");
+ }
+
+ // Get the context class loader and try to locate the bundle with it first
+ ClassLoader contextClassloader = AccessController.doPrivileged(
+ new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+
+ // Iterate through both listeners and locales
+ int n = warningListeners.size();
+ for (int i=0; i < n; i++) {
+ IIOWriteWarningListener listener = warningListeners.get(i);
+ Locale locale = warningLocales.get(i);
+
+ // Now try to get the resource bundle
+ ResourceBundle rb;
+ try {
+ rb = ResourceBundle.getBundle(bundle, locale, contextClassloader);
+ } catch (MissingResourceException e) {
+ try {
+ rb = ResourceBundle.getBundle(bundle, locale);
+ } catch (MissingResourceException e1) {
+ throw new IllegalArgumentException("Bundle not found!");
+ }
+ }
+
+ try {
+ String warning = rb.getString(key);
+ listener.warningOccurred(this, imageIndex, warning);
+ } catch (MissingResourceException e) {
+ throw new IllegalArgumentException("Resource is missing!");
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("Resource is not a String!");
+ }
+ }
+ }
+
+ /**
+ * Sets the specified Object to the output of this ImageWriter.
+ *
+ * @param output the Object which represents destination, it can
+ * be ImageOutputStream or other objects.
+ */
+ public void setOutput(Object output) {
+ if (output != null) {
+ ImageWriterSpi spi = getOriginatingProvider();
+ if (null != spi) {
+ Class[] outTypes = spi.getOutputTypes();
+ boolean supported = false;
+ for (Class<?> element : outTypes) {
+ if (element.isInstance(output)) {
+ supported = true;
+ break;
+ }
+ }
+ if (!supported) {
+ throw new IllegalArgumentException("output " + output + " is not supported");
+ }
+ }
+ }
+ this.output = output;
+ }
+
+ /**
+ * Writes a completed image stream that contains the specified image,
+ * default metadata, and thumbnails to the output.
+ *
+ * @param image the specified image to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred
+ * during writting.
+ */
+ public void write(IIOImage image) throws IOException {
+ write(null, image, null);
+ }
+
+ /**
+ * Writes a completed image stream that contains the specified
+ * rendered image, default metadata, and thumbnails to the output.
+ *
+ * @param image the specified RenderedImage to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred
+ * during writting.
+ */
+ public void write(RenderedImage image) throws IOException {
+ write(null, new IIOImage(image, null, null), null);
+ }
+
+ /**
+ * Writes a completed image stream that contains the specified image,
+ * metadata and thumbnails to the output.
+ *
+ * @param streamMetadata the stream metadata, or null.
+ * @param image the specified image to be written, if
+ * canWriteRaster() method returns false, then Image must contain
+ * only RenderedImage.
+ * @param param the ImageWriteParam, or null.
+ *
+ * @throws IOException - if an error occurs during writing.
+ */
+ public abstract void write(IIOMetadata streamMetadata,
+ IIOImage image, ImageWriteParam param) throws IOException;
+
+ /**
+ * Disposes of any resources.
+ */
+ public void dispose() {
+ // def impl. does nothing according to the spec.
+ }
+
+ /**
+ * Requests an abort operation for current writing operation.
+ */
+ public synchronized void abort() {
+ aborted = true;
+ }
+
+ /**
+ * Checks whether or not a request to abort the current write operation
+ * has been made successfully.
+ *
+ * @return true, if the request to abort the current write operation
+ * has been made successfully, false otherwise.
+ */
+ protected synchronized boolean abortRequested() {
+ return aborted;
+ }
+
+ /**
+ * Clears all previous abort request, and abortRequested returns false
+ * after calling this method.
+ */
+ protected synchronized void clearAbortRequest() {
+ aborted = false;
+ }
+
+ /**
+ * Adds the IIOWriteProgressListener listener.
+ *
+ * @param listener the IIOWriteProgressListener listener.
+ */
+ public void addIIOWriteProgressListener(IIOWriteProgressListener listener) {
+ if (listener == null) {
+ return;
+ }
+
+ if (progressListeners == null) {
+ progressListeners = new ArrayList<IIOWriteProgressListener>();
+ }
+
+ progressListeners.add(listener);
+ }
+
+ /**
+ * Adds the IIOWriteWarningListener.
+ *
+ * @param listener the IIOWriteWarningListener listener.
+ */
+ public void addIIOWriteWarningListener(IIOWriteWarningListener listener) {
+ if (listener == null) {
+ return;
+ }
+
+ if (warningListeners == null) {
+ warningListeners = new ArrayList<IIOWriteWarningListener>();
+ warningLocales = new ArrayList<Locale>();
+ }
+
+ warningListeners.add(listener);
+ warningLocales.add(getLocale());
+ }
+
+ /**
+ * Gets the output object that was set by setOutput method.
+ *
+ * @return the output object such as ImageOutputStream, or null if
+ * it is not set.
+ */
+ public Object getOutput() {
+ return output;
+ }
+
+ /**
+ * Check output return false.
+ *
+ * @return true, if successful
+ */
+ private final boolean checkOutputReturnFalse() {
+ if (getOutput() == null) {
+ throw new IllegalStateException("getOutput() == null!");
+ }
+ return false;
+ }
+
+ /**
+ * Unsupported operation.
+ */
+ private final void unsupportedOperation() {
+ if (getOutput() == null) {
+ throw new IllegalStateException("getOutput() == null!");
+ }
+ throw new UnsupportedOperationException("Unsupported write variant!");
+ }
+
+
+ /**
+ * Returns true if a new empty image can be inserted at
+ * the specified index.
+ *
+ * @param imageIndex the specified index of image.
+ *
+ * @return true if a new empty image can be inserted at
+ * the specified index, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canInsertEmpty(int imageIndex) throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if a new image can be inserted at the specified index.
+ *
+ * @param imageIndex the specified index of image.
+ *
+ * @return true if a new image can be inserted at the specified index,
+ * false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canInsertImage(int imageIndex) throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returnes true if the image with the specified index can be removed.
+ *
+ * @param imageIndex the specified index of image.
+ *
+ * @return true if the image with the specified index can be removed,
+ * false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canRemoveImage(int imageIndex) throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if metadata of the image with the specified index
+ * can be replaced.
+ *
+ * @param imageIndex the specified image index.
+ *
+ * @return true if metadata of the image with the specified index
+ * can be replaced, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canReplaceImageMetadata(int imageIndex) throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if pixels of the image with the specified index
+ * can be replaced by the replacePixels methods.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @return true if pixels of the image with the specified index
+ * can be replaced by the replacePixels methods, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canReplacePixels(int imageIndex) throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if the stream metadata presented in the output
+ * can be removed.
+ *
+ * @return true if the stream metadata presented in the output
+ * can be removed, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canReplaceStreamMetadata() throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if the writing of a complete image stream which
+ * contains a single image is supported with undefined pixel
+ * values and associated metadata and thumbnails to the output.
+ *
+ * @return true if the writing of a complete image stream which
+ * contains a single image is supported, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public boolean canWriteEmpty() throws IOException {
+ return checkOutputReturnFalse();
+ }
+
+ /**
+ * Returns true if the methods which taken an IIOImageParameter
+ * can deal with a Raster source image.
+ *
+ * @return true if the methods which taken an IIOImageParameter
+ * can deal with a Raster source image, false otherwise.
+ */
+ public boolean canWriteRasters() {
+ return false;
+ }
+
+ /**
+ * Returns true if the writer can add an image to stream that
+ * already contains header information.
+ *
+ * @return if the writer can add an image to stream that
+ * already contains header information, false otherwise.
+ */
+ public boolean canWriteSequence() {
+ return false;
+ }
+
+ /**
+ * Ends the insertion of a new image.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void endInsertEmpty() throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Ends the repalce pixels operation.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void endReplacePixels() throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Ends an empty write operation.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void endWriteEmpty() throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Ends the sequence of write operations.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void endWriteSequence() throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Gets an array of available locales.
+ *
+ * @return an of array available locales.
+ */
+ public Locale[] getAvailableLocales() {
+ if (availableLocales == null) {
+ return null;
+ }
+
+ return availableLocales.clone();
+ }
+
+ /**
+ * Gets an IIOMetadata object that contains default values
+ * for encoding an image with the specified type.
+ *
+ * @param imageType the ImageTypeSpecifier.
+ * @param param the ImageWriteParam.
+ *
+ * @return the IIOMetadata object.
+ */
+ public abstract IIOMetadata getDefaultImageMetadata(
+ ImageTypeSpecifier imageType,
+ ImageWriteParam param
+ );
+
+ /**
+ * Gets an IIOMetadata object that contains default values
+ * for encoding a stream of images.
+ *
+ * @param param the ImageWriteParam.
+ *
+ * @return the IIOMetadata object.
+ */
+ public abstract IIOMetadata getDefaultStreamMetadata(ImageWriteParam param);
+
+ /**
+ * Gets the current locale of this ImageWriter.
+ *
+ * @return the current locale of this ImageWriter.
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Gets the default write param.
+ * Gets a new ImageWriteParam object for this ImageWriter with the
+ * current Locale.
+ *
+ * @return a new ImageWriteParam object for this ImageWriter.
+ */
+ public ImageWriteParam getDefaultWriteParam() {
+ return new ImageWriteParam(getLocale());
+ }
+
+ /**
+ * Gets the number of thumbnails suported by the format
+ * being written with supported image type, image write
+ * parameters, stream, and image metadata objects.
+ *
+ * @param imageType the ImageTypeSpecifier.
+ * @param param the image's parameters.
+ * @param streamMetadata the stream metadata.
+ * @param imageMetadata the image metadata.
+ *
+ * @return the number of thumbnails supported
+ */
+ public int getNumThumbnailsSupported(
+ ImageTypeSpecifier imageType,
+ ImageWriteParam param,
+ IIOMetadata streamMetadata,
+ IIOMetadata imageMetadata
+ ) {
+ return 0;
+ }
+
+ /**
+ * Gets the preferred thumbnail sizes.
+ * Gets an array of Dimensions with the sizes for thumbnail images
+ * as they are encoded in the output file or stream.
+ *
+ * @param imageType the ImageTypeSpecifier.
+ * @param param the ImageWriteParam.
+ * @param streamMetadata the stream metadata.
+ * @param imageMetadata the image metadata.
+ *
+ * @return the preferred thumbnail sizes
+ */
+ public Dimension[] getPreferredThumbnailSizes(
+ ImageTypeSpecifier imageType,
+ ImageWriteParam param,
+ IIOMetadata streamMetadata,
+ IIOMetadata imageMetadata
+ ) {
+ return null;
+ }
+
+ /**
+ * Prepares insertion of an empty image by requesting the insertion of
+ * a new image into an existing image stream.
+ *
+ * @param imageIndex the image index.
+ * @param imageType the image type.
+ * @param width the width of the image.
+ * @param height the height of the image.
+ * @param imageMetadata the image metadata, or null.
+ * @param thumbnails the array thumbnails for this image, or null.
+ * @param param the ImageWriteParam, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void prepareInsertEmpty(
+ int imageIndex, ImageTypeSpecifier imageType,
+ int width, int height,
+ IIOMetadata imageMetadata, List<? extends BufferedImage> thumbnails,
+ ImageWriteParam param
+ ) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Prepares the writer to call the replacePixels method for the
+ * specified region.
+ *
+ * @param imageIndex the image's index.
+ * @param region the specified region.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void prepareReplacePixels(int imageIndex, Rectangle region) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Prepares the writer for writing an empty image by beginning the
+ * process of writing a complete image stream that contains a single image
+ * with undefined pixel values, metadata and thumbnails,
+ * to the output.
+ *
+ * @param streamMetadata the stream metadata.
+ * @param imageType the image type.
+ * @param width the width of the image.
+ * @param height the height of the image.
+ * @param imageMetadata the image's metadata, or null.
+ * @param thumbnails the image's thumbnails, or null.
+ * @param param the image's parameters, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void prepareWriteEmpty(
+ IIOMetadata streamMetadata, ImageTypeSpecifier imageType,
+ int width, int height,
+ IIOMetadata imageMetadata, List<? extends BufferedImage> thumbnails,
+ ImageWriteParam param
+ ) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Prepares a stream to accept calls of writeToSequence method
+ * using the metadata object.
+ *
+ * @param streamMetadata the stream metadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Processes the completion of a thumbnail read
+ * by calling their thumbnailComplete method
+ * of registered IIOWriteProgressListeners.
+ */
+ protected void processThumbnailComplete() {
+ if (progressListeners != null) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.thumbnailComplete(this);
+ }
+ }
+ }
+
+ /**
+ * Processes the current percentage of thumbnail completion
+ * by calling their thumbnailProgress method of registered
+ * IIOWriteProgressListeners.
+ *
+ * @param percentageDone the percentage done.
+ */
+ protected void processThumbnailProgress(float percentageDone) {
+ if (progressListeners != null) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.thumbnailProgress(this, percentageDone);
+ }
+ }
+ }
+
+ /**
+ * Processes the start of a thumbnail read by calling
+ * thumbnailStarted method of registered IIOWriteProgressListeners.
+ *
+ * @param imageIndex the image index.
+ * @param thumbnailIndex the thumbnail index.
+ */
+ protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) {
+ if (progressListeners != null) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.thumbnailStarted(this, imageIndex, thumbnailIndex);
+ }
+ }
+ }
+
+ /**
+ * Processes that the writing has been aborted by calling writeAborted
+ * method of registered IIOWriteProgressListeners.
+ */
+ protected void processWriteAborted() {
+ if (progressListeners != null) {
+ for (IIOWriteProgressListener listener : progressListeners) {
+ listener.writeAborted(this);
+ }
+ }
+ }
+
+ /**
+ * Removes the all IIOWriteProgressListener listeners.
+ */
+ public void removeAllIIOWriteProgressListeners() {
+ progressListeners = null;
+ }
+
+ /**
+ * Removes the all IIOWriteWarningListener listeners.
+ */
+ public void removeAllIIOWriteWarningListeners() {
+ warningListeners = null;
+ warningLocales = null;
+ }
+
+ /**
+ * Removes the specified IIOWriteProgressListener listener.
+ *
+ * @param listener the registered IIOWriteProgressListener
+ * to be removed.
+ */
+ public void removeIIOWriteProgressListener(IIOWriteProgressListener listener) {
+ if (progressListeners != null && listener != null) {
+ if (progressListeners.remove(listener) && progressListeners.isEmpty()) {
+ progressListeners = null;
+ }
+ }
+ }
+
+ /**
+ * Removes the specified IIOWriteWarningListener listener.
+ *
+ * @param listener the registered IIOWriteWarningListener listener
+ * to be removed.
+ */
+ public void removeIIOWriteWarningListener(IIOWriteWarningListener listener) {
+ if (warningListeners == null || listener == null) {
+ return;
+ }
+
+ int idx = warningListeners.indexOf(listener);
+ if (idx > -1) {
+ warningListeners.remove(idx);
+ warningLocales.remove(idx);
+
+ if (warningListeners.isEmpty()) {
+ warningListeners = null;
+ warningLocales = null;
+ }
+ }
+ }
+
+ /**
+ * Removes the image with the specified index from the stream.
+ *
+ * @param imageIndex the image's index.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void removeImage(int imageIndex) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Replaces image metadata of the image with specified index.
+ *
+ * @param imageIndex the image's index.
+ * @param imageMetadata the image metadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void replaceImageMetadata(int imageIndex, IIOMetadata imageMetadata) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Replaces a part of an image presented in the output
+ * with the specified RenderedImage.
+ *
+ * @param image the RenderedImage.
+ * @param param the ImageWriteParam.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void replacePixels(RenderedImage image, ImageWriteParam param) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Replaces a part of an image presented in the output
+ * with the specified Raster.
+ *
+ * @param raster the Raster.
+ * @param param the ImageWriteParam.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void replacePixels(Raster raster, ImageWriteParam param) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Replaces the stream metadata of the output with new IIOMetadata.
+ *
+ * @param streamMetadata the new stream metadata.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void replaceStreamMetadata(IIOMetadata streamMetadata) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Sets the locale of this ImageWriter.
+ *
+ * @param locale the new locale.
+ */
+ public void setLocale(Locale locale) {
+ if (locale == null) {
+ this.locale = null;
+ return;
+ }
+
+ Locale[] locales = getAvailableLocales();
+ boolean validLocale = false;
+ if (locales != null) {
+ for (int i = 0; i < locales.length; i++) {
+ if (locale.equals(locales[i])) {
+ validLocale = true;
+ break;
+ }
+ }
+ }
+
+ if (validLocale) {
+ this.locale = locale;
+ } else {
+ throw new IllegalArgumentException("Invalid locale!");
+ }
+ }
+
+ /**
+ * Resets this ImageWriter.
+ */
+ public void reset() {
+ setOutput(null);
+ setLocale(null);
+ removeAllIIOWriteWarningListeners();
+ removeAllIIOWriteProgressListeners();
+ clearAbortRequest();
+ }
+
+ /**
+ * Inserts image into existing output stream.
+ *
+ * @param imageIndex the image index where an image will be written.
+ * @param image the specified image to be written.
+ * @param param the ImageWriteParam, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public void writeInsert(int imageIndex, IIOImage image, ImageWriteParam param) throws IOException {
+ unsupportedOperation();
+ }
+
+ /**
+ * Writes the specified image to the sequence.
+ *
+ * @param image the image to be written.
+ * @param param the ImageWriteParam, or null.
+ *
+ * @throws IOException Signals that an I/O exception has occurred
+ * during writting.
+ */
+ public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException {
+ unsupportedOperation();
+ }
+}
diff --git a/awt/javax/imageio/event/IIOReadProgressListener.java b/awt/javax/imageio/event/IIOReadProgressListener.java
new file mode 100644
index 0000000..3d65807
--- /dev/null
+++ b/awt/javax/imageio/event/IIOReadProgressListener.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.event;
+
+import java.util.EventListener;
+import javax.imageio.ImageReader;
+
+/**
+ * The IIOReadProgressListener interface notifies callers
+ * about the progress of the image and thumbnail reading methods.
+ */
+public interface IIOReadProgressListener extends EventListener {
+
+ /**
+ * Notifies this listener that the image reading has been completed.
+ *
+ * @param source the ImageReader object which calls this method.
+ */
+ void imageComplete(ImageReader source);
+
+ /**
+ * Notifies this listener about the degree of completion of the read call.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param percentageDone the percentage of decoding done.
+ */
+ void imageProgress(ImageReader source, float percentageDone);
+
+ /**
+ * Notifies this listener that an image read operation has been started.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param imageIndex the index of the image in an input file or
+ * stream to be read.
+ */
+ void imageStarted(ImageReader source, int imageIndex);
+
+ /**
+ * Notifies this listener that a read operation has been aborted.
+ *
+ * @param source the ImageReader object which calls this method.
+ */
+ void readAborted(ImageReader source);
+
+ /**
+ * Notifies this listener that a sequence of read operations has been completed.
+ *
+ * @param source the ImageReader object which calls this method.
+ */
+ void sequenceComplete(ImageReader source);
+
+ /**
+ * Notifies this listener that a sequence of read operation has been started.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param minIndex the index of the first image to be read.
+ */
+ void sequenceStarted(ImageReader source, int minIndex);
+
+ /**
+ * Notifies that a thumbnail read operation has been completed.
+ *
+ * @param source the ImageReader object which calls this method.
+ */
+ void thumbnailComplete(ImageReader source);
+
+ /**
+ * Notifies this listener about the degree of completion of the read call.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param percentageDone the percentage of decoding done.
+ */
+ void thumbnailProgress(ImageReader source, float percentageDone);
+
+ /**
+ * Notifies this listener that a thumbnail reading operation has been started.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param imageIndex the index of the image in an input file or
+ * stream to be read.
+ * @param thumbnailIndex the index of the thumbnail to be read.
+ */
+ void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex);
+}
+
diff --git a/awt/javax/imageio/event/IIOReadUpdateListener.java b/awt/javax/imageio/event/IIOReadUpdateListener.java
new file mode 100644
index 0000000..ce5e2f1
--- /dev/null
+++ b/awt/javax/imageio/event/IIOReadUpdateListener.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.event;
+
+import java.awt.image.BufferedImage;
+import java.util.EventListener;
+import javax.imageio.ImageReader;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOReadUpdateListener interface provides functionality
+ * to receive notification of pixel updates during image and thumbnail
+ * reading operations.
+ */
+public interface IIOReadUpdateListener extends EventListener {
+
+ /**
+ * Notifies this listener that the specified area of the image has been updated.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theImage the image to be updated.
+ * @param minX the minimum X coordinate of the pixels in the updated area.
+ * @param minY the minimum Y coordinate of the pixels in the updated area.
+ * @param width the width of updated area.
+ * @param height the height of updated area.
+ * @param periodX the horizontal spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param periodY the vertical spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param bands the array of int values indicating the bands being updated.
+ */
+ void imageUpdate(ImageReader source, BufferedImage theImage, int minX,
+ int minY, int width, int height, int periodX, int periodY,
+ int[] bands);
+
+ /**
+ * Notifies this listener that the current read operation has completed a
+ * progressive pass.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theImage the image to be updated.
+ */
+ void passComplete(ImageReader source, BufferedImage theImage);
+
+ /**
+ * Notifies this listener that the current read operation has begun
+ * a progressive pass.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theImage the image to be updated.
+ * @param pass the numer of the pass.
+ * @param minPass the index of the first pass that will be decoded.
+ * @param maxPass the index of the last pass that will be decoded.
+ * @param minX the minimum X coordinate of the pixels in the updated area.
+ * @param minY the minimum Y coordinate of the pixels in the updated area.
+ * @param periodX the horizontal spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param periodY the vertical spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param bands the array of int values indicating the bands being updated.
+ */
+ void passStarted(ImageReader source, BufferedImage theImage, int pass,
+ int minPass, int maxPass, int minX, int minY, int periodX,
+ int periodY, int[] bands);
+
+ /**
+ * Notifies this listener that the current thumbnail read operation has
+ * completed a progressive pass.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theImage the thumbnail to be updated.
+ */
+ void thumbnailPassComplete(ImageReader source, BufferedImage theImage);
+
+ /**
+ * Notifies this listener that the current thumbnail read operation has
+ * begun a progressive pass.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theThumbnail the thumbnail to be updated.
+ * @param pass the numer of the pass.
+ * @param minPass the index of the first pass that will be decoded.
+ * @param maxPass the index of the last pass that will be decoded.
+ * @param minX the minimum X coordinate of the pixels in the updated area.
+ * @param minY the minimum Y coordinate of the pixels in the updated area.
+ * @param periodX the horizontal spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param periodY the vertical spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param bands the array of int values indicating the bands being updated.
+ */
+ void thumbnailPassStarted(ImageReader source, BufferedImage theThumbnail,
+ int pass, int minPass, int maxPass, int minX, int minY,
+ int periodX, int periodY, int[] bands);
+
+ /**
+ * Notifies this listener that a specified area of a thumbnail image has been
+ * updated.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param theThumbnail the thumbnail to be updated.
+ * @param minX the minimum X coordinate of the pixels in the updated area.
+ * @param minY the minimum Y coordinate of the pixels in the updated area.
+ * @param width the width of updated area.
+ * @param height the height of updated area.
+ * @param periodX the horizontal spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param periodY the vertical spacing period between updated
+ * pixels, if it equals 1, there is no space between pixels.
+ * @param bands the array of int values indicating the bands being updated.
+ */
+ void thumbnailUpdate(ImageReader source, BufferedImage theThumbnail,
+ int minX, int minY, int width, int height, int periodX,
+ int periodY, int[] bands);
+}
+
diff --git a/awt/javax/imageio/event/IIOReadWarningListener.java b/awt/javax/imageio/event/IIOReadWarningListener.java
new file mode 100644
index 0000000..92fa275
--- /dev/null
+++ b/awt/javax/imageio/event/IIOReadWarningListener.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.event;
+
+import java.util.EventListener;
+import javax.imageio.ImageReader;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOReadWarningListener provides methods to receive notification
+ * of warning messages generated by image
+ * and thumbnail reading methods.
+ */
+public interface IIOReadWarningListener extends EventListener {
+
+ /**
+ * Notifies this listener about a warning (non-fatal error) during decoding.
+ *
+ * @param source the ImageReader object which calls this method.
+ * @param warning the string describing the warning.
+ */
+ public void warningOccurred(ImageReader source, String warning);
+}
+
diff --git a/awt/javax/imageio/event/IIOWriteProgressListener.java b/awt/javax/imageio/event/IIOWriteProgressListener.java
new file mode 100644
index 0000000..19ae495
--- /dev/null
+++ b/awt/javax/imageio/event/IIOWriteProgressListener.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.event;
+
+import javax.imageio.ImageWriter;
+import java.util.EventListener;
+
+/**
+ * The IIOWriteProgressListener interface provides methods to
+ * receive notification about the progress of the image and
+ * thumbnail writing methods.
+ */
+public interface IIOWriteProgressListener extends EventListener {
+
+ /**
+ * Notifies this listener that an image write operation has been started.
+ *
+ * @param source the ImageWriter object which calls this method.
+ * @param imageIndex the index of the image being written.
+ */
+ void imageStarted(ImageWriter source, int imageIndex);
+
+ /**
+ * Notifies this listener about the degree of completion of the write call.
+ *
+ * @param source the ImageWriter object which calls this method.
+ * @param percentageDone the percentage of encoding done.
+ */
+ void imageProgress(ImageWriter source, float percentageDone);
+
+ /**
+ * Notifies this listener that the image writing has been completed.
+ *
+ * @param source the ImageWriter object which calls this method.
+ */
+ void imageComplete(ImageWriter source);
+
+ /**
+ * Notifies this listener that a thumbnail write operation has been started.
+ *
+ * @param source the ImageWriter object which calls this method.
+ * @param imageIndex the index of the image being written.
+ * @param thumbnailIndex the index of the thumbnail being written.
+ */
+ void thumbnailStarted(ImageWriter source, int imageIndex, int thumbnailIndex);
+
+ /**
+ * Notifies this listener about the degree of completion of the write call.
+ *
+ * @param source the ImageWriter object which calls this method.
+ * @param percentageDone the percentage of encoding done.
+ */
+ void thumbnailProgress(ImageWriter source, float percentageDone);
+
+ /**
+ * Notifies this listener that a thumbnail write operation has been completed.
+ *
+ * @param source the ImageWriter object which calls this method.
+ */
+ void thumbnailComplete(ImageWriter source);
+
+ /**
+ * Notifies this listener that writing operation has been aborted.
+ *
+ * @param source the ImageWriter object which calls this method.
+ */
+ void writeAborted(ImageWriter source);
+}
diff --git a/awt/javax/imageio/event/IIOWriteWarningListener.java b/awt/javax/imageio/event/IIOWriteWarningListener.java
new file mode 100644
index 0000000..f530d25
--- /dev/null
+++ b/awt/javax/imageio/event/IIOWriteWarningListener.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.event;
+
+import javax.imageio.ImageWriter;
+import java.util.EventListener;
+
+/**
+ * The IIOWriteWarningListener provides methods to receive notification
+ * of warnings generated by image and thumbnail writing methods.
+ */
+public interface IIOWriteWarningListener extends EventListener {
+
+ /**
+ * Notifies this listener about a warning (non-fatal error) during encoding.
+ *
+ * @param source the ImageWriter object which calls this method.
+ * @param imageIndex the index of the image generating the warning.
+ * @param warning the string describing the warning.
+ */
+ void warningOccurred(ImageWriter source, int imageIndex, String warning);
+}
diff --git a/awt/javax/imageio/metadata/IIOInvalidTreeException.java b/awt/javax/imageio/metadata/IIOInvalidTreeException.java
new file mode 100644
index 0000000..8690b2b
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOInvalidTreeException.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.metadata;
+
+import org.w3c.dom.Node;
+import javax.imageio.IIOException;
+
+/**
+ * The IIOInvalidTreeException provides notification about
+ * fails of IIOMetadataNodes tree parsing by IIOMetadata object.
+ */
+public class IIOInvalidTreeException extends IIOException {
+
+ /** The offending node. */
+ protected Node offendingNode = null;
+
+ /**
+ * Instantiates an IIOInvalidTreeException with the
+ * specified detailed message and specified offending
+ * Node.
+ *
+ * @param message the detailed message.
+ * @param offendingNode the offending node.
+ */
+ public IIOInvalidTreeException(String message, Node offendingNode) {
+ super(message);
+ this.offendingNode = offendingNode;
+ }
+
+ /**
+ * Instantiates a new IIOInvalidTreeException with the
+ * specified detailed message and specified offending
+ * Node.
+ *
+ * @param message the detailed message.
+ * @param cause the cause of this exception.
+ * @param offendingNode the offending node
+ */
+ public IIOInvalidTreeException(String message, Throwable cause, Node offendingNode) {
+ super(message, cause);
+ this.offendingNode = offendingNode;
+ }
+
+ /**
+ * Gets the offending node.
+ *
+ * @return the offending node.
+ */
+ public Node getOffendingNode() {
+ return offendingNode;
+ }
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadata.java b/awt/javax/imageio/metadata/IIOMetadata.java
new file mode 100644
index 0000000..f2387cc
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadata.java
@@ -0,0 +1,371 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package javax.imageio.metadata;
+
+import java.util.ArrayList;
+
+import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils;
+import org.w3c.dom.Node;
+
+/**
+ * The Class IIOMetadata represents the metadata (bundled with an image)
+ * as a Dom-type tree.
+ */
+public abstract class IIOMetadata {
+
+ /** Whether the standard metadata format is supported. */
+ protected boolean standardFormatSupported;
+
+ /** The native metadata format name. */
+ protected String nativeMetadataFormatName;
+
+ /** The native metadata format class name. */
+ protected String nativeMetadataFormatClassName;
+
+ /** The extra metadata format names. */
+ protected String[] extraMetadataFormatNames;
+
+ /** The extra metadata format class names. */
+ protected String[] extraMetadataFormatClassNames;
+
+ /** The default controller. */
+ protected IIOMetadataController defaultController;
+
+ /** The controller. */
+ protected IIOMetadataController controller;
+
+ /**
+ * Instantiates a new IIOMetadata with no data set.
+ */
+ protected IIOMetadata() {}
+
+ /**
+ * Instantiates a new IIOMetadata with the specified data parameters.
+ *
+ * @param standardMetadataFormatSupported whether the standard metadata format is supported
+ * @param nativeMetadataFormatName the native metadata format name
+ * @param nativeMetadataFormatClassName the native metadata format class name
+ * @param extraMetadataFormatNames the extra metadata format names
+ * @param extraMetadataFormatClassNames the extra metadata format class names
+ */
+ protected IIOMetadata(boolean standardMetadataFormatSupported,
+ String nativeMetadataFormatName,
+ String nativeMetadataFormatClassName,
+ String[] extraMetadataFormatNames,
+ String[] extraMetadataFormatClassNames) {
+ standardFormatSupported = standardMetadataFormatSupported;
+ this.nativeMetadataFormatName = nativeMetadataFormatName;
+ this.nativeMetadataFormatClassName = nativeMetadataFormatClassName;
+ if (extraMetadataFormatNames == null) {
+ if (extraMetadataFormatClassNames != null) {
+ throw new IllegalArgumentException(
+ "extraMetadataFormatNames == null && extraMetadataFormatClassNames != null!"
+ );
+ }
+ } else {
+ if (extraMetadataFormatClassNames == null) {
+ throw new IllegalArgumentException(
+ "extraMetadataFormatNames != null && extraMetadataFormatClassNames == null!"
+ );
+ }
+ if (extraMetadataFormatNames.length == 0) {
+ throw new IllegalArgumentException("extraMetadataFormatNames.length == 0!");
+ }
+ if (extraMetadataFormatClassNames.length != extraMetadataFormatNames.length) {
+ throw new IllegalArgumentException(
+ "extraMetadataFormatClassNames.length != extraMetadataFormatNames.length!"
+ );
+ }
+ this.extraMetadataFormatNames = extraMetadataFormatNames.clone();
+ this.extraMetadataFormatClassNames = extraMetadataFormatClassNames.clone();
+ }
+ }
+
+ /**
+ * Gets the metadata as tree-type document.
+ *
+ * @param formatName the format name
+ *
+ * @return the node in tree format
+ */
+ public abstract Node getAsTree(String formatName);
+
+ /**
+ * Checks if the metadata is read only.
+ *
+ * @return true, if the metadata is read only.
+ */
+ public abstract boolean isReadOnly();
+
+ /**
+ * Merges the specified tree with this metadata tree.
+ *
+ * @param formatName the format of the specified tree
+ * @param root the root node of the metadata tree
+ *
+ * @throws IIOInvalidTreeException if the specified tree
+ * is incompatible with the this metadata tree.
+ */
+ public abstract void mergeTree(String formatName, Node root) throws IIOInvalidTreeException;
+
+ /**
+ * Resets the controller.
+ */
+ public abstract void reset();
+
+ /**
+ * Gets the controller associated with this metadata document.
+ *
+ * @return the controller
+ */
+ public IIOMetadataController getController() {
+ return controller;
+ }
+
+ /**
+ * Checks whether this metadata has a controller.
+ *
+ * @return true, if this metadata has a controller
+ */
+ public boolean hasController() {
+ return getController() != null;
+ }
+
+ /**
+ * Activate the controller.
+ *
+ * @return true, if successful
+ */
+ public boolean activateController() {
+ if (!hasController()) {
+ throw new IllegalStateException("hasController() == false!");
+ }
+ return getController().activate(this);
+ }
+
+ /**
+ * Gets the default controller.
+ *
+ * @return the default controller
+ */
+ public IIOMetadataController getDefaultController() {
+ return defaultController;
+ }
+
+ /**
+ * Gets the extra metadata format names.
+ *
+ * @return the extra metadata format names
+ */
+ public String[] getExtraMetadataFormatNames() {
+ return extraMetadataFormatNames == null ? null : extraMetadataFormatNames.clone();
+ }
+
+ /**
+ * Gets the metadata format.
+ *
+ * @param formatName the format name
+ *
+ * @return the metadata format
+ */
+ public IIOMetadataFormat getMetadataFormat(String formatName) {
+ return IIOMetadataUtils.instantiateMetadataFormat(
+ formatName,
+ standardFormatSupported,
+ nativeMetadataFormatName, nativeMetadataFormatClassName,
+ extraMetadataFormatNames, extraMetadataFormatClassNames
+ );
+ }
+
+ /**
+ * Gets the native metadata format name.
+ *
+ * @return the native metadata format name
+ */
+ public String getNativeMetadataFormatName() {
+ return nativeMetadataFormatName;
+ }
+
+ /**
+ * Checks if the standard metadata format is supported.
+ *
+ * @return true, if the standard metadata format is supported
+ */
+ public boolean isStandardMetadataFormatSupported() {
+ return standardFormatSupported;
+ }
+
+ /**
+ * Gets the metadata format names.
+ *
+ * @return the metadata format names
+ */
+ public String[] getMetadataFormatNames() {
+ ArrayList<String> res = new ArrayList<String>();
+
+ String nativeMetadataFormatName = getNativeMetadataFormatName();
+ boolean standardFormatSupported = isStandardMetadataFormatSupported();
+ String extraMetadataFormatNames[] = getExtraMetadataFormatNames();
+
+ if (standardFormatSupported) {
+ res.add(IIOMetadataFormatImpl.standardMetadataFormatName);
+ }
+ if (nativeMetadataFormatName != null) {
+ res.add(nativeMetadataFormatName);
+ }
+ if (extraMetadataFormatNames != null) {
+ for (String extraMetadataFormatName : extraMetadataFormatNames) {
+ res.add(extraMetadataFormatName);
+ }
+ }
+
+ return res.size() > 0 ? res.toArray(new String[0]) : null;
+ }
+
+ /**
+ * Gets the standard chroma node.
+ *
+ * @return the standard chroma node
+ */
+ protected IIOMetadataNode getStandardChromaNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard compression node.
+ *
+ * @return the standard compression node
+ */
+ protected IIOMetadataNode getStandardCompressionNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard data node.
+ *
+ * @return the standard data node
+ */
+ protected IIOMetadataNode getStandardDataNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard dimension node.
+ *
+ * @return the standard dimension node
+ */
+ protected IIOMetadataNode getStandardDimensionNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard document node.
+ *
+ * @return the standard document node
+ */
+ protected IIOMetadataNode getStandardDocumentNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard text node.
+ *
+ * @return the standard text node
+ */
+ protected IIOMetadataNode getStandardTextNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard tile node.
+ *
+ * @return the standard tile node
+ */
+ protected IIOMetadataNode getStandardTileNode() {
+ return null;
+ }
+
+ /**
+ * Gets the standard transparency node.
+ *
+ * @return the standard transparency node
+ */
+ protected IIOMetadataNode getStandardTransparencyNode() {
+ return null;
+ }
+
+ /**
+ * Gets the metadata as a tree in standard format.
+ *
+ * @return the metadata as a tree in standard format
+ */
+ protected final IIOMetadataNode getStandardTree() {
+ // Create root node
+ IIOMetadataNode root = new IIOMetadataNode(IIOMetadataFormatImpl.standardMetadataFormatName);
+
+ Node node;
+ if ((node = getStandardChromaNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardCompressionNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardDataNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardDimensionNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardDocumentNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardTextNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardTileNode()) != null) {
+ root.appendChild(node);
+ }
+ if ((node = getStandardTransparencyNode()) != null) {
+ root.appendChild(node);
+ }
+
+ return root;
+ }
+
+ /**
+ * Sets the controller.
+ *
+ * @param controller the new controller
+ */
+ public void setController(IIOMetadataController controller) {
+ this.controller = controller;
+ }
+
+ /**
+ * Sets the from tree.
+ *
+ * @param formatName the name of the metatdata format of the from tree
+ * @param root the root node of the from tree
+ *
+ * @throws IIOInvalidTreeException if the tree or its format is not compatible with
+ * this metadata.
+ */
+ public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException {
+ reset();
+ mergeTree(formatName, root);
+ }
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadataController.java b/awt/javax/imageio/metadata/IIOMetadataController.java
new file mode 100644
index 0000000..dfd4e5c
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataController.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.metadata;
+
+/*
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+
+/**
+ * The IIOMetadataController interface provides a method for
+ * implementing objects to activate the controller without
+ * defining how the controller obtains values.
+ */
+public interface IIOMetadataController {
+
+ /**
+ * Activates a controller.
+ *
+ * @param metadata the metadata to be modified.
+ *
+ * @return true if the IIOMetadata has been modified,
+ * false otherwise.
+ */
+ public boolean activate(IIOMetadata metadata);
+}
+
diff --git a/awt/javax/imageio/metadata/IIOMetadataFormat.java b/awt/javax/imageio/metadata/IIOMetadataFormat.java
new file mode 100644
index 0000000..9e246b4
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataFormat.java
@@ -0,0 +1,347 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.metadata;
+
+import javax.imageio.ImageTypeSpecifier;
+import java.util.Locale;
+
+/**
+ * The Interface IIOMetadataFormat is implemented by classes that
+ * describe the rules and allowed elements for a metadata document
+ * tree.
+ */
+public interface IIOMetadataFormat {
+
+ /** The CHILD_POLICY_EMPTY. */
+ int CHILD_POLICY_EMPTY = 0;
+
+ /** The CHILD_POLICY_ALL. */
+ int CHILD_POLICY_ALL = 1;
+
+ /** The CHILD_POLICY_SOME. */
+ int CHILD_POLICY_SOME = 2;
+
+ /** The CHILD_POLICY_CHOICE. */
+ int CHILD_POLICY_CHOICE = 3;
+
+ /** The CHILD_POLICY_SEQUENCE. */
+ int CHILD_POLICY_SEQUENCE = 4;
+
+ /** The CHILD_POLICY_REPEAT. */
+ int CHILD_POLICY_REPEAT = 5;
+
+ /** The maximum value for the child policy. */
+ int CHILD_POLICY_MAX = CHILD_POLICY_REPEAT;
+
+ /** The DATATYPE_STRING. */
+ int DATATYPE_STRING = 0;
+
+ /** The DATATYPE_BOOLEAN. */
+ int DATATYPE_BOOLEAN = 1;
+
+ /** The DATATYPE_INTEGER. */
+ int DATATYPE_INTEGER = 2;
+
+ /** The DATATYPE_FLOAT. */
+ int DATATYPE_FLOAT = 3;
+
+ /** The DATATYPE_DOUBLE. */
+ int DATATYPE_DOUBLE = 4;
+
+ /** The VALUE_NONE. */
+ int VALUE_NONE = 0;
+
+ /** The VALUE_ARBITRARY. */
+ int VALUE_ARBITRARY = 1;
+
+ /** The VALUE_RANGE. */
+ int VALUE_RANGE = 2;
+
+ /** The VALUE_RANGE_MIN_INCLUSIVE_MASK. */
+ int VALUE_RANGE_MIN_INCLUSIVE_MASK = 4;
+
+ /** The VALUE_RANGE_MAX_INCLUSIVE_MASK. */
+ int VALUE_RANGE_MAX_INCLUSIVE_MASK = 8;
+
+ /** The VALUE_ENUMERATION. */
+ int VALUE_ENUMERATION = 16;
+
+ /** The VALUE_LIST. */
+ int VALUE_LIST = 32;
+
+ /** The VALUE_RANGE_MIN_INCLUSIVE. */
+ int VALUE_RANGE_MIN_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK;
+
+ /** The VALUE_RANGE_MAX_INCLUSIVE. */
+ int VALUE_RANGE_MAX_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MAX_INCLUSIVE_MASK;
+
+ /** The VALUE_RANGE_MIN_MAX_INCLUSIVE. */
+ int VALUE_RANGE_MIN_MAX_INCLUSIVE =
+ VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK | VALUE_RANGE_MAX_INCLUSIVE_MASK;
+
+ /**
+ * Tells whether the specified element is allowed for the specified
+ * image type.
+ *
+ * @param elementName the element name
+ * @param imageType the image type
+ *
+ * @return true, if the specified element is allowed for the specified
+ * image type
+ */
+ boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType);
+
+ /**
+ * Gets data type of the specified attribute of the specified element.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the attribute's data type
+ */
+ int getAttributeDataType(String elementName, String attrName);
+
+ /**
+ * Gets the default value of the specified attribute of the specified element.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the attribute's default value
+ */
+ String getAttributeDefaultValue(String elementName, String attrName);
+
+ /**
+ * Gets the user-friendly description of the attribute.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ * @param locale the locale giving the desired language for the
+ * description
+ *
+ * @return the attribute description
+ */
+ String getAttributeDescription(String elementName, String attrName, Locale locale);
+
+ /**
+ * Gets the attribute enumerations.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the attribute enumerations
+ */
+ String[] getAttributeEnumerations(String elementName, String attrName);
+
+ /**
+ * Gets the maximum length of the attribute list.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the maximum length of the attribute list
+ */
+ int getAttributeListMaxLength(String elementName, String attrName);
+
+ /**
+ * Gets the minimum length of the attribute list.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the minimum length of the attribute list
+ */
+ int getAttributeListMinLength(String elementName, String attrName);
+
+ /**
+ * Gets the maximum value allowed for the attribute.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the maximum value allowed for the attribute
+ */
+ String getAttributeMaxValue(String elementName, String attrName);
+
+ /**
+ * Gets the minimum value allowed for the attribute.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the minimum value allowed for the attribute
+ */
+ String getAttributeMinValue(String elementName, String attrName);
+
+ /**
+ * Gets the attribute names allowed for the specified element.
+ *
+ * @param elementName the element name
+ *
+ * @return the attribute names
+ */
+ String[] getAttributeNames(String elementName);
+
+ /**
+ * Gets the attribute value type.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return the attribute value type
+ */
+ int getAttributeValueType(String elementName, String attrName);
+
+ /**
+ * Checks whether the specified attribute is required
+ * for the specified element.
+ *
+ * @param elementName the element name
+ * @param attrName the attribute name
+ *
+ * @return true, if the specified attribute is required for the
+ * specified element
+ */
+ boolean isAttributeRequired(String elementName, String attrName);
+
+ /**
+ * Gets the names of the possible child elements for the given element.
+ *
+ * @param elementName the element name
+ *
+ * @return the child names
+ */
+ String[] getChildNames(String elementName);
+
+ /**
+ * Gets the constant describing the element's child policy.
+ *
+ * @param elementName the element name
+ *
+ * @return the child policy
+ */
+ int getChildPolicy(String elementName);
+
+ /**
+ * Gets the user-friendly description of the element.
+ *
+ * @param elementName the element name
+ * @param locale the locale giving the desired language for the
+ * description
+ *
+ * @return the element description
+ */
+ String getElementDescription(String elementName, Locale locale);
+
+ /**
+ * Gets the maximum number of children allowed for the element.
+ *
+ * @param elementName the element name
+ *
+ * @return the maximum number of children allowed for the element
+ */
+ int getElementMaxChildren(String elementName);
+
+ /**
+ * Gets the minimum number of children allowed for the element.
+ *
+ * @param elementName the element name
+ *
+ * @return the minimum number of children allowed for the element
+ */
+ int getElementMinChildren(String elementName);
+
+ /**
+ * Gets the maximum object array length allowed for the element.
+ *
+ * @param elementName the element name
+ *
+ * @return the maximum object array length allowed for the element
+ */
+ int getObjectArrayMaxLength(String elementName);
+
+ /**
+ * Gets the minimum object array length allowed for the element.
+ *
+ * @param elementName the element name
+ *
+ * @return the minimum object array length allowed for the element
+ */
+ int getObjectArrayMinLength(String elementName);
+
+ /**
+ * Gets the object class corresponding to the specified element.
+ *
+ * @param elementName the element name
+ *
+ * @return the object class corresponding to the specified element
+ */
+ Class<?> getObjectClass(String elementName);
+
+ /**
+ * Gets the object default value for the element.
+ *
+ * @param elementName the element name
+ *
+ * @return the object default value for the element
+ */
+ Object getObjectDefaultValue(String elementName);
+
+ /**
+ * Gets the object enumerations.
+ *
+ * @param elementName the element name
+ *
+ * @return the object enumerations
+ */
+ Object[] getObjectEnumerations(String elementName);
+
+ /**
+ * Gets the maximum value allowed for the element's object.
+ *
+ * @param elementName the element name
+ *
+ * @return the maximum value allowed for the element's object
+ */
+ Comparable<?> getObjectMaxValue(String elementName);
+
+ /**
+ * Gets the minimum value allowed for the element's object.
+ *
+ * @param elementName the element name
+ *
+ * @return the minimum value allowed for the element's object
+ */
+ Comparable<?> getObjectMinValue(String elementName);
+
+ /**
+ * Gets the constant that indicates the type of the element's value.
+ *
+ * @param elementName the element name
+ *
+ * @return the constant that indicates the type of the element's value
+ */
+ int getObjectValueType(String elementName);
+
+ /**
+ * Gets the name of the root element.
+ *
+ * @return the name of the root element
+ */
+ String getRootName();
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java b/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java
new file mode 100644
index 0000000..438ae90
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java
@@ -0,0 +1,939 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.metadata;
+
+import javax.imageio.ImageTypeSpecifier;
+import java.util.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * The IIOMetadataFormatImpl class provides an implementation of the
+ * IIOMetadataFormat interface.
+ */
+public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat {
+
+ /** The Constant standardMetadataFormatName. */
+ @SuppressWarnings({"ConstantDeclaredInAbstractClass"})
+ public static final String standardMetadataFormatName = "javax_imageio_1.0";
+
+ /** The standard format. */
+ @SuppressWarnings({"StaticNonFinalField"})
+ private static IIOMetadataFormatImpl standardFormat;
+
+ /** The root name. */
+ private String rootName;
+
+ /** The element hash. */
+ private HashMap<String, Element> elementHash = new HashMap<String, Element>();
+
+ /** The resource base name. */
+ private String resourceBaseName = getClass().getName() + "Resources";
+
+ /**
+ * Instantiates an IIOMetadataFormatImpl with the specified root
+ * name and child policy (not CHILD_POLICY_REPEAT).
+ *
+ * @param rootName the name of root element.
+ * @param childPolicy the child policy defined by one of the
+ * CHILD_POLICY_* constants (except CHILD_POLICY_REPEAT).
+ */
+ public IIOMetadataFormatImpl(String rootName, int childPolicy) {
+ if (rootName == null) {
+ throw new IllegalArgumentException("rootName is null");
+ }
+ if (
+ childPolicy < CHILD_POLICY_EMPTY ||
+ childPolicy > CHILD_POLICY_MAX ||
+ childPolicy == CHILD_POLICY_REPEAT
+ ) {
+ throw new IllegalArgumentException("childPolicy is not one of the predefined constants");
+ }
+
+ this.rootName = rootName;
+ Element root = new Element();
+ root.name = rootName;
+ root.childPolicy = childPolicy;
+ elementHash.put(rootName, root);
+ }
+
+ /**
+ * Instantiates an IIOMetadataFormatImpl with the specified root
+ * name and CHILD_POLICY_REPEAT child policy.
+ *
+ * @param rootName the name of root element.
+ * @param minChildren the minimum number of children.
+ * @param maxChildren the maximum number of children
+ */
+ public IIOMetadataFormatImpl(String rootName, int minChildren, int maxChildren) {
+ if (rootName == null) {
+ throw new IllegalArgumentException("rootName is null");
+ }
+ if (minChildren < 0) {
+ throw new IllegalArgumentException("minChildren < 0!");
+ }
+ if (minChildren > maxChildren) {
+ throw new IllegalArgumentException("minChildren > maxChildren!");
+ }
+
+ this.rootName = rootName;
+ Element root = new Element();
+ root.name = rootName;
+ root.minChildren = minChildren;
+ root.maxChildren = maxChildren;
+ root.childPolicy = CHILD_POLICY_REPEAT;
+ elementHash.put(rootName, root);
+ }
+
+ @SuppressWarnings({"AbstractMethodOverridesAbstractMethod"})
+ public abstract boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType);
+
+ /**
+ * Adds a new attribute to an existing element.
+ *
+ * @param elementName the name of the element to which the new attribute
+ * will be added.
+ * @param attrName the attribute name.
+ * @param dataType the data type of the new attribute.
+ * @param required the flag which indicates whether this attribute
+ * must be present.
+ * @param listMinLength the minimum legal number of list items.
+ * @param listMaxLength the the maximum legal number of list items.
+ */
+ protected void addAttribute(
+ String elementName, String attrName, int dataType,
+ boolean required, int listMinLength, int listMaxLength
+ ) {
+ if (attrName == null) {
+ throw new IllegalArgumentException("attrName == null!");
+ }
+ if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+ throw new IllegalArgumentException("Invalid value for dataType!");
+ }
+ if (listMinLength < 0 || listMinLength > listMaxLength) {
+ throw new IllegalArgumentException("Invalid list bounds!");
+ }
+
+ Element element = findElement(elementName);
+ Attlist attr = new Attlist();
+ attr.name = attrName;
+ attr.dataType = dataType;
+ attr.required = required;
+ attr.listMinLength = listMinLength;
+ attr.listMaxLength = listMaxLength;
+ attr.valueType = VALUE_LIST;
+
+ element.attributes.put(attrName, attr);
+ }
+
+ /**
+ * Adds a new attribute to an existing element.
+ *
+ * @param elementName the name of the element to which the new attribute
+ * will be added.
+ * @param attrName the attribute name.
+ * @param dataType the data type of the new attribute.
+ * @param required the flag which indicates whether this attribute
+ * must be present.
+ * @param defaultValue the default value of the attribute.
+ */
+ protected void addAttribute(
+ String elementName, String attrName, int dataType,
+ boolean required, String defaultValue
+ ) {
+ if (attrName == null) {
+ throw new IllegalArgumentException("attrName == null!");
+ }
+ if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+ throw new IllegalArgumentException("Invalid value for dataType!");
+ }
+
+ Element element = findElement(elementName);
+ Attlist attr = new Attlist();
+ attr.name = attrName;
+ attr.dataType = dataType;
+ attr.required = required;
+ attr.defaultValue = defaultValue;
+ attr.valueType = VALUE_ARBITRARY;
+
+ element.attributes.put(attrName, attr);
+ }
+
+ /**
+ * Adds a new attribute to an existing element.
+ *
+ * @param elementName the name of the element to which the new attribute
+ * will be added.
+ * @param attrName the attribute name.
+ * @param dataType the data type of the new attribute.
+ * @param required the flag which indicates whether this attribute
+ * must be present.
+ * @param defaultValue the default value of the attribute.
+ * @param enumeratedValues the legal values for the attribute as
+ * a list of strings.
+ */
+ protected void addAttribute(
+ String elementName, String attrName, int dataType,
+ boolean required, String defaultValue, List<String> enumeratedValues
+ ) {
+ if (attrName == null) {
+ throw new IllegalArgumentException("attrName == null!");
+ }
+ if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+ throw new IllegalArgumentException("Invalid value for dataType!");
+ }
+ if (enumeratedValues == null || enumeratedValues.isEmpty()) {
+ throw new IllegalArgumentException("enumeratedValues is empty or null");
+ }
+
+ try {
+ for (String enumeratedValue : enumeratedValues) {
+ if (enumeratedValue == null) {
+ throw new IllegalArgumentException("enumeratedValues contains a null!");
+ }
+ }
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("enumeratedValues contains a non-String value!");
+ }
+
+ Element element = findElement(elementName);
+ Attlist attr = new Attlist();
+ attr.name = attrName;
+ attr.dataType = dataType;
+ attr.required = required;
+ attr.defaultValue = defaultValue;
+ attr.enumeratedValues = enumeratedValues;
+ attr.valueType = VALUE_ENUMERATION;
+
+ element.attributes.put(attrName, attr);
+ }
+
+ /**
+ * Adds a new attribute to an existing element.
+ *
+ * @param elementName the name of the element to which the new attribute
+ * will be added.
+ * @param attrName the attribute name.
+ * @param dataType the data type of the new attribute.
+ * @param required the flag which indicates whether this attribute
+ * must be present.
+ * @param defaultValue the default value of attribute.
+ * @param minValue the minimum legal value of an attribute.
+ * @param maxValue the maximum legal value of an attribute.
+ * @param minInclusive the flag which indicates
+ * whether the minValue is inclusive.
+ * @param maxInclusive the flag which indicates
+ * whether the maxValue is inclusive.
+ */
+ protected void addAttribute(
+ String elementName, String attrName, int dataType,
+ boolean required, String defaultValue,
+ String minValue, String maxValue,
+ boolean minInclusive, boolean maxInclusive
+ ) {
+ if (attrName == null) {
+ throw new IllegalArgumentException("attrName == null!");
+ }
+ if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) {
+ throw new IllegalArgumentException("Invalid value for dataType!");
+ }
+
+ Element element = findElement(elementName);
+ Attlist attr = new Attlist();
+ attr.name = attrName;
+ attr.dataType = dataType;
+ attr.required = required;
+ attr.defaultValue = defaultValue;
+ attr.minValue = minValue;
+ attr.maxValue = maxValue;
+ attr.minInclusive = minInclusive;
+ attr.maxInclusive = maxInclusive;
+
+ attr.valueType = VALUE_RANGE;
+ attr.valueType |= minInclusive ? VALUE_RANGE_MIN_INCLUSIVE_MASK : 0;
+ attr.valueType |= maxInclusive ? VALUE_RANGE_MAX_INCLUSIVE_MASK : 0;
+
+ element.attributes.put(attrName, attr);
+ }
+
+ /**
+ * Adds a new attribute with boolean data type to an existing
+ * element.
+ *
+ * @param elementName the name of the element to which the new attribute
+ * will be added.
+ * @param attrName the attribute name.
+ * @param hasDefaultValue the flag which indicates whether this attribute
+ * must have a default value.
+ * @param defaultValue the default value.
+ */
+ protected void addBooleanAttribute(
+ String elementName, String attrName,
+ boolean hasDefaultValue, boolean defaultValue
+ ) {
+ String defaultVal = hasDefaultValue ? (defaultValue ? "TRUE" : "FALSE") : null;
+ ArrayList<String> values = new ArrayList<String>(2);
+ values.add("TRUE");
+ values.add("FALSE");
+
+ addAttribute(elementName, attrName, DATATYPE_BOOLEAN, true, defaultVal, values);
+ }
+
+ /**
+ * Adds an existing element to the list of child elements
+ * of the specified parent element.
+ *
+ * @param elementName the name of the element to be added.
+ * @param parentName the parent element name.
+ */
+ protected void addChildElement(String elementName, String parentName) {
+ Element parent = findElement(parentName);
+ Element element = findElement(elementName);
+ parent.children.add(element.name);
+ }
+
+ /**
+ * Adds a new element type to this IIOMetadataFormat with
+ * a child policy (if policy is not CHILD_POLICY_REPEAT).
+ *
+ * @param elementName the name of the element to be added.
+ * @param parentName the parent element name.
+ * @param childPolicy one of the CHILD_POLICY_* constants defined
+ * by IIOMetadataFormat.
+ */
+ protected void addElement(String elementName, String parentName, int childPolicy) {
+ if (
+ childPolicy < CHILD_POLICY_EMPTY ||
+ childPolicy > CHILD_POLICY_MAX ||
+ childPolicy == CHILD_POLICY_REPEAT
+ ) {
+ throw new IllegalArgumentException("childPolicy is not one of the predefined constants");
+ }
+
+ Element parent = findElement(parentName);
+ Element element = new Element();
+ element.name = elementName;
+ element.childPolicy = childPolicy;
+ elementHash.put(elementName, element);
+ parent.children.add(elementName);
+ }
+
+ /**
+ * Adds a new element type to this IIOMetadataFormat with
+ * CHILD_POLICY_REPEAT and the specified minimum and maximum
+ * number of child elements.
+ *
+ * @param elementName the element name to be added.
+ * @param parentName the parent element name.
+ * @param minChildren the minimum number of child elements.
+ * @param maxChildren the maximum number of child elements.
+ */
+ protected void addElement(
+ String elementName, String parentName,
+ int minChildren, int maxChildren
+ ) {
+ if (minChildren < 0) {
+ throw new IllegalArgumentException("minChildren < 0!");
+ }
+ if (minChildren > maxChildren) {
+ throw new IllegalArgumentException("minChildren > maxChildren!");
+ }
+
+ Element parent = findElement(parentName);
+ Element element = new Element();
+ element.name = elementName;
+ element.childPolicy = CHILD_POLICY_REPEAT;
+ element.minChildren = minChildren;
+ element.maxChildren = maxChildren;
+ elementHash.put(elementName, element);
+ parent.children.add(elementName);
+ }
+
+ /**
+ * Adds an Object reference with the specified class type to be
+ * stored as element's value.
+ *
+ * @param elementName the element name.
+ * @param classType the class indicates the legal types for
+ * the object's value.
+ * @param arrayMinLength the minimum legal length for the array.
+ * @param arrayMaxLength the maximum legal length for the array.
+ */
+ protected void addObjectValue(
+ String elementName, Class<?> classType,
+ int arrayMinLength, int arrayMaxLength
+ ) {
+ Element element = findElement(elementName);
+
+ ObjectValue objVal = new ObjectValue();
+ objVal.classType = classType;
+ objVal.arrayMaxLength = arrayMaxLength;
+ objVal.arrayMinLength = arrayMinLength;
+ objVal.valueType = VALUE_LIST;
+
+ element.objectValue = objVal;
+ }
+
+ /**
+ * Adds an Object reference with the specified class type to be
+ * stored as an element's value.
+ *
+ * @param elementName the element name.
+ * @param classType the class indicates the legal types for
+ * the object's value.
+ * @param required a flag indicated that this object value
+ * must be present.
+ * @param defaultValue the default value, or null.
+ */
+ protected <T> void addObjectValue(
+ String elementName, Class<T> classType,
+ boolean required, T defaultValue
+ ) {
+ // note: reqired is an unused parameter
+ Element element = findElement(elementName);
+
+ ObjectValue<T> objVal = new ObjectValue<T>();
+ objVal.classType = classType;
+ objVal.defaultValue = defaultValue;
+ objVal.valueType = VALUE_ARBITRARY;
+
+ element.objectValue = objVal;
+ }
+
+ /**
+ * Adds an Object reference with the specified class type to be
+ * stored as the element's value.
+ *
+ * @param elementName the element name.
+ * @param classType the class indicates the legal types for
+ * the object value.
+ * @param required a flag indicated that this object value
+ * must be present.
+ * @param defaultValue the default value, or null.
+ * @param enumeratedValues the list of legal values for the object.
+ */
+ protected <T> void addObjectValue(
+ String elementName, Class<T> classType,
+ boolean required, T defaultValue,
+ List<? extends T> enumeratedValues
+ ) {
+ // note: reqired is an unused parameter
+ if (enumeratedValues == null || enumeratedValues.isEmpty()) {
+ throw new IllegalArgumentException("enumeratedValues is empty or null");
+ }
+
+ try {
+ for (T enumeratedValue : enumeratedValues) {
+ if (enumeratedValue == null) {
+ throw new IllegalArgumentException("enumeratedValues contains a null!");
+ }
+ }
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("enumeratedValues contains a value not of class classType!");
+ }
+
+ Element element = findElement(elementName);
+
+ ObjectValue<T> objVal = new ObjectValue<T>();
+ objVal.classType = classType;
+ objVal.defaultValue = defaultValue;
+ objVal.enumeratedValues = enumeratedValues;
+ objVal.valueType = VALUE_ENUMERATION;
+
+ element.objectValue = objVal;
+ }
+
+ /**
+ * Adds an Object reference with the specified class type to be
+ * stored as the element's value.
+ *
+ * @param elementName the element name.
+ * @param classType the class indicates the legal types for
+ * the object value.
+ * @param defaultValue the default value, or null.
+ * @param minValue the minimum legal value for the object value.
+ * @param maxValue the maximum legal value for the object value.
+ * @param minInclusive the flag which indicates
+ * whether the minValue is inclusive.
+ * @param maxInclusive the flag which indicates
+ * whether the maxValue is inclusive.
+ */
+ protected <T extends Object & Comparable<? super T>> void addObjectValue(
+ String elementName, Class<T> classType,
+ T defaultValue, Comparable<? super T> minValue, Comparable<? super T> maxValue,
+ boolean minInclusive, boolean maxInclusive
+ ) {
+ Element element = findElement(elementName);
+
+ ObjectValue<T> objVal = new ObjectValue<T>();
+ objVal.classType = classType;
+ objVal.defaultValue = defaultValue;
+ objVal.minValue = minValue;
+ objVal.maxValue = maxValue;
+ objVal.minInclusive = minInclusive;
+ objVal.maxInclusive = maxInclusive;
+
+ objVal.valueType = VALUE_RANGE;
+ objVal.valueType |= minInclusive ? VALUE_RANGE_MIN_INCLUSIVE_MASK : 0;
+ objVal.valueType |= maxInclusive ? VALUE_RANGE_MAX_INCLUSIVE_MASK : 0;
+
+ element.objectValue = objVal;
+ }
+
+ public int getAttributeDataType(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ return attr.dataType;
+ }
+
+ public String getAttributeDefaultValue(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ return attr.defaultValue;
+ }
+
+ public String getAttributeDescription(String elementName, String attrName, Locale locale) {
+ findAttribute(elementName, attrName);
+ return getResourceString(elementName + "/" + attrName, locale);
+ }
+
+ public String[] getAttributeEnumerations(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ if (attr.valueType != VALUE_ENUMERATION) {
+ throw new IllegalArgumentException("Attribute is not an enumeration!");
+ }
+
+ return attr.enumeratedValues.toArray(new String[attr.enumeratedValues.size()]);
+ }
+
+ public int getAttributeListMaxLength(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ if (attr.valueType != VALUE_LIST) {
+ throw new IllegalArgumentException("Attribute is not a list!");
+ }
+ return attr.listMaxLength;
+ }
+
+ public int getAttributeListMinLength(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ if (attr.valueType != VALUE_LIST) {
+ throw new IllegalArgumentException("Attribute is not a list!");
+ }
+ return attr.listMinLength;
+ }
+
+ public String getAttributeMaxValue(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ if ((attr.valueType & VALUE_RANGE) == 0) {
+ throw new IllegalArgumentException("Attribute is not a range!");
+ }
+ return attr.maxValue;
+ }
+
+ public String getAttributeMinValue(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ if ((attr.valueType & VALUE_RANGE) == 0) {
+ throw new IllegalArgumentException("Attribute is not a range!");
+ }
+ return attr.minValue;
+ }
+
+ public String[] getAttributeNames(String elementName) {
+ Element element = findElement(elementName);
+ return element.attributes.keySet().toArray(new String[element.attributes.size()]);
+ }
+
+ public int getAttributeValueType(String elementName, String attrName) {
+ Attlist attr = findAttribute(elementName, attrName);
+ return attr.valueType;
+ }
+
+ public String[] getChildNames(String elementName) {
+ Element element = findElement(elementName);
+ if (element.childPolicy == CHILD_POLICY_EMPTY) { // Element cannot have children
+ return null;
+ }
+ return element.children.toArray(new String[element.children.size()]);
+ }
+
+ public int getChildPolicy(String elementName) {
+ Element element = findElement(elementName);
+ return element.childPolicy;
+ }
+
+ public String getElementDescription(String elementName, Locale locale) {
+ findElement(elementName); // Check if there is such element
+ return getResourceString(elementName, locale);
+ }
+
+ public int getElementMaxChildren(String elementName) {
+ Element element = findElement(elementName);
+ if (element.childPolicy != CHILD_POLICY_REPEAT) {
+ throw new IllegalArgumentException("Child policy is not CHILD_POLICY_REPEAT!");
+ }
+ return element.maxChildren;
+ }
+
+ public int getElementMinChildren(String elementName) {
+ Element element = findElement(elementName);
+ if (element.childPolicy != CHILD_POLICY_REPEAT) {
+ throw new IllegalArgumentException("Child policy is not CHILD_POLICY_REPEAT!");
+ }
+ return element.minChildren;
+ }
+
+ public int getObjectArrayMaxLength(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null || v.valueType != VALUE_LIST) {
+ throw new IllegalArgumentException("Not a list!");
+ }
+ return v.arrayMaxLength;
+ }
+
+ public int getObjectArrayMinLength(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null || v.valueType != VALUE_LIST) {
+ throw new IllegalArgumentException("Not a list!");
+ }
+ return v.arrayMinLength;
+ }
+
+ public Class<?> getObjectClass(String elementName) {
+ ObjectValue v = findObjectValue(elementName);
+ return v.classType;
+ }
+
+ public Object getObjectDefaultValue(String elementName) {
+ ObjectValue v = findObjectValue(elementName);
+ return v.defaultValue;
+ }
+
+ public Object[] getObjectEnumerations(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null || v.valueType != VALUE_ENUMERATION) {
+ throw new IllegalArgumentException("Not an enumeration!");
+ }
+ return v.enumeratedValues.toArray();
+ }
+
+ public Comparable<?> getObjectMaxValue(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null || (v.valueType & VALUE_RANGE) == 0) {
+ throw new IllegalArgumentException("Not a range!");
+ }
+ return v.maxValue;
+ }
+
+ public Comparable<?> getObjectMinValue(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null || (v.valueType & VALUE_RANGE) == 0) {
+ throw new IllegalArgumentException("Not a range!");
+ }
+ return v.minValue;
+ }
+
+ public int getObjectValueType(String elementName) {
+ Element element = findElement(elementName);
+ if (element.objectValue == null) {
+ return VALUE_NONE;
+ }
+ return element.objectValue.valueType;
+ }
+
+ /**
+ * Gets the resource base name for locating ResourceBundles.
+ *
+ * @return the current resource base name.
+ */
+ protected String getResourceBaseName() {
+ return resourceBaseName;
+ }
+
+ public String getRootName() {
+ return rootName;
+ }
+
+ /**
+ * Gets the standard format instance.
+ *
+ * @return the IIOMetadataFormat instance.
+ */
+ public static IIOMetadataFormat getStandardFormatInstance() {
+ if (standardFormat == null) {
+ standardFormat = new IIOStandardMetadataFormat();
+ }
+
+ return standardFormat;
+ }
+
+ public boolean isAttributeRequired(String elementName, String attrName) {
+ return findAttribute(elementName, attrName).required;
+ }
+
+ /**
+ * Removes the specified attribute from the specified element.
+ *
+ * @param elementName the specified element name.
+ * @param attrName the specified attribute name.
+ */
+ protected void removeAttribute(String elementName, String attrName) {
+ Element element = findElement(elementName);
+ element.attributes.remove(attrName);
+ }
+
+ /**
+ * Removes the specified element from this format.
+ *
+ * @param elementName the specified element name.
+ */
+ protected void removeElement(String elementName) {
+ Element element;
+ if ((element = elementHash.get(elementName)) != null) {
+ elementHash.remove(elementName);
+ for (Element e : elementHash.values()) {
+ e.children.remove(element.name);
+ }
+ }
+ }
+
+ /**
+ * Removes the object value from the specified element.
+ *
+ * @param elementName the element name.
+ */
+ protected void removeObjectValue(String elementName) {
+ Element element = findElement(elementName);
+ element.objectValue = null;
+ }
+
+ /**
+ * Sets a new base name for ResourceBundles containing
+ * descriptions of elements and attributes for this format.
+ *
+ * @param resourceBaseName the new resource base name.
+ */
+ protected void setResourceBaseName(String resourceBaseName) {
+ if (resourceBaseName == null) {
+ throw new IllegalArgumentException("resourceBaseName == null!");
+ }
+ this.resourceBaseName = resourceBaseName;
+ }
+
+ /**
+ * The Class Element.
+ */
+ @SuppressWarnings({"ClassWithoutConstructor"})
+ private class Element {
+
+ /** The name. */
+ String name;
+
+ /** The children. */
+ ArrayList<String> children = new ArrayList<String>();
+
+ /** The attributes. */
+ HashMap<String, Attlist> attributes = new HashMap<String, Attlist>();
+
+ /** The min children. */
+ int minChildren;
+
+ /** The max children. */
+ int maxChildren;
+
+ /** The child policy. */
+ int childPolicy;
+
+ /** The object value. */
+ ObjectValue objectValue;
+ }
+
+ /**
+ * The Class Attlist.
+ */
+ @SuppressWarnings({"ClassWithoutConstructor"})
+ private class Attlist {
+
+ /** The name. */
+ String name;
+
+ /** The data type. */
+ int dataType;
+
+ /** The required. */
+ boolean required;
+
+ /** The list min length. */
+ int listMinLength;
+
+ /** The list max length. */
+ int listMaxLength;
+
+ /** The default value. */
+ String defaultValue;
+
+ /** The enumerated values. */
+ List<String> enumeratedValues;
+
+ /** The min value. */
+ String minValue;
+
+ /** The max value. */
+ String maxValue;
+
+ /** The min inclusive. */
+ boolean minInclusive;
+
+ /** The max inclusive. */
+ boolean maxInclusive;
+
+ /** The value type. */
+ int valueType;
+ }
+
+ /**
+ * The Class ObjectValue.
+ */
+ @SuppressWarnings({"ClassWithoutConstructor"})
+ private class ObjectValue<T> {
+
+ /** The class type. */
+ Class<T> classType;
+
+ /** The array min length. */
+ int arrayMinLength;
+
+ /** The array max length. */
+ int arrayMaxLength;
+
+ /** The default value. */
+ T defaultValue;
+
+ /** The enumerated values. */
+ List<? extends T> enumeratedValues;
+
+ /** The min value. */
+ Comparable<? super T> minValue;
+
+ /** The max value. */
+ Comparable<? super T> maxValue;
+
+ /** The min inclusive. */
+ boolean minInclusive;
+
+ /** The max inclusive. */
+ boolean maxInclusive;
+
+ /** The value type. */
+ int valueType;
+ }
+
+ /**
+ * Find element.
+ *
+ * @param name the name
+ *
+ * @return the element
+ */
+ private Element findElement(String name) {
+ Element element;
+ if ((element = elementHash.get(name)) == null) {
+ throw new IllegalArgumentException("element name is null or no such element: " + name);
+ }
+
+ return element;
+ }
+
+ /**
+ * Find attribute.
+ *
+ * @param elementName the element name
+ * @param attributeName the attribute name
+ *
+ * @return the attlist
+ */
+ private Attlist findAttribute(String elementName, String attributeName) {
+ Element element = findElement(elementName);
+ Attlist attribute;
+ if ((attribute = element.attributes.get(attributeName)) == null) {
+ throw new IllegalArgumentException("attribute name is null or no such attribute: " + attributeName);
+ }
+
+ return attribute;
+ }
+
+ /**
+ * Find object value.
+ *
+ * @param elementName the element name
+ *
+ * @return the object value
+ */
+ private ObjectValue findObjectValue(String elementName) {
+ Element element = findElement(elementName);
+ ObjectValue v = element.objectValue;
+ if (v == null) {
+ throw new IllegalArgumentException("No object within element");
+ }
+ return v;
+ }
+
+ /**
+ * Gets the resource string.
+ *
+ * @param key the key
+ * @param locale the locale
+ *
+ * @return the resource string
+ */
+ private String getResourceString(String key, Locale locale) {
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+
+ // Get the context class loader and try to locate the bundle with it first
+ ClassLoader contextClassloader = AccessController.doPrivileged(
+ new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+
+ // Now try to get the resource bundle
+ ResourceBundle rb;
+ try {
+ rb = ResourceBundle.getBundle(resourceBaseName, locale, contextClassloader);
+ } catch (MissingResourceException e) {
+ try {
+ rb = ResourceBundle.getBundle(resourceBaseName, locale);
+ } catch (MissingResourceException e1) {
+ return null;
+ }
+ }
+
+ try {
+ return rb.getString(key);
+ } catch (MissingResourceException e) {
+ return null;
+ } catch (ClassCastException e) {
+ return null; // Not a string resource
+ }
+ }
+}
diff --git a/awt/javax/imageio/metadata/IIOMetadataNode.java b/awt/javax/imageio/metadata/IIOMetadataNode.java
new file mode 100644
index 0000000..d5ab7a5
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOMetadataNode.java
@@ -0,0 +1,675 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+//???AWT
+//import org.w3c.dom.TypeInfo;
+//import org.w3c.dom.UserDataHandler;
+
+/**
+ * The Class IIOMetadataNode represents a node of the
+ * (DOM-style) metadata tree.
+ */
+public class IIOMetadataNode implements Element, NodeList {
+
+ /** The node name. */
+ private String nodeName;
+
+ /** The node value. */
+ private String nodeValue;
+
+ /** The attributes. */
+ private IIOMetadataNodeList attrs = new IIOMetadataNodeList(new ArrayList<IIOMetadataNode>());
+
+ /** The parent node. */
+ private IIOMetadataNode parent;
+
+ /** The first child node. */
+ private IIOMetadataNode firstChild;
+
+ /** The last child node. */
+ private IIOMetadataNode lastChild;
+
+ /** The previous sibling. */
+ private IIOMetadataNode previousSibling;
+
+ /** The next sibling. */
+ private IIOMetadataNode nextSibling;
+
+ /** The number of children. */
+ private int nChildren;
+
+ /** The user object associated with this node. */
+ private Object userObject;
+
+ /** The text content of this node. */
+ private String textContent;
+
+ /**
+ * Instantiates a new empty node.
+ */
+ public IIOMetadataNode() {
+ }
+
+ /**
+ * Instantiates a new empty node with the specified name.
+ *
+ * @param nodeName the node name
+ */
+ public IIOMetadataNode(String nodeName) {
+ this.nodeName = nodeName;
+ }
+
+ /**
+ * Instantiates a new IIOMetadataNode with the specified
+ * name and value.
+ *
+ * @param nodeName the node name
+ * @param nodeValue the node value
+ */
+ private IIOMetadataNode(String nodeName, String nodeValue) {
+ this.nodeName = nodeName;
+ this.nodeValue = nodeValue;
+ }
+
+ public String getTagName() {
+ return nodeName;
+ }
+
+ public String getAttribute(String name) {
+ Attr attrNode = (Attr) attrs.getNamedItem(name);
+ return (attrNode == null) ? "" : attrNode.getValue();
+ }
+
+ public void setAttribute(String name, String value) throws DOMException {
+ Attr attr = (Attr) attrs.getNamedItem(name);
+ if (attr != null) {
+ attr.setValue(value);
+ } else {
+ attrs.list.add(new IIOMetadataAttr(name, value, this));
+ }
+ }
+
+ public void removeAttribute(String name) throws DOMException {
+ IIOMetadataAttr attr = (IIOMetadataAttr) attrs.getNamedItem(name);
+ if (attr != null) {
+ attr.setOwnerElement(null);
+ attrs.list.remove(attr);
+ }
+ }
+
+ public Attr getAttributeNode(String name) {
+ return (Attr) attrs.getNamedItem(name);
+ }
+
+ public Attr setAttributeNode(Attr newAttr) throws DOMException {
+ // Check if this attribute is already in use.
+ Element owner = newAttr.getOwnerElement();
+ if (owner != null) {
+ if (owner == this) { // Replacing an attribute node by itself has no effect
+ return null;
+ } else {
+ throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, "Attribute is already in use");
+ }
+ }
+
+ String name = newAttr.getName();
+ Attr oldAttr = getAttributeNode(name);
+ if (oldAttr != null) {
+ removeAttributeNode(oldAttr);
+ }
+
+ IIOMetadataAttr iioAttr;
+ if (newAttr instanceof IIOMetadataAttr) {
+ iioAttr = (IIOMetadataAttr) newAttr;
+ iioAttr.setOwnerElement(this);
+ } else {
+ iioAttr = new IIOMetadataAttr(name, newAttr.getValue(), this);
+ }
+
+ attrs.list.add(iioAttr);
+
+ return oldAttr;
+ }
+
+ public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
+ if (!attrs.list.remove(oldAttr)) { // Not found
+ throw new DOMException(DOMException.NOT_FOUND_ERR, "No such attribute!");
+ }
+
+ ((IIOMetadataAttr)oldAttr).setOwnerElement(null);
+
+ return oldAttr;
+ }
+
+ public NodeList getElementsByTagName(String name) {
+ ArrayList<IIOMetadataNode> nodes = new ArrayList<IIOMetadataNode>();
+
+ // Non-recursive tree walk
+ Node pos = this;
+
+ while (pos != null) {
+ if (pos.getNodeName().equals(name)) {
+ nodes.add((IIOMetadataNode)pos);
+ }
+
+ Node nextNode = pos.getFirstChild();
+
+ while (nextNode == null) {
+ if (pos == this) {
+ break;
+ }
+
+ nextNode = pos.getNextSibling();
+
+ if (nextNode == null) {
+ pos = pos.getParentNode();
+
+ if (pos == null || pos == this) {
+ nextNode = null;
+ break;
+ }
+ }
+ }
+ pos = nextNode;
+ }
+
+ return new IIOMetadataNodeList(nodes);
+ }
+
+ public String getAttributeNS(String namespaceURI, String localName) throws DOMException {
+ return getAttribute(localName);
+ }
+
+ public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException {
+ setAttribute(qualifiedName, value);
+ }
+
+ public void removeAttributeNS(String namespaceURI, String localName) throws DOMException {
+ removeAttribute(localName);
+ }
+
+ public Attr getAttributeNodeNS(String namespaceURI, String localName) throws DOMException {
+ return getAttributeNode(localName);
+ }
+
+ public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
+ return setAttributeNode(newAttr);
+ }
+
+ public NodeList getElementsByTagNameNS(String namespaceURI, String localName) throws DOMException {
+ return getElementsByTagName(localName);
+ }
+
+ public boolean hasAttribute(String name) {
+ return attrs.getNamedItem(name) != null;
+ }
+
+ public boolean hasAttributeNS(String namespaceURI, String localName) throws DOMException {
+ return hasAttribute(localName);
+ }
+
+ //???AWT
+ /*
+ public TypeInfo getSchemaTypeInfo() {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }*/
+
+ public void setIdAttribute(String name, boolean isId) throws DOMException {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public String getNodeName() {
+ return nodeName;
+ }
+
+ public String getNodeValue() throws DOMException {
+ return nodeValue;
+ }
+
+ public void setNodeValue(String nodeValue) throws DOMException {
+ this.nodeValue = nodeValue;
+ }
+
+ public short getNodeType() {
+ return ELEMENT_NODE;
+ }
+
+ public Node getParentNode() {
+ return parent;
+ }
+
+ public NodeList getChildNodes() {
+ return this;
+ }
+
+ public Node getFirstChild() {
+ return firstChild;
+ }
+
+ public Node getLastChild() {
+ return lastChild;
+ }
+
+ public Node getPreviousSibling() {
+ return previousSibling;
+ }
+
+ public Node getNextSibling() {
+ return nextSibling;
+ }
+
+ public NamedNodeMap getAttributes() {
+ return attrs;
+ }
+
+ public Document getOwnerDocument() {
+ return null;
+ }
+
+ public Node insertBefore(Node newChild, Node refChild) throws DOMException {
+ if (newChild == null) {
+ throw new IllegalArgumentException("newChild == null!");
+ }
+
+ IIOMetadataNode newIIOChild = (IIOMetadataNode) newChild;
+ IIOMetadataNode refIIOChild = (IIOMetadataNode) refChild;
+
+ newIIOChild.parent = this;
+
+ if (refIIOChild == null) {
+ newIIOChild.nextSibling = null;
+ newIIOChild.previousSibling = lastChild;
+
+ // Fix this node
+ lastChild = newIIOChild;
+ if (firstChild == null) {
+ firstChild = newIIOChild;
+ }
+ } else {
+ newIIOChild.nextSibling = refIIOChild;
+ newIIOChild.previousSibling = refIIOChild.previousSibling;
+
+ // Fix this node
+ if (firstChild == refIIOChild) {
+ firstChild = newIIOChild;
+ }
+
+ // Fix next node
+ if (refIIOChild != null) {
+ refIIOChild.previousSibling = newIIOChild;
+ }
+ }
+
+ // Fix prev node
+ if (newIIOChild.previousSibling != null) {
+ newIIOChild.previousSibling.nextSibling = newIIOChild;
+ }
+
+ nChildren++;
+
+ return newIIOChild;
+ }
+
+ public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
+ if (newChild == null) {
+ throw new IllegalArgumentException("newChild == null!");
+ }
+
+ IIOMetadataNode newIIOChild = (IIOMetadataNode) newChild;
+ IIOMetadataNode oldIIOChild = (IIOMetadataNode) oldChild;
+
+ IIOMetadataNode next = oldIIOChild.nextSibling;
+ IIOMetadataNode previous = oldIIOChild.previousSibling;
+
+ // Fix new node
+ newIIOChild.parent = this;
+ newIIOChild.nextSibling = next;
+ newIIOChild.previousSibling = previous;
+
+ // Fix this node
+ if (lastChild == oldIIOChild) {
+ lastChild = newIIOChild;
+ }
+ if (firstChild == oldIIOChild) {
+ firstChild = newIIOChild;
+ }
+
+ // Fix siblings
+ if (next != null) {
+ next.previousSibling = newIIOChild;
+ }
+ if (previous != null) {
+ previous.nextSibling = newIIOChild;
+ }
+
+ // Fix old child
+ oldIIOChild.parent = null;
+ oldIIOChild.nextSibling = next;
+ oldIIOChild.previousSibling = previous;
+
+ return oldIIOChild;
+ }
+
+ public Node removeChild(Node oldChild) throws DOMException {
+ if (oldChild == null) {
+ throw new IllegalArgumentException("oldChild == null!");
+ }
+
+ IIOMetadataNode oldIIOChild = (IIOMetadataNode) oldChild;
+
+ // Fix next and previous
+ IIOMetadataNode previous = oldIIOChild.previousSibling;
+ IIOMetadataNode next = oldIIOChild.nextSibling;
+
+ if (previous != null) {
+ previous.nextSibling = next;
+ }
+ if (next != null) {
+ next.previousSibling = previous;
+ }
+
+ // Fix this node
+ if (lastChild == oldIIOChild) {
+ lastChild = previous;
+ }
+ if (firstChild == oldIIOChild) {
+ firstChild = next;
+ }
+ nChildren--;
+
+ // Fix old child
+ oldIIOChild.parent = null;
+ oldIIOChild.previousSibling = null;
+ oldIIOChild.nextSibling = null;
+
+ return oldIIOChild;
+ }
+
+ public Node appendChild(Node newChild) throws DOMException {
+ return insertBefore(newChild, null);
+ }
+
+ public boolean hasChildNodes() {
+ return nChildren != 0;
+ }
+
+ public Node cloneNode(boolean deep) {
+ IIOMetadataNode cloned = new IIOMetadataNode(nodeName);
+ cloned.setUserObject(getUserObject());
+
+ if (deep) { // Clone recursively
+ IIOMetadataNode c = firstChild;
+ while (c != null) {
+ cloned.insertBefore(c.cloneNode(true), null);
+ c = c.nextSibling;
+ }
+ }
+
+ return cloned; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void normalize() {
+ // Do nothing
+ }
+
+ public boolean isSupported(String feature, String version) {
+ return false;
+ }
+
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ public String getPrefix() {
+ return null;
+ }
+
+ public void setPrefix(String prefix) throws DOMException {
+ // Do nothing
+ }
+
+ public String getLocalName() {
+ return nodeName;
+ }
+
+ public boolean hasAttributes() {
+ return attrs.list.size() > 0;
+ }
+
+ public String getBaseURI() {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public short compareDocumentPosition(Node other) throws DOMException {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public String getTextContent() throws DOMException {
+ return textContent;
+ }
+
+ public void setTextContent(String textContent) throws DOMException {
+ this.textContent = textContent;
+ }
+
+ public boolean isSameNode(Node other) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public String lookupPrefix(String namespaceURI) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public boolean isDefaultNamespace(String namespaceURI) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public String lookupNamespaceURI(String prefix) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public boolean isEqualNode(Node arg) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public Object getFeature(String feature, String version) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ //???AWT
+ /*
+ public Object setUserData(String key, Object data, UserDataHandler handler) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }*/
+
+ public Object getUserData(String key) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ public Node item(int index) {
+ if (index < 0 || index >= nChildren) {
+ return null;
+ }
+
+ Node n;
+ for (n = getFirstChild(); index > 0; index--) {
+ n = n.getNextSibling();
+ }
+
+ return n;
+ }
+
+ public int getLength() {
+ return nChildren;
+ }
+
+ /**
+ * Gets the user object associated with this node.
+ *
+ * @return the user object associated with this node
+ */
+ public Object getUserObject() {
+ return userObject;
+ }
+
+ /**
+ * Sets the user object associated with this node.
+ *
+ * @param userObject the new user object associated with this node
+ */
+ public void setUserObject(Object userObject) {
+ this.userObject = userObject;
+ }
+
+ /**
+ * The Class IIOMetadataAttr.
+ */
+ private class IIOMetadataAttr extends IIOMetadataNode implements Attr {
+
+ /** The owner element. */
+ private Element ownerElement;
+
+ /**
+ * Instantiates a new iIO metadata attr.
+ *
+ * @param name the name
+ * @param value the value
+ * @param owner the owner
+ */
+ public IIOMetadataAttr(String name, String value, Element owner) {
+ super(name, value);
+ this.ownerElement = owner;
+ }
+
+ public String getName() {
+ return getNodeName();
+ }
+
+ public boolean getSpecified() {
+ return true;
+ }
+
+ public String getValue() {
+ return nodeValue;
+ }
+
+ public void setValue(String value) throws DOMException {
+ nodeValue = value;
+ }
+
+ public Element getOwnerElement() {
+ return ownerElement;
+ }
+
+ /**
+ * Sets the owner element.
+ *
+ * @param ownerElement the new owner element
+ */
+ public void setOwnerElement(Element ownerElement) {
+ this.ownerElement = ownerElement;
+ }
+
+ public boolean isId() {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
+ }
+
+ @Override
+ public short getNodeType() {
+ return ATTRIBUTE_NODE;
+ }
+ }
+
+ /**
+ * The Class IIOMetadataNodeList.
+ */
+ private class IIOMetadataNodeList implements NodeList, NamedNodeMap {
+
+ /** The list. */
+ private List<IIOMetadataNode> list;
+
+ /**
+ * Instantiates a new iIO metadata node list.
+ *
+ * @param list the list
+ */
+ IIOMetadataNodeList(List<IIOMetadataNode> list) {
+ this.list = list;
+ }
+
+ public Node item(int index) {
+ try {
+ return list.get(index);
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ }
+
+ public int getLength() {
+ return list.size();
+ }
+
+ public Node getNamedItem(String name) {
+ for(IIOMetadataNode node:list) {
+ if (name.equals(node.getNodeName())) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ public Node setNamedItem(Node arg) throws DOMException {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!");
+ }
+
+ public Node removeNamedItem(String name) throws DOMException {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!");
+ }
+
+ public Node getNamedItemNS(String namespaceURI, String localName) throws DOMException {
+ return getNamedItem(localName);
+ }
+
+ public Node setNamedItemNS(Node arg) throws DOMException {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!");
+ }
+
+ public Node removeNamedItemNS(String namespaceURI, String localName) throws DOMException {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!");
+ }
+ }
+}
diff --git a/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java b/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java
new file mode 100644
index 0000000..94d2125
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.metadata;
+
+import javax.imageio.ImageTypeSpecifier;
+import java.util.ArrayList;
+
+/**
+ * The Class IIOStandardMetadataFormat describes the rules of the
+ * standard metadata format.
+ */
+class IIOStandardMetadataFormat extends IIOMetadataFormatImpl {
+
+ /**
+ * Instantiates a new IIOStandardMetadataFormat.
+ */
+ public IIOStandardMetadataFormat() {
+ super(standardMetadataFormatName, CHILD_POLICY_SOME);
+ buildDTD();
+ }
+
+ @Override
+ public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) {
+ return true;
+ }
+
+ /**
+ * Builds the dtd that describes the standard metadata format.
+ */
+ private void buildDTD() {
+ // CHROMA
+ addElement("Chroma", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("ColorSpaceType", "Chroma", CHILD_POLICY_EMPTY);
+
+ ArrayList<String> values = new ArrayList<String>(27);
+ values.add("XYZ");
+ values.add("Lab");
+ values.add("Luv");
+ values.add("YCbCr");
+ values.add("Yxy");
+ values.add("YCCK");
+ values.add("PhotoYCC");
+ values.add("RGB");
+ values.add("GRAY");
+ values.add("HSV");
+ values.add("HLS");
+ values.add("CMYK");
+ values.add("CMY");
+ values.add("2CLR");
+ values.add("3CLR");
+ values.add("4CLR");
+ values.add("5CLR");
+ values.add("6CLR");
+ values.add("7CLR");
+ values.add("8CLR");
+ values.add("9CLR");
+ values.add("ACLR");
+ values.add("BCLR");
+ values.add("CCLR");
+ values.add("DCLR");
+ values.add("ECLR");
+ values.add("FCLR");
+ addAttribute("ColorSpaceType", "name", DATATYPE_STRING, true, null, values);
+
+ addElement("NumChannels", "Chroma", CHILD_POLICY_EMPTY);
+ addAttribute("NumChannels", "value", DATATYPE_INTEGER, true, 0, Integer.MAX_VALUE); // list - why?
+
+ addElement("Gamma", "Chroma", CHILD_POLICY_EMPTY);
+ addAttribute("Gamma", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("BlackIsZero", "Chroma", CHILD_POLICY_EMPTY);
+ addBooleanAttribute("BlackIsZero", "value", true, true);
+
+ addElement("Palette", "Chroma", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+ addElement("PaletteEntry", "Palette", CHILD_POLICY_EMPTY);
+ addAttribute("PaletteEntry", "index", DATATYPE_INTEGER, true, null);
+ addAttribute("PaletteEntry", "red", DATATYPE_INTEGER, true, null);
+ addAttribute("PaletteEntry", "green", DATATYPE_INTEGER, true, null);
+ addAttribute("PaletteEntry", "blue", DATATYPE_INTEGER, true, null);
+ addAttribute("PaletteEntry", "alpha", DATATYPE_INTEGER, false, "255");
+
+ addElement("BackgroundIndex", "Chroma", CHILD_POLICY_EMPTY);
+ addAttribute("BackgroundIndex", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("BackgroundColor", "Chroma", CHILD_POLICY_EMPTY);
+ addAttribute("BackgroundColor", "red", DATATYPE_INTEGER, true, null);
+ addAttribute("BackgroundColor", "green", DATATYPE_INTEGER, true, null);
+ addAttribute("BackgroundColor", "blue", DATATYPE_INTEGER, true, null);
+
+ // COMPRESSION
+ addElement("Compression", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("CompressionTypeName", "Compression", CHILD_POLICY_EMPTY);
+ addAttribute("CompressionTypeName", "value", DATATYPE_STRING, true, null);
+
+ addElement("Lossless", "Compression", CHILD_POLICY_EMPTY);
+ addBooleanAttribute("Lossless", "value", true, true);
+
+ addElement("NumProgressiveScans", "Compression", CHILD_POLICY_EMPTY);
+ addAttribute("NumProgressiveScans", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("BitRate", "Compression", CHILD_POLICY_EMPTY);
+ addAttribute("BitRate", "value", DATATYPE_FLOAT, true, null);
+
+ // DATA
+ addElement("Data", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("PlanarConfiguration", "Data", CHILD_POLICY_EMPTY);
+ values = new ArrayList<String>(4);
+ values.add("PixelInterleaved");
+ values.add("PlaneInterleaved");
+ values.add("LineInterleaved");
+ values.add("TileInterleaved");
+ addAttribute("PlanarConfiguration", "value", DATATYPE_STRING, true, null, values);
+
+ addElement("SampleFormat", "Data", CHILD_POLICY_EMPTY);
+ values = new ArrayList<String>(4);
+ values.add("SignedIntegral");
+ values.add("UnsignedIntegral");
+ values.add("Real");
+ values.add("Index");
+ addAttribute("SampleFormat", "value", DATATYPE_STRING, true, null, values);
+
+ addElement("BitsPerSample", "Data", CHILD_POLICY_EMPTY);
+ addAttribute("BitsPerSample", "value", DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE); // list
+
+ addElement("SignificantBitsPerSample", "Data", CHILD_POLICY_EMPTY);
+ addAttribute(
+ "SignificantBitsPerSample", "value",
+ DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE
+ ); // list
+
+ addElement("SampleMSB", "Data", CHILD_POLICY_EMPTY);
+ addAttribute("SampleMSB", "value", DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE); // list
+
+ // DIMENSION
+ addElement("Dimension", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("PixelAspectRatio", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("PixelAspectRatio", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("ImageOrientation", "Dimension", CHILD_POLICY_EMPTY);
+ values = new ArrayList<String>(8);
+ values.add("Normal");
+ values.add("Rotate90");
+ values.add("Rotate180");
+ values.add("Rotate270");
+ values.add("FlipH");
+ values.add("FlipV");
+ values.add("FlipHRotate90");
+ values.add("FlipVRotate90");
+ addAttribute("ImageOrientation", "value", DATATYPE_STRING, true, null, values);
+
+ addElement("HorizontalPixelSize", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("HorizontalPixelSize", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("VerticalPixelSize", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("VerticalPixelSize", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("HorizontalPhysicalPixelSpacing", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("HorizontalPhysicalPixelSpacing", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("VerticalPhysicalPixelSpacing", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("VerticalPhysicalPixelSpacing", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("HorizontalPosition", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("HorizontalPosition", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("VerticalPosition", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("VerticalPosition", "value", DATATYPE_FLOAT, true, null);
+
+ addElement("HorizontalPixelOffset", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("HorizontalPixelOffset", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("VerticalPixelOffset", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("VerticalPixelOffset", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("HorizontalScreenSize", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("HorizontalScreenSize", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("VerticalScreenSize", "Dimension", CHILD_POLICY_EMPTY);
+ addAttribute("VerticalScreenSize", "value", DATATYPE_INTEGER, true, null);
+
+ // DOCUMENT
+ addElement("Document", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("FormatVersion", "Document", CHILD_POLICY_EMPTY);
+ addAttribute("FormatVersion", "value", DATATYPE_STRING, true, null);
+
+ addElement("SubimageInterpretation", "Document", CHILD_POLICY_EMPTY);
+ values = new ArrayList<String>(14);
+ values.add("Standalone");
+ values.add("SinglePage");
+ values.add("FullResolution");
+ values.add("ReducedResolution");
+ values.add("PyramidLayer");
+ values.add("Preview");
+ values.add("VolumeSlice");
+ values.add("ObjectView");
+ values.add("Panorama");
+ values.add("AnimationFrame");
+ values.add("TransparencyMask");
+ values.add("CompositingLayer");
+ values.add("SpectralSlice");
+ values.add("Unknown");
+ addAttribute("SubimageInterpretation", "value", DATATYPE_STRING, true, null, values);
+
+ addElement("ImageCreationTime", "Document", CHILD_POLICY_EMPTY);
+ addAttribute("ImageCreationTime", "year", DATATYPE_INTEGER, true, null);
+ addAttribute(
+ "ImageCreationTime", "month",
+ DATATYPE_INTEGER, true, null, "1", "12", true, true
+ );
+ addAttribute(
+ "ImageCreationTime", "day",
+ DATATYPE_INTEGER, true, null, "1", "31", true, true
+ );
+ addAttribute(
+ "ImageCreationTime", "hour",
+ DATATYPE_INTEGER, false, "0", "0", "23", true, true
+ );
+ addAttribute(
+ "ImageCreationTime", "minute",
+ DATATYPE_INTEGER, false, "0", "0", "59", true, true
+ );
+ addAttribute(
+ "ImageCreationTime", "second",
+ DATATYPE_INTEGER, false, "0", "0", "60", true, true
+ );
+
+ addElement("ImageModificationTime", "Document", CHILD_POLICY_EMPTY);
+ addAttribute("ImageModificationTime", "year", DATATYPE_INTEGER, true, null);
+ addAttribute(
+ "ImageModificationTime", "month",
+ DATATYPE_INTEGER, true, null, "1", "12", true, true
+ );
+ addAttribute(
+ "ImageModificationTime", "day",
+ DATATYPE_INTEGER, true, null, "1", "31", true, true
+ );
+ addAttribute(
+ "ImageModificationTime", "hour",
+ DATATYPE_INTEGER, false, "0", "0", "23", true, true
+ );
+ addAttribute(
+ "ImageModificationTime", "minute",
+ DATATYPE_INTEGER, false, "0", "0", "59", true, true
+ );
+ addAttribute(
+ "ImageModificationTime", "second",
+ DATATYPE_INTEGER, false, "0", "0", "60", true, true
+ );
+
+ // TEXT
+ addElement("Text", standardMetadataFormatName, 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+
+ addElement("TextEntry", "Text", CHILD_POLICY_EMPTY);
+ addAttribute("TextEntry", "keyword", DATATYPE_STRING, false, null);
+ addAttribute("TextEntry", "value", DATATYPE_STRING, true, null);
+ addAttribute("TextEntry", "language", DATATYPE_STRING, false, null);
+ addAttribute("TextEntry", "encoding", DATATYPE_STRING, false, null);
+ values = new ArrayList<String>(5);
+ values.add("none");
+ values.add("lzw");
+ values.add("zip");
+ values.add("bzip");
+ values.add("other");
+ addAttribute("TextEntry", "compression", DATATYPE_STRING, false, "none", values);
+
+ // TRANSPARENCY
+ addElement("Transparency", standardMetadataFormatName, CHILD_POLICY_SOME);
+
+ addElement("Alpha", "Transparency", CHILD_POLICY_EMPTY);
+ values = new ArrayList<String>(3);
+ values.add("none");
+ values.add("premultiplied");
+ values.add("nonpremultiplied");
+ addAttribute("Alpha", "value", DATATYPE_STRING, false, "none", values);
+
+ addElement("TransparentIndex", "Transparency", CHILD_POLICY_EMPTY);
+ addAttribute("TransparentIndex", "value", DATATYPE_INTEGER, true, null);
+
+ addElement("TransparentColor", "Transparency", CHILD_POLICY_EMPTY);
+ addAttribute("TransparentColor", "value", DATATYPE_INTEGER, true, 0, Integer.MAX_VALUE);
+
+ addElement("TileTransparencies", "Transparency", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+
+ addElement("TransparentTile", "TileTransparencies", CHILD_POLICY_EMPTY);
+ addAttribute("TransparentTile", "x", DATATYPE_INTEGER, true, null);
+ addAttribute("TransparentTile", "y", DATATYPE_INTEGER, true, null);
+
+ addElement("TileOpacities", "Transparency", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT
+
+ addElement("OpaqueTile", "TileOpacities", CHILD_POLICY_EMPTY);
+ addAttribute("OpaqueTile", "x", DATATYPE_INTEGER, true, null);
+ addAttribute("OpaqueTile", "y", DATATYPE_INTEGER, true, null);
+ }
+}
+
diff --git a/awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties b/awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties
new file mode 100644
index 0000000..d185808
--- /dev/null
+++ b/awt/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties
@@ -0,0 +1,133 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Descriptions of elements and attributes of the plugin neutral metadata format
+# (see IIOStandardMetadataFormat)
+
+# Messages for EN locale
+Chroma=Chroma (color) information
+ColorSpaceType=The raw color space of the image
+ColorSpaceType/name=The raw color space of the image
+NumChannels=The number of channels in the raw image, including alpha
+NumChannels/value=The number of channels in the raw image, including alpha
+Gamma=The image gamma
+Gamma/value=The image gamma
+BlackIsZero=True if smaller values represent darker shades
+BlackIsZero/value=True if smaller values represent darker shades
+Palette=Palette-color information
+PaletteEntry=A palette entry
+PaletteEntry/index=The index of the palette entry
+PaletteEntry/red=The red value for the palette entry
+PaletteEntry/green=The green value for the palette entry
+PaletteEntry/blue=The blue value for the palette entry
+PaletteEntry/alpha=The alpha value for the palette entry
+BackgroundIndex=A palette index to be used as a background
+BackgroundIndex/value=A palette index to be used as a background
+BackgroundColor=An RGB triple to be used as a background
+BackgroundColor/red=The red background value
+BackgroundColor/green=The green background value
+BackgroundColor/blue=The blue background value
+
+Compression=Compression information
+CompressionTypeName=The name of the compression scheme in use
+CompressionTypeName/value=The name of the compression scheme in use
+Lossless=True if the compression scheme is lossless
+Lossless/value=True if the compression scheme is lossless
+NumProgressiveScans=The number of progressive scans used in the image encoding
+NumProgressiveScans/value=The number of progressive scans used in the image encoding
+BitRate=The estimated bit rate of the compression scheme
+BitRate/value=The estimated bit rate of the compression scheme
+
+Data=Information on the image layout
+PlanarConfiguration=The organization of image samples in the stream
+PlanarConfiguration/value=The organization of image samples in the stream
+SampleFormat=The numeric format of image samples
+SampleFormat/value=The numeric format of image samples
+BitsPerSample=The number of bits per sample
+BitsPerSample/value=A list of integers, one per channel
+SignificantBitsPerSample=The number of significant bits per sample
+SignificantBitsPerSample/value=A list of integers, one per channel
+SampleMSB=The position of the most significant bit of each sample
+SampleMSB/value=A list of integers, one per channel
+
+Dimension=Dimension information
+PixelAspectRatio=The width of a pixel divided by its height
+PixelAspectRatio/value=The width of a pixel divided by its height
+ImageOrientation=The desired orientation of the image in terms of flips and counter-clockwise rotations
+ImageOrientation/value=The desired orientation of the image in terms of flips and counter-clockwise rotations
+HorizontalPixelSize=The width of a pixel, in millimeters, as it should be rendered on media
+HorizontalPixelSize/value=The width of a pixel, in millimeters, as it should be rendered on media
+VerticalPixelSize=The height of a pixel, in millimeters, as it should be rendered on media
+VerticalPixelSize/value=The height of a pixel, in millimeters, as it should be rendered on media
+HorizontalPhysicalPixelSpacing=The horizontal distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+HorizontalPhysicalPixelSpacing/value=The horizontal distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+VerticalPhysicalPixelSpacing=The vertical distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+VerticalPhysicalPixelSpacing/value=The vertical distance in the subject of the image, in millimeters, represented by one pixel at the center of the image
+HorizontalPosition=The horizontal position, in millimeters, where the image should be rendered on media
+HorizontalPosition/value=The horizontal position, in millimeters, where the image should be rendered on media
+VerticalPosition=The vertical position, in millimeters, where the image should be rendered on media
+VerticalPosition/value=The vertical position, in millimeters, where the image should be rendered on media
+HorizontalPixelOffset=The horizonal position, in pixels, where the image should be rendered onto a raster display
+HorizontalPixelOffset/value=The horizonal position, in pixels, where the image should be rendered onto a raster display
+VerticalPixelOffset=The vertical position, in pixels, where the image should be rendered onto a raster display
+VerticalPixelOffset/value=The vertical position, in pixels, where the image should be rendered onto a raster display
+HorizontalScreenSize=The width, in pixels, of the raster display into which the image should be rendered
+HorizontalScreenSize/value=The width, in pixels, of the raster display into which the image should be rendered
+VerticalScreenSize=The height, in pixels, of the raster display into which the image should be rendered
+VerticalScreenSize/value=The height, in pixels, of the raster display into which the image should be rendered
+
+Document=Document information
+FormatVersion=The version of the format used by the stream
+FormatVersion/value=The version of the format used by the stream
+SubimageInterpretation=The interpretation of this image in relation to the other images stored in the same stream
+SubimageInterpretation/value=The interpretation of this image in relation to the other images stored in the same stream
+ImageCreationTime=The time of image creation
+ImageCreationTime/year=The full year (e.g., 1967, not 67)
+ImageCreationTime/month=The month, with January = 1
+ImageCreationTime/day=The day of the month
+ImageCreationTime/hour=The hour from 0 to 23
+ImageCreationTime/minute=The minute from 0 to 59
+ImageCreationTime/second=The second from 0 to 60 (60 = leap second)
+ImageModificationTime=The time of the last image modification
+ImageModificationTime/year=The full year (e.g., 1967, not 67)
+ImageModificationTime/month=The month, with January = 1
+ImageModificationTime/day=The day of the month
+ImageModificationTime/hour=The hour from 0 to 23
+ImageModificationTime/minute=The minute from 0 to 59
+ImageModificationTime/second=The second from 0 to 60 (60 = leap second)
+
+Text=Text information
+TextEntry=A text entry
+TextEntry/keyword=A keyword associated with the text entry
+TextEntry/value=the text entry
+TextEntry/language=The language of the text
+TextEntry/encoding=The encoding of the text
+TextEntry/compression=The method used to compress the text
+
+Transparency=Transparency information
+Alpha=The type of alpha information contained in the image
+Alpha/value=The type of alpha information contained in the image
+TransparentIndex=A palette index to be treated as transparent
+TransparentIndex/value=A palette index to be treated as transparent
+TransparentColor=An RGB color to be treated as transparent
+TransparentColor/value=An RGB color to be treated as transparent
+TileTransparencies=A list of completely transparent tiles
+TransparentTile=The index of a completely transparent tile
+TransparentTile/x=The tile's X index
+TransparentTile/y=The tile's Y index
+TileOpacities=A list of completely opaque tiles
+OpaqueTile=The index of a completely opaque tile
+OpaqueTile/x=The tile's X index
+OpaqueTile/y=The tile's Y index
diff --git a/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java b/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java
new file mode 100644
index 0000000..0cd44db
--- /dev/null
+++ b/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.plugins.bmp;
+
+import javax.imageio.ImageWriteParam;
+import java.util.Locale;
+
+/**
+ * The BMPImageWriteParam class allows encoding an image in
+ * BMP format.
+ */
+public class BMPImageWriteParam extends ImageWriteParam {
+
+ /** The top down. */
+ private boolean topDown; // Default is bottom-up
+
+ /**
+ * Instantiates a new BMPImageWriteParam with default values of all
+ * parameters.
+ */
+ public BMPImageWriteParam() {
+ this(null);
+ }
+
+ /**
+ * Instantiates a new BMPImageWriteParam with the specified Locale.
+ *
+ * @param locale the specified Locale.
+ */
+ public BMPImageWriteParam(Locale locale) {
+ super(locale);
+
+ // Set the compression
+ canWriteCompressed = true;
+ compressionTypes = new String[] {"BI_RGB", "BI_RLE8", "BI_RLE4", "BI_BITFIELDS"};
+ compressionType = compressionTypes[0];
+ }
+
+ /**
+ * Sets true if the data will be written in a top-down order,
+ * false otherwise.
+ *
+ * @param topDown the new top-down value.
+ */
+ public void setTopDown(boolean topDown) {
+ this.topDown = topDown;
+ }
+
+ /**
+ * Returns true if the data is written in top-down order, false
+ * otherwise.
+ *
+ * @return true if the data is written in top-down order, false
+ * otherwise.
+ */
+ public boolean isTopDown() {
+ return topDown;
+ }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java b/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java
new file mode 100644
index 0000000..398c960
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.plugins.jpeg;
+
+/**
+ * The JPEGHuffmanTable class represents a single JPEG Huffman table.
+ * It contains the standard tables from the JPEG specification.
+ */
+public class JPEGHuffmanTable {
+
+ /** The standard DC luminance Huffman table . */
+ public static final JPEGHuffmanTable StdDCLuminance = new JPEGHuffmanTable(
+ new short[] {0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0},
+ new short[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B},
+ false
+ );
+
+ /** The standard DC chrominance Huffman table. */
+ public static final JPEGHuffmanTable StdDCChrominance = new JPEGHuffmanTable(
+ new short[] {0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
+ new short[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B},
+ false
+ );
+
+ /** The standard AC luminance Huffman table. */
+ public static final JPEGHuffmanTable StdACLuminance = new JPEGHuffmanTable(
+ new short[] {0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7D},
+ new short[] {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
+ 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08,
+ 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72,
+ 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75,
+ 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3,
+ 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
+ 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
+ 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
+ 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4,
+ 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
+ },
+ false
+ );
+
+ /**
+ * The standard AC chrominance Huffman table. */
+ public static final JPEGHuffmanTable StdACChrominance = new JPEGHuffmanTable(
+ new short[] {0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77},
+ new short[] {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
+ 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1,
+ 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,
+ 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A,
+ 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4,
+ 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
+ 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4,
+ 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
+ },
+ false
+ );
+
+ /** The lengths. */
+ private short lengths[];
+
+ /** The values. */
+ private short values[];
+
+ /**
+ * Instantiates a new jPEG huffman table.
+ *
+ * @param lengths the lengths
+ * @param values the values
+ * @param copy the copy
+ */
+ JPEGHuffmanTable(short[] lengths, short[] values, boolean copy) {
+ // Construction of standard tables without checks
+ // The third param is dummy
+ // Could be also used for copying of the existing tables
+ this.lengths = lengths;
+ this.values = values;
+ }
+
+ /**
+ * Instantiates a new JPEGHuffmanTable.
+ *
+ * @param lengths the array of shorts lengths.
+ * @param values the array of shorts containing
+ * the values in order of increasing code length.
+ */
+ public JPEGHuffmanTable(short[] lengths, short[] values) {
+ if (lengths == null) {
+ throw new IllegalArgumentException("lengths array is null!");
+ }
+ if (values == null) {
+ throw new IllegalArgumentException("values array is null!");
+ }
+ if (lengths.length > 16) { // According to the spec
+ throw new IllegalArgumentException("lengths array is too long!");
+ }
+ if (values.length > 256) { // According to the spec
+ throw new IllegalArgumentException("values array is too long");
+ }
+ for (short length : lengths) {
+ if (length < 0) {
+ throw new IllegalArgumentException("Values in lengths array must be non-negative.");
+ }
+ }
+ for (short value : values) {
+ if (value < 0) {
+ throw new IllegalArgumentException("Values in values array must be non-negative.");
+ }
+ }
+
+ checkHuffmanTable(lengths, values);
+
+ this.lengths = new short[lengths.length];
+ this.values = new short[values.length];
+ System.arraycopy(lengths, 0, this.lengths, 0, lengths.length);
+ System.arraycopy(values, 0, this.values, 0, values.length);
+ }
+
+ /**
+ * Gets an array of lengths in the Huffman table.
+ *
+ * @return the array of short values representing the
+ * length values in the Huffman table.
+ */
+ public short[] getLengths() {
+ short newLengths[] = new short[lengths.length];
+ System.arraycopy(lengths, 0, newLengths, 0, lengths.length);
+ return newLengths;
+ }
+
+ /**
+ * Gets an array of values represented by increasing length of
+ * their codes.
+ *
+ * @return the array of values.
+ */
+ public short[] getValues() {
+ short newValues[] = new short[values.length];
+ System.arraycopy(values, 0, newValues, 0, values.length);
+ return newValues;
+ }
+
+ /**
+ * Check huffman table.
+ *
+ * @param lengths the lengths
+ * @param values the values
+ */
+ private static void checkHuffmanTable(short[] lengths, short[] values) {
+ int numLeaves = 0;
+ int possibleLeaves = 2;
+ for (short length : lengths) {
+ numLeaves += length;
+ possibleLeaves -= length;
+ if (possibleLeaves < 0) {
+ throw new IllegalArgumentException("Invalid Huffman table provided, lengths are incorrect.");
+ }
+ possibleLeaves <<= 1;
+ }
+
+ if (values.length != numLeaves) {
+ throw new IllegalArgumentException("Invalid Huffman table provided, sum of lengths != values.");
+ }
+ }
+
+ /**
+ * Returns the string representation of this JPEGHuffmanTable object.
+ *
+ * @return the string representation of this JPEGHuffmanTable object.
+ */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("JPEGHuffmanTable:\nlengths:");
+ for (short length : lengths) {
+ sb.append(' ').append(length);
+ }
+
+ sb.append("\nvalues:");
+ for (short value : values) {
+ sb.append(' ').append(value);
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java b/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java
new file mode 100644
index 0000000..dd08d51
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.plugins.jpeg;
+
+import javax.imageio.ImageReadParam;
+
+/**
+ * The JPEGImageReadParam class provides functionality to set Huffman tables
+ * and quantization tables when using the JPEG reader plug-in.
+ */
+public class JPEGImageReadParam extends ImageReadParam {
+
+ /** The q tables. */
+ private JPEGQTable qTables[];
+
+ /** The dc huffman tables. */
+ private JPEGHuffmanTable dcHuffmanTables[];
+
+ /** The ac huffman tables. */
+ private JPEGHuffmanTable acHuffmanTables[];
+
+ /**
+ * Instantiates a new JPEGImageReadParam.
+ */
+ public JPEGImageReadParam() {
+ }
+
+ /**
+ * Returns true if tables are set, false otherwise.
+ *
+ * @return true if tables are set, false otherwise.
+ */
+ public boolean areTablesSet() {
+ return qTables != null;
+ }
+
+ /**
+ * Sets the quantization and Huffman tables for using in
+ * decoding streams.
+ *
+ * @param qTables the quantization tables.
+ * @param DCHuffmanTables the standart DC Huffman tables.
+ * @param ACHuffmanTables the standart AC huffman tables.
+ */
+ public void setDecodeTables(
+ JPEGQTable[] qTables,
+ JPEGHuffmanTable[] DCHuffmanTables,
+ JPEGHuffmanTable[] ACHuffmanTables
+ ) {
+ if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+ if(DCHuffmanTables.length != ACHuffmanTables.length) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+ if (qTables.length > 4 || DCHuffmanTables.length > 4) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+
+ // Do the shallow copy, it should be enough
+ this.qTables = qTables.clone();
+ dcHuffmanTables = DCHuffmanTables.clone();
+ acHuffmanTables = ACHuffmanTables.clone();
+ }
+
+ /**
+ * Unset all decoded tables.
+ */
+ public void unsetDecodeTables() {
+ qTables = null;
+ dcHuffmanTables = null;
+ acHuffmanTables = null;
+ }
+
+ /**
+ * Gets the quantization tables.
+ *
+ * @return the quantization tables, or null.
+ */
+ public JPEGQTable[] getQTables() {
+ return qTables == null ? null : qTables.clone();
+ }
+
+ /**
+ * Gets the DC Huffman tables.
+ *
+ * @return the DC Huffman tables which are set, or null.
+ */
+ public JPEGHuffmanTable[] getDCHuffmanTables() {
+ return dcHuffmanTables == null ? null : dcHuffmanTables.clone();
+ }
+
+ /**
+ * Gets the AC Huffman tables.
+ *
+ * @return the AC Huffman tables which are set, or null.
+ */
+ public JPEGHuffmanTable[] getACHuffmanTables() {
+ return acHuffmanTables == null ? null : acHuffmanTables.clone();
+ }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java b/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java
new file mode 100644
index 0000000..34a3cd9
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.imageio.plugins.jpeg;
+
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGConsts;
+
+import javax.imageio.ImageWriteParam;
+import java.util.Locale;
+
+/**
+ * The JPEGImageWriteParam class allows to set JPEG Huffman tables
+ * and quantization when using the JPEG writer plug-in.
+ */
+public class JPEGImageWriteParam extends ImageWriteParam {
+
+ /** The Constant COMP_QUALITY_VALUES. */
+ private static final float[] COMP_QUALITY_VALUES = {0.05f, 0.75f, 0.95f};
+
+ /** The Constant COMP_QUALITY_DESCRIPTIONS. */
+ private static final String[] COMP_QUALITY_DESCRIPTIONS = {
+ "Minimum useful",
+ "Visually lossless",
+ "Maximum useful"
+ };
+
+ /** The q tables. */
+ private JPEGQTable[] qTables;
+
+ /** The dc huffman tables. */
+ private JPEGHuffmanTable[] dcHuffmanTables;
+
+ /** The ac huffman tables. */
+ private JPEGHuffmanTable[] acHuffmanTables;
+
+ /** The optimize huffman tables. */
+ private boolean optimizeHuffmanTables;
+
+ /**
+ * Instantiates a new JPEGImageWriteParam object with
+ * the specified Locale.
+ *
+ * @param locale the Locale.
+ */
+ public JPEGImageWriteParam(Locale locale) {
+ super(locale);
+
+ canWriteProgressive = true;
+ progressiveMode = ImageWriteParam.MODE_DISABLED;
+
+ canWriteCompressed = true;
+ compressionTypes = new String[]{"JPEG"};
+ compressionType = compressionTypes[0];
+ compressionQuality = JPEGConsts.DEFAULT_JPEG_COMPRESSION_QUALITY;
+ }
+
+ /**
+ * Returns true if tables are set, false otherwise.
+ *
+ * @return true if tables are set, false otherwise.
+ */
+ public boolean areTablesSet() {
+ return qTables != null;
+ }
+
+ /**
+ * Sets the quantization and Huffman tables for using in
+ * encoding streams.
+ *
+ * @param qTables the quantization tables.
+ * @param DCHuffmanTables the standart DC Huffman tables.
+ * @param ACHuffmanTables the standart AC huffman tables.
+ */
+ public void setEncodeTables(
+ JPEGQTable[] qTables,
+ JPEGHuffmanTable[] DCHuffmanTables,
+ JPEGHuffmanTable[] ACHuffmanTables
+ ) {
+ if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+ if(DCHuffmanTables.length != ACHuffmanTables.length) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+ if (qTables.length > 4 || DCHuffmanTables.length > 4) {
+ throw new IllegalArgumentException("Invalid JPEG table arrays");
+ }
+
+ // Do the shallow copy, it should be enough
+ this.qTables = qTables.clone();
+ dcHuffmanTables = DCHuffmanTables.clone();
+ acHuffmanTables = ACHuffmanTables.clone();
+ }
+
+ /**
+ * Unset all encoded tables.
+ */
+ public void unsetEncodeTables() {
+ qTables = null;
+ dcHuffmanTables = null;
+ acHuffmanTables = null;
+ }
+
+ /**
+ * Gets the DC Huffman tables.
+ *
+ * @return the DC Huffman tables which are set, or null.
+ */
+ public JPEGHuffmanTable[] getDCHuffmanTables() {
+ return dcHuffmanTables == null ? null : dcHuffmanTables.clone();
+ }
+
+ /**
+ * Gets the AC Huffman tables.
+ *
+ * @return the AC Huffman tables which are set, or null.
+ */
+ public JPEGHuffmanTable[] getACHuffmanTables() {
+ return acHuffmanTables == null ? null : acHuffmanTables.clone();
+ }
+
+ /**
+ * Gets the quantization tables.
+ *
+ * @return the quantization tables, or null.
+ */
+ public JPEGQTable[] getQTables() {
+ return qTables == null ? null : qTables.clone();
+ }
+
+ @Override
+ public String[] getCompressionQualityDescriptions() {
+ super.getCompressionQualityDescriptions();
+ return COMP_QUALITY_DESCRIPTIONS.clone();
+ }
+
+ @Override
+ public float[] getCompressionQualityValues() {
+ super.getCompressionQualityValues();
+ return COMP_QUALITY_VALUES.clone();
+ }
+
+ /**
+ * Sets the flag indicated that the writer will generate optimized
+ * Huffman tables for the image as part of the writing process.
+ *
+ * @param optimize the flag of optimizing huffman tables.
+ */
+ public void setOptimizeHuffmanTables(boolean optimize) {
+ optimizeHuffmanTables = optimize;
+ }
+
+ /**
+ * Returns true if the writer generates optimized Huffman tables,
+ * false otherwise.
+ *
+ * @return the true if the writer generates optimized Huffman tables,
+ * false otherwise.
+ */
+ public boolean getOptimizeHuffmanTables() {
+ return optimizeHuffmanTables;
+ }
+
+ @Override
+ public boolean isCompressionLossless() {
+ if (getCompressionMode() != MODE_EXPLICIT) {
+ throw new IllegalStateException("Compression mode not MODE_EXPLICIT!");
+ }
+ return false;
+ }
+
+ @Override
+ public void unsetCompression() {
+ if (getCompressionMode() != MODE_EXPLICIT) {
+ throw new IllegalStateException("Compression mode not MODE_EXPLICIT!");
+ }
+ compressionQuality = JPEGConsts.DEFAULT_JPEG_COMPRESSION_QUALITY;
+ }
+}
diff --git a/awt/javax/imageio/plugins/jpeg/JPEGQTable.java b/awt/javax/imageio/plugins/jpeg/JPEGQTable.java
new file mode 100644
index 0000000..0c5b37e
--- /dev/null
+++ b/awt/javax/imageio/plugins/jpeg/JPEGQTable.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.plugins.jpeg;
+
+/**
+ * The JPEGQTable class represents a single JPEG quantization table
+ * and provides for the standard tables taken from the JPEG specification.
+ */
+public class JPEGQTable {
+
+ /** The Constant SIZE. */
+ private final static int SIZE = 64;
+
+ /** The Constant BASELINE_MAX. */
+ private final static int BASELINE_MAX = 255;
+
+ /** The Constant MAX. */
+ private final static int MAX = 32767;
+
+
+ /** The table. */
+ private int[] theTable;
+
+ /*
+ * K1 & K2 tables can be found in the JPEG format specification
+ * at http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ */
+
+ /** The Constant K1LumTable. */
+ private static final int[] K1LumTable = new int[] {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+ };
+
+ /** The Constant K2ChrTable. */
+ private static final int[] K2ChrTable = new int[] {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+ };
+
+ /**
+ * The K1Luminance indicates standart table K.1 from JPEG
+ * specification and produces "good" quality output.
+ */
+ public static final JPEGQTable K1Luminance = new JPEGQTable(K1LumTable);
+
+ /**
+ * The K1Div2Luminance indicates K.1 table from JPEG
+ * specification with all elements divided by 2 and produces
+ * "very good" quality output.
+ */
+ public static final JPEGQTable K1Div2Luminance = K1Luminance.getScaledInstance(0.5f, true);
+
+ /**
+ * The K2Chrominance indicates K.2 table from JPEG
+ * specification and produces "good" quality output.
+ */
+ public static final JPEGQTable K2Chrominance = new JPEGQTable(K2ChrTable);
+
+ /**
+ * The Constant K2Div2Chrominance indicates K.2 table from JPEG
+ * specification with all elements divided by 2 and produces
+ * "very good" quality output.
+ */
+ public static final JPEGQTable K2Div2Chrominance = K2Chrominance.getScaledInstance(0.5f, true);;
+
+
+ /**
+ * Instantiates a new JPEGQTable from the array, which
+ * should contain 64 elements in natural order.
+ *
+ * @param table the quantization table.
+ */
+ public JPEGQTable(int[] table) {
+ if (table == null) {
+ throw new IllegalArgumentException("table should not be NULL");
+ }
+ if (table.length != SIZE) {
+ throw new IllegalArgumentException("illegal table size: " + table.length);
+ }
+ theTable = table.clone();
+ }
+
+ /**
+ * Gets the current quantization table as an array of int values.
+ *
+ * @return the current quantization table as an array of int values.
+ */
+ public int[] getTable() {
+ return theTable.clone();
+ }
+
+ /**
+ * Gets the scaled instance as quantization table where
+ * the values are multiplied by the scaleFactor and then clamped
+ * if forceBaseline is true.
+ *
+ * @param scaleFactor the scale factor of table.
+ * @param forceBaseline the force baseline flag, the values
+ * should be clamped if true.
+ *
+ * @return the new quantization table.
+ */
+ public JPEGQTable getScaledInstance(float scaleFactor, boolean forceBaseline) {
+ int table[] = new int[SIZE];
+
+ int maxValue = forceBaseline ? BASELINE_MAX : MAX;
+
+ for (int i = 0; i < theTable.length; i++) {
+ int rounded = Math.round(theTable[i] * scaleFactor);
+ if (rounded < 1) {
+ rounded = 1;
+ }
+ if (rounded > maxValue) {
+ rounded = maxValue;
+ }
+ table[i] = rounded;
+ }
+ return new JPEGQTable(table);
+ }
+
+ /**
+ * Returns the string representation of this JPEGQTable object.
+ *
+ * @return the string representation of this JPEGQTable object.
+ */
+ @Override
+ public String toString() {
+ //-- TODO more informative info
+ return "JPEGQTable";
+ }
+}
diff --git a/awt/javax/imageio/spi/IIORegistry.java b/awt/javax/imageio/spi/IIORegistry.java
new file mode 100644
index 0000000..3c1c989
--- /dev/null
+++ b/awt/javax/imageio/spi/IIORegistry.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import java.util.Arrays;
+
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReaderSpi;
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriterSpi;
+import org.apache.harmony.x.imageio.plugins.png.PNGImageReaderSpi;
+import org.apache.harmony.x.imageio.plugins.png.PNGImageWriterSpi;
+import org.apache.harmony.x.imageio.spi.FileIISSpi;
+import org.apache.harmony.x.imageio.spi.FileIOSSpi;
+import org.apache.harmony.x.imageio.spi.InputStreamIISSpi;
+import org.apache.harmony.x.imageio.spi.OutputStreamIOSSpi;
+import org.apache.harmony.x.imageio.spi.RAFIISSpi;
+import org.apache.harmony.x.imageio.spi.RAFIOSSpi;
+
+/*
+ * @author Rustem V. Rafikov, Viskov Nikolay
+ * @version $Revision: 1.3 $
+ */
+
+/**
+ * The IIORegistry class registers service provider instances
+ * (SPI). Service provider instances are recognized by specific
+ * meta-information in the JAR files containing them. The JAR
+ * files with SPI classes are loaded from the application class
+ * path.
+ */
+public final class IIORegistry extends ServiceRegistry {
+
+ /** The instance. */
+ private static IIORegistry instance;
+
+ /** The Constant CATEGORIES. */
+ private static final Class[] CATEGORIES = new Class[] {
+ javax.imageio.spi.ImageWriterSpi.class,
+ javax.imageio.spi.ImageReaderSpi.class,
+ javax.imageio.spi.ImageInputStreamSpi.class,
+ //javax.imageio.spi.ImageTranscoderSpi.class,
+ javax.imageio.spi.ImageOutputStreamSpi.class
+ };
+
+ /**
+ * Instantiates a new iIO registry.
+ */
+ private IIORegistry() {
+ super(Arrays.<Class<?>>asList(CATEGORIES).iterator());
+ registerBuiltinSpis();
+ registerApplicationClasspathSpis();
+ }
+
+ /**
+ * Register builtin spis.
+ */
+ private void registerBuiltinSpis() {
+ registerServiceProvider(new JPEGImageWriterSpi());
+ registerServiceProvider(new JPEGImageReaderSpi());
+ registerServiceProvider(new PNGImageReaderSpi());
+ registerServiceProvider(new PNGImageWriterSpi());
+ registerServiceProvider(new FileIOSSpi());
+ registerServiceProvider(new FileIISSpi());
+ registerServiceProvider(new RAFIOSSpi());
+ registerServiceProvider(new RAFIISSpi());
+ registerServiceProvider(new OutputStreamIOSSpi());
+ registerServiceProvider(new InputStreamIISSpi());
+ //-- TODO implement
+ }
+
+ /**
+ * Gets the default IIORegistry instance.
+ *
+ * @return the default IIORegistry instance.
+ */
+ public static IIORegistry getDefaultInstance() {
+ // TODO implement own instance for each ThreadGroup (see also ThreadLocal)
+ synchronized (IIORegistry.class) {
+ if (instance == null) {
+ instance = new IIORegistry();
+ }
+ return instance;
+ }
+ }
+
+ /**
+ * Registers all service providers from the application class
+ * path.
+ */
+ public void registerApplicationClasspathSpis() {
+ //-- TODO implement for non-builtin plugins
+ }
+}
diff --git a/awt/javax/imageio/spi/IIOServiceProvider.java b/awt/javax/imageio/spi/IIOServiceProvider.java
new file mode 100644
index 0000000..f5873bf
--- /dev/null
+++ b/awt/javax/imageio/spi/IIOServiceProvider.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import java.util.Locale;
+
+/**
+ * The IIOServiceProvider abstract class provides base functionality
+ * for imageio service provider interfaces (SPIs).
+ */
+public abstract class IIOServiceProvider implements RegisterableService {
+
+ /** The vendor name of this service provider. */
+ protected String vendorName;
+
+ /** The version of this service provider. */
+ protected String version;
+
+ /**
+ * Instantiates a new IIOServiceProvider.
+ *
+ * @param vendorName the vendor name of service provider.
+ * @param version the version of service provider.
+ */
+ public IIOServiceProvider(String vendorName, String version) {
+ if (vendorName == null) {
+ throw new NullPointerException("vendor name cannot be NULL");
+ }
+ if (version == null) {
+ throw new NullPointerException("version name cannot be NULL");
+ }
+ this.vendorName = vendorName;
+ this.version = version;
+ }
+
+ /**
+ * Instantiates a new IIOServiceProvider.
+ */
+ public IIOServiceProvider() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ public void onRegistration(ServiceRegistry registry, Class<?> category) {
+ // the default impl. does nothing
+ }
+
+ public void onDeregistration(ServiceRegistry registry, Class<?> category) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets the vendor name of this service provider.
+ *
+ * @return the vendor name of this service provider.
+ */
+ public String getVendorName() {
+ return vendorName;
+ }
+
+ /**
+ * Gets the version of this service provider.
+ *
+ * @return the version of this service provider.
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Gets a description of this service provider.
+ * The result string should be localized for the specified
+ * Locale.
+ *
+ * @param locale the specified Locale.
+ *
+ * @return the description of this service provider.
+ */
+ public abstract String getDescription(Locale locale);
+}
diff --git a/awt/javax/imageio/spi/ImageInputStreamSpi.java b/awt/javax/imageio/spi/ImageInputStreamSpi.java
new file mode 100644
index 0000000..47d210a
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageInputStreamSpi.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import java.io.File;
+import java.io.IOException;
+import javax.imageio.stream.ImageInputStream;
+
+/**
+ * The ImageInputStreamSpi abstract class is a service provider
+ * interface (SPI) for ImageInputStreams.
+ */
+public abstract class ImageInputStreamSpi extends IIOServiceProvider implements
+ RegisterableService {
+
+ /** The input class. */
+ protected Class<?> inputClass;
+
+ /**
+ * Instantiates a new ImageInputStreamSpi.
+ */
+ protected ImageInputStreamSpi() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Instantiates a new ImageInputStreamSpi.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ * @param inputClass the input class.
+ */
+ public ImageInputStreamSpi(String vendorName, String version, Class<?> inputClass) {
+ super(vendorName, version);
+ this.inputClass = inputClass;
+ }
+
+ /**
+ * Gets an input Class object that represents class or
+ * interface that must be implemented by an input source.
+ *
+ * @return the input class.
+ */
+ public Class<?> getInputClass() {
+ return inputClass;
+ }
+
+ /**
+ * Returns true if the ImageInputStream can use a cache
+ * file. If this method returns false, the value of the
+ * useCache parameter of createInputStreamInstance will
+ * be ignored. The default implementation returns false.
+ *
+ * @return true if the ImageInputStream can use a cache
+ * file, false otherwise.
+ */
+ public boolean canUseCacheFile() {
+ return false; //-- def
+ }
+
+ /**
+ * Returns true if the ImageInputStream implementation
+ * requires the use of a cache file. The default implementation
+ * returns false.
+ *
+ * @return true if the ImageInputStream implementation
+ * requires the use of a cache file, false otherwise.
+ */
+ public boolean needsCacheFile() {
+ return false; // def
+ }
+
+ /**
+ * Creates the ImageInputStream associated with this
+ * service provider. The input object should
+ * be an instance of the class returned by th getInputClass
+ * method. This method uses the specified directory
+ * for the cache file if the useCache parameter is true.
+ *
+ * @param input the input Object.
+ * @param useCache the flag indicating if a cache file
+ * is needed or not.
+ * @param cacheDir the cache directory.
+ *
+ * @return the ImageInputStream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract ImageInputStream createInputStreamInstance(Object input, boolean useCache,
+ File cacheDir) throws IOException;
+
+ /**
+ * Creates the ImageInputStream associated with this
+ * service provider. The input object should
+ * be an instance of the class returned by getInputClass
+ * method. This method uses the default system directory
+ * for the cache file, if it is needed.
+ *
+ * @param input the input Object.
+ *
+ * @return the ImageInputStream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ImageInputStream createInputStreamInstance(Object input) throws IOException {
+ return createInputStreamInstance(input, true, null);
+ }
+}
diff --git a/awt/javax/imageio/spi/ImageOutputStreamSpi.java b/awt/javax/imageio/spi/ImageOutputStreamSpi.java
new file mode 100644
index 0000000..d45e24c
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageOutputStreamSpi.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import javax.imageio.stream.ImageOutputStream;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * The ImageOutputStreamSpi abstract class is a service provider
+ * interface (SPI) for ImageOutputStreams.
+ */
+public abstract class ImageOutputStreamSpi extends IIOServiceProvider implements
+ RegisterableService {
+
+ /** The output class. */
+ protected Class<?> outputClass;
+
+ /**
+ * Instantiates a new ImageOutputStreamSpi.
+ */
+ protected ImageOutputStreamSpi() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Instantiates a new ImageOutputStreamSpi.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ * @param outputClass the output class.
+ */
+ public ImageOutputStreamSpi(String vendorName, String version, Class<?> outputClass) {
+ super(vendorName, version);
+ this.outputClass = outputClass;
+ }
+
+ /**
+ * Gets an output Class object that represents the class or
+ * interface that must be implemented by an output source.
+ *
+ * @return the output class.
+ */
+ public Class<?> getOutputClass() {
+ return outputClass;
+ }
+
+ /**
+ * Returns true if the ImageOutputStream can use a cache
+ * file. If this method returns false, the value of the
+ * useCache parameter of createOutputStreamInstance will
+ * be ignored. The default implementation returns false.
+ *
+ * @return true if the ImageOutputStream can use a cache
+ * file, false otherwise.
+ */
+ public boolean canUseCacheFile() {
+ return false; // def
+ }
+
+ /**
+ * Returns true if the ImageOutputStream implementation
+ * requires the use of a cache file. The default implementation
+ * returns false.
+ *
+ * @return true if the ImageOutputStream implementation
+ * requires the use of a cache file, false otherwise.
+ */
+ public boolean needsCacheFile() {
+ return false; // def
+ }
+
+ /**
+ * Creates the ImageOutputStream associated with this
+ * service provider. The output object should
+ * be an instance of the class returned by getOutputClass
+ * method. This method uses the default system directory
+ * for the cache file, if it is needed.
+ *
+ * @param output the output Object.
+ *
+ * @return the ImageOutputStream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ImageOutputStream createOutputStreamInstance(Object output) throws IOException {
+ return createOutputStreamInstance(output, true, null);
+ }
+
+ /**
+ * Creates the ImageOutputStream associated with this
+ * service provider. The output object should
+ * be an instance of the class returned by getInputClass
+ * method. This method uses the specified directory
+ * for the cache file, if the useCache parameter is true.
+ *
+ * @param output the output Object.
+ * @param useCache the flag indicating if cache file
+ * is needed or not.
+ * @param cacheDir the cache directory.
+ *
+ * @return the ImageOutputStream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract ImageOutputStream createOutputStreamInstance(Object output,
+ boolean useCache, File cacheDir) throws IOException;
+}
diff --git a/awt/javax/imageio/spi/ImageReaderSpi.java b/awt/javax/imageio/spi/ImageReaderSpi.java
new file mode 100644
index 0000000..2e2484c
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageReaderSpi.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.ImageReader;
+import java.io.IOException;
+
+/**
+ * The ImageReaderSpi abstract class is a service provider
+ * interface (SPI) for ImageReaders.
+ */
+public abstract class ImageReaderSpi extends ImageReaderWriterSpi {
+
+ /**
+ * The STANDARD_INPUT_TYPE contains ImageInputStream.class.
+ */
+ public static final Class[] STANDARD_INPUT_TYPE = new Class[] {ImageInputStream.class};
+
+ /** The input types. */
+ protected Class[] inputTypes;
+
+ /** The writer SPI names. */
+ protected String[] writerSpiNames;
+
+ /**
+ * Instantiates a new ImageReaderSpi.
+ */
+ protected ImageReaderSpi() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Instantiates a new ImageReaderSpi.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ * @param names the format names.
+ * @param suffixes the array of strings representing the file suffixes.
+ * @param MIMETypes the an array of strings representing MIME types.
+ * @param pluginClassName the plugin class name.
+ * @param inputTypes the input types.
+ * @param writerSpiNames the array of strings with class names of all
+ * associated ImageWriters.
+ * @param supportsStandardStreamMetadataFormat the value indicating
+ * if stream metadata can be described by standart metadata format.
+ * @param nativeStreamMetadataFormatName the native stream metadata
+ * format name, returned by getNativeStreamMetadataFormatName.
+ * @param nativeStreamMetadataFormatClassName the native stream
+ * metadata format class name, returned by getNativeStreamMetadataFormat.
+ * @param extraStreamMetadataFormatNames the extra stream metadata
+ * format names, returned by getExtraStreamMetadataFormatNames.
+ * @param extraStreamMetadataFormatClassNames the extra stream metadata
+ * format class names, returned by getStreamMetadataFormat.
+ * @param supportsStandardImageMetadataFormat the value indicating
+ * if image metadata can be described by standart metadata format.
+ * @param nativeImageMetadataFormatName the native image metadata
+ * format name, returned by getNativeImageMetadataFormatName.
+ * @param nativeImageMetadataFormatClassName the native image
+ * metadata format class name, returned by getNativeImageMetadataFormat.
+ * @param extraImageMetadataFormatNames the extra image metadata
+ * format names, returned by getExtraImageMetadataFormatNames.
+ * @param extraImageMetadataFormatClassNames the extra image metadata
+ * format class names, returned by getImageMetadataFormat.
+ */
+ public ImageReaderSpi(String vendorName, String version, String[] names, String[] suffixes,
+ String[] MIMETypes, String pluginClassName,
+ Class[] inputTypes, String[] writerSpiNames,
+ boolean supportsStandardStreamMetadataFormat,
+ String nativeStreamMetadataFormatName,
+ String nativeStreamMetadataFormatClassName,
+ String[] extraStreamMetadataFormatNames,
+ String[] extraStreamMetadataFormatClassNames,
+ boolean supportsStandardImageMetadataFormat,
+ String nativeImageMetadataFormatName,
+ String nativeImageMetadataFormatClassName,
+ String[] extraImageMetadataFormatNames,
+ String[] extraImageMetadataFormatClassNames) {
+ super(vendorName, version, names, suffixes, MIMETypes, pluginClassName,
+ supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName,
+ nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames,
+ extraStreamMetadataFormatClassNames, supportsStandardImageMetadataFormat,
+ nativeImageMetadataFormatName, nativeImageMetadataFormatClassName,
+ extraImageMetadataFormatNames, extraImageMetadataFormatClassNames);
+
+ if (inputTypes == null || inputTypes.length == 0) {
+ throw new NullPointerException("input types array cannot be NULL or empty");
+ }
+ this.inputTypes = inputTypes;
+ this.writerSpiNames = writerSpiNames;
+ }
+
+ /**
+ * Gets an array of Class objects whose types can be used
+ * as input for this reader.
+ *
+ * @return the input types.
+ */
+ public Class[] getInputTypes() {
+ return inputTypes;
+ }
+
+ /**
+ * Returns true if the format of source object is
+ * supported by this reader.
+ *
+ * @param source the source object to be decoded
+ * (for example an ImageInputStream).
+ *
+ * @return true if the format of source object is
+ * supported by this reader, false otherwise.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract boolean canDecodeInput(Object source) throws IOException;
+
+ /**
+ * Returns an instance of the ImageReader implementation for
+ * this service provider.
+ *
+ * @return the ImageReader.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ImageReader createReaderInstance() throws IOException {
+ return createReaderInstance(null);
+ }
+
+ /**
+ * Returns an instance of the ImageReader implementation for
+ * this service provider.
+ *
+ * @param extension the a plugin specific extension object, or null.
+ *
+ * @return the ImageReader.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract ImageReader createReaderInstance(Object extension) throws IOException;
+
+ /**
+ * Checks whether or not the specified ImageReader object
+ * is an instance of the ImageReader associated with this
+ * service provider or not.
+ *
+ * @param reader the ImageReader.
+ *
+ * @return true, if the specified ImageReader object
+ * is an instance of the ImageReader associated with this
+ * service provider, false otherwise.
+ */
+ public boolean isOwnReader(ImageReader reader) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an array of strings with names of the ImageWriterSpi
+ * classes that support the internal metadata representation
+ * used by the ImageReader of this service provider, or null if
+ * there are no such ImageWriters.
+ *
+ * @return an array of strings with names of the ImageWriterSpi
+ * classes.
+ */
+ public String[] getImageWriterSpiNames() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+}
diff --git a/awt/javax/imageio/spi/ImageReaderWriterSpi.java b/awt/javax/imageio/spi/ImageReaderWriterSpi.java
new file mode 100644
index 0000000..b3c0f92
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageReaderWriterSpi.java
@@ -0,0 +1,315 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils;
+
+import javax.imageio.metadata.IIOMetadataFormat;
+
+/**
+ * The ImageReaderWriterSpi class is a superclass for the
+ * ImageReaderSpi and ImageWriterSpi SPIs.
+ */
+public abstract class ImageReaderWriterSpi extends IIOServiceProvider
+ implements RegisterableService {
+
+ /** The names. */
+ protected String[] names;
+
+ /** The suffixes. */
+ protected String[] suffixes;
+
+ /** The MIME types. */
+ protected String[] MIMETypes;
+
+ /** The plugin class name. */
+ protected String pluginClassName;
+
+ /** Whether the reader/writer supports standard stream metadata format. */
+ protected boolean supportsStandardStreamMetadataFormat;
+
+ /** The native stream metadata format name. */
+ protected String nativeStreamMetadataFormatName;
+
+ /** The native stream metadata format class name. */
+ protected String nativeStreamMetadataFormatClassName;
+
+ /** The extra stream metadata format names. */
+ protected String[] extraStreamMetadataFormatNames;
+
+ /** The extra stream metadata format class names. */
+ protected String[] extraStreamMetadataFormatClassNames;
+
+ /** Whether the reader/writer supports standard image metadata format. */
+ protected boolean supportsStandardImageMetadataFormat;
+
+ /** The native image metadata format name. */
+ protected String nativeImageMetadataFormatName;
+
+ /** The native image metadata format class name. */
+ protected String nativeImageMetadataFormatClassName;
+
+ /** The extra image metadata format names. */
+ protected String[] extraImageMetadataFormatNames;
+
+ /** The extra image metadata format class names. */
+ protected String[] extraImageMetadataFormatClassNames;
+
+ /**
+ * Instantiates a new ImageReaderWriterSpi.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ * @param names the format names.
+ * @param suffixes the array of strings representing the file suffixes.
+ * @param MIMETypes the an array of strings representing MIME types.
+ * @param pluginClassName the plugin class name.
+ * @param supportsStandardStreamMetadataFormat the value indicating
+ * if stream metadata can be described by standart metadata format.
+ * @param nativeStreamMetadataFormatName the native stream metadata
+ * format name, returned by getNativeStreamMetadataFormatName.
+ * @param nativeStreamMetadataFormatClassName the native stream
+ * metadata format class name, returned by getNativeStreamMetadataFormat.
+ * @param extraStreamMetadataFormatNames the extra stream metadata
+ * format names, returned by getExtraStreamMetadataFormatNames.
+ * @param extraStreamMetadataFormatClassNames the extra stream metadata
+ * format class names, returned by getStreamMetadataFormat.
+ * @param supportsStandardImageMetadataFormat the value indicating
+ * if image metadata can be described by standard metadata format.
+ * @param nativeImageMetadataFormatName the native image metadata
+ * format name, returned by getNativeImageMetadataFormatName.
+ * @param nativeImageMetadataFormatClassName the native image
+ * metadata format class name, returned by getNativeImageMetadataFormat.
+ * @param extraImageMetadataFormatNames the extra image metadata
+ * format names, returned by getExtraImageMetadataFormatNames.
+ * @param extraImageMetadataFormatClassNames the extra image metadata
+ * format class names, returned by getImageMetadataFormat.
+ */
+ public ImageReaderWriterSpi(String vendorName, String version, String[] names,
+ String[] suffixes, String[] MIMETypes,
+ String pluginClassName,
+ boolean supportsStandardStreamMetadataFormat,
+ String nativeStreamMetadataFormatName,
+ String nativeStreamMetadataFormatClassName,
+ String[] extraStreamMetadataFormatNames,
+ String[] extraStreamMetadataFormatClassNames,
+ boolean supportsStandardImageMetadataFormat,
+ String nativeImageMetadataFormatName,
+ String nativeImageMetadataFormatClassName,
+ String[] extraImageMetadataFormatNames,
+ String[] extraImageMetadataFormatClassNames) {
+ super(vendorName, version);
+
+ if (names == null || names.length == 0) {
+ throw new NullPointerException("format names array cannot be NULL or empty");
+ }
+
+ if (pluginClassName == null) {
+ throw new NullPointerException("Plugin class name cannot be NULL");
+ }
+
+ // We clone all the arrays to be consistent with the fact that
+ // some methods of this class must return clones of the arrays
+ // as it is stated in the spec.
+ this.names = names.clone();
+ this.suffixes = suffixes == null ? null : suffixes.clone();
+ this.MIMETypes = MIMETypes == null ? null : MIMETypes.clone();
+ this.pluginClassName = pluginClassName;
+ this.supportsStandardStreamMetadataFormat = supportsStandardStreamMetadataFormat;
+ this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName;
+ this.nativeStreamMetadataFormatClassName = nativeStreamMetadataFormatClassName;
+
+ this.extraStreamMetadataFormatNames =
+ extraStreamMetadataFormatNames == null ?
+ null : extraStreamMetadataFormatNames.clone();
+
+ this.extraStreamMetadataFormatClassNames =
+ extraStreamMetadataFormatClassNames == null ?
+ null : extraStreamMetadataFormatClassNames.clone();
+
+ this.supportsStandardImageMetadataFormat = supportsStandardImageMetadataFormat;
+ this.nativeImageMetadataFormatName = nativeImageMetadataFormatName;
+ this.nativeImageMetadataFormatClassName = nativeImageMetadataFormatClassName;
+
+ this.extraImageMetadataFormatNames =
+ extraImageMetadataFormatNames == null ?
+ null : extraImageMetadataFormatNames.clone();
+
+ this.extraImageMetadataFormatClassNames =
+ extraImageMetadataFormatClassNames == null ?
+ null : extraImageMetadataFormatClassNames.clone();
+ }
+
+ /**
+ * Instantiates a new ImageReaderWriterSpi.
+ */
+ public ImageReaderWriterSpi() {}
+
+ /**
+ * Gets an array of strings representing names of the formats
+ * that can be used by the ImageReader
+ * or ImageWriter implementation associated with this service
+ * provider.
+ *
+ * @return an array of supported format names.
+ */
+ public String[] getFormatNames() {
+ return names.clone();
+ }
+
+ /**
+ * Gets an array of strings representing file suffixes
+ * associated with the formats that can be used by the
+ * ImageReader or ImageWriter implementation of this
+ * service provider.
+ *
+ * @return an array of file suffixes.
+ */
+ public String[] getFileSuffixes() {
+ return suffixes == null ? null : suffixes.clone();
+ }
+
+ /**
+ * Gets an array of strings with the names of
+ * additional formats of the image metadata objects
+ * produced or consumed by this plug-in.
+ *
+ * @return the array of extra image metadata format names.
+ */
+ public String[] getExtraImageMetadataFormatNames() {
+ return extraImageMetadataFormatNames == null ? null : extraImageMetadataFormatNames.clone();
+ }
+
+ /**
+ * Gets an array of strings with the names of
+ * additional formats of the stream metadata objects
+ * produced or consumed by this plug-in.
+ *
+ * @return the array of extra stream metadata format names.
+ */
+ public String[] getExtraStreamMetadataFormatNames() {
+ return extraStreamMetadataFormatNames == null ? null : extraStreamMetadataFormatNames.clone();
+ }
+
+ /**
+ * Gets an IIOMetadataFormat object for the specified image
+ * metadata format name.
+ *
+ * @param formatName the format name.
+ *
+ * @return the IIOMetadataFormat, or null.
+ */
+ public IIOMetadataFormat getImageMetadataFormat(String formatName) {
+ return IIOMetadataUtils.instantiateMetadataFormat(
+ formatName, supportsStandardImageMetadataFormat,
+ nativeImageMetadataFormatName, nativeImageMetadataFormatClassName,
+ extraImageMetadataFormatNames, extraImageMetadataFormatClassNames
+ );
+ }
+
+ /**
+ * Gets an IIOMetadataFormat object for the specified stream
+ * metadata format name.
+ *
+ * @param formatName the format name.
+ *
+ * @return the IIOMetadataFormat, or null.
+ */
+ public IIOMetadataFormat getStreamMetadataFormat(String formatName) {
+ return IIOMetadataUtils.instantiateMetadataFormat(
+ formatName, supportsStandardStreamMetadataFormat,
+ nativeStreamMetadataFormatName, nativeStreamMetadataFormatClassName,
+ extraStreamMetadataFormatNames, extraStreamMetadataFormatClassNames
+ );
+ }
+
+ /**
+ * Gets an array of strings representing the MIME types
+ * of the formats that are supported by the
+ * ImageReader or ImageWriter implementation of this
+ * service provider.
+ *
+ * @return the array MIME types.
+ */
+ public String[] getMIMETypes() {
+ return MIMETypes == null ? null : MIMETypes.clone();
+ }
+
+ /**
+ * Gets the name of the native image metadata format for
+ * this reader/writer, which allows for lossless encoding
+ * or decoding of the image metadata with the format.
+ *
+ * @return the string with native image metadata format name,
+ * or null.
+ */
+ public String getNativeImageMetadataFormatName() {
+ return nativeImageMetadataFormatName;
+ }
+
+ /**
+ * Gets the name of the native stream metadata format for
+ * this reader/writer, which allows for lossless encoding
+ * or decoding of the stream metadata with the format.
+ *
+ * @return the string with native stream metadata format name,
+ * or null.
+ */
+ public String getNativeStreamMetadataFormatName() {
+ return nativeStreamMetadataFormatName;
+ }
+
+ /**
+ * Gets the class name of the ImageReader
+ * or ImageWriter associated with this service provider.
+ *
+ * @return the class name.
+ */
+ public String getPluginClassName() {
+ return pluginClassName;
+ }
+
+ /**
+ * Checks if the standard metadata format is supported
+ * by the getAsTree and setFromTree methods for the
+ * image metadata objects produced or consumed by this
+ * reader or writer.
+ *
+ * @return true, if standard image metadata format is
+ * supported, false otherwise.
+ */
+ public boolean isStandardImageMetadataFormatSupported() {
+ return supportsStandardImageMetadataFormat;
+ }
+
+ /**
+ * Checks if the standard metadata format is supported
+ * by the getAsTree and setFromTree methods for the
+ * stream metadata objects produced or consumed by this
+ * reader or writer.
+ *
+ * @return true, if standard stream metadata format is
+ * supported, false otherwise.
+ */
+ public boolean isStandardStreamMetadataFormatSupported() {
+ return supportsStandardStreamMetadataFormat;
+ }
+}
diff --git a/awt/javax/imageio/spi/ImageTranscoderSpi.java b/awt/javax/imageio/spi/ImageTranscoderSpi.java
new file mode 100644
index 0000000..68c4024
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageTranscoderSpi.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import javax.imageio.ImageTranscoder;
+
+/**
+ * The ImageTranscoderSpi class is a service provider interface (SPI)
+ * for ImageTranscoders.
+ */
+public abstract class ImageTranscoderSpi extends IIOServiceProvider
+ implements RegisterableService {
+
+ /**
+ * Instantiates a new ImageTranscoderSpi.
+ */
+ protected ImageTranscoderSpi() {
+ }
+
+ /**
+ * Instantiates a new ImageTranscoderSpi with the specified
+ * vendor name and version.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ */
+ public ImageTranscoderSpi(String vendorName, String version) {
+ super(vendorName, version);
+ }
+
+ /**
+ * Gets the class name of an ImageReaderSpi that
+ * produces IIOMetadata objects that can be used as
+ * input to this transcoder.
+ *
+ * @return the class name of an ImageReaderSpi.
+ */
+ public abstract String getReaderServiceProviderName();
+
+ /**
+ * Gets the class name of an ImageWriterSpi that
+ * produces IIOMetadata objects that can be used as
+ * input to this transcoder.
+ *
+ * @return the class name of an ImageWriterSpi.
+ */
+ public abstract String getWriterServiceProviderName();
+
+ /**
+ * Creates an instance of the ImageTranscoder associated
+ * with this service provider.
+ *
+ * @return the ImageTranscoder instance.
+ */
+ public abstract ImageTranscoder createTranscoderInstance();
+}
diff --git a/awt/javax/imageio/spi/ImageWriterSpi.java b/awt/javax/imageio/spi/ImageWriterSpi.java
new file mode 100644
index 0000000..979ef77
--- /dev/null
+++ b/awt/javax/imageio/spi/ImageWriterSpi.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriter;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+
+/**
+ * The ImageWriterSpi abstract class is a service provider
+ * interface (SPI) for ImageWriters.
+ */
+public abstract class ImageWriterSpi extends ImageReaderWriterSpi {
+
+ /** The STANDARD_OUTPUT_TYPE contains ImageInputStream.class. */
+ public static final Class[] STANDARD_OUTPUT_TYPE = new Class[] {ImageInputStream.class};
+
+ /** The output types. */
+ protected Class[] outputTypes;
+
+ /** The reader spi names. */
+ protected String[] readerSpiNames;
+
+ /**
+ * Instantiates a new ImageWriterSpi.
+ */
+ protected ImageWriterSpi() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Instantiates a new ImageWriterSpi with the specified parameters.
+ *
+ * @param vendorName the vendor name.
+ * @param version the version.
+ * @param names the format names.
+ * @param suffixes the array of strings representing the file suffixes.
+ * @param MIMETypes the an array of strings representing MIME types.
+ * @param pluginClassName the plugin class name.
+ * @param outputTypes the output types.
+ * @param readerSpiNames the array of strings with class names of all
+ * associated ImageReaders.
+ * @param supportsStandardStreamMetadataFormat the value indicating
+ * if stream metadata can be described by standard metadata format.
+ * @param nativeStreamMetadataFormatName the native stream metadata
+ * format name, returned by getNativeStreamMetadataFormatName.
+ * @param nativeStreamMetadataFormatClassName the native stream
+ * metadata format class name, returned by getNativeStreamMetadataFormat.
+ * @param extraStreamMetadataFormatNames the extra stream metadata
+ * format names, returned by getExtraStreamMetadataFormatNames.
+ * @param extraStreamMetadataFormatClassNames the extra stream metadata
+ * format class names, returned by getStreamMetadataFormat.
+ * @param supportsStandardImageMetadataFormat the value indicating
+ * if image metadata can be described by standard metadata format.
+ * @param nativeImageMetadataFormatName the native image metadata
+ * format name, returned by getNativeImageMetadataFormatName.
+ * @param nativeImageMetadataFormatClassName the native image
+ * metadata format class name, returned by getNativeImageMetadataFormat.
+ * @param extraImageMetadataFormatNames the extra image metadata
+ * format names, returned by getExtraImageMetadataFormatNames.
+ * @param extraImageMetadataFormatClassNames the extra image metadata
+ * format class names, returned by getImageMetadataFormat.
+ */
+ public ImageWriterSpi(String vendorName, String version, String[] names,
+ String[] suffixes, String[] MIMETypes,
+ String pluginClassName,
+ Class[] outputTypes, String[] readerSpiNames,
+ boolean supportsStandardStreamMetadataFormat,
+ String nativeStreamMetadataFormatName,
+ String nativeStreamMetadataFormatClassName,
+ String[] extraStreamMetadataFormatNames,
+ String[] extraStreamMetadataFormatClassNames,
+ boolean supportsStandardImageMetadataFormat,
+ String nativeImageMetadataFormatName,
+ String nativeImageMetadataFormatClassName,
+ String[] extraImageMetadataFormatNames,
+ String[] extraImageMetadataFormatClassNames) {
+ super(vendorName, version, names, suffixes, MIMETypes, pluginClassName,
+ supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName,
+ nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames,
+ extraStreamMetadataFormatClassNames, supportsStandardImageMetadataFormat,
+ nativeImageMetadataFormatName, nativeImageMetadataFormatClassName,
+ extraImageMetadataFormatNames, extraImageMetadataFormatClassNames);
+
+ if (outputTypes == null || outputTypes.length == 0) {
+ throw new NullPointerException("output types array cannot be NULL or empty");
+ }
+
+ this.outputTypes = outputTypes;
+ this.readerSpiNames = readerSpiNames;
+ }
+
+ /**
+ * Returns true if the format of the writer's output is lossless.
+ * The default implementation returns true.
+ *
+ * @return true, if a format is lossless, false otherwise.
+ */
+ public boolean isFormatLossless() {
+ return true;
+ }
+
+ /**
+ * Gets an array of Class objects whose types
+ * can be used as output for this writer.
+ *
+ * @return the output types.
+ */
+ public Class[] getOutputTypes() {
+ return outputTypes;
+ }
+
+ /**
+ * Checks whether or not the ImageWriter implementation associated
+ * with this service provider can encode an image with
+ * the specified type.
+ *
+ * @param type the ImageTypeSpecifier.
+ *
+ * @return true, if an image with the specified type can be
+ * encoded, false otherwise.
+ */
+ public abstract boolean canEncodeImage(ImageTypeSpecifier type);
+
+ /**
+ * Checks whether or not the ImageWriter implementation associated
+ * with this service provider can encode the specified RenderedImage.
+ *
+ * @param im the RenderedImage.
+ *
+ * @return true, if RenderedImage can be encoded,
+ * false otherwise.
+ */
+ public boolean canEncodeImage(RenderedImage im) {
+ return canEncodeImage(ImageTypeSpecifier.createFromRenderedImage(im));
+ }
+
+ /**
+ * Returns an instance of the ImageWriter implementation for
+ * this service provider.
+ *
+ * @return the ImageWriter.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public ImageWriter createWriterInstance() throws IOException {
+ return createWriterInstance(null);
+ }
+
+ /**
+ * Returns an instance of the ImageWriter implementation for
+ * this service provider.
+ *
+ * @param extension the a plugin specific extension object, or null.
+ *
+ * @return the ImageWriter.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public abstract ImageWriter createWriterInstance(Object extension) throws IOException;
+
+ /**
+ * Checks whether or not the specified ImageWriter object
+ * is an instance of the ImageWriter associated with this
+ * service provider or not.
+ *
+ * @param writer the ImageWriter.
+ *
+ * @return true, if the specified ImageWriter object
+ * is an instance of the ImageWriter associated with this
+ * service provider, false otherwise.
+ */
+ public boolean isOwnWriter(ImageWriter writer) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an array of strings with names of the ImageReaderSpi
+ * classes that support the internal metadata representation
+ * used by the ImageWriter of this service provider, or null if
+ * there are no such ImageReaders.
+ *
+ * @return an array of strings with names of the ImageWriterSpi
+ * classes.
+ */
+ public String[] getImageReaderSpiNames() {
+ return readerSpiNames;
+ }
+}
diff --git a/awt/javax/imageio/spi/RegisterableService.java b/awt/javax/imageio/spi/RegisterableService.java
new file mode 100644
index 0000000..b50754e
--- /dev/null
+++ b/awt/javax/imageio/spi/RegisterableService.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+/**
+ * The RegisterableService interface provides service provider
+ * objects that can be registered by a ServiceRegistry, and
+ * notifications that registration and deregistration have been
+ * performed.
+ */
+public interface RegisterableService {
+
+ /**
+ * This method is called when the object which implements this
+ * interface is registered to the specified category of the
+ * specified registry.
+ *
+ * @param registry the ServiceRegistry to be registered.
+ * @param category the class representing a category.
+ */
+ void onRegistration(ServiceRegistry registry, Class<?> category);
+
+ /**
+ * This method is called when the object which implements this
+ * interface is deregistered to the specified category of the
+ * specified registry.
+ *
+ * @param registry the ServiceRegistry to be registered.
+ * @param category the class representing a category.
+ */
+ void onDeregistration(ServiceRegistry registry, Class<?> category);
+}
diff --git a/awt/javax/imageio/spi/ServiceRegistry.java b/awt/javax/imageio/spi/ServiceRegistry.java
new file mode 100644
index 0000000..1a18b02
--- /dev/null
+++ b/awt/javax/imageio/spi/ServiceRegistry.java
@@ -0,0 +1,516 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.spi;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * The ServiceRegistry class provides ability to register,
+ * deregister, look up and obtain service provider instances (SPIs).
+ * A service means a set of interfaces and classes, and a service
+ * provider is an implementation of a service. Service providers can
+ * be associated with one or more categories. Each category is defined
+ * by a class or interface. Only a single instance of a each class is
+ * allowed to be registered as a category.
+ */
+public class ServiceRegistry {
+
+ /** The categories. */
+ CategoriesMap categories = new CategoriesMap(this);
+
+ /**
+ * Instantiates a new ServiceRegistry with the specified categories.
+ *
+ * @param categoriesIterator an Iterator of Class objects
+ * for defining of categories.
+ */
+ public ServiceRegistry(Iterator<Class<?>> categoriesIterator) {
+ if (null == categoriesIterator) {
+ throw new IllegalArgumentException("categories iterator should not be NULL");
+ }
+ while(categoriesIterator.hasNext()) {
+ Class<?> c = categoriesIterator.next();
+ categories.addCategory(c);
+ }
+ }
+
+ /**
+ * Looks up and instantiates the available providers of this service using
+ * the specified class loader.
+ *
+ * @param providerClass the Class object of the provider to be looked up.
+ * @param loader the class loader to be used.
+ *
+ * @return the iterator of providers objects for this service.
+ */
+ public static <T> Iterator<T> lookupProviders(Class<T> providerClass, ClassLoader loader) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Looks up and instantiates the available providers of this service using
+ * the context class loader.
+ *
+ * @param providerClass the Class object of the provider to be looked up.
+ *
+ * @return the iterator of providers objects for this service.
+ */
+ public static <T> Iterator<T> lookupProviders(Class<T> providerClass) {
+ return lookupProviders(providerClass, Thread.currentThread().getContextClassLoader());
+ }
+
+ /**
+ * Registers the specified service provider object in the
+ * specified categories.
+ *
+ * @param provider the specified provider to be registered.
+ * @param category the category.
+ *
+ * @return true if no provider of the same class is registered
+ * in this category, false otherwise.
+ */
+ public <T> boolean registerServiceProvider(T provider, Class<T> category) {
+ return categories.addProvider(provider, category);
+ }
+
+ /**
+ * Registers a list of service providers.
+ *
+ * @param providers the list of service providers.
+ */
+ public void registerServiceProviders(Iterator<?> providers) {
+ for (Iterator<?> iterator = providers; iterator.hasNext();) {
+ categories.addProvider(iterator.next(), null);
+ }
+ }
+
+ /**
+ * Registers the specified service provider object in all
+ * categories.
+ *
+ * @param provider the service provider.
+ */
+ public void registerServiceProvider(Object provider) {
+ categories.addProvider(provider, null);
+ }
+
+ /**
+ * Deregisters the specifies service provider from the
+ * specified category.
+ *
+ * @param provider the service provider to be deregistered.
+ * @param category the specified category.
+ *
+ * @return true if the provider was already registered
+ * in the specified category, false otherwise.
+ */
+ public <T> boolean deregisterServiceProvider(T provider, Class<T> category) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Deregisters the specified service provider from all
+ * categories.
+ *
+ * @param provider the specified service provider.
+ */
+ public void deregisterServiceProvider(Object provider) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an Iterator of registered service providers
+ * in the specified category which satisfy the specified Filter.
+ * The useOrdering parameter indicates whether the iterator will
+ * return all of the server provider objects in a set order.
+ *
+ * @param category the specified category.
+ * @param filter the specified filter.
+ * @param useOrdering the flag indicating that providers are ordered
+ * in the returned Iterator.
+ *
+ * @return the iterator of registered service providers.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> Iterator<T> getServiceProviders(Class<T> category, Filter filter, boolean useOrdering) {
+ return new FilteredIterator<T>(filter, (Iterator<T>)categories.getProviders(category, useOrdering));
+ }
+
+ /**
+ * Gets an Iterator of all registered service providers
+ * in the specified category. The useOrdering parameter
+ * indicates whether the iterator will return all of the server
+ * provider objects in a set order.
+ *
+ * @param category the specified category.
+ * @param useOrdering the flag indicating that providers are ordered
+ * in the returned Iterator.
+ *
+ * @return the Iterator of service providers.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> Iterator<T> getServiceProviders(Class<T> category, boolean useOrdering) {
+ return (Iterator<T>)categories.getProviders(category, useOrdering);
+ }
+
+ /**
+ * Gets the registered service provider object that has the
+ * specified class type.
+ *
+ * @param providerClass the specified provider class.
+ *
+ * @return the service provider object.
+ */
+ public <T> T getServiceProviderByClass(Class<T> providerClass) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Sets an ordering between two service provider objects
+ * within the specified category.
+ *
+ * @param category the specified category.
+ * @param firstProvider the first provider.
+ * @param secondProvider the second provider.
+ *
+ * @return true if a previously unset order was set.
+ */
+ public <T> boolean setOrdering(Class<T> category, T firstProvider, T secondProvider) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Unsets an ordering between two service provider objects
+ * within the specified category.
+ *
+ * @param category the specified category.
+ * @param firstProvider the first provider.
+ * @param secondProvider the second provider.
+ *
+ * @return true if a previously unset order was removed.
+ */
+ public <T> boolean unsetOrdering(Class<T> category, T firstProvider, T secondProvider) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Deregisters all providers from the specified category.
+ *
+ * @param category the specified category.
+ */
+ public void deregisterAll(Class<?> category) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Deregister all providers from all categories.
+ */
+ public void deregisterAll() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Finalizes this object.
+ *
+ * @throws Throwable throws if an error occurs during
+ * finalization.
+ */
+ @Override
+ public void finalize() throws Throwable {
+ //TODO uncomment when deregisterAll is implemented
+ //deregisterAll();
+ }
+
+ /**
+ * Checks whether the specified provider has been already registered.
+ *
+ * @param provider the provider to be checked.
+ *
+ * @return true, if the specified provider has been already registered,
+ * false otherwise.
+ */
+ public boolean contains(Object provider) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+
+ /**
+ * Gets an iterator of Class objects representing the current
+ * categories.
+ *
+ * @return the Iterator of Class objects.
+ */
+ public Iterator<Class<?>> getCategories() {
+ return categories.list();
+ }
+
+ /**
+ * The ServiceRegistry.Filter interface is used by
+ * ServiceRegistry.getServiceProviders to filter providers according
+ * to the specified criterion.
+ */
+ public static interface Filter {
+
+ /**
+ * Returns true if the specified provider satisfies the
+ * criterion of this Filter.
+ *
+ * @param provider the provider.
+ *
+ * @return true if the specified provider satisfies the
+ * criterion of this Filter, false otherwise.
+ */
+ boolean filter(Object provider);
+ }
+
+ /**
+ * The Class CategoriesMap.
+ */
+ private static class CategoriesMap {
+
+ /** The categories. */
+ Map<Class<?>, ProvidersMap> categories = new HashMap<Class<?>, ProvidersMap>();
+
+ /** The registry. */
+ ServiceRegistry registry;
+
+ /**
+ * Instantiates a new categories map.
+ *
+ * @param registry the registry
+ */
+ public CategoriesMap(ServiceRegistry registry) {
+ this.registry = registry;
+ }
+
+ //-- TODO: useOrdering
+ /**
+ * Gets the providers.
+ *
+ * @param category the category
+ * @param useOrdering the use ordering
+ *
+ * @return the providers
+ */
+ Iterator<?> getProviders(Class<?> category, boolean useOrdering) {
+ ProvidersMap providers = categories.get(category);
+ if (null == providers) {
+ throw new IllegalArgumentException("Unknown category: " + category);
+ }
+ return providers.getProviders(useOrdering);
+ }
+
+ /**
+ * List.
+ *
+ * @return the iterator< class<?>>
+ */
+ Iterator<Class<?>> list() {
+ return categories.keySet().iterator();
+ }
+
+ /**
+ * Adds the category.
+ *
+ * @param category the category
+ */
+ void addCategory(Class<?> category) {
+ categories.put(category, new ProvidersMap());
+ }
+
+ /**
+ * Adds a provider to the category. If <code>category</code> is
+ * <code>null</code> then the provider will be added to all categories
+ * which the provider is assignable from.
+ *
+ * @param provider provider to add
+ * @param category category to add provider to
+ *
+ * @return if there were such provider in some category
+ */
+ boolean addProvider(Object provider, Class<?> category) {
+ if (provider == null) {
+ throw new IllegalArgumentException("provider should be != NULL");
+ }
+
+ boolean rt;
+ if (category == null) {
+ rt = findAndAdd(provider);
+ } else {
+ rt = addToNamed(provider, category);
+ }
+
+ if (provider instanceof RegisterableService) {
+ ((RegisterableService) provider).onRegistration(registry, category);
+ }
+
+ return rt;
+ }
+
+ /**
+ * Adds the to named.
+ *
+ * @param provider the provider
+ * @param category the category
+ *
+ * @return true, if successful
+ */
+ private boolean addToNamed(Object provider, Class<?> category) {
+ Object obj = categories.get(category);
+
+ if (null == obj) {
+ throw new IllegalArgumentException("Unknown category: " + category);
+ }
+
+ return ((ProvidersMap) obj).addProvider(provider);
+ }
+
+ /**
+ * Find and add.
+ *
+ * @param provider the provider
+ *
+ * @return true, if successful
+ */
+ private boolean findAndAdd(Object provider) {
+ boolean rt = false;
+ for (Entry<Class<?>, ProvidersMap> e : categories.entrySet()) {
+ if (e.getKey().isAssignableFrom(provider.getClass())) {
+ rt |= e.getValue().addProvider(provider);
+ }
+ }
+ return rt;
+ }
+ }
+
+ /**
+ * The Class ProvidersMap.
+ */
+ private static class ProvidersMap {
+ //-- TODO: providers ordering support
+
+ /** The providers. */
+ Map<Class<?>, Object> providers = new HashMap<Class<?>, Object>();
+
+ /**
+ * Adds the provider.
+ *
+ * @param provider the provider
+ *
+ * @return true, if successful
+ */
+ boolean addProvider(Object provider) {
+ return providers.put(provider.getClass(), provider) != null;
+ }
+
+ /**
+ * Gets the provider classes.
+ *
+ * @return the provider classes
+ */
+ Iterator<Class<?>> getProviderClasses() {
+ return providers.keySet().iterator();
+ }
+
+ //-- TODO ordering
+ /**
+ * Gets the providers.
+ *
+ * @param userOrdering the user ordering
+ *
+ * @return the providers
+ */
+ Iterator<?> getProviders(boolean userOrdering) {
+ return providers.values().iterator();
+ }
+ }
+
+ /**
+ * The Class FilteredIterator.
+ */
+ private static class FilteredIterator<E> implements Iterator<E> {
+
+ /** The filter. */
+ private Filter filter;
+
+ /** The backend. */
+ private Iterator<E> backend;
+
+ /** The next obj. */
+ private E nextObj;
+
+ /**
+ * Instantiates a new filtered iterator.
+ *
+ * @param filter the filter
+ * @param backend the backend
+ */
+ public FilteredIterator(Filter filter, Iterator<E> backend) {
+ this.filter = filter;
+ this.backend = backend;
+ findNext();
+ }
+
+ /**
+ * Next.
+ *
+ * @return the e
+ */
+ public E next() {
+ if (nextObj == null) {
+ throw new NoSuchElementException();
+ }
+ E tmp = nextObj;
+ findNext();
+ return tmp;
+ }
+
+ /**
+ * Checks for next.
+ *
+ * @return true, if successful
+ */
+ public boolean hasNext() {
+ return nextObj != null;
+ }
+
+ /**
+ * Removes the.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Sets nextObj to a next provider matching the criterion given by the filter.
+ */
+ private void findNext() {
+ nextObj = null;
+ while (backend.hasNext()) {
+ E o = backend.next();
+ if (filter.filter(o)) {
+ nextObj = o;
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/awt/javax/imageio/stream/FileCacheImageInputStream.java b/awt/javax/imageio/stream/FileCacheImageInputStream.java
new file mode 100644
index 0000000..47bc189
--- /dev/null
+++ b/awt/javax/imageio/stream/FileCacheImageInputStream.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.stream;
+
+import java.io.*;
+
+/**
+ * The FileCacheImageInputStream class is an implementation of
+ * ImageInputStream which reads from its InputStream
+ * and uses a temporary file as a cache.
+ */
+public class FileCacheImageInputStream extends ImageInputStreamImpl {
+
+ /** The is. */
+ private InputStream is;
+
+ /** The file. */
+ private File file;
+
+ /** The raf. */
+ private RandomAccessFile raf;
+
+
+ /**
+ * Instantiates a new FileCacheImageInputStream from
+ * the specified InputStream and using the specified
+ * File as its cache directory.
+ *
+ * @param stream the InputStream for reading.
+ * @param cacheDir the cache directory where the chache file
+ * will be created.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public FileCacheImageInputStream(InputStream stream, File cacheDir) throws IOException {
+ if (stream == null) {
+ throw new IllegalArgumentException("stream == null!");
+ }
+ is = stream;
+
+ if (cacheDir == null || cacheDir.isDirectory()) {
+ file = File.createTempFile(FileCacheImageOutputStream.IIO_TEMP_FILE_PREFIX, null, cacheDir);
+ file.deleteOnExit();
+ } else {
+ throw new IllegalArgumentException("Not a directory!");
+ }
+
+ raf = new RandomAccessFile(file, "rw");
+ }
+
+ @Override
+ public int read() throws IOException {
+ bitOffset = 0;
+
+ if (streamPos >= raf.length()) {
+ int b = is.read();
+
+ if (b < 0) {
+ return -1;
+ }
+
+ raf.seek(streamPos++);
+ raf.write(b);
+ return b;
+ }
+
+ raf.seek(streamPos++);
+ return raf.read();
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ bitOffset = 0;
+
+ if (streamPos >= raf.length()) {
+ int nBytes = is.read(b, off, len);
+
+ if (nBytes < 0) {
+ return -1;
+ }
+
+ raf.seek(streamPos);
+ raf.write(b, off, nBytes);
+ streamPos += nBytes;
+ return nBytes;
+ }
+
+ raf.seek(streamPos);
+ int nBytes = raf.read(b, off, len);
+ streamPos += nBytes;
+ return nBytes;
+ }
+
+ @Override
+ public boolean isCached() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedFile() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedMemory() {
+ return false;
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ raf.close();
+ file.delete();
+ }
+}
diff --git a/awt/javax/imageio/stream/FileCacheImageOutputStream.java b/awt/javax/imageio/stream/FileCacheImageOutputStream.java
new file mode 100644
index 0000000..ae48585
--- /dev/null
+++ b/awt/javax/imageio/stream/FileCacheImageOutputStream.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.stream;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+
+/**
+ * The FileCacheImageOutputStream class is an implementation of
+ * ImageOutputStream that writes to its OutputStream
+ * using a temporary file as a cache.
+ */
+public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
+
+ /** The Constant IIO_TEMP_FILE_PREFIX. */
+ static final String IIO_TEMP_FILE_PREFIX = "iioCache";
+
+ /** The Constant MAX_BUFFER_LEN. */
+ static final int MAX_BUFFER_LEN = 1048575; // 1 MB - is it not too much?
+
+ /** The os. */
+ private OutputStream os;
+
+ /** The file. */
+ private File file;
+
+ /** The raf. */
+ private RandomAccessFile raf;
+
+ /**
+ * Instantiates a FileCacheImageOutputStream.
+ *
+ * @param stream the OutputStream for writing.
+ * @param cacheDir the cache directory where the chache file
+ * will be created.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public FileCacheImageOutputStream(OutputStream stream, File cacheDir) throws IOException {
+ if (stream == null) {
+ throw new IllegalArgumentException("stream == null!");
+ }
+ os = stream;
+
+ if (cacheDir == null || cacheDir.isDirectory()) {
+ file = File.createTempFile(IIO_TEMP_FILE_PREFIX, null, cacheDir);
+ file.deleteOnExit();
+ } else {
+ throw new IllegalArgumentException("Not a directory!");
+ }
+
+ raf = new RandomAccessFile(file, "rw");
+ }
+
+ @Override
+ public void close() throws IOException {
+ flushBefore(raf.length());
+ super.close();
+ raf.close();
+ file.delete();
+ }
+
+ @Override
+ public boolean isCached() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedFile() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedMemory() {
+ return false;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ flushBits(); // See the flushBits method description
+
+ raf.write(b);
+ streamPos++;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ flushBits(); // See the flushBits method description
+
+ raf.write(b, off, len);
+ streamPos += len;
+ }
+
+ @Override
+ public int read() throws IOException {
+ bitOffset = 0; // Should reset
+
+ int res = raf.read();
+ if (res >= 0) {
+ streamPos++;
+ }
+
+ return res;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ bitOffset = 0;
+
+ int numRead = raf.read(b, off, len);
+ if (numRead > 0) {
+ streamPos += numRead;
+ }
+
+ return numRead;
+ }
+
+ @Override
+ public void flushBefore(long pos) throws IOException {
+ long readFromPos = flushedPos;
+ super.flushBefore(pos);
+
+ long bytesToRead = pos - readFromPos;
+ raf.seek(readFromPos);
+
+ if (bytesToRead < MAX_BUFFER_LEN) {
+ byte buffer[] = new byte[(int)bytesToRead];
+ raf.readFully(buffer);
+ os.write(buffer);
+ } else {
+ byte buffer[] = new byte[MAX_BUFFER_LEN];
+ while (bytesToRead > 0) {
+ int count = (int) Math.min(MAX_BUFFER_LEN, bytesToRead);
+ raf.readFully(buffer, 0, count);
+ os.write(buffer, 0, count);
+ bytesToRead -= count;
+ }
+ }
+
+ os.flush();
+
+ if (pos != streamPos) {
+ raf.seek(streamPos); // Reset the position
+ }
+ }
+
+ @Override
+ public void seek(long pos) throws IOException {
+ if (pos < flushedPos) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ raf.seek(pos);
+ streamPos = raf.getFilePointer();
+ bitOffset = 0;
+ }
+
+ @Override
+ public long length() {
+ try {
+ return raf.length();
+ } catch(IOException e) {
+ return -1L;
+ }
+ }
+}
diff --git a/awt/javax/imageio/stream/FileImageInputStream.java b/awt/javax/imageio/stream/FileImageInputStream.java
new file mode 100644
index 0000000..6680ae0
--- /dev/null
+++ b/awt/javax/imageio/stream/FileImageInputStream.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.stream;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * The FileImageInputStream class implements ImageInputStream
+ * and obtains its input data from a File or RandomAccessFile.
+ */
+public class FileImageInputStream extends ImageInputStreamImpl {
+
+ /** The raf. */
+ RandomAccessFile raf;
+
+ /**
+ * Instantiates a new FileImageInputStream from the specified File.
+ *
+ * @param f the File of input data.
+ *
+ * @throws FileNotFoundException if the specified file
+ * doesn't exist.
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ @SuppressWarnings({"DuplicateThrows"})
+ public FileImageInputStream(File f) throws FileNotFoundException, IOException {
+ if (f == null) {
+ throw new IllegalArgumentException("f == null!");
+ }
+
+ raf = new RandomAccessFile(f, "r");
+ }
+
+ /**
+ * Instantiates a new FileImageInputStream from the specified
+ * RandomAccessFile.
+ *
+ * @param raf the RandomAccessFile of input data.
+ */
+ public FileImageInputStream(RandomAccessFile raf) {
+ if (raf == null) {
+ throw new IllegalArgumentException("raf == null!");
+ }
+
+ this.raf = raf;
+ }
+
+ @Override
+ public int read() throws IOException {
+ bitOffset = 0;
+
+ int res = raf.read();
+ if (res != -1) {
+ streamPos++;
+ }
+ return res;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ bitOffset = 0;
+
+ int numRead = raf.read(b, off, len);
+ if (numRead >= 0) {
+ streamPos += numRead;
+ }
+
+ return numRead;
+ }
+
+ @Override
+ public long length() {
+ try {
+ return raf.length();
+ } catch(IOException e) {
+ return -1L;
+ }
+ }
+
+ @Override
+ public void seek(long pos) throws IOException {
+ if (pos < getFlushedPosition()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ raf.seek(pos);
+ streamPos = raf.getFilePointer();
+ bitOffset = 0;
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ raf.close();
+ }
+}
diff --git a/awt/javax/imageio/stream/FileImageOutputStream.java b/awt/javax/imageio/stream/FileImageOutputStream.java
new file mode 100644
index 0000000..eaafe14
--- /dev/null
+++ b/awt/javax/imageio/stream/FileImageOutputStream.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.stream;
+
+import java.io.*;
+
+/**
+ * The FileImageOutputStream class implements ImageOutputStream
+ * and writes the output data to a File or RandomAccessFile.
+ */
+public class FileImageOutputStream extends ImageOutputStreamImpl {
+
+ /** The file. */
+ RandomAccessFile file;
+
+ /**
+ * Instantiates a new FileImageOutputStream with the specified
+ * File.
+ *
+ * @param f the output File.
+ *
+ * @throws FileNotFoundException if the file not found.
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ public FileImageOutputStream(File f) throws FileNotFoundException, IOException {
+ this(f != null
+ ? new RandomAccessFile(f, "rw")
+ : null);
+ }
+
+ /**
+ * Instantiates a new FileImageOutputStream with the specified
+ * RandomAccessFile.
+ *
+ * @param raf the output RandomAccessFile.
+ */
+ public FileImageOutputStream(RandomAccessFile raf) {
+ if (raf == null) {
+ throw new IllegalArgumentException("file should not be NULL");
+ }
+ file = raf;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ checkClosed();
+ // according to the spec for ImageOutputStreamImpl#flushBits()
+ flushBits();
+ file.write(b);
+ streamPos++;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ checkClosed();
+ // according to the spec for ImageOutputStreamImpl#flushBits()
+ flushBits();
+ file.write(b, off, len);
+ streamPos += len;
+ }
+
+ @Override
+ public int read() throws IOException {
+ checkClosed();
+ int rt = file.read();
+ if (rt != -1) {
+ streamPos++;
+ }
+ return rt;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ checkClosed();
+ int rt = file.read(b, off, len);
+ if (rt != -1) {
+ streamPos += rt;
+ }
+ return rt;
+ }
+
+ @Override
+ public long length() {
+ try {
+ checkClosed();
+ return file.length();
+ } catch(IOException e) {
+ return super.length(); // -1L
+ }
+ }
+
+ @Override
+ public void seek(long pos) throws IOException {
+ //-- checkClosed() is performed in super.seek()
+ super.seek(pos);
+ file.seek(pos);
+ streamPos = file.getFilePointer();
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ file.close();
+ }
+}
diff --git a/awt/javax/imageio/stream/IIOByteBuffer.java b/awt/javax/imageio/stream/IIOByteBuffer.java
new file mode 100644
index 0000000..961a7b3
--- /dev/null
+++ b/awt/javax/imageio/stream/IIOByteBuffer.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Sergey I. Salishev
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.stream;
+
+/**
+* @author Sergey I. Salishev
+* @version $Revision: 1.2 $
+*/
+
+/**
+ * The IIOByteBuffer class represents a byte array with offset and
+ * length that is used by ImageInputStream for obtaining a sequence
+ * of bytes.
+ */
+public class IIOByteBuffer {
+
+ /** The data. */
+ private byte[] data;
+
+ /** The offset. */
+ private int offset;
+
+ /** The length. */
+ private int length;
+
+ /**
+ * Instantiates a new IIOByteBuffer.
+ *
+ * @param data the byte array.
+ * @param offset the offset in the array.
+ * @param length the length of array.
+ */
+ public IIOByteBuffer(byte[] data, int offset, int length) {
+ this.data = data;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * Gets the byte array of this IIOByteBuffer.
+ *
+ * @return the byte array.
+ */
+ public byte[] getData() {
+ return data;
+ }
+
+ /**
+ * Gets the length in the array which will be used.
+ *
+ * @return the length of the data.
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * Gets the offset of this IIOByteBuffer.
+ *
+ * @return the offset of this IIOByteBuffer.
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Sets the new data array to this IIOByteBuffer object.
+ *
+ * @param data the new data array.
+ */
+ public void setData(byte[] data) {
+ this.data = data;
+ }
+
+ /**
+ * Sets the length of data which will be used.
+ *
+ * @param length the new length.
+ */
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+ /**
+ * Sets the offset in the data array of this IIOByteBuffer.
+ *
+ * @param offset the new offset.
+ */
+ public void setOffset(int offset) {
+ this.offset = offset;
+ }
+}
+
diff --git a/awt/javax/imageio/stream/ImageInputStream.java b/awt/javax/imageio/stream/ImageInputStream.java
new file mode 100644
index 0000000..771e9ff
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageInputStream.java
@@ -0,0 +1,485 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.stream;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+/**
+ * The ImageInputStream represents input stream interface that is
+ * used by ImageReaders.
+ */
+public interface ImageInputStream extends DataInput {
+
+ /**
+ * Sets the specified byte order for reading of data values
+ * from this stream.
+ *
+ * @param byteOrder the byte order.
+ */
+ void setByteOrder(ByteOrder byteOrder);
+
+ /**
+ * Gets the byte order.
+ *
+ * @return the byte order.
+ */
+ ByteOrder getByteOrder();
+
+ /**
+ * Reads a byte from the stream.
+ *
+ * @return the byte of the stream, or -1 for EOF indicating.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int read() throws IOException;
+
+ /**
+ * Reads number of bytes which is equal to the specified array's length
+ * and stores a result to this array.
+ *
+ * @param b the byte array.
+ *
+ * @return the number of read bytes, or -1 indicated EOF.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int read(byte[] b) throws IOException;
+
+ /**
+ * Reads the number of bytes specified by len parameter from
+ * the stream and stores a result to the specified array
+ * with the specified offset.
+ *
+ * @param b the byte array.
+ * @param off the offset.
+ * @param len the number of bytes to be read.
+ *
+ * @return the number of read bytes, or -1 indicated EOF.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int read(byte[] b, int off, int len) throws IOException;
+
+ /**
+ * Reads the number of bytes specified by len parameter
+ * from the stream, and modifies the specified IIOByteBuffer
+ * with the byte array, offset, and length.
+ *
+ * @param buf the IIOByteBuffer.
+ * @param len the number of bytes to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readBytes(IIOByteBuffer buf, int len) throws IOException;
+
+ /**
+ * Reads a byte from the stream and returns a boolean true value
+ * if it is non zero, false if it is zero.
+ *
+ * @return a boolean value for read byte.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ boolean readBoolean() throws IOException;
+
+ /**
+ * Reads a byte from the stream and returns its value
+ * as signed byte.
+ *
+ * @return a signed byte value for read byte.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ byte readByte() throws IOException;
+
+ /**
+ * Reads a byte from the stream and returns its value
+ * as int.
+ *
+ * @return a unsigned byte value for read byte as int.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int readUnsignedByte() throws IOException;
+
+ /**
+ * Reads 2 bytes from the stream, and returns the result
+ * as a short.
+ *
+ * @return the signed short value from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ short readShort() throws IOException;
+
+ /**
+ * Reads 2 bytes from the stream and returns its value
+ * as an unsigned short.
+ *
+ * @return a unsigned short value coded in an int.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int readUnsignedShort() throws IOException;
+
+ /**
+ * Reads 2 bytes from the stream and returns their
+ * unsigned char value.
+ *
+ * @return the unsigned char value.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ char readChar() throws IOException;
+
+ /**
+ * Reads 4 bytes from the stream, and returns the result
+ * as an int.
+ *
+ * @return the signed int value from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int readInt() throws IOException;
+
+ /**
+ * Reads 4 bytes from the stream and returns its value
+ * as long.
+ *
+ * @return a unsigned int value as long.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long readUnsignedInt() throws IOException;
+
+ /**
+ * Reads 8 bytes from the stream, and returns the result
+ * as a long.
+ *
+ * @return the long value from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long readLong() throws IOException;
+
+ /**
+ * Reads 4 bytes from the stream, and returns the result
+ * as a float.
+ *
+ * @return the float value from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ float readFloat() throws IOException;
+
+ /**
+ * Reads 8 bytes from the stream, and returns the result
+ * as a double.
+ *
+ * @return the double value from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ double readDouble() throws IOException;
+
+ /**
+ * Reads a line from the stream.
+ *
+ * @return the string contained the line from the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ String readLine() throws IOException;
+
+ /**
+ * Reads bytes from the stream in a string that has been encoded
+ * in a modified UTF-8 format.
+ *
+ * @return the string read from stream and modified UTF-8 format.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ String readUTF() throws IOException;
+
+ /**
+ * Reads the specified number of bytes from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param b the byte array.
+ * @param off the offset.
+ * @param len the number of bytes to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(byte[] b, int off, int len) throws IOException;
+
+ /**
+ * Reads number of bytes from the stream which is equal to
+ * the specified array's length, and stores them into
+ * this array.
+ *
+ * @param b the byte array.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(byte[] b) throws IOException;
+
+ /**
+ * Reads the specified number of shorts from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param s the short array.
+ * @param off the offset.
+ * @param len the number of shorts to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(short[] s, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of chars from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param c the char array.
+ * @param off the offset.
+ * @param len the number of chars to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(char[] c, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of ints from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param i the int array.
+ * @param off the offset.
+ * @param len the number of ints to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(int[] i, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of longs from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param l the long array.
+ * @param off the offset.
+ * @param len the number of longs to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(long[] l, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of floats from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param f the float array.
+ * @param off the offset.
+ * @param len the number of floats to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(float[] f, int off, int len) throws IOException;
+
+ /**
+ * Reads the specified number of doubles from the stream,
+ * and stores the result into the specified array starting at
+ * the specified index offset.
+ *
+ * @param d the double array.
+ * @param off the offset.
+ * @param len the number of doubles to be read.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void readFully(double[] d, int off, int len) throws IOException;
+
+ /**
+ * Gets the stream position.
+ *
+ * @return the stream position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long getStreamPosition() throws IOException;
+
+ /**
+ * Gets the bit offset.
+ *
+ * @return the bit offset.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int getBitOffset() throws IOException;
+
+ /**
+ * Sets the bit offset to an integer between 0 and 7.
+ *
+ * @param bitOffset the bit offset.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void setBitOffset(int bitOffset) throws IOException;
+
+ /**
+ * Reads a bit from the stream and returns the value 0 or 1.
+ *
+ * @return the value of single bit: 0 or 1.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int readBit() throws IOException;
+
+ /**
+ * Read the specified number of bits and returns their values as long.
+ *
+ * @param numBits the number of bits to be read.
+ *
+ * @return the bit string as a long.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long readBits(int numBits) throws IOException;
+
+ /**
+ * Returns the length of the stream.
+ *
+ * @return the length of the stream, or -1 if unknown.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long length() throws IOException;
+
+ /**
+ * Skipes the specified number of bytes by moving stream position.
+ *
+ * @param n the number of bytes.
+ *
+ * @return the actual skipped number of bytes.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ int skipBytes(int n) throws IOException;
+
+ /**
+ * Skipes the specified number of bytes by moving stream position.
+ *
+ * @param n the number of bytes.
+ *
+ * @return the actual skipped number of bytes.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ long skipBytes(long n) throws IOException;
+
+ /**
+ * Sets the current stream position to the specified location.
+ *
+ * @param pos a file pointer position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void seek(long pos) throws IOException;
+
+ /**
+ * Marks a position in the stream to be returned to by a subsequent
+ * call to reset.
+ */
+ void mark();
+
+ /**
+ * Returns the file pointer to its previous position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void reset() throws IOException;
+
+ /**
+ * Flushes the initial position in this stream prior to the
+ * specified stream position.
+ *
+ * @param pos the position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void flushBefore(long pos) throws IOException;
+
+ /**
+ * Flushes the initial position in this stream prior to the
+ * current stream position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void flush() throws IOException;
+
+ /**
+ * Gets the flushed position.
+ *
+ * @return the flushed position.
+ */
+ long getFlushedPosition();
+
+ /**
+ * Returns true if this ImageInputStream caches data in order
+ * to allow seeking backwards.
+ *
+ * @return true if this ImageInputStream caches data in order
+ * to allow seeking backwards, false otherwise.
+ */
+ boolean isCached();
+
+ /**
+ * Returns true if this ImageInputStream caches data in order
+ * to allow seeking backwards, and keeps it in memory.
+ *
+ * @return true if this ImageInputStream caches data in order
+ * to allow seeking backwards, and keeps it in memory.
+ */
+ boolean isCachedMemory();
+
+ /**
+ * Returns true if this ImageInputStream caches data in order
+ * to allow seeking backwards, and keeps it in a temporary file.
+ *
+ * @return true if this ImageInputStream caches data in order
+ * to allow seeking backwards, and keeps it in a temporary file.
+ */
+ boolean isCachedFile();
+
+ /**
+ * Closes this stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void close() throws IOException;
+}
diff --git a/awt/javax/imageio/stream/ImageInputStreamImpl.java b/awt/javax/imageio/stream/ImageInputStreamImpl.java
new file mode 100644
index 0000000..83ac13a
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageInputStreamImpl.java
@@ -0,0 +1,394 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.stream;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+/**
+ * The ImageInputStreamImpl abstract class implements
+ * the ImageInputStream interface.
+ */
+public abstract class ImageInputStreamImpl implements ImageInputStream {
+
+ /** The byte order. */
+ protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
+
+ /** The stream position. */
+ protected long streamPos = 0;
+
+ /** The flushed position. */
+ protected long flushedPos = 0;
+
+ /** The bit offset. */
+ protected int bitOffset = 0;
+
+ /** The closed. */
+ private boolean closed = false;
+
+ /** The position stack. */
+ private final PositionStack posStack = new PositionStack();
+
+ /**
+ * Instantiates a new ImageInputStreamImpl.
+ */
+ public ImageInputStreamImpl() {}
+
+ /**
+ * Check if the stream is closed and if true, throws an IOException.
+ *
+ * @throws IOException Signals that the stream is closed.
+ */
+ protected final void checkClosed() throws IOException {
+ if (closed) {
+ throw new IOException("stream is closed");
+ }
+ }
+
+ public void setByteOrder(ByteOrder byteOrder) {
+ this.byteOrder = byteOrder;
+ }
+
+ public ByteOrder getByteOrder() {
+ return byteOrder;
+ }
+
+ public abstract int read() throws IOException;
+
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ public abstract int read(byte[] b, int off, int len) throws IOException;
+
+ public void readBytes(IIOByteBuffer buf, int len) throws IOException {
+ if (buf == null) {
+ throw new NullPointerException("buffer is NULL");
+ }
+
+ byte[] b = new byte[len];
+ len = read(b, 0, b.length);
+
+ buf.setData(b);
+ buf.setOffset(0);
+ buf.setLength(len);
+ }
+
+ public boolean readBoolean() throws IOException {
+ int b = read();
+ if (b < 0) {
+ throw new EOFException("EOF reached");
+ }
+ return b != 0;
+ }
+
+ public byte readByte() throws IOException {
+ int b = read();
+ if (b < 0) {
+ throw new EOFException("EOF reached");
+ }
+ return (byte) b;
+ }
+
+ public int readUnsignedByte() throws IOException {
+ int b = read();
+ if (b < 0) {
+ throw new EOFException("EOF reached");
+ }
+ return b;
+ }
+
+ public short readShort() throws IOException {
+ int b1 = read();
+ int b2 = read();
+
+ if (b1 < 0 || b2 < 0) {
+ throw new EOFException("EOF reached");
+ }
+
+ return byteOrder == ByteOrder.BIG_ENDIAN ?
+ (short) ((b1 << 8) | (b2 & 0xff)) :
+ (short) ((b2 << 8) | (b1 & 0xff));
+ }
+
+ public int readUnsignedShort() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public char readChar() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public int readInt() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long readUnsignedInt() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long readLong() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public float readFloat() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public double readDouble() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public String readLine() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public String readUTF() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(byte[] b, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(byte[] b) throws IOException {
+ readFully(b, 0, b.length);
+ }
+
+ public void readFully(short[] s, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(char[] c, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(int[] i, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(long[] l, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(float[] f, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void readFully(double[] d, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long getStreamPosition() throws IOException {
+ checkClosed();
+ return streamPos;
+ }
+
+ public int getBitOffset() throws IOException {
+ checkClosed();
+ return bitOffset;
+ }
+
+ public void setBitOffset(int bitOffset) throws IOException {
+ checkClosed();
+ this.bitOffset = bitOffset;
+ }
+
+ public int readBit() throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long readBits(int numBits) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long length() {
+ return -1L;
+ }
+
+ public int skipBytes(int n) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public long skipBytes(long n) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void seek(long pos) throws IOException {
+ checkClosed();
+ if (pos < getFlushedPosition()) {
+ throw new IllegalArgumentException("trying to seek before flushed pos");
+ }
+ bitOffset = 0;
+ streamPos = pos;
+ }
+
+ public void mark() {
+ try {
+ posStack.push(getStreamPosition());
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Stream marking error");
+ }
+ }
+
+ public void reset() throws IOException {
+ //-- TODO bit pos
+ if (!posStack.isEmpty()) {
+ long p = posStack.pop();
+ if (p < flushedPos) {
+ throw new IOException("marked position lies in the flushed portion of the stream");
+ }
+ seek(p);
+ }
+ }
+
+ public void flushBefore(long pos) throws IOException {
+ if (pos > getStreamPosition()) {
+ throw new IndexOutOfBoundsException("Trying to flush outside of current position");
+ }
+ if (pos < flushedPos) {
+ throw new IndexOutOfBoundsException("Trying to flush within already flushed portion");
+ }
+ flushedPos = pos;
+ //-- TODO implement
+ }
+
+ public void flush() throws IOException {
+ flushBefore(getStreamPosition());
+ }
+
+ public long getFlushedPosition() {
+ return flushedPos;
+ }
+
+ public boolean isCached() {
+ return false; //def
+ }
+
+ public boolean isCachedMemory() {
+ return false; //def
+ }
+
+ public boolean isCachedFile() {
+ return false; //def
+ }
+
+ public void close() throws IOException {
+ checkClosed();
+ closed = true;
+
+ }
+
+ /**
+ * Finalizes this object.
+ *
+ * @throws Throwable if an error occurs.
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ if (!closed) {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+
+ /**
+ * The Class PositionStack.
+ */
+ private static class PositionStack {
+
+ /** The Constant SIZE. */
+ private static final int SIZE = 10;
+
+ /** The values. */
+ private long[] values = new long[SIZE];
+
+ /** The pos. */
+ private int pos = 0;
+
+
+ /**
+ * Push.
+ *
+ * @param v the v
+ */
+ void push(long v) {
+ if (pos >= values.length) {
+ ensure(pos+1);
+ }
+ values[pos++] = v;
+ }
+
+ /**
+ * Pop.
+ *
+ * @return the long
+ */
+ long pop() {
+ return values[--pos];
+ }
+
+ /**
+ * Checks if is empty.
+ *
+ * @return true, if is empty
+ */
+ boolean isEmpty() {
+ return pos == 0;
+ }
+
+ /**
+ * Ensure.
+ *
+ * @param size the size
+ */
+ private void ensure(int size) {
+ long[] arr = new long[Math.max(2 * values.length, size)];
+ System.arraycopy(values, 0, arr, 0, values.length);
+ values = arr;
+ }
+ }
+}
diff --git a/awt/javax/imageio/stream/ImageOutputStream.java b/awt/javax/imageio/stream/ImageOutputStream.java
new file mode 100644
index 0000000..e59b69d
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageOutputStream.java
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package javax.imageio.stream;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * The ImageOutputStream represents output stream interface that is
+ * used by ImageWriters.
+ */
+public interface ImageOutputStream extends DataOutput, ImageInputStream {
+
+ /**
+ * Writes a single byte to the stream at the current position.
+ *
+ * @param b the int value, of which the 8 lowest bits
+ * will be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void write(int b) throws IOException;
+
+ /**
+ * Writes the bytes array to the stream.
+ *
+ * @param b the byte array to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void write(byte[] b) throws IOException;
+
+ /**
+ * Writes a number of bytes from the specified byte array
+ * beggining from the specified offset.
+ *
+ * @param b the byte array.
+ * @param off the offset.
+ * @param len the number of bytes to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void write(byte[] b, int off, int len) throws IOException;
+
+ /**
+ * Writes the specified boolean value to the stream, 1 if it is true,
+ * 0 if it is false.
+ *
+ * @param b the boolean value to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeBoolean(boolean b) throws IOException;
+
+ /**
+ * Writes the 8 lowest bits of the specified int value to the stream.
+ *
+ * @param b the specified int value.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeByte(int b) throws IOException;
+
+ /**
+ * Writes a short value to the output stream.
+ *
+ * @param v the short value to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeShort(int v) throws IOException;
+
+ /**
+ * Writes the 16 lowest bits of the specified int value to the stream.
+ *
+ * @param v the specified int value.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeChar(int v) throws IOException;
+
+ /**
+ * Writes an integer value to the output stream.
+ *
+ * @param v the integer value to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeInt(int v) throws IOException;
+
+ /**
+ * Write long.
+ *
+ * @param v the long value
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeLong(long v) throws IOException;
+
+ /**
+ * Writes a float value to the output stream.
+ *
+ * @param v the float which contains value to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeFloat(float v) throws IOException;
+
+ /**
+ * Writes a double value to the output stream.
+ *
+ * @param v the double which contains value to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeDouble(double v) throws IOException;
+
+ /**
+ * Writes the specified string to the stream.
+ *
+ * @param s the string to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeBytes(String s) throws IOException;
+
+ /**
+ * Writes the specified String to the output stream.
+ *
+ * @param s the String to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeChars(String s) throws IOException;
+
+ /**
+ * Writes 2 bytes to the output stream in
+ * the modified UTF-8 representation of every character of
+ * the specified string.
+ *
+ * @param s the specified string to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeUTF(String s) throws IOException;
+
+ /**
+ * Flushes the initial position in this stream prior to the
+ * specified stream position.
+ *
+ * @param pos the position.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void flushBefore(long pos) throws IOException;
+
+
+ /**
+ * Writes a len number of short values from the specified array
+ * to the stream.
+ *
+ * @param s the shorts array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeShorts(short[] s, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of chars to the stream.
+ *
+ * @param c the char array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeChars(char[] c, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of int values from the specified array
+ * to the stream.
+ *
+ * @param i the int array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeInts(int[] i, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of long values from the specified array
+ * to the stream.
+ *
+ * @param l the long array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeLongs(long[] l, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of float values from the specified array
+ * to the stream.
+ *
+ * @param f the float array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeFloats(float[] f, int off, int len) throws IOException;
+
+ /**
+ * Writes a len number of double values from the specified array
+ * to the stream.
+ *
+ * @param d the double array to be written.
+ * @param off the offset in the char array.
+ * @param len the length of chars to be written.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeDoubles(double[] d, int off, int len) throws IOException;
+
+ /**
+ * Writes a single bit at the current position.
+ *
+ * @param bit the an int whose least significant bit is to be
+ * written to the stream.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeBit(int bit) throws IOException;
+
+ /**
+ * Writes a sequence of bits beggining from the current position.
+ *
+ * @param bits a long value containing the bits to be written,
+ * starting with the bit in position numBits - 1 down to the
+ * least significant bit.
+ * @param numBits the number of significant bit ,
+ * it can be between 0 and 64.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ void writeBits(long bits, int numBits) throws IOException;
+
+}
diff --git a/awt/javax/imageio/stream/ImageOutputStreamImpl.java b/awt/javax/imageio/stream/ImageOutputStreamImpl.java
new file mode 100644
index 0000000..c3d80fa
--- /dev/null
+++ b/awt/javax/imageio/stream/ImageOutputStreamImpl.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio.stream;
+
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+/*
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+
+/**
+ * The ImageOutputStreamImpl abstract class implements
+ * the ImageOutputStream interface.
+ */
+public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl
+ implements ImageOutputStream {
+
+ /**
+ * Instantiates a new ImageOutputStreamImpl.
+ */
+ public ImageOutputStreamImpl() {}
+
+ public abstract void write(int b) throws IOException;
+
+ public void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ public abstract void write(byte[] b, int off, int len) throws IOException;
+
+ public void writeBoolean(boolean v) throws IOException {
+ write(v ? 1 : 0);
+ }
+
+ public void writeByte(int v) throws IOException {
+ write(v);
+ }
+
+ public void writeShort(int v) throws IOException {
+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
+
+ } else {
+
+ }
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeChar(int v) throws IOException {
+ writeShort(v);
+ }
+
+ public void writeInt(int v) throws IOException {
+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
+
+ } else {
+
+ }
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeLong(long v) throws IOException {
+ if (byteOrder == ByteOrder.BIG_ENDIAN) {
+
+ } else {
+
+ }
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeFloat(float v) throws IOException {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ public void writeDouble(double v) throws IOException {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ public void writeBytes(String s) throws IOException {
+ write(s.getBytes());
+ }
+
+ public void writeChars(String s) throws IOException {
+ char[] chs = s.toCharArray();
+ writeChars(chs, 0, chs.length);
+ }
+
+ public void writeUTF(String s) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeShorts(short[] s, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeChars(char[] c, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeInts(int[] i, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeLongs(long[] l, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeFloats(float[] f, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeDoubles(double[] d, int off, int len) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeBit(int bit) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ public void writeBits(long bits, int numBits) throws IOException {
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Flushes the bits. This method should be called in the write
+ * methods by subclasses.
+ *
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ protected final void flushBits() throws IOException {
+ if (bitOffset == 0) {
+ return;
+ }
+
+ //-- TODO implement
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+}
diff --git a/awt/javax/imageio/stream/MemoryCacheImageInputStream.java b/awt/javax/imageio/stream/MemoryCacheImageInputStream.java
new file mode 100644
index 0000000..a3d470b
--- /dev/null
+++ b/awt/javax/imageio/stream/MemoryCacheImageInputStream.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.stream;
+
+import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * The MemoryCacheImageInputStream class implements ImageInputStream
+ * using a memory buffer for caching the data.
+ */
+public class MemoryCacheImageInputStream extends ImageInputStreamImpl {
+
+ /** The is. */
+ private InputStream is;
+
+ /** The ramc. */
+ private RandomAccessMemoryCache ramc = new RandomAccessMemoryCache();
+
+ /**
+ * Instantiates a new MemoryCacheImageInputStream
+ * which reads from the specified InputStream.
+ *
+ * @param stream the InputStream to be read.
+ */
+ public MemoryCacheImageInputStream(InputStream stream) {
+ if (stream == null) {
+ throw new IllegalArgumentException("stream == null!");
+ }
+ is = stream;
+ }
+
+ @Override
+ public int read() throws IOException {
+ bitOffset = 0;
+
+ if (streamPos >= ramc.length()) {
+ int count = (int)(streamPos - ramc.length() + 1);
+ int bytesAppended = ramc.appendData(is, count);
+
+ if (bytesAppended < count) {
+ return -1;
+ }
+ }
+
+ int res = ramc.getData(streamPos);
+ if (res >= 0) {
+ streamPos++;
+ }
+ return res;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ bitOffset = 0;
+
+ if (streamPos >= ramc.length()) {
+ int count = (int)(streamPos - ramc.length() + len);
+ ramc.appendData(is, count);
+ }
+
+ int res = ramc.getData(b, off, len, streamPos);
+ if (res > 0) {
+ streamPos += res;
+ }
+ return res;
+ }
+
+ @Override
+ public boolean isCached() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedFile() {
+ return false;
+ }
+
+ @Override
+ public boolean isCachedMemory() {
+ return true;
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ ramc.close();
+ }
+
+ @Override
+ public void flushBefore(long pos) throws IOException {
+ super.flushBefore(pos);
+ ramc.freeBefore(getFlushedPosition());
+ }
+}
diff --git a/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java b/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java
new file mode 100644
index 0000000..96ded43
--- /dev/null
+++ b/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package javax.imageio.stream;
+
+import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+
+/**
+ * The MemoryCacheImageOutputStream class implements ImageOutputStream
+ * using a memory buffer for caching the data.
+ */
+public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl {
+
+ /** The os. */
+ OutputStream os;
+
+ /** The ramc. */
+ RandomAccessMemoryCache ramc = new RandomAccessMemoryCache();
+
+ /**
+ * Instantiates a new MemoryCacheImageOutputStream
+ * which writes to the specified OutputStream.
+ *
+ * @param stream the OutputStream.
+ */
+ public MemoryCacheImageOutputStream(OutputStream stream) {
+ if (stream == null) {
+ throw new IllegalArgumentException("stream == null!");
+ }
+ os = stream;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ flushBits(); // See the flushBits method description
+
+ ramc.putData(b, streamPos);
+ streamPos++;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ flushBits(); // See the flushBits method description
+
+ ramc.putData(b, off, len, streamPos);
+ streamPos += len;
+ }
+
+ @Override
+ public int read() throws IOException {
+ bitOffset = 0;
+
+ int res = ramc.getData(streamPos);
+ if (res >= 0) {
+ streamPos++;
+ }
+ return res;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ bitOffset = 0;
+
+ int res = ramc.getData(b, off, len, streamPos);
+ if (res > 0) {
+ streamPos += res;
+ }
+ return res;
+ }
+
+ @Override
+ public long length() {
+ return ramc.length();
+ }
+
+ @Override
+ public boolean isCached() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedMemory() {
+ return true;
+ }
+
+ @Override
+ public boolean isCachedFile() {
+ return false;
+ }
+
+ @Override
+ public void close() throws IOException {
+ flushBefore(length());
+ super.close();
+ ramc.close();
+ }
+
+ @Override
+ public void flushBefore(long pos) throws IOException {
+ long flushedPosition = getFlushedPosition();
+ super.flushBefore(pos);
+
+ long newFlushedPosition = getFlushedPosition();
+ int nBytes = (int)(newFlushedPosition - flushedPosition);
+
+ ramc.getData(os, nBytes, flushedPosition);
+ ramc.freeBefore(newFlushedPosition);
+
+ os.flush();
+ }
+}
diff --git a/awt/org/apache/harmony/awt/ChoiceStyle.java b/awt/org/apache/harmony/awt/ChoiceStyle.java
new file mode 100644
index 0000000..93b7aad
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ChoiceStyle.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+/**
+ * ChoiceStyle.
+ * Is used to define custom choice properties:
+ * width and x screen coordinate of the list popup window.
+ */
+public interface ChoiceStyle {
+
+ int getPopupX(int x, int width, int choiceWidth, int screenWidth);
+ int getPopupWidth(int choiceWidth);
+
+}
diff --git a/awt/org/apache/harmony/awt/ClipRegion.java b/awt/org/apache/harmony/awt/ClipRegion.java
new file mode 100644
index 0000000..c89a81d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ClipRegion.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov, Anton Avtamonov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+import java.awt.Component;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class ClipRegion extends Rectangle {
+ private final MultiRectArea clip;
+
+ public ClipRegion(final MultiRectArea clip) {
+ this.clip = new MultiRectArea(clip);
+ setBounds(clip.getBounds());
+ }
+
+ public MultiRectArea getClip() {
+ return clip;
+ }
+
+ @Override
+ public String toString() {
+ String str = clip.toString();
+ int i = str.indexOf('[');
+ str = str.substring(i);
+ if (clip.getRectCount() == 1) {
+ str = str.substring(1, str.length() - 1);
+ }
+ return getClass().getName() + str;
+ }
+
+
+ public void convertRegion(final Component child, final Component parent) {
+ convertRegion(child, clip, parent);
+ }
+
+ public void intersect(final Rectangle rect) {
+ clip.intersect(rect);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return clip.isEmpty();
+ }
+
+ public static void convertRegion(final Component child,
+ final MultiRectArea region,
+ final Component parent) {
+ int x = 0, y = 0;
+ Component c = child;
+ //???AWT
+ /*
+ for (; c != null && c != parent; c = c.getParent()) {
+ x += c.getX();
+ y += c.getY();
+ }
+ */
+ if (c == null) {
+ // awt.51=Component expected to be a parent
+ throw new IllegalArgumentException(Messages.getString("awt.51")); //$NON-NLS-1$
+ }
+ region.translate(x, y);
+ }
+}
diff --git a/awt/org/apache/harmony/awt/ComponentInternals.java b/awt/org/apache/harmony/awt/ComponentInternals.java
new file mode 100644
index 0000000..c359784
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ComponentInternals.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+//???AWT
+//import java.awt.Component;
+//import java.awt.Container;
+//import java.awt.Dialog;
+import java.awt.Dimension;
+//import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+//import java.awt.Window;
+//import java.awt.Choice;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+//import org.apache.harmony.awt.text.TextFieldKit;
+//import org.apache.harmony.awt.text.TextKit;
+//import org.apache.harmony.awt.wtk.NativeWindow;
+
+import org.apache.harmony.luni.util.NotImplementedException;
+
+/**
+ * The accessor to AWT private API
+ */
+public abstract class ComponentInternals {
+
+ /**
+ * @return the ComponentInternals instance to serve the requests
+ */
+ public static ComponentInternals getComponentInternals() {
+ return ContextStorage.getComponentInternals();
+ }
+
+ /**
+ * This method must be called by AWT to establish the connection
+ * @param internals - implementation of ComponentInternals created by AWT
+ */
+ public static void setComponentInternals(ComponentInternals internals) {
+ ContextStorage.setComponentInternals(internals);
+ }
+
+ /**
+ * The accessor to native resource connected to a component.
+ * It returns non-<code>null</code> value only if component
+ * already has the native resource
+ */
+ //public abstract NativeWindow getNativeWindow(Component component);
+
+ /**
+ * Connect Window object to existing native resource
+ * @param nativeWindowId - id of native window to attach
+ * @return Window object with special behaviour that
+ * restricts manupulation with that window
+ */
+ //public abstract Window attachNativeWindow(long nativeWindowId);
+
+ /**
+ * Start mouse grab in "client" mode.
+ * All mouse events in AWT components will be reported as usual,
+ * mouse events that occured outside of AWT components will be sent to
+ * the window passed as grabWindow parameter. When mouse grab is canceled
+ * (because of click in non-AWT window or by task switching)
+ * the whenCanceled callback is called
+ *
+ * @param grabWindow - window that will own the grab
+ * @param whenCanceled - callback called when grab is canceled by user's action
+ */
+ //public abstract void startMouseGrab(Window grabWindow, Runnable whenCanceled);
+
+ /**
+ * End mouse grab and resume normal processing of mouse events
+ */
+ //public abstract void endMouseGrab();
+
+ /**
+ * Set the <code>popup</code> flag of the window to true.
+ * This window won't be controlled by window manager on Linux.
+ * Call this method before the window is shown first time
+ * @param window - the window that should become popup one
+ */
+ //public abstract void makePopup(Window window);
+
+ /**
+ * This method must be called by Graphics at the beginning of drawImage()
+ * to store image drawing parameters (defined by application developer) in component
+ *
+ * @param comp - component that draws the image
+ * @param image - image to be drawn
+ * @param destLocation - location of the image upon the component's surface. Never null.
+ * @param destSize - size of the component's area to be filled with the image.
+ * Equals to null if size parameters omitted in drawImage.
+ * @param source - area of the image to be drawn on the component.
+ * Equals to null if src parameters omitted in drawImage.
+ */
+ /*
+ public abstract void onDrawImage(Component comp, Image image, Point destLocation,
+ Dimension destSize, Rectangle source);
+*/
+ /**
+ * Sets system's caret position.
+ * This method should be called by text component to synchronize our caret position
+ * with system's caret position.
+ * @param x
+ * @param y
+ */
+ //public abstract void setCaretPos(Component c, int x, int y);
+
+ /**
+ * NEVER USE IT. FORGET IT. IT DOES NOT EXIST.
+ * See Toolkit.unsafeInvokeAndWait(Runnable).
+ *
+ * Accessor for Toolkit.unsafeInvokeAndWait(Runnable) method.
+ * For use in exceptional cases only.
+ * Read comments for Toolkit.unsafeInvokeAndWait(Runnable) before use.
+ */
+ /*
+ public abstract void unsafeInvokeAndWait(Runnable runnable)
+ throws InterruptedException, InvocationTargetException;
+
+ public abstract TextKit getTextKit(Component comp);
+
+ public abstract void setTextKit(Component comp, TextKit kit);
+
+ public abstract TextFieldKit getTextFieldKit(Component comp);
+
+ public abstract void setTextFieldKit(Component comp, TextFieldKit kit);
+*/
+ /**
+ * Terminate event dispatch thread, completely destroy AWT context.<br>
+ * Intended for multi-context mode, in single-context mode does nothing.
+ *
+ */
+ public abstract void shutdown();
+
+ /**
+ * Sets mouse events preprocessor for event queue
+ */
+ //public abstract void setMouseEventPreprocessor(MouseEventPreprocessor preprocessor);
+
+ /**
+ * Create customized Choice using style
+ */
+ //public abstract Choice createCustomChoice(ChoiceStyle style);
+
+ //public abstract Insets getNativeInsets(Window w);
+
+ /**
+ * Region to be repainted (could be null). Use this in overridden repaint()
+ */
+ //public abstract MultiRectArea getRepaintRegion(Component c);
+
+ //public abstract MultiRectArea subtractPendingRepaintRegion(Component c, MultiRectArea mra);
+
+ /**
+ * Returns true if the window was at least once painted due to native paint events
+ */
+ //public abstract boolean wasPainted(Window w);
+
+ /**
+ * The component's region hidden behind top-level windows
+ * (belonging to both this Java app and all other apps), and behind
+ * heavyweight components overlapping with passed component
+ */
+ //public abstract MultiRectArea getObscuredRegion(Component c);
+
+ /**
+ * An accessor to Container.addObscuredRegions() method
+ * @see java.awt.Container#addObscuredRegions(MultiRectArea, Component)
+ */
+ //public abstract void addObscuredRegions(MultiRectArea mra, Component c, Container container);
+
+ /**
+ * Makes it possible to call protected Toolkit.setDesktopProperty()
+ * method from any class outside of java.awt package
+ */
+ public abstract void setDesktopProperty(String name, Object value);
+
+ /**
+ * Makes it possible to start/stop dialog modal loop
+ * from anywhere outside of java.awt package
+ */
+ //public abstract void runModalLoop(Dialog dlg);
+ //public abstract void endModalLoop(Dialog dlg);
+
+ /**
+ * Sets component's visible flag only
+ * (the component is not actually shown/hidden)
+ */
+ //public abstract void setVisibleFlag(Component comp, boolean visible);
+
+}
diff --git a/awt/org/apache/harmony/awt/ContextStorage.java b/awt/org/apache/harmony/awt/ContextStorage.java
new file mode 100644
index 0000000..d44648a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ContextStorage.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+import java.awt.*;
+
+//???AWT
+//import org.apache.harmony.awt.datatransfer.*;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.awt.wtk.*;
+
+
+public final class ContextStorage {
+
+ private static volatile boolean multiContextMode = false;
+ private volatile boolean shutdownPending = false;
+
+ private static final ContextStorage globalContext = new ContextStorage();
+
+ private Toolkit toolkit;
+ private ComponentInternals componentInternals;
+ //???AWT: private DTK dtk;
+ private WTK wtk;
+ private GraphicsEnvironment graphicsEnvironment;
+
+ private class ContextLock {}
+ private final Object contextLock = new ContextLock();
+ private final Synchronizer synchronizer = new Synchronizer();
+
+ public static void activateMultiContextMode() {
+ // TODO: checkPermission
+ multiContextMode = true;
+ }
+
+ public static void setDefaultToolkit(Toolkit newToolkit) {
+ // TODO: checkPermission
+ getCurrentContext().toolkit = newToolkit;
+ }
+
+ public static Toolkit getDefaultToolkit() {
+ return getCurrentContext().toolkit;
+ }
+
+ //???AWT
+ /*
+ public static void setDTK(DTK dtk) {
+ // TODO: checkPermission
+ getCurrentContext().dtk = dtk;
+ }
+
+ public static DTK getDTK() {
+ return getCurrentContext().dtk;
+ }
+ */
+
+ public static Synchronizer getSynchronizer() {
+ return getCurrentContext().synchronizer;
+ }
+
+ public static ComponentInternals getComponentInternals() {
+ return getCurrentContext().componentInternals;
+ }
+
+ static void setComponentInternals(ComponentInternals internals) {
+ // TODO: checkPermission
+ getCurrentContext().componentInternals = internals;
+ }
+
+ public static Object getContextLock() {
+ return getCurrentContext().contextLock;
+ }
+
+ public static WindowFactory getWindowFactory() {
+ return getCurrentContext().wtk.getWindowFactory();
+ }
+
+ public static void setWTK(WTK wtk) {
+ getCurrentContext().wtk = wtk;
+ }
+
+ public static NativeIM getNativeIM() {
+ return getCurrentContext().wtk.getNativeIM();
+ }
+
+ public static NativeEventQueue getNativeEventQueue() {
+ return getCurrentContext().wtk.getNativeEventQueue();
+ }
+
+ public static GraphicsEnvironment getGraphicsEnvironment() {
+ return getCurrentContext().graphicsEnvironment;
+ }
+
+ public static void setGraphicsEnvironment(GraphicsEnvironment environment) {
+ getCurrentContext().graphicsEnvironment = environment;
+ }
+
+ private static ContextStorage getCurrentContext() {
+ return multiContextMode ? getContextThreadGroup().context : globalContext;
+ }
+
+ private static ContextThreadGroup getContextThreadGroup() {
+
+ Thread thread = Thread.currentThread();
+ ThreadGroup group = thread.getThreadGroup();
+ while (group != null) {
+ if (group instanceof ContextThreadGroup) {
+ return (ContextThreadGroup)group;
+ }
+ group = group.getParent();
+ }
+ // awt.59=Application has run out of context thread group
+ throw new RuntimeException(Messages.getString("awt.59")); //$NON-NLS-1$
+ }
+
+ public static boolean shutdownPending() {
+ return getCurrentContext().shutdownPending;
+ }
+
+ void shutdown() {
+ if (!multiContextMode) {
+ return;
+ }
+ shutdownPending = true;
+
+ //???AWT: componentInternals.shutdown();
+
+ synchronized(contextLock) {
+ toolkit = null;
+ componentInternals = null;
+ //???AWT: dtk = null;
+ wtk = null;
+ graphicsEnvironment = null;
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/ContextThreadGroup.java b/awt/org/apache/harmony/awt/ContextThreadGroup.java
new file mode 100644
index 0000000..4f0af52
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ContextThreadGroup.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+public class ContextThreadGroup extends ThreadGroup {
+
+ final ContextStorage context = new ContextStorage();
+
+ public ContextThreadGroup(String name) {
+ super(name);
+ }
+
+ public void dispose() {
+ context.shutdown();
+ }
+}
diff --git a/awt/org/apache/harmony/awt/ListenerList.java b/awt/org/apache/harmony/awt/ListenerList.java
new file mode 100644
index 0000000..f5c55f1
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ListenerList.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.awt;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * List of AWT listeners. It is for 3 purposes.
+ * 1. To support list modification from listeners
+ * 2. To ensure call for all listeners as atomic operation
+ * 3. To support system listeners that are needed for built-in AWT components
+ */
+public class ListenerList<T extends EventListener> implements Serializable {
+ private static final long serialVersionUID = 9180703263299648154L;
+
+ private transient ArrayList<T> systemList;
+ private transient ArrayList<T> userList;
+
+ public ListenerList() {
+ super();
+ }
+
+ /**
+ * Adds system listener to this list.
+ *
+ * @param listener - listener to be added.
+ */
+ public void addSystemListener(T listener) {
+ if (systemList == null) {
+ systemList = new ArrayList<T>();
+ }
+ systemList.add(listener);
+ }
+
+ /**
+ * Adds user (public) listener to this list.
+ *
+ * @param listener - listener to be added.
+ */
+ public void addUserListener(T listener) {
+ if (listener == null) {
+ return;
+ }
+ // transactionally replace old list
+ synchronized (this) {
+ if (userList == null) {
+ userList = new ArrayList<T>();
+ userList.add(listener);
+ return;
+ }
+ ArrayList<T> newList = new ArrayList<T>(userList);
+ newList.add(listener);
+ userList = newList;
+ }
+ }
+
+ /**
+ * Removes user (public) listener to this list.
+ *
+ * @param listener - listener to be removed.
+ */
+ public void removeUserListener(Object listener) {
+ if (listener == null) {
+ return;
+ }
+ // transactionally replace old list
+ synchronized (this) {
+ if (userList == null || !userList.contains(listener)) {
+ return;
+ }
+ ArrayList<T> newList = new ArrayList<T>(userList);
+ newList.remove(listener);
+ userList = (newList.size() > 0 ? newList : null);
+ }
+ }
+
+ /**
+ * Gets all user (public) listeners in one array.
+ *
+ * @param emptyArray - empty array, it's for deriving particular listeners class.
+ * @return array of all user listeners.
+ */
+ public <AT> AT[] getUserListeners(AT[] emptyArray){
+ synchronized (this) {
+ return (userList != null ? userList.toArray(emptyArray) : emptyArray);
+
+ }
+ }
+
+ /**
+ * Gets all user (public) listeners in one list.
+ *
+ * @return list of all user listeners.
+ */
+ public List<T> getUserListeners() {
+ synchronized (this) {
+ if (userList == null || userList.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return new ArrayList<T>(userList);
+ }
+ }
+
+ public List<T> getSystemListeners() {
+ synchronized (this) {
+ if (systemList == null || systemList.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return new ArrayList<T>(systemList);
+ }
+ }
+
+ /**
+ * Gets iterator for user listeners.
+ *
+ * @return iterator for user listeners.
+ */
+ public Iterator<T> getUserIterator() {
+ synchronized (this) {
+ if (userList == null) {
+ List<T> emptyList = Collections.emptyList();
+ return emptyList.iterator();
+ }
+ return new ReadOnlyIterator<T>(userList.iterator());
+ }
+ }
+
+ /**
+ * Gets iterator for system listeners.
+ *
+ * @return iterator for system listeners.
+ */
+ public Iterator<T> getSystemIterator() {
+ return systemList.iterator();
+ }
+
+ private static ArrayList<?> getOnlySerializable(ArrayList<?> list) {
+ if (list == null) {
+ return null;
+ }
+
+ ArrayList<Object> result = new ArrayList<Object>();
+ for (Iterator<?> it = list.iterator(); it.hasNext();) {
+ Object obj = it.next();
+ if (obj instanceof Serializable) {
+ result.add(obj);
+ }
+ }
+
+ return (result.size() != 0) ? result : null;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+
+ stream.defaultWriteObject();
+
+ stream.writeObject(getOnlySerializable(systemList));
+ stream.writeObject(getOnlySerializable(userList));
+ }
+
+ @SuppressWarnings("unchecked")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+
+ stream.defaultReadObject();
+
+ systemList = (ArrayList<T>)stream.readObject();
+ userList = (ArrayList<T>)stream.readObject();
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/ReadOnlyIterator.java b/awt/org/apache/harmony/awt/ReadOnlyIterator.java
new file mode 100644
index 0000000..671653f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/ReadOnlyIterator.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt;
+
+import java.util.Iterator;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * ReadOnlyIterator
+ */
+public final class ReadOnlyIterator<E> implements Iterator<E> {
+
+ private final Iterator<E> it;
+
+ public ReadOnlyIterator(Iterator<E> it) {
+ if (it == null) {
+ throw new NullPointerException();
+ }
+ this.it = it;
+ }
+
+ public void remove() {
+ // awt.50=Iterator is read-only
+ throw new UnsupportedOperationException(Messages.getString("awt.50")); //$NON-NLS-1$
+ }
+
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ public E next() {
+ return it.next();
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java b/awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java
new file mode 100644
index 0000000..bd5f6c6
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 23.11.2005
+ *
+ */
+
+
+package org.apache.harmony.awt.gl;
+
+import java.awt.Image;
+import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.DataBufferInt;
+
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+
+/**
+ * This class give an opportunity to get access to private data of
+ * some java.awt.image classes
+ * Implementation of this class placed in java.awt.image package
+ */
+
+public abstract class AwtImageBackdoorAccessor {
+
+ static protected AwtImageBackdoorAccessor inst;
+
+ public static AwtImageBackdoorAccessor getInstance(){
+ // First we need to run the static initializer in the DataBuffer class to resolve inst.
+ new DataBufferInt(0);
+ return inst;
+ }
+
+ public abstract Surface getImageSurface(Image image);
+ public abstract boolean isGrayPallete(IndexColorModel icm);
+
+ public abstract Object getData(DataBuffer db);
+ public abstract int[] getDataInt(DataBuffer db);
+ public abstract byte[] getDataByte(DataBuffer db);
+ public abstract short[] getDataShort(DataBuffer db);
+ public abstract short[] getDataUShort(DataBuffer db);
+ public abstract double[] getDataDouble(DataBuffer db);
+ public abstract float[] getDataFloat(DataBuffer db);
+ public abstract void releaseData(DataBuffer db);
+
+ public abstract void addDataBufferListener(DataBuffer db, DataBufferListener listener);
+ public abstract void removeDataBufferListener(DataBuffer db);
+ public abstract void validate(DataBuffer db);
+}
diff --git a/awt/org/apache/harmony/awt/gl/CommonGraphics2D.java b/awt/org/apache/harmony/awt/gl/CommonGraphics2D.java
new file mode 100644
index 0000000..a33c38b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/CommonGraphics2D.java
@@ -0,0 +1,1132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.PaintContext;
+import java.awt.Point;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.WritableRaster;
+import java.awt.image.renderable.RenderableImage;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.RoundRectangle2D;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+import org.apache.harmony.awt.gl.render.Blitter;
+import org.apache.harmony.awt.gl.render.JavaArcRasterizer;
+import org.apache.harmony.awt.gl.render.JavaLineRasterizer;
+import org.apache.harmony.awt.gl.render.JavaShapeRasterizer;
+import org.apache.harmony.awt.gl.render.JavaTextRenderer;
+import org.apache.harmony.awt.gl.render.NullBlitter;
+
+/*
+ * List of abstract methods to implement in subclusses
+ * Graphics.copyArea(int x, int y, int width, int height, int dx, int dy)
+ * Graphics.create()
+ * Graphics2D.getDeviceConfiguration()
+ * CommonGraphics2D.fillMultiRectAreaColor(MultiRectArea mra);
+ * CommonGraphics2D.fillMultiRectAreaPaint(MultiRectArea mra);
+ */
+
+/**
+ * CommonGraphics2D class is a super class for all system-dependent
+ * implementations. It implements major part of Graphics and Graphics2D
+ * abstract methods.
+ * <h2>CommonGraphics2D Class Internals</h2>
+ * <h3>Line and Shape Rasterizers</h3>
+ * <p>
+ * The CommonGraphics2D class splits all shapes into a set of rectangles
+ * to unify the drawing process for different operating systems and architectures.
+ * For this purpose Java 2D* uses the JavaShapeRasterizer and the JavaLineRasterizer
+ * classes from the org.apache.harmony.awt.gl.render package. The JavaShapeRasterizer
+ * class splits an object implementing a Shape interface into a set of rectangles and
+ * produces a MultiRectArea object. The JavaLineRasterizer class makes line drawing
+ * more accurate and processes lines with strokes, which are instances of the BasicStroke
+ * class.
+ * </p>
+ * <p>
+ * To port the shape drawing to another platform you just need to override
+ * rectangle-drawing methods. However, if your operating system has functions to draw
+ * particular shapes, you can optimize your subclass of the CommonGraphics2D class by
+ * using this functionality in overridden methods.
+ * </p>
+
+ * <h3>Blitters</h3>
+ * <p>
+ * Blitter classes draw images on the display or buffered images. All blitters inherit
+ * the org.apache.harmony.awt.gl.render.Blitter interface.
+ * </p>
+ * <p>Blitters are divided into:
+ * <ul>
+ * <li>Native blitters for simple types of images, which the underlying native library
+ * can draw.</li>
+ * <li>Java* blitters for those types of images, which the underlying native library
+ * cannot handle.</li>
+ * </ul></p>
+ * <p>
+ * DRL Java 2D* also uses blitters to fill the shapes and the user-defined subclasses
+ * of the java.awt.Paint class with paints, which the system does not support.
+ * </p>
+ *
+ *<h3>Text Renderers</h3>
+ *<p>
+ *Text renderers draw strings and glyph vectors. All text renderers are subclasses
+ *of the org.apache.harmony.awt.gl.TextRenderer class.
+ *</p>
+ *
+ */
+public abstract class CommonGraphics2D extends Graphics2D {
+ protected Surface dstSurf = null;
+ protected Blitter blitter = NullBlitter.getInstance();
+ protected RenderingHints hints = new RenderingHints(null);
+
+ // Clipping things
+ protected MultiRectArea clip = null;
+
+ protected Paint paint = Color.WHITE;
+ protected Color fgColor = Color.WHITE;
+ protected Color bgColor = Color.BLACK;
+
+ protected Composite composite = AlphaComposite.SrcOver;
+
+ protected Stroke stroke = new BasicStroke();
+
+ //TODO: Think more about FontRenderContext
+ protected FontRenderContext frc = new FontRenderContext(null, false, false);
+
+ protected JavaShapeRasterizer jsr = new JavaShapeRasterizer();
+
+ protected Font font = new Font("Dialog", Font.PLAIN, 12);; //$NON-NLS-1$
+
+ protected TextRenderer jtr = JavaTextRenderer.inst;
+
+ // Current graphics transform
+ protected AffineTransform transform = new AffineTransform();
+ protected double[] matrix = new double[6];
+
+ // Original user->device translation as transform and point
+ //public AffineTransform origTransform = new AffineTransform();
+ public Point origPoint = new Point(0, 0);
+
+
+ // Print debug output or not
+ protected static final boolean debugOutput = "1".equals(System.getProperty("g2d.debug")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // Constructors
+ protected CommonGraphics2D() {
+ }
+
+ protected CommonGraphics2D(int tx, int ty) {
+ this(tx, ty, null);
+ }
+
+ protected CommonGraphics2D(int tx, int ty, MultiRectArea clip) {
+ setTransform(AffineTransform.getTranslateInstance(tx, ty));
+ //origTransform = AffineTransform.getTranslateInstance(tx, ty);
+ origPoint = new Point(tx, ty);
+ setClip(clip);
+ }
+
+ // Public methods
+ @Override
+ public void addRenderingHints(Map<?,?> hints) {
+ this.hints.putAll(hints);
+ }
+
+ @Override
+ public void clearRect(int x, int y, int width, int height) {
+ Color c = getColor();
+ Paint p = getPaint();
+ setColor(getBackground());
+ fillRect(x, y, width, height);
+ setColor(c);
+ setPaint(p);
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.clearRect("+x+", "+y+", "+width+", "+height+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+ }
+
+ @Override
+ public void clipRect(int x, int y, int width, int height) {
+ clip(new Rectangle(x, y, width, height));
+ }
+
+
+ @Override
+ public void clip(Shape s) {
+ if (s == null) {
+ clip = null;
+ return;
+ }
+
+ MultiRectArea mra = null;
+ if (s instanceof MultiRectArea) {
+ mra = new MultiRectArea((MultiRectArea)s);
+ mra.translate((int)transform.getTranslateX(), (int)transform.getTranslateY());
+ } else {
+ int type = transform.getType();
+ if(s instanceof Rectangle && (type & (AffineTransform.TYPE_IDENTITY |
+ AffineTransform.TYPE_TRANSLATION)) != 0){
+ mra = new MultiRectArea((Rectangle)s);
+ if(type == AffineTransform.TYPE_TRANSLATION){
+ mra.translate((int)transform.getTranslateX(), (int)transform.getTranslateY());
+ }
+ } else {
+ s = transform.createTransformedShape(s);
+ mra = jsr.rasterize(s, 0.5);
+ }
+ }
+
+ if (clip == null) {
+ setTransformedClip(mra);
+ } else {
+ clip.intersect(mra);
+ setTransformedClip(clip);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ // Do nothing for Java only classes
+ }
+
+
+
+
+ /***************************************************************************
+ *
+ * Draw methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public void draw(Shape s) {
+ if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1) {
+ //TODO: Think about drawing the shape in one fillMultiRectArea call
+ BasicStroke bstroke = (BasicStroke)stroke;
+ JavaLineRasterizer.LineDasher ld = (bstroke.getDashArray() == null)?null:new JavaLineRasterizer.LineDasher(bstroke.getDashArray(), bstroke.getDashPhase());
+ PathIterator pi = s.getPathIterator(transform, 0.5);
+ float []points = new float[6];
+ int x1 = Integer.MIN_VALUE;
+ int y1 = Integer.MIN_VALUE;
+ int cx1 = Integer.MIN_VALUE;
+ int cy1 = Integer.MIN_VALUE;
+ while (!pi.isDone()) {
+ switch (pi.currentSegment(points)) {
+ case PathIterator.SEG_MOVETO:
+ x1 = (int)Math.floor(points[0]);
+ y1 = (int)Math.floor(points[1]);
+ cx1 = x1;
+ cy1 = y1;
+ break;
+ case PathIterator.SEG_LINETO:
+ int x2 = (int)Math.floor(points[0]);
+ int y2 = (int)Math.floor(points[1]);
+ fillMultiRectArea(JavaLineRasterizer.rasterize(x1, y1, x2, y2, null, ld, false));
+ x1 = x2;
+ y1 = y2;
+ break;
+ case PathIterator.SEG_CLOSE:
+ x2 = cx1;
+ y2 = cy1;
+ fillMultiRectArea(JavaLineRasterizer.rasterize(x1, y1, x2, y2, null, ld, false));
+ x1 = x2;
+ y1 = y2;
+ break;
+ }
+ pi.next();
+ }
+ } else {
+ s = stroke.createStrokedShape(s);
+ s = transform.createTransformedShape(s);
+ fillMultiRectArea(jsr.rasterize(s, 0.5));
+ }
+ }
+
+ @Override
+ public void drawArc(int x, int y, int width, int height, int sa, int ea) {
+ if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1 &&
+ ((BasicStroke)stroke).getDashArray() == null &&
+ (transform.isIdentity() || transform.getType() == AffineTransform.TYPE_TRANSLATION)) {
+ Point p = new Point(x, y);
+ transform.transform(p, p);
+ MultiRectArea mra = JavaArcRasterizer.rasterize(x, y, width, height, sa, ea, clip);
+ fillMultiRectArea(mra);
+ return;
+ }
+ draw(new Arc2D.Float(x, y, width, height, sa, ea, Arc2D.OPEN));
+ }
+
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, Color bgcolor,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) {
+ return drawImage(image, x, y, null, imageObserver);
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, int width, int height,
+ Color bgcolor, ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(width == 0 || height == 0) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ if(w == width && h == height){
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }else{
+ AffineTransform xform = new AffineTransform();
+ xform.setToScale((float)width / w, (float)height / h);
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ xform, composite, bgcolor, clip);
+ }
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int x, int y, int width, int height,
+ ImageObserver imageObserver) {
+ return drawImage(image, x, y, width, height, null, imageObserver);
+ }
+
+ @Override
+ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2, Color bgcolor,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) {
+ return true;
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+
+ int dstX = dx1;
+ int dstY = dy1;
+ int srcX = sx1;
+ int srcY = sy1;
+
+ int dstW = dx2 - dx1;
+ int dstH = dy2 - dy1;
+ int srcW = sx2 - sx1;
+ int srcH = sy2 - sy1;
+
+ if(srcW == dstW && srcH == dstH){
+ blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+ (AffineTransform) transform.clone(),
+ composite, bgcolor, clip);
+ }else{
+ AffineTransform xform = new AffineTransform();
+ xform.setToScale((float)dstW / srcW, (float)dstH / srcH);
+ blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH,
+ (AffineTransform) transform.clone(),
+ xform, composite, bgcolor, clip);
+ }
+ }
+ return done;
+ }
+
+ @Override
+ public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) {
+
+ return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
+ imageObserver);
+ }
+
+ @Override
+ public void drawImage(BufferedImage bufImage, BufferedImageOp op,
+ int x, int y) {
+
+ if(bufImage == null) {
+ return;
+ }
+
+ if(op == null) {
+ drawImage(bufImage, x, y, null);
+ } else if(op instanceof AffineTransformOp){
+ AffineTransformOp atop = (AffineTransformOp) op;
+ AffineTransform xform = atop.getTransform();
+ Surface srcSurf = Surface.getImageSurface(bufImage);
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(), xform,
+ composite, null, clip);
+ } else {
+ bufImage = op.filter(bufImage, null);
+ Surface srcSurf = Surface.getImageSurface(bufImage);
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ (AffineTransform) transform.clone(),
+ composite, null, clip);
+ }
+ }
+
+ @Override
+ public boolean drawImage(Image image, AffineTransform trans,
+ ImageObserver imageObserver) {
+
+ if(image == null) {
+ return true;
+ }
+ if(trans == null || trans.isIdentity()) {
+ return drawImage(image, 0, 0, imageObserver);
+ }
+
+ boolean done = false;
+ boolean somebits = false;
+ Surface srcSurf = null;
+ if(image instanceof OffscreenImage){
+ OffscreenImage oi = (OffscreenImage) image;
+ if((oi.getState() & ImageObserver.ERROR) != 0) {
+ return false;
+ }
+ done = oi.prepareImage(imageObserver);
+ somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0;
+ srcSurf = oi.getImageSurface();
+ }else{
+ done = true;
+ srcSurf = Surface.getImageSurface(image);
+ }
+
+ if(done || somebits) {
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ AffineTransform xform = (AffineTransform) transform.clone();
+ xform.concatenate(trans);
+ blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite,
+ null, clip);
+ }
+ return done;
+ }
+
+ @Override
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.drawLine("+x1+", "+y1+", "+x2+", "+y2+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+
+ if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1) {
+ BasicStroke bstroke = (BasicStroke)stroke;
+ Point p1 = new Point(x1, y1);
+ Point p2 = new Point(x2, y2);
+ transform.transform(p1, p1);
+ transform.transform(p2, p2);
+ JavaLineRasterizer.LineDasher ld = (bstroke.getDashArray() == null)?null:new JavaLineRasterizer.LineDasher(bstroke.getDashArray(), bstroke.getDashPhase());
+ MultiRectArea mra = JavaLineRasterizer.rasterize(p1.x, p1.y, p2.x, p2.y, null, ld, false);
+ fillMultiRectArea(mra);
+ return;
+ }
+ draw(new Line2D.Float(x1, y1, x2, y2));
+ }
+
+ @Override
+ public void drawOval(int x, int y, int width, int height) {
+ if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1 &&
+ ((BasicStroke)stroke).getDashArray() == null &&
+ (transform.isIdentity() || transform.getType() == AffineTransform.TYPE_TRANSLATION)) {
+ Point p = new Point(x, y);
+ transform.transform(p, p);
+ MultiRectArea mra = JavaArcRasterizer.rasterize(x, y, width, height, 0, 360, clip);
+ fillMultiRectArea(mra);
+ return;
+ }
+ draw(new Ellipse2D.Float(x, y, width, height));
+ }
+
+ @Override
+ public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) {
+ draw(new Polygon(xpoints, ypoints, npoints));
+ }
+
+ @Override
+ public void drawPolygon(Polygon polygon) {
+ draw(polygon);
+ }
+
+ @Override
+ public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) {
+ for (int i = 0; i < npoints-1; i++) {
+ drawLine(xpoints[i], ypoints[i], xpoints[i+1], ypoints[i+1]);
+ }
+ }
+
+ @Override
+ public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+ if (img == null) {
+ return;
+ }
+
+ double scaleX = xform.getScaleX();
+ double scaleY = xform.getScaleY();
+ if (scaleX == 1 && scaleY == 1) {
+ drawRenderedImage(img.createDefaultRendering(), xform);
+ } else {
+ int width = (int)Math.round(img.getWidth()*scaleX);
+ int height = (int)Math.round(img.getHeight()*scaleY);
+ xform = (AffineTransform)xform.clone();
+ xform.scale(1, 1);
+ drawRenderedImage(img.createScaledRendering(width, height, null), xform);
+ }
+ }
+
+ @Override
+ public void drawRenderedImage(RenderedImage rimg, AffineTransform xform) {
+ if (rimg == null) {
+ return;
+ }
+
+ Image img = null;
+
+ if (rimg instanceof Image) {
+ img = (Image)rimg;
+ } else {
+ //TODO: Create new class to provide Image interface for RenderedImage or rewrite this method
+ img = new BufferedImage(rimg.getColorModel(), rimg.copyData(null), false, null);
+ }
+
+ drawImage(img, xform, null);
+ }
+
+ @Override
+ public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.drawRoundRect("+x+", "+y+", "+width+", "+height+","+arcWidth+", "+arcHeight+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
+ }
+
+ draw(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
+ }
+
+
+
+
+
+ /***************************************************************************
+ *
+ * String methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, float x, float y) {
+ GlyphVector gv = font.createGlyphVector(frc, iterator);
+ drawGlyphVector(gv, x, y);
+ }
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+ drawString(iterator, (float)x, (float)y);
+ }
+
+ @Override
+ public void drawString(String str, int x, int y) {
+ drawString(str, (float)x, (float)y);
+ }
+
+ @Override
+ public void drawString(String str, float x, float y) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.drawString("+str+", "+x+", "+y+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+ AffineTransform at = (AffineTransform)this.getTransform().clone();
+ AffineTransform fontTransform = font.getTransform();
+ at.concatenate(fontTransform);
+
+ double[] matrix = new double[6];
+ if (!at.isIdentity()){
+
+ int atType = at.getType();
+ at.getMatrix(matrix);
+
+ // TYPE_TRANSLATION
+ if (atType == AffineTransform.TYPE_TRANSLATION){
+ jtr.drawString(this, str,
+ (float)(x+fontTransform.getTranslateX()),
+ (float)(y+fontTransform.getTranslateY()));
+ return;
+ }
+ // TODO: we use slow type of drawing strings when Font object
+ // in Graphics has transforms, we just fill outlines. New textrenderer
+ // is to be implemented.
+ Shape sh = font.createGlyphVector(this.getFontRenderContext(), str).getOutline(x, y);
+ this.fill(sh);
+
+ } else {
+ jtr.drawString(this, str, x, y);
+ }
+
+ }
+
+ @Override
+ public void drawGlyphVector(GlyphVector gv, float x, float y) {
+
+ AffineTransform at = gv.getFont().getTransform();
+
+ double[] matrix = new double[6];
+ if ((at != null) && (!at.isIdentity())){
+
+ int atType = at.getType();
+ at.getMatrix(matrix);
+
+ // TYPE_TRANSLATION
+ if ((atType == AffineTransform.TYPE_TRANSLATION) &&
+ ((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) == 0)){
+ jtr.drawGlyphVector(this, gv, (int)(x+matrix[4]), (int)(y+matrix[5]));
+ return;
+ }
+ } else {
+ if (((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) == 0)){
+ jtr.drawGlyphVector(this, gv, x, y);
+ return;
+ }
+ }
+
+ // TODO: we use slow type of drawing strings when Font object
+ // in Graphics has transforms, we just fill outlines. New textrenderer
+ // is to be implemented.
+
+ Shape sh = gv.getOutline(x, y);
+ this.fill(sh);
+
+ }
+
+
+
+
+ /***************************************************************************
+ *
+ * Fill methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public void fill(Shape s) {
+ s = transform.createTransformedShape(s);
+ MultiRectArea mra = jsr.rasterize(s, 0.5);
+ fillMultiRectArea(mra);
+ }
+
+ @Override
+ public void fillArc(int x, int y, int width, int height, int sa, int ea) {
+ fill(new Arc2D.Float(x, y, width, height, sa, ea, Arc2D.PIE));
+ }
+
+ @Override
+ public void fillOval(int x, int y, int width, int height) {
+ fill(new Ellipse2D.Float(x, y, width, height));
+ }
+
+ @Override
+ public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) {
+ fill(new Polygon(xpoints, ypoints, npoints));
+ }
+
+ @Override
+ public void fillPolygon(Polygon polygon) {
+ fill(polygon);
+ }
+
+ @Override
+ public void fillRect(int x, int y, int width, int height) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.fillRect("+x+", "+y+", "+width+", "+height+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+
+ fill(new Rectangle(x, y, width, height));
+ }
+
+ @Override
+ public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.fillRoundRect("+x+", "+y+", "+width+", "+height+","+arcWidth+", "+arcHeight+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
+ }
+
+ fill(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
+ }
+
+
+
+
+ /***************************************************************************
+ *
+ * Get methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public Color getBackground() {
+ return bgColor;
+ }
+
+ @Override
+ public Shape getClip() {
+ if (clip == null) {
+ return null;
+ }
+
+ MultiRectArea res = new MultiRectArea(clip);
+ res.translate(-Math.round((float)transform.getTranslateX()), -Math.round((float)transform.getTranslateY()));
+ return res;
+ }
+
+ @Override
+ public Rectangle getClipBounds() {
+ if (clip == null) {
+ return null;
+ }
+
+ Rectangle res = (Rectangle) clip.getBounds().clone();
+ res.translate(-Math.round((float)transform.getTranslateX()), -Math.round((float)transform.getTranslateY()));
+ return res;
+ }
+
+ @Override
+ public Color getColor() {
+ return fgColor;
+ }
+
+ @Override
+ public Composite getComposite() {
+ return composite;
+ }
+
+ @Override
+ public Font getFont() {
+ return font;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public FontMetrics getFontMetrics(Font font) {
+ return Toolkit.getDefaultToolkit().getFontMetrics(font);
+ }
+
+ @Override
+ public FontRenderContext getFontRenderContext() {
+ return frc;
+ }
+
+ @Override
+ public Paint getPaint() {
+ return paint;
+ }
+
+ @Override
+ public Object getRenderingHint(RenderingHints.Key key) {
+ return hints.get(key);
+ }
+
+ @Override
+ public RenderingHints getRenderingHints() {
+ return hints;
+ }
+
+ @Override
+ public Stroke getStroke() {
+ return stroke;
+ }
+
+ @Override
+ public AffineTransform getTransform() {
+ return (AffineTransform)transform.clone();
+ }
+
+ @Override
+ public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+ //TODO: Implement method....
+ return false;
+ }
+
+
+
+
+ /***************************************************************************
+ *
+ * Transformation methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public void rotate(double theta) {
+ transform.rotate(theta);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void rotate(double theta, double x, double y) {
+ transform.rotate(theta, x, y);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void scale(double sx, double sy) {
+ transform.scale(sx, sy);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void shear(double shx, double shy) {
+ transform.shear(shx, shy);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void transform(AffineTransform at) {
+ transform.concatenate(at);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void translate(double tx, double ty) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.translate("+tx+", "+ty+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ transform.translate(tx, ty);
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void translate(int tx, int ty) {
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.translate("+tx+", "+ty+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ transform.translate(tx, ty);
+ transform.getMatrix(matrix);
+ }
+
+
+
+
+ /***************************************************************************
+ *
+ * Set methods
+ *
+ ***************************************************************************/
+
+ @Override
+ public void setBackground(Color color) {
+ bgColor = color;
+ }
+
+ @Override
+ public void setClip(int x, int y, int width, int height) {
+ setClip(new Rectangle(x, y, width, height));
+ }
+
+ @Override
+ public void setClip(Shape s) {
+ if (s == null) {
+ setTransformedClip(null);
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.setClip(null)"); //$NON-NLS-1$
+ }
+ return;
+ }
+
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.setClip("+s.getBounds()+")"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (s instanceof MultiRectArea) {
+ MultiRectArea nclip = new MultiRectArea((MultiRectArea)s);
+ nclip.translate(Math.round((float)transform.getTranslateX()), Math.round((float)transform.getTranslateY()));
+ setTransformedClip(nclip);
+ } else {
+ int type = transform.getType();
+ if(s instanceof Rectangle && (type & (AffineTransform.TYPE_IDENTITY |
+ AffineTransform.TYPE_TRANSLATION)) != 0){
+ MultiRectArea nclip = new MultiRectArea((Rectangle)s);
+ if(type == AffineTransform.TYPE_TRANSLATION){
+ nclip.translate((int)transform.getTranslateX(), (int)transform.getTranslateY());
+ }
+ setTransformedClip(nclip);
+ } else {
+ s = transform.createTransformedShape(s);
+ setTransformedClip(jsr.rasterize(s, 0.5));
+ }
+ }
+ }
+
+ @Override
+ public void setColor(Color color) {
+ if (color != null) {
+ fgColor = color;
+ paint = color;
+ }
+ }
+
+ @Override
+ public void setComposite(Composite composite) {
+ this.composite = composite;
+ }
+
+ @Override
+ public void setFont(Font font) {
+ this.font = font;
+ }
+
+ @Override
+ public void setPaint(Paint paint) {
+ if (paint == null)
+ return;
+
+ this.paint = paint;
+ if (paint instanceof Color) {
+ fgColor = (Color)paint;
+ }
+ }
+
+ @Override
+ public void setPaintMode() {
+ composite = AlphaComposite.SrcOver;
+ }
+
+ @Override
+ public void setRenderingHint(RenderingHints.Key key, Object value) {
+ hints.put(key, value);
+ }
+
+ @Override
+ public void setRenderingHints(Map<?,?> hints) {
+ this.hints.clear();
+ this.hints.putAll(hints);
+ }
+
+ @Override
+ public void setStroke(Stroke stroke) {
+ this.stroke = stroke;
+ }
+
+ @Override
+ public void setTransform(AffineTransform transform) {
+ this.transform = transform;
+
+ transform.getMatrix(matrix);
+ }
+
+ @Override
+ public void setXORMode(Color color) {
+ composite = new XORComposite(color);
+ }
+
+
+ // Protected methods
+ protected void setTransformedClip(MultiRectArea clip) {
+ this.clip = clip;
+ }
+
+ /**
+ * This method fills the given MultiRectArea with current paint.
+ * It calls fillMultiRectAreaColor and fillMultiRectAreaPaint
+ * methods depending on the type of current paint.
+ * @param mra MultiRectArea to fill
+ */
+ protected void fillMultiRectArea(MultiRectArea mra) {
+ if (clip != null) {
+ mra.intersect(clip);
+ }
+
+ // Return if all stuff is clipped
+ if (mra.rect[0] < 5) {
+ return;
+ }
+
+ if (debugOutput) {
+ System.err.println("CommonGraphics2D.fillMultiRectArea("+mra+")"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (paint instanceof Color){
+ fillMultiRectAreaColor(mra);
+ }else{
+ fillMultiRectAreaPaint(mra);
+ }
+ }
+
+ /**
+ * This method fills the given MultiRectArea with solid color.
+ * @param mra MultiRectArea to fill
+ */
+ protected void fillMultiRectAreaColor(MultiRectArea mra) {
+ fillMultiRectAreaPaint(mra);
+ }
+
+ /**
+ * This method fills the given MultiRectArea with any paint.
+ * @param mra MultiRectArea to fill
+ */
+ protected void fillMultiRectAreaPaint(MultiRectArea mra) {
+ Rectangle rec = mra.getBounds();
+ int x = rec.x;
+ int y = rec.y;
+ int w = rec.width;
+ int h = rec.height;
+ if(w <= 0 || h <= 0) {
+ return;
+ }
+ PaintContext pc = paint.createContext(null, rec, rec, transform, hints);
+ Raster r = pc.getRaster(x, y, w, h);
+ WritableRaster wr;
+ if(r instanceof WritableRaster){
+ wr = (WritableRaster) r;
+ }else{
+ wr = r.createCompatibleWritableRaster();
+ wr.setRect(r);
+ }
+ Surface srcSurf = new ImageSurface(pc.getColorModel(), wr);
+ blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h,
+ composite, null, mra);
+ srcSurf.dispose();
+ }
+
+ /**
+ * Copies graphics class fields.
+ * Used in create method
+ *
+ * @param copy Graphics class to copy
+ */
+ protected void copyInternalFields(CommonGraphics2D copy) {
+ if (clip == null) {
+ copy.setTransformedClip(null);
+ } else {
+ copy.setTransformedClip(new MultiRectArea(clip));
+ }
+ copy.setBackground(bgColor);
+ copy.setColor(fgColor);
+ copy.setPaint(paint);
+ copy.setComposite(composite);
+ copy.setStroke(stroke);
+ copy.setFont(font);
+ copy.setTransform(new AffineTransform(transform));
+ //copy.origTransform = new AffineTransform(origTransform);
+ copy.origPoint = new Point(origPoint);
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java b/awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java
new file mode 100644
index 0000000..27e3ef0
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko, Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.peer.FontPeer;
+
+import org.apache.harmony.awt.gl.font.FontMetricsImpl;
+import org.apache.harmony.awt.wtk.GraphicsFactory;
+
+/**
+ * Common GraphicsFactory implementation
+ *
+ */
+public abstract class CommonGraphics2DFactory implements GraphicsFactory {
+
+ // static instance of CommonGraphics2DFactory
+ public static CommonGraphics2DFactory inst;
+
+ /**
+ * Returns FontMetrics object that keeps metrics of the specified font.
+ *
+ * @param font specified Font
+ * @return FontMetrics object corresponding to the specified Font object
+ */
+ public FontMetrics getFontMetrics(Font font) {
+ FontMetrics fm;
+ for (FontMetrics element : cacheFM) {
+ fm = element;
+ if (fm == null){
+ break;
+ }
+
+ if (fm.getFont().equals(font)){
+ return fm;
+ }
+ }
+ fm = new FontMetricsImpl(font);
+
+ System.arraycopy(cacheFM, 0, cacheFM, 1, cacheFM.length -1);
+ cacheFM[0] = fm;
+
+ return fm;
+ }
+ // Font methods
+
+ public FontPeer getFontPeer(Font font) {
+ return getFontManager().getFontPeer(font.getName(), font.getStyle(), font.getSize());
+ }
+
+ /**
+ * Embeds font from gile with specified path into the system.
+ *
+ * @param fontFilePath path to the font file
+ * @return Font object that was created from the file.
+ */
+ public abstract Font embedFont(String fontFilePath);
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java b/awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java
new file mode 100644
index 0000000..5c78e50
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko, Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import org.apache.harmony.awt.gl.image.BufferedImageGraphics2D;
+
+/**
+ * Common GraphicsEnvironment implementation
+ *
+ */
+public abstract class CommonGraphicsEnvironment extends GraphicsEnvironment {
+
+ @Override
+ public Graphics2D createGraphics(BufferedImage bufferedImage) {
+ return new BufferedImageGraphics2D(bufferedImage);
+ }
+
+ @Override
+ public String[] getAvailableFontFamilyNames(Locale locale) {
+ Font[] fonts = getAllFonts();
+ ArrayList<String> familyNames = new ArrayList<String>();
+
+ for (Font element : fonts) {
+ String name = element.getFamily(locale);
+ if (!familyNames.contains(name)) {
+ familyNames.add(name);
+ }
+ }
+
+ return familyNames.toArray(new String[familyNames.size()]);
+ }
+
+ @Override
+ public Font[] getAllFonts() {
+ return CommonGraphics2DFactory.inst.getFontManager().getAllFonts();
+ }
+
+ @Override
+ public String[] getAvailableFontFamilyNames() {
+ return CommonGraphics2DFactory.inst.getFontManager().getAllFamilies();
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/Crossing.java b/awt/org/apache/harmony/awt/gl/Crossing.java
new file mode 100644
index 0000000..ae7fb0e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/Crossing.java
@@ -0,0 +1,889 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Shape;
+import java.awt.geom.PathIterator;
+
+public class Crossing {
+
+ /**
+ * Allowable tolerance for bounds comparison
+ */
+ static final double DELTA = 1E-5;
+
+ /**
+ * If roots have distance less then <code>ROOT_DELTA</code> they are double
+ */
+ static final double ROOT_DELTA = 1E-10;
+
+ /**
+ * Rectangle cross segment
+ */
+ public static final int CROSSING = 255;
+
+ /**
+ * Unknown crossing result
+ */
+ static final int UNKNOWN = 254;
+
+ /**
+ * Solves quadratic equation
+ * @param eqn - the coefficients of the equation
+ * @param res - the roots of the equation
+ * @return a number of roots
+ */
+ public static int solveQuad(double eqn[], double res[]) {
+ double a = eqn[2];
+ double b = eqn[1];
+ double c = eqn[0];
+ int rc = 0;
+ if (a == 0.0) {
+ if (b == 0.0) {
+ return -1;
+ }
+ res[rc++] = -c / b;
+ } else {
+ double d = b * b - 4.0 * a * c;
+ // d < 0.0
+ if (d < 0.0) {
+ return 0;
+ }
+ d = Math.sqrt(d);
+ res[rc++] = (- b + d) / (a * 2.0);
+ // d != 0.0
+ if (d != 0.0) {
+ res[rc++] = (- b - d) / (a * 2.0);
+ }
+ }
+ return fixRoots(res, rc);
+ }
+
+ /**
+ * Solves cubic equation
+ * @param eqn - the coefficients of the equation
+ * @param res - the roots of the equation
+ * @return a number of roots
+ */
+ public static int solveCubic(double eqn[], double res[]) {
+ double d = eqn[3];
+ if (d == 0) {
+ return solveQuad(eqn, res);
+ }
+ double a = eqn[2] / d;
+ double b = eqn[1] / d;
+ double c = eqn[0] / d;
+ int rc = 0;
+
+ double Q = (a * a - 3.0 * b) / 9.0;
+ double R = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0;
+ double Q3 = Q * Q * Q;
+ double R2 = R * R;
+ double n = - a / 3.0;
+
+ if (R2 < Q3) {
+ double t = Math.acos(R / Math.sqrt(Q3)) / 3.0;
+ double p = 2.0 * Math.PI / 3.0;
+ double m = -2.0 * Math.sqrt(Q);
+ res[rc++] = m * Math.cos(t) + n;
+ res[rc++] = m * Math.cos(t + p) + n;
+ res[rc++] = m * Math.cos(t - p) + n;
+ } else {
+// Debug.println("R2 >= Q3 (" + R2 + "/" + Q3 + ")");
+ double A = Math.pow(Math.abs(R) + Math.sqrt(R2 - Q3), 1.0 / 3.0);
+ if (R > 0.0) {
+ A = -A;
+ }
+// if (A == 0.0) {
+ if (-ROOT_DELTA < A && A < ROOT_DELTA) {
+ res[rc++] = n;
+ } else {
+ double B = Q / A;
+ res[rc++] = A + B + n;
+// if (R2 == Q3) {
+ double delta = R2 - Q3;
+ if (-ROOT_DELTA < delta && delta < ROOT_DELTA) {
+ res[rc++] = - (A + B) / 2.0 + n;
+ }
+ }
+
+ }
+ return fixRoots(res, rc);
+ }
+
+ /**
+ * Excludes double roots. Roots are double if they lies enough close with each other.
+ * @param res - the roots
+ * @param rc - the roots count
+ * @return new roots count
+ */
+ static int fixRoots(double res[], int rc) {
+ int tc = 0;
+ for(int i = 0; i < rc; i++) {
+ out: {
+ for(int j = i + 1; j < rc; j++) {
+ if (isZero(res[i] - res[j])) {
+ break out;
+ }
+ }
+ res[tc++] = res[i];
+ }
+ }
+ return tc;
+ }
+
+ /**
+ * QuadCurve class provides basic functionality to find curve crossing and calculating bounds
+ */
+ public static class QuadCurve {
+
+ double ax, ay, bx, by;
+ double Ax, Ay, Bx, By;
+
+ public QuadCurve(double x1, double y1, double cx, double cy, double x2, double y2) {
+ ax = x2 - x1;
+ ay = y2 - y1;
+ bx = cx - x1;
+ by = cy - y1;
+
+ Bx = bx + bx; // Bx = 2.0 * bx
+ Ax = ax - Bx; // Ax = ax - 2.0 * bx
+
+ By = by + by; // By = 2.0 * by
+ Ay = ay - By; // Ay = ay - 2.0 * by
+ }
+
+ int cross(double res[], int rc, double py1, double py2) {
+ int cross = 0;
+
+ for (int i = 0; i < rc; i++) {
+ double t = res[i];
+
+ // CURVE-OUTSIDE
+ if (t < -DELTA || t > 1 + DELTA) {
+ continue;
+ }
+ // CURVE-START
+ if (t < DELTA) {
+ if (py1 < 0.0 && (bx != 0.0 ? bx : ax - bx) < 0.0) {
+ cross--;
+ }
+ continue;
+ }
+ // CURVE-END
+ if (t > 1 - DELTA) {
+ if (py1 < ay && (ax != bx ? ax - bx : bx) > 0.0) {
+ cross++;
+ }
+ continue;
+ }
+ // CURVE-INSIDE
+ double ry = t * (t * Ay + By);
+ // ry = t * t * Ay + t * By
+ if (ry > py2) {
+ double rxt = t * Ax + bx;
+ // rxt = 2.0 * t * Ax + Bx = 2.0 * t * Ax + 2.0 * bx
+ if (rxt > -DELTA && rxt < DELTA) {
+ continue;
+ }
+ cross += rxt > 0.0 ? 1 : -1;
+ }
+ } // for
+
+ return cross;
+ }
+
+ int solvePoint(double res[], double px) {
+ double eqn[] = {-px, Bx, Ax};
+ return solveQuad(eqn, res);
+ }
+
+ int solveExtrem(double res[]) {
+ int rc = 0;
+ if (Ax != 0.0) {
+ res[rc++] = - Bx / (Ax + Ax);
+ }
+ if (Ay != 0.0) {
+ res[rc++] = - By / (Ay + Ay);
+ }
+ return rc;
+ }
+
+ int addBound(double bound[], int bc, double res[], int rc, double minX, double maxX, boolean changeId, int id) {
+ for(int i = 0; i < rc; i++) {
+ double t = res[i];
+ if (t > -DELTA && t < 1 + DELTA) {
+ double rx = t * (t * Ax + Bx);
+ if (minX <= rx && rx <= maxX) {
+ bound[bc++] = t;
+ bound[bc++] = rx;
+ bound[bc++] = t * (t * Ay + By);
+ bound[bc++] = id;
+ if (changeId) {
+ id++;
+ }
+ }
+ }
+ }
+ return bc;
+ }
+
+ }
+
+ /**
+ * CubicCurve class provides basic functionality to find curve crossing and calculating bounds
+ */
+ public static class CubicCurve {
+
+ double ax, ay, bx, by, cx, cy;
+ double Ax, Ay, Bx, By, Cx, Cy;
+ double Ax3, Bx2;
+
+ public CubicCurve(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2) {
+ ax = x2 - x1;
+ ay = y2 - y1;
+ bx = cx1 - x1;
+ by = cy1 - y1;
+ cx = cx2 - x1;
+ cy = cy2 - y1;
+
+ Cx = bx + bx + bx; // Cx = 3.0 * bx
+ Bx = cx + cx + cx - Cx - Cx; // Bx = 3.0 * cx - 6.0 * bx
+ Ax = ax - Bx - Cx; // Ax = ax - 3.0 * cx + 3.0 * bx
+
+ Cy = by + by + by; // Cy = 3.0 * by
+ By = cy + cy + cy - Cy - Cy; // By = 3.0 * cy - 6.0 * by
+ Ay = ay - By - Cy; // Ay = ay - 3.0 * cy + 3.0 * by
+
+ Ax3 = Ax + Ax + Ax;
+ Bx2 = Bx + Bx;
+ }
+
+ int cross(double res[], int rc, double py1, double py2) {
+ int cross = 0;
+ for (int i = 0; i < rc; i++) {
+ double t = res[i];
+
+ // CURVE-OUTSIDE
+ if (t < -DELTA || t > 1 + DELTA) {
+ continue;
+ }
+ // CURVE-START
+ if (t < DELTA) {
+ if (py1 < 0.0 && (bx != 0.0 ? bx : (cx != bx ? cx - bx : ax - cx)) < 0.0) {
+ cross--;
+ }
+ continue;
+ }
+ // CURVE-END
+ if (t > 1 - DELTA) {
+ if (py1 < ay && (ax != cx ? ax - cx : (cx != bx ? cx - bx : bx)) > 0.0) {
+ cross++;
+ }
+ continue;
+ }
+ // CURVE-INSIDE
+ double ry = t * (t * (t * Ay + By) + Cy);
+ // ry = t * t * t * Ay + t * t * By + t * Cy
+ if (ry > py2) {
+ double rxt = t * (t * Ax3 + Bx2) + Cx;
+ // rxt = 3.0 * t * t * Ax + 2.0 * t * Bx + Cx
+ if (rxt > -DELTA && rxt < DELTA) {
+ rxt = t * (Ax3 + Ax3) + Bx2;
+ // rxt = 6.0 * t * Ax + 2.0 * Bx
+ if (rxt < -DELTA || rxt > DELTA) {
+ // Inflection point
+ continue;
+ }
+ rxt = ax;
+ }
+ cross += rxt > 0.0 ? 1 : -1;
+ }
+ } //for
+
+ return cross;
+ }
+
+ int solvePoint(double res[], double px) {
+ double eqn[] = {-px, Cx, Bx, Ax};
+ return solveCubic(eqn, res);
+ }
+
+ int solveExtremX(double res[]) {
+ double eqn[] = {Cx, Bx2, Ax3};
+ return solveQuad(eqn, res);
+ }
+
+ int solveExtremY(double res[]) {
+ double eqn[] = {Cy, By + By, Ay + Ay + Ay};
+ return solveQuad(eqn, res);
+ }
+
+ int addBound(double bound[], int bc, double res[], int rc, double minX, double maxX, boolean changeId, int id) {
+ for(int i = 0; i < rc; i++) {
+ double t = res[i];
+ if (t > -DELTA && t < 1 + DELTA) {
+ double rx = t * (t * (t * Ax + Bx) + Cx);
+ if (minX <= rx && rx <= maxX) {
+ bound[bc++] = t;
+ bound[bc++] = rx;
+ bound[bc++] = t * (t * (t * Ay + By) + Cy);
+ bound[bc++] = id;
+ if (changeId) {
+ id++;
+ }
+ }
+ }
+ }
+ return bc;
+ }
+
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross line.
+ */
+ public static int crossLine(double x1, double y1, double x2, double y2, double x, double y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < x2) ||
+ (x > x1 && x > x2) ||
+ (y > y1 && y > y2) ||
+ (x1 == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < y2) {
+ } else {
+ // INSIDE
+ if ((y2 - y1) * (x - x1) / (x2 - x1) <= y - y1) {
+ // INSIDE-UP
+ return 0;
+ }
+ }
+
+ // START
+ if (x == x1) {
+ return x1 < x2 ? 0 : -1;
+ }
+
+ // END
+ if (x == x2) {
+ return x1 < x2 ? 1 : 0;
+ }
+
+ // INSIDE-DOWN
+ return x1 < x2 ? 1 : -1;
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross quard curve
+ */
+ public static int crossQuad(double x1, double y1, double cx, double cy, double x2, double y2, double x, double y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < cx && x < x2) ||
+ (x > x1 && x > cx && x > x2) ||
+ (y > y1 && y > cy && y > y2) ||
+ (x1 == cx && cx == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < cy && y < y2 && x != x1 && x != x2) {
+ if (x1 < x2) {
+ return x1 < x && x < x2 ? 1 : 0;
+ }
+ return x2 < x && x < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ QuadCurve c = new QuadCurve(x1, y1, cx, cy, x2, y2);
+ double px = x - x1;
+ double py = y - y1;
+ double res[] = new double[3];
+ int rc = c.solvePoint(res, px);
+
+ return c.cross(res, rc, py, py);
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross cubic curve
+ */
+ public static int crossCubic(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2, double x, double y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < cx1 && x < cx2 && x < x2) ||
+ (x > x1 && x > cx1 && x > cx2 && x > x2) ||
+ (y > y1 && y > cy1 && y > cy2 && y > y2) ||
+ (x1 == cx1 && cx1 == cx2 && cx2 == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < cy1 && y < cy2 && y < y2 && x != x1 && x != x2) {
+ if (x1 < x2) {
+ return x1 < x && x < x2 ? 1 : 0;
+ }
+ return x2 < x && x < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
+ double px = x - x1;
+ double py = y - y1;
+ double res[] = new double[3];
+ int rc = c.solvePoint(res, px);
+ return c.cross(res, rc, py, py);
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross path
+ */
+ public static int crossPath(PathIterator p, double x, double y) {
+ int cross = 0;
+ double mx, my, cx, cy;
+ mx = my = cx = cy = 0.0;
+ double coords[] = new double[6];
+
+ while (!p.isDone()) {
+ switch (p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (cx != mx || cy != my) {
+ cross += crossLine(cx, cy, mx, my, x, y);
+ }
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ break;
+ case PathIterator.SEG_LINETO:
+ cross += crossLine(cx, cy, cx = coords[0], cy = coords[1], x, y);
+ break;
+ case PathIterator.SEG_QUADTO:
+ cross += crossQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3], x, y);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ cross += crossCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5], x, y);
+ break;
+ case PathIterator.SEG_CLOSE:
+ if (cy != my || cx != mx) {
+ cross += crossLine(cx, cy, cx = mx, cy = my, x, y);
+ }
+ break;
+ }
+ p.next();
+ }
+ if (cy != my) {
+ cross += crossLine(cx, cy, mx, my, x, y);
+ }
+ return cross;
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross shape
+ */
+ public static int crossShape(Shape s, double x, double y) {
+ if (!s.getBounds2D().contains(x, y)) {
+ return 0;
+ }
+ return crossPath(s.getPathIterator(null), x, y);
+ }
+
+ /**
+ * Returns true if value enough small
+ */
+ public static boolean isZero(double val) {
+ return -DELTA < val && val < DELTA;
+ }
+
+ /**
+ * Sort bound array
+ */
+ static void sortBound(double bound[], int bc) {
+ for(int i = 0; i < bc - 4; i += 4) {
+ int k = i;
+ for(int j = i + 4; j < bc; j += 4) {
+ if (bound[k] > bound[j]) {
+ k = j;
+ }
+ }
+ if (k != i) {
+ double tmp = bound[i];
+ bound[i] = bound[k];
+ bound[k] = tmp;
+ tmp = bound[i + 1];
+ bound[i + 1] = bound[k + 1];
+ bound[k + 1] = tmp;
+ tmp = bound[i + 2];
+ bound[i + 2] = bound[k + 2];
+ bound[k + 2] = tmp;
+ tmp = bound[i + 3];
+ bound[i + 3] = bound[k + 3];
+ bound[k + 3] = tmp;
+ }
+ }
+ }
+
+ /**
+ * Returns are bounds intersect or not intersect rectangle
+ */
+ static int crossBound(double bound[], int bc, double py1, double py2) {
+
+ // LEFT/RIGHT
+ if (bc == 0) {
+ return 0;
+ }
+
+ // Check Y coordinate
+ int up = 0;
+ int down = 0;
+ for(int i = 2; i < bc; i += 4) {
+ if (bound[i] < py1) {
+ up++;
+ continue;
+ }
+ if (bound[i] > py2) {
+ down++;
+ continue;
+ }
+ return CROSSING;
+ }
+
+ // UP
+ if (down == 0) {
+ return 0;
+ }
+
+ if (up != 0) {
+ // bc >= 2
+ sortBound(bound, bc);
+ boolean sign = bound[2] > py2;
+ for(int i = 6; i < bc; i += 4) {
+ boolean sign2 = bound[i] > py2;
+ if (sign != sign2 && bound[i + 1] != bound[i - 3]) {
+ return CROSSING;
+ }
+ sign = sign2;
+ }
+ }
+ return UNKNOWN;
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross line or the are intersect
+ */
+ public static int intersectLine(double x1, double y1, double x2, double y2, double rx1, double ry1, double rx2, double ry2) {
+
+ // LEFT/RIGHT/UP
+ if ((rx2 < x1 && rx2 < x2) ||
+ (rx1 > x1 && rx1 > x2) ||
+ (ry1 > y1 && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (ry2 < y1 && ry2 < y2) {
+ } else {
+
+ // INSIDE
+ if (x1 == x2) {
+ return CROSSING;
+ }
+
+ // Build bound
+ double bx1, bx2;
+ if (x1 < x2) {
+ bx1 = x1 < rx1 ? rx1 : x1;
+ bx2 = x2 < rx2 ? x2 : rx2;
+ } else {
+ bx1 = x2 < rx1 ? rx1 : x2;
+ bx2 = x1 < rx2 ? x1 : rx2;
+ }
+ double k = (y2 - y1) / (x2 - x1);
+ double by1 = k * (bx1 - x1) + y1;
+ double by2 = k * (bx2 - x1) + y1;
+
+ // BOUND-UP
+ if (by1 < ry1 && by2 < ry1) {
+ return 0;
+ }
+
+ // BOUND-DOWN
+ if (by1 > ry2 && by2 > ry2) {
+ } else {
+ return CROSSING;
+ }
+ }
+
+ // EMPTY
+ if (x1 == x2) {
+ return 0;
+ }
+
+ // CURVE-START
+ if (rx1 == x1) {
+ return x1 < x2 ? 0 : -1;
+ }
+
+ // CURVE-END
+ if (rx1 == x2) {
+ return x1 < x2 ? 1 : 0;
+ }
+
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross quad curve or the are intersect
+ */
+ public static int intersectQuad(double x1, double y1, double cx, double cy, double x2, double y2, double rx1, double ry1, double rx2, double ry2) {
+
+ // LEFT/RIGHT/UP ------------------------------------------------------
+ if ((rx2 < x1 && rx2 < cx && rx2 < x2) ||
+ (rx1 > x1 && rx1 > cx && rx1 > x2) ||
+ (ry1 > y1 && ry1 > cy && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN ---------------------------------------------------------------
+ if (ry2 < y1 && ry2 < cy && ry2 < y2 && rx1 != x1 && rx1 != x2) {
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+ }
+
+ // INSIDE -------------------------------------------------------------
+ QuadCurve c = new QuadCurve(x1, y1, cx, cy, x2, y2);
+ double px1 = rx1 - x1;
+ double py1 = ry1 - y1;
+ double px2 = rx2 - x1;
+ double py2 = ry2 - y1;
+
+ double res1[] = new double[3];
+ double res2[] = new double[3];
+ int rc1 = c.solvePoint(res1, px1);
+ int rc2 = c.solvePoint(res2, px2);
+
+ // INSIDE-LEFT/RIGHT
+ if (rc1 == 0 && rc2 == 0) {
+ return 0;
+ }
+
+ // Build bound --------------------------------------------------------
+ double minX = px1 - DELTA;
+ double maxX = px2 + DELTA;
+ double bound[] = new double[28];
+ int bc = 0;
+ // Add roots
+ bc = c.addBound(bound, bc, res1, rc1, minX, maxX, false, 0);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, false, 1);
+ // Add extremal points`
+ rc2 = c.solveExtrem(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 2);
+ // Add start and end
+ if (rx1 < x1 && x1 < rx2) {
+ bound[bc++] = 0.0;
+ bound[bc++] = 0.0;
+ bound[bc++] = 0.0;
+ bound[bc++] = 4;
+ }
+ if (rx1 < x2 && x2 < rx2) {
+ bound[bc++] = 1.0;
+ bound[bc++] = c.ax;
+ bound[bc++] = c.ay;
+ bound[bc++] = 5;
+ }
+ // End build bound ----------------------------------------------------
+
+ int cross = crossBound(bound, bc, py1, py2);
+ if (cross != UNKNOWN) {
+ return cross;
+ }
+ return c.cross(res1, rc1, py1, py2);
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross cubic curve or the are intersect
+ */
+ public static int intersectCubic(double x1, double y1, double cx1, double cy1, double cx2, double cy2, double x2, double y2, double rx1, double ry1, double rx2, double ry2) {
+
+ // LEFT/RIGHT/UP
+ if ((rx2 < x1 && rx2 < cx1 && rx2 < cx2 && rx2 < x2) ||
+ (rx1 > x1 && rx1 > cx1 && rx1 > cx2 && rx1 > x2) ||
+ (ry1 > y1 && ry1 > cy1 && ry1 > cy2 && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (ry2 < y1 && ry2 < cy1 && ry2 < cy2 && ry2 < y2 && rx1 != x1 && rx1 != x2) {
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
+ double px1 = rx1 - x1;
+ double py1 = ry1 - y1;
+ double px2 = rx2 - x1;
+ double py2 = ry2 - y1;
+
+ double res1[] = new double[3];
+ double res2[] = new double[3];
+ int rc1 = c.solvePoint(res1, px1);
+ int rc2 = c.solvePoint(res2, px2);
+
+ // LEFT/RIGHT
+ if (rc1 == 0 && rc2 == 0) {
+ return 0;
+ }
+
+ double minX = px1 - DELTA;
+ double maxX = px2 + DELTA;
+
+ // Build bound --------------------------------------------------------
+ double bound[] = new double[40];
+ int bc = 0;
+ // Add roots
+ bc = c.addBound(bound, bc, res1, rc1, minX, maxX, false, 0);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, false, 1);
+ // Add extrimal points
+ rc2 = c.solveExtremX(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 2);
+ rc2 = c.solveExtremY(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 4);
+ // Add start and end
+ if (rx1 < x1 && x1 < rx2) {
+ bound[bc++] = 0.0;
+ bound[bc++] = 0.0;
+ bound[bc++] = 0.0;
+ bound[bc++] = 6;
+ }
+ if (rx1 < x2 && x2 < rx2) {
+ bound[bc++] = 1.0;
+ bound[bc++] = c.ax;
+ bound[bc++] = c.ay;
+ bound[bc++] = 7;
+ }
+ // End build bound ----------------------------------------------------
+
+ int cross = crossBound(bound, bc, py1, py2);
+ if (cross != UNKNOWN) {
+ return cross;
+ }
+ return c.cross(res1, rc1, py1, py2);
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross path or the are intersect
+ */
+ public static int intersectPath(PathIterator p, double x, double y, double w, double h) {
+
+ int cross = 0;
+ int count;
+ double mx, my, cx, cy;
+ mx = my = cx = cy = 0.0;
+ double coords[] = new double[6];
+
+ double rx1 = x;
+ double ry1 = y;
+ double rx2 = x + w;
+ double ry2 = y + h;
+
+ while (!p.isDone()) {
+ count = 0;
+ switch (p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (cx != mx || cy != my) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ }
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ break;
+ case PathIterator.SEG_LINETO:
+ count = intersectLine(cx, cy, cx = coords[0], cy = coords[1], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_QUADTO:
+ count = intersectQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ count = intersectCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_CLOSE:
+ if (cy != my || cx != mx) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ }
+ cx = mx;
+ cy = my;
+ break;
+ }
+ if (count == CROSSING) {
+ return CROSSING;
+ }
+ cross += count;
+ p.next();
+ }
+ if (cy != my) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ if (count == CROSSING) {
+ return CROSSING;
+ }
+ cross += count;
+ }
+ return cross;
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross shape or the are intersect
+ */
+ public static int intersectShape(Shape s, double x, double y, double w, double h) {
+ if (!s.getBounds2D().intersects(x, y, w, h)) {
+ return 0;
+ }
+ return intersectPath(s.getPathIterator(null), x, y, w, h);
+ }
+
+ /**
+ * Returns true if cross count correspond inside location for non zero path rule
+ */
+ public static boolean isInsideNonZero(int cross) {
+ return cross != 0;
+ }
+
+ /**
+ * Returns true if cross count correspond inside location for even-odd path rule
+ */
+ public static boolean isInsideEvenOdd(int cross) {
+ return (cross & 1) != 0;
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/GLVolatileImage.java b/awt/org/apache/harmony/awt/gl/GLVolatileImage.java
new file mode 100644
index 0000000..177be23
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/GLVolatileImage.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.image.*;
+
+import org.apache.harmony.awt.gl.Surface;
+
+public abstract class GLVolatileImage extends VolatileImage {
+
+ public abstract Surface getImageSurface();
+}
diff --git a/awt/org/apache/harmony/awt/gl/ICompositeContext.java b/awt/org/apache/harmony/awt/gl/ICompositeContext.java
new file mode 100644
index 0000000..fc5631f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/ICompositeContext.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.render.NativeImageBlitter;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class represent implementation of the CompositeContext interface
+ */
+public class ICompositeContext implements CompositeContext {
+ Composite composite;
+ ColorModel srcCM, dstCM;
+ ImageSurface srcSurf, dstSurf;
+
+ public ICompositeContext(Composite comp, ColorModel src, ColorModel dst){
+ composite = comp;
+ srcCM = src;
+ dstCM = dst;
+ }
+
+ public void dispose() {
+ srcSurf.dispose();
+ dstSurf.dispose();
+ }
+
+ public void compose(Raster srcIn, Raster dstIn, WritableRaster dstOut) {
+
+ if(!srcCM.isCompatibleRaster(srcIn)) {
+ // awt.48=The srcIn raster is incompatible with src ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.48")); //$NON-NLS-1$
+ }
+
+ if(!dstCM.isCompatibleRaster(dstIn)) {
+ // awt.49=The dstIn raster is incompatible with dst ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.49")); //$NON-NLS-1$
+ }
+
+ if(dstIn != dstOut){
+ if(!dstCM.isCompatibleRaster(dstOut)) {
+ // awt.4A=The dstOut raster is incompatible with dst ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.4A")); //$NON-NLS-1$
+ }
+ dstOut.setDataElements(0, 0, dstIn);
+ }
+ WritableRaster src;
+ if(srcIn instanceof WritableRaster){
+ src = (WritableRaster) srcIn;
+ }else{
+ src = srcIn.createCompatibleWritableRaster();
+ src.setDataElements(0, 0, srcIn);
+ }
+ srcSurf = new ImageSurface(srcCM, src);
+ dstSurf = new ImageSurface(dstCM, dstOut);
+
+ int w = Math.min(srcIn.getWidth(), dstOut.getWidth());
+ int h = Math.min(srcIn.getHeight(), dstOut.getHeight());
+
+ NativeImageBlitter.getInstance().blit(0, 0, srcSurf, 0, 0, dstSurf,
+ w, h, composite, null, null);
+
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/ImageSurface.java b/awt/org/apache/harmony/awt/gl/ImageSurface.java
new file mode 100644
index 0000000..6368dd8
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/ImageSurface.java
@@ -0,0 +1,323 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 10.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.BandedSampleModel;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DirectColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+import org.apache.harmony.awt.gl.image.DataBufferListener;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class represent Surface for different types of Images (BufferedImage,
+ * OffscreenImage and so on)
+ */
+public class ImageSurface extends Surface implements DataBufferListener {
+
+ boolean nativeDrawable = true;
+ int surfaceType;
+ int csType;
+ ColorModel cm;
+ WritableRaster raster;
+ Object data;
+
+ boolean needToRefresh = true;
+ boolean dataTaken = false;
+
+ private long cachedDataPtr; // Pointer for cached Image Data
+ private boolean alphaPre; // Cached Image Data alpha premultiplied
+
+ public ImageSurface(ColorModel cm, WritableRaster raster){
+ this(cm, raster, Surface.getType(cm, raster));
+ }
+
+ public ImageSurface(ColorModel cm, WritableRaster raster, int type){
+ if (!cm.isCompatibleRaster(raster)) {
+ // awt.4D=The raster is incompatible with this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+ }
+ this.cm = cm;
+ this.raster = raster;
+ surfaceType = type;
+
+ data = AwtImageBackdoorAccessor.getInstance().
+ getData(raster.getDataBuffer());
+ ColorSpace cs = cm.getColorSpace();
+ transparency = cm.getTransparency();
+ width = raster.getWidth();
+ height = raster.getHeight();
+
+ // For the moment we can build natively only images which have
+ // sRGB, Linear_RGB, Linear_Gray Color Space and type different
+ // from BufferedImage.TYPE_CUSTOM
+ if(cs == LUTColorConverter.sRGB_CS){
+ csType = sRGB_CS;
+ }else if(cs == LUTColorConverter.LINEAR_RGB_CS){
+ csType = Linear_RGB_CS;
+ }else if(cs == LUTColorConverter.LINEAR_GRAY_CS){
+ csType = Linear_Gray_CS;
+ }else{
+ csType = Custom_CS;
+ nativeDrawable = false;
+ }
+
+ if(type == BufferedImage.TYPE_CUSTOM){
+ nativeDrawable = false;
+ }
+ }
+
+ @Override
+ public ColorModel getColorModel() {
+ return cm;
+ }
+
+ @Override
+ public WritableRaster getRaster() {
+ return raster;
+ }
+
+ @Override
+ public long getSurfaceDataPtr() {
+ if(surfaceDataPtr == 0L && nativeDrawable){
+ createSufaceStructure();
+ }
+ return surfaceDataPtr;
+ }
+
+ @Override
+ public Object getData(){
+ return data;
+ }
+
+ @Override
+ public boolean isNativeDrawable(){
+ return nativeDrawable;
+ }
+
+ @Override
+ public int getSurfaceType() {
+ return surfaceType;
+ }
+
+ /**
+ * Creates native Surface structure which used for native blitting
+ */
+ private void createSufaceStructure(){
+ int cmType = 0;
+ int numComponents = cm.getNumComponents();
+ boolean hasAlpha = cm.hasAlpha();
+ boolean isAlphaPre = cm.isAlphaPremultiplied();
+ int transparency = cm.getTransparency();
+ int bits[] = cm.getComponentSize();
+ int pixelStride = cm.getPixelSize();
+ int masks[] = null;
+ int colorMap[] = null;
+ int colorMapSize = 0;
+ int transpPixel = -1;
+ boolean isGrayPallete = false;
+ SampleModel sm = raster.getSampleModel();
+ int smType = 0;
+ int dataType = sm.getDataType();
+ int scanlineStride = 0;
+ int bankIndeces[] = null;
+ int bandOffsets[] = null;
+ int offset = raster.getDataBuffer().getOffset();
+
+ if(cm instanceof DirectColorModel){
+ cmType = DCM;
+ DirectColorModel dcm = (DirectColorModel) cm;
+ masks = dcm.getMasks();
+ smType = SPPSM;
+ SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+ scanlineStride = sppsm.getScanlineStride();
+
+ }else if(cm instanceof IndexColorModel){
+ cmType = ICM;
+ IndexColorModel icm = (IndexColorModel) cm;
+ colorMapSize = icm.getMapSize();
+ colorMap = new int[colorMapSize];
+ icm.getRGBs(colorMap);
+ transpPixel = icm.getTransparentPixel();
+ isGrayPallete = Surface.isGrayPallete(icm);
+
+ if(sm instanceof MultiPixelPackedSampleModel){
+ smType = MPPSM;
+ MultiPixelPackedSampleModel mppsm =
+ (MultiPixelPackedSampleModel) sm;
+ scanlineStride = mppsm.getScanlineStride();
+ }else if(sm instanceof ComponentSampleModel){
+ smType = CSM;
+ ComponentSampleModel csm =
+ (ComponentSampleModel) sm;
+ scanlineStride = csm.getScanlineStride();
+ }else{
+ // awt.4D=The raster is incompatible with this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+ }
+
+ }else if(cm instanceof ComponentColorModel){
+ cmType = CCM;
+ if(sm instanceof ComponentSampleModel){
+ ComponentSampleModel csm = (ComponentSampleModel) sm;
+ scanlineStride = csm.getScanlineStride();
+ bankIndeces = csm.getBankIndices();
+ bandOffsets = csm.getBandOffsets();
+ if(sm instanceof PixelInterleavedSampleModel){
+ smType = PISM;
+ }else if(sm instanceof BandedSampleModel){
+ smType = BSM;
+ }else{
+ smType = CSM;
+ }
+ }else{
+ // awt.4D=The raster is incompatible with this ColorModel
+ throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
+ }
+
+ }else{
+ surfaceDataPtr = 0L;
+ return;
+ }
+ surfaceDataPtr = createSurfStruct(surfaceType, width, height, cmType, csType, smType, dataType,
+ numComponents, pixelStride, scanlineStride, bits, masks, colorMapSize,
+ colorMap, transpPixel, isGrayPallete, bankIndeces, bandOffsets,
+ offset, hasAlpha, isAlphaPre, transparency);
+ }
+
+ @Override
+ public void dispose() {
+ if(surfaceDataPtr != 0L){
+ dispose(surfaceDataPtr);
+ surfaceDataPtr = 0L;
+ }
+ }
+
+ public long getCachedData(boolean alphaPre){
+ if(nativeDrawable){
+ if(cachedDataPtr == 0L || needToRefresh || this.alphaPre != alphaPre){
+ cachedDataPtr = updateCache(getSurfaceDataPtr(), data, alphaPre);
+ this.alphaPre = alphaPre;
+ validate();
+ }
+ }
+ return cachedDataPtr;
+ }
+
+ private native long createSurfStruct(int surfaceType, int width, int height,
+ int cmType, int csType, int smType, int dataType,
+ int numComponents, int pixelStride, int scanlineStride,
+ int bits[], int masks[], int colorMapSize, int colorMap[],
+ int transpPixel, boolean isGrayPalette, int bankIndeces[],
+ int bandOffsets[], int offset, boolean hasAlpha, boolean isAlphaPre,
+ int transparency);
+
+ private native void dispose(long structPtr);
+
+ private native void setImageSize(long structPtr, int width, int height);
+
+ private native long updateCache(long structPtr, Object data, boolean alphaPre);
+
+ /**
+ * Supposes that new raster is compatible with an old one
+ * @param r
+ */
+ public void setRaster(WritableRaster r) {
+ raster = r;
+ data = AwtImageBackdoorAccessor.getInstance().getData(r.getDataBuffer());
+ if (surfaceDataPtr != 0) {
+ setImageSize(surfaceDataPtr, r.getWidth(), r.getHeight());
+ }
+ this.width = r.getWidth();
+ this.height = r.getHeight();
+ }
+
+ @Override
+ public long lock() {
+ // TODO
+ return 0;
+ }
+
+ @Override
+ public void unlock() {
+ //TODO
+ }
+
+ @Override
+ public Surface getImageSurface() {
+ return this;
+ }
+
+ public void dataChanged() {
+ needToRefresh = true;
+ clearValidCaches();
+ }
+
+ public void dataTaken() {
+ dataTaken = true;
+ needToRefresh = true;
+ clearValidCaches();
+ }
+
+ public void dataReleased(){
+ dataTaken = false;
+ needToRefresh = true;
+ clearValidCaches();
+ }
+
+ @Override
+ public void invalidate(){
+ needToRefresh = true;
+ clearValidCaches();
+ }
+
+ @Override
+ public void validate(){
+ if(!needToRefresh) {
+ return;
+ }
+ if(!dataTaken){
+ needToRefresh = false;
+ AwtImageBackdoorAccessor ba = AwtImageBackdoorAccessor.getInstance();
+ ba.validate(raster.getDataBuffer());
+ }
+
+ }
+
+ @Override
+ public boolean invalidated(){
+ return needToRefresh;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/MultiRectArea.java b/awt/org/apache/harmony/awt/gl/MultiRectArea.java
new file mode 100644
index 0000000..c4267f3
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/MultiRectArea.java
@@ -0,0 +1,836 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class MultiRectArea implements Shape {
+
+ /**
+ * If CHECK is true validation check active
+ */
+ private static final boolean CHECK = false;
+
+ boolean sorted = true;
+
+ /**
+ * Rectangle buffer
+ */
+ public int[] rect;
+
+ /**
+ * Bounding box
+ */
+ Rectangle bounds;
+
+ /**
+ * Result rectangle array
+ */
+ Rectangle[] rectangles;
+
+ /**
+ * LineCash provides creating MultiRectArea line by line. Used in JavaShapeRasterizer.
+ */
+ public static class LineCash extends MultiRectArea {
+
+ int lineY;
+ int bottomCount;
+ int[] bottom;
+
+ public LineCash(int size) {
+ super();
+ bottom = new int[size];
+ bottomCount = 0;
+ }
+
+ public void setLine(int y) {
+ lineY = y;
+ }
+
+ public void skipLine() {
+ lineY++;
+ bottomCount = 0;
+ }
+
+ public void addLine(int[] points, int pointCount) {
+ int bottomIndex = 0;
+ int pointIndex = 0;
+ int rectIndex = 0;
+ int pointX1 = 0;
+ int pointX2 = 0;
+ int bottomX1 = 0;
+ int bottomX2 = 0;
+ boolean appendRect = false;
+ boolean deleteRect = false;
+ int lastCount = bottomCount;
+
+ while (bottomIndex < lastCount || pointIndex < pointCount) {
+
+ appendRect = false;
+ deleteRect = false;
+
+ if (bottomIndex < lastCount) {
+ rectIndex = bottom[bottomIndex];
+ bottomX1 = rect[rectIndex];
+ bottomX2 = rect[rectIndex + 2];
+ } else {
+ appendRect = true;
+ }
+
+ if (pointIndex < pointCount) {
+ pointX1 = points[pointIndex];
+ pointX2 = points[pointIndex + 1];
+ } else {
+ deleteRect = true;
+ }
+
+ if (!deleteRect && !appendRect) {
+ if (pointX1 == bottomX1 && pointX2 == bottomX2) {
+ rect[rectIndex + 3] = rect[rectIndex + 3] + 1;
+ pointIndex += 2;
+ bottomIndex++;
+ continue;
+ }
+ deleteRect = pointX2 >= bottomX1;
+ appendRect = pointX1 <= bottomX2;
+ }
+
+ if (deleteRect) {
+ if (bottomIndex < bottomCount - 1) {
+ System.arraycopy(bottom, bottomIndex + 1, bottom, bottomIndex, bottomCount - bottomIndex - 1);
+ rectIndex -= 4;
+ }
+ bottomCount--;
+ lastCount--;
+ }
+
+ if (appendRect) {
+ int i = rect[0];
+ bottom[bottomCount++] = i;
+ rect = MultiRectAreaOp.checkBufSize(rect, 4);
+ rect[i++] = pointX1;
+ rect[i++] = lineY;
+ rect[i++] = pointX2;
+ rect[i++] = lineY;
+ pointIndex += 2;
+ }
+ }
+ lineY++;
+
+ invalidate();
+ }
+
+ }
+
+ /**
+ * RectCash provides simple creating MultiRectArea
+ */
+ public static class RectCash extends MultiRectArea {
+
+ int[] cash;
+
+ public RectCash() {
+ super();
+ cash = new int[MultiRectAreaOp.RECT_CAPACITY];
+ cash[0] = 1;
+ }
+
+ public void addRectCashed(int x1, int y1, int x2, int y2) {
+ addRect(x1, y1, x2, y2);
+ invalidate();
+/*
+ // Exclude from cash unnecessary rectangles
+ int i = 1;
+ while(i < cash[0]) {
+ if (rect[cash[i] + 3] >= y1 - 1) {
+ if (i > 1) {
+ System.arraycopy(cash, i, cash, 1, cash[0] - i);
+ }
+ break;
+ }
+ i++;
+ }
+ cash[0] -= i - 1;
+
+ // Find in cash rectangle to concatinate
+ i = 1;
+ while(i < cash[0]) {
+ int index = cash[i];
+ if (rect[index + 3] != y1 - 1) {
+ break;
+ }
+ if (rect[index] == x1 && rect[index + 2] == x2) {
+ rect[index + 3] += y2 - y1 + 1;
+
+ int pos = i + 1;
+ while(pos < cash[0]) {
+ if (rect[index + 3] <= rect[cash[i] + 3]) {
+ System.arraycopy(cash, i + 1, cash, i, pos - i);
+ break;
+ }
+ i++;
+ }
+ cash[pos - 1] = index;
+
+ invalidate();
+ return;
+ }
+ i++;
+ }
+
+ // Add rectangle to buffer
+ int index = rect[0];
+ rect = MultiRectAreaOp.checkBufSize(rect, 4);
+ rect[index + 0] = x1;
+ rect[index + 1] = y1;
+ rect[index + 2] = x2;
+ rect[index + 3] = y2;
+
+ // Add rectangle to cash
+ int length = cash[0];
+ cash = MultiRectAreaOp.checkBufSize(cash, 1);
+ while(i < length) {
+ if (y2 <= rect[cash[i] + 3]) {
+ System.arraycopy(cash, i, cash, i + 1, length - i);
+ break;
+ }
+ i++;
+ }
+ cash[i] = index;
+ invalidate();
+*/
+ }
+
+ public void addRectCashed(int[] rect, int rectOff, int rectLength) {
+ for(int i = rectOff; i < rectOff + rectLength;) {
+ addRect(rect[i++], rect[i++], rect[i++], rect[i++]);
+// addRectCashed(rect[i++], rect[i++], rect[i++], rect[i++]);
+ }
+ }
+
+ }
+
+ /**
+ * MultiRectArea path iterator
+ */
+ class Iterator implements PathIterator {
+
+ int type;
+ int index;
+ int pos;
+
+ int[] rect;
+ AffineTransform t;
+
+ Iterator(MultiRectArea mra, AffineTransform t) {
+ rect = new int[mra.rect[0] - 1];
+ System.arraycopy(mra.rect, 1, rect, 0, rect.length);
+ this.t = t;
+ }
+
+ public int getWindingRule() {
+ return WIND_NON_ZERO;
+ }
+
+ public boolean isDone() {
+ return pos >= rect.length;
+ }
+
+ public void next() {
+ if (index == 4) {
+ pos += 4;
+ }
+ index = (index + 1) % 5;
+ }
+
+ public int currentSegment(double[] coords) {
+ if (isDone()) {
+ // awt.4B=Iiterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type = 0;
+
+ switch(index) {
+ case 0 :
+ type = SEG_MOVETO;
+ coords[0] = rect[pos + 0];
+ coords[1] = rect[pos + 1];
+ break;
+ case 1:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 2];
+ coords[1] = rect[pos + 1];
+ break;
+ case 2:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 2];
+ coords[1] = rect[pos + 3];
+ break;
+ case 3:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 0];
+ coords[1] = rect[pos + 3];
+ break;
+ case 4:
+ type = SEG_CLOSE;
+ break;
+ }
+
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ // awt.4B=Iiterator out of bounds
+ throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$
+ }
+ int type = 0;
+
+ switch(index) {
+ case 0 :
+ type = SEG_MOVETO;
+ coords[0] = rect[pos + 0];
+ coords[1] = rect[pos + 1];
+ break;
+ case 1:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 2];
+ coords[1] = rect[pos + 1];
+ break;
+ case 2:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 2];
+ coords[1] = rect[pos + 3];
+ break;
+ case 3:
+ type = SEG_LINETO;
+ coords[0] = rect[pos + 0];
+ coords[1] = rect[pos + 3];
+ break;
+ case 4:
+ type = SEG_CLOSE;
+ break;
+ }
+
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, 1);
+ }
+ return type;
+ }
+
+ }
+
+ /**
+ * Constructs a new empty MultiRectArea
+ */
+ public MultiRectArea() {
+ rect = MultiRectAreaOp.createBuf(0);
+ }
+
+ public MultiRectArea(boolean sorted) {
+ this();
+ this.sorted = sorted;
+ }
+
+ /**
+ * Constructs a new MultiRectArea as a copy of another one
+ */
+ public MultiRectArea(MultiRectArea mra) {
+ if (mra == null) {
+ rect = MultiRectAreaOp.createBuf(0);
+ } else {
+ rect = new int[mra.rect.length];
+ System.arraycopy(mra.rect, 0, rect, 0, mra.rect.length);
+ check(this, "MultiRectArea(MRA)"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Constructs a new MultiRectArea consists of single rectangle
+ */
+ public MultiRectArea(Rectangle r) {
+ rect = MultiRectAreaOp.createBuf(0);
+ if (r != null && !r.isEmpty()) {
+ rect[0] = 5;
+ rect[1] = r.x;
+ rect[2] = r.y;
+ rect[3] = r.x + r.width - 1;
+ rect[4] = r.y + r.height - 1;
+ }
+ check(this, "MultiRectArea(Rectangle)"); //$NON-NLS-1$
+ }
+
+ /**
+ * Constructs a new MultiRectArea consists of single rectangle
+ */
+ public MultiRectArea(int x0, int y0, int x1, int y1) {
+ rect = MultiRectAreaOp.createBuf(0);
+ if (x1 >= x0 && y1 >= y0) {
+ rect[0] = 5;
+ rect[1] = x0;
+ rect[2] = y0;
+ rect[3] = x1;
+ rect[4] = y1;
+ }
+ check(this, "MultiRectArea(Rectangle)"); //$NON-NLS-1$
+ }
+
+ /**
+ * Constructs a new MultiRectArea and append rectangle from buffer
+ */
+ public MultiRectArea(Rectangle[] buf) {
+ this();
+ for (Rectangle element : buf) {
+ add(element);
+ }
+ }
+
+ /**
+ * Constructs a new MultiRectArea and append rectangle from array
+ */
+ public MultiRectArea(ArrayList<Rectangle> buf) {
+ this();
+ for(int i = 0; i < buf.size(); i++) {
+ add(buf.get(i));
+ }
+ }
+
+ /**
+ * Sort rectangle buffer
+ */
+ void resort() {
+ int[] buf = new int[4];
+ for(int i = 1; i < rect[0]; i += 4) {
+ int k = i;
+ int x1 = rect[k];
+ int y1 = rect[k + 1];
+ for(int j = i + 4; j < rect[0]; j += 4) {
+ int x2 = rect[j];
+ int y2 = rect[j + 1];
+ if (y1 > y2 || (y1 == y2 && x1 > x2)) {
+ x1 = x2;
+ y1 = y2;
+ k = j;
+ }
+ }
+ if (k != i) {
+ System.arraycopy(rect, i, buf, 0, 4);
+ System.arraycopy(rect, k, rect, i, 4);
+ System.arraycopy(buf, 0, rect, k, 4);
+ }
+ }
+ invalidate();
+ }
+
+ /**
+ * Tests equals with another object
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof MultiRectArea) {
+ MultiRectArea mra = (MultiRectArea) obj;
+ for(int i = 0; i < rect[0]; i++) {
+ if (rect[i] != mra.rect[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks validation of MultiRectArea object
+ */
+ static MultiRectArea check(MultiRectArea mra, String msg) {
+ if (CHECK && mra != null) {
+ if (MultiRectArea.checkValidation(mra.getRectangles(), mra.sorted) != -1) {
+ // awt.4C=Invalid MultiRectArea in method {0}
+ new RuntimeException(Messages.getString("awt.4C", msg)); //$NON-NLS-1$
+ }
+ }
+ return mra;
+ }
+
+ /**
+ * Checks validation of MultiRectArea object
+ */
+ public static int checkValidation(Rectangle[] r, boolean sorted) {
+
+ // Check width and height
+ for(int i = 0; i < r.length; i++) {
+ if (r[i].width <= 0 || r[i].height <= 0) {
+ return i;
+ }
+ }
+
+ // Check order
+ if (sorted) {
+ for(int i = 1; i < r.length; i++) {
+ if (r[i - 1].y > r[i].y) {
+ return i;
+ }
+ if (r[i - 1].y == r[i].y) {
+ if (r[i - 1].x > r[i].x) {
+ return i;
+ }
+ }
+ }
+ }
+
+ // Check override
+ for(int i = 0; i < r.length; i++) {
+ for(int j = i + 1; j < r.length; j++) {
+ if (r[i].intersects(r[j])) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Assigns rectangle from another buffer
+ */
+ protected void setRect(int[] buf, boolean copy) {
+ if (copy) {
+ rect = new int[buf.length];
+ System.arraycopy(buf, 0, rect, 0, buf.length);
+ } else {
+ rect = buf;
+ }
+ invalidate();
+ }
+
+ /**
+ * Union with another MultiRectArea object
+ */
+ public void add(MultiRectArea mra) {
+ setRect(union(this, mra).rect, false);
+ invalidate();
+ }
+
+ /**
+ * Intersect with another MultiRectArea object
+ */
+ public void intersect(MultiRectArea mra) {
+ setRect(intersect(this, mra).rect, false);
+ invalidate();
+ }
+
+ /**
+ * Subtract another MultiRectArea object
+ */
+ public void substract(MultiRectArea mra) {
+ setRect(subtract(this, mra).rect, false);
+ invalidate();
+ }
+
+ /**
+ * Union with Rectangle object
+ */
+ public void add(Rectangle rect) {
+ setRect(union(this, new MultiRectArea(rect)).rect, false);
+ invalidate();
+ }
+
+ /**
+ * Intersect with Rectangle object
+ */
+ public void intersect(Rectangle rect) {
+ setRect(intersect(this, new MultiRectArea(rect)).rect, false);
+ invalidate();
+ }
+
+ /**
+ * Subtract rectangle object
+ */
+ public void substract(Rectangle rect) {
+ setRect(subtract(this, new MultiRectArea(rect)).rect, false);
+ }
+
+ /**
+ * Union two MutliRectareArea objects
+ */
+ public static MultiRectArea intersect(MultiRectArea src1, MultiRectArea src2) {
+ MultiRectArea res = check(MultiRectAreaOp.Intersection.getResult(src1, src2), "intersect(MRA,MRA)"); //$NON-NLS-1$
+ return res;
+ }
+
+ /**
+ * Intersect two MultiRectArea objects
+ */
+ public static MultiRectArea union(MultiRectArea src1, MultiRectArea src2) {
+ MultiRectArea res = check(new MultiRectAreaOp.Union().getResult(src1, src2), "union(MRA,MRA)"); //$NON-NLS-1$
+ return res;
+ }
+
+ /**
+ * Subtract two MultiRectArea objects
+ */
+ public static MultiRectArea subtract(MultiRectArea src1, MultiRectArea src2) {
+ MultiRectArea res = check(MultiRectAreaOp.Subtraction.getResult(src1, src2), "subtract(MRA,MRA)"); //$NON-NLS-1$
+ return res;
+ }
+
+ /**
+ * Print MultiRectArea object to output stream
+ */
+ public static void print(MultiRectArea mra, String msg) {
+ if (mra == null) {
+ System.out.println(msg + "=null"); //$NON-NLS-1$
+ } else {
+ Rectangle[] rects = mra.getRectangles();
+ System.out.println(msg + "(" + rects.length + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ for (Rectangle element : rects) {
+ System.out.println(
+ element.x + "," + //$NON-NLS-1$
+ element.y + "," + //$NON-NLS-1$
+ (element.x + element.width - 1) + "," + //$NON-NLS-1$
+ (element.y + element.height - 1));
+ }
+ }
+ }
+
+ /**
+ * Translate MultiRectArea object by (x, y)
+ */
+ public void translate(int x, int y) {
+ for(int i = 1; i < rect[0];) {
+ rect[i++] += x;
+ rect[i++] += y;
+ rect[i++] += x;
+ rect[i++] += y;
+ }
+
+ if (bounds != null && !bounds.isEmpty()) {
+ bounds.translate(x, y);
+ }
+
+ if (rectangles != null) {
+ for (Rectangle element : rectangles) {
+ element.translate(x, y);
+ }
+ }
+ }
+
+ /**
+ * Add rectangle to the buffer without any checking
+ */
+ public void addRect(int x1, int y1, int x2, int y2) {
+ int i = rect[0];
+ rect = MultiRectAreaOp.checkBufSize(rect, 4);
+ rect[i++] = x1;
+ rect[i++] = y1;
+ rect[i++] = x2;
+ rect[i++] = y2;
+ }
+
+ /**
+ * Tests is MultiRectArea empty
+ */
+ public boolean isEmpty() {
+ return rect[0] == 1;
+ }
+
+ void invalidate() {
+ bounds = null;
+ rectangles = null;
+ }
+
+ /**
+ * Returns bounds of MultiRectArea object
+ */
+ public Rectangle getBounds() {
+ if (bounds != null) {
+ return bounds;
+ }
+
+ if (isEmpty()) {
+ return bounds = new Rectangle();
+ }
+
+ int x1 = rect[1];
+ int y1 = rect[2];
+ int x2 = rect[3];
+ int y2 = rect[4];
+
+ for(int i = 5; i < rect[0]; i += 4) {
+ int rx1 = rect[i + 0];
+ int ry1 = rect[i + 1];
+ int rx2 = rect[i + 2];
+ int ry2 = rect[i + 3];
+ if (rx1 < x1) {
+ x1 = rx1;
+ }
+ if (rx2 > x2) {
+ x2 = rx2;
+ }
+ if (ry1 < y1) {
+ y1 = ry1;
+ }
+ if (ry2 > y2) {
+ y2 = ry2;
+ }
+ }
+
+ return bounds = new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+ }
+
+ /**
+ * Recturn rectangle count in the buffer
+ */
+ public int getRectCount() {
+ return (rect[0] - 1) / 4;
+ }
+
+ /**
+ * Returns Rectangle array
+ */
+ public Rectangle[] getRectangles() {
+ if (rectangles != null) {
+ return rectangles;
+ }
+
+ rectangles = new Rectangle[(rect[0] - 1) / 4];
+ int j = 0;
+ for(int i = 1; i < rect[0]; i += 4) {
+ rectangles[j++] = new Rectangle(
+ rect[i],
+ rect[i + 1],
+ rect[i + 2] - rect[i] + 1,
+ rect[i + 3] - rect[i + 1] + 1);
+ }
+ return rectangles;
+ }
+
+ /**
+ * Returns Bounds2D
+ */
+ public Rectangle2D getBounds2D() {
+ return getBounds();
+ }
+
+ /**
+ * Tests does point lie inside MultiRectArea object
+ */
+ public boolean contains(double x, double y) {
+ for(int i = 1; i < rect[0]; i+= 4) {
+ if (rect[i] <= x && x <= rect[i + 2] && rect[i + 1] <= y && y <= rect[i + 3]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tests does Point2D lie inside MultiRectArea object
+ */
+ public boolean contains(Point2D p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ /**
+ * Tests does rectangle lie inside MultiRectArea object
+ */
+ public boolean contains(double x, double y, double w, double h) {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Tests does Rectangle2D lie inside MultiRectArea object
+ */
+ public boolean contains(Rectangle2D r) {
+ throw new RuntimeException("Not implemented"); //$NON-NLS-1$
+ }
+
+ /**
+ * Tests does rectangle intersect MultiRectArea object
+ */
+ public boolean intersects(double x, double y, double w, double h) {
+ Rectangle r = new Rectangle();
+ r.setRect(x, y, w, h);
+ return intersects(r);
+ }
+
+ /**
+ * Tests does Rectangle2D intersect MultiRectArea object
+ */
+ public boolean intersects(Rectangle2D r) {
+ if (r == null || r.isEmpty()) {
+ return false;
+ }
+ for(int i = 1; i < rect[0]; i+= 4) {
+ if (r.intersects(rect[i], rect[i+1], rect[i + 2]-rect[i]+1, rect[i + 3]-rect[i + 1]+1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns path iterator
+ */
+ public PathIterator getPathIterator(AffineTransform t, double flatness) {
+ return new Iterator(this, t);
+ }
+
+ /**
+ * Returns path iterator
+ */
+ public PathIterator getPathIterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ /**
+ * Returns MultiRectArea object converted to string
+ */
+ @Override
+ public String toString() {
+ int cnt = getRectCount();
+ StringBuffer sb = new StringBuffer((cnt << 5) + 128);
+ sb.append(getClass().getName()).append(" ["); //$NON-NLS-1$
+ for(int i = 1; i < rect[0]; i += 4) {
+ sb.append(i > 1 ? ", [" : "[").append(rect[i]).append(", ").append(rect[i + 1]). //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ append(", ").append(rect[i + 2] - rect[i] + 1).append(", "). //$NON-NLS-1$ //$NON-NLS-2$
+ append(rect[i + 3] - rect[i + 1] + 1).append("]"); //$NON-NLS-1$
+ }
+ return sb.append("]").toString(); //$NON-NLS-1$
+ }
+
+}
+
diff --git a/awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java b/awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java
new file mode 100644
index 0000000..c75e203
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/MultiRectAreaOp.java
@@ -0,0 +1,837 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Rectangle;
+
+public class MultiRectAreaOp {
+
+ /**
+ * Rectangle buffer capacity
+ */
+ public static final int RECT_CAPACITY = 16;
+
+ /**
+ * If number of rectangle in MultiRectArea object less than MAX_SIMPLE simple algorithm applies
+ */
+ private static final int MAX_SIMPLE = 8;
+
+ /**
+ * Create buffer
+ */
+ public static int[] createBuf(int capacity) {
+ if (capacity == 0) {
+ capacity = RECT_CAPACITY;
+ }
+ int[] buf = new int[capacity];
+ buf[0] = 1;
+ return buf;
+ }
+
+ /**
+ * Checks buffer size and reallocate if necessary
+ */
+ public static int[] checkBufSize(int[] buf, int capacity) {
+ if (buf[0] + capacity >= buf.length) {
+ int length = buf[0] + (capacity > RECT_CAPACITY ? capacity : RECT_CAPACITY);
+ int[] tmp = new int[length];
+ System.arraycopy(buf, 0, tmp, 0, buf[0]);
+ buf = tmp;
+ }
+ buf[0] += capacity;
+ return buf;
+ }
+
+ /**
+ * Region class provides basic functionlity for MultiRectArea objects to make logical operations
+ */
+ static class Region {
+
+ int[] region;
+ int[] active;
+ int[] bottom;
+ int index;
+
+ public Region(int[] region) {
+ this.region = region;
+ active = new int[RECT_CAPACITY];
+ bottom = new int[RECT_CAPACITY];
+ active[0] = 1;
+ bottom[0] = 1;
+ index = 1;
+ }
+
+ void addActive(int index) {
+ int length = active[0];
+ active = checkBufSize(active, 4);
+ int i = 1;
+
+ while(i < length) {
+ if (region[index] < active[i]) {
+ // Insert
+ System.arraycopy(active, i, active, i + 4, length - i);
+ length = i;
+ break;
+ }
+ i += 4;
+ }
+ System.arraycopy(region, index, active, length, 4);
+
+ }
+
+ void findActive(int top, int bottom) {
+ while(index < region[0]) {
+ if (region[index + 1] > bottom) { // y1 > bottom
+ return;
+ }
+ if (region[index + 3] >= top) { // y2 >= top
+ addActive(index);
+ }
+ index += 4;
+ }
+ }
+
+ void deleteActive(int bottom) {
+ int length = active[0];
+ for(int i = 1; i < length;) {
+ if (active[i + 3] == bottom) {
+ length -= 4;
+ if (i < length) {
+ System.arraycopy(active, i + 4, active, i, length - i);
+ }
+ } else {
+ i += 4;
+ }
+ }
+ active[0] = length;
+ }
+
+ void deleteActive() {
+ int length = active[0];
+ for(int i = length - 4; i > 0; i -= 4) {
+ if (active[i + 1] > active[i + 3]) {
+ length -= 4;
+ if (i < length) {
+ System.arraycopy(active, i + 4, active, i, length - i);
+ }
+ }
+ }
+ active[0] = length;
+ }
+
+ void createLevel(int[] level) {
+ int levelCount = 1;
+ int topIndex = 1;
+ int i = 1;
+ while(i < region[0]) {
+
+ int top = region[i + 1];
+ int bottom = region[i + 3] + 1;
+ int j = topIndex;
+
+ addTop: {
+ while(j < levelCount) {
+ if (level[j] == top) {
+ break addTop;
+ }
+ if (level[j] > top) {
+ System.arraycopy(level, j, level, j + 1, levelCount - j);
+ break;
+ }
+ j++;
+ }
+
+ level[j] = top;
+ levelCount++;
+ topIndex = j;
+ }
+
+ addBottom: {
+ while(j < levelCount) {
+ if (level[j] == bottom) {
+ break addBottom;
+ }
+ if (level[j] > bottom) {
+ System.arraycopy(level, j, level, j + 1, levelCount - j);
+ break;
+ }
+ j++;
+ };
+
+ level[j] = bottom;
+ levelCount++;
+ }
+
+ i += 4;
+ }
+ level[0] = levelCount;
+ }
+
+ static void sortOrdered(int[] src1, int[] src2, int[] dst) {
+ int length1 = src1[0];
+ int length2 = src2[0];
+ int count = 1;
+ int i1 = 1;
+ int i2 = 1;
+ int v1 = src1[1];
+ int v2 = src2[1];
+ while(true) {
+
+ LEFT: {
+ while(i1 < length1) {
+ v1 = src1[i1];
+ if (v1 >= v2) {
+ break LEFT;
+ }
+ dst[count++] = v1;
+ i1++;
+ }
+ while(i2 < length2) {
+ dst[count++] = src2[i2++];
+ }
+ dst[0] = count;
+ return;
+ }
+
+ RIGHT: {
+ while(i2 < length2) {
+ v2 = src2[i2];
+ if (v2 >= v1) {
+ break RIGHT;
+ }
+ dst[count++] = v2;
+ i2++;
+ }
+ while(i1 < length1) {
+ dst[count++] = src1[i1++];
+ }
+ dst[0] = count;
+ return;
+ }
+
+ if (v1 == v2) {
+ dst[count++] = v1;
+ i1++;
+ i2++;
+ if (i1 < length1) {
+ v1 = src1[i1];
+ }
+ if (i2 < length2 - 1) {
+ v2 = src2[i2];
+ }
+ }
+ }
+ // UNREACHABLE
+ }
+
+ }
+
+ /**
+ * Intersection class provides intersection of two MultiRectAre aobjects
+ */
+ static class Intersection {
+
+ static void intersectRegions(int[] reg1, int[] reg2, MultiRectArea.RectCash dst, int height1, int height2) {
+
+ Region d1 = new Region(reg1);
+ Region d2 = new Region(reg2);
+
+ int[] level = new int[height1 + height2];
+ int[] level1 = new int[height1];
+ int[] level2 = new int[height2];
+ d1.createLevel(level1);
+ d2.createLevel(level2);
+ Region.sortOrdered(level1, level2, level);
+
+ int top;
+ int bottom = level[1] - 1;
+ for(int i = 2; i < level[0]; i++) {
+
+ top = bottom + 1;
+ bottom = level[i] - 1;
+
+ d1.findActive(top, bottom);
+ d2.findActive(top, bottom);
+
+ int i1 = 1;
+ int i2 = 1;
+
+ while(i1 < d1.active[0] && i2 < d2.active[0]) {
+
+ int x11 = d1.active[i1];
+ int x12 = d1.active[i1 + 2];
+ int x21 = d2.active[i2];
+ int x22 = d2.active[i2 + 2];
+
+ if (x11 <= x21) {
+ if (x12 >= x21) {
+ if (x12 <= x22) {
+ dst.addRectCashed(x21, top, x12, bottom);
+ i1 += 4;
+ } else {
+ dst.addRectCashed(x21, top, x22, bottom);
+ i2 += 4;
+ }
+ } else {
+ i1 += 4;
+ }
+ } else {
+ if (x22 >= x11) {
+ if (x22 <= x12) {
+ dst.addRectCashed(x11, top, x22, bottom);
+ i2 += 4;
+ } else {
+ dst.addRectCashed(x11, top, x12, bottom);
+ i1 += 4;
+ }
+ } else {
+ i2 += 4;
+ }
+ }
+ }
+
+ d1.deleteActive(bottom);
+ d2.deleteActive(bottom);
+ }
+ }
+
+ static int[] simpleIntersect(MultiRectArea src1, MultiRectArea src2) {
+ int[] rect1 = src1.rect;
+ int[] rect2 = src2.rect;
+ int[] rect = createBuf(0);
+
+ int k = 1;
+ for(int i = 1; i < rect1[0];) {
+
+ int x11 = rect1[i++];
+ int y11 = rect1[i++];
+ int x12 = rect1[i++];
+ int y12 = rect1[i++];
+
+ for(int j = 1; j < rect2[0];) {
+
+ int x21 = rect2[j++];
+ int y21 = rect2[j++];
+ int x22 = rect2[j++];
+ int y22 = rect2[j++];
+
+ if (x11 <= x22 && x12 >= x21 &&
+ y11 <= y22 && y12 >= y21)
+ {
+ rect = checkBufSize(rect, 4);
+ rect[k++] = x11 > x21 ? x11 : x21;
+ rect[k++] = y11 > y21 ? y11 : y21;
+ rect[k++] = x12 > x22 ? x22 : x12;
+ rect[k++] = y12 > y22 ? y22 : y12;
+ }
+ }
+ }
+
+ rect[0] = k;
+ return rect;
+ }
+
+ public static MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) {
+
+ if (src1 == null || src2 == null || src1.isEmpty() || src2.isEmpty()) {
+ return new MultiRectArea();
+ }
+
+ MultiRectArea.RectCash dst = new MultiRectArea.RectCash();
+
+ if (!src1.sorted || !src2.sorted ||
+ src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE)
+ {
+ dst.setRect(simpleIntersect(src1, src2), false);
+ } else {
+ Rectangle bounds1 = src1.getBounds();
+ Rectangle bounds2 = src2.getBounds();
+ Rectangle bounds3 = bounds1.intersection(bounds2);
+ if (bounds3.width > 0 && bounds3.height > 0) {
+ intersectRegions(src1.rect, src2.rect, dst, bounds1.height + 2, bounds2.height + 2);
+ }
+ }
+
+ return dst;
+ }
+
+ }
+
+ /**
+ * Union class provides union of two MultiRectAre aobjects
+ */
+ static class Union {
+
+ int rx1, rx2;
+ int top, bottom;
+ MultiRectArea.RectCash dst;
+
+ boolean next(Region d, int index) {
+ int x1 = d.active[index];
+ int x2 = d.active[index + 2];
+ boolean res = false;
+
+ if (x2 < rx1 - 1) {
+ res = true;
+ dst.addRectCashed(x1, top, x2, bottom);
+ } else
+ if (x1 > rx2 + 1) {
+ res = false;
+ dst.addRectCashed(rx1, top, rx2, bottom);
+ rx1 = x1;
+ rx2 = x2;
+ } else {
+ res = x2 <= rx2;
+ rx1 = Math.min(x1, rx1);
+ rx2 = Math.max(x2, rx2);
+ }
+
+ // Top
+ if (d.active[index + 1] < top) {
+ dst.addRectCashed(x1, d.active[index + 1], x2, top - 1);
+ }
+ // Bottom
+ if (d.active[index + 3] > bottom) {
+ d.active[index + 1] = bottom + 1;
+ }
+ return res;
+ }
+
+ void check(Region d, int index, boolean t) {
+ int x1 = d.active[index];
+ int x2 = d.active[index + 2];
+ // Top
+ if (d.active[index + 1] < top) {
+ dst.addRectCashed(x1, d.active[index + 1], x2, top - 1);
+ }
+ if (t) {
+ dst.addRectCashed(x1, top, x2, bottom);
+ }
+ // Bottom
+ if (d.active[index + 3] > bottom) {
+ d.active[index + 1] = bottom + 1;
+ }
+ }
+
+ void unionRegions(int[] reg1, int[] reg2, int height1, int height2) {
+ Region d1 = new Region(reg1);
+ Region d2 = new Region(reg2);
+
+ int[] level = new int[height1 + height2];
+ int[] level1 = new int[height1];
+ int[] level2 = new int[height2];
+ d1.createLevel(level1);
+ d2.createLevel(level2);
+ Region.sortOrdered(level1, level2, level);
+
+ bottom = level[1] - 1;
+ for(int i = 2; i < level[0]; i++) {
+
+ top = bottom + 1;
+ bottom = level[i] - 1;
+
+ d1.findActive(top, bottom);
+ d2.findActive(top, bottom);
+
+ int i1 = 1;
+ int i2 = 1;
+ boolean res1, res2;
+
+ if (d1.active[0] > 1) {
+ check(d1, 1, false);
+ rx1 = d1.active[1];
+ rx2 = d1.active[3];
+ i1 += 4;
+ res1 = false;
+ res2 = true;
+ } else
+ if (d2.active[0] > 1) {
+ check(d2, 1, false);
+ rx1 = d2.active[1];
+ rx2 = d2.active[3];
+ i2 += 4;
+ res1 = true;
+ res2 = false;
+ } else {
+ continue;
+ }
+
+ outer:
+ while(true) {
+
+ while (res1) {
+ if (i1 >= d1.active[0]) {
+ dst.addRectCashed(rx1, top, rx2, bottom);
+ while(i2 < d2.active[0]) {
+ check(d2, i2, true);
+ i2 += 4;
+ }
+ break outer;
+ }
+ res1 = next(d1, i1);
+ i1 += 4;
+ }
+
+ while (res2) {
+ if (i2 >= d2.active[0]) {
+ dst.addRectCashed(rx1, top, rx2, bottom);
+ while(i1 < d1.active[0]) {
+ check(d1, i1, true);
+ i1 += 4;
+ }
+ break outer;
+ }
+ res2 = next(d2, i2);
+ i2 += 4;
+ }
+
+ res1 = true;
+ res2 = true;
+ } // while
+
+ d1.deleteActive(bottom);
+ d2.deleteActive(bottom);
+
+ }
+ }
+
+ static void simpleUnion(MultiRectArea src1, MultiRectArea src2, MultiRectArea dst) {
+ if (src1.getRectCount() < src2.getRectCount()) {
+ simpleUnion(src2, src1, dst);
+ } else {
+ Subtraction.simpleSubtract(src1, src2, dst);
+ int pos = dst.rect[0];
+ int size = src2.rect[0] - 1;
+ dst.rect = checkBufSize(dst.rect, size);
+ System.arraycopy(src2.rect,1, dst.rect, pos, size);
+ dst.resort();
+ }
+ }
+
+ MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) {
+
+ if (src1 == null || src1.isEmpty()) {
+ return new MultiRectArea(src2);
+ }
+
+ if (src2 == null || src2.isEmpty()) {
+ return new MultiRectArea(src1);
+ }
+
+ dst = new MultiRectArea.RectCash();
+
+ if (!src1.sorted || !src2.sorted ||
+ src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE)
+ {
+ simpleUnion(src1, src2, dst);
+ } else {
+ Rectangle bounds1 = src1.getBounds();
+ Rectangle bounds2 = src2.getBounds();
+ Rectangle bounds3 = bounds1.intersection(bounds2);
+
+ if (bounds3.width < 0 || bounds3.height < 0) {
+ if (bounds1.y + bounds1.height < bounds2.y) {
+ dst.setRect(addVerRegion(src1.rect, src2.rect), false);
+ } else
+ if (bounds2.y + bounds2.height < bounds1.y) {
+ dst.setRect(addVerRegion(src2.rect, src1.rect), false);
+ } else
+ if (bounds1.x < bounds2.x) {
+ dst.setRect(addHorRegion(src1.rect, src2.rect), false);
+ } else {
+ dst.setRect(addHorRegion(src2.rect, src1.rect), false);
+ }
+ } else {
+ unionRegions(src1.rect, src2.rect, bounds1.height + 2, bounds2.height + 2);
+ }
+ }
+
+ return dst;
+ }
+
+ int[] addVerRegion(int[] top, int[] bottom) {
+ int length = top[0] + bottom[0] - 1;
+ int[] dst = new int[length];
+ dst[0] = length;
+ System.arraycopy(top, 1, dst, 1, top[0] - 1);
+ System.arraycopy(bottom, 1, dst, top[0], bottom[0] - 1);
+ return dst;
+ }
+
+ int[] addHorRegion(int[] left, int[] right) {
+ int count1 = left[0];
+ int count2 = right[0];
+ int[] dst = new int[count1 + count2 + 1];
+ int count = 1;
+ int index1 = 1;
+ int index2 = 1;
+
+ int top1 = left[2];
+ int top2 = right[2];
+ int pos1, pos2;
+
+ while(true) {
+
+ if (index1 >= count1) {
+ System.arraycopy(right, index2, dst, count, count2 - index2);
+ count += count2 - index2;
+ break;
+ }
+ if (index2 >= count2) {
+ System.arraycopy(left, index1, dst, count, count1 - index1);
+ count += count1 - index1;
+ break;
+ }
+
+ if (top1 < top2) {
+ pos1 = index1;
+ do {
+ index1 += 4;
+ } while (index1 < count1 && (top1 = left[index1 + 1]) < top2);
+ System.arraycopy(left, pos1, dst, count, index1 - pos1);
+ count += index1 - pos1;
+ continue;
+ }
+
+ if (top1 > top2) {
+ pos2 = index2;
+ do {
+ index2 += 4;
+ } while (index2 < count2 && (top2 = right[index2 + 1]) < top1);
+ System.arraycopy(right, pos2, dst, count, index2 - pos2);
+ count += index2 - pos2;
+ continue;
+ }
+
+ int top = top1;
+ pos1 = index1;
+ pos2 = index2;
+ do {
+ index1 += 4;
+ } while(index1 < count1 && (top1 = left[index1 + 1]) == top);
+ do {
+ index2 += 4;
+ } while(index2 < count2 && (top2 = right[index2 + 1]) == top);
+
+ System.arraycopy(left, pos1, dst, count, index1 - pos1);
+ count += index1 - pos1;
+ System.arraycopy(right, pos2, dst, count, index2 - pos2);
+ count += index2 - pos2;
+ }
+
+ dst[0] = count;
+ return dst;
+ }
+
+ }
+
+ /**
+ * Subtraction class provides subtraction of two MultiRectAre aobjects
+ */
+ static class Subtraction {
+
+ static void subtractRegions(int[] reg1, int[] reg2, MultiRectArea.RectCash dst, int height1, int height2) {
+ Region d1 = new Region(reg1);
+ Region d2 = new Region(reg2);
+
+ int[] level = new int[height1 + height2];
+ int[] level1 = new int[height1];
+ int[] level2 = new int[height2];
+ d1.createLevel(level1);
+ d2.createLevel(level2);
+ Region.sortOrdered(level1, level2, level);
+
+ int top;
+ int bottom = level[1] - 1;
+ for(int i = 2; i < level[0]; i++) {
+
+ top = bottom + 1;
+ bottom = level[i] - 1;
+
+ d1.findActive(top, bottom);
+ if (d1.active[0] == 1) {
+ d2.deleteActive(bottom);
+ continue;
+ }
+
+ d2.findActive(top, bottom);
+
+ int i1 = 1;
+ int i2 = 1;
+
+ int rx1 = 0;
+ int rx2 = 0;
+
+ boolean next = true;
+
+ while(true) {
+
+ if (next) {
+ next = false;
+ if (i1 >= d1.active[0]) {
+ break;
+ }
+ // Bottom
+ d1.active[i1 + 1] = bottom + 1;
+ rx1 = d1.active[i1];
+ rx2 = d1.active[i1 + 2];
+ i1 += 4;
+ }
+
+ if (i2 >= d2.active[0]) {
+ dst.addRectCashed(rx1, top, rx2, bottom);
+ for(int j = i1; j < d1.active[0]; j += 4) {
+ dst.addRectCashed(d1.active[j], top, d1.active[j + 2], bottom);
+ d1.active[j + 1] = bottom + 1;
+ }
+ break;
+ }
+
+ int x1 = d2.active[i2];
+ int x2 = d2.active[i2 + 2];
+
+ if (rx1 < x1) {
+ if (rx2 >= x1) {
+ if (rx2 <= x2) {
+ // [-----------]
+ // [-------------]
+ dst.addRectCashed(rx1, top, x1 - 1, bottom);
+ next = true;
+ } else {
+ // [-----------------]
+ // [------]
+ dst.addRectCashed(rx1, top, x1 - 1, bottom);
+ rx1 = x2 + 1;
+ i2 += 4;
+ }
+ } else {
+ // [-----]
+ // [----]
+ dst.addRectCashed(rx1, top, rx2, bottom);
+ next = true;
+ }
+ } else {
+ if (rx1 <= x2) {
+ if (rx2 <= x2) {
+ // [------]
+ // [-----------]
+ next = true;
+ } else {
+ // [------------]
+ // [---------]
+ rx1 = x2 + 1;
+ i2 += 4;
+ }
+ } else {
+ // [----]
+ // [-----]
+ i2 += 4;
+ }
+ }
+
+ }
+ d1.deleteActive();
+ d2.deleteActive(bottom);
+ }
+ }
+
+ static void subtractRect(int x11, int y11, int x12, int y12, int[] rect, int index, MultiRectArea dst) {
+
+ for(int i = index; i < rect[0]; i += 4) {
+ int x21 = rect[i + 0];
+ int y21 = rect[i + 1];
+ int x22 = rect[i + 2];
+ int y22 = rect[i + 3];
+
+ if (x11 <= x22 && x12 >= x21 && y11 <= y22 && y12 >= y21) {
+ int top, bottom;
+ if (y11 < y21) {
+ subtractRect(x11, y11, x12, y21 - 1, rect, i + 4, dst);
+ top = y21;
+ } else {
+ top = y11;
+ }
+ if (y12 > y22) {
+ subtractRect(x11, y22 + 1, x12, y12, rect, i + 4, dst);
+ bottom = y22;
+ } else {
+ bottom = y12;
+ }
+ if (x11 < x21) {
+ subtractRect(x11, top, x21 - 1, bottom, rect, i + 4, dst);
+ }
+ if (x12 > x22) {
+ subtractRect(x22 + 1, top, x12, bottom, rect, i + 4, dst);
+ }
+ return;
+ }
+ }
+ dst.addRect(x11, y11, x12, y12);
+ }
+
+ static void simpleSubtract(MultiRectArea src1, MultiRectArea src2, MultiRectArea dst) {
+ for(int i = 1; i < src1.rect[0]; i += 4) {
+ subtractRect(
+ src1.rect[i + 0],
+ src1.rect[i + 1],
+ src1.rect[i + 2],
+ src1.rect[i + 3],
+ src2.rect,
+ 1,
+ dst);
+ }
+ dst.resort();
+ }
+
+ public static MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) {
+
+ if (src1 == null || src1.isEmpty()) {
+ return new MultiRectArea();
+ }
+
+ if (src2 == null || src2.isEmpty()) {
+ return new MultiRectArea(src1);
+ }
+
+ MultiRectArea.RectCash dst = new MultiRectArea.RectCash();
+
+ if (!src1.sorted || !src2.sorted ||
+ src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE)
+ {
+ simpleSubtract(src1, src2, dst);
+ } else {
+ Rectangle bounds1 = src1.getBounds();
+ Rectangle bounds2 = src2.getBounds();
+ Rectangle bounds3 = bounds1.intersection(bounds2);
+
+ if (bounds3.width > 0 && bounds3.height > 0) {
+ subtractRegions(src1.rect, src2.rect, dst, bounds1.height + 2, bounds2.height + 2);
+ } else {
+ dst.setRect(src1.rect, true);
+ }
+ }
+
+ return dst;
+ }
+
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/Surface.java b/awt/org/apache/harmony/awt/gl/Surface.java
new file mode 100644
index 0000000..8b0ae38
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/Surface.java
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 10.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Image;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.gl.color.LUTColorConverter;
+
+
+/**
+ * This class is super class for others types of Surfaces.
+ * Surface is storing data and data format description, that are using
+ * in blitting operations
+ */
+public abstract class Surface implements Transparency{
+
+ // Color Space Types
+ public static final int sRGB_CS = 1;
+ public static final int Linear_RGB_CS = 2;
+ public static final int Linear_Gray_CS = 3;
+ public static final int Custom_CS = 0;
+
+ // Color Model Types
+ public static final int DCM = 1; // Direct Color Model
+ public static final int ICM = 2; // Index Color Model
+ public static final int CCM = 3; // Component Color Model
+
+ // Sample Model Types
+ public static final int SPPSM = 1; // Single Pixel Packed Sample Model
+ public static final int MPPSM = 2; // Multi Pixel Packed Sample Model
+ public static final int CSM = 3; // Component Sample Model
+ public static final int PISM = 4; // Pixel Interleaved Sample Model
+ public static final int BSM = 5; // Banded Sample Model
+
+ // Surface Types
+ private static final int ALPHA_MASK = 0xff000000;
+ private static final int RED_MASK = 0x00ff0000;
+ private static final int GREEN_MASK = 0x0000ff00;
+ private static final int BLUE_MASK = 0x000000ff;
+ private static final int RED_BGR_MASK = 0x000000ff;
+ private static final int GREEN_BGR_MASK = 0x0000ff00;
+ private static final int BLUE_BGR_MASK = 0x00ff0000;
+ private static final int RED_565_MASK = 0xf800;
+ private static final int GREEN_565_MASK = 0x07e0;
+ private static final int BLUE_565_MASK = 0x001f;
+ private static final int RED_555_MASK = 0x7c00;
+ private static final int GREEN_555_MASK = 0x03e0;
+ private static final int BLUE_555_MASK = 0x001f;
+
+ static{
+ //???AWT
+ /*
+ System.loadLibrary("gl"); //$NON-NLS-1$
+ initIDs();
+ */
+ }
+
+
+ protected long surfaceDataPtr; // Pointer for Native Surface data
+ protected int transparency = OPAQUE;
+ protected int width;
+ protected int height;
+
+ /**
+ * This list contains caches with the data of this surface that are valid at the moment.
+ * Surface should clear this list when its data is updated.
+ * Caches may check if they are still valid using isCacheValid method.
+ * When cache gets data from the surface, it should call addValidCache method of the surface.
+ */
+ private final ArrayList<Object> validCaches = new ArrayList<Object>();
+
+ public abstract ColorModel getColorModel();
+ public abstract WritableRaster getRaster();
+ public abstract int getSurfaceType(); // Syrface type. It is equal
+ // BufferedImge type
+ /**
+ * Lock Native Surface data
+ */
+ public abstract long lock();
+
+ /**
+ * Unlock Native Surface data
+ */
+ public abstract void unlock();
+
+ /**
+ * Dispose Native Surface data
+ */
+ public abstract void dispose();
+ public abstract Surface getImageSurface();
+
+ public long getSurfaceDataPtr(){
+ return surfaceDataPtr;
+ }
+
+ public final boolean isCaheValid(Object cache) {
+ return validCaches.contains(cache);
+ }
+
+ public final void addValidCache(Object cache) {
+ validCaches.add(cache);
+ }
+
+ protected final void clearValidCaches() {
+ validCaches.clear();
+ }
+
+ /**
+ * Returns could or coldn't the Surface be blit by Native blitter
+ * @return - true if the Surface could be blit by Native blitter,
+ * false in other case
+ */
+ public boolean isNativeDrawable(){
+ return true;
+ }
+
+ public int getTransparency() {
+ return transparency;
+ }
+
+ public int getWidth(){
+ return width;
+ }
+
+ public int getHeight(){
+ return height;
+ }
+
+ /**
+ * If Surface has Raster, this method returns data array of Raster's DataBuffer
+ * @return - data array
+ */
+ public Object getData(){
+ return null;
+ }
+
+ public boolean invalidated(){
+ return true;
+ }
+
+ public void validate(){}
+
+ public void invalidate(){}
+
+ /**
+ * Computation type of BufferedImage or Surface
+ * @param cm - ColorModel
+ * @param raster - WritableRaste
+ * @return - type of BufferedImage
+ */
+ public static int getType(ColorModel cm, WritableRaster raster){
+ int transferType = cm.getTransferType();
+ boolean hasAlpha = cm.hasAlpha();
+ ColorSpace cs = cm.getColorSpace();
+ int csType = cs.getType();
+ SampleModel sm = raster.getSampleModel();
+
+ if(csType == ColorSpace.TYPE_RGB){
+ if(cm instanceof DirectColorModel){
+ DirectColorModel dcm = (DirectColorModel) cm;
+ switch (transferType) {
+ case DataBuffer.TYPE_INT:
+ if (dcm.getRedMask() == RED_MASK &&
+ dcm.getGreenMask() == GREEN_MASK &&
+ dcm.getBlueMask() == BLUE_MASK) {
+ if (!hasAlpha) {
+ return BufferedImage.TYPE_INT_RGB;
+ }
+ if (dcm.getAlphaMask() == ALPHA_MASK) {
+ if (dcm.isAlphaPremultiplied()) {
+ return BufferedImage.TYPE_INT_ARGB_PRE;
+ }
+ return BufferedImage.TYPE_INT_ARGB;
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ } else if (dcm.getRedMask() == RED_BGR_MASK &&
+ dcm.getGreenMask() == GREEN_BGR_MASK &&
+ dcm.getBlueMask() == BLUE_BGR_MASK) {
+ if (!hasAlpha) {
+ return BufferedImage.TYPE_INT_BGR;
+ }
+ } else {
+ return BufferedImage.TYPE_CUSTOM;
+ }
+ case DataBuffer.TYPE_USHORT:
+ if (dcm.getRedMask() == RED_555_MASK &&
+ dcm.getGreenMask() == GREEN_555_MASK &&
+ dcm.getBlueMask() == BLUE_555_MASK && !hasAlpha) {
+ return BufferedImage.TYPE_USHORT_555_RGB;
+ } else if (dcm.getRedMask() == RED_565_MASK &&
+ dcm.getGreenMask() == GREEN_565_MASK &&
+ dcm.getBlueMask() == BLUE_565_MASK) {
+ return BufferedImage.TYPE_USHORT_565_RGB;
+ }
+ default:
+ return BufferedImage.TYPE_CUSTOM;
+ }
+ }else if(cm instanceof IndexColorModel){
+ IndexColorModel icm = (IndexColorModel) cm;
+ int pixelBits = icm.getPixelSize();
+ if(transferType == DataBuffer.TYPE_BYTE){
+ if(sm instanceof MultiPixelPackedSampleModel && !hasAlpha &&
+ pixelBits < 5){
+ return BufferedImage.TYPE_BYTE_BINARY;
+ }else if(pixelBits == 8){
+ return BufferedImage.TYPE_BYTE_INDEXED;
+ }
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ }else if(cm instanceof ComponentColorModel){
+ ComponentColorModel ccm = (ComponentColorModel) cm;
+ if(transferType == DataBuffer.TYPE_BYTE &&
+ sm instanceof ComponentSampleModel){
+ ComponentSampleModel csm =
+ (ComponentSampleModel) sm;
+ int[] offsets = csm.getBandOffsets();
+ int[] bits = ccm.getComponentSize();
+ boolean isCustom = false;
+ for (int i = 0; i < bits.length; i++) {
+ if (bits[i] != 8 ||
+ offsets[i] != offsets.length - 1 - i) {
+ isCustom = true;
+ break;
+ }
+ }
+ if (!isCustom) {
+ if (!ccm.hasAlpha()) {
+ return BufferedImage.TYPE_3BYTE_BGR;
+ } else if (ccm.isAlphaPremultiplied()) {
+ return BufferedImage.TYPE_4BYTE_ABGR_PRE;
+ } else {
+ return BufferedImage.TYPE_4BYTE_ABGR;
+ }
+ }
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ }else if(cs == LUTColorConverter.LINEAR_GRAY_CS){
+ if(cm instanceof ComponentColorModel &&
+ cm.getNumComponents() == 1){
+ int bits[] = cm.getComponentSize();
+ if(transferType == DataBuffer.TYPE_BYTE &&
+ bits[0] == 8){
+ return BufferedImage.TYPE_BYTE_GRAY;
+ }else if(transferType == DataBuffer.TYPE_USHORT &&
+ bits[0] == 16){
+ return BufferedImage.TYPE_USHORT_GRAY;
+ }else{
+ return BufferedImage.TYPE_CUSTOM;
+ }
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ }
+ return BufferedImage.TYPE_CUSTOM;
+ }
+
+ public static Surface getImageSurface(Image image){
+ return AwtImageBackdoorAccessor.getInstance().getImageSurface(image);
+ }
+
+ @Override
+ protected void finalize() throws Throwable{
+ dispose();
+ }
+
+ public static boolean isGrayPallete(IndexColorModel icm){
+ return AwtImageBackdoorAccessor.getInstance().isGrayPallete(icm);
+ }
+
+ /**
+ * Initialization of Native data
+ *
+ */
+ //???AWT: private static native void initIDs();
+}
diff --git a/awt/org/apache/harmony/awt/gl/TextRenderer.java b/awt/org/apache/harmony/awt/gl/TextRenderer.java
new file mode 100644
index 0000000..f57952d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/TextRenderer.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Graphics2D;
+import java.awt.font.GlyphVector;
+
+public abstract class TextRenderer {
+
+ /**
+ * Draws string on specified Graphics at desired position.
+ *
+ * @param g specified Graphics2D object
+ * @param str String object to draw
+ * @param x start X position to draw
+ * @param y start Y position to draw
+ */
+ public abstract void drawString(Graphics2D g, String str, float x, float y);
+
+ /**
+ * Draws string on specified Graphics at desired position.
+ *
+ * @param g specified Graphics2D object
+ * @param str String object to draw
+ * @param x start X position to draw
+ * @param y start Y position to draw
+ */
+ public void drawString(Graphics2D g, String str, int x, int y){
+ drawString(g, str, (float)x, (float)y);
+ }
+
+ /**
+ * Draws GlyphVector on specified Graphics at desired position.
+ *
+ * @param g specified Graphics2D object
+ * @param glyphVector GlyphVector object to draw
+ * @param x start X position to draw
+ * @param y start Y position to draw
+ */
+ public abstract void drawGlyphVector(Graphics2D g, GlyphVector glyphVector, float x, float y);
+}
diff --git a/awt/org/apache/harmony/awt/gl/XORComposite.java b/awt/org/apache/harmony/awt/gl/XORComposite.java
new file mode 100644
index 0000000..e27e1d3
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/XORComposite.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 21.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.RenderingHints;
+import java.awt.image.ColorModel;
+
+public class XORComposite implements Composite {
+
+ Color xorcolor;
+
+ public XORComposite(Color xorcolor){
+ this.xorcolor = xorcolor;
+ }
+
+ public CompositeContext createContext(ColorModel srcCM, ColorModel dstCM,
+ RenderingHints hints) {
+
+ return new ICompositeContext(this, srcCM, dstCM);
+ }
+
+ public Color getXORColor(){
+ return xorcolor;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/ColorConverter.java b/awt/org/apache/harmony/awt/gl/color/ColorConverter.java
new file mode 100644
index 0000000..c98e114
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ColorConverter.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+/**
+ * This class combines ColorScaler, ICC_Transform and NativeImageFormat functionality
+ * in the workflows for different types of input/output pixel data.
+ */
+public class ColorConverter {
+ private ColorScaler scaler = new ColorScaler();
+
+ public void loadScalingData(ColorSpace cs) {
+ scaler.loadScalingData(cs);
+ }
+
+ /**
+ * Translates pixels, stored in source buffered image and writes the data
+ * to the destination image.
+ * @param t - ICC transform
+ * @param src - source image
+ * @param dst - destination image
+ */
+ public void translateColor(ICC_Transform t,
+ BufferedImage src, BufferedImage dst) {
+ NativeImageFormat srcIF = NativeImageFormat.createNativeImageFormat(src);
+ NativeImageFormat dstIF = NativeImageFormat.createNativeImageFormat(dst);
+
+ if (srcIF != null && dstIF != null) {
+ t.translateColors(srcIF, dstIF);
+ return;
+ }
+
+ srcIF = createImageFormat(src);
+ dstIF = createImageFormat(dst);
+
+ short srcChanData[] = (short[]) srcIF.getChannelData();
+ short dstChanData[] = (short[]) dstIF.getChannelData();
+
+ ColorModel srcCM = src.getColorModel();
+ int nColorChannels = srcCM.getNumColorComponents();
+ scaler.loadScalingData(srcCM.getColorSpace()); // input scaling data
+ ColorModel dstCM = dst.getColorModel();
+
+ // Prepare array for alpha channel
+ float alpha[] = null;
+ boolean saveAlpha = srcCM.hasAlpha() && dstCM.hasAlpha();
+ if (saveAlpha) {
+ alpha = new float[src.getWidth()*src.getHeight()];
+ }
+
+ WritableRaster wr = src.getRaster();
+ int srcDataPos = 0, alphaPos = 0;
+ float normalizedVal[];
+ for (int row=0, nRows = srcIF.getNumRows(); row<nRows; row++) {
+ for (int col=0, nCols = srcIF.getNumCols(); col<nCols; col++) {
+ normalizedVal = srcCM.getNormalizedComponents(
+ wr.getDataElements(col, row, null),
+ null, 0);
+ // Save alpha channel
+ if (saveAlpha) {
+ // We need nColorChannels'th element cause it's nChannels - 1
+ alpha[alphaPos++] = normalizedVal[nColorChannels];
+ }
+ scaler.scale(normalizedVal, srcChanData, srcDataPos);
+ srcDataPos += nColorChannels;
+ }
+ }
+
+ t.translateColors(srcIF, dstIF);
+
+ nColorChannels = dstCM.getNumColorComponents();
+ boolean fillAlpha = dstCM.hasAlpha();
+ scaler.loadScalingData(dstCM.getColorSpace()); // output scaling data
+ float dstPixel[] = new float[dstCM.getNumComponents()];
+ int dstDataPos = 0;
+ alphaPos = 0;
+ wr = dst.getRaster();
+
+ for (int row=0, nRows = dstIF.getNumRows(); row<nRows; row++) {
+ for (int col=0, nCols = dstIF.getNumCols(); col<nCols; col++) {
+ scaler.unscale(dstPixel, dstChanData, dstDataPos);
+ dstDataPos += nColorChannels;
+ if (fillAlpha) {
+ if (saveAlpha) {
+ dstPixel[nColorChannels] = alpha[alphaPos++];
+ } else {
+ dstPixel[nColorChannels] = 1f;
+ }
+ }
+ wr.setDataElements(col, row,
+ dstCM.getDataElements(dstPixel, 0 , null));
+ }
+ }
+ }
+
+ /**
+ * Translates pixels, stored in the float data buffer.
+ * Each pixel occupies separate array. Input pixels passed in the buffer
+ * are replaced by output pixels and then the buffer is returned
+ * @param t - ICC transform
+ * @param buffer - data buffer
+ * @param srcCS - source color space
+ * @param dstCS - destination color space
+ * @param nPixels - number of pixels
+ * @return translated pixels
+ */
+ public float[][] translateColor(ICC_Transform t,
+ float buffer[][],
+ ColorSpace srcCS,
+ ColorSpace dstCS,
+ int nPixels) {
+ // Scale source data
+ if (srcCS != null) { // if it is null use old scaling data
+ scaler.loadScalingData(srcCS);
+ }
+ int nSrcChannels = t.getNumInputChannels();
+ short srcShortData[] = new short[nPixels*nSrcChannels];
+ for (int i=0, srcDataPos = 0; i<nPixels; i++) {
+ scaler.scale(buffer[i], srcShortData, srcDataPos);
+ srcDataPos += nSrcChannels;
+ }
+
+ // Apply transform
+ short dstShortData[] = this.translateColor(t, srcShortData, null);
+
+ int nDstChannels = t.getNumOutputChannels();
+ int bufferSize = buffer[0].length;
+ if (bufferSize < nDstChannels + 1) { // Re-allocate buffer if needed
+ for (int i=0; i<nPixels; i++) {
+ // One extra element reserved for alpha
+ buffer[i] = new float[nDstChannels + 1];
+ }
+ }
+
+ // Unscale destination data
+ if (dstCS != null) { // if it is null use old scaling data
+ scaler.loadScalingData(dstCS);
+ }
+ for (int i=0, dstDataPos = 0; i<nPixels; i++) {
+ scaler.unscale(buffer[i], dstShortData, dstDataPos);
+ dstDataPos += nDstChannels;
+ }
+
+ return buffer;
+ }
+
+ /**
+ * Translates pixels stored in a raster.
+ * All data types are supported
+ * @param t - ICC transform
+ * @param src - source pixels
+ * @param dst - destination pixels
+ */
+ public void translateColor(ICC_Transform t, Raster src, WritableRaster dst) {
+ try{
+ NativeImageFormat srcFmt = NativeImageFormat.createNativeImageFormat(src);
+ NativeImageFormat dstFmt = NativeImageFormat.createNativeImageFormat(dst);
+
+ if (srcFmt != null && dstFmt != null) {
+ t.translateColors(srcFmt, dstFmt);
+ return;
+ }
+ } catch (IllegalArgumentException e) {
+ }
+
+ // Go ahead and rescale the source image
+ scaler.loadScalingData(src, t.getSrc());
+ short srcData[] = scaler.scale(src);
+
+ short dstData[] = translateColor(t, srcData, null);
+
+ scaler.loadScalingData(dst, t.getDst());
+ scaler.unscale(dstData, dst);
+ }
+
+ /**
+ * Translates pixels stored in an array of shorts.
+ * Samples are stored one-by-one, i.e. array structure is like following: RGBRGBRGB...
+ * The number of pixels is (size of the array) / (number of components).
+ * @param t - ICC transform
+ * @param src - source pixels
+ * @param dst - destination pixels
+ * @return destination pixels, stored in the array, passed in dst
+ */
+ public short[] translateColor(ICC_Transform t, short src[], short dst[]) {
+ NativeImageFormat srcFmt = createImageFormat(t, src, 0, true);
+ NativeImageFormat dstFmt = createImageFormat(t, dst, srcFmt.getNumCols(), false);
+
+ t.translateColors(srcFmt, dstFmt);
+
+ return (short[]) dstFmt.getChannelData();
+ }
+
+
+ /**
+ * Creates NativeImageFormat from buffered image.
+ * @param bi - buffered image
+ * @return created NativeImageFormat
+ */
+ private NativeImageFormat createImageFormat(BufferedImage bi) {
+ int nRows = bi.getHeight();
+ int nCols = bi.getWidth();
+ int nComps = bi.getColorModel().getNumColorComponents();
+ short imgData[] = new short[nRows*nCols*nComps];
+ return new NativeImageFormat(
+ imgData, nComps, nRows, nCols);
+ }
+
+ /**
+ * Creates one-row NativeImageFormat, using either nCols if it is positive,
+ * or arr.length to determine the number of pixels
+ *
+ * @param t - transform
+ * @param arr - short array or null if nCols is positive
+ * @param nCols - number of pixels in the array or 0 if array is not null
+ * @param in - is it an input or output array
+ * @return one-row NativeImageFormat
+ */
+ private NativeImageFormat createImageFormat(
+ ICC_Transform t, short arr[], int nCols, boolean in
+ ) {
+ int nComponents = in ? t.getNumInputChannels() : t.getNumOutputChannels();
+
+ if (arr == null || arr.length < nCols*nComponents) {
+ arr = new short[nCols*nComponents];
+ }
+
+ if (nCols == 0)
+ nCols = arr.length / nComponents;
+
+ return new NativeImageFormat(arr, nComponents, 1, nCols);
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/ColorScaler.java b/awt/org/apache/harmony/awt/gl/color/ColorScaler.java
new file mode 100644
index 0000000..a1cc169
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ColorScaler.java
@@ -0,0 +1,355 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+
+/**
+ * This class provides functionality for scaling color data when
+ * ranges of the source and destination color values differs.
+ */
+public class ColorScaler {
+ private static final float MAX_SHORT = 0xFFFF;
+ private static final float MAX_SIGNED_SHORT = 0x7FFF;
+
+ private static final float MAX_XYZ = 1f + (32767f/32768f);
+
+ // Cached values for scaling color data
+ private float[] channelMinValues = null;
+ private float[] channelMulipliers = null; // for scale
+ private float[] invChannelMulipliers = null; // for unscale
+
+ int nColorChannels = 0;
+
+ // For scaling rasters, false if transfer type is double or float
+ boolean isTTypeIntegral = false;
+
+ /**
+ * Loads scaling data for raster. Note, if profile pf is null,
+ * for non-integral data types multipliers are not initialized.
+ * @param r - raster
+ * @param pf - profile which helps to determine the ranges of the color data
+ */
+ public void loadScalingData(Raster r, ICC_Profile pf) {
+ boolean isSrcTTypeIntegral =
+ r.getTransferType() != DataBuffer.TYPE_FLOAT &&
+ r.getTransferType() != DataBuffer.TYPE_DOUBLE;
+ if (isSrcTTypeIntegral)
+ loadScalingData(r.getSampleModel());
+ else if (pf != null)
+ loadScalingData(pf);
+ }
+
+ /**
+ * Use this method only for integral transfer types.
+ * Extracts min/max values from the sample model
+ * @param sm - sample model
+ */
+ public void loadScalingData(SampleModel sm) {
+ // Supposing integral transfer type
+ isTTypeIntegral = true;
+
+ nColorChannels = sm.getNumBands();
+
+ channelMinValues = new float[nColorChannels];
+ channelMulipliers = new float[nColorChannels];
+ invChannelMulipliers = new float[nColorChannels];
+
+ boolean isSignedShort =
+ (sm.getTransferType() == DataBuffer.TYPE_SHORT);
+
+ float maxVal;
+ for (int i=0; i<nColorChannels; i++) {
+ channelMinValues[i] = 0;
+ if (isSignedShort) {
+ channelMulipliers[i] = MAX_SHORT / MAX_SIGNED_SHORT;
+ invChannelMulipliers[i] = MAX_SIGNED_SHORT / MAX_SHORT;
+ } else {
+ maxVal = ((1 << sm.getSampleSize(i)) - 1);
+ channelMulipliers[i] = MAX_SHORT / maxVal;
+ invChannelMulipliers[i] = maxVal / MAX_SHORT;
+ }
+ }
+ }
+
+ /**
+ * Use this method only for double of float transfer types.
+ * Extracts scaling data from the color space signature
+ * and other tags, stored in the profile
+ * @param pf - ICC profile
+ */
+ public void loadScalingData(ICC_Profile pf) {
+ // Supposing double or float transfer type
+ isTTypeIntegral = false;
+
+ nColorChannels = pf.getNumComponents();
+
+ // Get min/max values directly from the profile
+ // Very much like fillMinMaxValues in ICC_ColorSpace
+ float maxValues[] = new float[nColorChannels];
+ float minValues[] = new float[nColorChannels];
+
+ switch (pf.getColorSpaceType()) {
+ case ColorSpace.TYPE_XYZ:
+ minValues[0] = 0;
+ minValues[1] = 0;
+ minValues[2] = 0;
+ maxValues[0] = MAX_XYZ;
+ maxValues[1] = MAX_XYZ;
+ maxValues[2] = MAX_XYZ;
+ break;
+ case ColorSpace.TYPE_Lab:
+ minValues[0] = 0;
+ minValues[1] = -128;
+ minValues[2] = -128;
+ maxValues[0] = 100;
+ maxValues[1] = 127;
+ maxValues[2] = 127;
+ break;
+ default:
+ for (int i=0; i<nColorChannels; i++) {
+ minValues[i] = 0;
+ maxValues[i] = 1;
+ }
+ }
+
+ channelMinValues = minValues;
+ channelMulipliers = new float[nColorChannels];
+ invChannelMulipliers = new float[nColorChannels];
+
+ for (int i = 0; i < nColorChannels; i++) {
+ channelMulipliers[i] =
+ MAX_SHORT / (maxValues[i] - channelMinValues[i]);
+
+ invChannelMulipliers[i] =
+ (maxValues[i] - channelMinValues[i]) / MAX_SHORT;
+ }
+ }
+
+ /**
+ * Extracts scaling data from the color space
+ * @param cs - color space
+ */
+ public void loadScalingData(ColorSpace cs) {
+ nColorChannels = cs.getNumComponents();
+
+ channelMinValues = new float[nColorChannels];
+ channelMulipliers = new float[nColorChannels];
+ invChannelMulipliers = new float[nColorChannels];
+
+ for (int i = 0; i < nColorChannels; i++) {
+ channelMinValues[i] = cs.getMinValue(i);
+
+ channelMulipliers[i] =
+ MAX_SHORT / (cs.getMaxValue(i) - channelMinValues[i]);
+
+ invChannelMulipliers[i] =
+ (cs.getMaxValue(i) - channelMinValues[i]) / MAX_SHORT;
+ }
+ }
+
+ /**
+ * Scales and normalizes the whole raster and returns the result
+ * in the float array
+ * @param r - source raster
+ * @return scaled and normalized raster data
+ */
+ public float[][] scaleNormalize(Raster r) {
+ int width = r.getWidth();
+ int height = r.getHeight();
+ float result[][] = new float[width*height][nColorChannels];
+ float normMultipliers[] = new float[nColorChannels];
+
+ int pos = 0;
+ if (isTTypeIntegral) {
+ // Change max value from MAX_SHORT to 1f
+ for (int i=0; i<nColorChannels; i++) {
+ normMultipliers[i] = channelMulipliers[i] / MAX_SHORT;
+ }
+
+ int sample;
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = r.getSample(row, col, chan);
+ result[pos][chan] = (sample * normMultipliers[chan]);
+ }
+ pos++;
+ }
+ }
+ } else { // Just get the samples...
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ result[pos][chan] = r.getSampleFloat(row, col, chan);
+ }
+ pos++;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Unscale the whole float array and put the result
+ * in the raster
+ * @param r - destination raster
+ * @param data - input pixels
+ */
+ public void unscaleNormalized(WritableRaster r, float data[][]) {
+ int width = r.getWidth();
+ int height = r.getHeight();
+ float normMultipliers[] = new float[nColorChannels];
+
+ int pos = 0;
+ if (isTTypeIntegral) {
+ // Change max value from MAX_SHORT to 1f
+ for (int i=0; i<nColorChannels; i++) {
+ normMultipliers[i] = invChannelMulipliers[i] * MAX_SHORT;
+ }
+
+ int sample;
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = (int) (data[pos][chan] * normMultipliers[chan] + 0.5f);
+ r.setSample(row, col, chan, sample);
+ }
+ pos++;
+ }
+ }
+ } else { // Just set the samples...
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ r.setSample(row, col, chan, data[pos][chan]);
+ }
+ pos++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Scales the whole raster to short and returns the result
+ * in the array
+ * @param r - source raster
+ * @return scaled and normalized raster data
+ */
+ public short[] scale(Raster r) {
+ int width = r.getWidth();
+ int height = r.getHeight();
+ short result[] = new short[width*height*nColorChannels];
+
+ int pos = 0;
+ if (isTTypeIntegral) {
+ int sample;
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = r.getSample(row, col, chan);
+ result[pos++] =
+ (short) (sample * channelMulipliers[chan] + 0.5f);
+ }
+ }
+ }
+ } else {
+ float sample;
+ for (int row=r.getMinX(); row<width; row++) {
+ for (int col=r.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = r.getSampleFloat(row, col, chan);
+ result[pos++] = (short) ((sample - channelMinValues[chan])
+ * channelMulipliers[chan] + 0.5f);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Unscales the whole data array and puts obtained values to the raster
+ * @param data - input data
+ * @param wr - destination raster
+ */
+ public void unscale(short[] data, WritableRaster wr) {
+ int width = wr.getWidth();
+ int height = wr.getHeight();
+
+ int pos = 0;
+ if (isTTypeIntegral) {
+ int sample;
+ for (int row=wr.getMinX(); row<width; row++) {
+ for (int col=wr.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = (int) ((data[pos++] & 0xFFFF) *
+ invChannelMulipliers[chan] + 0.5f);
+ wr.setSample(row, col, chan, sample);
+ }
+ }
+ }
+ } else {
+ float sample;
+ for (int row=wr.getMinX(); row<width; row++) {
+ for (int col=wr.getMinY(); col<height; col++) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ sample = (data[pos++] & 0xFFFF) *
+ invChannelMulipliers[chan] + channelMinValues[chan];
+ wr.setSample(row, col, chan, sample);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Scales one pixel and puts obtained values to the chanData
+ * @param pixelData - input pixel
+ * @param chanData - output buffer
+ * @param chanDataOffset - output buffer offset
+ */
+ public void scale(float[] pixelData, short[] chanData, int chanDataOffset) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ chanData[chanDataOffset + chan] =
+ (short) ((pixelData[chan] - channelMinValues[chan]) *
+ channelMulipliers[chan] + 0.5f);
+ }
+ }
+
+ /**
+ * Unscales one pixel and puts obtained values to the pixelData
+ * @param pixelData - output pixel
+ * @param chanData - input buffer
+ * @param chanDataOffset - input buffer offset
+ */
+ public void unscale(float[] pixelData, short[] chanData, int chanDataOffset) {
+ for (int chan = 0; chan < nColorChannels; chan++) {
+ pixelData[chan] = (chanData[chanDataOffset + chan] & 0xFFFF)
+ * invChannelMulipliers[chan] + channelMinValues[chan];
+ }
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java b/awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java
new file mode 100644
index 0000000..2f7e519
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ICC_ProfileHelper.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ICC_Profile;
+
+/**
+ * Includes utility methods for reading ICC profile data.
+ * Created to provide public access to ICC_Profile methods
+ * for classes outside of java.awt.color
+ */
+public class ICC_ProfileHelper {
+ /**
+ * Utility method.
+ * Gets integer value from the byte array
+ * @param byteArray - byte array
+ * @param idx - byte offset
+ * @return integer value
+ */
+ public static int getIntFromByteArray(byte[] byteArray, int idx) {
+ return (byteArray[idx] & 0xFF)|
+ ((byteArray[idx+1] & 0xFF) << 8) |
+ ((byteArray[idx+2] & 0xFF) << 16)|
+ ((byteArray[idx+3] & 0xFF) << 24);
+ }
+
+ /**
+ * Utility method.
+ * Gets big endian integer value from the byte array
+ * @param byteArray - byte array
+ * @param idx - byte offset
+ * @return integer value
+ */
+ public static int getBigEndianFromByteArray(byte[] byteArray, int idx) {
+ return ((byteArray[idx] & 0xFF) << 24) |
+ ((byteArray[idx+1] & 0xFF) << 16) |
+ ((byteArray[idx+2] & 0xFF) << 8) |
+ ( byteArray[idx+3] & 0xFF);
+ }
+
+ /**
+ * Utility method.
+ * Gets short value from the byte array
+ * @param byteArray - byte array
+ * @param idx - byte offset
+ * @return short value
+ */
+ public static short getShortFromByteArray(byte[] byteArray, int idx) {
+ return (short) ((byteArray[idx] & 0xFF) |
+ ((byteArray[idx+1] & 0xFF) << 8));
+ }
+
+ /**
+ * Used in ICC_Transform class to check the rendering intent of the profile
+ * @param profile - ICC profile
+ * @return rendering intent
+ */
+ public static int getRenderingIntent(ICC_Profile profile) {
+ return getIntFromByteArray(
+ profile.getData(ICC_Profile.icSigHead), // pf header
+ ICC_Profile.icHdrRenderingIntent
+ );
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/ICC_Transform.java b/awt/org/apache/harmony/awt/gl/color/ICC_Transform.java
new file mode 100644
index 0000000..27646c4
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/ICC_Transform.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ICC_Profile;
+
+import org.apache.harmony.awt.gl.color.NativeCMM;
+
+/**
+ * This class encapsulates native ICC transform object, is responsible for its
+ * creation, destruction and passing its handle to the native CMM.
+ */
+public class ICC_Transform {
+ private long transformHandle;
+ private int numInputChannels;
+ private int numOutputChannels;
+ private ICC_Profile src;
+ private ICC_Profile dst;
+
+
+ /**
+ * @return Returns the number of input channels.
+ */
+ public int getNumInputChannels() {
+ return numInputChannels;
+ }
+
+ /**
+ * @return Returns the number of output channels.
+ */
+ public int getNumOutputChannels() {
+ return numOutputChannels;
+ }
+
+ /**
+ * @return Returns the dst.
+ */
+ public ICC_Profile getDst() {
+ return dst;
+ }
+
+ /**
+ * @return Returns the src.
+ */
+ public ICC_Profile getSrc() {
+ return src;
+ }
+
+ /**
+ * Constructs a multiprofile ICC transform
+ * @param profiles - list of ICC profiles
+ * @param renderIntents - only hints for CMM
+ */
+ public ICC_Transform(ICC_Profile[] profiles, int[] renderIntents) {
+ int numProfiles = profiles.length;
+
+ long[] profileHandles = new long[numProfiles];
+ for (int i=0; i<numProfiles; i++) {
+ profileHandles[i] = NativeCMM.getHandle(profiles[i]);
+ }
+
+ transformHandle = NativeCMM.cmmCreateMultiprofileTransform(
+ profileHandles,
+ renderIntents);
+
+ src = profiles[0];
+ dst = profiles[numProfiles-1];
+ numInputChannels = src.getNumComponents();
+ numOutputChannels = dst.getNumComponents();
+ }
+
+ /**
+ * This constructor is able to set intents by default
+ * @param profiles - list of ICC profiles
+ */
+ public ICC_Transform(ICC_Profile[] profiles) {
+ int numProfiles = profiles.length;
+ int[] renderingIntents = new int[numProfiles];
+
+ // Default is perceptual
+ int currRenderingIntent = ICC_Profile.icPerceptual;
+
+ // render as colorimetric for output device
+ if (profiles[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) {
+ currRenderingIntent = ICC_Profile.icRelativeColorimetric;
+ }
+
+ // get the transforms from each profile
+ for (int i = 0; i < numProfiles; i++) {
+ // first or last profile cannot be abstract
+ // if profile is abstract, the only possible way is
+ // use AToB0Tag (perceptual), see ICC spec
+ if (i != 0 &&
+ i != numProfiles - 1 &&
+ profiles[i].getProfileClass() == ICC_Profile.CLASS_ABSTRACT
+ ) {
+ currRenderingIntent = ICC_Profile.icPerceptual;
+ }
+
+ renderingIntents[i] = currRenderingIntent;
+ // use current rendering intent
+ // to select LUT from the next profile (chaining)
+ currRenderingIntent =
+ ICC_ProfileHelper.getRenderingIntent(profiles[i]);
+ }
+
+ // Get the profile handles and go ahead
+ long[] profileHandles = new long[numProfiles];
+ for (int i=0; i<numProfiles; i++) {
+ profileHandles[i] = NativeCMM.getHandle(profiles[i]);
+ }
+
+ transformHandle = NativeCMM.cmmCreateMultiprofileTransform(
+ profileHandles,
+ renderingIntents);
+
+ src = profiles[0];
+ dst = profiles[numProfiles-1];
+ numInputChannels = src.getNumComponents();
+ numOutputChannels = dst.getNumComponents();
+ }
+
+ @Override
+ protected void finalize() {
+ if (transformHandle != 0) {
+ NativeCMM.cmmDeleteTransform(transformHandle);
+ }
+ }
+
+ /**
+ * Invokes native color conversion
+ * @param src - source image format
+ * @param dst - destination image format
+ */
+ public void translateColors(NativeImageFormat src, NativeImageFormat dst) {
+ NativeCMM.cmmTranslateColors(transformHandle, src, dst);
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java b/awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java
new file mode 100644
index 0000000..5ea6d25
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/LUTColorConverter.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 02.11.2004
+ *
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ColorSpace;
+
+public class LUTColorConverter {
+
+ private static byte from8lRGBtosRGB_LUT[];
+
+ private static byte from16lRGBtosRGB_LUT[];
+
+ private static byte fromsRGBto8lRGB_LUT[];
+
+ private static short fromsRGBto16lRGB_LUT[];
+
+ private static byte fromsRGBto8sRGB_LUTs[][];
+
+ public static ColorSpace LINEAR_RGB_CS;
+
+ public static ColorSpace LINEAR_GRAY_CS;
+
+ public static ColorSpace sRGB_CS;
+
+ public LUTColorConverter() {
+ }
+
+ /*
+ * This class prepared and returned lookup tables for conversion color
+ * values from Linear RGB Color Space to sRGB and vice versa.
+ * Conversion is producing according to sRGB Color Space definition.
+ * "A Standard Default Color Space for the Internet - sRGB",
+ * Michael Stokes (Hewlett-Packard), Matthew Anderson (Microsoft),
+ * Srinivasan Chandrasekar (Microsoft), Ricardo Motta (Hewlett-Packard)
+ * Version 1.10, November 5, 1996
+ * This document is available: http://www.w3.org/Graphics/Color/sRGB
+ */
+ public static byte[] getFrom8lRGBtosRGB_LUT() {
+ if (from8lRGBtosRGB_LUT == null) {
+ from8lRGBtosRGB_LUT = new byte[256];
+ float v;
+ for (int i = 0; i < 256; i++) {
+ v = (float)i / 255;
+ v = (v <= 0.04045f) ? v / 12.92f :
+ (float) Math.pow((v + 0.055) / 1.055, 2.4);
+ from8lRGBtosRGB_LUT[i] = (byte) Math.round(v * 255.0f);
+ }
+ }
+ return from8lRGBtosRGB_LUT;
+ }
+
+ public static byte[] getFrom16lRGBtosRGB_LUT() {
+ if (from16lRGBtosRGB_LUT == null) {
+ from16lRGBtosRGB_LUT = new byte[65536];
+ float v;
+ for (int i = 0; i < 65536; i++) {
+ v = (float) i / 65535;
+ v = (v <= 0.04045f) ? v / 12.92f :
+ (float) Math.pow((v + 0.055) / 1.055, 2.4);
+ from16lRGBtosRGB_LUT[i] = (byte) Math.round(v * 255.0f);
+ }
+ }
+ return from16lRGBtosRGB_LUT;
+ }
+
+ public static byte[] getFromsRGBto8lRGB_LUT() {
+ if (fromsRGBto8lRGB_LUT == null) {
+ fromsRGBto8lRGB_LUT = new byte[256];
+ float v;
+ for (int i = 0; i < 256; i++) {
+ v = (float) i / 255;
+ v = (v <= 0.0031308f) ? v * 12.92f :
+ ((float) Math.pow(v, 1.0 / 2.4)) * 1.055f - 0.055f;
+ fromsRGBto8lRGB_LUT[i] = (byte) Math.round(v * 255.0f);
+ }
+ }
+ return fromsRGBto8lRGB_LUT;
+ }
+
+ public static short[] getFromsRGBto16lRGB_LUT() {
+ if (fromsRGBto16lRGB_LUT == null) {
+ fromsRGBto16lRGB_LUT = new short[256];
+ float v;
+ for (int i = 0; i < 256; i++) {
+ v = (float) i / 255;
+ v = (v <= 0.0031308f) ? v * 12.92f :
+ ((float) Math.pow(v, 1.0 / 2.4)) * 1.055f - 0.055f;
+ fromsRGBto16lRGB_LUT[i] = (short) Math.round(v * 65535.0f);
+ }
+ }
+ return fromsRGBto16lRGB_LUT;
+ }
+
+ public static byte[] getsRGBLUT(int bits) {
+ if (bits < 1) return null;
+ int idx = bits -1;
+ if(fromsRGBto8sRGB_LUTs == null) fromsRGBto8sRGB_LUTs = new byte[16][];
+
+ if(fromsRGBto8sRGB_LUTs[idx] == null){
+ fromsRGBto8sRGB_LUTs[idx] = createLUT(bits);
+ }
+ return fromsRGBto8sRGB_LUTs[idx];
+ }
+
+ private static byte[] createLUT(int bits) {
+ int lutSize = (1 << bits);
+ byte lut[] = new byte[lutSize];
+ for (int i = 0; i < lutSize; i++) {
+ lut[i] = (byte) (255.0f / (lutSize - 1) + 0.5f);
+ }
+ return lut;
+ }
+
+ public static boolean is_LINEAR_RGB_CS(ColorSpace cs) {
+ return (cs == LINEAR_RGB_CS);
+ }
+
+ public static boolean is_LINEAR_GRAY_CS(ColorSpace cs) {
+ return (cs == LINEAR_GRAY_CS);
+ }
+
+ public static boolean is_sRGB_CS(ColorSpace cs) {
+ return (cs == sRGB_CS);
+ }
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/color/NativeCMM.java b/awt/org/apache/harmony/awt/gl/color/NativeCMM.java
new file mode 100644
index 0000000..7f8c7e6
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/NativeCMM.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.color.ICC_Profile;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+
+/**
+ * This class is a wrapper for the native CMM library
+ */
+public class NativeCMM {
+
+ /**
+ * Storage for profile handles, since they are private
+ * in ICC_Profile, but we need access to them.
+ */
+ private static HashMap<ICC_Profile, Long> profileHandles = new HashMap<ICC_Profile, Long>();
+
+ private static boolean isCMMLoaded;
+
+ public static void addHandle(ICC_Profile key, long handle) {
+ profileHandles.put(key, new Long(handle));
+ }
+
+ public static void removeHandle(ICC_Profile key) {
+ profileHandles.remove(key);
+ }
+
+ public static long getHandle(ICC_Profile key) {
+ return profileHandles.get(key).longValue();
+ }
+
+ /* ICC profile management */
+ public static native long cmmOpenProfile(byte[] data);
+ public static native void cmmCloseProfile(long profileID);
+ public static native int cmmGetProfileSize(long profileID);
+ public static native void cmmGetProfile(long profileID, byte[] data);
+ public static native int cmmGetProfileElementSize(long profileID, int signature);
+ public static native void cmmGetProfileElement(long profileID, int signature,
+ byte[] data);
+ public static native void cmmSetProfileElement(long profileID, int tagSignature,
+ byte[] data);
+
+
+ /* ICC transforms */
+ public static native long cmmCreateMultiprofileTransform(
+ long[] profileHandles,
+ int[] renderingIntents
+ );
+ public static native void cmmDeleteTransform(long transformHandle);
+ public static native void cmmTranslateColors(long transformHandle,
+ NativeImageFormat src,
+ NativeImageFormat dest);
+
+ static void loadCMM() {
+ if (!isCMMLoaded) {
+ AccessController.doPrivileged(
+ new PrivilegedAction<Void>() {
+ public Void run() {
+ System.loadLibrary("lcmm"); //$NON-NLS-1$
+ return null;
+ }
+ } );
+ isCMMLoaded = true;
+ }
+ }
+
+ /* load native CMM library */
+ static {
+ loadCMM();
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java b/awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java
new file mode 100644
index 0000000..9594047
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/color/NativeImageFormat.java
@@ -0,0 +1,642 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.color;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class converts java color/sample models to the LCMS pixel formats.
+ * It also encapsulates all the information about the image format, which native CMM
+ * needs to have in order to read/write data.
+ *
+ * At present planar formats (multiple bands) are not supported
+ * and they are handled as a common (custom) case.
+ * Samples other than 1 - 7 bytes and multiple of 8 bits are
+ * also handled as custom (and won't be supported in the nearest future).
+ */
+class NativeImageFormat {
+ //////////////////////////////////////////////
+ // LCMS Pixel types
+ private static final int PT_ANY = 0; // Don't check colorspace
+ // 1 & 2 are reserved
+ private static final int PT_GRAY = 3;
+ private static final int PT_RGB = 4;
+ // Skipping other since we don't use them here
+ ///////////////////////////////////////////////
+
+ // Conversion of predefined BufferedImage formats to LCMS formats
+ private static final int INT_RGB_LCMS_FMT =
+ colorspaceSh(PT_RGB)|
+ extraSh(1)|
+ channelsSh(3)|
+ bytesSh(1)|
+ doswapSh(1)|
+ swapfirstSh(1);
+
+ private static final int INT_ARGB_LCMS_FMT = INT_RGB_LCMS_FMT;
+
+ private static final int INT_BGR_LCMS_FMT =
+ colorspaceSh(PT_RGB)|
+ extraSh(1)|
+ channelsSh(3)|
+ bytesSh(1);
+
+ private static final int THREE_BYTE_BGR_LCMS_FMT =
+ colorspaceSh(PT_RGB)|
+ channelsSh(3)|
+ bytesSh(1)|
+ doswapSh(1);
+
+ private static final int FOUR_BYTE_ABGR_LCMS_FMT =
+ colorspaceSh(PT_RGB)|
+ extraSh(1)|
+ channelsSh(3)|
+ bytesSh(1)|
+ doswapSh(1);
+
+ private static final int BYTE_GRAY_LCMS_FMT =
+ colorspaceSh(PT_GRAY)|
+ channelsSh(1)|
+ bytesSh(1);
+
+ private static final int USHORT_GRAY_LCMS_FMT =
+ colorspaceSh(PT_GRAY)|
+ channelsSh(1)|
+ bytesSh(2);
+
+ // LCMS format packed into 32 bit value. For description
+ // of this format refer to LCMS documentation.
+ private int cmmFormat = 0;
+
+ // Dimensions
+ private int rows = 0;
+ private int cols = 0;
+
+ // Scanline may contain some padding in the end
+ private int scanlineStride = -1;
+
+ private Object imageData;
+ // It's possible to have offset from the beginning of the array
+ private int dataOffset;
+
+ // Has the image alpha channel? If has - here its band band offset goes
+ private int alphaOffset = -1;
+
+ // initializes proper field IDs
+ private static native void initIDs();
+
+ static {
+ NativeCMM.loadCMM();
+ initIDs();
+ }
+
+ ////////////////////////////////////
+ // LCMS image format encoders
+ ////////////////////////////////////
+ private static int colorspaceSh(int s) {
+ return (s << 16);
+ }
+
+ private static int swapfirstSh(int s) {
+ return (s << 14);
+ }
+
+ private static int flavorSh(int s) {
+ return (s << 13);
+ }
+
+ private static int planarSh(int s) {
+ return (s << 12);
+ }
+
+ private static int endianSh(int s) {
+ return (s << 11);
+ }
+
+ private static int doswapSh(int s) {
+ return (s << 10);
+ }
+
+ private static int extraSh(int s) {
+ return (s << 7);
+ }
+
+ private static int channelsSh(int s) {
+ return (s << 3);
+ }
+
+ private static int bytesSh(int s) {
+ return s;
+ }
+ ////////////////////////////////////
+ // End of LCMS image format encoders
+ ////////////////////////////////////
+
+ // Accessors
+ Object getChannelData() {
+ return imageData;
+ }
+
+ int getNumCols() {
+ return cols;
+ }
+
+ int getNumRows() {
+ return rows;
+ }
+
+ // Constructors
+ public NativeImageFormat() {
+ }
+
+ /**
+ * Simple image layout for common case with
+ * not optimized workflow.
+ *
+ * For hifi colorspaces with 5+ color channels imgData
+ * should be <code>byte</code> array.
+ *
+ * For common colorspaces with up to 4 color channels it
+ * should be <code>short</code> array.
+ *
+ * Alpha channel is handled by caller, not by CMS.
+ *
+ * Color channels are in their natural order (not BGR but RGB).
+ *
+ * @param imgData - array of <code>byte</code> or <code>short</code>
+ * @param nChannels - number of channels
+ * @param nRows - number of scanlines in the image
+ * @param nCols - number of pixels in one row of the image
+ */
+ public NativeImageFormat(Object imgData, int nChannels, int nRows, int nCols) {
+ if (imgData instanceof short[]) {
+ cmmFormat |= bytesSh(2);
+ }
+ else if (imgData instanceof byte[]) {
+ cmmFormat |= bytesSh(1);
+ }
+ else
+ // awt.47=First argument should be byte or short array
+ throw new IllegalArgumentException(Messages.getString("awt.47")); //$NON-NLS-1$
+
+ cmmFormat |= channelsSh(nChannels);
+
+ rows = nRows;
+ cols = nCols;
+
+ imageData = imgData;
+
+ dataOffset = 0;
+ }
+
+ /**
+ * Deduces image format from the buffered image type
+ * or color and sample models.
+ * @param bi - image
+ * @return image format object
+ */
+ public static NativeImageFormat createNativeImageFormat(BufferedImage bi) {
+ NativeImageFormat fmt = new NativeImageFormat();
+
+ switch (bi.getType()) {
+ case BufferedImage.TYPE_INT_RGB: {
+ fmt.cmmFormat = INT_RGB_LCMS_FMT;
+ break;
+ }
+
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE: {
+ fmt.cmmFormat = INT_ARGB_LCMS_FMT;
+ fmt.alphaOffset = 3;
+ break;
+ }
+
+ case BufferedImage.TYPE_INT_BGR: {
+ fmt.cmmFormat = INT_BGR_LCMS_FMT;
+ break;
+ }
+
+ case BufferedImage.TYPE_3BYTE_BGR: {
+ fmt.cmmFormat = THREE_BYTE_BGR_LCMS_FMT;
+ break;
+ }
+
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+ case BufferedImage.TYPE_4BYTE_ABGR: {
+ fmt.cmmFormat = FOUR_BYTE_ABGR_LCMS_FMT;
+ fmt.alphaOffset = 0;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_GRAY: {
+ fmt.cmmFormat = BYTE_GRAY_LCMS_FMT;
+ break;
+ }
+
+ case BufferedImage.TYPE_USHORT_GRAY: {
+ fmt.cmmFormat = USHORT_GRAY_LCMS_FMT;
+ break;
+ }
+
+ case BufferedImage.TYPE_BYTE_BINARY:
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ case BufferedImage.TYPE_BYTE_INDEXED: {
+ // A bunch of unsupported formats
+ return null;
+ }
+
+ default:
+ break; // Try to look at sample model and color model
+ }
+
+
+ if (fmt.cmmFormat == 0) {
+ ColorModel cm = bi.getColorModel();
+ SampleModel sm = bi.getSampleModel();
+
+ if (sm instanceof ComponentSampleModel) {
+ ComponentSampleModel csm = (ComponentSampleModel) sm;
+ fmt.cmmFormat = getFormatFromComponentModel(csm, cm.hasAlpha());
+ fmt.scanlineStride = calculateScanlineStrideCSM(csm, bi.getRaster());
+ } else if (sm instanceof SinglePixelPackedSampleModel) {
+ SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+ fmt.cmmFormat = getFormatFromSPPSampleModel(sppsm, cm.hasAlpha());
+ fmt.scanlineStride = calculateScanlineStrideSPPSM(sppsm, bi.getRaster());
+ }
+
+ if (cm.hasAlpha())
+ fmt.alphaOffset = calculateAlphaOffset(sm, bi.getRaster());
+ }
+
+ if (fmt.cmmFormat == 0)
+ return null;
+
+ if (!fmt.setImageData(bi.getRaster().getDataBuffer())) {
+ return null;
+ }
+
+ fmt.rows = bi.getHeight();
+ fmt.cols = bi.getWidth();
+
+ fmt.dataOffset = bi.getRaster().getDataBuffer().getOffset();
+
+ return fmt;
+ }
+
+ /**
+ * Deduces image format from the raster sample model.
+ * @param r - raster
+ * @return image format object
+ */
+ public static NativeImageFormat createNativeImageFormat(Raster r) {
+ NativeImageFormat fmt = new NativeImageFormat();
+ SampleModel sm = r.getSampleModel();
+
+ // Assume that there's no alpha
+ if (sm instanceof ComponentSampleModel) {
+ ComponentSampleModel csm = (ComponentSampleModel) sm;
+ fmt.cmmFormat = getFormatFromComponentModel(csm, false);
+ fmt.scanlineStride = calculateScanlineStrideCSM(csm, r);
+ } else if (sm instanceof SinglePixelPackedSampleModel) {
+ SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+ fmt.cmmFormat = getFormatFromSPPSampleModel(sppsm, false);
+ fmt.scanlineStride = calculateScanlineStrideSPPSM(sppsm, r);
+ }
+
+ if (fmt.cmmFormat == 0)
+ return null;
+
+ fmt.cols = r.getWidth();
+ fmt.rows = r.getHeight();
+ fmt.dataOffset = r.getDataBuffer().getOffset();
+
+ if (!fmt.setImageData(r.getDataBuffer()))
+ return null;
+
+ return fmt;
+ }
+
+ /**
+ * Obtains LCMS format from the component sample model
+ * @param sm - sample model
+ * @param hasAlpha - true if there's an alpha channel
+ * @return LCMS format
+ */
+ private static int getFormatFromComponentModel(ComponentSampleModel sm, boolean hasAlpha) {
+ // Multiple data arrays (banks) not supported
+ int bankIndex = sm.getBankIndices()[0];
+ for (int i=1; i < sm.getNumBands(); i++) {
+ if (sm.getBankIndices()[i] != bankIndex) {
+ return 0;
+ }
+ }
+
+ int channels = hasAlpha ? sm.getNumBands()-1 : sm.getNumBands();
+ int extra = hasAlpha ? 1 : 0;
+ int bytes = 1;
+ switch (sm.getDataType()) {
+ case DataBuffer.TYPE_BYTE:
+ bytes = 1; break;
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ bytes = 2; break;
+ case DataBuffer.TYPE_INT:
+ bytes = 4; break;
+ case DataBuffer.TYPE_DOUBLE:
+ bytes = 0; break;
+ default:
+ return 0; // Unsupported data type
+ }
+
+ int doSwap = 0;
+ int swapFirst = 0;
+ boolean knownFormat = false;
+
+ int i;
+
+ // "RGBA"
+ for (i=0; i < sm.getNumBands(); i++) {
+ if (sm.getBandOffsets()[i] != i) break;
+ }
+ if (i == sm.getNumBands()) { // Ok, it is it
+ doSwap = 0;
+ swapFirst = 0;
+ knownFormat = true;
+ }
+
+ // "ARGB"
+ if (!knownFormat) {
+ for (i=0; i < sm.getNumBands()-1; i++) {
+ if (sm.getBandOffsets()[i] != i+1) break;
+ }
+ if (sm.getBandOffsets()[i] == 0) i++;
+ if (i == sm.getNumBands()) { // Ok, it is it
+ doSwap = 0;
+ swapFirst = 1;
+ knownFormat = true;
+ }
+ }
+
+ // "BGRA"
+ if (!knownFormat) {
+ for (i=0; i < sm.getNumBands()-1; i++) {
+ if (sm.getBandOffsets()[i] != sm.getNumBands() - 2 - i) break;
+ }
+ if (sm.getBandOffsets()[i] == sm.getNumBands()-1) i++;
+ if (i == sm.getNumBands()) { // Ok, it is it
+ doSwap = 1;
+ swapFirst = 1;
+ knownFormat = true;
+ }
+ }
+
+ // "ABGR"
+ if (!knownFormat) {
+ for (i=0; i < sm.getNumBands(); i++) {
+ if (sm.getBandOffsets()[i] != sm.getNumBands() - 1 - i) break;
+ }
+ if (i == sm.getNumBands()) { // Ok, it is it
+ doSwap = 1;
+ swapFirst = 0;
+ knownFormat = true;
+ }
+ }
+
+ // XXX - Planar formats are not supported yet
+ if (!knownFormat)
+ return 0;
+
+ return
+ channelsSh(channels) |
+ bytesSh(bytes) |
+ extraSh(extra) |
+ doswapSh(doSwap) |
+ swapfirstSh(swapFirst);
+ }
+
+ /**
+ * Obtains LCMS format from the single pixel packed sample model
+ * @param sm - sample model
+ * @param hasAlpha - true if there's an alpha channel
+ * @return LCMS format
+ */
+ private static int getFormatFromSPPSampleModel(SinglePixelPackedSampleModel sm,
+ boolean hasAlpha) {
+ // Can we extract bytes?
+ int mask = sm.getBitMasks()[0] >>> sm.getBitOffsets()[0];
+ if (!(mask == 0xFF || mask == 0xFFFF || mask == 0xFFFFFFFF))
+ return 0;
+
+ // All masks are same?
+ for (int i = 1; i < sm.getNumBands(); i++) {
+ if ((sm.getBitMasks()[i] >>> sm.getBitOffsets()[i]) != mask)
+ return 0;
+ }
+
+ int pixelSize = 0;
+ // Check if data type is supported
+ if (sm.getDataType() == DataBuffer.TYPE_USHORT)
+ pixelSize = 2;
+ else if (sm.getDataType() == DataBuffer.TYPE_INT)
+ pixelSize = 4;
+ else
+ return 0;
+
+
+ int bytes = 0;
+ switch (mask) {
+ case 0xFF:
+ bytes = 1;
+ break;
+ case 0xFFFF:
+ bytes = 2;
+ break;
+ case 0xFFFFFFFF:
+ bytes = 4;
+ break;
+ default: return 0;
+ }
+
+
+ int channels = hasAlpha ? sm.getNumBands()-1 : sm.getNumBands();
+ int extra = hasAlpha ? 1 : 0;
+ extra += pixelSize/bytes - sm.getNumBands(); // Unused bytes?
+
+ // Form an ArrayList containing offset for each band
+ ArrayList<Integer> offsetsLst = new ArrayList<Integer>();
+ for (int k=0; k < sm.getNumBands(); k++) {
+ offsetsLst.add(new Integer(sm.getBitOffsets()[k]/(bytes*8)));
+ }
+
+ // Add offsets for unused space
+ for (int i=0; i<pixelSize/bytes; i++) {
+ if (offsetsLst.indexOf(new Integer(i)) < 0)
+ offsetsLst.add(new Integer(i));
+ }
+
+ int offsets[] = new int[pixelSize/bytes];
+ for (int i=0; i<offsetsLst.size(); i++) {
+ offsets[i] = offsetsLst.get(i).intValue();
+ }
+
+ int doSwap = 0;
+ int swapFirst = 0;
+ boolean knownFormat = false;
+
+ int i;
+
+ // "RGBA"
+ for (i=0; i < pixelSize; i++) {
+ if (offsets[i] != i) break;
+ }
+ if (i == pixelSize) { // Ok, it is it
+ doSwap = 0;
+ swapFirst = 0;
+ knownFormat = true;
+ }
+
+ // "ARGB"
+ if (!knownFormat) {
+ for (i=0; i < pixelSize-1; i++) {
+ if (offsets[i] != i+1) break;
+ }
+ if (offsets[i] == 0) i++;
+ if (i == pixelSize) { // Ok, it is it
+ doSwap = 0;
+ swapFirst = 1;
+ knownFormat = true;
+ }
+ }
+
+ // "BGRA"
+ if (!knownFormat) {
+ for (i=0; i < pixelSize-1; i++) {
+ if (offsets[i] != pixelSize - 2 - i) break;
+ }
+ if (offsets[i] == pixelSize-1) i++;
+ if (i == pixelSize) { // Ok, it is it
+ doSwap = 1;
+ swapFirst = 1;
+ knownFormat = true;
+ }
+ }
+
+ // "ABGR"
+ if (!knownFormat) {
+ for (i=0; i < pixelSize; i++) {
+ if (offsets[i] != pixelSize - 1 - i) break;
+ }
+ if (i == pixelSize) { // Ok, it is it
+ doSwap = 1;
+ swapFirst = 0;
+ knownFormat = true;
+ }
+ }
+
+ // XXX - Planar formats are not supported yet
+ if (!knownFormat)
+ return 0;
+
+ return
+ channelsSh(channels) |
+ bytesSh(bytes) |
+ extraSh(extra) |
+ doswapSh(doSwap) |
+ swapfirstSh(swapFirst);
+ }
+
+ /**
+ * Obtains data array from the DataBuffer object
+ * @param db - data buffer
+ * @return - true if successful
+ */
+ private boolean setImageData(DataBuffer db) {
+ AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
+ try {
+ imageData = dbAccess.getData(db);
+ } catch (IllegalArgumentException e) {
+ return false; // Unknown data buffer type
+ }
+
+ return true;
+ }
+
+ /**
+ * Calculates scanline stride in bytes
+ * @param csm - component sample model
+ * @param r - raster
+ * @return scanline stride in bytes
+ */
+ private static int calculateScanlineStrideCSM(ComponentSampleModel csm, Raster r) {
+ if (csm.getScanlineStride() != csm.getPixelStride()*csm.getWidth()) {
+ int dataTypeSize = DataBuffer.getDataTypeSize(r.getDataBuffer().getDataType()) / 8;
+ return csm.getScanlineStride()*dataTypeSize;
+ }
+ return -1;
+ }
+
+ /**
+ * Calculates scanline stride in bytes
+ * @param sppsm - sample model
+ * @param r - raster
+ * @return scanline stride in bytes
+ */
+ private static int calculateScanlineStrideSPPSM(SinglePixelPackedSampleModel sppsm, Raster r) {
+ if (sppsm.getScanlineStride() != sppsm.getWidth()) {
+ int dataTypeSize = DataBuffer.getDataTypeSize(r.getDataBuffer().getDataType()) / 8;
+ return sppsm.getScanlineStride()*dataTypeSize;
+ }
+ return -1;
+ }
+
+ /**
+ * Calculates byte offset of the alpha channel from the beginning of the pixel data
+ * @param sm - sample model
+ * @param r - raster
+ * @return byte offset of the alpha channel
+ */
+ private static int calculateAlphaOffset(SampleModel sm, Raster r) {
+ if (sm instanceof ComponentSampleModel) {
+ ComponentSampleModel csm = (ComponentSampleModel) sm;
+ int dataTypeSize =
+ DataBuffer.getDataTypeSize(r.getDataBuffer().getDataType()) / 8;
+ return
+ csm.getBandOffsets()[csm.getBandOffsets().length - 1] * dataTypeSize;
+ } else if (sm instanceof SinglePixelPackedSampleModel) {
+ SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
+ return sppsm.getBitOffsets()[sppsm.getBitOffsets().length - 1] / 8;
+ } else {
+ return -1; // No offset, don't copy alpha
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidFont.java b/awt/org/apache/harmony/awt/gl/font/AndroidFont.java
new file mode 100644
index 0000000..e8ad1bb
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidFont.java
@@ -0,0 +1,254 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.util.Hashtable;
+import java.util.Locale;
+
+import org.apache.harmony.awt.gl.font.FontManager;
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.Glyph;
+import org.apache.harmony.awt.gl.font.LineMetricsImpl;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Linux platform font peer implementation based on Xft and FreeType libraries.
+ */
+public class AndroidFont extends FontPeerImpl {
+
+ // Pairs of [begin, end],[..].. unicode ranges values
+ private int[] fontUnicodeRanges;
+
+ // table with loaded cached Glyphs
+ private Hashtable glyphs = new Hashtable();
+
+ // X11 display value
+ private long display = 0;
+
+ // X11 screen value
+ private int screen = 0;
+
+ public AndroidFont(String fontName, int fontStyle, int fontSize) {
+ /*
+ * Workaround : to initialize awt platform-dependent fields and libraries.
+ */
+ Toolkit.getDefaultToolkit();
+ this.name = fontName;
+ this.size = fontSize;
+ this.style = fontStyle;
+
+ initAndroidFont();
+ }
+
+ /**
+ * Initializes some native dependent font information, e.g. number of glyphs,
+ * font metrics, italic angle etc.
+ */
+ public void initAndroidFont(){
+ this.nlm = new AndroidLineMetrics(this, null, " "); //$NON-NLS-1$
+ this.ascent = nlm.getLogicalAscent();
+ this.descent = nlm.getLogicalDescent();
+ this.height = nlm.getHeight();
+ this.leading = nlm.getLogicalLeading();
+ this.maxAdvance = nlm.getLogicalMaxCharWidth();
+
+ if (this.fontType == FontManager.FONT_TYPE_T1){
+ this.defaultChar = 1;
+ } else {
+ this.defaultChar = 0;
+ }
+
+ this.maxCharBounds = new Rectangle2D.Float(0, -nlm.getAscent(), nlm.getMaxCharWidth(), this.height);
+ }
+
+
+ public boolean canDisplay(char chr) {
+ // TODO: to improve performance there is a sence to implement get
+ // unicode ranges to check if char can be displayed without
+ // native calls in isGlyphExists() method
+
+ return isGlyphExists(chr);
+ }
+
+ public LineMetrics getLineMetrics(String str, FontRenderContext frc, AffineTransform at) {
+
+ // Initialize baseline offsets
+ nlm.getBaselineOffsets();
+
+ LineMetricsImpl lm = (LineMetricsImpl)(this.nlm.clone());
+ lm.setNumChars(str.length());
+
+ if ((at != null) && (!at.isIdentity())){
+ lm.scale((float)at.getScaleX(), (float)at.getScaleY());
+ }
+
+ return lm;
+ }
+
+ public String getPSName() {
+ return psName;
+ }
+
+ public String getFamily(Locale l) {
+ // TODO: implement localized family
+ if (fontType == FontManager.FONT_TYPE_TT){
+ return this.getFamily();
+ }
+
+ return this.fontFamilyName;
+ }
+
+ public String getFontName(Locale l) {
+ if ((pFont == 0) || (this.fontType == FontManager.FONT_TYPE_T1)){
+ return this.name;
+ }
+
+ return this.getFontName();
+ }
+
+
+ public int getMissingGlyphCode() {
+ return getDefaultGlyph().getGlyphCode();
+ }
+
+ public Glyph getGlyph(char index) {
+ Glyph result = null;
+
+ Object key = new Integer(index);
+ if (glyphs.containsKey(key)) {
+ result = (Glyph) glyphs.get(key);
+ } else {
+ if (this.addGlyph(index)) {
+ result = (Glyph) glyphs.get(key);
+ } else {
+ result = this.getDefaultGlyph();
+ }
+ }
+
+ return result;
+ }
+
+ public Glyph getDefaultGlyph() {
+ throw new RuntimeException("DefaultGlyphs not implemented!");
+ }
+
+ /**
+ * Disposes native font handle. If this font peer was created from InputStream
+ * temporary created font resource file is deleted.
+ */
+ public void dispose(){
+ String tempDirName;
+ if (pFont != 0){
+ pFont = 0;
+
+ if (isCreatedFromStream()) {
+ File fontFile = new File(getTempFontFileName());
+ tempDirName = fontFile.getParent();
+ fontFile.delete();
+ }
+ }
+ }
+
+ /**
+ * Add glyph to cached Glyph objects in this LinuxFont object.
+ *
+ * @param uChar the specified character
+ * @return true if glyph of the specified character exists in this
+ * LinuxFont or this character is escape sequence character.
+ */
+ public boolean addGlyph(char uChar) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ /**
+ * Adds range of existing glyphs to this LinuxFont object
+ *
+ * @param uFirst the lowest range's bound, inclusive
+ * @param uLast the highest range's bound, exclusive
+ */
+ public void addGlyphs(char uFirst, char uLast) {
+
+ char index = uFirst;
+ if (uLast < uFirst) {
+ // awt.09=min range bound value is grater than max range bound
+ throw new IllegalArgumentException(Messages.getString("awt.09")); //$NON-NLS-1$
+ }
+ while (index < uLast) {
+ addGlyph(index);
+ index++;
+ }
+
+ }
+
+ /**
+ * Returns true if specified character has corresopnding glyph, false otherwise.
+ *
+ * @param uIndex specified char
+ */
+ public boolean isGlyphExists(char uIndex) {
+ throw new RuntimeException("DefaultGlyphs not implemented!");
+ }
+
+ /**
+ * Returns an array of unicode ranges that are supported by this LinuxFont.
+ */
+ public int[] getUnicodeRanges() {
+ int[] ranges = new int[fontUnicodeRanges.length];
+ System.arraycopy(fontUnicodeRanges, 0, ranges, 0,
+ fontUnicodeRanges.length);
+
+ return ranges;
+ }
+
+ /**
+ * Return Font object if it was successfully embedded in System
+ */
+ public static Font embedFont(String absolutePath){
+ throw new RuntimeException("embedFont not implemented!");
+ }
+
+ public String getFontName(){
+ if ((pFont != 0) && (faceName == null)){
+ if (this.fontType == FontManager.FONT_TYPE_T1){
+ faceName = getFamily();
+ }
+ }
+ return faceName;
+ }
+
+ public String getFamily() {
+ return fontFamilyName;
+ }
+
+ /**
+ * Returns initiated FontExtraMetrics instance of this WindowsFont.
+ */
+ public FontExtraMetrics getExtraMetrics(){
+ throw new RuntimeException("Not implemented!");
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java b/awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java
new file mode 100644
index 0000000..063a256
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidFontManager.java
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.peer.FontPeer;
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.font.FontManager;
+import org.apache.harmony.awt.gl.font.FontProperty;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+import android.util.Log;
+
+public class AndroidFontManager extends FontManager {
+
+ // set of all available faces supported by a system
+ String faces[];
+
+ // weight names according to xlfd structure
+ public static final String[] LINUX_WEIGHT_NAMES = {
+ "black", "bold", "demibold", "medium", "light" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ };
+
+ // slant names according to xlfd structure
+ public static final String[] LINUX_SLANT_NAMES = {
+ "i", "o", "r" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ };
+
+ /** Singleton AndroidFontManager instance */
+ public static final AndroidFontManager inst = new AndroidFontManager();
+
+ private AndroidFontManager() {
+ super();
+ faces = new String[] {/*"PLAIN",*/ "NORMAL", "BOLD", "ITALIC", "BOLDITALIC"};
+ initFontProperties();
+ }
+
+ public void initLCIDTable(){
+ throw new RuntimeException("Not implemented!");
+ }
+
+ /**
+ * Returns temporary File object to store data from InputStream.
+ * This File object saved to `~/.fonts/' folder that is included in the
+ * list of folders searched for font files, and this is where user-specific
+ * font files should be installed.
+ */
+ public File getTempFontFile()throws IOException{
+ File fontFile = File.createTempFile("jFont", ".ttf", new File(System.getProperty("user.home") +"/.fonts")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ fontFile.deleteOnExit();
+
+ return fontFile;
+ }
+
+ /**
+ * Initializes fProperties array field for the current system configuration font
+ * property file.
+ *
+ * RuntimeException is thrown if font property contains incorrect format of
+ * xlfd string.
+ *
+ * @return true is success, false if font property doesn't exist or doesn't
+ * contain roperties.
+ */
+ public boolean initFontProperties(){
+ File fpFile = getFontPropertyFile();
+ if (fpFile == null){
+ return false;
+ }
+
+ Properties props = getProperties(fpFile);
+ if (props == null){
+ return false;
+ }
+
+ for (int i=0; i < LOGICAL_FONT_NAMES.length; i++){
+ String lName = LOGICAL_FONT_NAMES[i];
+ for (int j=0; j < STYLE_NAMES.length; j++){
+ String styleName = STYLE_NAMES[j];
+ Vector propsVector = new Vector();
+
+ // Number of entries for a logical font
+ int numComp = 0;
+ // Is more entries for this style and logical font name left
+ boolean moreEntries = true;
+ String value = null;
+
+ while(moreEntries){
+ // Component Font Mappings property name
+ String property = FONT_MAPPING_KEYS[0].replaceAll("LogicalFontName", lName).replaceAll("StyleName", styleName).replaceAll("ComponentIndex", String.valueOf(numComp)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ value = props.getProperty(property);
+
+ // If the StyleName is omitted, it's assumed to be plain
+ if ((j == 0) && (value == null)){
+ property = FONT_MAPPING_KEYS[1].replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp)); //$NON-NLS-1$ //$NON-NLS-2$
+ value = props.getProperty(property);
+ }
+
+ if (value != null){
+ String[] fields = parseXLFD(value);
+
+ if (fields == null){
+ // awt.08=xfld parse string error: {0}
+ throw new RuntimeException(Messages.getString("awt.08", value)); //$NON-NLS-1$
+ }
+
+ String fontName = fields[1];
+ String weight = fields[2];
+ String italic = fields[3];
+
+ int style = getBoldStyle(weight) | getItalicStyle(italic);
+ // Component Font Character Encodings property value
+ String encoding = props.getProperty(FONT_CHARACTER_ENCODING.replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp))); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // Exclusion Ranges property value
+ String exclString = props.getProperty(EXCLUSION_RANGES.replaceAll("LogicalFontName", lName).replaceAll("ComponentIndex", String.valueOf(numComp))); //$NON-NLS-1$ //$NON-NLS-2$
+ int[] exclRange = parseIntervals(exclString);
+
+ FontProperty fp = new AndroidFontProperty(lName, styleName, null, fontName, value, style, exclRange, encoding);
+
+ propsVector.add(fp);
+ numComp++;
+ } else {
+ moreEntries = false;
+ }
+ }
+ fProperties.put(LOGICAL_FONT_NAMES[i] + "." + j, propsVector); //$NON-NLS-1$
+ }
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Returns style according to the xlfd weight string.
+ * If weight string is incorrect returned value is Font.PLAIN
+ *
+ * @param str weight name String
+ */
+ private int getBoldStyle(String str){
+ for (int i = 0; i < LINUX_WEIGHT_NAMES.length;i++){
+ if (str.equalsIgnoreCase(LINUX_WEIGHT_NAMES[i])){
+ return (i < 3) ? Font.BOLD : Font.PLAIN;
+ }
+ }
+ return Font.PLAIN;
+ }
+
+ /**
+ * Returns style according to the xlfd slant string.
+ * If slant string is incorrect returned value is Font.PLAIN
+ *
+ * @param str slant name String
+ */
+ private int getItalicStyle(String str){
+ for (int i = 0; i < LINUX_SLANT_NAMES.length;i++){
+ if (str.equalsIgnoreCase(LINUX_SLANT_NAMES[i])){
+ return (i < 2) ? Font.ITALIC : Font.PLAIN;
+ }
+ }
+ return Font.PLAIN;
+ }
+
+ /**
+ * Parse xlfd string and returns array of Strings with separate xlfd
+ * elements.<p>
+ *
+ * xlfd format:
+ * -Foundry-Family-Weight-Slant-Width-Style-PixelSize-PointSize-ResX-ResY-Spacing-AvgWidth-Registry-Encoding
+ * @param xlfd String parameter in xlfd format
+ */
+ public static String[] parseXLFD(String xlfd){
+ int fieldsCount = 14;
+ String fieldsDelim = "-"; //$NON-NLS-1$
+ String[] res = new String[fieldsCount];
+ if (!xlfd.startsWith(fieldsDelim)){
+ return null;
+ }
+
+ xlfd = xlfd.substring(1);
+ int i=0;
+ int pos;
+ for (i=0; i < fieldsCount-1; i++){
+ pos = xlfd.indexOf(fieldsDelim);
+ if (pos != -1){
+ res[i] = xlfd.substring(0, pos);
+ xlfd = xlfd.substring(pos + 1);
+ } else {
+ return null;
+ }
+ }
+ pos = xlfd.indexOf(fieldsDelim);
+
+ // check if no fields left
+ if(pos != -1){
+ return null;
+ }
+ res[fieldsCount-1] = xlfd;
+
+ return res;
+ }
+
+ public int getFaceIndex(String faceName){
+
+ for (int i = 0; i < faces.length; i++) {
+ if(faces[i].equals(faceName)){
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public String[] getAllFamilies(){
+ if (allFamilies == null){
+ allFamilies = new String[]{"sans-serif", "serif", "monospace"};
+ }
+ return allFamilies;
+ }
+
+ public Font[] getAllFonts(){
+ Font[] fonts = new Font[faces.length];
+ for (int i =0; i < fonts.length;i++){
+ fonts[i] = new Font(faces[i], Font.PLAIN, 1);
+ }
+ return fonts;
+ }
+
+ public FontPeer createPhysicalFontPeer(String name, int style, int size) {
+ AndroidFont peer;
+ int familyIndex = getFamilyIndex(name);
+ if (familyIndex != -1){
+ // !! we use family names from the list with cached families because
+ // they are differ from the family names in xlfd structure, in xlfd
+ // family names mostly in lower case.
+ peer = new AndroidFont(getFamily(familyIndex), style, size);
+ peer.setFamily(getFamily(familyIndex));
+ return peer;
+ }
+ int faceIndex = getFaceIndex(name);
+ if (faceIndex != -1){
+
+ peer = new AndroidFont(name, style, size);
+ return peer;
+ }
+
+ return null;
+ }
+
+ public FontPeer createDefaultFont(int style, int size) {
+ Log.i("DEFAULT FONT", Integer.toString(style));
+ return new AndroidFont(DEFAULT_NAME, style, size);
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java b/awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java
new file mode 100644
index 0000000..0cfdc43
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidFontProperty.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ *
+ */
+package org.apache.harmony.awt.gl.font;
+
+/**
+ * Android FontProperty implementation, applicable for Linux formats of
+ * font property files.
+ */
+public class AndroidFontProperty extends FontProperty {
+
+ /** xlfd string that is applicable for Linux font.properties */
+ String xlfd;
+
+ /** logical name of the font corresponding to this FontProperty */
+ String logicalName;
+
+ /** style name of the font corresponding to this FontProperty */
+ String styleName;
+
+ public AndroidFontProperty(String _logicalName, String _styleName, String _fileName, String _name, String _xlfd, int _style, int[] exclusionRange, String _encoding){
+ this.logicalName = _logicalName;
+ this.styleName = _styleName;
+ this.name = _name;
+ this.encoding = _encoding;
+ this.exclRange = exclusionRange;
+ this.fileName = _fileName;
+ this.xlfd = _xlfd;
+ this.style = _style;
+ }
+
+ /**
+ * Returns logical name of the font corresponding to this FontProperty.
+ */
+ public String getLogicalName(){
+ return logicalName;
+ }
+
+ /**
+ * Returns style name of the font corresponding to this FontProperty.
+ */
+ public String getStyleName(){
+ return styleName;
+ }
+
+ /**
+ * Returns xlfd string of this FontProperty.
+ */
+ public String getXLFD(){
+ return xlfd;
+ }
+
+ public String toString(){
+ return new String(this.getClass().getName() +
+ "[name=" + name + //$NON-NLS-1$
+ ",fileName="+ fileName + //$NON-NLS-1$
+ ",Charset=" + encoding + //$NON-NLS-1$
+ ",exclRange=" + exclRange + //$NON-NLS-1$
+ ",xlfd=" + xlfd + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java b/awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java
new file mode 100644
index 0000000..4ce5aed
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java
@@ -0,0 +1,219 @@
+package org.apache.harmony.awt.gl.font;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.Font;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import android.util.Log;
+import android.graphics.Path;
+
+public class AndroidGlyphVector extends GlyphVector {
+
+ // array of chars defined in constructor
+ public char[] charVector;
+
+ // array of Glyph objects, that describe information about glyphs
+ public Glyph[] vector;
+
+ // array of default positions of glyphs in GlyphVector
+ // without applying GlyphVector's transform
+ float[] defaultPositions;
+
+ // array of logical positions of glyphs in GlyphVector
+
+ float[] logicalPositions;
+
+ // array of visual (real) positions of glyphs in GlyphVector
+ public float[] visualPositions;
+
+ // FontRenderContext for this vector.
+ protected FontRenderContext vectorFRC;
+
+ // layout flags mask
+ protected int layoutFlags = 0;
+
+ // array of cached glyph outlines
+ protected Shape[] gvShapes;
+
+ FontPeerImpl peer;
+
+ // font corresponding to the GlyphVector
+ Font font;
+
+ // ascent of the font
+ float ascent;
+
+ // height of the font
+ float height;
+
+ // leading of the font
+ float leading;
+
+ // descent of the font
+ float descent;
+
+ // transform of the GlyphVector
+ AffineTransform transform;
+
+ @SuppressWarnings("deprecation")
+ public AndroidGlyphVector(char[] chars, FontRenderContext frc, Font fnt,
+ int flags) {
+ int len = chars.length;
+ this.font = fnt;
+ LineMetricsImpl lmImpl = (LineMetricsImpl)fnt.getLineMetrics(String.valueOf(chars), frc);
+ this.ascent = lmImpl.getAscent();
+ this.height = lmImpl.getHeight();
+ this.leading = lmImpl.getLeading();
+ this.descent = lmImpl.getDescent();
+ this.charVector = chars;
+ this.vectorFRC = frc;
+ }
+
+ public AndroidGlyphVector(char[] chars, FontRenderContext frc, Font fnt) {
+ this(chars, frc, fnt, 0);
+ }
+
+ public AndroidGlyphVector(String str, FontRenderContext frc, Font fnt) {
+ this(str.toCharArray(), frc, fnt, 0);
+ }
+
+ public AndroidGlyphVector(String str, FontRenderContext frc, Font fnt, int flags) {
+ this(str.toCharArray(), frc, fnt, flags);
+ }
+
+ @Override
+ public boolean equals(GlyphVector glyphVector) {
+ return false;
+ }
+
+ public char[] getGlyphs() {
+ return this.charVector;
+ }
+
+ @Override
+ public Font getFont() {
+ return this.font;
+ }
+
+ @Override
+ public FontRenderContext getFontRenderContext() {
+ return this.vectorFRC;
+ }
+
+ @Override
+ public int getGlyphCode(int glyphIndex) {
+ return charVector[glyphIndex];
+ }
+
+ @Override
+ public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
+ int[] codeReturn) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public Shape getGlyphLogicalBounds(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public GlyphMetrics getGlyphMetrics(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ public Path getAndroidGlyphOutline(int glyphIndex) {
+ AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+ Path path = new Path();
+ char tmp[] = new char[1];
+ tmp[0] = charVector[glyphIndex];
+ ((AndroidGraphics2D)g).getAndroidPaint().getTextPath(new String(tmp), 0, 1, 0, 0, path);
+ return path;
+ }
+
+ @Override
+ public Shape getGlyphOutline(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public Point2D getGlyphPosition(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
+ float[] positionReturn) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public AffineTransform getGlyphTransform(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public Shape getGlyphVisualBounds(int glyphIndex) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public Rectangle2D getLogicalBounds() {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public int getNumGlyphs() {
+ return charVector.length;
+ }
+
+ @Override
+ public Shape getOutline(float x, float y) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public Shape getOutline() {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ public Path getAndroidOutline() {
+ AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+ Path path = new Path();
+ ((AndroidGraphics2D)g).getAndroidPaint().getTextPath(new String(charVector), 0, charVector.length, 0, 0, path);
+ return path;
+ }
+
+ @Override
+ public Rectangle2D getVisualBounds() {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public void performDefaultLayout() {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public void setGlyphPosition(int glyphIndex, Point2D newPos) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+ @Override
+ public void setGlyphTransform(int glyphIndex, AffineTransform trans) {
+ throw new RuntimeException("Not implemented!");
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java b/awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java
new file mode 100644
index 0000000..f37be6d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.FontRenderContext;
+import org.apache.harmony.awt.gl.font.LineMetricsImpl;
+
+
+/**
+ *
+ * Linux implementation of LineMetrics class
+ */
+public class AndroidLineMetrics extends LineMetricsImpl {
+
+ /**
+ * Constructor
+ */
+ public AndroidLineMetrics( AndroidFont fnt,
+ FontRenderContext frc,
+ String str){
+ numChars = str.length();
+ baseLineIndex = 0;
+
+ ascent = fnt.ascent; // Ascent of the font
+ descent = -fnt.descent; // Descent of the font
+ leading = fnt.leading; // External leading
+
+ height = ascent + descent + leading; // Height of the font ( == (ascent + descent + leading))
+ underlineThickness = 0.0f;
+ underlineOffset = 0.0f;
+ strikethroughThickness = 0.0f;
+ strikethroughOffset = 0.0f;
+ maxCharWidth = 0.0f;
+
+ // TODO: Find out pixel metrics
+ /*
+ * positive metrics rounded to the smallest int that is bigger than value
+ * negative metrics rounded to the smallest int that is lesser than value
+ * thicknesses rounded to int ((int)round(value + 0.5))
+ *
+ */
+
+ lAscent = (int)Math.ceil(fnt.ascent);// // Ascent of the font
+ lDescent = -(int)Math.ceil(fnt.descent);// Descent of the font
+ lLeading = (int)Math.ceil(leading); // External leading
+
+ lHeight = lAscent + lDescent + lLeading; // Height of the font ( == (ascent + descent + leading))
+
+ lUnderlineThickness = Math.round(underlineThickness);//(int)metrics[11];
+
+ if (underlineOffset >= 0){
+ lUnderlineOffset = (int)Math.ceil(underlineOffset);
+ } else {
+ lUnderlineOffset = (int)Math.floor(underlineOffset);
+ }
+
+ lStrikethroughThickness = Math.round(strikethroughThickness); //(int)metrics[13];
+
+ if (strikethroughOffset >= 0){
+ lStrikethroughOffset = (int)Math.ceil(strikethroughOffset);
+ } else {
+ lStrikethroughOffset = (int)Math.floor(strikethroughOffset);
+ }
+
+ lMaxCharWidth = (int)Math.ceil(maxCharWidth); //(int)metrics[15];
+ units_per_EM = 0;
+
+ }
+
+ public float[] getBaselineOffsets() {
+ // TODO: implement baseline offsets for TrueType fonts
+ if (baselineOffsets == null){
+ float[] baselineData = null;
+
+ // Temporary workaround:
+ // Commented out native data initialization, since it can
+ // cause failures with opening files in multithreaded applications.
+ //
+ // TODO: support work with truetype data in multithreaded
+ // applications.
+
+ // If font TrueType data is taken from BASE table
+// if ((this.font.getFontHandle() != 0) && (font.getFontType() == FontManager.FONT_TYPE_TT)){
+// baselineData = LinuxNativeFont.getBaselineOffsetsNative(font.getFontHandle(), font.getSize(), ascent, descent, units_per_EM);
+// }
+//
+ baseLineIndex = 0;
+ baselineOffsets = new float[]{0, (-ascent+descent)/2, -ascent};
+ }
+
+ return baselineOffsets;
+ }
+
+ public int getBaselineIndex() {
+ if (baselineOffsets == null){
+ // get offsets and set correct index
+ getBaselineOffsets();
+ }
+ return baseLineIndex;
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/BasicMetrics.java b/awt/org/apache/harmony/awt/gl/font/BasicMetrics.java
new file mode 100644
index 0000000..c0fb390
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/BasicMetrics.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.LineMetrics;
+import java.awt.font.GraphicAttribute;
+import java.awt.*;
+
+/**
+ * Date: May 14, 2005
+ * Time: 7:44:13 PM
+ *
+ * This class incapsulates text metrics specific for the text layout or
+ * for the separate text segment. Text segment is a text run with the constant direction
+ * and attributes like font, decorations, etc. BasicMetrics is also used to store
+ * calculated text metrics like advance, ascent or descent. this class is very similar to
+ * LineMetrics, but provides some additional info, constructors and is more transparent.
+ */
+public class BasicMetrics {
+ int baseLineIndex;
+
+ float ascent; // Ascent of the font
+ float descent; // Descent of the font
+ float leading; // External leading
+ float advance;
+
+ float italicAngle;
+ float superScriptOffset;
+
+ float underlineOffset;
+ float underlineThickness;
+
+ float strikethroughOffset;
+ float strikethroughThickness;
+
+ /**
+ * Constructs BasicMetrics from LineMetrics and font
+ * @param lm
+ * @param font
+ */
+ BasicMetrics(LineMetrics lm, Font font) {
+ ascent = lm.getAscent();
+ descent = lm.getDescent();
+ leading = lm.getLeading();
+
+ underlineOffset = lm.getUnderlineOffset();
+ underlineThickness = lm.getUnderlineThickness();
+
+ strikethroughOffset = lm.getStrikethroughOffset();
+ strikethroughThickness = lm.getStrikethroughThickness();
+
+ baseLineIndex = lm.getBaselineIndex();
+
+ italicAngle = font.getItalicAngle();
+ superScriptOffset = (float) font.getTransform().getTranslateY();
+ }
+
+ /**
+ * Constructs BasicMetrics from GraphicAttribute.
+ * It gets ascent and descent from the graphic attribute and
+ * computes reasonable defaults for other metrics.
+ * @param ga - graphic attribute
+ */
+ BasicMetrics(GraphicAttribute ga) {
+ ascent = ga.getAscent();
+ descent = ga.getDescent();
+ leading = 2;
+
+ baseLineIndex = ga.getAlignment();
+
+ italicAngle = 0;
+ superScriptOffset = 0;
+
+ underlineOffset = Math.max(descent/2, 1);
+
+ // Just suggested, should be cap_stem_width or something like that
+ underlineThickness = Math.max(ascent/13, 1);
+
+ strikethroughOffset = -ascent/2; // Something like middle of the line
+ strikethroughThickness = underlineThickness;
+ }
+
+ /**
+ * Copies metrics from the TextMetricsCalculator object.
+ * @param tmc - TextMetricsCalculator object
+ */
+ BasicMetrics(TextMetricsCalculator tmc) {
+ ascent = tmc.ascent;
+ descent = tmc.descent;
+ leading = tmc.leading;
+ advance = tmc.advance;
+ baseLineIndex = tmc.baselineIndex;
+ }
+
+ public float getAscent() {
+ return ascent;
+ }
+
+ public float getDescent() {
+ return descent;
+ }
+
+ public float getLeading() {
+ return leading;
+ }
+
+ public float getAdvance() {
+ return advance;
+ }
+
+ public int getBaseLineIndex() {
+ return baseLineIndex;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/CaretManager.java b/awt/org/apache/harmony/awt/gl/font/CaretManager.java
new file mode 100644
index 0000000..b18bdd5
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/CaretManager.java
@@ -0,0 +1,530 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Jun 14, 2005
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.TextHitInfo;
+import java.awt.font.TextLayout;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+import java.awt.*;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class provides functionality for creating caret and highlight shapes
+ * (bidirectional text is also supported, but, unfortunately, not tested yet).
+ */
+public class CaretManager {
+ private TextRunBreaker breaker;
+
+ public CaretManager(TextRunBreaker breaker) {
+ this.breaker = breaker;
+ }
+
+ /**
+ * Checks if TextHitInfo is not out of the text range and throws the
+ * IllegalArgumentException if it is.
+ * @param info - text hit info
+ */
+ private void checkHit(TextHitInfo info) {
+ int idx = info.getInsertionIndex();
+
+ if (idx < 0 || idx > breaker.getCharCount()) {
+ // awt.42=TextHitInfo out of range
+ throw new IllegalArgumentException(Messages.getString("awt.42")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Calculates and returns visual position from the text hit info.
+ * @param hitInfo - text hit info
+ * @return visual index
+ */
+ private int getVisualFromHitInfo(TextHitInfo hitInfo) {
+ final int idx = hitInfo.getCharIndex();
+
+ if (idx >= 0 && idx < breaker.getCharCount()) {
+ int visual = breaker.getVisualFromLogical(idx);
+ // We take next character for (LTR char + TRAILING info) and (RTL + LEADING)
+ if (hitInfo.isLeadingEdge() ^ ((breaker.getLevel(idx) & 0x1) == 0x0)) {
+ visual++;
+ }
+ return visual;
+ } else if (idx < 0) {
+ return breaker.isLTR() ? 0: breaker.getCharCount();
+ } else {
+ return breaker.isLTR() ? breaker.getCharCount() : 0;
+ }
+ }
+
+ /**
+ * Calculates text hit info from the visual position
+ * @param visual - visual position
+ * @return text hit info
+ */
+ private TextHitInfo getHitInfoFromVisual(int visual) {
+ final boolean first = visual == 0;
+
+ if (!(first || visual == breaker.getCharCount())) {
+ int logical = breaker.getLogicalFromVisual(visual);
+ return (breaker.getLevel(logical) & 0x1) == 0x0 ?
+ TextHitInfo.leading(logical) : // LTR
+ TextHitInfo.trailing(logical); // RTL
+ } else if (first) {
+ return breaker.isLTR() ?
+ TextHitInfo.trailing(-1) :
+ TextHitInfo.leading(breaker.getCharCount());
+ } else { // Last
+ return breaker.isLTR() ?
+ TextHitInfo.leading(breaker.getCharCount()) :
+ TextHitInfo.trailing(-1);
+ }
+ }
+
+ /**
+ * Creates caret info. Required for the getCaretInfo
+ * methods of the TextLayout
+ * @param hitInfo - specifies caret position
+ * @return caret info, see TextLayout.getCaretInfo documentation
+ */
+ public float[] getCaretInfo(TextHitInfo hitInfo) {
+ checkHit(hitInfo);
+ float res[] = new float[2];
+
+ int visual = getVisualFromHitInfo(hitInfo);
+ float advance, angle;
+ TextRunSegment seg;
+
+ if (visual < breaker.getCharCount()) {
+ int logIdx = breaker.getLogicalFromVisual(visual);
+ int segmentIdx = breaker.logical2segment[logIdx];
+ seg = breaker.runSegments.get(segmentIdx);
+ advance = seg.x + seg.getAdvanceDelta(seg.getStart(), logIdx);
+ angle = seg.metrics.italicAngle;
+
+ } else { // Last character
+ int logIdx = breaker.getLogicalFromVisual(visual-1);
+ int segmentIdx = breaker.logical2segment[logIdx];
+ seg = breaker.runSegments.get(segmentIdx);
+ advance = seg.x + seg.getAdvanceDelta(seg.getStart(), logIdx+1);
+ }
+
+ angle = seg.metrics.italicAngle;
+
+ res[0] = advance;
+ res[1] = angle;
+
+ return res;
+ }
+
+ /**
+ * Returns the next position to the right from the current caret position
+ * @param hitInfo - current position
+ * @return next position to the right
+ */
+ public TextHitInfo getNextRightHit(TextHitInfo hitInfo) {
+ checkHit(hitInfo);
+ int visual = getVisualFromHitInfo(hitInfo);
+
+ if (visual == breaker.getCharCount()) {
+ return null;
+ }
+
+ TextHitInfo newInfo;
+
+ while(visual <= breaker.getCharCount()) {
+ visual++;
+ newInfo = getHitInfoFromVisual(visual);
+
+ if (newInfo.getCharIndex() >= breaker.logical2segment.length) {
+ return newInfo;
+ }
+
+ if (hitInfo.getCharIndex() >= 0) { // Don't check for leftmost info
+ if (
+ breaker.logical2segment[newInfo.getCharIndex()] !=
+ breaker.logical2segment[hitInfo.getCharIndex()]
+ ) {
+ return newInfo; // We crossed segment boundary
+ }
+ }
+
+ TextRunSegment seg = breaker.runSegments.get(breaker.logical2segment[newInfo
+ .getCharIndex()]);
+ if (!seg.charHasZeroAdvance(newInfo.getCharIndex())) {
+ return newInfo;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the next position to the left from the current caret position
+ * @param hitInfo - current position
+ * @return next position to the left
+ */
+ public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) {
+ checkHit(hitInfo);
+ int visual = getVisualFromHitInfo(hitInfo);
+
+ if (visual == 0) {
+ return null;
+ }
+
+ TextHitInfo newInfo;
+
+ while(visual >= 0) {
+ visual--;
+ newInfo = getHitInfoFromVisual(visual);
+
+ if (newInfo.getCharIndex() < 0) {
+ return newInfo;
+ }
+
+ // Don't check for rightmost info
+ if (hitInfo.getCharIndex() < breaker.logical2segment.length) {
+ if (
+ breaker.logical2segment[newInfo.getCharIndex()] !=
+ breaker.logical2segment[hitInfo.getCharIndex()]
+ ) {
+ return newInfo; // We crossed segment boundary
+ }
+ }
+
+ TextRunSegment seg = breaker.runSegments.get(breaker.logical2segment[newInfo
+ .getCharIndex()]);
+ if (!seg.charHasZeroAdvance(newInfo.getCharIndex())) {
+ return newInfo;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * For each visual caret position there are two hits. For the simple LTR text one is
+ * a trailing of the previous char and another is the leading of the next char. This
+ * method returns the opposite hit for the given hit.
+ * @param hitInfo - given hit
+ * @return opposite hit
+ */
+ public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) {
+ checkHit(hitInfo);
+
+ int idx = hitInfo.getCharIndex();
+
+ int resIdx;
+ boolean resIsLeading;
+
+ if (idx >= 0 && idx < breaker.getCharCount()) { // Hit info in the middle
+ int visual = breaker.getVisualFromLogical(idx);
+
+ // Char is LTR + LEADING info
+ if (((breaker.getLevel(idx) & 0x1) == 0x0) ^ hitInfo.isLeadingEdge()) {
+ visual++;
+ if (visual == breaker.getCharCount()) {
+ if (breaker.isLTR()) {
+ resIdx = breaker.getCharCount();
+ resIsLeading = true;
+ } else {
+ resIdx = -1;
+ resIsLeading = false;
+ }
+ } else {
+ resIdx = breaker.getLogicalFromVisual(visual);
+ if ((breaker.getLevel(resIdx) & 0x1) == 0x0) {
+ resIsLeading = true;
+ } else {
+ resIsLeading = false;
+ }
+ }
+ } else {
+ visual--;
+ if (visual == -1) {
+ if (breaker.isLTR()) {
+ resIdx = -1;
+ resIsLeading = false;
+ } else {
+ resIdx = breaker.getCharCount();
+ resIsLeading = true;
+ }
+ } else {
+ resIdx = breaker.getLogicalFromVisual(visual);
+ if ((breaker.getLevel(resIdx) & 0x1) == 0x0) {
+ resIsLeading = false;
+ } else {
+ resIsLeading = true;
+ }
+ }
+ }
+ } else if (idx < 0) { // before "start"
+ if (breaker.isLTR()) {
+ resIdx = breaker.getLogicalFromVisual(0);
+ resIsLeading = (breaker.getLevel(resIdx) & 0x1) == 0x0; // LTR char?
+ } else {
+ resIdx = breaker.getLogicalFromVisual(breaker.getCharCount() - 1);
+ resIsLeading = (breaker.getLevel(resIdx) & 0x1) != 0x0; // RTL char?
+ }
+ } else { // idx == breaker.getCharCount()
+ if (breaker.isLTR()) {
+ resIdx = breaker.getLogicalFromVisual(breaker.getCharCount() - 1);
+ resIsLeading = (breaker.getLevel(resIdx) & 0x1) != 0x0; // LTR char?
+ } else {
+ resIdx = breaker.getLogicalFromVisual(0);
+ resIsLeading = (breaker.getLevel(resIdx) & 0x1) == 0x0; // RTL char?
+ }
+ }
+
+ return resIsLeading ? TextHitInfo.leading(resIdx) : TextHitInfo.trailing(resIdx);
+ }
+
+ public Line2D getCaretShape(TextHitInfo hitInfo, TextLayout layout) {
+ return getCaretShape(hitInfo, layout, true, false, null);
+ }
+
+ /**
+ * Creates a caret shape.
+ * @param hitInfo - hit where to place a caret
+ * @param layout - text layout
+ * @param useItalic - unused for now, was used to create
+ * slanted carets for italic text
+ * @param useBounds - true if the cared should fit into the provided bounds
+ * @param bounds - bounds for the caret
+ * @return caret shape
+ */
+ public Line2D getCaretShape(
+ TextHitInfo hitInfo, TextLayout layout,
+ boolean useItalic, boolean useBounds, Rectangle2D bounds
+ ) {
+ checkHit(hitInfo);
+
+ float x1, x2, y1, y2;
+
+ int charIdx = hitInfo.getCharIndex();
+
+ if (charIdx >= 0 && charIdx < breaker.getCharCount()) {
+ TextRunSegment segment = breaker.runSegments.get(breaker.logical2segment[charIdx]);
+ y1 = segment.metrics.descent;
+ y2 = - segment.metrics.ascent - segment.metrics.leading;
+
+ x1 = x2 = segment.getCharPosition(charIdx) + (hitInfo.isLeadingEdge() ?
+ 0 : segment.getCharAdvance(charIdx));
+ // Decided that straight cursor looks better even for italic fonts,
+ // especially combined with highlighting
+ /*
+ // Not graphics, need to check italic angle and baseline
+ if (layout.getBaseline() >= 0) {
+ if (segment.metrics.italicAngle != 0 && useItalic) {
+ x1 -= segment.metrics.italicAngle * segment.metrics.descent;
+ x2 += segment.metrics.italicAngle *
+ (segment.metrics.ascent + segment.metrics.leading);
+
+ float baselineOffset =
+ layout.getBaselineOffsets()[layout.getBaseline()];
+ y1 += baselineOffset;
+ y2 += baselineOffset;
+ }
+ }
+ */
+ } else {
+ y1 = layout.getDescent();
+ y2 = - layout.getAscent() - layout.getLeading();
+ x1 = x2 = ((breaker.getBaseLevel() & 0x1) == 0 ^ charIdx < 0) ?
+ layout.getAdvance() : 0;
+ }
+
+ if (useBounds) {
+ y1 = (float) bounds.getMaxY();
+ y2 = (float) bounds.getMinY();
+
+ if (x2 > bounds.getMaxX()) {
+ x1 = x2 = (float) bounds.getMaxX();
+ }
+ if (x1 < bounds.getMinX()) {
+ x1 = x2 = (float) bounds.getMinX();
+ }
+ }
+
+ return new Line2D.Float(x1, y1, x2, y2);
+ }
+
+ /**
+ * Creates caret shapes for the specified offset. On the boundaries where
+ * the text is changing its direction this method may return two shapes
+ * for the strong and the weak carets, in other cases it would return one.
+ * @param offset - offset in the text.
+ * @param bounds - bounds to fit the carets into
+ * @param policy - caret policy
+ * @param layout - text layout
+ * @return one or two caret shapes
+ */
+ public Shape[] getCaretShapes(
+ int offset, Rectangle2D bounds,
+ TextLayout.CaretPolicy policy, TextLayout layout
+ ) {
+ TextHitInfo hit1 = TextHitInfo.afterOffset(offset);
+ TextHitInfo hit2 = getVisualOtherHit(hit1);
+
+ Shape caret1 = getCaretShape(hit1, layout);
+
+ if (getVisualFromHitInfo(hit1) == getVisualFromHitInfo(hit2)) {
+ return new Shape[] {caret1, null};
+ }
+ Shape caret2 = getCaretShape(hit2, layout);
+
+ TextHitInfo strongHit = policy.getStrongCaret(hit1, hit2, layout);
+ return strongHit.equals(hit1) ?
+ new Shape[] {caret1, caret2} :
+ new Shape[] {caret2, caret1};
+ }
+
+ /**
+ * Connects two carets to produce a highlight shape.
+ * @param caret1 - 1st caret
+ * @param caret2 - 2nd caret
+ * @return highlight shape
+ */
+ GeneralPath connectCarets(Line2D caret1, Line2D caret2) {
+ GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+ path.moveTo((float) caret1.getX1(), (float) caret1.getY1());
+ path.lineTo((float) caret2.getX1(), (float) caret2.getY1());
+ path.lineTo((float) caret2.getX2(), (float) caret2.getY2());
+ path.lineTo((float) caret1.getX2(), (float) caret1.getY2());
+
+ path.closePath();
+
+ return path;
+ }
+
+ /**
+ * Creates a highlight shape from given two hits. This shape
+ * will always be visually contiguous
+ * @param hit1 - 1st hit
+ * @param hit2 - 2nd hit
+ * @param bounds - bounds to fit the shape into
+ * @param layout - text layout
+ * @return highlight shape
+ */
+ public Shape getVisualHighlightShape(
+ TextHitInfo hit1, TextHitInfo hit2,
+ Rectangle2D bounds, TextLayout layout
+ ) {
+ checkHit(hit1);
+ checkHit(hit2);
+
+ Line2D caret1 = getCaretShape(hit1, layout, false, true, bounds);
+ Line2D caret2 = getCaretShape(hit2, layout, false, true, bounds);
+
+ return connectCarets(caret1, caret2);
+ }
+
+ /**
+ * Suppose that the user visually selected a block of text which has
+ * several different levels (mixed RTL and LTR), so, in the logical
+ * representation of the text this selection may be not contigous.
+ * This methods returns a set of logical ranges for the arbitrary
+ * visual selection represented by two hits.
+ * @param hit1 - 1st hit
+ * @param hit2 - 2nd hit
+ * @return logical ranges for the selection
+ */
+ public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) {
+ checkHit(hit1);
+ checkHit(hit2);
+
+ int visual1 = getVisualFromHitInfo(hit1);
+ int visual2 = getVisualFromHitInfo(hit2);
+
+ if (visual1 > visual2) {
+ int tmp = visual2;
+ visual2 = visual1;
+ visual1 = tmp;
+ }
+
+ // Max level is 255, so we don't need more than 512 entries
+ int results[] = new int[512];
+
+ int prevLogical, logical, runStart, numRuns = 0;
+
+ logical = runStart = prevLogical = breaker.getLogicalFromVisual(visual1);
+
+ // Get all the runs. We use the fact that direction is constant in all runs.
+ for (int i=visual1+1; i<=visual2; i++) {
+ logical = breaker.getLogicalFromVisual(i);
+ int diff = logical-prevLogical;
+
+ // Start of the next run encountered
+ if (diff > 1 || diff < -1) {
+ results[(numRuns)*2] = Math.min(runStart, prevLogical);
+ results[(numRuns)*2 + 1] = Math.max(runStart, prevLogical);
+ numRuns++;
+ runStart = logical;
+ }
+
+ prevLogical = logical;
+ }
+
+ // The last unsaved run
+ results[(numRuns)*2] = Math.min(runStart, logical);
+ results[(numRuns)*2 + 1] = Math.max(runStart, logical);
+ numRuns++;
+
+ int retval[] = new int[numRuns*2];
+ System.arraycopy(results, 0, retval, 0, numRuns*2);
+ return retval;
+ }
+
+ /**
+ * Creates a highlight shape from given two endpoints in the logical
+ * representation. This shape is not always visually contiguous
+ * @param firstEndpoint - 1st logical endpoint
+ * @param secondEndpoint - 2nd logical endpoint
+ * @param bounds - bounds to fit the shape into
+ * @param layout - text layout
+ * @return highlight shape
+ */
+ public Shape getLogicalHighlightShape(
+ int firstEndpoint, int secondEndpoint,
+ Rectangle2D bounds, TextLayout layout
+ ) {
+ GeneralPath res = new GeneralPath();
+
+ for (int i=firstEndpoint; i<=secondEndpoint; i++) {
+ int endRun = breaker.getLevelRunLimit(i, secondEndpoint);
+ TextHitInfo hit1 = TextHitInfo.leading(i);
+ TextHitInfo hit2 = TextHitInfo.trailing(endRun-1);
+
+ Line2D caret1 = getCaretShape(hit1, layout, false, true, bounds);
+ Line2D caret2 = getCaretShape(hit2, layout, false, true, bounds);
+
+ res.append(connectCarets(caret1, caret2), false);
+
+ i = endRun;
+ }
+
+ return res;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java b/awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java
new file mode 100644
index 0000000..4040a60
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/CommonGlyphVector.java
@@ -0,0 +1,954 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * GlyphVector implementation
+ */
+public class CommonGlyphVector extends GlyphVector {
+
+ // array of transforms of glyphs in GlyphVector
+ protected AffineTransform[] glsTransforms;
+
+ // array of chars defined in constructor
+ public char[] charVector;
+
+ // array of Glyph objects, that describe information about glyphs
+ public Glyph[] vector;
+
+ // array of default positions of glyphs in GlyphVector
+ // without applying GlyphVector's transform
+ float[] defaultPositions;
+
+ // array of logical positions of glyphs in GlyphVector
+
+ float[] logicalPositions;
+
+ // array of visual (real) positions of glyphs in GlyphVector
+ public float[] visualPositions;
+
+ // FontRenderContext for this vector.
+ protected FontRenderContext vectorFRC;
+
+ // layout flags mask
+ protected int layoutFlags = 0;
+
+ // array of cached glyph outlines
+ protected Shape[] gvShapes;
+
+ FontPeerImpl peer;
+
+ // font corresponding to the GlyphVector
+ Font font;
+
+ // ascent of the font
+ float ascent;
+
+ // height of the font
+ float height;
+
+ // leading of the font
+ float leading;
+
+ // descent of the font
+ float descent;
+
+ // transform of the GlyphVector
+ AffineTransform transform;
+
+ /**
+ * Creates new CommonGlyphVector object from the specified parameters.
+ *
+ * @param chars an array of chars
+ * @param frc FontRenderContext object
+ * @param fnt Font object
+ * @param flags layout flags
+ */
+ @SuppressWarnings("deprecation")
+ public CommonGlyphVector(char[] chars, FontRenderContext frc, Font fnt,
+ int flags) {
+ int len = chars.length;
+
+ this.font = fnt;
+ this.transform = fnt.getTransform();
+ this.peer = (FontPeerImpl) fnt.getPeer();
+
+ gvShapes = new Shape[len];
+
+ // !! As pointed in API documentation for the
+ // getGlyphPosisitions(int index,int numEntries, float[] positionReturn)
+ // and getGlyphPosition(int index) methods, if the index is equals to
+ // the number of glyphs the position after the last glyph must be
+ // returned, thus there are n+1 positions and last (n+1) position
+ // points to the end of GlyphVector.
+
+ logicalPositions = new float[(len+1)<<1];
+ visualPositions = new float[(len+1)<<1];
+ defaultPositions = new float[(len+1)<<1];
+
+ glsTransforms = new AffineTransform[len];
+
+ this.charVector = chars;
+ this.vectorFRC = frc;
+ //LineMetricsImpl lmImpl = (LineMetricsImpl)peer.getLineMetrics();
+
+ LineMetricsImpl lmImpl = (LineMetricsImpl)fnt.getLineMetrics(String.valueOf(chars), frc);
+
+ this.ascent = lmImpl.getAscent();
+ this.height = lmImpl.getHeight();
+ this.leading = lmImpl.getLeading();
+ this.descent = lmImpl.getDescent();
+ this.layoutFlags = flags;
+
+ if ((flags & Font.LAYOUT_RIGHT_TO_LEFT) != 0){
+ char vector[] = new char[len];
+ for(int i=0; i < len; i++){
+ vector[i] = chars[len-i-1];
+ }
+ this.vector = peer.getGlyphs(vector);
+
+ } else {
+ this.vector = peer.getGlyphs(chars);
+ }
+
+ this.glsTransforms = new AffineTransform[len];
+
+ setDefaultPositions();
+ performDefaultLayout();
+ }
+
+ /**
+ * Creates new CommonGlyphVector object from the specified parameters.
+ * Layout flags set to default.
+ *
+ * @param chars an array of chars
+ * @param frc FontRenderContext object
+ * @param fnt Font object
+ */
+ public CommonGlyphVector(char[] chars, FontRenderContext frc, Font fnt) {
+ this(chars, frc, fnt, 0);
+ }
+
+ /**
+ * Creates new CommonGlyphVector object from the specified parameters.
+ * Layout flags set to default.
+ *
+ * @param str specified string
+ * @param frc FontRenderContext object
+ * @param fnt Font object
+ */
+ public CommonGlyphVector(String str, FontRenderContext frc, Font fnt) {
+ this(str.toCharArray(), frc, fnt, 0);
+ }
+
+ /**
+ * Creates new CommonGlyphVector object from the specified parameters.
+ *
+ * @param str specified string
+ * @param frc FontRenderContext object
+ * @param fnt Font object
+ * @param flags layout flags
+ */
+ public CommonGlyphVector(String str, FontRenderContext frc, Font fnt, int flags) {
+ this(str.toCharArray(), frc, fnt, flags);
+ }
+
+ /**
+ * Set array of logical positions of the glyphs to
+ * default with their default advances and height.
+ */
+ void setDefaultPositions(){
+ int len = getNumGlyphs();
+
+ // First [x,y] is set into [0,0] position
+ // for this reason start index is 1
+ for (int i=1; i <= len; i++ ){
+ int idx = i << 1;
+ float advanceX = vector[i-1].getGlyphPointMetrics().getAdvanceX();
+ float advanceY = vector[i-1].getGlyphPointMetrics().getAdvanceY();
+
+ defaultPositions[idx] = defaultPositions[idx-2] + advanceX;
+ defaultPositions[idx+1] = defaultPositions[idx-1] + advanceY;
+
+ }
+ transform.transform(defaultPositions, 0, logicalPositions, 0, getNumGlyphs()+1);
+
+ }
+
+ /**
+ * Returnes the pixel bounds of this GlyphVector rendered at the
+ * specified x,y location with the given FontRenderContext.
+ *
+ * @param frc a FontRenderContext that is used
+ * @param x specified x coordinate value
+ * @param y specified y coordinate value
+ * @return a Rectangle that bounds pixels of this GlyphVector
+ */
+ @Override
+ public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) {
+
+ double xM, yM, xm, ym;
+
+ double minX = 0;
+ double minY = 0;
+ double maxX = 0;
+ double maxY = 0;
+
+ for (int i = 0; i < this.getNumGlyphs(); i++) {
+ Rectangle glyphBounds = this.getGlyphPixelBounds(i, frc, 0, 0);
+ xm = glyphBounds.getMinX();
+ ym = glyphBounds.getMinY();
+ xM = glyphBounds.getMaxX();
+ yM = glyphBounds.getMaxY();
+
+ if (i == 0) {
+ minX = xm;
+ minY = ym;
+ maxX = xM;
+ maxY = yM;
+ }
+
+ if (minX > xm) {
+ minX = xm;
+ }
+ if (minY > ym) {
+ minY = ym;
+ }
+ if (maxX < xM) {
+ maxX = xM;
+ }
+ if (maxY < yM) {
+ maxY = yM;
+ }
+ }
+ return new Rectangle((int)(minX + x), (int)(minY + y), (int)(maxX - minX), (int)(maxY - minY));
+
+ }
+
+ /**
+ * Returns the visual bounds of this GlyphVector.
+ * The visual bounds is the bounds of the total outline of
+ * this GlyphVector.
+ * @return a Rectangle2D that id the visual bounds of this GlyphVector
+ */
+ @Override
+ public Rectangle2D getVisualBounds() {
+ float xM, yM, xm, ym;
+ float minX = 0;
+ float minY = 0;
+ float maxX = 0;
+ float maxY = 0;
+ boolean firstIteration = true;
+
+ for (int i = 0; i < this.getNumGlyphs(); i++) {
+ Rectangle2D bounds = this.getGlyphVisualBounds(i).getBounds2D();
+ if (bounds.getWidth() == 0){
+ continue;
+ }
+ xm = (float)bounds.getX();
+ ym = (float)bounds.getY();
+
+ xM = (float)(xm + bounds.getWidth());
+
+ yM = ym + (float) bounds.getHeight();
+
+ if (firstIteration) {
+ minX = xm;
+ minY = ym;
+ maxX = xM;
+ maxY = yM;
+ firstIteration = false;
+ } else {
+ if (minX > xm) {
+ minX = xm;
+ }
+ if (minY > ym) {
+ minY = ym;
+ }
+ if (maxX < xM) {
+ maxX = xM;
+ }
+ if (maxY < yM) {
+ maxY = yM;
+ }
+
+ }
+ }
+
+ return (this.getNumGlyphs() != 0) ? new Rectangle2D.Float(minX, minY,
+ (maxX - minX), (maxY - minY)) : null;
+ }
+
+ /**
+ * Sets new position to the specified glyph.
+ */
+ @Override
+ public void setGlyphPosition(int glyphIndex, Point2D newPos) {
+ if ((glyphIndex > vector.length) || (glyphIndex < 0)) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ float x = (float)newPos.getX();
+ float y = (float)newPos.getY();
+ int index = glyphIndex << 1;
+
+ if ((x != visualPositions[index]) || (y != visualPositions[index + 1])){
+ visualPositions[index] = x;
+ visualPositions[index+1] = y;
+ layoutFlags = layoutFlags | FLAG_HAS_POSITION_ADJUSTMENTS;
+ }
+
+ }
+
+ /**
+ * Returns the position of the specified glyph relative to the origin of
+ * this GlyphVector
+ * @return a Point2D that the origin of the glyph with specified index
+ */
+ @Override
+ public Point2D getGlyphPosition(int glyphIndex) {
+ if ((glyphIndex > vector.length) || (glyphIndex < 0)) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ int index = glyphIndex << 1;
+ Point2D pos = new Point2D.Float(visualPositions[index], visualPositions[index+1]);
+
+ // For last position we don't have to transform !!
+ if(glyphIndex==vector.length){
+ return pos;
+ }
+
+ AffineTransform at = getGlyphTransform(glyphIndex);
+ if ((at == null) || (at.isIdentity())){
+ return pos;
+ }
+
+ pos.setLocation(pos.getX() + at.getTranslateX(), pos.getY() + at.getTranslateY());
+
+ return pos;
+ }
+
+ /**
+ * Sets new transform to the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ * @param trans AffineTransform of the glyph with specified index
+ */
+ @Override
+ public void setGlyphTransform(int glyphIndex, AffineTransform trans) {
+ if ((glyphIndex >= vector.length) || (glyphIndex < 0)) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+
+ if ((trans == null) || (trans.isIdentity())) {
+ glsTransforms[glyphIndex] = null;
+ } else {
+ glsTransforms[glyphIndex] = new AffineTransform(trans);
+ layoutFlags = layoutFlags | FLAG_HAS_TRANSFORMS;
+ }
+ }
+
+ /**
+ * Returns the affine transform of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ * @return an AffineTransform of the glyph with specified index
+ */
+ @Override
+ public AffineTransform getGlyphTransform(int glyphIndex) {
+ if ((glyphIndex >= this.vector.length) || (glyphIndex < 0)) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ return this.glsTransforms[glyphIndex];
+ }
+
+ /**
+ * Returns the metrics of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ @Override
+ public GlyphMetrics getGlyphMetrics(int glyphIndex) {
+
+ if ((glyphIndex < 0) || ((glyphIndex) >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ // TODO: is there a sence in GlyphMetrics
+ // if certain glyph or Font has a transform??
+ return this.vector[glyphIndex].getGlyphMetrics();
+ }
+
+ /**
+ * Returns a justification information for the glyph with specified glyph
+ * index.
+ * @param glyphIndex index of a glyph which GlyphJustificationInfo is to be
+ * received
+ * @return a GlyphJustificationInfo object that contains glyph justification
+ * properties of the specified glyph
+ */
+ @Override
+ public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) {
+ // TODO : Find out the source of Justification info
+ if (true) {
+ throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Returns the FontRenderContext parameter of this GlyphVector.
+ */
+ @Override
+ public FontRenderContext getFontRenderContext() {
+ return this.vectorFRC;
+ }
+
+ /**
+ * Returns the visual bounds of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ @Override
+ public Shape getGlyphVisualBounds(int glyphIndex) {
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+
+ int idx = glyphIndex << 1;
+
+ AffineTransform fontTransform = this.transform;
+ double xOffs = fontTransform.getTranslateX();
+ double yOffs = fontTransform.getTranslateY();
+
+ if (vector[glyphIndex].getWidth() == 0){
+ return new Rectangle2D.Float((float)xOffs, (float)yOffs, 0, 0);
+ }
+
+ AffineTransform at = AffineTransform.getTranslateInstance(xOffs, yOffs);
+ AffineTransform glyphTransform = getGlyphTransform(glyphIndex);
+
+ if (transform.isIdentity() && ((glyphTransform == null) || glyphTransform.isIdentity())){
+ Rectangle2D blackBox = vector[glyphIndex].getGlyphMetrics().getBounds2D();
+ at.translate(visualPositions[idx], visualPositions[idx+1]);
+ return(at.createTransformedShape(blackBox));
+ }
+
+ GeneralPath shape = (GeneralPath)this.getGlyphOutline(glyphIndex);
+ shape.transform(at);
+ return shape.getBounds2D();
+ }
+
+ /**
+ * Returnes the pixel bounds of the specified glyph within GlyphVector
+ * rendered at the specified x,y location.
+ *
+ * @param glyphIndex index of the glyph
+ * @param frc a FontRenderContext that is used
+ * @param x specified x coordinate value
+ * @param y specified y coordinate value
+ * @return a Rectangle that bounds pixels of the specified glyph
+ */
+ @Override
+ public Rectangle getGlyphPixelBounds(int glyphIndex, FontRenderContext frc,
+ float x, float y) {
+ // TODO : need to be implemented with FontRenderContext
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+
+ int idx = glyphIndex << 1;
+
+ if (vector[glyphIndex].getWidth() == 0){
+ AffineTransform fontTransform = this.transform;
+ double xOffs = x + visualPositions[idx] + fontTransform.getTranslateX();
+ double yOffs = y + visualPositions[idx+1] + fontTransform.getTranslateY();
+ return new Rectangle((int)xOffs, (int)yOffs, 0, 0);
+ }
+
+ GeneralPath shape = (GeneralPath)this.getGlyphOutline(glyphIndex);
+
+ AffineTransform at = AffineTransform.getTranslateInstance(x, y);
+
+ if (frc != null){
+ at.concatenate(frc.getTransform());
+ }
+
+ shape.transform(at);
+
+ Rectangle bounds = shape.getBounds();
+ return new Rectangle((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth()-1, (int)bounds.getHeight()-1);
+ }
+
+ /**
+ * Returns a Shape that encloses specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ @Override
+ public Shape getGlyphOutline(int glyphIndex) {
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+
+ if (gvShapes[glyphIndex] == null) {
+ gvShapes[glyphIndex] = vector[glyphIndex].getShape();
+ }
+
+ GeneralPath gp = (GeneralPath)((GeneralPath)gvShapes[glyphIndex]).clone();
+
+ /* Applying GlyphVector font transform */
+ AffineTransform at = (AffineTransform)this.transform.clone();
+
+ /* Applying Glyph transform */
+ AffineTransform glyphAT = getGlyphTransform(glyphIndex);
+ if (glyphAT != null){
+ at.preConcatenate(glyphAT);
+ }
+
+ int idx = glyphIndex << 1;
+
+ gp.transform(at);
+ gp.transform(AffineTransform.getTranslateInstance(visualPositions[idx], visualPositions[idx+1]));
+ return gp;
+ }
+
+
+ /**
+ * Returns a Shape that is the outline representation of this GlyphVector
+ * rendered at the specified x,y coordinates.
+ *
+ * @param x specified x coordinate value
+ * @param y specified y coordinate value
+ * @return a Shape object that is the outline of this GlyphVector
+ * at the specified coordinates.
+ */
+ @Override
+ public Shape getOutline(float x, float y) {
+ GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
+ for (int i = 0; i < this.vector.length; i++) {
+ GeneralPath outline = (GeneralPath)getGlyphOutline(i);
+
+ /* Applying translation to actual visual bounds */
+ outline.transform(AffineTransform.getTranslateInstance(x, y));
+ gp.append(outline, false);
+ }
+
+ return gp;
+ }
+
+ /**
+ * Returns a Shape that is the outline representation of this GlyphVector.
+ *
+ * @return a Shape object that is the outline of this GlyphVector
+ */
+ @Override
+ public Shape getOutline() {
+ return this.getOutline(0, 0);
+ }
+
+ /**
+ * Returns an array of glyphcodes for the specified glyphs.
+ *
+ * @param beginGlyphIndex the start index
+ * @param numEntries the number of glyph codes to get
+ * @param codeReturn the array that receives glyph codes' values
+ * @return an array that receives glyph codes' values
+ */
+ @Override
+ public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
+ int[] codeReturn) {
+
+ if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > this.getNumGlyphs())) {
+ // awt.44=beginGlyphIndex is out of vector's range
+ throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$
+ }
+
+ if (numEntries < 0) {
+ // awt.45=numEntries is out of vector's range
+ throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+ }
+
+ if (codeReturn == null) {
+ codeReturn = new int[numEntries];
+ }
+
+ for (int i = beginGlyphIndex; i < beginGlyphIndex + numEntries; i++) {
+ codeReturn[i-beginGlyphIndex] = this.vector[i].getGlyphCode();
+ }
+
+ return codeReturn;
+ }
+
+ /**
+ * Returns an array of numEntries character indices for the specified glyphs.
+ *
+ * @param beginGlyphIndex the start index
+ * @param numEntries the number of glyph codes to get
+ * @param codeReturn the array that receives glyph codes' values
+ * @return an array that receives glyph char indices
+ */
+ @Override
+ public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries,
+ int[] codeReturn) {
+ if ((beginGlyphIndex < 0) || (beginGlyphIndex >= this.getNumGlyphs())) {
+ // awt.44=beginGlyphIndex is out of vector's range
+ throw new IllegalArgumentException(Messages.getString("awt.44")); //$NON-NLS-1$
+ }
+
+ if ((numEntries < 0)
+ || ((numEntries + beginGlyphIndex) > this.getNumGlyphs())) {
+ // awt.45=numEntries is out of vector's range
+ throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+ }
+
+ if (codeReturn == null) {
+ codeReturn = new int[numEntries];
+ }
+
+ for (int i = 0; i < numEntries; i++) {
+ codeReturn[i] = this.getGlyphCharIndex(i + beginGlyphIndex);
+ }
+ return codeReturn;
+ }
+
+ /**
+ * Returns an array of numEntries glyphs positions from beginGlyphIndex
+ * glyph in Glyph Vector.
+ *
+ * @param beginGlyphIndex the start index
+ * @param numEntries the number of glyph codes to get
+ * @param positionReturn the array that receives glyphs' positions
+ * @return an array of floats that receives glyph char indices
+ */
+ @Override
+ public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
+ float[] positionReturn) {
+
+ int len = (this.getNumGlyphs()+1) << 1;
+ beginGlyphIndex *= 2;
+ numEntries *= 2;
+
+ if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > len)) {
+ // awt.44=beginGlyphIndex is out of vector's range
+ throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$
+ }
+
+ if (numEntries < 0) {
+ // awt.45=numEntries is out of vector's range
+ throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+ }
+
+ if (positionReturn == null) {
+ positionReturn = new float[numEntries];
+ }
+
+ System.arraycopy(visualPositions, beginGlyphIndex, positionReturn, 0, numEntries);
+
+ return positionReturn;
+ }
+
+ /**
+ * Set numEntries elements of the visualPositions array from beginGlyphIndex
+ * of numEntries glyphs positions from beginGlyphIndex glyph in Glyph Vector.
+ *
+ * @param beginGlyphIndex the start index
+ * @param numEntries the number of glyph codes to get
+ * @param setPositions the array of positions to set
+ */
+ public void setGlyphPositions(int beginGlyphIndex, int numEntries,
+ float[] setPositions) {
+
+ int len = (this.getNumGlyphs()+1) << 1;
+ beginGlyphIndex *= 2;
+ numEntries *= 2;
+
+ if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > len)) {
+ // awt.44=beginGlyphIndex is out of vector's range
+ throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$
+ }
+
+ if (numEntries < 0) {
+ // awt.45=numEntries is out of vector's range
+ throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$
+ }
+
+ System.arraycopy(setPositions, 0, visualPositions, beginGlyphIndex, numEntries);
+ layoutFlags = layoutFlags & FLAG_HAS_POSITION_ADJUSTMENTS;
+
+ }
+
+ /**
+ * Set elements of the visualPositions array.
+ *
+ * @param setPositions the array of positions to set
+ */
+ public void setGlyphPositions(float[] setPositions) {
+
+ int len = (this.getNumGlyphs()+1) << 1;
+ if (len != setPositions.length){
+ // awt.46=length of setPositions array differs from the length of positions array
+ throw new IllegalArgumentException(Messages.getString("awt.46")); //$NON-NLS-1$
+ }
+
+ System.arraycopy(setPositions, 0, visualPositions, 0, len);
+ layoutFlags = layoutFlags & FLAG_HAS_POSITION_ADJUSTMENTS;
+
+ }
+
+
+ /**
+ * Returns glyph code of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ @Override
+ public int getGlyphCode(int glyphIndex) {
+ if (glyphIndex >= this.vector.length || glyphIndex < 0) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ return this.vector[glyphIndex].getGlyphCode();
+ }
+
+ /**
+ * Returns character index of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ @Override
+ public int getGlyphCharIndex(int glyphIndex) {
+
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IllegalArgumentException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+
+ if ((this.layoutFlags & Font.LAYOUT_RIGHT_TO_LEFT) != 0) {
+ return this.charVector.length - glyphIndex - 1;
+ }
+
+ return glyphIndex;
+ }
+
+ /**
+ * Returns a character value of the specified glyph.
+ *
+ * @param glyphIndex specified index of the glyph
+ */
+ public char getGlyphChar(int glyphIndex) {
+
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) {
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IllegalArgumentException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ return this.charVector[glyphIndex];
+ }
+
+ /**
+ * Assigns default positions to each glyph in this GlyphVector.
+ */
+ @Override
+ public void performDefaultLayout() {
+
+ System.arraycopy(logicalPositions, 0, visualPositions, 0, logicalPositions.length);
+
+ // Set position changes flag to zero
+ clearLayoutFlags(GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS);
+ }
+
+ /**
+ * Returns the number of glyphs in this Glyph Vector
+ */
+ @Override
+ public int getNumGlyphs() {
+ return vector.length;
+ }
+
+ /**
+ * Returns the logical bounds of this GlyphVector
+ */
+ @Override
+ public Rectangle2D getLogicalBounds(){
+ // XXX: for transforms where an angle between basis vectors is not 90 degrees
+ // Rectanlge2D class doesn't fit as Logical bounds. For this reason we use
+ // only non-transformed bounds!!
+
+ float x = visualPositions[0];
+ float width = visualPositions[visualPositions.length-2];
+
+ double scaleY = transform.getScaleY();
+
+ Rectangle2D bounds = new Rectangle2D.Float(x, (float)((-this.ascent-this.leading)*scaleY), width, (float)(this.height*scaleY));
+ return bounds;
+ }
+
+
+ /**
+ * Checks whether given GlyphVector equals to this GlyphVector.
+ * @param glyphVector GlyphVector object to compare
+ */
+ @Override
+ public boolean equals(GlyphVector glyphVector){
+ if (glyphVector == this){
+ return true;
+ }
+
+ if (glyphVector != null) {
+
+ if (!(glyphVector.getFontRenderContext().equals(this.vectorFRC) &&
+ glyphVector.getFont().equals(this.font))){
+ return false;
+ }
+
+ try {
+ boolean eq = true;
+ for (int i = 0; i < getNumGlyphs(); i++) {
+
+ int idx = i*2;
+ eq = (((CommonGlyphVector)glyphVector).visualPositions[idx] == this.visualPositions[idx]) &&
+ (((CommonGlyphVector)glyphVector).visualPositions[idx+1] == this.visualPositions[idx+1]) &&
+ (glyphVector.getGlyphCharIndex(i) == this.getGlyphCharIndex(i));
+
+ if (eq){
+ AffineTransform trans = glyphVector.getGlyphTransform(i);
+ if (trans == null){
+ eq = (this.glsTransforms[i] == null);
+ }else{
+ eq = this.glsTransforms[i].equals(trans);
+ }
+ }
+
+ if (!eq){
+ return false;
+ }
+ }
+
+ return eq;
+ } catch (ClassCastException e) {
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns flags describing the state of the GlyphVector.
+ */
+ @Override
+ public int getLayoutFlags() {
+ return layoutFlags;
+ }
+
+ /**
+ * Returns char with the specified index.
+ *
+ * @param index specified index of the char
+ *
+ */
+ public char getChar(int index) {
+ return this.charVector[index];
+
+ }
+
+ /**
+ * Clear desired flags in layout flags describing the state.
+ *
+ * @param clearFlags flags mask to clear
+ */
+
+ private void clearLayoutFlags(int clearFlags){
+ layoutFlags &= ~clearFlags;
+ }
+
+ /**
+ * Returns the logical bounds of the specified glyph within this CommonGlyphVector.
+ *
+ * @param glyphIndex index of the glyph to get it's logical bounds
+ * @return logical bounds of the specified glyph
+ */
+ @Override
+ public Shape getGlyphLogicalBounds(int glyphIndex){
+ if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())){
+ // awt.43=glyphIndex is out of vector's limits
+ throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$
+ }
+ Glyph glyph = this.vector[glyphIndex];
+
+ float x0 = visualPositions[glyphIndex*2];
+ float y0 = visualPositions[glyphIndex*2+1];
+ float advanceX = glyph.getGlyphPointMetrics().getAdvanceX();
+
+ GeneralPath gp = new GeneralPath();
+ gp.moveTo(0, -ascent - leading);
+ gp.lineTo(advanceX ,-ascent - leading);
+ gp.lineTo(advanceX, descent);
+ gp.lineTo(0, descent);
+ gp.lineTo(0, -ascent - leading);
+ gp.closePath();
+
+ /* Applying GlyphVector font transform */
+ AffineTransform at = (AffineTransform)this.transform.clone();
+
+ /* Applying Glyph transform */
+ AffineTransform glyphTransform = getGlyphTransform(glyphIndex);
+ if (glyphTransform != null){
+ at.concatenate(glyphTransform);
+ }
+
+ /* Applying translation to actual visual bounds */
+ at.preConcatenate(AffineTransform.getTranslateInstance(x0, y0));
+ gp.transform(at);
+ return gp;
+ }
+
+ /**
+ * Returns the Font parameter of this GlyphVector
+ */
+ @Override
+ public Font getFont(){
+ return this.font;
+ }
+
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/font/CompositeFont.java b/awt/org/apache/harmony/awt/gl/font/CompositeFont.java
new file mode 100644
index 0000000..70cb334
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/CompositeFont.java
@@ -0,0 +1,486 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.FontProperty;
+
+/**
+ * CompositeFont class is the implementation of logical font classes.
+ * Every logical font consists of several physical fonts that described
+ * in font.properties file according to the face name of this logical font.
+ */
+public class CompositeFont extends FontPeerImpl{
+
+ // a number of physical fonts that CompositeFont consist of
+ int numFonts;
+
+ // font family name
+ String family;
+
+ // font face name
+ String face;
+
+ String[] fontNames;
+
+ // an array of font properties applicable to this CompositeFont
+ FontProperty[] fontProperties;
+
+ // an array of font peers applicable to this CompositeFont
+ public FontPeerImpl[] fPhysicalFonts;
+
+ // missing glyph code field
+ int missingGlyphCode = -1;
+
+ // line metrics of this font
+ LineMetricsImpl nlm = null;
+
+ // cached num glyphs parameter of this font that is the sum of num glyphs of
+ // font peers composing this font
+ int cachedNumGlyphs = -1;
+ /**
+ * Creates CompositeFont object that is corresponding to the specified logical
+ * family name.
+ *
+ * @param familyName logical family name CompositeFont is to be created from
+ * @param faceName logical face name CompositeFont is to be created from
+ * @param _style style of the CompositeFont to be created
+ * @param _size size of the CompositeFont to be created
+ * @param fProperties an array of FontProperties describing physical fonts -
+ * parts of logical font
+ * @param physFonts an array of physical font peers related to the CompositeFont
+ * to be created
+ */
+ public CompositeFont(String familyName, String faceName, int _style, int _size, FontProperty[] fProperties, FontPeerImpl[] physFonts){
+ this.size = _size;
+ this.name = faceName;
+ this.family = familyName;
+ this.style = _style;
+ this.face = faceName;
+ this.psName = faceName;
+ this.fontProperties = fProperties;// !! Supposed that fProperties parameter != null
+ fPhysicalFonts = physFonts;
+ numFonts = fPhysicalFonts.length;
+ setDefaultLineMetrics("", null); //$NON-NLS-1$
+ this.uniformLM = false;
+ }
+
+ /**
+ * Returns the index of the FontPeer in array of physical fonts that is applicable
+ * for the given character. This font has to have the highest priority among fonts
+ * that can display this character and don't have exclusion range covering
+ * specified character. If there is no desired fonts -1 is returned.
+ *
+ * @param chr specified character
+ * @return index of the font from the array of physical fonts that will be used
+ * during processing of the specified character.
+ */
+ public int getCharFontIndex(char chr){
+ for (int i = 0; i < numFonts; i++){
+ if (fontProperties[i].isCharExcluded(chr)){
+ continue;
+ }
+ if (fPhysicalFonts[i].canDisplay(chr)){
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Returns the index of the FontPeer in array of physical fonts that is applicable
+ * for the given character. This font has to have the highest priority among fonts
+ * that can display this character and don't have exclusion range covering
+ * specified character. If there is no desired fonts default value is returned.
+ *
+ * @param chr specified character
+ * @param defaultValue default index that is returned if the necessary font couldn't be found.
+ * @return index of the font from the array of physical fonts that will be used
+ * during processing of the specified character.
+ */
+ public int getCharFontIndex(char chr, int defaultValue){
+ for (int i = 0; i < numFonts; i++){
+ if (fontProperties[i].isCharExcluded(chr)){
+ continue;
+ }
+ if (fPhysicalFonts[i].canDisplay(chr)){
+ return i;
+ }
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns true if one of the physical fonts composing this font CompositeFont
+ * can display specified character.
+ *
+ * @param chr specified character
+ */
+ @Override
+ public boolean canDisplay(char chr){
+ return (getCharFontIndex(chr) != -1);
+ }
+
+ /**
+ * Returns logical ascent (in pixels)
+ */
+ @Override
+ public int getAscent(){
+ return nlm.getLogicalAscent();
+ }
+
+ /**
+ * Returns LineMetrics instance scaled according to the specified transform.
+ *
+ * @param str specified String
+ * @param frc specified FontRenderContext
+ * @param at specified AffineTransform
+ */
+ @Override
+ public LineMetrics getLineMetrics(String str, FontRenderContext frc , AffineTransform at){
+ LineMetricsImpl lm = (LineMetricsImpl)(this.nlm.clone());
+ lm.setNumChars(str.length());
+
+ if ((at != null) && (!at.isIdentity())){
+ lm.scale((float)at.getScaleX(), (float)at.getScaleY());
+ }
+
+ return lm;
+ }
+
+ /**
+ * Returns cached LineMetrics instance for the null string or creates it if
+ * it wasn't cached yet.
+ */
+ @Override
+ public LineMetrics getLineMetrics(){
+ if (nlm == null){
+ setDefaultLineMetrics("", null); //$NON-NLS-1$
+ }
+
+ return this.nlm;
+ }
+
+ /**
+ * Creates LineMetrics instance and set cached LineMetrics field to it.
+ * Created LineMetrics has maximum values of the idividual metrics of all
+ * composing physical fonts. If there is only one physical font - it's
+ * LineMetrics object is returned.
+ *
+ * @param str specified String
+ * @param frc specified FontRenderContext
+ */
+ private void setDefaultLineMetrics(String str, FontRenderContext frc){
+ LineMetrics lm = fPhysicalFonts[0].getLineMetrics(str, frc, null);
+ float maxCharWidth = (float)fPhysicalFonts[0].getMaxCharBounds(frc).getWidth();
+
+ if (numFonts == 1) {
+ this.nlm = (LineMetricsImpl)lm;
+ return;
+ }
+
+ float[] baselineOffsets = lm.getBaselineOffsets();
+ int numChars = str.length();
+
+ // XXX: default value - common for all Fonts
+ int baseLineIndex = lm.getBaselineIndex();
+
+ float maxUnderlineThickness = lm.getUnderlineThickness();
+ float maxUnderlineOffset = lm.getUnderlineOffset();
+ float maxStrikethroughThickness = lm.getStrikethroughThickness();
+ float minStrikethroughOffset = lm.getStrikethroughOffset();
+ float maxLeading = lm.getLeading(); // External leading
+ float maxHeight = lm.getHeight(); // Height of the font ( == (ascent + descent + leading))
+ float maxAscent = lm.getAscent(); // Ascent of the font
+ float maxDescent = lm.getDescent(); // Descent of the font
+
+ for (int i = 1; i < numFonts; i++){
+ lm = fPhysicalFonts[i].getLineMetrics(str, frc, null);
+ if (maxUnderlineThickness < lm.getUnderlineThickness()){
+ maxUnderlineThickness = lm.getUnderlineThickness();
+ }
+
+ if (maxUnderlineOffset < lm.getUnderlineOffset()){
+ maxUnderlineOffset = lm.getUnderlineOffset();
+ }
+
+ if (maxStrikethroughThickness < lm.getStrikethroughThickness()){
+ maxStrikethroughThickness = lm.getStrikethroughThickness();
+ }
+
+ if (minStrikethroughOffset > lm.getStrikethroughOffset()){
+ minStrikethroughOffset = lm.getStrikethroughOffset();
+ }
+
+ if (maxLeading < lm.getLeading()){
+ maxLeading = lm.getLeading();
+ }
+
+ if (maxAscent < lm.getAscent()){
+ maxAscent = lm.getAscent();
+ }
+
+ if (maxDescent < lm.getDescent()){
+ maxDescent = lm.getDescent();
+ }
+
+ float width = (float)fPhysicalFonts[i].getMaxCharBounds(frc).getWidth();
+ if(maxCharWidth < width){
+ maxCharWidth = width;
+ }
+ for (int j =0; j < baselineOffsets.length; j++){
+ float[] offsets = lm.getBaselineOffsets();
+ if (baselineOffsets[j] > offsets[j]){
+ baselineOffsets[j] = offsets[j];
+ }
+ }
+
+ }
+ maxHeight = maxAscent + maxDescent + maxLeading;
+
+ this.nlm = new LineMetricsImpl(
+ numChars,
+ baseLineIndex,
+ baselineOffsets,
+ maxUnderlineThickness,
+ maxUnderlineOffset,
+ maxStrikethroughThickness,
+ minStrikethroughOffset,
+ maxLeading,
+ maxHeight,
+ maxAscent,
+ maxDescent,
+ maxCharWidth);
+
+ }
+
+ /**
+ * Returns the number of glyphs in this CompositeFont object.
+ */
+ @Override
+ public int getNumGlyphs(){
+ if (this.cachedNumGlyphs == -1){
+
+ this.cachedNumGlyphs = 0;
+
+ for (int i = 0; i < numFonts; i++){
+ this.cachedNumGlyphs += fPhysicalFonts[i].getNumGlyphs();
+ }
+ }
+
+ return this.cachedNumGlyphs;
+ }
+
+ /**
+ * Returns the italic angle of this object.
+ */
+ @Override
+ public float getItalicAngle(){
+ // !! only first physical font used to get this value
+ return fPhysicalFonts[0].getItalicAngle();
+ }
+
+ /**
+ * Returns rectangle that bounds the specified string in terms of composite line metrics.
+ *
+ * @param chars an array of chars
+ * @param start the initial offset in array of chars
+ * @param end the end offset in array of chars
+ * @param frc specified FontRenderContext
+ */
+ public Rectangle2D getStringBounds(char[] chars, int start, int end, FontRenderContext frc){
+
+ LineMetrics lm = getLineMetrics();
+ float minY = -lm.getAscent();
+ float minX = 0;
+ float height = lm.getHeight();
+ float width = 0;
+
+ for (int i = start; i < end; i++){
+ width += charWidth(chars[i]);
+ }
+
+ Rectangle2D rect2D = new Rectangle2D.Float(minX, minY, width, height);
+ return rect2D;
+
+ }
+
+ /**
+ * Returns maximum rectangle that encloses all maximum char bounds of
+ * physical fonts composing this CompositeFont.
+ *
+ * @param frc specified FontRenderContext
+ */
+ @Override
+ public Rectangle2D getMaxCharBounds(FontRenderContext frc){
+
+ Rectangle2D rect2D = fPhysicalFonts[0].getMaxCharBounds(frc);
+ float minY = (float)rect2D.getY();
+ float maxWidth = (float)rect2D.getWidth();
+ float maxHeight = (float)rect2D.getHeight();
+ if (numFonts == 1){
+ return rect2D;
+ }
+
+ for (int i = 1; i < numFonts; i++){
+ if (fPhysicalFonts[i] != null){
+ rect2D = fPhysicalFonts[i].getMaxCharBounds(frc);
+ float y = (float)rect2D.getY();
+ float mWidth = (float)rect2D.getWidth();
+ float mHeight = (float)rect2D.getHeight();
+ if (y < minY){
+ minY = y;
+ }
+ if (mWidth > maxWidth){
+ maxHeight = mWidth;
+ }
+
+ if (mHeight > maxHeight){
+ maxHeight = mHeight;
+ }
+ }
+ }
+
+ rect2D = new Rectangle2D.Float(0, minY, maxWidth, maxHeight);
+
+ return rect2D;
+ }
+
+ /**
+ * Returns font name.
+ */
+ @Override
+ public String getFontName(){
+ return face;
+ }
+
+ /**
+ * Returns font postscript name.
+ */
+ @Override
+ public String getPSName(){
+ return psName;
+ }
+
+ /**
+ * Returns font family name.
+ */
+ @Override
+ public String getFamily(){
+ return family;
+ }
+
+ /**
+ * Returns the code of the missing glyph.
+ */
+ @Override
+ public int getMissingGlyphCode(){
+ // !! only first physical font used to get this value
+ return fPhysicalFonts[0].getMissingGlyphCode();
+ }
+
+ /**
+ * Returns Glyph object corresponding to the specified character.
+ *
+ * @param ch specified char
+ */
+ @Override
+ public Glyph getGlyph(char ch){
+ for (int i = 0; i < numFonts; i++){
+ if (fontProperties[i].isCharExcluded(ch)){
+ continue;
+ }
+
+ /* Control symbols considered to be supported by the font peer */
+ if ((ch < 0x20) || fPhysicalFonts[i].canDisplay(ch)){
+ return fPhysicalFonts[i].getGlyph(ch);
+ }
+ }
+ return getDefaultGlyph();
+ }
+
+ /**
+ * Returns width of the char with specified index.
+ *
+ * @param ind specified index of the character
+ */
+ @Override
+ public int charWidth(int ind){
+ return charWidth((char)ind);
+ }
+
+ /**
+ * Returns width of the specified char.
+ *
+ * @param c specified character
+ */
+ @Override
+ public int charWidth(char c){
+ Glyph gl = this.getGlyph(c);
+ return (int)gl.getGlyphPointMetrics().getAdvanceX();
+ }
+
+ /**
+ * Returns debug information about this class.
+ */
+ @Override
+ public String toString(){
+ return new String(this.getClass().getName() +
+ "[name=" + this.name + //$NON-NLS-1$
+ ",style="+ this.style + //$NON-NLS-1$
+ ",fps=" + this.fontProperties + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Returns Glyph object corresponding to the default glyph.
+ */
+ @Override
+ public Glyph getDefaultGlyph(){
+ // !! only first physical font used to get this value
+ return fPhysicalFonts[0].getDefaultGlyph();
+ }
+
+ /**
+ * Returns FontExtraMetrics object with extra metrics
+ * related to this CompositeFont.
+ */
+ @Override
+ public FontExtraMetrics getExtraMetrics(){
+ // Returns FontExtraMetrics instanse of the first physical
+ // Font from the array of fonts.
+ return fPhysicalFonts[0].getExtraMetrics();
+ }
+
+ /**
+ * Disposes CompositeFont object's resources.
+ */
+ @Override
+ public void dispose() {
+ // Nothing to dispose
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java b/awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java
new file mode 100644
index 0000000..047ba6d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontExtraMetrics.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ *
+ */
+package org.apache.harmony.awt.gl.font;
+
+/**
+ * Extra font metrics: sub/superscripts sizes, offsets, average char width.
+ */
+public class FontExtraMetrics {
+
+ /* !! Subscript/superscript metrics are undefined for Type1. As a possible
+ * solution we can use values for Type1, that are proportionate to TrueType
+ * ones:
+ * SubscriptSizeX == 0.7 * fontSize
+ * SubscriptSizeY == 0.65 * fontSize
+ * SubscriptOffsetX == 0;
+ * SubscriptOffsetY == 0.15 * fontSize;
+ * SuperscriptSizeX == 0.7 * fontSize
+ * SuperscriptSizeY == 0.65 * fontSize
+ * SuperscriptOffsetX == 0;
+ * SuperscriptOffsetY == 0.45 * fontSize
+ *
+ */
+
+ /*
+ * The average width of characters in the font.
+ */
+ private float lAverageCharWidth;
+
+ /*
+ * Horizontal size for subscripts.
+ */
+ private float lSubscriptSizeX;
+
+ /*
+ * Vertical size for subscripts.
+ */
+ private float lSubscriptSizeY;
+
+ /*
+ * Horizontal offset for subscripts, the offset from the character origin
+ * to the origin of the subscript character.
+ */
+ private float lSubscriptOffsetX;
+
+ /*
+ * Vertical offset for subscripts, the offset from the character origin
+ * to the origin of the subscript character.
+ */
+ private float lSubscriptOffsetY;
+
+ /*
+ * Horizontal size for superscripts.
+ */
+ private float lSuperscriptSizeX;
+
+ /*
+ * Vertical size for superscripts.
+ */
+ private float lSuperscriptSizeY;
+
+ /*
+ * Horizontal offset for superscripts, the offset from the character
+ * base line to the base line of the superscript character.
+ */
+ private float lSuperscriptOffsetX;
+
+ /*
+ * Vertical offset for superscripts, the offset from the character
+ * base line to the base line of the superscript character.
+ */
+ private float lSuperscriptOffsetY;
+
+ public FontExtraMetrics(){
+ // default constructor
+ }
+
+ public FontExtraMetrics(float[] metrics){
+ lAverageCharWidth = metrics[0];
+ lSubscriptSizeX = metrics[1];
+ lSubscriptSizeY = metrics[2];
+ lSubscriptOffsetX = metrics[3];
+ lSubscriptOffsetY = metrics[4];
+ lSuperscriptSizeX = metrics[5];
+ lSuperscriptSizeY = metrics[6];
+ lSuperscriptOffsetX = metrics[7];
+ lSuperscriptOffsetY = metrics[8];
+ }
+
+ public float getAverageCharWidth(){
+ return lAverageCharWidth;
+ }
+
+ public float getSubscriptSizeX(){
+ return lSubscriptSizeX;
+ }
+
+ public float getSubscriptSizeY(){
+ return lSubscriptSizeY;
+ }
+
+ public float getSubscriptOffsetX(){
+ return lSubscriptOffsetX;
+ }
+
+ public float getSubscriptOffsetY(){
+ return lSubscriptOffsetY;
+ }
+
+ public float getSuperscriptSizeX(){
+ return lSuperscriptSizeX;
+ }
+
+ public float getSuperscriptSizeY(){
+ return lSuperscriptSizeY;
+ }
+
+ public float getSuperscriptOffsetX(){
+ return lSuperscriptOffsetX;
+ }
+
+ public float getSuperscriptOffsetY(){
+ return lSuperscriptOffsetY;
+ }
+
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontFinder.java b/awt/org/apache/harmony/awt/gl/font/FontFinder.java
new file mode 100644
index 0000000..09bcf5c
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontFinder.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Jul 12, 2005
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.GraphicsEnvironment;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class chooses the default font for the given text.
+ * If it finds the character which current font is unable to display
+ * it starts the next font run and looks for the font which is able to
+ * display the current character. It also caches the font mappings
+ * (index in the array containing all fonts) for the characters,
+ * using that fact that scripts are mainly contiguous in the UTF-16 encoding
+ * and there's a high probability that the upper byte will be the same for the
+ * next character as for the previous. This allows to save the space used for the cache.
+ */
+public class FontFinder {
+ private static final float DEFAULT_FONT_SIZE = 12;
+
+ private static final Font fonts[] =
+ GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
+
+ private static final int NUM_BLOCKS = 256;
+ private static final int BLOCK_SIZE = 256;
+ private static final int INDEX_MASK = 0xFF;
+ private static final int BLOCK_SHIFT = 8;
+
+ // Maps characters into the fonts array
+ private static final int blocks[][] = new int[NUM_BLOCKS][];
+
+ /**
+ * Finds the font which is able to display the given character
+ * and saves the font mapping for this character
+ * @param c - character
+ * @return font
+ */
+ static Font findFontForChar(char c) {
+ int blockNum = c >> BLOCK_SHIFT;
+ int index = c & INDEX_MASK;
+
+ if (blocks[blockNum] == null) {
+ blocks[blockNum] = new int[BLOCK_SIZE];
+ }
+
+ if (blocks[blockNum][index] == 0) {
+ blocks[blockNum][index] = 1;
+
+ for (int i=0; i<fonts.length; i++) {
+ if (fonts[i].canDisplay(c)) {
+ blocks[blockNum][index] = i+1;
+ break;
+ }
+ }
+ }
+
+ return getDefaultSizeFont(blocks[blockNum][index]-1);
+ }
+
+ /**
+ * Derives the default size font
+ * @param i - index in the array of all fonts
+ * @return derived font
+ */
+ static Font getDefaultSizeFont(int i) {
+ if (fonts[i].getSize() != DEFAULT_FONT_SIZE) {
+ fonts[i] = fonts[i].deriveFont(DEFAULT_FONT_SIZE);
+ }
+
+ return fonts[i];
+ }
+
+ /**
+ * Assigns default fonts for the given text run.
+ * First three parameters are input, last three are output.
+ * @param text - given text
+ * @param runStart - start of the text run
+ * @param runLimit - end of the text run
+ * @param runStarts - starts of the resulting font runs
+ * @param fonts - mapping of the font run starts to the fonts
+ */
+ static void findFonts(char text[], int runStart, int runLimit, List<Integer> runStarts,
+ Map<Integer, Font> fonts) {
+ Font prevFont = null;
+ Font currFont;
+ for (int i = runStart; i < runLimit; i++) {
+ currFont = findFontForChar(text[i]);
+ if (currFont != prevFont) {
+ prevFont = currFont;
+ Integer idx = new Integer(i);
+ fonts.put(idx, currFont);
+ if (i != runStart) {
+ runStarts.add(idx);
+ }
+ }
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontManager.java b/awt/org/apache/harmony/awt/gl/font/FontManager.java
new file mode 100644
index 0000000..8354e25
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontManager.java
@@ -0,0 +1,819 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Font;
+import java.awt.peer.FontPeer;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
+import org.apache.harmony.luni.util.NotImplementedException;
+
+
+public abstract class FontManager {
+
+ //???AWT
+ boolean NOT_IMP = false;
+
+ /**
+ * array of font families names
+ */
+ public String[] allFamilies;
+
+ public static final String DEFAULT_NAME = "Default"; /* Default font name */ //$NON-NLS-1$
+ public static final String DIALOG_NAME = "Dialog"; /* Dialog font name */ //$NON-NLS-1$
+
+ /**
+ * Set of constants applicable to the TrueType 'name' table.
+ */
+ public static final byte FAMILY_NAME_ID = 1; /* Family name identifier */
+ public static final byte FONT_NAME_ID = 4; /* Full font name identifier */
+ public static final byte POSTSCRIPT_NAME_ID = 6; /* PostScript name identifier */
+ public static final short ENGLISH_LANGID = 0x0409; /* English (United States)language identifier */
+
+ /**
+ * Set of constants describing font type.
+ */
+ public static final byte FONT_TYPE_TT = 4; /* TrueType type (TRUETYPE_FONTTYPE) */
+ public static final byte FONT_TYPE_T1 = 2; /* Type1 type (DEVICE_FONTTYPE) */
+ public static final byte FONT_TYPE_UNDEF = 0; /* Undefined type */
+
+ // logical family types (indices in FontManager.LOGICAL_FONT_NAMES)
+ static final int DIALOG = 3; // FF_SWISS
+ static final int SANSSERIF = 1; // FF_SWISS
+ static final int DIALOGINPUT = 4; // FF_MODERN
+ static final int MONOSPACED = 2; // FF_MODERN
+ static final int SERIF = 0; // FF_ROMAN
+
+
+ /**
+ * FontProperty related constants.
+ */
+ public static final String PLATFORM_FONT_NAME = "PlatformFontName"; //$NON-NLS-1$
+ public static final String LOGICAL_FONT_NAME = "LogicalFontName"; //$NON-NLS-1$
+ public static final String COMPONENT_INDEX = "ComponentIndex"; //$NON-NLS-1$
+ public static final String STYLE_INDEX = "StyleIndex"; //$NON-NLS-1$
+
+ public static final String[] FONT_MAPPING_KEYS = {
+ "LogicalFontName.StyleName.ComponentIndex", "LogicalFontName.ComponentIndex" //$NON-NLS-1$ //$NON-NLS-2$
+ };
+
+ public static final String FONT_CHARACTER_ENCODING = "fontcharset.LogicalFontName.ComponentIndex"; //$NON-NLS-1$
+
+ public static final String EXCLUSION_RANGES = "exclusion.LogicalFontName.ComponentIndex"; //$NON-NLS-1$
+
+ public static final String FONT_FILE_NAME = "filename.PlatformFontName"; //$NON-NLS-1$
+
+ /**
+ * Available logical font families names.
+ */
+ public static final String[] LOGICAL_FONT_FAMILIES = {
+ "Serif", "SansSerif", "Monospaced", "Dialog", "DialogInput" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ };
+
+ /**
+ * Available logical font names.
+ */
+ public static final String[] LOGICAL_FONT_NAMES = {
+ "serif", "serif.plain", "serif.bold", "serif.italic", "serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "sansserif", "sansserif.plain", "sansserif.bold", "sansserif.italic", "sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "monospaced", "monospaced.plain", "monospaced.bold", "monospaced.italic", "monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "dialog", "dialog.plain", "dialog.bold", "dialog.italic", "dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "dialoginput", "dialoginput.plain", "dialoginput.bold", "dialoginput.italic", "dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ };
+
+ /**
+ * Available logical font face names.
+ */
+ public static final String[] LOGICAL_FONT_FACES = {
+ "Serif", "Serif.plain", "Serif.bold", "Serif.italic", "Serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "Sansserif", "Sansserif.plain", "Sansserif.bold", "Sansserif.italic", "Sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "Monospaced", "Monospaced.plain", "Monospaced.bold", "Monospaced.italic", "Monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "Dialog", "Dialog.plain", "Dialog.bold", "Dialog.italic", "Dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "Dialoginput", "Dialoginput.plain", "Dialoginput.bold", "Dialoginput.italic", "Dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ };
+
+ /**
+ * Set of font style names.
+ * Font.getStyle() corresponds to indexes in STYLE_NAMES array.
+ */
+ public static final String[] STYLE_NAMES = {
+ "plain", "bold", "italic", "bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ };
+
+ /**
+ * Logical font styles names table where font styles names used
+ * as the key and the value is the index of this style name.
+ */
+ private static final Hashtable<String, Integer> style_keys = new Hashtable<String, Integer>(4);
+
+ /**
+ * Initialize font styles keys table.
+ */
+ static {
+ for (int i = 0; i < STYLE_NAMES.length; i++){
+ style_keys.put(STYLE_NAMES[i], Integer.valueOf(i));
+ }
+ }
+
+ /**
+ * Return font style from the logical style name.
+ *
+ * @param lName style name of the logical face
+ */
+ public static int getLogicalStyle(String lName){
+ Integer value = style_keys.get(lName);
+ return value != null ? value.intValue(): -1;
+ }
+
+ /**
+ * Set of possible "os" property values.
+ */
+ public static final String[] OS_VALUES = {
+ "NT", "98", "2000", "Me", "XP", // For Windows //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ "Redhat", "Turbo", "SuSE" // For Linux //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ };
+
+ /**
+ * Set of possible font.property file names.
+ * Language, Country, Encoding, OS, Version should be replaced with
+ * the values from current configuration.
+ */
+ public static final String[] FP_FILE_NAMES = {
+ "/lib/font.properties.Language_Country_Encoding.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country_Encoding.OS", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country_Encoding.Version", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country_Encoding", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country.OS", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country.Version", //$NON-NLS-1$
+ "/lib/font.properties.Language_Country", //$NON-NLS-1$
+ "/lib/font.properties.Language_Encoding.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.Language_Encoding.OS", //$NON-NLS-1$
+ "/lib/font.properties.Language_Encoding.Version", //$NON-NLS-1$
+ "/lib/font.properties.Language_Encoding", //$NON-NLS-1$
+ "/lib/font.properties.Language.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.Language.OS", //$NON-NLS-1$
+ "/lib/font.properties.Language.Version", //$NON-NLS-1$
+ "/lib/font.properties.Language", //$NON-NLS-1$
+ "/lib/font.properties.Encoding.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.Encoding.OS", //$NON-NLS-1$
+ "/lib/font.properties.Encoding.Version", //$NON-NLS-1$
+ "/lib/font.properties.Encoding", //$NON-NLS-1$
+ "/lib/font.properties.OSVersion", //$NON-NLS-1$
+ "/lib/font.properties.OS", //$NON-NLS-1$
+ "/lib/font.properties.Version", //$NON-NLS-1$
+ "/lib/font.properties" //$NON-NLS-1$
+ };
+
+ /**
+ * Table with all available font properties corresponding
+ * to the current system configuration.
+ */
+ public Hashtable<String, Vector<FontProperty>> fProperties = new Hashtable<String, Vector<FontProperty>>();
+
+ public FontManager(){
+ allFamilies = getAllFamilies();
+ /*
+ * Creating and registering shutdown hook to free resources
+ * before object is destroyed.
+ */
+ //???AWT
+ //DisposeNativeHook shutdownHook = new DisposeNativeHook();
+ //Runtime.getRuntime().addShutdownHook(shutdownHook);
+ }
+
+ /**
+ * Maximum number of unreferenced font peers to keep.
+ */
+ public static final int EMPTY_FONTS_CAPACITY = 10;
+
+ /**
+ * Locale - Language ID hash table.
+ */
+ Hashtable<String, Short> tableLCID = new Hashtable<String, Short>();
+
+ /**
+ * Hash table that contains FontPeers instances.
+ */
+ public Hashtable<String, HashMapReference> fontsTable = new Hashtable<String, HashMapReference>();
+
+ /**
+ * ReferenceQueue for HashMapReference objects to check
+ * if they were collected by garbage collector.
+ */
+ public ReferenceQueue<FontPeer> queue = new ReferenceQueue<FontPeer>();
+
+ /**
+ * Singleton instance
+ */
+ public final static FontManager inst = CommonGraphics2DFactory.inst.getFontManager();
+
+ /**
+ * Gets singleton instance of FontManager
+ *
+ * @return instance of FontManager implementation
+ */
+ public static FontManager getInstance() {
+ return inst;
+ }
+
+ /**
+ * Returns platform-dependent Font peer created from the specified
+ * Font object from the table with cached FontPeers instances.
+ *
+ * Note, this method checks whether FontPeer with specified parameters
+ * exists in the table with cached FontPeers' instances. If there is no needed
+ * instance - it is created and cached.
+ *
+ * @param fontName name of the font
+ * @param _fontStyle style of the font
+ * @param size font size
+ *
+ * @return platform dependent FontPeer implementation created from
+ * the specified parameters
+ */
+ public FontPeer getFontPeer(String fontName, int _fontStyle, int size) {
+ updateFontsTable();
+
+ FontPeer peer = null;
+ String key;
+ String name;
+ int fontStyle = _fontStyle;
+
+ int logicalIndex = getLogicalFaceIndex(fontName);
+
+ if (logicalIndex != -1){
+ name = getLogicalFaceFromFont(fontStyle, logicalIndex);
+ fontStyle = getStyleFromLogicalFace(name);
+ key = name.concat(String.valueOf(size));
+ } else {
+ name = fontName;
+ key = name.concat(String.valueOf(fontStyle)).
+ concat(String.valueOf(size));
+ }
+
+ HashMapReference hmr = fontsTable.get(key);
+ if (hmr != null) {
+ peer = hmr.get();
+ }
+
+ if (peer == null) {
+ peer = createFontPeer(name, fontStyle, size, logicalIndex);
+ if (peer == null){
+ peer = getFontPeer(DIALOG_NAME, fontStyle, size);
+ }
+ fontsTable.put(key, new HashMapReference(key, peer, queue));
+ }
+
+ return peer;
+ }
+
+ /**
+ * Returns instance of font peer (logical or physical) according to the
+ * specified parameters.
+ *
+ * @param name font face name
+ * @param style style of the font
+ * @param size size of the font
+ * @param logicalIndex index of the logical face name in LOGICAL_FONT_FACES
+ * array or -1 if desired font peer is not logical.
+ */
+ private FontPeer createFontPeer(String name, int style, int size, int logicalIndex){
+ FontPeer peer;
+ if (logicalIndex != -1){
+ peer = createLogicalFontPeer(name, style, size);
+ }else {
+ peer = createPhysicalFontPeer(name, style, size);
+ }
+
+ return peer;
+ }
+
+ /**
+ * Returns family name for logical face names as a parameter.
+ *
+ * @param faceName logical font face name
+ */
+ public String getFamilyFromLogicalFace(String faceName){
+ int pos = faceName.indexOf("."); //$NON-NLS-1$
+ if (pos == -1){
+ return faceName;
+ }
+
+ return faceName.substring(0, pos);
+ }
+
+ /**
+ * Returns new logical font peer for the parameters specified using font
+ * properties.
+ *
+ * @param faceName face name of the logical font
+ * @param style style of the font
+ * @param size font size
+ *
+ */
+ private FontPeer createLogicalFontPeer(String faceName, int style, int size){
+ String family = getFamilyFromLogicalFace(faceName);
+ FontProperty[] fps = getFontProperties(family.toLowerCase() + "." + style); //$NON-NLS-1$
+ if (fps != null){
+ int numFonts = fps.length;
+ FontPeerImpl[] physicalFonts = new FontPeerImpl[numFonts];
+ for (int i = 0; i < numFonts; i++){
+ FontProperty fp = fps[i];
+
+ String name = fp.getName();
+ int fpStyle = fp.getStyle();
+ String key = name.concat(String.valueOf(fpStyle)).
+ concat(String.valueOf(size));
+
+ HashMapReference hmr = fontsTable.get(key);
+ if (hmr != null) {
+ physicalFonts[i] = (FontPeerImpl)hmr.get();
+ }
+
+ if (physicalFonts[i] == null){
+ physicalFonts[i] = (FontPeerImpl)createPhysicalFontPeer(name, fpStyle, size);
+ fontsTable.put(key, new HashMapReference(key, physicalFonts[i], queue));
+ }
+
+ if (physicalFonts[i] == null){
+ physicalFonts[i] = (FontPeerImpl)getDefaultFont(style, size);
+ }
+ }
+ return new CompositeFont(family, faceName, style, size, fps, physicalFonts);
+ }
+
+ // if there is no property for this logical font - default font is to be
+ // created
+ FontPeerImpl peer = (FontPeerImpl)getDefaultFont(style, size);
+
+ return peer;
+ }
+
+ /**
+ * Returns new physical font peer for the parameters specified using font properties
+ * This method must be overridden by subclasses implementations.
+ *
+ * @param faceName face name or family name of the font
+ * @param style style of the font
+ * @param size font size
+ *
+ */
+ public abstract FontPeer createPhysicalFontPeer(String name, int style, int size);
+
+ /**
+ * Returns default font peer class with "Default" name that is usually
+ * used when font with specified font names and style doesn't exsist
+ * on a system.
+ *
+ * @param style style of the font
+ * @param size size of the font
+ */
+ public FontPeer getDefaultFont(int style, int size){
+ updateFontsTable();
+
+ FontPeer peer = null;
+ String key = DEFAULT_NAME.concat(String.valueOf(style)).
+ concat(String.valueOf(size));
+
+ HashMapReference hmr = fontsTable.get(key);
+ if (hmr != null) {
+ peer = hmr.get();
+ }
+
+ if (peer == null) {
+ peer = createDefaultFont(style, size);
+
+ ((FontPeerImpl)peer).setFamily(DEFAULT_NAME);
+ ((FontPeerImpl)peer).setPSName(DEFAULT_NAME);
+ ((FontPeerImpl)peer).setFontName(DEFAULT_NAME);
+
+ fontsTable.put(key, new HashMapReference(key, peer, queue));
+ }
+
+ return peer;
+ }
+
+ /**
+ *
+ * Returns new default font peer with "Default" name for the parameters
+ * specified. This method must be overridden by subclasses implementations.
+ *
+ * @param style style of the font
+ * @param size size of the font
+ */
+ public abstract FontPeer createDefaultFont(int style, int size);
+
+ /**
+ * Returns face name of the logical font, which is the result
+ * of specified font style and face style union.
+ *
+ * @param fontStyle specified style of the font
+ * @param logicalIndex index of the specified face from the
+ * LOGICAL_FONT_FACES array
+ * @return resulting face name
+ */
+ public String getLogicalFaceFromFont(int fontStyle, int logicalIndex){
+ int style = 0;
+ String name = LOGICAL_FONT_FACES[logicalIndex];
+ int pos = name.indexOf("."); //$NON-NLS-1$
+
+ if (pos == -1){
+ return createLogicalFace(name, fontStyle);
+ }
+
+ String styleName = name.substring(pos+1);
+ name = name.substring(0, pos);
+
+ // appending font style to the face style
+ style = fontStyle | getLogicalStyle(styleName);
+
+ return createLogicalFace(name, style);
+ }
+
+ /**
+ * Function returns style value from logical face name.
+ *
+ * @param name face name
+ * @return font style
+ */
+ public int getStyleFromLogicalFace(String name){
+ int style;
+ int pos = name.indexOf("."); //$NON-NLS-1$
+
+ if (pos == -1){
+ return Font.PLAIN;
+ }
+
+ String styleName = name.substring(pos+1);
+
+ style = getLogicalStyle(styleName);
+
+ return style;
+ }
+
+ /**
+ * Returns logical face name corresponding to the logical
+ * family name and style of the font.
+ *
+ * @param family font family
+ * @param styleIndex index of the style name from the STYLE_NAMES array
+ */
+ public String createLogicalFace(String family, int styleIndex){
+ return family + "." + STYLE_NAMES[styleIndex]; //$NON-NLS-1$
+ }
+
+ /**
+ * Return language Id from LCID hash corresponding to the specified locale
+ *
+ * @param l specified locale
+ */
+ public Short getLCID(Locale l){
+ if (this.tableLCID.size() == 0){
+ initLCIDTable();
+ }
+
+ return tableLCID.get(l.toString());
+ }
+
+ /**
+ * Platform-dependent LCID table init.
+ */
+ public abstract void initLCIDTable();
+
+ /**
+ * Freeing native resources. This hook is used to avoid
+ * sudden application exit and to free resources created in native code.
+ */
+ private class DisposeNativeHook extends Thread {
+
+ @Override
+ public void run() {
+ try{
+ /* Disposing native font peer's resources */
+ Enumeration<String> kEnum = fontsTable.keys();
+
+ while(kEnum.hasMoreElements()){
+ Object key = kEnum.nextElement();
+ HashMapReference hmr = fontsTable.remove(key);
+ FontPeerImpl delPeer = (FontPeerImpl)hmr.get();
+
+ if ((delPeer != null) && (delPeer.getClass() != CompositeFont.class)){
+ // there's nothing to dispose in CompositeFont objects
+ delPeer.dispose();
+ }
+ }
+ } catch (Throwable t){
+ throw new RuntimeException(t);
+ }
+ }
+ }
+
+ /**
+ * Returns File object, created in a directory
+ * according to the System, where JVM is being ran.
+ *
+ * In Linux case we use ".fonts" directory (for fontconfig purpose),
+ * where font file from the stream will be stored, hence in LinuxFontManager this
+ * method is overridden.
+ * In Windows case we use Windows temp directory (default implementation)
+ *
+ */
+ public File getTempFontFile()throws IOException{
+ //???AWT
+ /*
+ File fontFile = File.createTempFile("jFont", ".ttf"); //$NON-NLS-1$ //$NON-NLS-2$
+ fontFile.deleteOnExit();
+
+ return fontFile;
+ */
+ if(NOT_IMP)
+ throw new NotImplementedException("getTempFontFile not Implemented");
+ return null;
+ }
+
+ /**
+ * Returns File object with font properties. It's name obtained using current
+ * system configuration properties and locale settings. If no appropriate
+ * file is found method returns null.
+ */
+ public static File getFontPropertyFile(){
+ File file = null;
+
+ String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
+ Locale l = Locale.getDefault();
+ String language = l.getLanguage();
+ String country = l.getCountry();
+ String fileEncoding = System.getProperty("file.encoding"); //$NON-NLS-1$
+
+ String os = System.getProperty("os.name"); //$NON-NLS-1$
+
+ int i = 0;
+
+ // OS names from system properties don't match
+ // OS identifiers used in font.property files
+ for (; i < OS_VALUES.length; i++){
+ if (os.endsWith(OS_VALUES[i])){
+ os = OS_VALUES[i];
+ break;
+ }
+ }
+
+ if (i == OS_VALUES.length){
+ os = null;
+ }
+
+ String version = System.getProperty("os.version"); //$NON-NLS-1$
+ String pathname;
+
+ for (i = 0; i < FP_FILE_NAMES.length; i++){
+ pathname = FP_FILE_NAMES[i];
+ if (os != null){
+ pathname = pathname.replaceFirst("OS", os); //$NON-NLS-1$
+ }
+
+ pathname = javaHome + pathname;
+
+ pathname = pathname.replaceAll("Language", language). //$NON-NLS-1$
+ replaceAll("Country", country). //$NON-NLS-1$
+ replaceAll("Encoding", fileEncoding). //$NON-NLS-1$
+ replaceAll("Version", version); //$NON-NLS-1$
+
+ file = new File(pathname);
+
+ if (file.exists()){
+ break;
+ }
+ }
+
+ return file.exists() ? file : null;
+ }
+
+ /**
+ * Returns an array of integer range values
+ * if the parameter exclusionString has format:
+ * Range
+ * Range [, exclusionString]
+ *
+ * Range:
+ * Char-Char
+ *
+ * Char:
+ * HexDigit HexDigit HexDigit HexDigit
+ *
+ * Method returns null if the specified string is null.
+ *
+ * @param exclusionString string parameter in specified format
+ */
+ public static int[] parseIntervals(String exclusionString){
+ int[] results = null;
+
+ if (exclusionString == null){
+ return null;
+ }
+
+ String[] intervals = exclusionString.split(","); //$NON-NLS-1$
+
+ if (intervals != null){
+ int num = intervals.length;
+ if (num > 0){
+ results = new int[intervals.length << 1];
+ for (int i = 0; i < intervals.length; i++){
+ String ranges[] = intervals[i].split("-"); //$NON-NLS-1$
+ results[i*2] = Integer.parseInt(ranges[0], 16);
+ results[i*2+1] = Integer.parseInt(ranges[1], 16);
+
+ }
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Returns Properties from the properties file or null if
+ * there is an error with FileInputStream processing.
+ *
+ * @param file File object containing properties
+ */
+ public static Properties getProperties(File file){
+ Properties props = null;
+ FileInputStream fis = null;
+ try{
+ fis = new FileInputStream(file);
+ props = new Properties();
+ props.load(fis);
+ } catch (Exception e){
+ System.out.println(e);
+ }
+ return props;
+ }
+
+ /**
+ * Returns an array of FontProperties from the properties file
+ * with the specified property name "logical face.style". E.g.
+ * "dialog.2" corresponds to the font family Dialog with bold style.
+ *
+ * @param fpName key of the font properties in the properties set
+ */
+ public FontProperty[] getFontProperties(String fpName){
+ Vector<FontProperty> props = fProperties.get(fpName);
+
+ if (props == null){
+ return null;
+ }
+
+ int size = props.size();
+
+ if (size == 0){
+ return null;
+ }
+
+ FontProperty[] fps = new FontProperty[size];
+ for (int i=0; i < fps.length; i++){
+ fps[i] = props.elementAt(i);
+ }
+ return fps;
+ }
+
+ /**
+ * Returns index of the font name in array of font names or -1 if
+ * this font is not logical.
+ *
+ * @param fontName specified font name
+ */
+ public static int getLogicalFaceIndex(String fontName){
+ for (int i=0; i<LOGICAL_FONT_NAMES.length; i++ ){
+ if (LOGICAL_FONT_NAMES[i].equalsIgnoreCase(fontName)){
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns true if specified family name is available in this
+ * GraphicsEnvironment.
+ *
+ * @param familyName the specified font family name
+ */
+ public boolean isFamilyExist(String familyName){
+ return (getFamilyIndex(familyName) != -1);
+ }
+
+ /**
+ * Returns index of family name from the array of family names available in
+ * this GraphicsEnvironment or -1 if no family name was found.
+ *
+ * @param familyName specified font family name
+ */
+ public int getFamilyIndex(String familyName){
+ for (int i=0; i<allFamilies.length; i++ ){
+ if (familyName.equalsIgnoreCase(allFamilies[i])){
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns family with index specified from the array of family names available in
+ * this GraphicsEnvironment.
+ *
+ * @param index index of the family in families names array
+ */
+ public String getFamily(int index){
+ return allFamilies[index];
+ }
+ /**
+ * Returns index of face name from the array of face names available in
+ * this GraphicsEnvironment or -1 if no face name was found. Default return
+ * value is -1, method must be overridden by FontManager implementation.
+ *
+ * @param faceName font face name which index is to be searched
+ */
+ public int getFaceIndex(String faceName){
+ return -1;
+ }
+
+ public abstract String[] getAllFamilies();
+
+ public abstract Font[] getAllFonts();
+
+ /**
+ * Class contains SoftReference instance that can be stored in the
+ * Hashtable by means of key field corresponding to it.
+ */
+ private class HashMapReference extends SoftReference<FontPeer> {
+
+ /**
+ * The key for Hashtable.
+ */
+ private final String key;
+
+ /**
+ * Creates a new soft reference with the key specified and
+ * adding this reference in the reference queue specified.
+ *
+ * @param key the key in Hashtable
+ * @param value object that corresponds to the key
+ * @param queue reference queue where reference is to be added
+ */
+ public HashMapReference(final String key, final FontPeer value,
+ final ReferenceQueue<FontPeer> queue) {
+ super(value, queue);
+ this.key = key;
+ }
+
+ /**
+ * Returns the key that corresponds to the SoftReference instance
+ *
+ * @return the key in Hashtable with cached references
+ */
+ public Object getKey() {
+ return key;
+ }
+ }
+
+ /**
+ * Removes keys from the Hashtable with font peers which corresponding
+ * HashMapReference objects were garbage collected.
+ */
+ private void updateFontsTable() {
+ HashMapReference r;
+ //???AWT
+ //while ((r = (HashMapReference)queue.poll()) != null) {
+ // fontsTable.remove(r.getKey());
+ //}
+ }
+
+}
+
+
diff --git a/awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java b/awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java
new file mode 100644
index 0000000..7783317
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontMetricsImpl.java
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import com.android.internal.awt.AndroidGraphics2D;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+//import java.awt.Paint;
+import java.awt.geom.AffineTransform;
+
+import android.graphics.Paint;
+
+/**
+ * FontMetrics implementation
+ */
+
+public class FontMetricsImpl extends FontMetrics {
+
+ private static final long serialVersionUID = 844695615201925138L;
+
+ // ascent of the font
+ private int ascent;
+
+ // descent of the font
+ private int descent;
+
+ // leading of the font
+ private int leading;
+
+ // maximum ascent of the font
+ private int maxAscent;
+
+ // maximum descent of the font
+ private int maxDescent;
+
+ // maximum advance of the font
+ private int maxAdvance;
+
+ // array of char advance widths
+ private int[] widths = new int[256];
+
+ // font peer corresponding to this FontPeerImpl
+ private transient FontPeerImpl peer;
+
+ // X scale parameter of the font transform
+ private float scaleX = 1;
+
+ public AndroidGraphics2D mSg;
+
+ private Font mFn;
+
+ // Y scale parameter of the font transform
+ private float scaleY = 1;
+
+ /**
+ * Creates new FontMericsImpl object described by the specified Font.
+ *
+ * @param fnt
+ * the specified Font object
+ */
+ public FontMetricsImpl(Font fnt) {
+ super(fnt);
+ this.mFn = fnt;
+
+ mSg = AndroidGraphics2D.getInstance();
+ Paint p = mSg.getAndroidPaint();
+
+ this.ascent = (int)-p.ascent();
+ this.descent = (int)p.descent();
+ this.leading = p.getFontMetricsInt().leading;
+
+ AffineTransform at = fnt.getTransform();
+ if (!at.isIdentity()) {
+ scaleX = (float) at.getScaleX();
+ scaleY = (float) at.getScaleY();
+ }
+
+ /*
+ * metrics[5] - strikethrough thickness<p>
+ * -metrics[6] - strikethrough offset<p>
+ * metrics[7] - maximum char width<p>
+ * metrics[8] - ascent in pixels<p>
+ * metrics[9] - descent in pixles<p>
+ * metrics[10] - external leading in pixels<p>
+ * metrics[11] - underline thickness in pixels<p>
+ * -metrics[12] - underline offset in pixels<p>
+ * metrics[13] - strikethrough thickness in pixels<p>
+ * -metrics[14] - strikethrough offset in pixels<p>
+ * metrics[15] - maximum char width in pixels<p>
+
+ * @param _baselineData an array of 3 elements with baseline offsets metrics<p>
+ * _baselineData[0] - roman baseline offset<p>
+ * _baselineData[1] - center baseline offset<p>
+ * _baselineData[2] - hanging baseline offset<p>
+ */
+ }
+
+
+ /**
+ * Initialize the array of the first 256 chars' advance widths of the Font
+ * describing this FontMetricsImpl object.
+ */
+ private void initWidths() {
+
+ this.widths = new int[256];
+ for (int chr = 0; chr < 256; chr++) {
+ widths[chr] = (int) (getFontPeer().charWidth((char) chr) * scaleX);
+ }
+
+ }
+
+ /**
+ * Returns the ascent of the Font describing this FontMetricsImpl object.
+ */
+ @Override
+ public int getAscent() {
+ return this.ascent;
+ }
+
+ /**
+ * Returns the descent of the Font describing this FontMetricsImpl object.
+ */
+ @Override
+ public int getDescent() {
+ return this.descent;
+ }
+
+ /**
+ * Returns the leading of the Font describing this FontMetricsImpl object.
+ */
+ @Override
+ public int getLeading() {
+ return this.leading;
+ }
+
+ /**
+ * Returns the advance width of the specified char of the Font describing
+ * this FontMetricsImpl object.
+ *
+ * @param ch
+ * the char which width is to be returned
+ * @return the advance width of the specified char of the Font describing
+ * this FontMetricsImpl object
+ */
+ @Override
+ public int charWidth(int ch) {
+ if (ch < 256) {
+ return widths[ch];
+ }
+
+ return getFontPeer().charWidth((char) ch);
+ }
+
+ /**
+ * Returns the advance width of the specified char of the Font describing
+ * this FontMetricsImpl object.
+ *
+ * @param ch
+ * the char which width is to be returned
+ * @return the advance width of the specified char of the Font describing
+ * this FontMetricsImpl object
+ */
+ @Override
+ public int charWidth(char ch) {
+ if (ch < 256) {
+ return widths[ch];
+ }
+ return (int) (getFontPeer().charWidth(ch) * scaleX);
+ }
+
+ /**
+ * Returns the maximum advance of the Font describing this FontMetricsImpl
+ * object.
+ */
+ @Override
+ public int getMaxAdvance() {
+ return this.maxAdvance;
+ }
+
+ /**
+ * Returns the maximum ascent of the Font describing this FontMetricsImpl
+ * object.
+ */
+ @Override
+ public int getMaxAscent() {
+ return this.maxAscent;
+ }
+
+ /**
+ * Returns the maximum descent of the Font describing this FontMetricsImpl
+ * object.
+ */
+ @SuppressWarnings("deprecation")
+ @Deprecated
+ @Override
+ public int getMaxDecent() {
+ return this.maxDescent;
+ }
+
+ /**
+ * Returns the maximum descent of the Font describing this FontMetricsImpl
+ * object.
+ */
+ @Override
+ public int getMaxDescent() {
+ return this.maxDescent;
+ }
+
+ /**
+ * Returns the advance widths of the first 256 characters in the Font
+ * describing this FontMetricsImpl object.
+ */
+ @Override
+ public int[] getWidths() {
+ return this.widths;
+ }
+
+ /**
+ * Returns the total advance width of the specified string in the metrics of
+ * the Font describing this FontMetricsImpl object.
+ *
+ * @param str
+ * the String which width is to be measured
+ * @return the total advance width of the specified string in the metrics of
+ * the Font describing this FontMetricsImpl object
+ */
+ @Override
+ public int stringWidth(String str) {
+
+ int width = 0;
+ char chr;
+
+ for (int i = 0; i < str.length(); i++) {
+ chr = str.charAt(i);
+ width += charWidth(chr);
+ }
+ return width;
+
+ /*
+ * float res = 0; int ln = str.length(); char[] c = new char[ln]; float[] f =
+ * new float[ln]; str.getChars(0, ln, c, 0); mSg.getPaint().getTextWidths(c, 0,
+ * ln, f);
+ *
+ * for(int i = 0; i < f.length; i++) { res += f[i]; } return (int)res;
+ */
+ }
+
+ /**
+ * Returns FontPeer implementation of the Font describing this
+ * FontMetricsImpl object.
+ *
+ * @return a FontPeer object, that is the platform dependent FontPeer
+ * implementation for the Font describing this FontMetricsImpl
+ * object.
+ */
+ @SuppressWarnings("deprecation")
+ public FontPeerImpl getFontPeer() {
+ if (peer == null) {
+ peer = (FontPeerImpl) font.getPeer();
+ }
+ return peer;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java b/awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java
new file mode 100644
index 0000000..14ff997
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontPeerImpl.java
@@ -0,0 +1,499 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+
+import com.android.internal.awt.AndroidGraphics2D;
+import com.android.internal.awt.AndroidGraphicsFactory;
+
+import java.awt.Graphics2D;
+import java.awt.Toolkit;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.peer.FontPeer;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+import android.graphics.Paint;
+
+/**
+ * Abstract class for platform dependent peer implementation of the Font class.
+ */
+public abstract class FontPeerImpl implements FontPeer{
+
+ // ascent of this font peer (in pixels)
+ int ascent;
+
+ // descent of this font peer (in pixels)
+ int descent;
+
+ // leading of this font peer (in pixels)
+ int leading;
+
+ // logical maximum advance of this font peer (in pixels)
+ int maxAdvance;
+
+ // the height of this font peer
+ float height;
+
+ // the style of this font peer
+ int style;
+
+ // the point size of this font peer (in pixels)
+ int size;
+
+ // the logical hight of this font peer (in pixels)
+ int logicalHeight;
+
+ // the name of this font peer
+ String name;
+
+ // family name of this font peer
+ String fontFamilyName;
+
+ // the Face name of this font peer
+ String faceName;
+
+ // bounds rectanlge of the largest character in this font peer
+ Rectangle2D maxCharBounds;
+
+ // italic angle value of this font peer
+ float italicAngle = 0.0f;
+
+ // the number of glyphs supported by this font peer
+ int numGlyphs = 0;
+
+ // native font handle
+ long pFont;
+
+ // cached line metrics object
+ LineMetricsImpl nlm;
+
+ // the postscript name of this font peer
+ String psName = null;
+
+ /**
+ * Default glyph index, that is used, when the desired glyph
+ * is unsupported in this Font.
+ */
+ public char defaultChar = (char)0xFFFF;
+
+ /**
+ * Uniform LineMetrics flag, that is false for CompositeFont.
+ * Default value is true.
+ */
+ boolean uniformLM = true;
+
+ /**
+ * Flag of the type of this Font that is indicate is the Font
+ * has TrueType or Type1 type. Default value is FONT_TYPE_UNDEF.
+ */
+ int fontType = FontManager.FONT_TYPE_UNDEF;
+
+ /**
+ * Flag if this Font was created from stream,
+ * this parameter used in finilize method.
+ */
+ private boolean createdFromStream = false;
+
+ // temorary Font file name, if this FontPeerImpl was created from InputStream
+ private String tempFontFileName = null;
+
+ // cached FontExtraMetrics object related to this font peer
+ FontExtraMetrics extraMetrix = null;
+
+ public abstract FontExtraMetrics getExtraMetrics();
+
+ /**
+ * Returns LineMetrics object with specified parameters
+ * @param str specified String
+ * @param frc specified render context
+ * @param at specified affine transform
+ * @return
+ */
+ public abstract LineMetrics getLineMetrics(String str, FontRenderContext frc, AffineTransform at);
+
+ /**
+ * Returns postscript name of the font.
+ */
+ public abstract String getPSName();
+
+ //private Graphics2D g = ((AndroidGraphicsFactory)Toolkit.getDefaultToolkit().getGraphicsFactory()).getGraphics2D();
+ //private Graphics2D g = AndroidGraphics2D.getInstance();
+
+ /**
+ * Set postscript name of the font to the specified parameter.
+ */
+ public void setPSName(String name){
+ this.psName = name;
+ }
+
+ /**
+ * Returns code of the missing glyph.
+ */
+ public abstract int getMissingGlyphCode();
+
+ /**
+ * Returns Glyph representation of the given char.
+ * @param ch specified char
+ */
+ public abstract Glyph getGlyph(char ch);
+
+ /**
+ * Disposes nesessary resources.
+ */
+ public abstract void dispose();
+
+ /**
+ * Returns Glyph represeting missing char.
+ */
+ public abstract Glyph getDefaultGlyph();
+
+ /**
+ * Returns true if this FontPeerImpl can display the specified char
+ */
+ public abstract boolean canDisplay(char c);
+
+ /**
+ * Returns family name of the font in specified locale settings.
+ * @param l specified Locale
+ */
+ public String getFamily(Locale l){
+ return this.getFamily();
+ }
+
+ /**
+ * Sets family name of the font in specified locale settings.
+ */
+ public void setFamily(String familyName){
+ this.fontFamilyName = familyName;
+ }
+
+ /**
+ * Returns face name of the font in specified locale settings.
+ * @param l specified Locale
+ */
+ public String getFontName(Locale l){
+ return this.getFontName();
+ }
+
+ /**
+ * Sets font name of the font in specified locale settings.
+ */
+ public void setFontName(String fontName){
+ this.faceName = fontName;
+ }
+
+ /**
+ * Returns true, if this font peer was created from InputStream, false otherwise.
+ * In case of creating fonts from InputStream some font peer implementations
+ * may need to free temporary resources.
+ */
+ public boolean isCreatedFromStream(){
+ return this.createdFromStream;
+ }
+
+ /**
+ * Sets createdFromStream flag to the specified parameter.
+ * If parameter is true it means font peer was created from InputStream.
+ *
+ * @param value true, if font peer was created from InputStream
+ */
+ public void setCreatedFromStream(boolean value){
+ this.createdFromStream = value;
+ }
+
+ /**
+ * Returns font file name of this font.
+ */
+ public String getTempFontFileName(){
+ return this.tempFontFileName;
+ }
+
+ /**
+ * Sets font file name of this font to the specified one.
+ * @param value String representing font file name
+ */
+ public void setFontFileName(String value){
+ this.tempFontFileName = value;
+ }
+
+ /**
+ * Returns the advance width of the specified char of this FontPeerImpl.
+ * Note, if glyph is absent in the font's glyphset - returned value
+ * is the advance of the deafualt glyph. For escape-chars returned
+ * width value is 0.
+ *
+ * @param ch the char which width is to be returned
+ * @return the advance width of the specified char of this FontPeerImpl
+ */
+ public int charWidth(char ch) {
+ Paint p;
+ AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+ if(g == null) {
+ throw new RuntimeException("AndroidGraphics2D not instantiated!");
+ }
+ p = ((AndroidGraphics2D)g).getAndroidPaint();
+ char[] ca = {ch};
+ float[] fa = new float[1];
+ p.getTextWidths(ca, 0, 1, fa);
+ return (int)fa[0];
+ }
+
+ /**
+ * Returns the advance width of the specified char of this FontPeerImpl.
+ *
+ * @param ind the char which width is to be returned
+ * @return the advance width of the specified char of this FontPeerImpl
+ */
+ public int charWidth(int ind) {
+ return charWidth((char)ind);
+ }
+
+ /**
+ * Returns an array of Glyphs that represent characters from the specified
+ * Unicode range.
+ *
+ * @param uFirst start position in Unicode range
+ * @param uLast end position in Unicode range
+ * @return
+ */
+ public Glyph[] getGlyphs(char uFirst, char uLast) {
+
+ char i = uFirst;
+ int len = uLast - uFirst;
+ ArrayList<Glyph> lst = new ArrayList<Glyph>(len);
+
+ if (size < 0) {
+ // awt.09=min range bound value is greater than max range bound
+ throw new IllegalArgumentException(Messages.getString("awt.09")); //$NON-NLS-1$
+ }
+
+ while (i < uLast) {
+ lst.add(this.getGlyph(i));
+ }
+
+ return (Glyph[]) lst.toArray();
+ }
+
+ /**
+ * Returns an array of Glyphs representing given array of chars.
+ *
+ * @param chars specified array of chars
+ */
+ public Glyph[] getGlyphs(char[] chars) {
+ if (chars == null){
+ return null;
+ }
+
+ Glyph[] result = new Glyph[chars.length];
+
+ for (int i = 0; i < chars.length; i++) {
+ result[i] = this.getGlyph(chars[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Returns an array of Glyphs representing given string.
+ *
+ * @param str specified string
+ */
+ public Glyph[] getGlyphs(String str) {
+ char[] chars = str.toCharArray();
+ return this.getGlyphs(chars);
+ }
+
+ /**
+ * Returns family name of this FontPeerImpl.
+ */
+ public String getFamily() {
+ return fontFamilyName;
+ }
+
+ /**
+ * Returns face name of this FontPeerImpl.
+ */
+ public String getFontName() {
+ if (this.fontType == FontManager.FONT_TYPE_T1){
+ return this.fontFamilyName;
+ }
+
+ return faceName;
+ }
+
+ /**
+ * Returns height of this font peer in pixels.
+ */
+ public int getLogicalHeight() {
+ return logicalHeight;
+ }
+
+ /**
+ * Sets height of this font peer in pixels to the given value.
+ *
+ * @param newHeight new height in pixels value
+ */
+ public void setLogicalHeight(int newHeight) {
+ logicalHeight = newHeight;
+ }
+
+ /**
+ * Returns font size.
+ */
+ public int getSize() {
+ return size;
+ }
+
+ /**
+ * Returns font style.
+ */
+ public int getStyle() {
+ return style;
+ }
+
+ /**
+ * Returns font name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the bounds of the largest char in this FontPeerImpl in
+ * specified render context.
+ *
+ * @param frc specified FontRenderContext
+ */
+ public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
+ return maxCharBounds;
+ }
+
+ /**
+ * Returns the number of glyphs in this FontPeerImpl.
+ */
+ public int getNumGlyphs() {
+ return numGlyphs;
+ }
+
+ /**
+ * Returns tangens of the italic angle of this FontPeerImpl.
+ * If the FontPeerImpl has TrueType font type, italic angle value can be
+ * calculated as (CharSlopeRun / CharSlopeRise) in terms of GDI.
+ */
+ public float getItalicAngle() {
+ return italicAngle;
+ }
+
+ /**
+ * Returns height of this font peer.
+ */
+ public float getHeight(){
+ return height;
+ }
+
+ /**
+ * Returns cached LineMetrics object of this font peer.
+ */
+ public LineMetrics getLineMetrics(){
+ return nlm;
+ }
+
+ /**
+ * Returns native font handle of this font peer.
+ */
+ public long getFontHandle(){
+ return pFont;
+ }
+
+ /**
+ * Returns ascent of this font peer.
+ */
+ public int getAscent(){
+ Paint p;
+ AndroidGraphics2D g = AndroidGraphics2D.getInstance();
+ if(g == null) {
+ throw new RuntimeException("AndroidGraphics2D not instantiated!");
+ }
+ p = ((AndroidGraphics2D)g).getAndroidPaint();
+ return (int)p.ascent();
+ //return ascent;
+ }
+
+ /**
+ * Returns descent of this font peer.
+ */
+ public int getDescent(){
+ return descent;
+ }
+
+ /**
+ * Returns leading of this font peer.
+ */
+ public int getLeading(){
+ return leading;
+ }
+
+ /**
+ * Returns true if this font peer has uniform line metrics.
+ */
+ public boolean hasUniformLineMetrics(){
+ return uniformLM;
+ }
+
+ /**
+ * Returns type of this font.
+ *
+ * @return one of constant font type values.
+ */
+ public int getFontType(){
+ return fontType;
+ }
+
+ /**
+ * Sets new font type to the font object.
+ *
+ * @param newType new type value
+ */
+ public void setFontType(int newType){
+ if (newType == FontManager.FONT_TYPE_T1 || newType == FontManager.FONT_TYPE_TT){
+ fontType = newType;
+ }
+ }
+
+ /**
+ * Sets new font type to the font object.
+ *
+ * @param newType new type value
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+
+ dispose();
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/FontProperty.java b/awt/org/apache/harmony/awt/gl/font/FontProperty.java
new file mode 100644
index 0000000..4eb7cbb
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/FontProperty.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+
+/**
+ * Class containing font property information. This information can be found
+ * in font.property files. See API documentation, logical fonts description part.
+ *
+ */
+public class FontProperty {
+
+ // font file name
+ String fileName = null;
+
+ // name of the encoding to be used
+ String encoding = null;
+
+ // array of exclusion ranges (pairs of low and high unicode exclusion bounds)
+ int[] exclRange = null;
+
+ // font face name
+ String name = null;
+
+ // font style
+ int style = -1;
+
+ /**
+ * Returns font style of this font property.
+ */
+ public int getStyle(){
+ return this.style;
+ }
+
+ /**
+ * Returns font name of this font property.
+ */
+ public String getName(){
+ return this.name;
+ }
+
+ /**
+ * Returns encoding used in this font property.
+ */
+ public String getEncoding(){
+ return this.encoding;
+ }
+
+ /**
+ * Returns an array of exclusion ranges. This array contain pairs of
+ * low and high bounds of the intervals of characters to ignore in
+ * total Unicode characters range.
+ */
+ public int[] getExclusionRange(){
+ return this.exclRange;
+ }
+
+ /**
+ * Returns file name of the font that is described by this font property.
+ */
+ public String getFileName(){
+ return this.fileName;
+ }
+
+ /**
+ * Returns true if specified character covered by exclusion ranges of this
+ * font property, false otherwise.
+ *
+ * @param ch specified char to check
+ */
+ public boolean isCharExcluded(char ch){
+ if (exclRange == null ){
+ return false;
+ }
+
+ for (int i = 0; i < exclRange.length;){
+ int lb = exclRange[i++];
+ int hb = exclRange[i++];
+
+ if (ch >= lb && ch <= hb){
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/Glyph.java b/awt/org/apache/harmony/awt/gl/font/Glyph.java
new file mode 100644
index 0000000..44b8809
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/Glyph.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Shape;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+import java.awt.image.BufferedImage;
+
+public abstract class Glyph{
+
+ // character of the glyph
+ char glChar;
+
+ // precise glyph metrics
+ GlyphMetrics glMetrics;
+
+ // glyph metrics in pixels
+ GlyphMetrics glPointMetrics;
+
+ // glyph code of this Glyph
+ int glCode;
+
+ // justification info of this glyph
+ GlyphJustificationInfo glJustInfo;
+
+ // native font handle of the font corresponding to this glyph
+ long pFont;
+
+ // size of the font corresponding to this glyph
+ int fontSize;
+
+ // bitmap representation of the glyph
+ byte[] bitmap = null;
+
+ // Buffered image representation of the glyph
+ BufferedImage image;
+
+ // shape that representing the outline of this glyph
+ Shape glOutline = null;
+
+ /**
+ * image bitmap parameters
+ */
+
+ // top side bearing
+ public int bmp_top = 0;
+
+ // left side bearing
+ public int bmp_left = 0;
+
+ // number of bytes in row
+ public int bmp_pitch;
+
+ // number of rows
+ public int bmp_rows;
+
+ // width of the row
+ public int bmp_width;
+
+ /**
+ * Retruns handle to Native Font object
+ */
+ public long getPFont(){
+ return this.pFont;
+ }
+
+ /**
+ * Retruns char value of this glyph object
+ */
+ public char getChar(){
+ return glChar;
+ }
+
+ /**
+ * Retruns precise width of this glyph object
+ */
+ public int getWidth(){
+ return Math.round((float)glMetrics.getBounds2D().getWidth());
+ }
+
+ /**
+ * Retruns precise height of this glyph object
+ */
+ public int getHeight(){
+ return Math.round((float)glMetrics.getBounds2D().getHeight());
+ }
+
+ /**
+ * Retruns glyph code of this glyph object
+ */
+ public int getGlyphCode(){
+ return glCode;
+ }
+
+ /**
+ * Retruns GlyphMetrics of this glyph object with precise metrics.
+ */
+ public GlyphMetrics getGlyphMetrics(){
+ return glMetrics;
+ }
+
+ /**
+ * Retruns GlyphMetrics of this glyph object in pixels.
+ */
+ public GlyphMetrics getGlyphPointMetrics(){
+ return glPointMetrics;
+ }
+
+ /**
+ * Retruns GlyphJustificationInfo of this glyph object
+ */
+ public GlyphJustificationInfo getGlyphJustificationInfo(){
+ return glJustInfo;
+ }
+
+ /**
+ * Sets JustificationInfo of this glyph object
+ *
+ * @param newJustInfo GlyphJustificationInfo object to set to the Glyph object
+ */
+ public void setGlyphJustificationInfo(GlyphJustificationInfo newJustInfo){
+ this.glJustInfo = newJustInfo;
+ }
+
+ /**
+ * Returns an int array of 3 elements, so-called ABC structure that contains
+ * the width of the character:
+ * 1st element = left side bearing of the glyph
+ * 2nd element = width of the glyph
+ * 3d element = right side bearing of the glyph
+ */
+ public int[] getABC(){
+ int[] abc = new int[3];
+ abc[0] = (int)glMetrics.getLSB();
+ abc[1] = (int)glMetrics.getBounds2D().getWidth();
+ abc[2] = (int)glMetrics.getRSB();
+
+ return abc;
+ }
+
+ /**
+ * Sets BufferedImage representation of this glyph to the specified parameter.
+ *
+ * @param newImage new BufferedImage object to be set as BufferedImage
+ * representation.
+ */
+ public void setImage(BufferedImage newImage){
+ this.image = newImage;
+ }
+
+ /**
+ * Returns true if this Glyph and specified object are equal.
+ */
+ @Override
+ public boolean equals(Object obj){
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj != null) {
+ try {
+ Glyph gl = (Glyph)obj;
+
+ return ((this.getChar() == gl.getChar())
+ && (this.getGlyphMetrics().equals(gl.getGlyphMetrics()))
+ && (this.getGlyphCode() == gl.getGlyphCode()));
+ } catch (ClassCastException e) {
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns height of the glyph in points.
+ */
+ public int getPointHeight(){
+ return (int)glPointMetrics.getBounds2D().getHeight();
+ }
+
+ /**
+ * Returns width of the glyph in points.
+ */
+ public int getPointWidth(){
+ return (int)glPointMetrics.getBounds2D().getWidth();
+ }
+
+ public Shape getShape(){
+ if (glOutline == null){
+ glOutline = initOutline(this.glChar);
+ }
+ return glOutline;
+ }
+
+ /**
+ * Sets BufferedImage representation of this glyph.
+ */
+ public BufferedImage getImage(){
+ //!! Implementation classes must override this method
+ return null;
+ }
+
+ /**
+ * Returns array of bytes, representing image of this glyph
+ */
+ public abstract byte[] getBitmap();
+
+ /**
+ * Returns shape that represents outline of the specified character.
+ *
+ * @param c specified character
+ */
+ public abstract Shape initOutline(char c);
+
+}
+
+
diff --git a/awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java b/awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java
new file mode 100644
index 0000000..370146d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/LineMetricsImpl.java
@@ -0,0 +1,412 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.LineMetrics;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ *
+ * LineMetrics implementation class.
+ */
+
+public class LineMetricsImpl extends LineMetrics implements Cloneable{
+
+ // array of baseline offsets
+ float[] baselineOffsets;
+
+ // the number of characters to measure
+ int numChars;
+
+ // baseline index of the font corresponding to this line metrics
+ int baseLineIndex;
+
+ // underline thickness
+ float underlineThickness;
+
+ // underline offset
+ float underlineOffset;
+
+ // strikethrough thickness
+ float strikethroughThickness;
+
+ // strikethrough offset
+ float strikethroughOffset;
+
+ // External leading
+ float leading;
+
+ // Height of the font ( == (ascent+descent+leading))
+ float height;
+
+ // Ascent of the font
+ float ascent;
+
+ // Descent of the font
+ float descent;
+
+ // Width of the widest char in the font
+ float maxCharWidth;
+
+ // underline thickness (in pixels)
+ int lUnderlineThickness;
+
+ // underline offset (in pixels)
+ int lUnderlineOffset;
+
+ // strikethrough thickness (in pixels)
+ int lStrikethroughThickness;
+
+ // strikethrough offset (in pixels)
+ int lStrikethroughOffset;
+
+ // External leading (in pixels)
+ int lLeading;
+
+ // Height of the font ( == (ascent+descent+leading)) (in pixels)
+ int lHeight;
+
+ // Ascent of the font (in pixels)
+ int lAscent;
+
+ // Descent of the font (in pixels)
+ int lDescent;
+
+ // Width of the widest char in the font (in pixels)
+ int lMaxCharWidth;
+
+ // units per EM square in font value
+ int units_per_EM = 0;
+
+ /**
+ * Creates LineMetricsImpl object from specified parameters. If baseline data parameter
+ * is null than {0, (-ascent+descent)/2, -ascent} values are used for baseline offsets.
+ *
+ * @param len a number of characters
+ * @param metrics an array of 16 elements with metrics values that can be
+ * initialized in native code.<p>
+ * metrics[0] - ascent<p>
+ * metrics[1] - descent<p>
+ * metrics[2] - external leading<p>
+ * metrics[3] - underline thickness<p>
+ * -metrics[4] - underline offset<p>
+ * metrics[5] - strikethrough thickness<p>
+ * -metrics[6] - strikethrough offset<p>
+ * metrics[7] - maximum char width<p>
+ * metrics[8] - ascent in pixels<p>
+ * metrics[9] - descent in pixles<p>
+ * metrics[10] - external leading in pixels<p>
+ * metrics[11] - underline thickness in pixels<p>
+ * -metrics[12] - underline offset in pixels<p>
+ * metrics[13] - strikethrough thickness in pixels<p>
+ * -metrics[14] - strikethrough offset in pixels<p>
+ * metrics[15] - maximum char width in pixels<p>
+
+ * @param _baselineData an array of 3 elements with baseline offsets metrics<p>
+ * _baselineData[0] - roman baseline offset<p>
+ * _baselineData[1] - center baseline offset<p>
+ * _baselineData[2] - hanging baseline offset<p>
+ */
+ public LineMetricsImpl(int len, float[] metrics, float[] _baselineData){
+ numChars = len;
+
+ ascent = metrics[0]; // Ascent of the font
+ descent = metrics[1]; // Descent of the font
+ leading = metrics[2]; // External leading
+ height = metrics[0] + metrics[1] + metrics[2]; // Height of the font ( == (ascent + descent + leading))
+ }
+
+ /**
+ * Creates LineMetricsImpl object from specified parameters. If baseline data parameter
+ * is null than {0, (-ascent+descent)/2, -ascent} values are used for baseline offsets.
+ *
+ * @param _numChars number of chars
+ * @param _baseLineIndex index of the baseline offset
+ * @param _baselineOffsets an array of baseline offsets
+ * @param _underlineThickness underline thickness
+ * @param _underlineOffset underline offset
+ * @param _strikethroughThickness strikethrough thickness
+ * @param _strikethroughOffset strinkethrough offset
+ * @param _leading leading of the font
+ * @param _height font height
+ * @param _ascent ascent of the font
+ * @param _descent descent of the font
+ * @param _maxCharWidth max char width
+ */
+ public LineMetricsImpl(int _numChars, int _baseLineIndex,
+ float[] _baselineOffsets, float _underlineThickness,
+ float _underlineOffset, float _strikethroughThickness,
+ float _strikethroughOffset, float _leading, float _height,
+ float _ascent, float _descent, float _maxCharWidth) {
+
+ numChars = _numChars;
+ baseLineIndex = _baseLineIndex;
+ underlineThickness = _underlineThickness;
+ underlineOffset = _underlineOffset;
+ strikethroughThickness = _strikethroughThickness;
+ strikethroughOffset = _strikethroughOffset;
+ leading = _leading;
+ height = _height;
+ ascent = _ascent;
+ descent = _descent;
+ baselineOffsets = _baselineOffsets;
+ lUnderlineThickness = (int) underlineThickness;
+ lUnderlineOffset = (int) underlineOffset;
+ lStrikethroughThickness = (int) strikethroughThickness;
+ lStrikethroughOffset = (int) strikethroughOffset;
+ lLeading = (int) leading;
+ lHeight = (int) height;
+ lAscent = (int) ascent;
+ lDescent = (int) descent;
+ maxCharWidth = _maxCharWidth;
+ }
+
+ public LineMetricsImpl(){
+
+ }
+
+ /**
+ * All metrics are scaled according to scaleX and scaleY values.
+ * This function helps to recompute metrics according to the scale factors
+ * of desired AffineTransform.
+ *
+ * @param scaleX scale X factor
+ * @param scaleY scale Y factor
+ */
+ public void scale(float scaleX, float scaleY){
+ float absScaleX = Math.abs(scaleX);
+ float absScaleY = Math.abs(scaleY);
+
+ underlineThickness *= absScaleY;
+ underlineOffset *= scaleY;
+ strikethroughThickness *= absScaleY;
+ strikethroughOffset *= scaleY;
+ leading *= absScaleY;
+ height *= absScaleY;
+ ascent *= absScaleY;
+ descent *= absScaleY;
+
+ if(baselineOffsets == null) {
+ getBaselineOffsets();
+ }
+
+ for (int i=0; i< baselineOffsets.length; i++){
+ baselineOffsets[i] *= scaleY;
+ }
+
+ lUnderlineThickness *= absScaleY;
+ lUnderlineOffset *= scaleY;
+ lStrikethroughThickness *= absScaleY;
+ lStrikethroughOffset *= scaleY;
+ lLeading *= absScaleY;
+ lHeight *= absScaleY;
+ lAscent *= absScaleY;
+ lDescent *= absScaleY;
+ maxCharWidth *= absScaleX;
+
+ }
+
+
+ /**
+ * Returns offset of the baseline.
+ */
+ @Override
+ public float[] getBaselineOffsets() {
+ // XXX: at the moment there only horizontal metrics are taken into
+ // account. If there is no baseline information in TrueType font
+ // file default values used: {0, -ascent, (-ascent+descent)/2}
+
+ return baselineOffsets;
+ }
+
+ /**
+ * Returns a number of chars in specified text
+ */
+ @Override
+ public int getNumChars() {
+ return numChars;
+ }
+
+ /**
+ * Returns index of the baseline, one of predefined constants.
+ */
+ @Override
+ public int getBaselineIndex() {
+ // Baseline index is the deafult baseline index value
+ // taken from the TrueType table "BASE".
+ return baseLineIndex;
+ }
+
+ /**
+ * Returns thickness of the Underline.
+ */
+ @Override
+ public float getUnderlineThickness() {
+ return underlineThickness;
+ }
+
+ /**
+ * Returns offset of the Underline.
+ */
+ @Override
+ public float getUnderlineOffset() {
+ return underlineOffset;
+ }
+
+ /**
+ * Returns thickness of the Strikethrough line.
+ */
+ @Override
+ public float getStrikethroughThickness() {
+ return strikethroughThickness;
+ }
+
+ /**
+ * Returns offset of the Strikethrough line.
+ */
+ @Override
+ public float getStrikethroughOffset() {
+ return strikethroughOffset;
+ }
+
+ /**
+ * Returns the leading.
+ */
+ @Override
+ public float getLeading() {
+ return leading;
+ }
+
+ /**
+ * Returns the height of the font.
+ */
+ @Override
+ public float getHeight() {
+ //return height; // equals to (ascent + descent + leading);
+ return ascent + descent + leading;
+ }
+
+ /**
+ * Returns the descent.
+ */
+ @Override
+ public float getDescent() {
+ return descent;
+ }
+
+ /**
+ * Returns the ascent.
+ */
+ @Override
+ public float getAscent() {
+ return ascent;
+ }
+
+ /**
+ * Returns logical thickness of the Underline.
+ */
+ public int getLogicalUnderlineThickness() {
+ return lUnderlineThickness;
+ }
+
+ /**
+ * Returns logical offset of the Underline.
+ */
+ public int getLogicalUnderlineOffset() {
+ return lUnderlineOffset;
+ }
+
+ /**
+ * Returns logical thickness of the Strikethrough line.
+ */
+ public int getLogicalStrikethroughThickness() {
+ return lStrikethroughThickness;
+ }
+
+ /**
+ * Returns logical offset of the Strikethrough line.
+ */
+ public int getLogicalStrikethroughOffset() {
+ return lStrikethroughOffset;
+ }
+
+ /**
+ * Returns the logical leading.
+ */
+ public int getLogicalLeading() {
+ return lLeading;
+ }
+
+ /**
+ * Returns the logical height of the font.
+ */
+ public int getLogicalHeight() {
+ return lHeight; // equals to (ascent + descent + leading);
+ }
+
+ /**
+ * Returns the logical descent.
+ */
+ public int getLogicalDescent() {
+ return lDescent;
+ }
+
+ /**
+ * Returns the logical ascent.
+ */
+ public int getLogicalAscent() {
+ return lAscent;
+ }
+
+ /**
+ * Returns the logical size of the widest char.
+ */
+ public int getLogicalMaxCharWidth() {
+ return lMaxCharWidth;
+ }
+
+ /**
+ * Returns the size of the widest char.
+ */
+ public float getMaxCharWidth() {
+ return maxCharWidth;
+ }
+
+ /**
+ * Set num chars to the desired value.
+ *
+ * @param num specified number of chars
+ */
+ public void setNumChars(int num){
+ numChars = num;
+ }
+
+ @Override
+ public Object clone(){
+ try{
+ return super.clone();
+ }catch (CloneNotSupportedException e){
+ return null;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/font/TextDecorator.java b/awt/org/apache/harmony/awt/gl/font/TextDecorator.java
new file mode 100644
index 0000000..81905fd
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextDecorator.java
@@ -0,0 +1,433 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.TextAttribute;
+import java.awt.geom.Area;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.Map;
+
+/**
+ * This class is responsible for rendering text decorations like
+ * underline, strikethrough, text with background, etc.
+ */
+public class TextDecorator {
+ private static final TextDecorator inst = new TextDecorator();
+ private TextDecorator() {}
+ static TextDecorator getInstance() {
+ return inst;
+ }
+
+ /**
+ * This class encapsulates a set of decoration attributes for a single text run.
+ */
+ static class Decoration {
+ private static final BasicStroke UNDERLINE_LOW_ONE_PIXEL_STROKE =
+ new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10);
+
+ private static final BasicStroke UNDERLINE_LOW_TWO_PIXEL_STROKE =
+ new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10);
+
+ private static final BasicStroke UNDERLINE_LOW_DOTTED_STROKE =
+ new BasicStroke(
+ 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,
+ new float[] { 1, 1 }, 0
+ );
+
+ private static final BasicStroke UNDERLINE_LOW_DOTTED_STROKE2 =
+ new BasicStroke(
+ 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,
+ new float[] { 1, 1 }, 1
+ );
+
+ private static final BasicStroke UNDERLINE_LOW_DASHED_STROKE =
+ new BasicStroke(
+ 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10,
+ new float[] { 4, 4 }, 0
+ );
+
+ boolean ulOn = false; // Have standard underline?
+ BasicStroke ulStroke;
+
+ BasicStroke imUlStroke; // Stroke for INPUT_METHOD_UNDERLINE
+ BasicStroke imUlStroke2; // Specially for UNDERLINE_LOW_GRAY
+
+ boolean strikeThrough;
+ BasicStroke strikeThroughStroke;
+
+ boolean haveStrokes = false; // Strokes already created?
+
+ boolean swapBfFg;
+ Paint bg; // background color
+ Paint fg; // foreground color
+
+ Paint graphicsPaint; // Slot for saving current paint
+
+ Decoration(
+ Integer imUl,
+ boolean swap,
+ boolean sth,
+ Paint bg, Paint fg,
+ boolean ulOn) {
+
+ if (imUl != null) {
+ // Determine which stroke to use
+ if (imUl == TextAttribute.UNDERLINE_LOW_ONE_PIXEL) {
+ this.imUlStroke = Decoration.UNDERLINE_LOW_ONE_PIXEL_STROKE;
+ } else if (imUl == TextAttribute.UNDERLINE_LOW_TWO_PIXEL) {
+ this.imUlStroke = Decoration.UNDERLINE_LOW_TWO_PIXEL_STROKE;
+ } else if (imUl == TextAttribute.UNDERLINE_LOW_DOTTED) {
+ this.imUlStroke = Decoration.UNDERLINE_LOW_DOTTED_STROKE;
+ } else if (imUl == TextAttribute.UNDERLINE_LOW_GRAY) {
+ this.imUlStroke = Decoration.UNDERLINE_LOW_DOTTED_STROKE;
+ this.imUlStroke2 = Decoration.UNDERLINE_LOW_DOTTED_STROKE2;
+ } else if (imUl == TextAttribute.UNDERLINE_LOW_DASHED) {
+ this.imUlStroke = Decoration.UNDERLINE_LOW_DASHED_STROKE;
+ }
+ }
+
+ this.ulOn = ulOn; // Has underline
+ this.swapBfFg = swap;
+ this.strikeThrough = sth;
+ this.bg = bg;
+ this.fg = fg;
+ }
+
+ /**
+ * Creates strokes of proper width according to the info
+ * stored in the BasicMetrics
+ * @param metrics - basic metrics
+ */
+ private void getStrokes(BasicMetrics metrics) {
+ if (!haveStrokes) {
+ if (strikeThrough) {
+ strikeThroughStroke =
+ new BasicStroke(
+ metrics.strikethroughThickness,
+ BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_MITER,
+ 10
+ );
+ }
+
+ if (ulOn) {
+ ulStroke =
+ new BasicStroke(
+ metrics.underlineThickness,
+ BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_MITER,
+ 10
+ );
+ }
+
+ haveStrokes = true;
+ }
+ }
+ }
+
+ /**
+ * Creates Decoration object from the set of text attributes
+ * @param attributes - text attributes
+ * @return Decoration object
+ */
+ static Decoration getDecoration(Map<? extends Attribute, ?> attributes) {
+ if (attributes == null) {
+ return null; // It is for plain text
+ }
+
+ Object underline = attributes.get(TextAttribute.UNDERLINE);
+ boolean hasStandardUnderline = underline == TextAttribute.UNDERLINE_ON;
+
+ Object imUnderline = attributes.get(TextAttribute.INPUT_METHOD_UNDERLINE);
+ Integer imUl = (Integer) imUnderline;
+
+ boolean swapBgFg =
+ TextAttribute.SWAP_COLORS_ON.equals(
+ attributes.get(TextAttribute.SWAP_COLORS)
+ );
+
+ boolean strikeThrough =
+ TextAttribute.STRIKETHROUGH_ON.equals(
+ attributes.get(TextAttribute.STRIKETHROUGH)
+ );
+
+ Paint fg = (Paint) attributes.get(TextAttribute.FOREGROUND);
+ Paint bg = (Paint) attributes.get(TextAttribute.BACKGROUND);
+
+ if (
+ !hasStandardUnderline &&
+ imUnderline == null &&
+ fg == null &&
+ bg == null &&
+ !swapBgFg &&
+ !strikeThrough
+ ) {
+ return null;
+ }
+ return new Decoration(imUl, swapBgFg, strikeThrough, bg, fg, hasStandardUnderline);
+ }
+
+ /**
+ * Fills the background before drawing if needed.
+ *
+ * @param trs - text segment
+ * @param g2d - graphics to draw to
+ * @param xOffset - offset in X direction to the upper left corner of the
+ * layout from the origin of the graphics
+ * @param yOffset - offset in Y direction to the upper left corner of the
+ * layout from the origin of the graphics
+ */
+ static void prepareGraphics(
+ TextRunSegment trs, Graphics2D g2d,
+ float xOffset, float yOffset
+ ) {
+ Decoration d = trs.decoration;
+
+ if (d.fg == null && d.bg == null && d.swapBfFg == false) {
+ return; // Nothing to do
+ }
+
+ d.graphicsPaint = g2d.getPaint();
+
+ if (d.fg == null) {
+ d.fg = d.graphicsPaint;
+ }
+
+ if (d.swapBfFg) {
+ // Fill background area
+ g2d.setPaint(d.fg);
+ Rectangle2D bgArea = trs.getLogicalBounds();
+ Rectangle2D toFill =
+ new Rectangle2D.Double(
+ bgArea.getX() + xOffset,
+ bgArea.getY() + yOffset,
+ bgArea.getWidth(),
+ bgArea.getHeight()
+ );
+ g2d.fill(toFill);
+
+ // Set foreground color
+ g2d.setPaint(d.bg == null ? Color.WHITE : d.bg);
+ } else {
+ if (d.bg != null) { // Fill background area
+ g2d.setPaint(d.bg);
+ Rectangle2D bgArea = trs.getLogicalBounds();
+ Rectangle2D toFill =
+ new Rectangle2D.Double(
+ bgArea.getX() + xOffset,
+ bgArea.getY() + yOffset,
+ bgArea.getWidth(),
+ bgArea.getHeight()
+ );
+ g2d.fill(toFill);
+ }
+
+ // Set foreground color
+ g2d.setPaint(d.fg);
+ }
+ }
+
+ /**
+ * Restores the original state of the graphics if needed
+ * @param d - decoration
+ * @param g2d - graphics
+ */
+ static void restoreGraphics(Decoration d, Graphics2D g2d) {
+ if (d.fg == null && d.bg == null && d.swapBfFg == false) {
+ return; // Nothing to do
+ }
+
+ g2d.setPaint(d.graphicsPaint);
+ }
+
+ /**
+ * Renders the text decorations
+ * @param trs - text run segment
+ * @param g2d - graphics to render to
+ * @param xOffset - offset in X direction to the upper left corner
+ * of the layout from the origin of the graphics
+ * @param yOffset - offset in Y direction to the upper left corner
+ * of the layout from the origin of the graphics
+ */
+ static void drawTextDecorations(
+ TextRunSegment trs, Graphics2D g2d,
+ float xOffset, float yOffset
+ ) {
+ Decoration d = trs.decoration;
+
+ if (!d.ulOn && d.imUlStroke == null && !d.strikeThrough) {
+ return; // Nothing to do
+ }
+
+ float left = xOffset + (float) trs.getLogicalBounds().getMinX();
+ float right = xOffset + (float) trs.getLogicalBounds().getMaxX();
+
+ Stroke savedStroke = g2d.getStroke();
+
+ d.getStrokes(trs.metrics);
+
+ if (d.strikeThrough) {
+ float y = trs.y + yOffset + trs.metrics.strikethroughOffset;
+ g2d.setStroke(d.strikeThroughStroke);
+ g2d.draw(new Line2D.Float(left, y, right, y));
+ }
+
+ if (d.ulOn) {
+ float y = trs.y + yOffset + trs.metrics.underlineOffset;
+ g2d.setStroke(d.ulStroke);
+ g2d.draw(new Line2D.Float(left, y, right, y));
+ }
+
+ if (d.imUlStroke != null) {
+ float y = trs.y + yOffset + trs.metrics.underlineOffset;
+ g2d.setStroke(d.imUlStroke);
+ g2d.draw(new Line2D.Float(left, y, right, y));
+ if (d.imUlStroke2 != null) {
+ y++;
+ g2d.setStroke(d.imUlStroke2);
+ g2d.draw(new Line2D.Float(left, y, right, y));
+ }
+ }
+
+ g2d.setStroke(savedStroke);
+ }
+
+ /**
+ * Extends the visual bounds of the text run segment to
+ * include text decorations.
+ * @param trs - text segment
+ * @param segmentBounds - bounds of the undecorated text
+ * @param d - decoration
+ * @return extended bounds
+ */
+ static Rectangle2D extendVisualBounds(
+ TextRunSegment trs,
+ Rectangle2D segmentBounds,
+ Decoration d
+ ) {
+ if (d == null) {
+ return segmentBounds;
+ }
+ double minx = segmentBounds.getMinX();
+ double miny = segmentBounds.getMinY();
+ double maxx = segmentBounds.getMaxX();
+ double maxy = segmentBounds.getMaxY();
+
+ Rectangle2D lb = trs.getLogicalBounds();
+
+ if (d.swapBfFg || d.bg != null) {
+ minx = Math.min(lb.getMinX() - trs.x, minx);
+ miny = Math.min(lb.getMinY() - trs.y, miny);
+ maxx = Math.max(lb.getMaxX() - trs.x, maxx);
+ maxy = Math.max(lb.getMaxY() - trs.y, maxy);
+ }
+
+ if (d.ulOn || d.imUlStroke != null || d.strikeThrough) {
+ minx = Math.min(lb.getMinX() - trs.x, minx);
+ maxx = Math.max(lb.getMaxX() - trs.x, maxx);
+
+ d.getStrokes(trs.metrics);
+
+ if (d.ulStroke != null) {
+ maxy = Math.max(
+ maxy,
+ trs.metrics.underlineOffset +
+ d.ulStroke.getLineWidth()
+ );
+ }
+
+ if (d.imUlStroke != null) {
+ maxy = Math.max(
+ maxy,
+ trs.metrics.underlineOffset +
+ d.imUlStroke.getLineWidth() +
+ (d.imUlStroke2 == null ? 0 : d.imUlStroke2.getLineWidth())
+ );
+ }
+ }
+
+ return new Rectangle2D.Double(minx, miny, maxx-minx, maxy-miny);
+ }
+
+ /**
+ * Extends the outline of the text run segment to
+ * include text decorations.
+ * @param trs - text segment
+ * @param segmentOutline - outline of the undecorated text
+ * @param d - decoration
+ * @return extended outline
+ */
+ static Shape extendOutline(
+ TextRunSegment trs,
+ Shape segmentOutline,
+ Decoration d
+ ) {
+ if (d == null || !d.ulOn && d.imUlStroke == null && !d.strikeThrough) {
+ return segmentOutline; // Nothing to do
+ }
+
+ Area res = new Area(segmentOutline);
+
+ float left = (float) trs.getLogicalBounds().getMinX() - trs.x;
+ float right = (float) trs.getLogicalBounds().getMaxX() - trs.x;
+
+ d.getStrokes(trs.metrics);
+
+ if (d.strikeThrough) {
+ float y = trs.metrics.strikethroughOffset;
+ res.add(new Area(d.strikeThroughStroke.createStrokedShape(
+ new Line2D.Float(left, y, right, y)
+ )));
+ }
+
+ if (d.ulOn) {
+ float y = trs.metrics.underlineOffset;
+ res.add(new Area(d.ulStroke.createStrokedShape(
+ new Line2D.Float(left, y, right, y)
+ )));
+ }
+
+ if (d.imUlStroke != null) {
+ float y = trs.metrics.underlineOffset;
+ res.add(new Area(d.imUlStroke.createStrokedShape(
+ new Line2D.Float(left, y, right, y)
+ )));
+
+ if (d.imUlStroke2 != null) {
+ y++;
+ res.add(new Area(d.imUlStroke2.createStrokedShape(
+ new Line2D.Float(left, y, right, y)
+ )));
+ }
+ }
+
+ return res;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java b/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java
new file mode 100644
index 0000000..be5762a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.LineMetrics;
+import java.awt.font.GraphicAttribute;
+import java.awt.Font;
+import java.util.HashMap;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class operates with an arbitrary text string which can include
+ * any number of style, font and direction runs. It is responsible for computation
+ * of the text metrics, such as ascent, descent, leading and advance. Actually,
+ * each text run segment contains logic which allows it to compute its own metrics and
+ * responsibility of this class is to combine metrics for all segments included in the text,
+ * managed by the associated TextRunBreaker object.
+ */
+public class TextMetricsCalculator {
+ TextRunBreaker breaker; // Associated run breaker
+
+ // Metrics
+ float ascent = 0;
+ float descent = 0;
+ float leading = 0;
+ float advance = 0;
+
+ private float baselineOffsets[];
+ int baselineIndex;
+
+ public TextMetricsCalculator(TextRunBreaker breaker) {
+ this.breaker = breaker;
+ checkBaselines();
+ }
+
+ /**
+ * Returns either values cached by checkBaselines method or reasonable
+ * values for the TOP and BOTTOM alignments.
+ * @param baselineIndex - baseline index
+ * @return baseline offset
+ */
+ float getBaselineOffset(int baselineIndex) {
+ if (baselineIndex >= 0) {
+ return baselineOffsets[baselineIndex];
+ } else if (baselineIndex == GraphicAttribute.BOTTOM_ALIGNMENT) {
+ return descent;
+ } else if (baselineIndex == GraphicAttribute.TOP_ALIGNMENT) {
+ return -ascent;
+ } else {
+ // awt.3F=Invalid baseline index
+ throw new IllegalArgumentException(Messages.getString("awt.3F")); //$NON-NLS-1$
+ }
+ }
+
+ public float[] getBaselineOffsets() {
+ float ret[] = new float[baselineOffsets.length];
+ System.arraycopy(baselineOffsets, 0, ret, 0, baselineOffsets.length);
+ return ret;
+ }
+
+ /**
+ * Take baseline offsets from the first font or graphic attribute
+ * and normalizes them, than caches the results.
+ */
+ public void checkBaselines() {
+ // Take baseline offsets of the first font and normalize them
+ HashMap<Integer, Font> fonts = breaker.fonts;
+
+ Object val = fonts.get(new Integer(0));
+
+ if (val instanceof Font) {
+ Font firstFont = (Font) val;
+ LineMetrics lm = firstFont.getLineMetrics(breaker.text, 0, 1, breaker.frc);
+ baselineOffsets = lm.getBaselineOffsets();
+ baselineIndex = lm.getBaselineIndex();
+ } else if (val instanceof GraphicAttribute) {
+ // Get first graphic attribute and use it
+ GraphicAttribute ga = (GraphicAttribute) val;
+
+ int align = ga.getAlignment();
+
+ if (
+ align == GraphicAttribute.TOP_ALIGNMENT ||
+ align == GraphicAttribute.BOTTOM_ALIGNMENT
+ ) {
+ baselineIndex = GraphicAttribute.ROMAN_BASELINE;
+ } else {
+ baselineIndex = align;
+ }
+
+ baselineOffsets = new float[3];
+ baselineOffsets[0] = 0;
+ baselineOffsets[1] = (ga.getDescent() - ga.getAscent()) / 2.f;
+ baselineOffsets[2] = -ga.getAscent();
+ } else { // Use defaults - Roman baseline and zero offsets
+ baselineIndex = GraphicAttribute.ROMAN_BASELINE;
+ baselineOffsets = new float[3];
+ }
+
+ // Normalize offsets if needed
+ if (baselineOffsets[baselineIndex] != 0) {
+ float baseOffset = baselineOffsets[baselineIndex];
+ for (int i = 0; i < baselineOffsets.length; i++) {
+ baselineOffsets[i] -= baseOffset;
+ }
+ }
+ }
+
+ /**
+ * Computes metrics for the text managed by the associated TextRunBreaker
+ */
+ void computeMetrics() {
+
+ ArrayList<TextRunSegment> segments = breaker.runSegments;
+
+ float maxHeight = 0;
+ float maxHeightLeading = 0;
+
+ for (int i = 0; i < segments.size(); i++) {
+ TextRunSegment segment = segments.get(i);
+ BasicMetrics metrics = segment.metrics;
+ int baseline = metrics.baseLineIndex;
+
+ if (baseline >= 0) {
+ float baselineOffset = baselineOffsets[metrics.baseLineIndex];
+ float fixedDescent = metrics.descent + baselineOffset;
+
+ ascent = Math.max(ascent, metrics.ascent - baselineOffset);
+ descent = Math.max(descent, fixedDescent);
+ leading = Math.max(leading, fixedDescent + metrics.leading);
+ } else { // Position is not fixed by the baseline, need sum of ascent and descent
+ float height = metrics.ascent + metrics.descent;
+
+ maxHeight = Math.max(maxHeight, height);
+ maxHeightLeading = Math.max(maxHeightLeading, height + metrics.leading);
+ }
+ }
+
+ // Need to increase sizes for graphics?
+ if (maxHeightLeading != 0) {
+ descent = Math.max(descent, maxHeight - ascent);
+ leading = Math.max(leading, maxHeightLeading - ascent);
+ }
+
+ // Normalize leading
+ leading -= descent;
+
+ BasicMetrics currMetrics;
+ float currAdvance = 0;
+
+ for (int i = 0; i < segments.size(); i++) {
+ TextRunSegment segment = segments.get(breaker.getSegmentFromVisualOrder(i));
+ currMetrics = segment.metrics;
+
+ segment.y = getBaselineOffset(currMetrics.baseLineIndex)
+ + currMetrics.superScriptOffset;
+ segment.x = currAdvance;
+
+ currAdvance += segment.getAdvance();
+ }
+
+ advance = currAdvance;
+ }
+
+ /**
+ * Computes metrics and creates BasicMetrics object from them
+ * @return basic metrics
+ */
+ public BasicMetrics createMetrics() {
+ computeMetrics();
+ return new BasicMetrics(this);
+ }
+
+ /**
+ * Corrects advance after justification. Gets BasicMetrics object
+ * and updates advance stored into it.
+ * @param metrics - metrics with outdated advance which should be corrected
+ */
+ public void correctAdvance(BasicMetrics metrics) {
+ ArrayList<TextRunSegment> segments = breaker.runSegments;
+ TextRunSegment segment = segments.get(breaker
+ .getSegmentFromVisualOrder(segments.size() - 1));
+
+ advance = segment.x + segment.getAdvance();
+ metrics.advance = advance;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java b/awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java
new file mode 100644
index 0000000..be606f7
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextRunBreaker.java
@@ -0,0 +1,861 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+import java.awt.im.InputMethodHighlight;
+import java.awt.font.*;
+import java.awt.*;
+import java.text.AttributedCharacterIterator;
+import java.text.Annotation;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.*;
+
+import org.apache.harmony.awt.gl.font.TextDecorator.Decoration;
+import org.apache.harmony.awt.internal.nls.Messages;
+import org.apache.harmony.misc.HashCode;
+// TODO - bidi not implemented yet
+
+/**
+ * This class is responsible for breaking the text into the run segments
+ * with constant font, style, other text attributes and direction.
+ * It also stores the created text run segments and covers functionality
+ * related to the operations on the set of segments, like calculating metrics,
+ * rendering, justification, hit testing, etc.
+ */
+public class TextRunBreaker implements Cloneable {
+ AttributedCharacterIterator aci;
+ FontRenderContext frc;
+
+ char[] text;
+
+ byte[] levels;
+
+ HashMap<Integer, Font> fonts;
+ HashMap<Integer, Decoration> decorations;
+
+ // Related to default font substitution
+ int forcedFontRunStarts[];
+
+ ArrayList<TextRunSegment> runSegments = new ArrayList<TextRunSegment>();
+
+ // For fast retrieving of the segment containing
+ // character with known logical index
+ int logical2segment[];
+ int segment2visual[]; // Visual order of segments TODO - implement
+ int visual2segment[];
+ int logical2visual[];
+ int visual2logical[];
+
+ SegmentsInfo storedSegments;
+ private boolean haveAllSegments = false;
+ int segmentsStart, segmentsEnd;
+
+ float justification = 1.0f;
+
+ public TextRunBreaker(AttributedCharacterIterator aci, FontRenderContext frc) {
+ this.aci = aci;
+ this.frc = frc;
+
+ segmentsStart = aci.getBeginIndex();
+ segmentsEnd = aci.getEndIndex();
+
+ int len = segmentsEnd - segmentsStart;
+ text = new char[len];
+ aci.setIndex(segmentsEnd);
+ while (len-- != 0) { // Going in backward direction is faster? Simplier checks here?
+ text[len] = aci.previous();
+ }
+
+ createStyleRuns();
+ }
+
+ /**
+ * Visual order of text segments may differ from the logical order.
+ * This method calculates visual position of the segment from its logical position.
+ * @param segmentNum - logical position of the segment
+ * @return visual position of the segment
+ */
+ int getVisualFromSegmentOrder(int segmentNum) {
+ return (segment2visual == null) ? segmentNum : segment2visual[segmentNum];
+ }
+
+ /**
+ * Visual order of text segments may differ from the logical order.
+ * This method calculates logical position of the segment from its visual position.
+ * @param visual - visual position of the segment
+ * @return logical position of the segment
+ */
+ int getSegmentFromVisualOrder(int visual) {
+ return (visual2segment == null) ? visual : visual2segment[visual];
+ }
+
+ /**
+ * Visual order of the characters may differ from the logical order.
+ * This method calculates visual position of the character from its logical position.
+ * @param logical - logical position of the character
+ * @return visual position
+ */
+ int getVisualFromLogical(int logical) {
+ return (logical2visual == null) ? logical : logical2visual[logical];
+ }
+
+ /**
+ * Visual order of the characters may differ from the logical order.
+ * This method calculates logical position of the character from its visual position.
+ * @param visual - visual position
+ * @return logical position
+ */
+ int getLogicalFromVisual(int visual) {
+ return (visual2logical == null) ? visual : visual2logical[visual];
+ }
+
+ /**
+ * Calculates the end index of the level run, limited by the given text run.
+ * @param runStart - run start
+ * @param runEnd - run end
+ * @return end index of the level run
+ */
+ int getLevelRunLimit(int runStart, int runEnd) {
+ if (levels == null) {
+ return runEnd;
+ }
+ int endLevelRun = runStart + 1;
+ byte level = levels[runStart];
+
+ while (endLevelRun <= runEnd && levels[endLevelRun] == level) {
+ endLevelRun++;
+ }
+
+ return endLevelRun;
+ }
+
+ /**
+ * Adds InputMethodHighlight to the attributes
+ * @param attrs - text attributes
+ * @return patched text attributes
+ */
+ Map<? extends Attribute, ?> unpackAttributes(Map<? extends Attribute, ?> attrs) {
+ if (attrs.containsKey(TextAttribute.INPUT_METHOD_HIGHLIGHT)) {
+ Map<TextAttribute, ?> styles = null;
+
+ Object val = attrs.get(TextAttribute.INPUT_METHOD_HIGHLIGHT);
+
+ if (val instanceof Annotation) {
+ val = ((Annotation) val).getValue();
+ }
+
+ if (val instanceof InputMethodHighlight) {
+ InputMethodHighlight ihl = ((InputMethodHighlight) val);
+ styles = ihl.getStyle();
+
+ if (styles == null) {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ styles = tk.mapInputMethodHighlight(ihl);
+ }
+ }
+
+ if (styles != null) {
+ HashMap<Attribute, Object> newAttrs = new HashMap<Attribute, Object>();
+ newAttrs.putAll(attrs);
+ newAttrs.putAll(styles);
+ return newAttrs;
+ }
+ }
+
+ return attrs;
+ }
+
+ /**
+ * Breaks the text into separate style runs.
+ */
+ void createStyleRuns() {
+ // TODO - implement fast and simple case
+ fonts = new HashMap<Integer, Font>();
+ decorations = new HashMap<Integer, Decoration>();
+ ////
+
+ ArrayList<Integer> forcedFontRunStartsList = null;
+
+ Map<? extends Attribute, ?> attributes = null;
+
+ // Check justification attribute
+ Object val = aci.getAttribute(TextAttribute.JUSTIFICATION);
+ if (val != null) {
+ justification = ((Float) val).floatValue();
+ }
+
+ for (
+ int index = segmentsStart, nextRunStart = segmentsStart;
+ index < segmentsEnd;
+ index = nextRunStart, aci.setIndex(index)
+ ) {
+ nextRunStart = aci.getRunLimit();
+ attributes = unpackAttributes(aci.getAttributes());
+
+ TextDecorator.Decoration d = TextDecorator.getDecoration(attributes);
+ decorations.put(new Integer(index), d);
+
+ // Find appropriate font or place GraphicAttribute there
+
+ // 1. Try to pick up CHAR_REPLACEMENT (compatibility)
+ Font value = (Font)attributes.get(TextAttribute.CHAR_REPLACEMENT);
+
+ if (value == null) {
+ // 2. Try to Get FONT
+ value = (Font)attributes.get(TextAttribute.FONT);
+
+ if (value == null) {
+ // 3. Try to create font from FAMILY
+ if (attributes.get(TextAttribute.FAMILY) != null) {
+ value = Font.getFont(attributes);
+ }
+
+ if (value == null) {
+ // 4. No attributes found, using default.
+ if (forcedFontRunStartsList == null) {
+ forcedFontRunStartsList = new ArrayList<Integer>();
+ }
+ FontFinder.findFonts(
+ text,
+ index,
+ nextRunStart,
+ forcedFontRunStartsList,
+ fonts
+ );
+ value = fonts.get(new Integer(index));
+ }
+ }
+ }
+
+ fonts.put(new Integer(index), value);
+ }
+
+ // We have added some default fonts, so we have some extra runs in text
+ if (forcedFontRunStartsList != null) {
+ forcedFontRunStarts = new int[forcedFontRunStartsList.size()];
+ for (int i=0; i<forcedFontRunStartsList.size(); i++) {
+ forcedFontRunStarts[i] =
+ forcedFontRunStartsList.get(i).intValue();
+ }
+ }
+ }
+
+ /**
+ * Starting from the current position looks for the end of the text run with
+ * constant text attributes.
+ * @param runStart - start position
+ * @param maxPos - position where to stop if no run limit found
+ * @return style run limit
+ */
+ int getStyleRunLimit(int runStart, int maxPos) {
+ try {
+ aci.setIndex(runStart);
+ } catch(IllegalArgumentException e) { // Index out of bounds
+ if (runStart < segmentsStart) {
+ aci.first();
+ } else {
+ aci.last();
+ }
+ }
+
+ // If we have some extra runs we need to check for their limits
+ if (forcedFontRunStarts != null) {
+ for (int element : forcedFontRunStarts) {
+ if (element > runStart) {
+ maxPos = Math.min(element, maxPos);
+ break;
+ }
+ }
+ }
+
+ return Math.min(aci.getRunLimit(), maxPos);
+ }
+
+ /**
+ * Creates segments for the text run with
+ * constant decoration, font and bidi level
+ * @param runStart - run start
+ * @param runEnd - run end
+ */
+ public void createSegments(int runStart, int runEnd) {
+ int endStyleRun, endLevelRun;
+
+ // TODO - update levels
+
+ int pos = runStart, levelPos;
+
+ aci.setIndex(pos);
+ final int firstRunStart = aci.getRunStart();
+ Object tdd = decorations.get(new Integer(firstRunStart));
+ Object fontOrGAttr = fonts.get(new Integer(firstRunStart));
+
+ logical2segment = new int[runEnd - runStart];
+
+ do {
+ endStyleRun = getStyleRunLimit(pos, runEnd);
+
+ // runStart can be non-zero, but all arrays will be indexed from 0
+ int ajustedPos = pos - runStart;
+ int ajustedEndStyleRun = endStyleRun - runStart;
+ levelPos = ajustedPos;
+ do {
+ endLevelRun = getLevelRunLimit(levelPos, ajustedEndStyleRun);
+
+ if (fontOrGAttr instanceof GraphicAttribute) {
+ runSegments.add(
+ new TextRunSegmentImpl.TextRunSegmentGraphic(
+ (GraphicAttribute)fontOrGAttr,
+ endLevelRun - levelPos,
+ levelPos + runStart)
+ );
+ Arrays.fill(logical2segment, levelPos, endLevelRun, runSegments.size()-1);
+ } else {
+ TextRunSegmentImpl.TextSegmentInfo i =
+ new TextRunSegmentImpl.TextSegmentInfo(
+ levels == null ? 0 : levels[ajustedPos],
+ (Font) fontOrGAttr,
+ frc,
+ text,
+ levelPos + runStart,
+ endLevelRun + runStart
+ );
+
+ runSegments.add(
+ new TextRunSegmentImpl.TextRunSegmentCommon(
+ i,
+ (TextDecorator.Decoration) tdd
+ )
+ );
+ Arrays.fill(logical2segment, levelPos, endLevelRun, runSegments.size()-1);
+ }
+
+ levelPos = endLevelRun;
+ } while (levelPos < ajustedEndStyleRun);
+
+ // Prepare next iteration
+ pos = endStyleRun;
+ tdd = decorations.get(new Integer(pos));
+ fontOrGAttr = fonts.get(new Integer(pos));
+ } while (pos < runEnd);
+ }
+
+ /**
+ * Checks if text run segments are up to date and creates the new segments if not.
+ */
+ public void createAllSegments() {
+ if ( !haveAllSegments &&
+ (logical2segment == null ||
+ logical2segment.length != segmentsEnd - segmentsStart)
+ ) { // Check if we don't have all segments yet
+ resetSegments();
+ createSegments(segmentsStart, segmentsEnd);
+ }
+
+ haveAllSegments = true;
+ }
+
+ /**
+ * Calculates position where line should be broken without
+ * taking into account word boundaries.
+ * @param start - start index
+ * @param maxAdvance - maximum advance, width of the line
+ * @return position where to break
+ */
+ public int getLineBreakIndex(int start, float maxAdvance) {
+ int breakIndex;
+ TextRunSegment s = null;
+
+ for (
+ int segmentIndex = logical2segment[start];
+ segmentIndex < runSegments.size();
+ segmentIndex++
+ ) {
+ s = runSegments.get(segmentIndex);
+ breakIndex = s.getCharIndexFromAdvance(maxAdvance, start);
+
+ if (breakIndex < s.getEnd()) {
+ return breakIndex;
+ }
+ maxAdvance -= s.getAdvanceDelta(start, s.getEnd());
+ start = s.getEnd();
+ }
+
+ return s.getEnd();
+ }
+
+ /**
+ * Inserts character into the managed text.
+ * @param newParagraph - new character iterator
+ * @param insertPos - insertion position
+ */
+ public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) {
+ aci = newParagraph;
+
+ char insChar = aci.setIndex(insertPos);
+
+ Integer key = new Integer(insertPos);
+
+ insertPos -= aci.getBeginIndex();
+
+ char newText[] = new char[text.length + 1];
+ System.arraycopy(text, 0, newText, 0, insertPos);
+ newText[insertPos] = insChar;
+ System.arraycopy(text, insertPos, newText, insertPos+1, text.length - insertPos);
+ text = newText;
+
+ if (aci.getRunStart() == key.intValue() && aci.getRunLimit() == key.intValue() + 1) {
+ createStyleRuns(); // We have to create one new run, could be optimized
+ } else {
+ shiftStyleRuns(key, 1);
+ }
+
+ resetSegments();
+
+ segmentsEnd++;
+ }
+
+ /**
+ * Deletes character from the managed text.
+ * @param newParagraph - new character iterator
+ * @param deletePos - deletion position
+ */
+ public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) {
+ aci = newParagraph;
+
+ Integer key = new Integer(deletePos);
+
+ deletePos -= aci.getBeginIndex();
+
+ char newText[] = new char[text.length - 1];
+ System.arraycopy(text, 0, newText, 0, deletePos);
+ System.arraycopy(text, deletePos+1, newText, deletePos, newText.length - deletePos);
+ text = newText;
+
+ if (fonts.get(key) != null) {
+ fonts.remove(key);
+ }
+
+ shiftStyleRuns(key, -1);
+
+ resetSegments();
+
+ segmentsEnd--;
+ }
+
+ /**
+ * Shift all runs after specified position, needed to perfom insertion
+ * or deletion in the managed text
+ * @param pos - position where to start
+ * @param shift - shift, could be negative
+ */
+ private void shiftStyleRuns(Integer pos, final int shift) {
+ ArrayList<Integer> keys = new ArrayList<Integer>();
+
+ Integer key, oldkey;
+ for (Iterator<Integer> it = fonts.keySet().iterator(); it.hasNext(); ) {
+ oldkey = it.next();
+ if (oldkey.intValue() > pos.intValue()) {
+ keys.add(oldkey);
+ }
+ }
+
+ for (int i=0; i<keys.size(); i++) {
+ oldkey = keys.get(i);
+ key = new Integer(shift + oldkey.intValue());
+ fonts.put(key, fonts.remove(oldkey));
+ decorations.put(key, decorations.remove(oldkey));
+ }
+ }
+
+ /**
+ * Resets state of the class
+ */
+ private void resetSegments() {
+ runSegments = new ArrayList<TextRunSegment>();
+ logical2segment = null;
+ segment2visual = null;
+ visual2segment = null;
+ levels = null;
+ haveAllSegments = false;
+ }
+
+ private class SegmentsInfo {
+ ArrayList<TextRunSegment> runSegments;
+ int logical2segment[];
+ int segment2visual[];
+ int visual2segment[];
+ byte levels[];
+ int segmentsStart;
+ int segmentsEnd;
+ }
+
+ /**
+ * Saves the internal state of the class
+ * @param newSegStart - new start index in the text
+ * @param newSegEnd - new end index in the text
+ */
+ public void pushSegments(int newSegStart, int newSegEnd) {
+ storedSegments = new SegmentsInfo();
+ storedSegments.runSegments = this.runSegments;
+ storedSegments.logical2segment = this.logical2segment;
+ storedSegments.segment2visual = this.segment2visual;
+ storedSegments.visual2segment = this.visual2segment;
+ storedSegments.levels = this.levels;
+ storedSegments.segmentsStart = segmentsStart;
+ storedSegments.segmentsEnd = segmentsEnd;
+
+ resetSegments();
+
+ segmentsStart = newSegStart;
+ segmentsEnd = newSegEnd;
+ }
+
+ /**
+ * Restores the internal state of the class
+ */
+ public void popSegments() {
+ if (storedSegments == null) {
+ return;
+ }
+
+ this.runSegments = storedSegments.runSegments;
+ this.logical2segment = storedSegments.logical2segment;
+ this.segment2visual = storedSegments.segment2visual;
+ this.visual2segment = storedSegments.visual2segment;
+ this.levels = storedSegments.levels;
+ this.segmentsStart = storedSegments.segmentsStart;
+ this.segmentsEnd = storedSegments.segmentsEnd;
+ storedSegments = null;
+
+ if (runSegments.size() == 0 && logical2segment == null) {
+ haveAllSegments = false;
+ } else {
+ haveAllSegments = true;
+ }
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ TextRunBreaker res = (TextRunBreaker) super.clone();
+ res.storedSegments = null;
+ ArrayList<TextRunSegment> newSegments = new ArrayList<TextRunSegment>(runSegments.size());
+ for (int i = 0; i < runSegments.size(); i++) {
+ TextRunSegment seg = runSegments.get(i);
+ newSegments.add((TextRunSegment)seg.clone());
+ }
+ res.runSegments = newSegments;
+ return res;
+ } catch (CloneNotSupportedException e) {
+ // awt.3E=Clone not supported
+ throw new UnsupportedOperationException(Messages.getString("awt.3E")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof TextRunBreaker)) {
+ return false;
+ }
+
+ TextRunBreaker br = (TextRunBreaker) obj;
+
+ if (br.getACI().equals(aci) && br.frc.equals(frc)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCode.combine(aci.hashCode(), frc.hashCode());
+ }
+
+ /**
+ * Renders the managed text
+ * @param g2d - graphics where to render
+ * @param xOffset - offset in X direction to the upper left corner
+ * of the layout from the origin of the graphics
+ * @param yOffset - offset in Y direction to the upper left corner
+ * of the layout from the origin of the graphics
+ */
+ public void drawSegments(Graphics2D g2d, float xOffset, float yOffset) {
+ for (int i=0; i<runSegments.size(); i++) {
+ runSegments.get(i).draw(g2d, xOffset, yOffset);
+ }
+ }
+
+ /**
+ * Creates the black box bounds shape
+ * @param firstEndpoint - start position
+ * @param secondEndpoint - end position
+ * @return black box bounds shape
+ */
+ public Shape getBlackBoxBounds(int firstEndpoint, int secondEndpoint) {
+ GeneralPath bounds = new GeneralPath();
+
+ TextRunSegment segment;
+
+ for (int idx = firstEndpoint; idx < secondEndpoint; idx=segment.getEnd()) {
+ segment = runSegments.get(logical2segment[idx]);
+ bounds.append(segment.getCharsBlackBoxBounds(idx, secondEndpoint), false);
+ }
+
+ return bounds;
+ }
+
+ /**
+ * Creates visual bounds shape
+ * @return visual bounds rectangle
+ */
+ public Rectangle2D getVisualBounds() {
+ Rectangle2D bounds = null;
+
+ for (int i=0; i<runSegments.size(); i++) {
+ TextRunSegment s = runSegments.get(i);
+ if (bounds != null) {
+ Rectangle2D.union(bounds, s.getVisualBounds(), bounds);
+ } else {
+ bounds = s.getVisualBounds();
+ }
+ }
+
+ return bounds;
+ }
+
+ /**
+ * Creates logical bounds shape
+ * @return logical bounds rectangle
+ */
+ public Rectangle2D getLogicalBounds() {
+ Rectangle2D bounds = null;
+
+ for (int i=0; i<runSegments.size(); i++) {
+ TextRunSegment s = runSegments.get(i);
+ if (bounds != null) {
+ Rectangle2D.union(bounds, s.getLogicalBounds(), bounds);
+ } else {
+ bounds = s.getLogicalBounds();
+ }
+ }
+
+ return bounds;
+ }
+
+ public int getCharCount() {
+ return segmentsEnd - segmentsStart;
+ }
+
+ public byte getLevel(int idx) {
+ if (levels == null) {
+ return 0;
+ }
+ return levels[idx];
+ }
+
+ public int getBaseLevel() {
+ return 0;
+ }
+
+ public boolean isLTR() {
+ return true;
+ }
+
+ public char getChar(int index) {
+ return text[index];
+ }
+
+ public AttributedCharacterIterator getACI() {
+ return aci;
+ }
+
+ /**
+ * Creates outline shape for the managed text
+ * @return outline
+ */
+ public GeneralPath getOutline() {
+ GeneralPath outline = new GeneralPath();
+
+ TextRunSegment segment;
+
+ for (int i = 0; i < runSegments.size(); i++) {
+ segment = runSegments.get(i);
+ outline.append(segment.getOutline(), false);
+ }
+
+ return outline;
+ }
+
+ /**
+ * Calculates text hit info from the screen coordinates.
+ * Current implementation totally ignores Y coordinate.
+ * If X coordinate is outside of the layout boundaries, this
+ * method returns leftmost or rightmost hit.
+ * @param x - x coordinate of the hit
+ * @param y - y coordinate of the hit
+ * @return hit info
+ */
+ public TextHitInfo hitTest(float x, float y) {
+ TextRunSegment segment;
+
+ double endOfPrevSeg = -1;
+ for (int i = 0; i < runSegments.size(); i++) {
+ segment = runSegments.get(i);
+ Rectangle2D bounds = segment.getVisualBounds();
+ if ((bounds.getMinX() <= x && bounds.getMaxX() >= x) || // We are in the segment
+ (endOfPrevSeg < x && bounds.getMinX() > x)) { // We are somewhere between the segments
+ return segment.hitTest(x,y);
+ }
+ endOfPrevSeg = bounds.getMaxX();
+ }
+
+ return isLTR() ? TextHitInfo.trailing(text.length) : TextHitInfo.leading(0);
+ }
+
+ public float getJustification() {
+ return justification;
+ }
+
+ /**
+ * Calculates position of the last non whitespace character
+ * in the managed text.
+ * @return position of the last non whitespace character
+ */
+ public int getLastNonWhitespace() {
+ int lastNonWhitespace = text.length;
+
+ while (lastNonWhitespace >= 0) {
+ lastNonWhitespace--;
+ if (!Character.isWhitespace(text[lastNonWhitespace])) {
+ break;
+ }
+ }
+
+ return lastNonWhitespace;
+ }
+
+ /**
+ * Performs justification of the managed text by changing segment positions
+ * and positions of the glyphs inside of the segments.
+ * @param gap - amount of space which should be compensated by justification
+ */
+ public void justify(float gap) {
+ // Ignore trailing logical whitespace
+ int firstIdx = segmentsStart;
+ int lastIdx = getLastNonWhitespace() + segmentsStart;
+ JustificationInfo jInfos[] = new JustificationInfo[5];
+ float gapLeft = gap;
+
+ int highestPriority = -1;
+ // GlyphJustificationInfo.PRIORITY_KASHIDA is 0
+ // GlyphJustificationInfo.PRIORITY_NONE is 3
+ for (int priority = 0; priority <= GlyphJustificationInfo.PRIORITY_NONE + 1; priority++) {
+ JustificationInfo jInfo = new JustificationInfo();
+ jInfo.lastIdx = lastIdx;
+ jInfo.firstIdx = firstIdx;
+ jInfo.grow = gap > 0;
+ jInfo.gapToFill = gapLeft;
+
+ if (priority <= GlyphJustificationInfo.PRIORITY_NONE) {
+ jInfo.priority = priority;
+ } else {
+ jInfo.priority = highestPriority; // Last pass
+ }
+
+ for (int i = 0; i < runSegments.size(); i++) {
+ TextRunSegment segment = runSegments.get(i);
+ if (segment.getStart() <= lastIdx) {
+ segment.updateJustificationInfo(jInfo);
+ }
+ }
+
+ if (jInfo.priority == highestPriority) {
+ jInfo.absorb = true;
+ jInfo.absorbedWeight = jInfo.weight;
+ }
+
+ if (jInfo.weight != 0) {
+ if (highestPriority < 0) {
+ highestPriority = priority;
+ }
+ jInfos[priority] = jInfo;
+ } else {
+ continue;
+ }
+
+ gapLeft -= jInfo.growLimit;
+
+ if (((gapLeft > 0) ^ jInfo.grow) || gapLeft == 0) {
+ gapLeft = 0;
+ jInfo.gapPerUnit = jInfo.gapToFill/jInfo.weight;
+ break;
+ }
+ jInfo.useLimits = true;
+
+ if (jInfo.absorbedWeight > 0) {
+ jInfo.absorb = true;
+ jInfo.absorbedGapPerUnit =
+ (jInfo.gapToFill-jInfo.growLimit)/jInfo.absorbedWeight;
+ break;
+ }
+ }
+
+ float currJustificationOffset = 0;
+ for (int i = 0; i < runSegments.size(); i++) {
+ TextRunSegment segment =
+ runSegments.get(getSegmentFromVisualOrder(i));
+ segment.x += currJustificationOffset;
+ currJustificationOffset += segment.doJustification(jInfos);
+ }
+
+ justification = -1; // Make further justification impossible
+ }
+
+ /**
+ * This class represents the information collected before the actual
+ * justification is started and needed to perform the justification.
+ * This information is closely related to the information stored in the
+ * GlyphJustificationInfo for the text represented by glyph vectors.
+ */
+ class JustificationInfo {
+ boolean grow;
+ boolean absorb = false;
+ boolean useLimits = false;
+ int priority = 0;
+ float weight = 0;
+ float absorbedWeight = 0;
+ float growLimit = 0;
+
+ int lastIdx;
+ int firstIdx;
+
+ float gapToFill;
+
+ float gapPerUnit = 0; // Precalculated value, gapToFill / weight
+ float absorbedGapPerUnit = 0; // Precalculated value, gapToFill / weight
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextRunSegment.java b/awt/org/apache/harmony/awt/gl/font/TextRunSegment.java
new file mode 100644
index 0000000..1cd2c05
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextRunSegment.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.font.TextHitInfo;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Abstract class which represents the segment of the text with constant attributes
+ * running in one direction (i.e. constant level).
+ */
+public abstract class TextRunSegment implements Cloneable {
+ float x; // Calculated x location of this segment on the screen
+ float y; // Calculated y location of this segment on the screen
+
+ BasicMetrics metrics; // Metrics of this text run segment
+ TextDecorator.Decoration decoration; // Underline, srikethrough, etc.
+ Rectangle2D logicalBounds = null; // Logical bounding box for the segment
+ Rectangle2D visualBounds = null; // Visual bounding box for the segment
+
+ /**
+ * Returns start index of the segment
+ * @return start index
+ */
+ abstract int getStart();
+
+ /**
+ * Returns end index of the segment
+ * @return end index
+ */
+ abstract int getEnd();
+
+ /**
+ * Returns the number of characters in the segment
+ * @return number of characters
+ */
+ abstract int getLength();
+
+ /**
+ * Renders this text run segment
+ * @param g2d - graphics to render to
+ * @param xOffset - X offset from the graphics origin to the
+ * origin of the text layout
+ * @param yOffset - Y offset from the graphics origin to the
+ * origin of the text layout
+ */
+ abstract void draw(Graphics2D g2d, float xOffset, float yOffset);
+
+ /**
+ * Creates black box bounds shape for the specified range
+ * @param start - range sart
+ * @param limit - range end
+ * @return black box bounds shape
+ */
+ abstract Shape getCharsBlackBoxBounds(int start, int limit);
+
+ /**
+ * Returns the outline shape
+ * @return outline
+ */
+ abstract Shape getOutline();
+
+ /**
+ * Returns visual bounds of this segment
+ * @return visual bounds
+ */
+ abstract Rectangle2D getVisualBounds();
+
+ /**
+ * Returns logical bounds of this segment
+ * @return logical bounds
+ */
+ abstract Rectangle2D getLogicalBounds();
+
+ /**
+ * Calculates advance of the segment
+ * @return advance
+ */
+ abstract float getAdvance();
+
+ /**
+ * Calculates advance delta between two characters
+ * @param start - 1st position
+ * @param end - 2nd position
+ * @return advance increment between specified positions
+ */
+ abstract float getAdvanceDelta(int start, int end);
+
+ /**
+ * Calculates index of the character which advance is equal to
+ * the given. If the given advance is greater then the segment
+ * advance it returns the position after the last character.
+ * @param advance - given advance
+ * @param start - character, from which to start measuring advance
+ * @return character index
+ */
+ abstract int getCharIndexFromAdvance(float advance, int start);
+
+ /**
+ * Checks if the character doesn't contribute to the text advance
+ * @param index - character index
+ * @return true if the character has zero advance
+ */
+ abstract boolean charHasZeroAdvance(int index);
+
+ /**
+ * Calculates position of the character on the screen
+ * @param index - character index
+ * @return X coordinate of the character position
+ */
+ abstract float getCharPosition(int index);
+
+ /**
+ * Returns the advance of the individual character
+ * @param index - character index
+ * @return character advance
+ */
+ abstract float getCharAdvance(int index);
+
+ /**
+ * Creates text hit info from the hit position
+ * @param x - X coordinate relative to the origin of the layout
+ * @param y - Y coordinate relative to the origin of the layout
+ * @return hit info
+ */
+ abstract TextHitInfo hitTest(float x, float y);
+
+ /**
+ * Collects justification information into JustificationInfo object
+ * @param jInfo - JustificationInfo object
+ */
+ abstract void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo);
+
+ /**
+ * Performs justification of the segment.
+ * Updates positions of individual characters.
+ * @param jInfos - justification information, gathered by the previous passes
+ * @return amount of growth or shrink of the segment
+ */
+ abstract float doJustification(TextRunBreaker.JustificationInfo jInfos[]);
+
+ @Override
+ public abstract Object clone();
+}
diff --git a/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java b/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java
new file mode 100644
index 0000000..0ec2d05
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java
@@ -0,0 +1,979 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+// XXX - TODO - bidi not implemented yet
+//import java.text.Bidi;
+import java.util.Arrays;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Date: Apr 25, 2005
+ * Time: 4:33:18 PM
+ *
+ * This class contains the implementation of the behavior of the
+ * text run segment with constant text attributes and direction.
+ */
+public class TextRunSegmentImpl {
+
+ /**
+ * This class contains basic information required for creation
+ * of the glyph-based text run segment.
+ */
+ public static class TextSegmentInfo {
+ // XXX - TODO - bidi not implemented yet
+ //Bidi bidi;
+
+ Font font;
+ FontRenderContext frc;
+
+ char text[];
+
+ int start;
+ int end;
+ int length;
+
+ int flags = 0;
+
+ byte level = 0;
+
+ TextSegmentInfo(
+ byte level,
+ Font font, FontRenderContext frc,
+ char text[], int start, int end
+ ) {
+ this.font = font;
+ this.frc = frc;
+ this.text = text;
+ this.start = start;
+ this.end = end;
+ this.level = level;
+ length = end - start;
+ }
+ }
+
+ /**
+ * This class represents a simple text segment backed by the glyph vector
+ */
+ public static class TextRunSegmentCommon extends TextRunSegment {
+ TextSegmentInfo info;
+ private GlyphVector gv;
+ private float advanceIncrements[];
+ private int char2glyph[];
+ private GlyphJustificationInfo gjis[]; // Glyph justification info
+
+ TextRunSegmentCommon(TextSegmentInfo i, TextDecorator.Decoration d) {
+ // XXX - todo - check support bidi
+ i.flags &= ~0x09; // Clear bidi flags
+
+ if ((i.level & 0x1) != 0) {
+ i.flags |= Font.LAYOUT_RIGHT_TO_LEFT;
+ }
+
+ info = i;
+ this.decoration = d;
+
+ LineMetrics lm = i.font.getLineMetrics(i.text, i.start, i.end, i.frc);
+ this.metrics = new BasicMetrics(lm, i.font);
+
+ if (lm.getNumChars() != i.length) { // XXX todo - This should be handled
+ // awt.41=Font returned unsupported type of line metrics. This case is known, but not supported yet.
+ throw new UnsupportedOperationException(
+ Messages.getString("awt.41")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Object clone() {
+ return new TextRunSegmentCommon(info, decoration);
+ }
+
+ /**
+ * Creates glyph vector from the managed text if needed
+ * @return glyph vector
+ */
+ private GlyphVector getGlyphVector() {
+ if (gv==null) {
+ gv = info.font.layoutGlyphVector(
+ info.frc,
+ info.text,
+ info.start,
+ info.end - info.start, // NOTE: This parameter violates
+ // spec, it is count,
+ // not limit as spec states
+ info.flags
+ );
+ }
+
+ return gv;
+ }
+
+ /**
+ * Renders this text run segment
+ * @param g2d - graphics to render to
+ * @param xOffset - X offset from the graphics origin to the
+ * origin of the text layout
+ * @param yOffset - Y offset from the graphics origin to the
+ * origin of the text layout
+ */
+ @Override
+ void draw(Graphics2D g2d, float xOffset, float yOffset) {
+ if (decoration == null) {
+ g2d.drawGlyphVector(getGlyphVector(), xOffset + x, yOffset + y);
+ } else {
+ TextDecorator.prepareGraphics(this, g2d, xOffset, yOffset);
+ g2d.drawGlyphVector(getGlyphVector(), xOffset + x, yOffset + y);
+ TextDecorator.drawTextDecorations(this, g2d, xOffset, yOffset);
+ TextDecorator.restoreGraphics(decoration, g2d);
+ }
+ }
+
+ /**
+ * Returns visual bounds of this segment
+ * @return visual bounds
+ */
+ @Override
+ Rectangle2D getVisualBounds() {
+ if (visualBounds == null) {
+ visualBounds =
+ TextDecorator.extendVisualBounds(
+ this,
+ getGlyphVector().getVisualBounds(),
+ decoration
+ );
+
+ visualBounds.setRect(
+ x + visualBounds.getX(),
+ y + visualBounds.getY(),
+ visualBounds.getWidth(),
+ visualBounds.getHeight()
+ );
+ }
+
+ return (Rectangle2D) visualBounds.clone();
+ }
+
+ /**
+ * Returns logical bounds of this segment
+ * @return logical bounds
+ */
+ @Override
+ Rectangle2D getLogicalBounds() {
+ if (logicalBounds == null) {
+ logicalBounds = getGlyphVector().getLogicalBounds();
+
+ logicalBounds.setRect(
+ x + logicalBounds.getX(),
+ y + logicalBounds.getY(),
+ logicalBounds.getWidth(),
+ logicalBounds.getHeight()
+ );
+ }
+
+ return (Rectangle2D) logicalBounds.clone();
+ }
+
+ @Override
+ float getAdvance() {
+ return (float) getLogicalBounds().getWidth();
+ }
+
+ /**
+ * Attemts to map each character to the corresponding advance increment
+ */
+ void initAdvanceMapping() {
+ GlyphVector gv = getGlyphVector();
+ int charIndicies[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
+ advanceIncrements = new float[info.length];
+
+ for (int i=0; i<charIndicies.length; i++) {
+ advanceIncrements[charIndicies[i]] = gv.getGlyphMetrics(i).getAdvance();
+ }
+ }
+
+ /**
+ * Calculates advance delta between two characters
+ * @param start - 1st position
+ * @param end - 2nd position
+ * @return advance increment between specified positions
+ */
+ @Override
+ float getAdvanceDelta(int start, int end) {
+ // Get coordinates in the segment context
+ start -= info.start;
+ end -= info.start;
+
+ if (advanceIncrements == null) {
+ initAdvanceMapping();
+ }
+
+ if (start < 0) {
+ start = 0;
+ }
+ if (end > info.length) {
+ end = info.length;
+ }
+
+ float sum = 0;
+ for (int i=start; i<end; i++) {
+ sum += advanceIncrements[i];
+ }
+
+ return sum;
+ }
+
+ /**
+ * Calculates index of the character which advance is equal to
+ * the given. If the given advance is greater then the segment
+ * advance it returns the position after the last character.
+ * @param advance - given advance
+ * @param start - character, from which to start measuring advance
+ * @return character index
+ */
+ @Override
+ int getCharIndexFromAdvance(float advance, int start) {
+ // XXX - todo - probably, possible to optimize
+ // Add check if the given advance is greater then
+ // the segment advance in the beginning. In this case
+ // we don't need to run through all increments
+ if (advanceIncrements == null) {
+ initAdvanceMapping();
+ }
+
+ start -= info.start;
+
+ if (start < 0) {
+ start = 0;
+ }
+
+ int i = start;
+ for (; i<info.length; i++) {
+ advance -= advanceIncrements[i];
+ if (advance < 0) {
+ break;
+ }
+ }
+
+ return i + info.start;
+ }
+
+ @Override
+ int getStart() {
+ return info.start;
+ }
+
+ @Override
+ int getEnd() {
+ return info.end;
+ }
+
+ @Override
+ int getLength() {
+ return info.length;
+ }
+
+ /**
+ * Attemts to create mapping of the characters to glyphs in the glyph vector.
+ * @return array where for each character index stored corresponding glyph index
+ */
+ private int[] getChar2Glyph() {
+ if (char2glyph == null) {
+ GlyphVector gv = getGlyphVector();
+ char2glyph = new int[info.length];
+ Arrays.fill(char2glyph, -1);
+
+ // Fill glyph indicies for first characters corresponding to each glyph
+ int charIndicies[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null);
+ for (int i=0; i<charIndicies.length; i++) {
+ char2glyph[charIndicies[i]] = i;
+ }
+
+ // If several characters corresponds to one glyph, create mapping for them
+ // Suppose that these characters are going all together
+ int currIndex = 0;
+ for (int i=0; i<char2glyph.length; i++) {
+ if (char2glyph[i] < 0) {
+ char2glyph[i] = currIndex;
+ } else {
+ currIndex = char2glyph[i];
+ }
+ }
+ }
+
+ return char2glyph;
+ }
+
+ /**
+ * Creates black box bounds shape for the specified range
+ * @param start - range sart
+ * @param limit - range end
+ * @return black box bounds shape
+ */
+ @Override
+ Shape getCharsBlackBoxBounds(int start, int limit) {
+ start -= info.start;
+ limit -= info.start;
+
+ if (limit > info.length) {
+ limit = info.length;
+ }
+
+ GeneralPath result = new GeneralPath();
+
+ int glyphIndex = 0;
+
+ for (int i=start; i<limit; i++) {
+ glyphIndex = getChar2Glyph()[i];
+ result.append(getGlyphVector().getGlyphVisualBounds(glyphIndex), false);
+ }
+
+ // Shift to the segment's coordinates
+ result.transform(AffineTransform.getTranslateInstance(x, y));
+
+ return result;
+ }
+
+ /**
+ * Calculates position of the character on the screen
+ * @param index - character index
+ * @return X coordinate of the character position
+ */
+ @Override
+ float getCharPosition(int index) {
+ index -= info.start;
+
+ if (index > info.length) {
+ index = info.length;
+ }
+
+ float result = 0;
+
+ int glyphIndex = getChar2Glyph()[index];
+ result = (float) getGlyphVector().getGlyphPosition(glyphIndex).getX();
+
+ // Shift to the segment's coordinates
+ result += x;
+
+ return result;
+ }
+
+ /**
+ * Returns the advance of the individual character
+ * @param index - character index
+ * @return character advance
+ */
+ @Override
+ float getCharAdvance(int index) {
+ if (advanceIncrements == null) {
+ initAdvanceMapping();
+ }
+
+ return advanceIncrements[index - this.getStart()];
+ }
+
+ /**
+ * Returns the outline shape
+ * @return outline
+ */
+ @Override
+ Shape getOutline() {
+ AffineTransform t = AffineTransform.getTranslateInstance(x, y);
+ return t.createTransformedShape(
+ TextDecorator.extendOutline(
+ this,
+ getGlyphVector().getOutline(),
+ decoration
+ )
+ );
+ }
+
+ /**
+ * Checks if the character doesn't contribute to the text advance
+ * @param index - character index
+ * @return true if the character has zero advance
+ */
+ @Override
+ boolean charHasZeroAdvance(int index) {
+ if (advanceIncrements == null) {
+ initAdvanceMapping();
+ }
+
+ return advanceIncrements[index - this.getStart()] == 0;
+ }
+
+ /**
+ * Creates text hit info from the hit position
+ * @param hitX - X coordinate relative to the origin of the layout
+ * @param hitY - Y coordinate relative to the origin of the layout
+ * @return hit info
+ */
+ @Override
+ TextHitInfo hitTest(float hitX, float hitY) {
+ hitX -= x;
+
+ float glyphPositions[] =
+ getGlyphVector().getGlyphPositions(0, info.length+1, null);
+
+ int glyphIdx;
+ boolean leading = false;
+ for (glyphIdx = 1; glyphIdx <= info.length; glyphIdx++) {
+ if (glyphPositions[(glyphIdx)*2] >= hitX) {
+ float advance =
+ glyphPositions[(glyphIdx)*2] - glyphPositions[(glyphIdx-1)*2];
+ leading = glyphPositions[(glyphIdx-1)*2] + advance/2 > hitX ? true : false;
+ glyphIdx--;
+ break;
+ }
+ }
+
+ if (glyphIdx == info.length) {
+ glyphIdx--;
+ }
+
+ int charIdx = getGlyphVector().getGlyphCharIndex(glyphIdx);
+
+ return (leading) ^ ((info.level & 0x1) == 0x1)?
+ TextHitInfo.leading(charIdx + info.start) :
+ TextHitInfo.trailing(charIdx + info.start);
+ }
+
+ /**
+ * Collects GlyphJustificationInfo objects from the glyph vector
+ * @return array of all GlyphJustificationInfo objects
+ */
+ private GlyphJustificationInfo[] getGlyphJustificationInfos() {
+ if (gjis == null) {
+ GlyphVector gv = getGlyphVector();
+ int nGlyphs = gv.getNumGlyphs();
+ int charIndicies[] = gv.getGlyphCharIndices(0, nGlyphs, null);
+ gjis = new GlyphJustificationInfo[nGlyphs];
+
+ // Patch: temporary patch, getGlyphJustificationInfo is not implemented
+ float fontSize = info.font.getSize2D();
+ GlyphJustificationInfo defaultInfo =
+ new GlyphJustificationInfo(
+ 0, // weight
+ false, GlyphJustificationInfo.PRIORITY_NONE, 0, 0, // grow
+ false, GlyphJustificationInfo.PRIORITY_NONE, 0, 0); // shrink
+ GlyphJustificationInfo spaceInfo = new GlyphJustificationInfo(
+ fontSize, // weight
+ true, GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, fontSize, // grow
+ true, GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, fontSize); // shrink
+
+ ////////
+ // Temporary patch, getGlyphJustificationInfo is not implemented
+ for (int i = 0; i < nGlyphs; i++) {
+ //gjis[i] = getGlyphVector().getGlyphJustificationInfo(i);
+
+ char c = info.text[charIndicies[i] + info.start];
+ if (Character.isWhitespace(c)) {
+ gjis[i] = spaceInfo;
+ } else {
+ gjis[i] = defaultInfo;
+ }
+ // End patch
+ }
+ }
+
+ return gjis;
+ }
+
+ /**
+ * Collects justification information into JustificationInfo object
+ * @param jInfo - JustificationInfo object
+ */
+ @Override
+ void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo) {
+ int lastChar = Math.min(jInfo.lastIdx, info.end) - info.start;
+ boolean haveFirst = info.start <= jInfo.firstIdx;
+ boolean haveLast = info.end >= (jInfo.lastIdx + 1);
+
+ int prevGlyphIdx = -1;
+ int currGlyphIdx;
+
+ if (jInfo.grow) { // Check how much we can grow/shrink on current priority level
+ for (int i=0; i<lastChar; i++) {
+ currGlyphIdx = getChar2Glyph()[i];
+
+ if (currGlyphIdx == prevGlyphIdx) {
+ // Several chars could be represented by one glyph,
+ // suppose they are contiguous
+ continue;
+ }
+ prevGlyphIdx = currGlyphIdx;
+
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[currGlyphIdx];
+ if (gji.growPriority == jInfo.priority) {
+ jInfo.weight += gji.weight * 2;
+ jInfo.growLimit += gji.growLeftLimit;
+ jInfo.growLimit += gji.growRightLimit;
+ if (gji.growAbsorb) {
+ jInfo.absorbedWeight += gji.weight * 2;
+ }
+ }
+ }
+ } else {
+ for (int i=0; i<lastChar; i++) {
+ currGlyphIdx = getChar2Glyph()[i];
+ if (currGlyphIdx == prevGlyphIdx) {
+ continue;
+ }
+ prevGlyphIdx = currGlyphIdx;
+
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[currGlyphIdx];
+ if (gji.shrinkPriority == jInfo.priority) {
+ jInfo.weight += gji.weight * 2;
+ jInfo.growLimit -= gji.shrinkLeftLimit;
+ jInfo.growLimit -= gji.shrinkRightLimit;
+ if (gji.shrinkAbsorb) {
+ jInfo.absorbedWeight += gji.weight * 2;
+ }
+ }
+ }
+ }
+
+ if (haveFirst) { // Don't add padding before first char
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[getChar2Glyph()[0]];
+ jInfo.weight -= gji.weight;
+ if (jInfo.grow) {
+ jInfo.growLimit -= gji.growLeftLimit;
+ if (gji.growAbsorb) {
+ jInfo.absorbedWeight -= gji.weight;
+ }
+ } else {
+ jInfo.growLimit += gji.shrinkLeftLimit;
+ if (gji.shrinkAbsorb) {
+ jInfo.absorbedWeight -= gji.weight;
+ }
+ }
+ }
+
+ if (haveLast) { // Don't add padding after last char
+ GlyphJustificationInfo gji =
+ getGlyphJustificationInfos()[getChar2Glyph()[lastChar]];
+ jInfo.weight -= gji.weight;
+ if (jInfo.grow) {
+ jInfo.growLimit -= gji.growRightLimit;
+ if (gji.growAbsorb) {
+ jInfo.absorbedWeight -= gji.weight;
+ }
+ } else {
+ jInfo.growLimit += gji.shrinkRightLimit;
+ if (gji.shrinkAbsorb) {
+ jInfo.absorbedWeight -= gji.weight;
+ }
+ }
+ }
+ }
+
+ /**
+ * Performs justification of the segment.
+ * Updates positions of individual characters.
+ * @param jInfos - justification information, gathered by the previous passes
+ * @return amount of growth or shrink of the segment
+ */
+ @Override
+ float doJustification(TextRunBreaker.JustificationInfo jInfos[]) {
+ int lastPriority =
+ jInfos[jInfos.length-1] == null ?
+ -1 : jInfos[jInfos.length-1].priority;
+
+ // Get the highest priority
+ int highestPriority = 0;
+ for (; highestPriority<jInfos.length; highestPriority++) {
+ if (jInfos[highestPriority] != null) {
+ break;
+ }
+ }
+
+ if (highestPriority == jInfos.length) {
+ return 0;
+ }
+
+ TextRunBreaker.JustificationInfo firstInfo = jInfos[highestPriority];
+ TextRunBreaker.JustificationInfo lastInfo =
+ lastPriority > 0 ? jInfos[lastPriority] : null;
+
+ boolean haveFirst = info.start <= firstInfo.firstIdx;
+ boolean haveLast = info.end >= (firstInfo.lastIdx + 1);
+
+ // Here we suppose that GLYPHS are ordered LEFT TO RIGHT
+ int firstGlyph = haveFirst ?
+ getChar2Glyph()[firstInfo.firstIdx - info.start] :
+ getChar2Glyph()[0];
+
+ int lastGlyph = haveLast ?
+ getChar2Glyph()[firstInfo.lastIdx - info.start] :
+ getChar2Glyph()[info.length - 1];
+ if (haveLast) {
+ lastGlyph--;
+ }
+
+ TextRunBreaker.JustificationInfo currInfo;
+ float glyphOffset = 0;
+ float positionIncrement = 0;
+ float sideIncrement = 0;
+
+ if (haveFirst) { // Don't add padding before first char
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[firstGlyph];
+ currInfo = jInfos[gji.growPriority];
+ if (currInfo != null) {
+ if (currInfo.useLimits) {
+ if (currInfo.absorb) {
+ glyphOffset += gji.weight * currInfo.absorbedGapPerUnit;
+ } else if (
+ lastInfo != null &&
+ lastInfo.priority == currInfo.priority
+ ) {
+ glyphOffset += gji.weight * lastInfo.absorbedGapPerUnit;
+ }
+ glyphOffset +=
+ firstInfo.grow ?
+ gji.growRightLimit :
+ -gji.shrinkRightLimit;
+ } else {
+ glyphOffset += gji.weight * currInfo.gapPerUnit;
+ }
+ }
+
+ firstGlyph++;
+ }
+
+ if (firstInfo.grow) {
+ for (int i=firstGlyph; i<=lastGlyph; i++) {
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[i];
+ currInfo = jInfos[gji.growPriority];
+ if (currInfo == null) {
+ // We still have to increment glyph position
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+ glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(i, glyphPos);
+
+ continue;
+ }
+
+ if (currInfo.useLimits) {
+ glyphOffset += gji.growLeftLimit;
+ if (currInfo.absorb) {
+ sideIncrement = gji.weight * currInfo.absorbedGapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
+ sideIncrement = gji.weight * lastInfo.absorbedGapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ } else {
+ positionIncrement = glyphOffset;
+ }
+ glyphOffset += gji.growRightLimit;
+ } else {
+ sideIncrement = gji.weight * currInfo.gapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ }
+
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+ glyphPos.setLocation(glyphPos.getX() + positionIncrement, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(i, glyphPos);
+ }
+ } else {
+ for (int i=firstGlyph; i<=lastGlyph; i++) {
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[i];
+ currInfo = jInfos[gji.shrinkPriority];
+ if (currInfo == null) {
+ // We still have to increment glyph position
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+ glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(i, glyphPos);
+
+ continue;
+ }
+
+ if (currInfo.useLimits) {
+ glyphOffset -= gji.shrinkLeftLimit;
+ if (currInfo.absorb) {
+ sideIncrement = gji.weight * currInfo.absorbedGapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
+ sideIncrement = gji.weight * lastInfo.absorbedGapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ } else {
+ positionIncrement = glyphOffset;
+ }
+ glyphOffset -= gji.shrinkRightLimit;
+ } else {
+ sideIncrement = gji.weight * currInfo.gapPerUnit;
+ glyphOffset += sideIncrement;
+ positionIncrement = glyphOffset;
+ glyphOffset += sideIncrement;
+ }
+
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+ glyphPos.setLocation(glyphPos.getX() + positionIncrement, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(i, glyphPos);
+ }
+ }
+
+
+ if (haveLast) { // Don't add padding after last char
+ lastGlyph++;
+
+ GlyphJustificationInfo gji = getGlyphJustificationInfos()[lastGlyph];
+ currInfo = jInfos[gji.growPriority];
+
+ if (currInfo != null) {
+ if (currInfo.useLimits) {
+ glyphOffset += firstInfo.grow ? gji.growLeftLimit : -gji.shrinkLeftLimit;
+ if (currInfo.absorb) {
+ glyphOffset += gji.weight * currInfo.absorbedGapPerUnit;
+ } else if (lastInfo != null && lastInfo.priority == currInfo.priority) {
+ glyphOffset += gji.weight * lastInfo.absorbedGapPerUnit;
+ }
+ } else {
+ glyphOffset += gji.weight * currInfo.gapPerUnit;
+ }
+ }
+
+ // Ajust positions of all glyphs after last glyph
+ for (int i=lastGlyph; i<getGlyphVector().getNumGlyphs()+1; i++) {
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(i);
+ glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(i, glyphPos);
+ }
+ } else { // Update position after last glyph in glyph vector -
+ // to get correct advance for it
+ Point2D glyphPos = getGlyphVector().getGlyphPosition(lastGlyph+1);
+ glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY());
+ getGlyphVector().setGlyphPosition(lastGlyph+1, glyphPos);
+ }
+
+ gjis = null; // We don't need justification infos any more
+ // Also we have to reset cached bounds and metrics
+ this.visualBounds = null;
+ this.logicalBounds = null;
+
+ return glyphOffset; // How much our segment grown or shrunk
+ }
+ }
+
+ public static class TextRunSegmentGraphic extends TextRunSegment {
+ GraphicAttribute ga;
+ int start;
+ int length;
+ float fullAdvance;
+
+ TextRunSegmentGraphic(GraphicAttribute attr, int len, int start) {
+ this.start = start;
+ length = len;
+ ga = attr;
+ metrics = new BasicMetrics(ga);
+ fullAdvance = ga.getAdvance() * length;
+ }
+
+ @Override
+ public Object clone() {
+ return new TextRunSegmentGraphic(ga, length, start);
+ }
+
+ // Renders this text run segment
+ @Override
+ void draw(Graphics2D g2d, float xOffset, float yOffset) {
+ if (decoration != null) {
+ TextDecorator.prepareGraphics(this, g2d, xOffset, yOffset);
+ }
+
+ float xPos = x + xOffset;
+ float yPos = y + yOffset;
+
+ for (int i=0; i < length; i++) {
+ ga.draw(g2d, xPos, yPos);
+ xPos += ga.getAdvance();
+ }
+
+ if (decoration != null) {
+ TextDecorator.drawTextDecorations(this, g2d, xOffset, yOffset);
+ TextDecorator.restoreGraphics(decoration, g2d);
+ }
+ }
+
+ // Returns visual bounds of this segment
+ @Override
+ Rectangle2D getVisualBounds() {
+ if (visualBounds == null) {
+ Rectangle2D bounds = ga.getBounds();
+
+ // First and last chars can be out of logical bounds, so we calculate
+ // (bounds.getWidth() - ga.getAdvance()) which is exactly the difference
+ bounds.setRect(
+ bounds.getMinX() + x,
+ bounds.getMinY() + y,
+ bounds.getWidth() - ga.getAdvance() + getAdvance(),
+ bounds.getHeight()
+ );
+ visualBounds = TextDecorator.extendVisualBounds(this, bounds, decoration);
+ }
+
+ return (Rectangle2D) visualBounds.clone();
+ }
+
+ @Override
+ Rectangle2D getLogicalBounds() {
+ if (logicalBounds == null) {
+ logicalBounds =
+ new Rectangle2D.Float(
+ x, y - metrics.ascent,
+ getAdvance(), metrics.ascent + metrics.descent
+ );
+ }
+
+ return (Rectangle2D) logicalBounds.clone();
+ }
+
+ @Override
+ float getAdvance() {
+ return fullAdvance;
+ }
+
+ @Override
+ float getAdvanceDelta(int start, int end) {
+ return ga.getAdvance() * (end - start);
+ }
+
+ @Override
+ int getCharIndexFromAdvance(float advance, int start) {
+ start -= this.start;
+
+ if (start < 0) {
+ start = 0;
+ }
+
+ int charOffset = (int) (advance/ga.getAdvance());
+
+ if (charOffset + start > length) {
+ return length + this.start;
+ }
+ return charOffset + start + this.start;
+ }
+
+ @Override
+ int getStart() {
+ return start;
+ }
+
+ @Override
+ int getEnd() {
+ return start + length;
+ }
+
+ @Override
+ int getLength() {
+ return length;
+ }
+
+ @Override
+ Shape getCharsBlackBoxBounds(int start, int limit) {
+ start -= this.start;
+ limit -= this.start;
+
+ if (limit > length) {
+ limit = length;
+ }
+
+ Rectangle2D charBounds = ga.getBounds();
+ charBounds.setRect(
+ charBounds.getX() + ga.getAdvance() * start + x,
+ charBounds.getY() + y,
+ charBounds.getWidth() + ga.getAdvance() * (limit - start),
+ charBounds.getHeight()
+ );
+
+ return charBounds;
+ }
+
+ @Override
+ float getCharPosition(int index) {
+ index -= start;
+ if (index > length) {
+ index = length;
+ }
+
+ return ga.getAdvance() * index + x;
+ }
+
+ @Override
+ float getCharAdvance(int index) {
+ return ga.getAdvance();
+ }
+
+ @Override
+ Shape getOutline() {
+ AffineTransform t = AffineTransform.getTranslateInstance(x, y);
+ return t.createTransformedShape(
+ TextDecorator.extendOutline(this, getVisualBounds(), decoration)
+ );
+ }
+
+ @Override
+ boolean charHasZeroAdvance(int index) {
+ return false;
+ }
+
+ @Override
+ TextHitInfo hitTest(float hitX, float hitY) {
+ hitX -= x;
+
+ float tmp = hitX / ga.getAdvance();
+ int hitIndex = Math.round(tmp);
+
+ if (tmp > hitIndex) {
+ return TextHitInfo.leading(hitIndex + this.start);
+ }
+ return TextHitInfo.trailing(hitIndex + this.start);
+ }
+
+ @Override
+ void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo) {
+ // Do nothing
+ }
+
+ @Override
+ float doJustification(TextRunBreaker.JustificationInfo jInfos[]) {
+ // Do nothing
+ return 0;
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java b/awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java
new file mode 100644
index 0000000..f1d64fb
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexey A. Petrenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.Graphics;
+import java.awt.GraphicsConfiguration;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.CommonGraphics2D;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.render.JavaBlitter;
+import org.apache.harmony.awt.gl.render.NativeImageBlitter;
+
+/**
+ * BufferedImageGraphics2D is implementation of CommonGraphics2D for
+ * drawing on buffered images.
+ */
+public class BufferedImageGraphics2D extends CommonGraphics2D {
+ private BufferedImage bi = null;
+ private Rectangle bounds = null;
+
+ public BufferedImageGraphics2D(BufferedImage bi) {
+ super();
+ this.bi = bi;
+ this.bounds = new Rectangle(0, 0, bi.getWidth(), bi.getHeight());
+ clip(bounds);
+ dstSurf = Surface.getImageSurface(bi);
+ if(dstSurf.isNativeDrawable()){
+ blitter = NativeImageBlitter.getInstance();
+ }else{
+ blitter = JavaBlitter.getInstance();
+ }
+ }
+
+ @Override
+ public void copyArea(int x, int y, int width, int height, int dx, int dy) {
+ }
+
+ @Override
+ public Graphics create() {
+ BufferedImageGraphics2D res = new BufferedImageGraphics2D(bi);
+ copyInternalFields(res);
+ return res;
+ }
+
+ @Override
+ public GraphicsConfiguration getDeviceConfiguration() {
+ return null;
+ }
+
+ public ColorModel getColorModel() {
+ return bi.getColorModel();
+ }
+
+ public WritableRaster getWritableRaster() {
+ return bi.getRaster();
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java b/awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java
new file mode 100644
index 0000000..0fe25a2
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/BufferedImageSource.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
+
+public class BufferedImageSource implements ImageProducer {
+
+ private Hashtable<?, ?> properties;
+ private ColorModel cm;
+ private WritableRaster raster;
+ private int width;
+ private int height;
+
+ private ImageConsumer ic;
+
+ public BufferedImageSource(BufferedImage image, Hashtable<?, ?> properties){
+ if(properties == null) {
+ this.properties = new Hashtable<Object, Object>();
+ } else {
+ this.properties = properties;
+ }
+
+ width = image.getWidth();
+ height = image.getHeight();
+ cm = image.getColorModel();
+ raster = image.getRaster();
+ }
+
+ public BufferedImageSource(BufferedImage image){
+ this(image, null);
+ }
+
+ public boolean isConsumer(ImageConsumer ic) {
+ return (this.ic == ic);
+ }
+
+ public void startProduction(ImageConsumer ic) {
+ addConsumer(ic);
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer ic) {
+ }
+
+ public void removeConsumer(ImageConsumer ic) {
+ if (this.ic == ic) {
+ this.ic = null;
+ }
+ }
+
+ public void addConsumer(ImageConsumer ic) {
+ this.ic = ic;
+ startProduction();
+ }
+
+ private void startProduction(){
+ try {
+ ic.setDimensions(width, height);
+ ic.setProperties(properties);
+ ic.setColorModel(cm);
+ ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT |
+ ImageConsumer.COMPLETESCANLINES |
+ ImageConsumer.SINGLEFRAME |
+ ImageConsumer.SINGLEPASS);
+ if(cm instanceof IndexColorModel &&
+ raster.getTransferType() == DataBuffer.TYPE_BYTE ||
+ cm instanceof ComponentColorModel &&
+ raster.getTransferType() == DataBuffer.TYPE_BYTE &&
+ raster.getNumDataElements() == 1){
+ DataBufferByte dbb = (DataBufferByte) raster.getDataBuffer();
+ byte data[] = dbb.getData();
+ int off = dbb.getOffset();
+ ic.setPixels(0, 0, width, height, cm, data, off, width);
+ }else if(cm instanceof DirectColorModel &&
+ raster.getTransferType() == DataBuffer.TYPE_INT){
+ DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+ int data[] = dbi.getData();
+ int off = dbi.getOffset();
+ ic.setPixels(0, 0, width, height, cm, data, off, width);
+ }else if(cm instanceof DirectColorModel &&
+ raster.getTransferType() == DataBuffer.TYPE_BYTE){
+ DataBufferByte dbb = (DataBufferByte) raster.getDataBuffer();
+ byte data[] = dbb.getData();
+ int off = dbb.getOffset();
+ ic.setPixels(0, 0, width, height, cm, data, off, width);
+ }else{
+ ColorModel rgbCM = ColorModel.getRGBdefault();
+ int pixels[] = new int[width];
+ Object pix = null;
+ for(int y = 0; y < height; y++){
+ for(int x = 0 ; x < width; x++){
+ pix = raster.getDataElements(x, y, pix);
+ pixels[x] = cm.getRGB(pix);
+ }
+ ic.setPixels(0, y, width, 1, rgbCM, pixels, 0, width);
+ }
+ }
+ ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
+ }catch (NullPointerException e){
+ if (ic != null) {
+ ic.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java
new file mode 100644
index 0000000..cc6d7cf
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 10.02.2005
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+public class ByteArrayDecodingImageSource extends DecodingImageSource {
+
+ byte imagedata[];
+ int imageoffset;
+ int imagelength;
+
+ public ByteArrayDecodingImageSource(byte imagedata[], int imageoffset,
+ int imagelength){
+ this.imagedata = imagedata;
+ this.imageoffset = imageoffset;
+ this.imagelength = imagelength;
+ }
+
+ public ByteArrayDecodingImageSource(byte imagedata[]){
+ this(imagedata, 0, imagedata.length);
+ }
+
+ @Override
+ protected boolean checkConnection() {
+ return true;
+ }
+
+ @Override
+ protected InputStream getInputStream() {
+ // BEGIN android-modified
+ // TODO: Why does a ByteArrayInputStream need to be buffered at all?
+ return new BufferedInputStream(new ByteArrayInputStream(imagedata,
+ imageoffset, imagelength), 1024);
+ // END android-modified
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/DataBufferListener.java b/awt/org/apache/harmony/awt/gl/image/DataBufferListener.java
new file mode 100644
index 0000000..8793050
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/DataBufferListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 13.03.2006
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+public interface DataBufferListener {
+
+ void dataChanged();
+ void dataTaken();
+ void dataReleased();
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java
new file mode 100644
index 0000000..958d691
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/DecodingImageSource.java
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 18.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is an abstract class that encapsulates a main part of ImageProducer functionality
+ * for the images being decoded by the native decoders, like PNG, JPEG and GIF.
+ * It helps to integrate image decoders into producer/consumer model. It provides
+ * functionality for working with several decoder instances and several image consumers
+ * simultaneously.
+ */
+public abstract class DecodingImageSource implements ImageProducer {
+ List<ImageConsumer> consumers = new ArrayList<ImageConsumer>(5);
+ List<ImageDecoder> decoders = new ArrayList<ImageDecoder>(5);
+ boolean loading;
+
+ ImageDecoder decoder;
+
+ protected abstract boolean checkConnection();
+
+ protected abstract InputStream getInputStream();
+
+ public synchronized void addConsumer(ImageConsumer ic) {
+ if (!checkConnection()) { // No permission for this consumer
+ ic.imageComplete(ImageConsumer.IMAGEERROR);
+ return;
+ }
+
+ ImageConsumer cons = findConsumer(consumers, ic);
+
+ if (cons == null) { // Try to look in the decoders
+ ImageDecoder d = null;
+
+ // Check for all existing decoders
+ for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
+ d = i.next();
+ cons = findConsumer(d.consumers, ic);
+ if (cons != null) {
+ break;
+ }
+ }
+ }
+
+ if (cons == null) { // Not found, add this consumer
+ consumers.add(ic);
+ }
+ }
+
+ /**
+ * This method stops sending data to the given consumer
+ * @param ic - consumer
+ */
+ private void abortConsumer(ImageConsumer ic) {
+ ic.imageComplete(ImageConsumer.IMAGEERROR);
+ consumers.remove(ic);
+ }
+
+ /**
+ * This method stops sending data to the list of consumers.
+ * @param consumersList - list of consumers
+ */
+ private void abortAllConsumers(List<ImageConsumer> consumersList) {
+ for (ImageConsumer imageConsumer : consumersList) {
+ abortConsumer(imageConsumer);
+ }
+ }
+
+ public synchronized void removeConsumer(ImageConsumer ic) {
+ ImageDecoder d = null;
+
+ // Remove in all existing decoders
+ for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
+ d = i.next();
+ removeConsumer(d.consumers, ic);
+ if (d.consumers.size() <= 0) {
+ d.terminate();
+ }
+ }
+
+ // Remove in the current queue of consumers
+ removeConsumer(consumers, ic);
+ }
+
+ /**
+ * Static implementation of removeConsumer method
+ * @param consumersList - list of consumers
+ * @param ic - consumer to be removed
+ */
+ private static void removeConsumer(List<ImageConsumer> consumersList, ImageConsumer ic) {
+ ImageConsumer cons = null;
+
+ for (Iterator<ImageConsumer> i = consumersList.iterator(); i.hasNext();) {
+ cons = i.next();
+ if (cons.equals(ic)) {
+ i.remove();
+ }
+ }
+ }
+
+ public void requestTopDownLeftRightResend(ImageConsumer consumer) {
+ // Do nothing
+ }
+
+ public synchronized void startProduction(ImageConsumer ic) {
+ if (ic != null) {
+ addConsumer(ic);
+ }
+
+ if (!loading && consumers.size() > 0) {
+ ImageLoader.addImageSource(this);
+ loading = true;
+ }
+ }
+
+ public synchronized boolean isConsumer(ImageConsumer ic) {
+ ImageDecoder d = null;
+
+ // Check for all existing decoders
+ for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
+ d = i.next();
+ if (findConsumer(d.consumers, ic) != null) {
+ return true;
+ }
+ }
+
+ // Check current queue of consumers
+ return findConsumer(consumers, ic) != null;
+ }
+
+ /**
+ * Checks if the consumer is in the list and returns it it is there
+ * @param consumersList - list of consumers
+ * @param ic - consumer
+ * @return consumer if found, null otherwise
+ */
+ private static ImageConsumer findConsumer(List<ImageConsumer> consumersList, ImageConsumer ic) {
+ ImageConsumer res = null;
+
+ for (Iterator<ImageConsumer> i = consumersList.iterator(); i.hasNext();) {
+ res = i.next();
+ if (res.equals(ic)) {
+ return res;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Use this method to finish decoding or lock the list of consumers
+ * for a particular decoder
+ * @param d - decoder
+ */
+ synchronized void lockDecoder(ImageDecoder d) {
+ if (d == decoder) {
+ decoder = null;
+ startProduction(null);
+ }
+ }
+
+ /**
+ * Tries to find an appropriate decoder for the input stream and adds it
+ * to the list of decoders
+ * @return created decoder
+ */
+ private ImageDecoder createDecoder() {
+ InputStream is = getInputStream();
+
+ ImageDecoder decoder;
+
+ if (is == null) {
+ decoder = null;
+ } else {
+ decoder = ImageDecoder.createDecoder(this, is);
+ }
+
+ if (decoder != null) {
+ synchronized (this) {
+ decoders.add(decoder);
+ this.decoder = decoder;
+ loading = false;
+ consumers = new ArrayList<ImageConsumer>(5); // Reset queue
+ }
+
+ return decoder;
+ }
+ // We were not able to find appropriate decoder
+ List<ImageConsumer> cs;
+ synchronized (this) {
+ cs = consumers;
+ consumers = new ArrayList<ImageConsumer>(5);
+ loading = false;
+ }
+ abortAllConsumers(cs);
+
+ return null;
+ }
+
+ /**
+ * Stop the given decoder and remove it from the list
+ * @param dr - decoder
+ */
+ private synchronized void removeDecoder(ImageDecoder dr) {
+ lockDecoder(dr);
+ decoders.remove(dr);
+ }
+
+ /**
+ * This method serves as an entry point.
+ * It starts the decoder and loads the image data.
+ */
+ public void load() {
+ synchronized (this) {
+ if (consumers.size() == 0) {
+ loading = false;
+ return;
+ }
+ }
+
+ ImageDecoder d = createDecoder();
+ if (d != null) {
+ try {
+ decoder.decodeImage();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ removeDecoder(d);
+ abortAllConsumers(d.consumers);
+ }
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java
new file mode 100644
index 0000000..54d4664
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 20.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+public class FileDecodingImageSource extends DecodingImageSource {
+ String filename;
+
+ public FileDecodingImageSource(String file) {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(file);
+ }
+
+ filename = file;
+ }
+
+ @Override
+protected boolean checkConnection() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ try {
+ security.checkRead(filename);
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+protected InputStream getInputStream() {
+ try {
+ // BEGIN android-modified
+ return new BufferedInputStream(new FileInputStream(filename), 8192);
+ // END android-modified
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/GifDecoder.java b/awt/org/apache/harmony/awt/gl/image/GifDecoder.java
new file mode 100644
index 0000000..7ecb15b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/GifDecoder.java
@@ -0,0 +1,692 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+* Created on 27.01.2005
+*/
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.IndexColorModel;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+public class GifDecoder extends ImageDecoder {
+ // initializes proper field IDs
+ private static native void initIDs();
+
+ static {
+ System.loadLibrary("gl"); //$NON-NLS-1$
+ initIDs();
+ }
+
+ // ImageConsumer hints: common
+ private static final int baseHints =
+ ImageConsumer.SINGLEPASS | ImageConsumer.COMPLETESCANLINES |
+ ImageConsumer.SINGLEFRAME;
+ // ImageConsumer hints: interlaced
+ private static final int interlacedHints =
+ baseHints | ImageConsumer.RANDOMPIXELORDER;
+
+ // Impossible color value - no translucent pixels allowed
+ static final int IMPOSSIBLE_VALUE = 0x0FFFFFFF;
+
+ // I/O buffer
+ private static final int BUFFER_SIZE = 1024;
+ private byte buffer[] = new byte[BUFFER_SIZE];
+
+ GifDataStream gifDataStream = new GifDataStream();
+ GifGraphicBlock currBlock;
+
+ // Pointer to native structure which store decoding state
+ // between subsequent decoding/IO-suspension cycles
+ private long hNativeDecoder; // NULL initially
+
+ // Number of bytes eaten by the native decoder
+ private int bytesConsumed;
+
+ private boolean consumersPrepared;
+ private Hashtable<String, String> properties = new Hashtable<String, String>();
+
+ // Could be set up by java code or native method when
+ // transparent pixel index changes or local color table encountered
+ private boolean forceRGB;
+
+ private byte screenBuffer[];
+ private int screenRGBBuffer[];
+
+ public GifDecoder(DecodingImageSource src, InputStream is) {
+ super(src, is);
+ }
+
+ private static native int[] toRGB(byte imageData[], byte colormap[], int transparentColor);
+
+ private static native void releaseNativeDecoder(long hDecoder);
+
+ private native int decode(
+ byte input[],
+ int bytesInBuffer,
+ long hDecoder,
+ GifDataStream dataStream,
+ GifGraphicBlock currBlock
+ );
+
+ private int[] getScreenRGBBuffer() {
+ if (screenRGBBuffer == null) {
+ if (screenBuffer != null) {
+ int transparentColor =
+ gifDataStream.logicalScreen.globalColorTable.cm.getTransparentPixel();
+ transparentColor = transparentColor > 0 ? transparentColor : IMPOSSIBLE_VALUE;
+ screenRGBBuffer =
+ toRGB(
+ screenBuffer,
+ gifDataStream.logicalScreen.globalColorTable.colors,
+ transparentColor
+ );
+ } else {
+ int size = gifDataStream.logicalScreen.logicalScreenHeight *
+ gifDataStream.logicalScreen.logicalScreenWidth;
+ screenRGBBuffer = new int[size];
+ }
+ }
+
+ return screenRGBBuffer;
+ }
+
+ private void prepareConsumers() {
+ GifLogicalScreen gls = gifDataStream.logicalScreen;
+ setDimensions(gls.logicalScreenWidth,
+ gls.logicalScreenHeight);
+ setProperties(properties);
+
+ currBlock = gifDataStream.graphicBlocks.get(0);
+ if (forceRGB) {
+ setColorModel(ColorModel.getRGBdefault());
+ } else {
+ setColorModel(gls.globalColorTable.getColorModel(currBlock.transparentColor));
+ }
+
+ // Fill screen buffer with the background or transparent color
+ if (forceRGB) {
+ int fillColor = 0xFF000000;
+ if (gls.backgroundColor != IMPOSSIBLE_VALUE) {
+ fillColor = gls.backgroundColor;
+ }
+
+ Arrays.fill(getScreenRGBBuffer(), fillColor);
+ } else {
+ int fillColor = 0;
+
+ if (gls.backgroundColor != IMPOSSIBLE_VALUE) {
+ fillColor = gls.backgroundColor;
+ } else {
+ fillColor = gls.globalColorTable.cm.getTransparentPixel();
+ }
+
+ screenBuffer = new byte[gls.logicalScreenHeight*gls.logicalScreenWidth];
+ Arrays.fill(screenBuffer, (byte) fillColor);
+ }
+
+ setHints(interlacedHints); // XXX - always random pixel order
+ }
+
+ @Override
+ public void decodeImage() throws IOException {
+ try {
+ int bytesRead = 0;
+ int needBytes, offset, bytesInBuffer = 0;
+ boolean eosReached = false;
+ GifGraphicBlock blockToDispose = null;
+
+ // Create new graphic block
+ if (currBlock == null) {
+ currBlock = new GifGraphicBlock();
+ gifDataStream.graphicBlocks.add(currBlock);
+ }
+
+ // Read from the input stream
+ for (;;) {
+ needBytes = BUFFER_SIZE - bytesInBuffer;
+ offset = bytesInBuffer;
+
+ bytesRead = inputStream.read(buffer, offset, needBytes);
+
+ if (bytesRead < 0) {
+ eosReached = true;
+ bytesRead = 0;
+ } // Don't break, maybe something left in buffer
+
+ // Keep track on how much bytes left in buffer
+ bytesInBuffer += bytesRead;
+
+ // Here we pass number of new bytes read from the input stream (bytesRead)
+ // since native decoder uses java buffer and doesn't have its own
+ // buffer. So it adds this number to the number of bytes left
+ // in buffer from the previous call.
+ int numLines = decode(
+ buffer,
+ bytesRead,
+ hNativeDecoder,
+ gifDataStream,
+ currBlock);
+
+ // Keep track on how much bytes left in buffer
+ bytesInBuffer -= bytesConsumed;
+
+ if (
+ !consumersPrepared &&
+ gifDataStream.logicalScreen.completed &&
+ gifDataStream.logicalScreen.globalColorTable.completed &&
+ (currBlock.imageData != null || // Have transparent pixel filled
+ currBlock.rgbImageData != null)
+ ) {
+ prepareConsumers();
+ consumersPrepared = true;
+ }
+
+ if (bytesConsumed < 0) {
+ break; // Error exit
+ }
+
+ if (currBlock != null) {
+ if (numLines != 0) {
+ // Dispose previous image only before showing next
+ if (blockToDispose != null) {
+ blockToDispose.dispose();
+ blockToDispose = null;
+ }
+
+ currBlock.sendNewData(this, numLines);
+ }
+
+ if (currBlock.completed && hNativeDecoder != 0) {
+ blockToDispose = currBlock; // Dispose only before showing new pixels
+ currBlock = new GifGraphicBlock();
+ gifDataStream.graphicBlocks.add(currBlock);
+ }
+ }
+
+ if (hNativeDecoder == 0) {
+ break;
+ }
+
+ if (eosReached && numLines == 0) { // Maybe image is truncated...
+ releaseNativeDecoder(hNativeDecoder);
+ break;
+ }
+ }
+ } finally {
+ closeStream();
+ }
+
+ // Here all animation goes
+ // Repeat image loopCount-1 times or infinitely if loopCount = 0
+ if (gifDataStream.loopCount != 1) {
+ if (currBlock.completed == false) {
+ gifDataStream.graphicBlocks.remove(currBlock);
+ }
+
+ int numFrames = gifDataStream.graphicBlocks.size();
+ // At first last block will be disposed
+ GifGraphicBlock gb =
+ gifDataStream.graphicBlocks.get(numFrames-1);
+
+ ImageLoader.beginAnimation();
+
+ while (gifDataStream.loopCount != 1) {
+ if (gifDataStream.loopCount != 0) {
+ gifDataStream.loopCount--;
+ }
+
+ // Show all frames
+ for (int i=0; i<numFrames; i++) {
+ gb.dispose();
+ gb = gifDataStream.graphicBlocks.get(i);
+
+ // Show one frame
+ if (forceRGB) {
+ setPixels(
+ gb.imageLeft,
+ gb.imageTop,
+ gb.imageWidth,
+ gb.imageHeight,
+ ColorModel.getRGBdefault(),
+ gb.getRgbImageData(),
+ 0,
+ gb.imageWidth
+ );
+ } else {
+ setPixels(
+ gb.imageLeft,
+ gb.imageTop,
+ gb.imageWidth,
+ gb.imageHeight,
+ null,
+ gb.imageData,
+ 0,
+ gb.imageWidth
+ );
+ }
+ }
+ }
+ ImageLoader.endAnimation();
+ }
+
+ imageComplete(ImageConsumer.STATICIMAGEDONE);
+ }
+
+ void setComment(String newComment) {
+ Object currComment = properties.get("comment"); //$NON-NLS-1$
+
+ if (currComment == null) {
+ properties.put("comment", newComment); //$NON-NLS-1$
+ } else {
+ properties.put("comment", (String) currComment + "\n" + newComment); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ setProperties(properties);
+ }
+
+ class GifDataStream {
+ // Indicates that reading of the whole data stream accomplished
+ boolean completed = false;
+
+ // Added to support Netscape 2.0 application
+ // extension block.
+ int loopCount = 1;
+
+ GifLogicalScreen logicalScreen = new GifLogicalScreen();
+ List<GifGraphicBlock> graphicBlocks = new ArrayList<GifGraphicBlock>(10); // Of GifGraphicBlocks
+
+ // Comments from the image
+ String comments[];
+ }
+
+ class GifLogicalScreen {
+ // Indicates that reading of this block accomplished
+ boolean completed = false;
+
+ int logicalScreenWidth;
+ int logicalScreenHeight;
+
+ int backgroundColor = IMPOSSIBLE_VALUE;
+
+ GifColorTable globalColorTable = new GifColorTable();
+ }
+
+ class GifGraphicBlock {
+ // Indicates that reading of this block accomplished
+ boolean completed = false;
+
+ final static int DISPOSAL_NONE = 0;
+ final static int DISPOSAL_NODISPOSAL = 1;
+ final static int DISPOSAL_BACKGROUND = 2;
+ final static int DISPOSAL_RESTORE = 3;
+
+ int disposalMethod;
+ int delayTime; // Multiplied by 10 already
+ int transparentColor = IMPOSSIBLE_VALUE;
+
+ int imageLeft;
+ int imageTop;
+ int imageWidth;
+ int imageHeight;
+
+ // Auxilliary variables to minimize computations
+ int imageRight;
+ int imageBottom;
+
+ boolean interlace;
+
+ // Don't need local color table - if it is specified
+ // image data are converted to RGB in the native code
+
+ byte imageData[] = null;
+ int rgbImageData[] = null;
+
+ private int currY = 0; // Current output scanline
+
+ int[] getRgbImageData() {
+ if (rgbImageData == null) {
+ rgbImageData =
+ toRGB(
+ imageData,
+ gifDataStream.logicalScreen.globalColorTable.colors,
+ transparentColor
+ );
+ if (transparentColor != IMPOSSIBLE_VALUE) {
+ transparentColor =
+ gifDataStream.logicalScreen.globalColorTable.cm.getRGB(transparentColor);
+ transparentColor &= 0x00FFFFFF;
+ }
+ }
+ return rgbImageData;
+ }
+
+ private void replaceTransparentPixels(int numLines) {
+ List<GifGraphicBlock> graphicBlocks = gifDataStream.graphicBlocks;
+ int prevBlockIndex = graphicBlocks.indexOf(this) - 1;
+
+ if (prevBlockIndex >= 0) {
+ int maxY = currY + numLines + imageTop;
+ int offset = currY * imageWidth;
+
+ // Update right and bottom coordinates
+ imageRight = imageLeft + imageWidth;
+ imageBottom = imageTop + imageHeight;
+
+ int globalWidth = gifDataStream.logicalScreen.logicalScreenWidth;
+ int pixelValue, imageOffset;
+ int rgbData[] = forceRGB ? getRgbImageData() : null;
+
+ for (int y = currY + imageTop; y < maxY; y++) {
+ imageOffset = globalWidth * y + imageLeft;
+ for (int x = imageLeft; x < imageRight; x++) {
+ pixelValue = forceRGB ?
+ rgbData[offset] :
+ imageData[offset] & 0xFF;
+ if (pixelValue == transparentColor) {
+ if (forceRGB) {
+ pixelValue = getScreenRGBBuffer() [imageOffset];
+ rgbData[offset] = pixelValue;
+ } else {
+ pixelValue = screenBuffer [imageOffset];
+ imageData[offset] = (byte) pixelValue;
+ }
+ }
+ offset++;
+ imageOffset++;
+ } // for
+ } // for
+
+ } // if (prevBlockIndex >= 0)
+ }
+
+ public void sendNewData(GifDecoder decoder, int numLines) {
+ // Get values for transparent pixels
+ // from the perevious frames
+ if (transparentColor != IMPOSSIBLE_VALUE) {
+ replaceTransparentPixels(numLines);
+ }
+
+ if (forceRGB) {
+ decoder.setPixels(
+ imageLeft,
+ imageTop + currY,
+ imageWidth,
+ numLines,
+ ColorModel.getRGBdefault(),
+ getRgbImageData(),
+ currY*imageWidth,
+ imageWidth
+ );
+ } else {
+ decoder.setPixels(
+ imageLeft,
+ imageTop + currY,
+ imageWidth,
+ numLines,
+ null,
+ imageData,
+ currY*imageWidth,
+ imageWidth
+ );
+ }
+
+ currY += numLines;
+ }
+
+ public void dispose() {
+ imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+
+ // Show current frame until delayInterval will not elapse
+ if (delayTime > 0) {
+ try {
+ Thread.sleep(delayTime);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } else {
+ Thread.yield(); // Allow consumers to consume data
+ }
+
+ // Don't dispose if image is outside of the visible area
+ if (imageLeft > gifDataStream.logicalScreen.logicalScreenWidth ||
+ imageTop > gifDataStream.logicalScreen.logicalScreenHeight) {
+ disposalMethod = DISPOSAL_NONE;
+ }
+
+ switch(disposalMethod) {
+ case DISPOSAL_BACKGROUND: {
+ if (forceRGB) {
+ getRgbImageData(); // Ensure that transparentColor is RGB, not index
+
+ int data[] = new int[imageWidth*imageHeight];
+
+ // Compatibility: Fill with transparent color if we have one
+ if (transparentColor != IMPOSSIBLE_VALUE) {
+ Arrays.fill(
+ data,
+ transparentColor
+ );
+ } else {
+ Arrays.fill(
+ data,
+ gifDataStream.logicalScreen.backgroundColor
+ );
+ }
+
+ setPixels(
+ imageLeft,
+ imageTop,
+ imageWidth,
+ imageHeight,
+ ColorModel.getRGBdefault(),
+ data,
+ 0,
+ imageWidth
+ );
+
+ sendToScreenBuffer(data);
+ } else {
+ byte data[] = new byte[imageWidth*imageHeight];
+
+ // Compatibility: Fill with transparent color if we have one
+ if (transparentColor != IMPOSSIBLE_VALUE) {
+ Arrays.fill(
+ data,
+ (byte) transparentColor
+ );
+ } else {
+ Arrays.fill(
+ data,
+ (byte) gifDataStream.logicalScreen.backgroundColor
+ );
+ }
+
+ setPixels(
+ imageLeft,
+ imageTop,
+ imageWidth,
+ imageHeight,
+ null,
+ data,
+ 0,
+ imageWidth
+ );
+
+ sendToScreenBuffer(data);
+ }
+ break;
+ }
+ case DISPOSAL_RESTORE: {
+ screenBufferToScreen();
+ break;
+ }
+ case DISPOSAL_NONE:
+ case DISPOSAL_NODISPOSAL:
+ default: {
+ // Copy transmitted data to the screen buffer
+ Object data = forceRGB ? (Object) getRgbImageData() : imageData;
+ sendToScreenBuffer(data);
+ break;
+ }
+ }
+ }
+
+ private void sendToScreenBuffer(Object data) {
+ int dataInt[];
+ byte dataByte[];
+
+ int width = gifDataStream.logicalScreen.logicalScreenWidth;
+
+
+ if (forceRGB) {
+ dataInt = (int[]) data;
+
+ if (imageWidth == width) {
+ System.arraycopy(dataInt,
+ 0,
+ getScreenRGBBuffer(),
+ imageLeft + imageTop*width,
+ dataInt.length
+ );
+ } else { // Each scanline
+ copyScanlines(dataInt, getScreenRGBBuffer(), width);
+ }
+ } else {
+ dataByte = (byte[]) data;
+
+ if (imageWidth == width) {
+ System.arraycopy(dataByte,
+ 0,
+ screenBuffer,
+ imageLeft + imageTop*width,
+ dataByte.length
+ );
+ } else { // Each scanline
+ copyScanlines(dataByte, screenBuffer, width);
+ }
+ }
+ } // sendToScreenBuffer
+
+ private void copyScanlines(Object src, Object dst, int width) {
+ for (int i=0; i<imageHeight; i++) {
+ System.arraycopy(src,
+ i*imageWidth,
+ dst,
+ imageLeft + i*width + imageTop*width,
+ imageWidth
+ );
+ } // for
+ }
+
+ private void screenBufferToScreen() {
+ int width = gifDataStream.logicalScreen.logicalScreenWidth;
+
+ Object dst = forceRGB ?
+ (Object) new int[imageWidth*imageHeight] :
+ new byte[imageWidth*imageHeight];
+
+ Object src = forceRGB ?
+ getScreenRGBBuffer() :
+ (Object) screenBuffer;
+
+ int offset = 0;
+ Object toSend;
+
+ if (width == imageWidth) {
+ offset = imageWidth * imageTop;
+ toSend = src;
+ } else {
+ for (int i=0; i<imageHeight; i++) {
+ System.arraycopy(src,
+ imageLeft + i*width + imageTop*width,
+ dst,
+ i*imageWidth,
+ imageWidth
+ );
+ } // for
+ toSend = dst;
+ }
+
+ if (forceRGB) {
+ setPixels(
+ imageLeft,
+ imageTop,
+ imageWidth,
+ imageHeight,
+ ColorModel.getRGBdefault(),
+ (int [])toSend,
+ offset,
+ imageWidth
+ );
+ } else {
+ setPixels(
+ imageLeft,
+ imageTop,
+ imageWidth,
+ imageHeight,
+ null,
+ (byte [])toSend,
+ offset,
+ imageWidth
+ );
+ }
+ }
+ }
+
+ class GifColorTable {
+ // Indicates that reading of this block accomplished
+ boolean completed = false;
+
+ IndexColorModel cm = null;
+ int size = 0; // Actual number of colors in the color table
+ byte colors[] = new byte[256*3];
+
+ IndexColorModel getColorModel(int transparentColor) {
+ if (cm != null) {
+ if (transparentColor != cm.getTransparentPixel()) {
+ return cm = null; // Force default ARGB color model
+ }
+ return cm;
+ } else
+ if (completed && size > 0) {
+ if (transparentColor == IMPOSSIBLE_VALUE) {
+ return cm =
+ new IndexColorModel(8, size, colors, 0, false);
+ }
+
+ if (transparentColor > size) {
+ size = transparentColor + 1;
+ }
+ return cm =
+ new IndexColorModel(8, size, colors, 0, false, transparentColor);
+ }
+
+ return cm = null; // Force default ARGB color model
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/ImageDecoder.java b/awt/org/apache/harmony/awt/gl/image/ImageDecoder.java
new file mode 100644
index 0000000..d16128e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/ImageDecoder.java
@@ -0,0 +1,258 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 18.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import com.android.internal.awt.AndroidImageDecoder;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ImageConsumer;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ConcurrentModificationException;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * This class contains common functionality for all image decoders.
+ */
+public abstract class ImageDecoder {
+
+ /** Image types */
+ public static final int GENERIC_DECODER = 0;
+ public static final int JPG_DECODER = 1;
+ public static final int GIF_DECODER = 2;
+ public static final int PNG_DECODER = 3;
+
+ private static final int MAX_BYTES_IN_SIGNATURE = 8;
+
+ protected List<ImageConsumer> consumers;
+ protected InputStream inputStream;
+ protected DecodingImageSource src;
+
+ protected boolean terminated;
+
+ /**
+ * Chooses appropriate image decoder by looking into input stream and checking
+ * the image signature.
+ * @param src - image producer, required for passing data to it from the
+ * created decoder via callbacks
+ * @param is - stream
+ * @return decoder
+ */
+ static ImageDecoder createDecoder(DecodingImageSource src, InputStream is) {
+ InputStream markable;
+
+ if (!is.markSupported()) {
+ // BEGIN android-modified
+ markable = new BufferedInputStream(is, 8192);
+ // END android-modified
+ } else {
+ markable = is;
+ }
+
+ // Read the signature from the stream and then reset it back
+ try {
+ markable.mark(MAX_BYTES_IN_SIGNATURE);
+
+ byte[] signature = new byte[MAX_BYTES_IN_SIGNATURE];
+ markable.read(signature, 0, MAX_BYTES_IN_SIGNATURE);
+ markable.reset();
+
+ if ((signature[0] & 0xFF) == 0xFF &&
+ (signature[1] & 0xFF) == 0xD8 &&
+ (signature[2] & 0xFF) == 0xFF) { // JPEG
+ return loadDecoder(PNG_DECODER, src, is);
+ } else if ((signature[0] & 0xFF) == 0x47 && // G
+ (signature[1] & 0xFF) == 0x49 && // I
+ (signature[2] & 0xFF) == 0x46) { // F
+ return loadDecoder(GIF_DECODER, src, is);
+ } else if ((signature[0] & 0xFF) == 137 && // PNG signature: 137 80 78 71 13 10 26 10
+ (signature[1] & 0xFF) == 80 &&
+ (signature[2] & 0xFF) == 78 &&
+ (signature[3] & 0xFF) == 71 &&
+ (signature[4] & 0xFF) == 13 &&
+ (signature[5] & 0xFF) == 10 &&
+ (signature[6] & 0xFF) == 26 &&
+ (signature[7] & 0xFF) == 10) {
+ return loadDecoder(JPG_DECODER, src, is);
+ }
+
+ return loadDecoder(GENERIC_DECODER, src, is);
+
+ } catch (IOException e) { // Silently
+ }
+
+ return null;
+ }
+
+ /*
+ * In the future, we might return different decoders for differen image types.
+ * But for now, we always return the generic one.
+ * Also: we could add a factory to load image decoder.
+ */
+ private static ImageDecoder loadDecoder(int type, DecodingImageSource src,
+ InputStream is) {
+ return new AndroidImageDecoder(src, is);
+ }
+
+ protected ImageDecoder(DecodingImageSource _src, InputStream is) {
+ src = _src;
+ consumers = src.consumers;
+ inputStream = is;
+ }
+
+ public abstract void decodeImage() throws IOException;
+
+ public synchronized void closeStream() {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ /**
+ * Stops the decoding by interrupting the current decoding thread.
+ * Used when all consumers are removed and there's no more need to
+ * run the decoder.
+ */
+ public void terminate() {
+ src.lockDecoder(this);
+ closeStream();
+
+ AccessController.doPrivileged(
+ new PrivilegedAction<Void>() {
+ public Void run() {
+ Thread.currentThread().interrupt();
+ return null;
+ }
+ }
+ );
+
+ terminated = true;
+ }
+
+ protected void setDimensions(int w, int h) {
+ if (terminated) {
+ return;
+ }
+
+ for (ImageConsumer ic : consumers) {
+ ic.setDimensions(w, h);
+ }
+ }
+
+ protected void setProperties(Hashtable<?, ?> props) {
+ if (terminated) {
+ return;
+ }
+
+ for (ImageConsumer ic : consumers) {
+ ic.setProperties(props);
+ }
+ }
+
+ protected void setColorModel(ColorModel cm) {
+ if (terminated) {
+ return;
+ }
+
+ for (ImageConsumer ic : consumers) {
+ ic.setColorModel(cm);
+ }
+ }
+
+ protected void setHints(int hints) {
+ if (terminated) {
+ return;
+ }
+
+ for (ImageConsumer ic : consumers) {
+ ic.setHints(hints);
+ }
+ }
+
+ protected void setPixels(
+ int x, int y,
+ int w, int h,
+ ColorModel model,
+ byte pix[],
+ int off, int scansize
+ ) {
+ if (terminated) {
+ return;
+ }
+
+ src.lockDecoder(this);
+
+ for (ImageConsumer ic : consumers) {
+ ic.setPixels(x, y, w, h, model, pix, off, scansize);
+ }
+ }
+
+ protected void setPixels(
+ int x, int y,
+ int w, int h,
+ ColorModel model,
+ int pix[],
+ int off, int scansize
+ ) {
+ if (terminated) {
+ return;
+ }
+
+ src.lockDecoder(this);
+
+ for (ImageConsumer ic : consumers) {
+ ic.setPixels(x, y, w, h, model, pix, off, scansize);
+ }
+ }
+
+ protected void imageComplete(int status) {
+ if (terminated) {
+ return;
+ }
+
+ src.lockDecoder(this);
+
+ ImageConsumer ic = null;
+
+ for (Iterator<ImageConsumer> i = consumers.iterator(); i.hasNext();) {
+ try {
+ ic = i.next();
+ } catch (ConcurrentModificationException e) {
+ i = consumers.iterator();
+ continue;
+ }
+ ic.imageComplete(status);
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/ImageLoader.java b/awt/org/apache/harmony/awt/gl/image/ImageLoader.java
new file mode 100644
index 0000000..5c7d180
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/ImageLoader.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+/*
+ * Created on 18.01.2005
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class provides functionality for simultaneous loading of
+ * several images and running animation.
+ */
+public class ImageLoader extends Thread {
+ // Contains ImageLoader objects
+ // and queue of image sources waiting to be loaded
+ static class ImageLoadersStorage {
+ private static final int MAX_THREADS = 5;
+ private static final int TIMEOUT = 4000;
+ static ImageLoadersStorage instance;
+
+ List<DecodingImageSource> queue = new LinkedList<DecodingImageSource>();
+ List<Thread> loaders = new ArrayList<Thread>(MAX_THREADS);
+
+ private int freeLoaders;
+
+ private ImageLoadersStorage() {}
+
+ static ImageLoadersStorage getStorage() {
+ if (instance == null) {
+ instance = new ImageLoadersStorage();
+ }
+
+ return instance;
+ }
+ }
+
+ ImageLoader() {
+ super();
+ setDaemon(true);
+ }
+
+ /**
+ * This method creates a new thread which is able to load an image
+ * or run animation (if the number of existing loader threads does not
+ * exceed the limit).
+ */
+ private static void createLoader() {
+ final ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+
+ synchronized(storage.loaders) {
+ if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS) {
+ AccessController.doPrivileged(
+ new PrivilegedAction<Void>() {
+ public Void run() {
+ ImageLoader loader = new ImageLoader();
+ storage.loaders.add(loader);
+ loader.start();
+ return null;
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Adds a new image source to the queue and starts a new loader
+ * thread if required
+ * @param imgSrc - image source
+ */
+ public static void addImageSource(DecodingImageSource imgSrc) {
+ ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+ synchronized(storage.queue) {
+ if (!storage.queue.contains(imgSrc)) {
+ storage.queue.add(imgSrc);
+ }
+ if (storage.freeLoaders == 0) {
+ createLoader();
+ }
+
+ storage.queue.notify();
+ }
+ }
+
+ /**
+ * Waits for a new ImageSource until timout expires.
+ * Loader thread will terminate after returning from this method
+ * if timeout expired and image source was not picked up from the queue.
+ * @return image source picked up from the queue or null if timeout expired
+ */
+ private static DecodingImageSource getWaitingImageSource() {
+ ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+
+ synchronized(storage.queue) {
+ DecodingImageSource isrc = null;
+
+ if (storage.queue.size() == 0) {
+ try {
+ storage.freeLoaders++;
+ storage.queue.wait(ImageLoadersStorage.TIMEOUT);
+ } catch (InterruptedException e) {
+ return null;
+ } finally {
+ storage.freeLoaders--;
+ }
+ }
+
+ if (storage.queue.size() > 0) {
+ isrc = storage.queue.get(0);
+ storage.queue.remove(0);
+ }
+
+ return isrc;
+ }
+ }
+
+ /**
+ * Entry point of the loader thread. Picks up image sources and
+ * runs decoders for them while there are available image sources in the queue.
+ * If there are no and timeout expires it terminates.
+ */
+ @Override
+ public void run() {
+ ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+
+ try {
+ while (storage.loaders.contains(this)) {
+ Thread.interrupted(); // Reset the interrupted flag
+ DecodingImageSource isrc = getWaitingImageSource();
+ if (isrc != null) {
+ try {
+ isrc.load();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ break; // Don't wait if timeout expired - terminate loader
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ synchronized(storage.loaders) {
+ storage.loaders.remove(Thread.currentThread());
+ }
+ }
+ }
+
+ /**
+ * Removes current thread from loaders (so we are able
+ * to create more loaders) and decreases its priority.
+ */
+ static void beginAnimation() {
+ ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+ Thread currThread = Thread.currentThread();
+
+ synchronized(storage) {
+ storage.loaders.remove(currThread);
+
+ if (storage.freeLoaders < storage.queue.size()) {
+ createLoader();
+ }
+ }
+
+ currThread.setPriority(Thread.MIN_PRIORITY);
+ }
+
+ /**
+ * Sends the current thread to wait for the new images to load
+ * if there are free placeholders for loaders
+ */
+ static void endAnimation() {
+ ImageLoadersStorage storage = ImageLoadersStorage.getStorage();
+ Thread currThread = Thread.currentThread();
+
+ synchronized(storage) {
+ if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS &&
+ !storage.loaders.contains(currThread)
+ ) {
+ storage.loaders.add(currThread);
+ }
+ }
+
+ currThread.setPriority(Thread.NORM_PRIORITY);
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/JpegDecoder.java b/awt/org/apache/harmony/awt/gl/image/JpegDecoder.java
new file mode 100644
index 0000000..2e64427
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/JpegDecoder.java
@@ -0,0 +1,231 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.image.*;
+import java.awt.color.ColorSpace;
+import java.awt.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class JpegDecoder extends ImageDecoder {
+ // Only 2 output colorspaces expected. Others are converted into
+ // these ones.
+ // 1. Grayscale
+ public static final int JCS_GRAYSCALE = 1;
+ // 2. RGB
+ public static final int JCS_RGB = 2;
+
+ // Flags for the consumer, progressive JPEG
+ private static final int hintflagsProgressive =
+ ImageConsumer.SINGLEFRAME | // JPEG is a static image
+ ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible
+ ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines
+ // Flags for the consumer, singlepass JPEG
+ private static final int hintflagsSingle =
+ ImageConsumer.SINGLEPASS |
+ hintflagsProgressive;
+
+ // Buffer for the stream
+ private static final int BUFFER_SIZE = 1024;
+ private byte buffer[] = new byte[BUFFER_SIZE];
+
+ // 3 possible color models only
+ private static ColorModel cmRGB;
+ private static ColorModel cmGray;
+
+ // initializes proper field IDs
+ private static native void initIDs();
+
+ // Pointer to native structure which store decoding state
+ // between subsequent decoding/IO-suspension cycles
+ private long hNativeDecoder = 0; // NULL initially
+
+ private boolean headerDone = false;
+
+ // Next 4 members are filled by the native method (decompress).
+ // We can simply check if imageWidth is still negative to find
+ // out if they are already filled.
+ private int imageWidth = -1;
+ private int imageHeight = -1;
+ private boolean progressive = false;
+ private int jpegColorSpace = 0;
+
+ // Stores number of bytes consumed by the native decoder
+ private int bytesConsumed = 0;
+ // Stores current scanline returned by the decoder
+ private int currScanline = 0;
+
+ private ColorModel cm = null;
+
+ static {
+ System.loadLibrary("jpegdecoder"); //$NON-NLS-1$
+
+ cmGray = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ false, false,
+ Transparency.OPAQUE, DataBuffer.TYPE_BYTE
+ );
+
+ // Create RGB color model
+ cmRGB = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
+
+ initIDs();
+ }
+
+ public JpegDecoder(DecodingImageSource src, InputStream is) {
+ super(src, is);
+ }
+
+ /*
+ public JpegDecoder(InputStream iStream, ImageConsumer iConsumer) {
+ inputStream = iStream;
+ consumer = iConsumer;
+ }
+ */
+
+ /**
+ * @return - not NULL if call is successful
+ */
+ private native Object decode(
+ byte[] input,
+ int bytesInBuffer,
+ long hDecoder);
+
+ private static native void releaseNativeDecoder(long hDecoder);
+
+ @Override
+ public void decodeImage() throws IOException {
+ try {
+ int bytesRead = 0, dataLength = 0;
+ boolean eosReached = false;
+ int needBytes, offset, bytesInBuffer = 0;
+ byte byteOut[] = null;
+ int intOut[] = null;
+ // Read from the input stream
+ for (;;) {
+ needBytes = BUFFER_SIZE - bytesInBuffer;
+ offset = bytesInBuffer;
+
+ bytesRead = inputStream.read(buffer, offset, needBytes);
+
+ if (bytesRead < 0) {
+ bytesRead = 0;//break;
+ eosReached = true;
+ } // Don't break, maybe something left in buffer
+
+ // Keep track on how much bytes left in buffer
+ bytesInBuffer += bytesRead;
+
+ // Here we pass overall number of bytes left in the java buffer
+ // (bytesInBuffer) since jpeg decoder has its own buffer and consumes
+ // as many bytes as it can. If there are any unconsumed bytes
+ // it didn't add them to its buffer...
+ Object arr = decode(
+ buffer,
+ bytesInBuffer,
+ hNativeDecoder);
+
+ // Keep track on how much bytes left in buffer
+ bytesInBuffer -= bytesConsumed;
+
+ if (!headerDone && imageWidth != -1) {
+ returnHeader();
+ headerDone = true;
+ }
+
+ if (bytesConsumed < 0) {
+ break; // Error exit
+ }
+
+ if (arr instanceof byte[]) {
+ byteOut = (byte[]) arr;
+ dataLength = byteOut.length;
+ returnData(byteOut, currScanline);
+ } else if (arr instanceof int[]) {
+ intOut = (int[]) arr;
+ dataLength = intOut.length;
+ returnData(intOut, currScanline);
+ } else {
+ dataLength = 0;
+ }
+
+ if (hNativeDecoder == 0) {
+ break;
+ }
+
+ if (dataLength == 0 && eosReached) {
+ releaseNativeDecoder(hNativeDecoder);
+ break; // Probably image is truncated
+ }
+ }
+ imageComplete(ImageConsumer.STATICIMAGEDONE);
+ } catch (IOException e) {
+ throw e;
+ } finally {
+ closeStream();
+ }
+ }
+
+ public void returnHeader() {
+ setDimensions(imageWidth, imageHeight);
+
+ switch (jpegColorSpace) {
+ case JCS_GRAYSCALE: cm = cmGray; break;
+ case JCS_RGB: cm = cmRGB; break;
+ default:
+ // awt.3D=Unknown colorspace
+ throw new IllegalArgumentException(Messages.getString("awt.3D")); //$NON-NLS-1$
+ }
+ setColorModel(cm);
+
+ setHints(progressive ? hintflagsProgressive : hintflagsSingle);
+
+ setProperties(new Hashtable<Object, Object>()); // Empty
+ }
+
+ // Send the data to the consumer
+ public void returnData(int data[], int currScanLine) {
+ // Send 1 or more scanlines to the consumer.
+ int numScanlines = data.length / imageWidth;
+ if (numScanlines > 0) {
+ setPixels(
+ 0, currScanLine - numScanlines,
+ imageWidth, numScanlines,
+ cm, data, 0, imageWidth
+ );
+ }
+ }
+
+ public void returnData(byte data[], int currScanLine) {
+ int numScanlines = data.length / imageWidth;
+ if (numScanlines > 0) {
+ setPixels(
+ 0, currScanLine - numScanlines,
+ imageWidth, numScanlines,
+ cm, data, 0, imageWidth
+ );
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/OffscreenImage.java b/awt/org/apache/harmony/awt/gl/image/OffscreenImage.java
new file mode 100644
index 0000000..3445f8e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/OffscreenImage.java
@@ -0,0 +1,532 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 22.12.2004
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+
+/**
+ * This class represent implementation of abstract Image class
+ */
+public class OffscreenImage extends Image implements ImageConsumer {
+
+ static final ColorModel rgbCM = ColorModel.getRGBdefault();
+ ImageProducer src;
+ BufferedImage image;
+ ColorModel cm;
+ WritableRaster raster;
+ boolean isIntRGB;
+ Hashtable<?, ?> properties;
+ Vector<ImageObserver> observers;
+ int width;
+ int height;
+ int imageState;
+ int hints;
+ private boolean producing;
+ private ImageSurface imageSurf;
+
+ public OffscreenImage(ImageProducer ip){
+ imageState = 0;
+ src = ip;
+ width = -1;
+ height = -1;
+ observers = new Vector<ImageObserver>();
+ producing = false;
+ }
+
+ @Override
+ public Object getProperty(String name, ImageObserver observer) {
+ if(name == null) {
+ // awt.38=Property name is not defined
+ throw new NullPointerException(Messages.getString("awt.38")); //$NON-NLS-1$
+ }
+ if(properties == null){
+ addObserver(observer);
+ startProduction();
+ if(properties == null) {
+ return null;
+ }
+ }
+ Object prop = properties.get(name);
+ if(prop == null) {
+ prop = UndefinedProperty;
+ }
+ return prop;
+ }
+
+ @Override
+ public ImageProducer getSource() {
+ return src;
+ }
+
+ @Override
+ public int getWidth(ImageObserver observer) {
+ if((imageState & ImageObserver.WIDTH) == 0){
+ addObserver(observer);
+ startProduction();
+ if((imageState & ImageObserver.WIDTH) == 0) {
+ return -1;
+ }
+ }
+ return width;
+ }
+
+ @Override
+ public int getHeight(ImageObserver observer) {
+ if((imageState & ImageObserver.HEIGHT) == 0){
+ addObserver(observer);
+ startProduction();
+ if((imageState & ImageObserver.HEIGHT) == 0) {
+ return -1;
+ }
+ }
+ return height;
+ }
+
+ @Override
+ public Graphics getGraphics() {
+ // awt.39=This method is not implemented for image obtained from ImageProducer
+ throw new UnsupportedOperationException(Messages.getString("awt.39")); //$NON-NLS-1$
+ }
+
+ @Override
+ public void flush() {
+ stopProduction();
+ imageUpdate(this, ImageObserver.ABORT, -1, -1, -1, -1);
+ imageState &= ~ImageObserver.ERROR;
+ imageState = 0;
+ image = null;
+ cm = null;
+ raster = null;
+ hints = 0;
+ width = -1;
+ height = -1;
+ }
+
+ public void setProperties(Hashtable<?, ?> properties) {
+ this.properties = properties;
+ imageUpdate(this, ImageObserver.PROPERTIES, 0, 0, width, height);
+ }
+
+ public void setColorModel(ColorModel cm) {
+ this.cm = cm;
+ }
+
+ /*
+ * We suppose what in case loading JPEG image then image has DirectColorModel
+ * and for infill image Raster will use setPixels method with int array.
+ *
+ * In case loading GIF image, for raster infill, is used setPixels method with
+ * byte array and Color Model is IndexColorModel. But Color Model may
+ * be changed during this process. Then is called setPixels method with
+ * int array and image force to default color model - int ARGB. The rest
+ * pixels are sending in DirectColorModel.
+ */
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ int[] pixels, int off, int scansize) {
+ if(raster == null){
+ if(cm == null){
+ if(model == null) {
+ // awt.3A=Color Model is null
+ throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$
+ }
+ cm = model;
+ }
+ createRaster();
+ }
+
+ if(model == null) {
+ model = cm;
+ }
+ if(cm != model){
+ forceToIntARGB();
+ }
+
+ if(cm == model && model.getTransferType() == DataBuffer.TYPE_INT &&
+ raster.getNumDataElements() == 1){
+
+ DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+ int data[] = dbi.getData();
+ int scanline = raster.getWidth();
+ int rof = dbi.getOffset() + y * scanline + x;
+ for(int lineOff = off, line = y; line < y + h;
+ line++, lineOff += scansize, rof += scanline){
+
+ System.arraycopy(pixels, lineOff, data, rof, w);
+ }
+
+ }else if(isIntRGB){
+ int buff[] = new int[w];
+ DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+ int data[] = dbi.getData();
+ int scanline = raster.getWidth();
+ int rof = dbi.getOffset() + y * scanline + x;
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
+ rof += scanline) {
+
+ for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+ buff[idx] = model.getRGB(pixels[sOff + idx]);
+ }
+ System.arraycopy(buff, 0, data, rof, w);
+ }
+ }else{
+ Object buf = null;
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
+ for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+ int rgb = model.getRGB(pixels[sOff + idx]);
+ buf = cm.getDataElements(rgb, buf);
+ raster.setDataElements(sx, sy, buf);
+ }
+ }
+ }
+
+ if (imageSurf != null) {
+ imageSurf.invalidate();
+ }
+
+ imageUpdate(this, ImageObserver.SOMEBITS, 0, 0, width, height);
+ }
+
+ public void setPixels(int x, int y, int w, int h, ColorModel model,
+ byte[] pixels, int off, int scansize) {
+
+ if(raster == null){
+ if(cm == null){
+ if(model == null) {
+ // awt.3A=Color Model is null
+ throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$
+ }
+ cm = model;
+ }
+ createRaster();
+ }
+ if(model == null) {
+ model = cm;
+ }
+ if(model != cm){
+ forceToIntARGB();
+ }
+
+ if(isIntRGB){
+ int buff[] = new int[w];
+ IndexColorModel icm = (IndexColorModel) model;
+ int colorMap[] = new int[icm.getMapSize()];
+ icm.getRGBs(colorMap);
+ DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
+ int data[] = dbi.getData();
+ int scanline = raster.getWidth();
+ int rof = dbi.getOffset() + y * scanline + x;
+ if(model instanceof IndexColorModel){
+
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
+ rof += scanline) {
+ for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+ buff[idx] = colorMap[pixels[sOff + idx] & 0xff];
+ }
+ System.arraycopy(buff, 0, data, rof, w);
+ }
+ }else{
+
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize,
+ rof += scanline) {
+ for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+ buff[idx] = model.getRGB(pixels[sOff + idx] & 0xff);
+ }
+ System.arraycopy(buff, 0, data, rof, w);
+ }
+ }
+ }else if(model == cm && model.getTransferType() == DataBuffer.TYPE_BYTE &&
+ raster.getNumDataElements() == 1){
+
+ DataBufferByte dbb = (DataBufferByte)raster.getDataBuffer();
+ byte data[] = dbb.getData();
+ int scanline = raster.getWidth();
+ int rof = dbb.getOffset() + y * scanline + x;
+ for(int lineOff = off, line = y; line < y + h;
+ line++, lineOff += scansize, rof += scanline){
+ System.arraycopy(pixels, lineOff, data, rof, w);
+ }
+ // BEGIN android-added (taken from newer Harmony)
+ }else if(model == cm && model.getTransferType() == DataBuffer.TYPE_BYTE &&
+ cm instanceof ComponentColorModel){
+
+ int nc = cm.getNumComponents();
+ byte stride[] = new byte[scansize];
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
+ System.arraycopy(pixels, sOff, stride, 0, scansize);
+
+ raster.setDataElements(x, sy, w, 1, stride);
+ }
+ // END android-added
+ }else {
+ for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) {
+ for (int sx = x, idx = 0; sx < x + w; sx++, idx++) {
+ int rgb = model.getRGB(pixels[sOff + idx] & 0xff);
+ raster.setDataElements(sx, sy, cm.getDataElements(rgb, null));
+ }
+ }
+ }
+
+ if (imageSurf != null) {
+ imageSurf.invalidate();
+ }
+
+ imageUpdate(this, ImageObserver.SOMEBITS, 0, 0, width, height);
+ }
+
+ public void setDimensions(int width, int height) {
+ if(width <= 0 || height <= 0){
+ imageComplete(ImageObserver.ERROR);
+ return;
+ }
+
+ this.width = width;
+ this.height = height;
+ imageUpdate(this, (ImageObserver.HEIGHT | ImageObserver.WIDTH),
+ 0, 0, width, height);
+ }
+
+ public void setHints(int hints) {
+ this.hints = hints;
+ }
+
+ public void imageComplete(int state) {
+ int flag;
+ switch(state){
+ case IMAGEABORTED:
+ flag = ImageObserver.ABORT;
+ break;
+ case IMAGEERROR:
+ flag = ImageObserver.ERROR | ImageObserver.ABORT;
+ break;
+ case SINGLEFRAMEDONE:
+ flag = ImageObserver.FRAMEBITS;
+ break;
+ case STATICIMAGEDONE:
+ flag = ImageObserver.ALLBITS;
+ break;
+ default:
+ // awt.3B=Incorrect ImageConsumer completion status
+ throw new IllegalArgumentException(Messages.getString("awt.3B")); //$NON-NLS-1$
+ }
+ imageUpdate(this, flag, 0, 0, width, height);
+
+ if((flag & (ImageObserver.ERROR | ImageObserver.ABORT |
+ ImageObserver.ALLBITS)) != 0 ) {
+ stopProduction();
+ observers.removeAllElements();
+ }
+ }
+
+ public /*synchronized*/ BufferedImage getBufferedImage(){
+ if(image == null){
+ ColorModel model = getColorModel();
+ WritableRaster wr = getRaster();
+ if(model != null && wr != null) {
+ image = new BufferedImage(model, wr, model.isAlphaPremultiplied(), null);
+ }
+ }
+ return image;
+ }
+
+ public /*synchronized*/ int checkImage(ImageObserver observer){
+ addObserver(observer);
+ return imageState;
+ }
+
+ public /*synchronized*/ boolean prepareImage(ImageObserver observer){
+ if((imageState & ImageObserver.ERROR) != 0){
+ if(observer != null){
+ observer.imageUpdate(this, ImageObserver.ERROR |
+ ImageObserver.ABORT, -1, -1, -1, -1);
+ }
+ return false;
+ }
+ if((imageState & ImageObserver.ALLBITS) != 0) {
+ return true;
+ }
+ addObserver(observer);
+ startProduction();
+ return ((imageState & ImageObserver.ALLBITS) != 0);
+ }
+
+ public /*synchronized*/ ColorModel getColorModel(){
+ if(cm == null) {
+ startProduction();
+ }
+ return cm;
+ }
+
+ public /*synchronized*/ WritableRaster getRaster(){
+ if(raster == null) {
+ startProduction();
+ }
+ return raster;
+ }
+
+ public int getState(){
+ return imageState;
+ }
+
+ private /*synchronized*/ void addObserver(ImageObserver observer){
+ if(observer != null){
+ if(observers.contains(observer)) {
+ return;
+ }
+ if((imageState & ImageObserver.ERROR) != 0){
+ observer.imageUpdate(this, ImageObserver.ERROR |
+ ImageObserver.ABORT, -1, -1, -1, -1);
+ return;
+ }
+ if((imageState & ImageObserver.ALLBITS) != 0){
+ observer.imageUpdate(this, imageState, 0, 0, width, height);
+ return;
+ }
+ observers.addElement(observer);
+ }
+ }
+
+ private synchronized void startProduction(){
+ if(!producing){
+ imageState &= ~ImageObserver.ABORT;
+ producing = true;
+ src.startProduction(this);
+ }
+ }
+
+ private synchronized void stopProduction(){
+ producing = false;
+ src.removeConsumer(this);
+ }
+
+ private void createRaster(){
+ try{
+ raster = cm.createCompatibleWritableRaster(width, height);
+ isIntRGB = false;
+ if(cm instanceof DirectColorModel){
+ DirectColorModel dcm = (DirectColorModel) cm;
+ if(dcm.getTransferType() == DataBuffer.TYPE_INT &&
+ dcm.getRedMask() == 0xff0000 &&
+ dcm.getGreenMask() == 0xff00 &&
+ dcm.getBlueMask() == 0xff){
+ isIntRGB = true;
+ }
+ }
+ }catch(Exception e){
+ cm = ColorModel.getRGBdefault();
+ raster = cm.createCompatibleWritableRaster(width, height);
+ isIntRGB = true;
+ }
+ }
+
+ private /*synchronized*/ void imageUpdate(Image img, int infoflags, int x, int y,
+ int width, int height){
+
+ imageState |= infoflags;
+ for (ImageObserver observer : observers) {
+ observer.imageUpdate(this, infoflags, x, y, width, height);
+ }
+
+// notifyAll();
+ }
+
+ private void forceToIntARGB(){
+
+ int w = raster.getWidth();
+ int h = raster.getHeight();
+
+ WritableRaster destRaster = rgbCM.createCompatibleWritableRaster(w, h);
+
+ Object obj = null;
+ int pixels[] = new int[w];
+
+ if(cm instanceof IndexColorModel){
+ IndexColorModel icm = (IndexColorModel) cm;
+ int colorMap[] = new int[icm.getMapSize()];
+ icm.getRGBs(colorMap);
+
+ for (int y = 0; y < h; y++) {
+ obj = raster.getDataElements(0, y, w, 1, obj);
+ byte ba[] = (byte[]) obj;
+ for (int x = 0; x < ba.length; x++) {
+ pixels[x] = colorMap[ba[x] & 0xff];
+ }
+ destRaster.setDataElements(0, y, w, 1, pixels);
+ }
+
+ }else{
+ for(int y = 0; y < h; y++){
+ for(int x = 0; x < w; x++){
+ obj = raster.getDataElements(x, y, obj);
+ pixels[x] = cm.getRGB(obj);
+ }
+ destRaster.setDataElements(0, y, w, 1, pixels);
+ }
+ }
+
+ synchronized(this){
+ if(imageSurf != null){
+ imageSurf.dispose();
+ imageSurf = null;
+ }
+ if(image != null){
+ image.flush();
+ image = null;
+ }
+ cm = rgbCM;
+ raster = destRaster;
+ isIntRGB = true;
+ }
+ }
+
+ public ImageSurface getImageSurface() {
+ if (imageSurf == null) {
+ ColorModel model = getColorModel();
+ WritableRaster wr = getRaster();
+ if(model != null && wr != null) {
+ imageSurf = new ImageSurface(model, wr);
+ }
+ }
+ return imageSurf;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java b/awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java
new file mode 100644
index 0000000..1748e1b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 30.09.2004
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+
+public class OrdinaryWritableRaster extends WritableRaster {
+
+ public OrdinaryWritableRaster(SampleModel sampleModel,
+ DataBuffer dataBuffer, Rectangle aRegion,
+ Point sampleModelTranslate, WritableRaster parent) {
+ super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent);
+ }
+
+ public OrdinaryWritableRaster(SampleModel sampleModel,
+ DataBuffer dataBuffer, Point origin) {
+ super(sampleModel, dataBuffer, origin);
+ }
+
+ public OrdinaryWritableRaster(SampleModel sampleModel, Point origin) {
+ super(sampleModel, origin);
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Object inData) {
+ super.setDataElements(x, y, inData);
+ }
+
+ @Override
+ public void setDataElements(int x, int y, int w, int h, Object inData) {
+ super.setDataElements(x, y, w, h, inData);
+ }
+
+ @Override
+ public WritableRaster createWritableChild(int parentX, int parentY, int w,
+ int h, int childMinX, int childMinY, int[] bandList) {
+ return super.createWritableChild(parentX, parentY, w, h, childMinX,
+ childMinY, bandList);
+ }
+
+ @Override
+ public WritableRaster createWritableTranslatedChild(int childMinX,
+ int childMinY) {
+ return super.createWritableTranslatedChild(childMinX, childMinY);
+ }
+
+ @Override
+ public WritableRaster getWritableParent() {
+ return super.getWritableParent();
+ }
+
+ @Override
+ public void setRect(Raster srcRaster) {
+ super.setRect(srcRaster);
+ }
+
+ @Override
+ public void setRect(int dx, int dy, Raster srcRaster) {
+ super.setRect(dx, dy, srcRaster);
+ }
+
+ @Override
+ public void setDataElements(int x, int y, Raster inRaster) {
+ super.setDataElements(x, y, inRaster);
+ }
+
+ @Override
+ public void setPixel(int x, int y, int[] iArray) {
+ super.setPixel(x, y, iArray);
+ }
+
+ @Override
+ public void setPixel(int x, int y, float[] fArray) {
+ super.setPixel(x, y, fArray);
+ }
+
+ @Override
+ public void setPixel(int x, int y, double[] dArray) {
+ super.setPixel(x, y, dArray);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, int[] iArray) {
+ super.setPixels(x, y, w, h, iArray);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, float[] fArray) {
+ super.setPixels(x, y, w, h, fArray);
+ }
+
+ @Override
+ public void setPixels(int x, int y, int w, int h, double[] dArray) {
+ super.setPixels(x, y, w, h, dArray);
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, int[] iArray) {
+ super.setSamples(x, y, w, h, b, iArray);
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, float[] fArray) {
+ super.setSamples(x, y, w, h, b, fArray);
+ }
+
+ @Override
+ public void setSamples(int x, int y, int w, int h, int b, double[] dArray) {
+ super.setSamples(x, y, w, h, b, dArray);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, int s) {
+ super.setSample(x, y, b, s);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, float s) {
+ super.setSample(x, y, b, s);
+ }
+
+ @Override
+ public void setSample(int x, int y, int b, double s) {
+ super.setSample(x, y, b, s);
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/PngDecoder.java b/awt/org/apache/harmony/awt/gl/image/PngDecoder.java
new file mode 100644
index 0000000..7e85600
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/PngDecoder.java
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ * @date: Jul 22, 2005
+ */
+
+package org.apache.harmony.awt.gl.image;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+import java.awt.color.ColorSpace;
+import java.awt.image.*;
+import java.awt.*;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class PngDecoder extends ImageDecoder {
+ // initializes proper field IDs
+ private static native void initIDs();
+
+ static {
+ System.loadLibrary("gl"); //$NON-NLS-1$
+ initIDs();
+ }
+
+ private static final int hintflags =
+ ImageConsumer.SINGLEFRAME | // PNG is a static image
+ ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible
+ ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines
+
+ // Each pixel is a grayscale sample.
+ private static final int PNG_COLOR_TYPE_GRAY = 0;
+ // Each pixel is an R,G,B triple.
+ private static final int PNG_COLOR_TYPE_RGB = 2;
+ // Each pixel is a palette index, a PLTE chunk must appear.
+ private static final int PNG_COLOR_TYPE_PLTE = 3;
+ // Each pixel is a grayscale sample, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4;
+ // Each pixel is an R,G,B triple, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_RGBA = 6;
+
+ private static final int INPUT_BUFFER_SIZE = 4096;
+ private byte buffer[] = new byte[INPUT_BUFFER_SIZE];
+
+ // Buffers for decoded image data
+ byte byteOut[];
+ int intOut[];
+
+ // Native pointer to png decoder data
+ private long hNativeDecoder;
+
+ int imageWidth, imageHeight;
+ int colorType;
+ int bitDepth;
+ byte cmap[];
+
+ boolean transferInts; // Is transfer type int?.. or byte?
+ int dataElementsPerPixel = 1;
+
+ ColorModel cm;
+
+ int updateFromScanline; // First scanline to update
+ int numScanlines; // Number of scanlines to update
+
+ private native long decode(byte[] input, int bytesInBuffer, long hDecoder);
+
+ private static native void releaseNativeDecoder(long hDecoder);
+
+ public PngDecoder(DecodingImageSource src, InputStream is) {
+ super(src, is);
+ }
+
+ @Override
+ public void decodeImage() throws IOException {
+ try {
+ int bytesRead = 0;
+ int needBytes, offset, bytesInBuffer = 0;
+ // Read from the input stream
+ for (;;) {
+ needBytes = INPUT_BUFFER_SIZE - bytesInBuffer;
+ offset = bytesInBuffer;
+
+ bytesRead = inputStream.read(buffer, offset, needBytes);
+
+ if (bytesRead < 0) { // Break, nothing to read from buffer, image truncated?
+ releaseNativeDecoder(hNativeDecoder);
+ break;
+ }
+
+ // Keep track on how much bytes left in buffer
+ bytesInBuffer += bytesRead;
+ hNativeDecoder = decode(buffer, bytesInBuffer, hNativeDecoder);
+ // PNG decoder always consumes all bytes at once
+ bytesInBuffer = 0;
+
+ // if (bytesConsumed < 0)
+ //break; // Error exit
+
+ returnData();
+
+ // OK, we decoded all the picture in the right way...
+ if (hNativeDecoder == 0) {
+ break;
+ }
+ }
+
+ imageComplete(ImageConsumer.STATICIMAGEDONE);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ imageComplete(ImageConsumer.IMAGEERROR);
+ throw e;
+ } finally {
+ closeStream();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private void returnHeader() { // Called from native code
+ setDimensions(imageWidth, imageHeight);
+
+ switch (colorType) {
+ case PNG_COLOR_TYPE_GRAY: {
+ if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ // Create gray color model
+ int numEntries = 1 << bitDepth;
+ int scaleFactor = 255 / (numEntries-1);
+ byte comps[] = new byte[numEntries];
+ for (int i = 0; i < numEntries; i++) {
+ comps[i] = (byte) (i * scaleFactor);
+ }
+ cm = new IndexColorModel(/*bitDepth*/8, numEntries, comps, comps, comps);
+
+ transferInts = false;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_RGB: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
+
+ transferInts = true;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_PLTE: {
+ if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = new IndexColorModel(/*bitDepth*/8, cmap.length / 3, cmap, 0, false);
+
+ transferInts = false;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_GRAY_ALPHA: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
+ true, false,
+ Transparency.TRANSLUCENT,
+ DataBuffer.TYPE_BYTE);
+
+ transferInts = false;
+ dataElementsPerPixel = 2;
+ break;
+ }
+
+ case PNG_COLOR_TYPE_RGBA: {
+ if (bitDepth != 8) {
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ cm = ColorModel.getRGBdefault();
+
+ transferInts = true;
+ break;
+ }
+ default:
+ // awt.3C=Unknown PNG color type
+ throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$
+ }
+
+ // Create output buffer
+ if (transferInts) {
+ intOut = new int[imageWidth * imageHeight];
+ } else {
+ byteOut = new byte[imageWidth * imageHeight * dataElementsPerPixel];
+ }
+
+ setColorModel(cm);
+
+ setHints(hintflags);
+ setProperties(new Hashtable<Object, Object>()); // Empty
+ }
+
+ // Send the data to the consumer
+ private void returnData() {
+ // Send 1 or more scanlines to the consumer.
+ if (numScanlines > 0) {
+ // Native decoder could have returned
+ // some data from the next pass, handle it here
+ int pass1, pass2;
+ if (updateFromScanline + numScanlines > imageHeight) {
+ pass1 = imageHeight - updateFromScanline;
+ pass2 = updateFromScanline + numScanlines - imageHeight;
+ } else {
+ pass1 = numScanlines;
+ pass2 = 0;
+ }
+
+ transfer(updateFromScanline, pass1);
+ if (pass2 != 0) {
+ transfer(0, pass2);
+ }
+ }
+ }
+
+ private void transfer(int updateFromScanline, int numScanlines) {
+ if (transferInts) {
+ setPixels(
+ 0, updateFromScanline,
+ imageWidth, numScanlines,
+ cm, intOut,
+ updateFromScanline * imageWidth,
+ imageWidth
+ );
+ } else {
+ setPixels(
+ 0, updateFromScanline,
+ imageWidth, numScanlines,
+ cm, byteOut,
+ updateFromScanline * imageWidth * dataElementsPerPixel,
+ imageWidth * dataElementsPerPixel
+ );
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java b/awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java
new file mode 100644
index 0000000..46545f9
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/PngDecoderJava.java
@@ -0,0 +1,282 @@
+package org.apache.harmony.awt.gl.image;
+
+// A simple PNG decoder source code in Java.
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.zip.CRC32;
+import java.util.zip.InflaterInputStream;
+
+//import javax.swing.JFrame;
+
+public class PngDecoderJava {
+
+/*
+ public static void main(String[] args) throws Exception {
+ String name = "logo.png";
+ if (args.length > 0)
+ name = args[0];
+ InputStream in = PngDecoderJava.class.getResourceAsStream(name);
+ final BufferedImage image = PngDecoderJava.decode(in);
+ in.close();
+
+ JFrame f = new JFrame() {
+ public void paint(Graphics g) {
+ Insets insets = getInsets();
+ g.drawImage(image, insets.left, insets.top, null);
+ }
+ };
+ f.setVisible(true);
+ Insets insets = f.getInsets();
+ f.setSize(image.getWidth() + insets.left + insets.right, image
+ .getHeight()
+ + insets.top + insets.bottom);
+ }
+ */
+
+ public static BufferedImage decode(InputStream in) throws IOException {
+ DataInputStream dataIn = new DataInputStream(in);
+ readSignature(dataIn);
+ PNGData chunks = readChunks(dataIn);
+
+ long widthLong = chunks.getWidth();
+ long heightLong = chunks.getHeight();
+ if (widthLong > Integer.MAX_VALUE || heightLong > Integer.MAX_VALUE)
+ throw new IOException("That image is too wide or tall.");
+ int width = (int) widthLong;
+ int height = (int) heightLong;
+
+ ColorModel cm = chunks.getColorModel();
+ WritableRaster raster = chunks.getRaster();
+
+ BufferedImage image = new BufferedImage(cm, raster, false, null);
+
+ return image;
+ }
+
+ protected static void readSignature(DataInputStream in) throws IOException {
+ long signature = in.readLong();
+ if (signature != 0x89504e470d0a1a0aL)
+ throw new IOException("PNG signature not found!");
+ }
+
+ protected static PNGData readChunks(DataInputStream in) throws IOException {
+ PNGData chunks = new PNGData();
+
+ boolean trucking = true;
+ while (trucking) {
+ try {
+ // Read the length.
+ int length = in.readInt();
+ if (length < 0)
+ throw new IOException("Sorry, that file is too long.");
+ // Read the type.
+ byte[] typeBytes = new byte[4];
+ in.readFully(typeBytes);
+ // Read the data.
+ byte[] data = new byte[length];
+ in.readFully(data);
+ // Read the CRC.
+ long crc = in.readInt() & 0x00000000ffffffffL; // Make it
+ // unsigned.
+ if (verifyCRC(typeBytes, data, crc) == false)
+ throw new IOException("That file appears to be corrupted.");
+
+ PNGChunk chunk = new PNGChunk(typeBytes, data);
+ chunks.add(chunk);
+ } catch (EOFException eofe) {
+ trucking = false;
+ }
+ }
+ return chunks;
+ }
+
+ protected static boolean verifyCRC(byte[] typeBytes, byte[] data, long crc) {
+ CRC32 crc32 = new CRC32();
+ crc32.update(typeBytes);
+ crc32.update(data);
+ long calculated = crc32.getValue();
+ return (calculated == crc);
+ }
+}
+
+class PNGData {
+ private int mNumberOfChunks;
+
+ private PNGChunk[] mChunks;
+
+ public PNGData() {
+ mNumberOfChunks = 0;
+ mChunks = new PNGChunk[10];
+ }
+
+ public void add(PNGChunk chunk) {
+ mChunks[mNumberOfChunks++] = chunk;
+ if (mNumberOfChunks >= mChunks.length) {
+ PNGChunk[] largerArray = new PNGChunk[mChunks.length + 10];
+ System.arraycopy(mChunks, 0, largerArray, 0, mChunks.length);
+ mChunks = largerArray;
+ }
+ }
+
+ public long getWidth() {
+ return getChunk("IHDR").getUnsignedInt(0);
+ }
+
+ public long getHeight() { return getChunk("IHDR").getUnsignedInt(4);
+ }
+
+ public short getBitsPerPixel() {
+ return getChunk("IHDR").getUnsignedByte(8);
+ }
+
+ public short getColorType() {
+ return getChunk("IHDR").getUnsignedByte(9);
+ }
+
+ public short getCompression() {
+ return getChunk("IHDR").getUnsignedByte(10);
+ }
+
+ public short getFilter() {
+ return getChunk("IHDR").getUnsignedByte(11);
+ }
+
+ public short getInterlace() {
+ return getChunk("IHDR").getUnsignedByte(12);
+ }
+
+ public ColorModel getColorModel() {
+ short colorType = getColorType();
+ int bitsPerPixel = getBitsPerPixel();
+
+ if (colorType == 3) {
+ byte[] paletteData = getChunk("PLTE").getData();
+ int paletteLength = paletteData.length / 3;
+ return new IndexColorModel(bitsPerPixel, paletteLength,
+ paletteData, 0, false);
+ }
+ System.out.println("Unsupported color type: " + colorType);
+ return null;
+ }
+
+ public WritableRaster getRaster() {
+ int width = (int) getWidth();
+ int height = (int) getHeight();
+ int bitsPerPixel = getBitsPerPixel();
+ short colorType = getColorType();
+
+ if (colorType == 3) {
+ byte[] imageData = getImageData();
+ //Orig: DataBuffer db = new DataBufferByte(imageData, imageData.length);
+ int len = Math.max(imageData.length, (width - 1) * (height -1));
+ DataBuffer db = new DataBufferByte(imageData, len);
+ WritableRaster raster = Raster.createPackedRaster(db, width,
+ height, bitsPerPixel, null);
+ return raster;
+ } else
+ System.out.println("Unsupported color type!");
+ return null;
+ }
+
+ public byte[] getImageData() {
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ // Write all the IDAT data into the array.
+ for (int i = 0; i < mNumberOfChunks; i++) {
+ PNGChunk chunk = mChunks[i];
+ if (chunk.getTypeString().equals("IDAT")) {
+ out.write(chunk.getData());
+ }
+ }
+ out.flush();
+ // Now deflate the data.
+ InflaterInputStream in = new InflaterInputStream(
+ new ByteArrayInputStream(out.toByteArray()));
+ ByteArrayOutputStream inflatedOut = new ByteArrayOutputStream();
+ int readLength;
+ byte[] block = new byte[8192];
+ while ((readLength = in.read(block)) != -1)
+ inflatedOut.write(block, 0, readLength);
+ inflatedOut.flush();
+ byte[] imageData = inflatedOut.toByteArray();
+ // Compute the real length.
+ int width = (int) getWidth();
+ int height = (int) getHeight();
+ int bitsPerPixel = getBitsPerPixel();
+ int length = width * height * bitsPerPixel / 8;
+
+ byte[] prunedData = new byte[length];
+
+ // We can only deal with non-interlaced images.
+ if (getInterlace() == 0) {
+ int index = 0;
+ for (int i = 0; i < length; i++) {
+ if ((i * 8 / bitsPerPixel) % width == 0) {
+ index++; // Skip the filter byte.
+ }
+ prunedData[i] = imageData[index++];
+ }
+ } else
+ System.out.println("Couldn't undo interlacing.");
+
+ return prunedData;
+ } catch (IOException ioe) {
+ }
+ return null;
+ }
+
+ public PNGChunk getChunk(String type) {
+ for (int i = 0; i < mNumberOfChunks; i++)
+ if (mChunks[i].getTypeString().equals(type))
+ return mChunks[i];
+ return null;
+ }
+}
+
+class PNGChunk {
+ private byte[] mType;
+
+ private byte[] mData;
+
+ public PNGChunk(byte[] type, byte[] data) {
+ mType = type;
+ mData = data;
+ }
+
+ public String getTypeString() {
+ try {
+ return new String(mType, "UTF8");
+ } catch (UnsupportedEncodingException uee) {
+ return "";
+ }
+ }
+
+ public byte[] getData() {
+ return mData;
+ }
+
+ public long getUnsignedInt(int offset) {
+ long value = 0;
+ for (int i = 0; i < 4; i++)
+ value += (mData[offset + i] & 0xff) << ((3 - i) * 8);
+ return value;
+ }
+
+ public short getUnsignedByte(int offset) {
+ return (short) (mData[offset] & 0x00ff);
+ }
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java b/awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java
new file mode 100644
index 0000000..a1899d6
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ */
+/*
+ * Created on 10.02.2005
+ *
+ */
+package org.apache.harmony.awt.gl.image;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.Permission;
+
+public class URLDecodingImageSource extends DecodingImageSource {
+
+ URL url;
+
+ public URLDecodingImageSource(URL url){
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkConnect(url.getHost(), url.getPort());
+ try {
+ Permission p = url.openConnection().getPermission();
+ security.checkPermission(p);
+ } catch (IOException e) {
+ }
+ }
+ this.url = url;
+ }
+
+ @Override
+ protected boolean checkConnection() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ try {
+ security.checkConnect(url.getHost(), url.getPort());
+ return true;
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected InputStream getInputStream() {
+ try{
+ URLConnection uc = url.openConnection();
+ // BEGIN android-modified
+ return new BufferedInputStream(uc.getInputStream(), 8192);
+ // END android-modified
+ }catch(IOException e){
+ return null;
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/Blitter.java b/awt/org/apache/harmony/awt/gl/render/Blitter.java
new file mode 100644
index 0000000..3b8012e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/Blitter.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 14.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.geom.AffineTransform;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+
+/**
+ * The interface for objects which can drawing Images on other Images which have
+ * Graphics or on the display.
+ */
+public interface Blitter {
+
+ public abstract void blit(int srcX, int srcY, Surface srcSurf,
+ int dstX, int dstY, Surface dstSurf, int width, int height,
+ AffineTransform sysxform, AffineTransform xform,
+ Composite comp, Color bgcolor,
+ MultiRectArea clip);
+
+ public abstract void blit(int srcX, int srcY, Surface srcSurf,
+ int dstX, int dstY, Surface dstSurf, int width, int height,
+ AffineTransform sysxform, Composite comp, Color bgcolor,
+ MultiRectArea clip);
+
+ public abstract void blit(int srcX, int srcY, Surface srcSurf,
+ int dstX, int dstY, Surface dstSurf, int width, int height,
+ Composite comp, Color bgcolor, MultiRectArea clip);
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java b/awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java
new file mode 100644
index 0000000..b643b41
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java
@@ -0,0 +1,502 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+public class JavaArcRasterizer {
+
+ /**
+ * Adds particular arc segment to mra
+ */
+ static void addX0LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int x1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x2 = line[i];
+ int y = cy + (b - i);
+ if (x1 <= finish && x2 >= start) {
+ mra.addRect(cx + Math.max(x1, start), y, cx + Math.min(x2, finish), y);
+ }
+ x1 = x2 + 1;
+ }
+ }
+
+ static void addX1LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int x1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x2 = line[i];
+ int y = cy - (b - i);
+ if (x1 <= finish && x2 >= start) {
+ mra.addRect(cx + Math.max(x1, start), y, cx + Math.min(x2, finish), y);
+ }
+ x1 = x2 + 1;
+ }
+ }
+
+ static void addX2LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int x1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x2 = line[i];
+ int y = cy - (b - i);
+ if (x1 <= finish && x2 >= start) {
+ mra.addRect(cx - Math.min(x2, finish), y, cx - Math.max(x1, start), y);
+ }
+ x1 = x2 + 1;
+ }
+ }
+
+ static void addX3LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int x1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x2 = line[i];
+ int y = cy + (b - i);
+ if (x1 <= finish && x2 >= start) {
+ mra.addRect(cx - Math.min(x2, finish), y, cx - Math.max(x1, start), y);
+ }
+ x1 = x2 + 1;
+ }
+ }
+
+ static void addY0LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int y1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x = cx + (b - i);
+ int y2 = line[i];
+ if (y1 <= finish && y2 >= start) {
+ mra.addRect(x, cy + Math.max(y1, start), x, cy + Math.min(y2, finish));
+ }
+ y1 = y2 + 1;
+ }
+ }
+
+ static void addY1LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int y1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x = cx - (b - i);
+ int y2 = line[i];
+ if (y1 <= finish && y2 >= start) {
+ mra.addRect(x, cy + Math.max(y1, start), x, cy + Math.min(y2, finish));
+ }
+ y1 = y2 + 1;
+ }
+ }
+
+ static void addY2LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int y1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x = cx - (b - i);
+ int y2 = line[i];
+ if (y1 <= finish && y2 >= start) {
+ mra.addRect(x, cy - Math.min(y2, finish), x, cy - Math.max(y1, start));
+ }
+ y1 = y2 + 1;
+ }
+ }
+
+ static void addY3LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) {
+ int y1 = 0;
+ for(int i = 0; i < line.length; i++) {
+ int x = cx + (b - i);
+ int y2 = line[i];
+ if (y1 <= finish && y2 >= start) {
+ mra.addRect(x, cy - Math.min(y2, finish), x, cy - Math.max(y1, start));
+ }
+ y1 = y2 + 1;
+ }
+ }
+
+ static void addX0Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx + prev, cy + (b - i), cx + line[i], cy + (b - i));
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addX1Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx + prev, cy - (b - i), cx + line[i], cy - (b - i));
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addX2Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx - line[i], cy - (b - i), cx - prev, cy - (b - i));
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addX3Line(MultiRectArea mra, int[] line, int cx, int cy, int b) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx - line[i], cy + (b - i), cx - prev, cy + (b - i));
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addY0Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx + (a - i), cy + prev, cx + (a - i), cy + line[i]);
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addY1Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx - (a - i), cy + prev, cx - (a - i), cy + line[i]);
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addY2Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx - (a - i), cy - line[i], cx - (a - i), cy - prev);
+ prev = line[i] + 1;
+ }
+ }
+
+ static void addY3Line(MultiRectArea mra, int[] line, int cx, int cy, int a) {
+ int prev = 0;
+ for(int i = 0; i < line.length; i++) {
+ mra.addRect(cx + (a - i), cy - line[i], cx + (a - i), cy - prev);
+ prev = line[i] + 1;
+ }
+ }
+
+ /**
+ * Returns normalized angle (from 0 to 360 degrees)
+ */
+ static double getNormAngle(double angle) {
+ angle -= Math.floor(angle / 360) * 360;
+ if (angle < 0) {
+ angle += 360;
+ }
+ return angle;
+ }
+
+ /**
+ * Creates arc lookup table
+ */
+ static int[] createLine(int a, int b, int xcount, int ycount) {
+ int[] buf = new int[b - ycount + 1];
+ int d = a * a + 2 * b * b - 2 * a * a * b;
+ int x = 0;
+ int y = b;
+ while (y >= ycount) {
+ if (d < 0) {
+ d = d + b * b * (4 * x + 6);
+ } else {
+ buf[b - y] = x;
+ d = d + b * b * (4 * x + 6) + 4 * a * a * (1 - y);
+ y--;
+ }
+ x++;
+ }
+ return buf;
+ }
+
+ /**
+ * Adds head/tail arc segment to MultiRectArea
+ */
+ static void addSeg(MultiRectArea mra, int cx1, int cy1, int cx2, int cy2, int a, int b, int[] xline, int[] yline, int[] bounds) {
+ switch(bounds[0]) {
+ case 0:
+ addY3LineSeg(mra, yline, cx2, cy1, a, bounds[1], bounds[2]);
+ break;
+ case 1:
+ addX1LineSeg(mra, xline, cx2, cy1, b, bounds[1], bounds[2]);
+ break;
+ case 2:
+ addX2LineSeg(mra, xline, cx1, cy1, b, bounds[1], bounds[2]);
+ break;
+ case 3:
+ addY2LineSeg(mra, yline, cx1, cy1, a, bounds[1], bounds[2]);
+ break;
+ case 4:
+ addY1LineSeg(mra, yline, cx1, cy2, a, bounds[1], bounds[2]);
+ break;
+ case 5:
+ addX3LineSeg(mra, xline, cx1, cy2, b, bounds[1], bounds[2]);
+ break;
+ case 6:
+ addX0LineSeg(mra, xline, cx2, cy2, b, bounds[1], bounds[2]);
+ break;
+ case 7:
+ addY0LineSeg(mra, yline, cx2, cy2, a, bounds[1], bounds[2]);
+ break;
+ }
+ }
+
+ /**
+ * Returns bounds for non quadratic arc head
+ */
+ static int[] getSegment1(double angle, int ax, int ay, int xcount, int ycount) {
+ int[] bounds = new int[3];
+ switch((int)(angle / 90)) {
+ case 0:
+ if (xcount < ax) {
+ bounds[0] = 0; // Y3
+ bounds[1] = -ay;
+ bounds[2] = ycount;
+ } else {
+ bounds[0] = 1; // X1
+ bounds[1] = 0;
+ bounds[2] = ax;
+ }
+ break;
+ case 1:
+ if (xcount > -ax) {
+ bounds[0] = 2; // X2
+ bounds[1] = -ax;
+ bounds[2] = xcount;
+ } else {
+ bounds[0] = 3; // Y2
+ bounds[1] = 0;
+ bounds[2] = -ay;
+ }
+ break;
+ case 2:
+ if (xcount < -ax) {
+ bounds[0] = 4; // Y1
+ bounds[1] = ay;
+ bounds[2] = ycount;
+ } else {
+ bounds[0] = 5; // X3
+ bounds[1] = 0;
+ bounds[2] = -ax;
+ }
+ break;
+ case 3:
+ if (xcount > ax) {
+ bounds[0] = 6; // X0
+ bounds[1] = ax;
+ bounds[2] = xcount;
+ } else {
+ bounds[0] = 7; // Y0
+ bounds[1] = 0;
+ bounds[2] = ay;
+ }
+ break;
+ }
+ return bounds;
+ }
+
+ /**
+ * Returns bounds for non quadratic arc tail
+ */
+ static int[] getSegment2(double angle, int ax, int ay, int xcount, int ycount) {
+ int[] bounds = new int[3];
+ switch((int)(angle / 90)) {
+ case 0:
+ if (xcount < ax) {
+ bounds[0] = 0; // Y3
+ bounds[1] = 0;
+ bounds[2] = -ay;
+ } else {
+ bounds[0] = 1; // X1
+ bounds[1] = ax;
+ bounds[2] = xcount;
+ }
+ break;
+ case 1:
+ if (xcount > -ax) {
+ bounds[0] = 2; // X2
+ bounds[1] = 0;
+ bounds[2] = -ax;
+ } else {
+ bounds[0] = 3; // Y2
+ bounds[1] = -ay;
+ bounds[2] = ycount;
+ }
+ break;
+ case 2:
+ if (xcount < -ax) {
+ bounds[0] = 4; // Y1
+ bounds[1] = 0;
+ bounds[2] = ay;
+ } else {
+ bounds[0] = 5; // X3
+ bounds[1] = -ax;
+ bounds[2] = xcount;
+ }
+ break;
+ case 3:
+ if (xcount > ax) {
+ bounds[0] = 6; // X0
+ bounds[1] = 0;
+ bounds[2] = ax;
+ } else {
+ bounds[0] = 7; // Y0
+ bounds[1] = ay;
+ bounds[2] = ycount;
+ }
+ break;
+ }
+ return bounds;
+ }
+
+ /**
+ * Rasterizes arc using clippind and dashing style
+ * @param x1 - the x coordinate of the left-upper corner of the arc bounds
+ * @param y1 - the y coordinate of the left-upper corner of the arc bounds
+ * @param width - the width of the arc bounds
+ * @param height - the height of the arc bounds
+ * @param angleStart - the start angle of the arc in degrees
+ * @param angleExtent - the angle extent in degrees
+ * @param clip - the MultiRectArea object of clipping area
+ * @return a MultiRectArea of rasterizer arc
+ */
+ public static MultiRectArea rasterize(int x, int y, int width, int height, double angleStart, double angleExtent, MultiRectArea clip) {
+
+ MultiRectArea mra = new MultiRectArea(false);
+
+ int cx1, cx2, cy1, cy2;
+ cx1 = cx2 = x + width / 2;
+ cy1 = cy2 = y + height / 2;
+
+ if (width % 2 == 0) {
+ cx2--;
+ }
+
+ if (height % 2 == 0) {
+ cy2--;
+ }
+
+ int a = width / 2;
+ int b = height / 2;
+ double c = Math.sqrt(a * a + b * b);
+
+ int xcount, ycount;
+ if (a < b) {
+ xcount = (int)Math.ceil(a * a / c);
+ ycount = (int)Math.floor(b * b / c);
+ } else {
+ xcount = (int)Math.floor(a * a / c);
+ ycount = (int)Math.ceil(b * b / c);
+ }
+
+ int[] xline = createLine(a, b, xcount, ycount);
+ int[] yline = createLine(b, a, ycount, xcount);
+
+ // Correct lines
+ int i = xline.length;
+ while(xline[--i] > xcount) {
+ xline[i] = xcount;
+ }
+
+ i = yline.length;
+ while(yline[--i] > ycount) {
+ yline[i] = ycount;
+ }
+
+ if (Math.abs(angleExtent) >= 360) {
+ // Rasterize CIRCLE
+ addX0Line(mra, xline, cx2, cy2, b);
+ addX1Line(mra, xline, cx2, cy1, b);
+ addX2Line(mra, xline, cx1, cy1, b);
+ addX3Line(mra, xline, cx1, cy2, b);
+ addY0Line(mra, yline, cx2, cy2, a);
+ addY1Line(mra, yline, cx1, cy2, a);
+ addY2Line(mra, yline, cx1, cy1, a);
+ addY3Line(mra, yline, cx2, cy1, a);
+ } else {
+ // Rasterize ARC
+ angleStart = getNormAngle(angleStart);
+ double angleFinish = getNormAngle(angleStart + angleExtent);
+
+ if (angleExtent < 0) {
+ double tmp = angleStart;
+ angleStart = angleFinish;
+ angleFinish = tmp;
+ }
+
+ double radStart = -Math.toRadians(angleStart);
+ double radFinish = -Math.toRadians(angleFinish);
+ int ax1 = (int)(a * Math.cos(radStart));
+ int ay1 = (int)(b * Math.sin(radStart));
+ int ax2 = (int)(a * Math.cos(radFinish));
+ int ay2 = (int)(b * Math.sin(radFinish));
+
+ int[] seg1 = getSegment1(angleStart, ax1, ay1, xcount, ycount);
+ int[] seg2 = getSegment2(angleFinish, ax2, ay2, xcount, ycount);
+
+ // Start and Finish located in the same quater
+ if (angleStart < angleFinish && seg1[0] == seg2[0]) {
+ if (seg1[0] % 2 == 0) {
+ seg1[2] = seg2[2];
+ } else {
+ seg1[1] = seg2[1];
+ }
+ addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg1);
+ return mra;
+ }
+
+ addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg1);
+ addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg2);
+
+ int startSeg = (seg1[0] + 1) % 8;
+ int finishSeg = seg2[0];
+
+ while (startSeg != finishSeg) {
+ switch(startSeg) {
+ case 0:
+ addY3Line(mra, yline, cx2, cy1, a);
+ break;
+ case 1:
+ addX1Line(mra, xline, cx2, cy1, b);
+ break;
+ case 2:
+ addX2Line(mra, xline, cx1, cy1, b);
+ break;
+ case 3:
+ addY2Line(mra, yline, cx1, cy1, a);
+ break;
+ case 4:
+ addY1Line(mra, yline, cx1, cy2, a);
+ break;
+ case 5:
+ addX3Line(mra, xline, cx1, cy2, b);
+ break;
+ case 6:
+ addX0Line(mra, xline, cx2, cy2, b);
+ break;
+ case 7:
+ addY0Line(mra, yline, cx2, cy2, a);
+ break;
+ }
+ startSeg = (startSeg + 1) % 8;
+ }
+ }
+
+ if (clip != null) {
+ mra.intersect(clip);
+ }
+
+ return mra;
+ }
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java b/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java
new file mode 100644
index 0000000..67e0a59
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaBlitter.java
@@ -0,0 +1,611 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 18.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.XORComposite;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Java implenetation of the Blitter interface. Using when we can't
+ * draw images natively.
+ */
+public class JavaBlitter implements Blitter {
+
+ /**
+ * Instead of multiplication and division we are using values from
+ * Lookup tables.
+ */
+ static byte mulLUT[][]; // Lookup table for multiplication
+ static byte divLUT[][]; // Lookup table for division
+
+ static{
+ mulLUT = new byte[256][256];
+ for(int i = 0; i < 256; i++){
+ for(int j = 0; j < 256; j++){
+ mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f);
+ }
+ }
+ divLUT = new byte[256][256];
+ for(int i = 1; i < 256; i++){
+ for(int j = 0; j < i; j++){
+ divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f);
+ }
+ for(int j = i; j < 256; j++){
+ divLUT[i][j] = (byte)255;
+ }
+ }
+ }
+
+ final static int AlphaCompositeMode = 1;
+ final static int XORMode = 2;
+
+ final static JavaBlitter inst = new JavaBlitter();
+
+ public static JavaBlitter getInstance(){
+ return inst;
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ AffineTransform xform, Composite comp, Color bgcolor,
+ MultiRectArea clip) {
+
+ if(xform == null){
+ blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }else{
+ double scaleX = xform.getScaleX();
+ double scaleY = xform.getScaleY();
+ double scaledX = dstX / scaleX;
+ double scaledY = dstY / scaleY;
+ AffineTransform at = new AffineTransform();
+ at.setToTranslation(scaledX, scaledY);
+ xform.concatenate(at);
+ sysxform.concatenate(xform);
+ blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }
+
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ Composite comp, Color bgcolor, MultiRectArea clip) {
+
+ if(sysxform == null) {
+ sysxform = new AffineTransform();
+ }
+ int type = sysxform.getType();
+ switch(type){
+ case AffineTransform.TYPE_TRANSLATION:
+ dstX += sysxform.getTranslateX();
+ dstY += sysxform.getTranslateY();
+ case AffineTransform.TYPE_IDENTITY:
+ blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
+ width, height, comp, bgcolor, clip);
+ break;
+ default:
+ int srcW = srcSurf.getWidth();
+ int srcH = srcSurf.getHeight();
+
+ int w = srcX + width < srcW ? width : srcW - srcX;
+ int h = srcY + height < srcH ? height : srcH - srcY;
+
+ ColorModel srcCM = srcSurf.getColorModel();
+ Raster srcR = srcSurf.getRaster().createChild(srcX, srcY,
+ w, h, 0, 0, null);
+
+ ColorModel dstCM = dstSurf.getColorModel();
+ WritableRaster dstR = dstSurf.getRaster();
+
+ transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h,
+ sysxform, comp, bgcolor, clip);
+
+ }
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+
+ javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(),
+ srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY,
+ dstSurf.getWidth(), dstSurf.getHeight(),
+ dstSurf.getColorModel(), dstSurf.getRaster(),
+ width, height, comp, bgcolor, clip);
+
+ }
+ public void javaBlt(int srcX, int srcY, int srcW, int srcH,
+ ColorModel srcCM, Raster srcRast, int dstX, int dstY,
+ int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, Composite comp, Color bgcolor,
+ MultiRectArea clip){
+
+ int srcX2 = srcW - 1;
+ int srcY2 = srcH - 1;
+ int dstX2 = dstW - 1;
+ int dstY2 = dstH - 1;
+
+ if(srcX < 0){
+ width += srcX;
+ srcX = 0;
+ }
+ if(srcY < 0){
+ height += srcY;
+ srcY = 0;
+ }
+
+ if(dstX < 0){
+ width += dstX;
+ srcX -= dstX;
+ dstX = 0;
+ }
+ if(dstY < 0){
+ height += dstY;
+ srcY -= dstY;
+ dstY = 0;
+ }
+
+ if(srcX > srcX2 || srcY > srcY2) {
+ return;
+ }
+ if(dstX > dstX2 || dstY > dstY2) {
+ return;
+ }
+
+ if(srcX + width > srcX2) {
+ width = srcX2 - srcX + 1;
+ }
+ if(srcY + height > srcY2) {
+ height = srcY2 - srcY + 1;
+ }
+ if(dstX + width > dstX2) {
+ width = dstX2 - dstX + 1;
+ }
+ if(dstY + height > dstY2) {
+ height = dstY2 - dstY + 1;
+ }
+
+ if(width <= 0 || height <= 0) {
+ return;
+ }
+
+ int clipRects[];
+ if(clip != null) {
+ clipRects = clip.rect;
+ } else {
+ clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1};
+ }
+
+ boolean isAlphaComp = false;
+ int rule = 0;
+ float alpha = 0;
+ boolean isXORComp = false;
+ Color xorcolor = null;
+ CompositeContext cont = null;
+
+ if(comp instanceof AlphaComposite){
+ isAlphaComp = true;
+ AlphaComposite ac = (AlphaComposite) comp;
+ rule = ac.getRule();
+ alpha = ac.getAlpha();
+ }else if(comp instanceof XORComposite){
+ isXORComp = true;
+ XORComposite xcomp = (XORComposite) comp;
+ xorcolor = xcomp.getXORColor();
+ }else{
+ cont = comp.createContext(srcCM, dstCM, null);
+ }
+
+ for(int i = 1; i < clipRects[0]; i += 4){
+ int _sx = srcX;
+ int _sy = srcY;
+
+ int _dx = dstX;
+ int _dy = dstY;
+
+ int _w = width;
+ int _h = height;
+
+ int cx = clipRects[i]; // Clipping left top X
+ int cy = clipRects[i + 1]; // Clipping left top Y
+ int cx2 = clipRects[i + 2]; // Clipping right bottom X
+ int cy2 = clipRects[i + 3]; // Clipping right bottom Y
+
+ if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) {
+ continue;
+ }
+
+ if(cx > _dx){
+ int shx = cx - _dx;
+ _w -= shx;
+ _dx = cx;
+ _sx += shx;
+ }
+
+ if(cy > _dy){
+ int shy = cy - _dy;
+ _h -= shy;
+ _dy = cy;
+ _sy += shy;
+ }
+
+ if(_dx + _w > cx2 + 1){
+ _w = cx2 - _dx + 1;
+ }
+
+ if(_dy + _h > cy2 + 1){
+ _h = cy2 - _dy + 1;
+ }
+
+ if(_sx > srcX2 || _sy > srcY2) {
+ continue;
+ }
+
+ if(isAlphaComp){
+ alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+ dstCM, dstRast, _w, _h, rule, alpha, bgcolor);
+ }else if(isXORComp){
+ xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy,
+ dstCM, dstRast, _w, _h, xorcolor);
+ }else{
+ Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null);
+ WritableRaster dr = dstRast.createWritableChild(_dx, _dy,
+ _w, _h, 0, 0, null);
+ cont.compose(sr, dr, dr);
+ }
+ }
+ }
+
+ void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+ int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, int rule, float alpha, Color bgcolor){
+
+ Object srcPixel, dstPixel;
+ int srcConstAllpha = (int)(alpha * 255 + 0.5f);
+ int srcRGB, dstRGB = 0;
+
+ if(bgcolor != null){
+ dstRGB = bgcolor.getRGB();
+ }
+
+ for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){
+ for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){
+ srcPixel = srcRast.getDataElements(sx, sy, null);
+ srcRGB = srcCM.getRGB(srcPixel);
+ if(bgcolor == null){
+ dstPixel = dstRast.getDataElements(dx, dy, null);
+ dstRGB = dstCM.getRGB(dstPixel);
+ }
+
+ dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(),
+ dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(),
+ rule, srcConstAllpha);
+
+ dstPixel = dstCM.getDataElements(dstRGB, null);
+ dstRast.setDataElements(dx,dy,dstPixel);
+ }
+ }
+ }
+
+ void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast,
+ int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast,
+ int width, int height, Color xorcolor){
+
+ Object srcPixel, dstPixel;
+ int xorRGB = xorcolor.getRGB();
+ int srcRGB, dstRGB;
+
+ for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){
+ for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){
+ srcPixel = srcRast.getDataElements(sx, sy, null);
+ dstPixel = dstRast.getDataElements(dx, dy, null);
+
+ srcRGB = srcCM.getRGB(srcPixel);
+ dstRGB = dstCM.getRGB(dstPixel);
+ dstRGB = srcRGB ^ xorRGB ^ dstRGB;
+
+ dstRGB = 0xff000000 | dstRGB;
+ dstPixel = dstCM.getDataElements(dstRGB, dstPixel);
+ dstRast.setDataElements(dx,dy,dstPixel);
+
+ }
+ }
+
+ }
+
+ private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY,
+ ColorModel dstCM, WritableRaster dstR, int dstX, int dstY,
+ int width, int height, AffineTransform at, Composite comp,
+ Color bgcolor,MultiRectArea clip) {
+
+ Rectangle srcBounds = new Rectangle(width, height);
+ Rectangle dstBlitBounds = new Rectangle(dstX, dstY, srcR.getWidth(), srcR.getHeight());
+
+ Rectangle transSrcBounds = getBounds2D(at, srcBounds).getBounds();
+ Rectangle transDstBlitBounds = getBounds2D(at, dstBlitBounds).getBounds();
+
+ int translateX = transDstBlitBounds.x - transSrcBounds.x;
+ int translateY = transDstBlitBounds.y - transSrcBounds.y;
+
+ AffineTransform inv = null;
+ try {
+ inv = at.createInverse();
+ } catch (NoninvertibleTransformException e) {
+ return;
+ }
+
+ double[] m = new double[6];
+ inv.getMatrix(m);
+
+ int clipRects[];
+ if(clip != null) {
+ clipRects = clip.rect;
+ } else {
+ clipRects = new int[]{5, 0, 0, dstR.getWidth(), dstR.getHeight()};
+ }
+
+ int compType = 0;
+ int srcConstAlpha = 0;
+ int rule = 0;
+ int bgRGB = bgcolor == null ? 0 : bgcolor.getRGB();
+ int srcRGB = 0, dstRGB = 0;
+ Object srcVal = null, dstVal = null;
+ if(comp instanceof AlphaComposite){
+ compType = AlphaCompositeMode;
+ AlphaComposite ac = (AlphaComposite) comp;
+ rule = ac.getRule();
+ srcConstAlpha = (int)(ac.getAlpha() * 255 + 0.5f);
+ }else if(comp instanceof XORComposite){
+ compType = XORMode;
+ XORComposite xor = (XORComposite) comp;
+ bgRGB = xor.getXORColor().getRGB();
+ }
+
+ for(int i = 1; i < clipRects[0]; i += 4){
+ Rectangle dstBounds = new Rectangle(clipRects[i], clipRects[i + 1], 0, 0);
+ dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 1]);
+ dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 3] + 1);
+ dstBounds.add(clipRects[i], clipRects[i + 3] + 1);
+
+ Rectangle bounds = dstBounds.intersection(transDstBlitBounds);
+
+ int minSrcX = srcBounds.x;
+ int minSrcY = srcBounds.y;
+ int maxSrcX = minSrcX + srcBounds.width;
+ int maxSrcY = minSrcY + srcBounds.height;
+
+ int minX = bounds.x;
+ int minY = bounds.y;
+ int maxX = minX + bounds.width;
+ int maxY = minY + bounds.height;
+
+ int hx = (int)((m[0] * 256) + 0.5);
+ int hy = (int)((m[1] * 256) + 0.5);
+ int vx = (int)((m[2] * 256) + 0.5);
+ int vy = (int)((m[3] * 256) + 0.5);
+ int sx = (int)((m[4] + m[0] * (bounds.x - translateX) + m[2] * (bounds.y - translateY)) * 256 + 0.5);
+ int sy = (int)((m[5] + m[1] * (bounds.x - translateX) + m[3] * (bounds.y - translateY)) * 256 + 0.5);
+
+ vx -= hx * bounds.width;
+ vy -= hy * bounds.width;
+
+ for(int y = minY; y < maxY; y++) {
+ for(int x = minX; x < maxX; x++) {
+ int px = sx >> 8;
+ int py = sy >> 8;
+ if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) {
+ switch(compType){
+ case AlphaCompositeMode:
+ srcVal = srcR.getDataElements(px , py , null);
+ srcRGB = srcCM.getRGB(srcVal);
+ if(bgcolor != null){
+ dstRGB = bgRGB;
+ }else{
+ dstVal = dstR.getDataElements(x, y, null);
+ dstRGB = dstCM.getRGB(dstVal);
+ }
+ dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(),
+ dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(),
+ rule, srcConstAlpha);
+ dstVal = dstCM.getDataElements(dstRGB, null);
+ dstR.setDataElements(x, y, dstVal);
+ break;
+
+ case XORMode:
+ srcVal = srcR.getDataElements(px , py , null);
+ srcRGB = srcCM.getRGB(srcVal);
+ dstVal = dstR.getDataElements(x, y, null);
+ dstRGB = dstCM.getRGB(dstVal);
+ dstRGB = srcRGB ^ bgRGB;
+
+ dstRGB = 0xff000000 | dstRGB;
+ dstVal = dstCM.getDataElements(dstRGB, null);
+ dstR.setDataElements(x, y, dstVal);
+ break;
+
+ default:
+ // awt.37=Unknown composite type {0}
+ throw new IllegalArgumentException(Messages.getString("awt.37", //$NON-NLS-1$
+ comp.getClass()));
+ }
+ }
+ sx += hx;
+ sy += hy;
+ }
+ sx += vx;
+ sy += vy;
+ }
+ }
+
+ }
+
+ private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) {
+ int x = r.x;
+ int y = r.y;
+ int width = r.width;
+ int height = r.height;
+
+ float[] corners = {
+ x, y,
+ x + width, y,
+ x + width, y + height,
+ x, y + height
+ };
+
+ at.transform(corners, 0, corners, 0, 4);
+
+ Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0);
+ bounds.add(corners[2], corners[3]);
+ bounds.add(corners[4], corners[5]);
+ bounds.add(corners[6], corners[7]);
+
+ return bounds;
+ }
+
+ private int compose(int srcRGB, boolean isSrcAlphaPre,
+ int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre,
+ int rule, int srcConstAlpha){
+
+ int sa, sr, sg, sb, da, dr, dg, db;
+
+ sa = (srcRGB >> 24) & 0xff;
+ sr = (srcRGB >> 16) & 0xff;
+ sg = (srcRGB >> 8) & 0xff;
+ sb = srcRGB & 0xff;
+
+ if(isSrcAlphaPre){
+ sa = mulLUT[srcConstAlpha][sa] & 0xff;
+ sr = mulLUT[srcConstAlpha][sr] & 0xff;
+ sg = mulLUT[srcConstAlpha][sg] & 0xff;
+ sb = mulLUT[srcConstAlpha][sb] & 0xff;
+ }else{
+ sa = mulLUT[srcConstAlpha][sa] & 0xff;
+ sr = mulLUT[sa][sr] & 0xff;
+ sg = mulLUT[sa][sg] & 0xff;
+ sb = mulLUT[sa][sb] & 0xff;
+ }
+
+ da = (dstRGB >> 24) & 0xff;
+ dr = (dstRGB >> 16) & 0xff;
+ dg = (dstRGB >> 8) & 0xff;
+ db = dstRGB & 0xff;
+
+ if(!isDstAlphaPre){
+ dr = mulLUT[da][dr] & 0xff;
+ dg = mulLUT[da][dg] & 0xff;
+ db = mulLUT[da][db] & 0xff;
+ }
+
+ int Fs = 0;
+ int Fd = 0;
+ switch(rule){
+ case AlphaComposite.CLEAR:
+ break;
+
+ case AlphaComposite.DST:
+ Fd = 255;
+ break;
+
+ case AlphaComposite.DST_ATOP:
+ Fs = 255 - da;
+ Fd = sa;
+ break;
+
+ case AlphaComposite.DST_IN:
+ Fd = sa;
+ break;
+
+ case AlphaComposite.DST_OUT:
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.DST_OVER:
+ Fs = 255 - da;
+ Fd = 255;
+ break;
+
+ case AlphaComposite.SRC:
+ Fs = 255;
+ break;
+
+ case AlphaComposite.SRC_ATOP:
+ Fs = da;
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.SRC_IN:
+ Fs = da;
+ break;
+
+ case AlphaComposite.SRC_OUT:
+ Fs = 255 - da;
+ break;
+
+ case AlphaComposite.SRC_OVER:
+ Fs = 255;
+ Fd = 255 - sa;
+ break;
+
+ case AlphaComposite.XOR:
+ Fs = 255 - da;
+ Fd = 255 - sa;
+ break;
+ }
+ dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff);
+ dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff);
+ db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff);
+
+ da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff);
+
+ if(!isDstAlphaPre){
+ if(da != 255){
+ dr = divLUT[da][dr] & 0xff;
+ dg = divLUT[da][dg] & 0xff;
+ db = divLUT[da][db] & 0xff;
+ }
+ }
+ if(!dstHasAlpha) {
+ da = 0xff;
+ }
+ dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db;
+
+ return dstRGB;
+
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java b/awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java
new file mode 100644
index 0000000..eb6f7b5
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java
@@ -0,0 +1,760 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+
+public class JavaLineRasterizer {
+
+ /**
+ * LineDasher class provides dashing for particular dash style
+ */
+ public static class LineDasher {
+
+ int index;
+ float pos;
+ float phase;
+ float dash[];
+ float inv[];
+ boolean visible;
+
+ public LineDasher() {
+ }
+
+ public LineDasher(float dash[], float phase) {
+ this.dash = dash;
+ this.phase = phase;
+
+ inv = new float[dash.length];
+ int j = dash.length;
+ for (float element : dash) {
+ inv[--j] = element;
+ }
+ index = 0;
+ while (phase > dash[index]) {
+ phase -= dash[index];
+ index = (index + 1) % dash.length;
+ }
+ visible = index % 2 == 0;
+ }
+
+ void move(float step) { // main dasher
+ pos += step;
+ step += phase;
+ while(step >= dash[index]) {
+ step -= dash[index];
+ index = (index + 1) % dash.length;
+ visible = !visible;
+ }
+ phase = step;
+ }
+
+ float nextDash() {
+ phase = 0.0f;
+ index = (index + 1) % dash.length;
+ visible = !visible;
+ return dash[index];
+ }
+
+ LineDasher createDiagonal(double k, float length, boolean invert) {
+ LineDasher local = new LineDasher();
+ local.dash = new float[dash.length];
+ if (invert) { // inverted dasher
+ move(length);
+ local.phase = (float)((dash[index] - phase) * k);
+ local.visible = visible;
+ local.index = inv.length - index - 1;
+ for(int i = 0; i < inv.length; i++) {
+ local.dash[i] = (float)(inv[i] * k);
+ }
+ } else {
+ local.phase = (float)(phase * k);
+ local.visible = visible;
+ local.index = index;
+ for(int i = 0; i < dash.length; i++) {
+ local.dash[i] = (float)(dash[i] * k);
+ }
+ move(length);
+ }
+ return local;
+ }
+
+ LineDasher createOrtogonal(float length, boolean invert) {
+ LineDasher local = new LineDasher();
+ local.dash = new float[dash.length];
+ if (invert) { // inverted dasher
+ move(length);
+ local.phase = dash[index] - phase;
+ local.visible = visible;
+ local.index = inv.length - index - 1;
+ local.dash = inv;
+ } else {
+ local.phase = phase;
+ local.visible = visible;
+ local.index = index;
+ local.dash = dash;
+ move(length);
+ }
+ return local;
+ }
+
+ LineDasher createChild(float start) {
+ LineDasher child = new LineDasher();
+ child.phase = phase;
+ child.visible = visible;
+ child.index = index;
+ child.dash = dash;
+ child.move(start);
+ return child;
+ }
+
+ }
+
+ /**
+ * Line class provides rasterization for different line types
+ */
+ abstract static class Line {
+
+ int x1, y1, x2, y2;
+ int x, y;
+ MultiRectArea dst;
+
+ Line(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.x2 = x2;
+ this.y2 = y2;
+ this.dst = dst;
+ }
+
+ static abstract class Diag extends Line {
+ int dx, dy, adx, ady, sx, sy;
+ int eBase, ePos, eNeg;
+ int xcount;
+ int e;
+
+ Diag(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ dx = x2 - x1;
+ dy = y2 - y1;
+ sy = 1;
+ if (dx > 0) {
+ adx = dx;
+ sx = 1;
+ } else {
+ adx = -dx;
+ sx = -1;
+ }
+ ady = dy;
+ }
+
+ float getLength() {
+ return (float)Math.sqrt(dx * dx + dy * dy);
+ }
+
+ static class Hor extends Diag {
+
+ Hor(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ eBase = ady + ady - adx;
+ ePos = 2 * (ady - adx);
+ eNeg = ady + ady;
+ xcount = adx;
+ }
+
+ @Override
+ void rasterize() {
+ e = eBase;
+ x = x1;
+ y = y1;
+ rasterize(xcount);
+ }
+
+ @Override
+ void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+ e = eBase + 2 * (ady * Math.abs(nx1 - x1) - adx * Math.abs(ny1 - y1));
+ x = nx1;
+ y = ny1;
+ rasterize(dx > 0 ? nx2 - nx1 : nx1 - nx2);
+ }
+
+ @Override
+ void rasterize(int count) {
+ int px = x;
+ while (count-- > 0) {
+ if (e >= 0) {
+ if (sx > 0) {
+ dst.addRect(px, y, x, y);
+ } else {
+ dst.addRect(x, y, px, y);
+ }
+ x += sx;
+ y += sy;
+ e += ePos;
+ px = x;
+ } else {
+ e += eNeg;
+ x += sx;
+ }
+ }
+ if (sx > 0) {
+ dst.addRect(px, y, x, y);
+ } else {
+ dst.addRect(x, y, px, y);
+ }
+ }
+
+ @Override
+ void skip(int count) {
+ while (count-- > 0) {
+ x += sx;
+ if (e >= 0) {
+ y += sy;
+ e += ePos;
+ } else {
+ e += eNeg;
+ }
+ }
+ }
+
+ }
+
+ static class Ver extends Diag {
+
+ Ver(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ eBase = adx + adx - ady;
+ ePos = 2 * (adx - ady);
+ eNeg = adx + adx;
+ xcount = ady;
+ }
+
+ @Override
+ void rasterize() {
+ e = eBase;
+ x = x1;
+ y = y1;
+ rasterize(xcount);
+ }
+
+ @Override
+ void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+ e = eBase + 2 * (adx * Math.abs(ny1 - y1) - ady * Math.abs(nx1 - x1));
+ x = nx1;
+ y = ny1;
+ rasterize(ny2 - ny1);
+ }
+
+ @Override
+ void rasterize(int count) {
+ int py = y;
+ while (count-- > 0) {
+ if (e >= 0) {
+ dst.addRect(x, py, x, y);
+ x += sx;
+ y += sy;
+ e += ePos;
+ py = y;
+ } else {
+ y += sy;
+ e += eNeg;
+ }
+ }
+ dst.addRect(x, py, x, y);
+ }
+
+ @Override
+ void skip(int count) {
+ while (count-- > 0) {
+ y += sy;
+ if (e >= 0) {
+ x += sx;
+ e += ePos;
+ } else {
+ e += eNeg;
+ }
+ }
+ }
+
+ }
+
+ static class HorDashed extends Hor {
+
+ LineDasher local;
+
+ HorDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) {
+ super(x1, y1, x2, y2, dst);
+ float length = getLength();
+ local = dasher.createDiagonal(xcount / length, length, invert);
+ }
+
+ @Override
+ void rasterize() {
+ e = eBase;
+ x = x1;
+ y = y1;
+ rasterizeDash(xcount, local);
+ }
+
+ @Override
+ void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+ e = eBase + 2 * (ady * Math.abs(nx1 - x1) - adx * Math.abs(ny1 - y1));
+ x = nx1;
+ y = ny1;
+ rasterizeDash(Math.abs(nx2 - nx1), local.createChild(Math.abs(nx1 - x1)));
+ }
+
+ }
+
+ static class VerDashed extends Ver {
+
+ LineDasher local;
+
+ VerDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) {
+ super(x1, y1, x2, y2, dst);
+ float length = getLength();
+ local = dasher.createDiagonal(xcount / length, length, invert);
+ }
+
+ @Override
+ void rasterize() {
+ e = eBase;
+ x = x1;
+ y = y1;
+ rasterizeDash(xcount, local);
+ }
+
+ @Override
+ void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
+ e = eBase + 2 * (adx * Math.abs(ny1 - y1) - ady * Math.abs(nx1 - x1));
+ x = nx1;
+ y = ny1;
+ rasterizeDash(ny2 - ny1, local.createChild(ny1 - y1));
+ }
+
+ }
+
+ @Override
+ void rasterize(int[] clip, int index) {
+ int cx1 = clip[index + 0];
+ int cy1 = clip[index + 1];
+ int cx2 = clip[index + 2] + 1;
+ int cy2 = clip[index + 3] + 1;
+
+ int code1 =
+ (x1 < cx1 ? 1 : 0) | (x1 >= cx2 ? 2 : 0) |
+ (y1 < cy1 ? 8 : 0) | (y1 >= cy2 ? 4 : 0);
+ int code2 =
+ (x2 < cx1 ? 1 : 0) | (x2 >= cx2 ? 2 : 0) |
+ (y2 < cy1 ? 8 : 0) | (y2 >= cy2 ? 4 : 0);
+
+ // Outside
+ if ((code1 & code2) != 0) {
+ return;
+ }
+
+ // Inside
+ if (code1 == 0 && code2 == 0) {
+ rasterize();
+ return;
+ }
+
+ // Clip
+ int nx1 = x1;
+ int ny1 = y1;
+ int nx2 = x2;
+ int ny2 = y2;
+ // need to clip
+ cx1 -= x1; cx2 -= x1;
+ cy1 -= y1; cy2 -= y1;
+// int d;
+ int newx1 = 0, newy1 = 0, newx2 = 0, newy2 = 0;
+ if (code1 != 0) {
+ newx1 = Integer.MAX_VALUE;
+ if ((code1 & 8) != 0) {
+ // clip point 1 with top clip bound
+ newy1 = cy1;
+ newx1 = clipY(dx, dy, newy1, true);
+
+ } else if ((code1 & 4) != 0) {
+ // clip point 1 with bottom clip bound
+ newy1 = cy2 - 1;
+ newx1 = clipY(dx, dy, newy1, false);
+ }
+ if ((code1 & 1) != 0 && (cx1 > newx1 || newx1 == Integer.MAX_VALUE)) {
+ // clip point 1 with left clip bound
+ newx1 = cx1;
+ newy1 = clipX(dx, dy, newx1, false);
+ } else if ((code1 & 2) != 0 && (newx1 >= cx2 || newx1 == Integer.MAX_VALUE)) {
+ // clip point 1 with right clip bound
+ newx1 = cx2 - 1;
+ newy1 = clipX(dx, dy, newx1, false);
+ }
+ if (newx1 < cx1 || newx1 >= cx2 || newy1 < cy1 || newy1 >= cy2) {
+ return;
+ }
+// d = 2 * (ady * Math.abs(newx1) - adx * Math.abs(newy1)) + 2 * ady - adx;
+ } else {
+// d = (ady << 1) - adx;
+ }
+
+ if (code2 != 0) {
+ newx2=Integer.MAX_VALUE;
+ if ((code2 & 8) != 0) {
+ // clip point 2 with top clip bound
+ newy2 = cy1;
+ newx2 = clipY(dx, dy, newy2, true);
+ } else if ((code2 & 4) != 0) {
+ // clip point 2 with bottom clip bound
+ newy2 = cy2 - 1;
+ newx2 = clipY(dx, dy, newy2, false);
+ }
+ if ((code2 & 1) != 0 && (cx1 > newx2 || newx2 == Integer.MAX_VALUE)) {
+ // clip point 2 with left clip bound
+ newx2 = cx1;
+ newy2 = clipX(dx, dy, newx2, false);
+ } else if ((code2 & 2) != 0 && (newx2 >= cx2 || newx2 == Integer.MAX_VALUE)) {
+ // clip point 2 with right clip bound
+ newx2 = cx2 - 1;
+ newy2 = clipX(dx, dy, newx2, false);
+ }
+ if (newx2 < cx1 || newx2 >= cx2 || newy2 < cy1 || newy2 >= cy2) {
+ return;
+ }
+ nx2 = x1 + newx2;
+ ny2 = y1 + newy2;
+ }
+ nx1 = x1 + newx1;
+ ny1 = y1 + newy1;
+
+ rasterizeClipped(nx1, ny1, nx2, ny2);
+ }
+
+ abstract void rasterizeClipped(int nx1, int ny1, int nx2, int ny2);
+
+ }
+
+ static abstract class Ortog extends Line {
+
+ Ortog(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ }
+
+ static class Hor extends Ortog {
+
+ int dx;
+
+ Hor(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ dx = x2 - x1;
+ }
+
+ @Override
+ void rasterize() {
+ if (dx > 0) {
+ dst.addRect(x1, y1, x2, y2);
+ } else {
+ dst.addRect(x2, y2, x1, y1);
+ }
+ }
+
+ @Override
+ void rasterize(int step) {
+ int px = x;
+ if (dx > 0) {
+ x += step;
+ dst.addRect(px, y1, x - 1, y2);
+ } else {
+ x -= step;
+ dst.addRect(x + 1, y2, px, y1);
+ }
+ }
+
+ @Override
+ void skip(int step) {
+ if (dx > 0) {
+ x += step;
+ } else {
+ x -= step;
+ }
+ }
+
+ void rasterizeClipped(int nx1, int nx2) {
+ if (nx1 < nx2) {
+ dst.addRect(nx1, y1, nx2, y1);
+ } else {
+ dst.addRect(nx2, y1, nx1, y1);
+ }
+ }
+
+ @Override
+ void rasterize(int[] clip, int index) {
+ if (y1 >= clip[index + 1] && y1 <= clip[index + 3]) {
+ int cx1 = clip[index + 0];
+ int cx2 = clip[index + 2];
+ if (x1 <= cx2 && x2 >= cx1) {
+ int nx1, nx2;
+ if (dx > 0) {
+ nx1 = Math.max(x1, cx1);
+ nx2 = Math.min(x2, cx2);
+ } else {
+ nx2 = Math.max(x2, cx1);
+ nx1 = Math.min(x1, cx2);
+ }
+ rasterizeClipped(nx1, nx2);
+ }
+ }
+ }
+
+ }
+
+ static class Ver extends Ortog {
+
+ int dy;
+
+ Ver(int x1, int y1, int x2, int y2, MultiRectArea dst) {
+ super(x1, y1, x2, y2, dst);
+ dy = y2 - y1;
+ }
+
+ @Override
+ void rasterize() {
+ dst.addRect(x1, y1, x2, y2);
+ }
+
+ @Override
+ void rasterize(int step) {
+ int py = y;
+ y += step;
+ dst.addRect(x1, py, x2, y - 1);
+ }
+
+ @Override
+ void skip(int step) {
+ y += step;
+ }
+
+ void rasterizeClipped(int ny1, int ny2) {
+ dst.addRect(x1, ny1, x1, ny2);
+ }
+
+ @Override
+ void rasterize(int[] clip, int index) {
+ if (x1 >= clip[index] && x1 <= clip[index + 2]) {
+ int cy1 = clip[index + 1];
+ int cy2 = clip[index + 3];
+ if (y1 <= cy2 && y2 >= cy1) {
+ rasterizeClipped(Math.max(y1, cy1), Math.min(y2, cy2));
+ }
+ }
+ }
+
+ }
+
+ static class HorDashed extends Hor {
+
+ LineDasher local;
+
+ HorDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher) {
+ super(x1, y1, x2, y2, dst);
+ dx = x2 - x1;
+ local = dasher.createOrtogonal(Math.abs(dx), false);
+ }
+
+ @Override
+ void rasterize() {
+ x = x1;
+ y = y1;
+ rasterizeDash(Math.abs(dx), local);
+ }
+
+ @Override
+ void rasterizeClipped(int nx1, int nx2) {
+ x = nx1;
+ y = y1;
+ rasterizeDash(Math.abs(nx2 - nx1), local.createChild(Math.abs(nx1 - x1)));
+ }
+
+ }
+
+ static class VerDashed extends Ver {
+
+ LineDasher local;
+
+ VerDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) {
+ super(x1, y1, x2, y2, dst);
+ dy = y2 - y1;
+ local = dasher.createOrtogonal(dy, invert);
+ }
+
+ @Override
+ void rasterize() {
+ x = x1;
+ y = y1;
+ rasterizeDash(dy, local);
+ }
+
+ @Override
+ void rasterizeClipped(int ny1, int ny2) {
+ x = x1;
+ y = ny1;
+ rasterizeDash(ny2 - ny1, local.createChild(ny1));
+ }
+
+ }
+
+ }
+
+ abstract void rasterize();
+ abstract void rasterize(int[] clip, int index);
+ abstract void rasterize(int count);
+ abstract void skip(int count);
+
+ void rasterizeDash(int count, LineDasher dasher) {
+ float delta = dasher.dash[dasher.index] - dasher.phase;
+ int step = (int)delta;
+ delta -= step;
+ while(count > step) {
+ if (dasher.visible) {
+ rasterize(step);
+ } else {
+ skip(step);
+ }
+ count -= step;
+ delta += dasher.nextDash();
+ step = (int)delta;
+ delta -= step;
+ }
+ if (count > 0 && dasher.visible) {
+ rasterize(count);
+ dasher.move(count);
+ }
+ }
+
+ }
+
+ /**
+ * Common clipping method
+ */
+ static int clip(int dX1, int dX2, int cX, boolean top) {
+ int adX1 = dX1 < 0 ? -dX1 : dX1;
+ int adX2 = dX2 < 0 ? -dX2 : dX2;
+ if (adX1 <= adX2) {
+ // obtuse intersection angle
+ return ((dX1 << 1) * cX + (dX1 > 0 ? dX2 : -dX2)) / (dX2 << 1);
+ }
+ int k;
+ if (top) {
+ k = -dX1 + (dX2 < 0 ? 0 : dX1 > 0 ? (dX2 << 1) : -(dX2 << 1));
+ } else {
+ k = dX1 + (dX2 > 0 ? 0 : dX1 > 0 ? (dX2 << 1) : -(dX2 << 1));
+ }
+
+ k += dX1 > 0 == dX2 > 0 ? -1 : 1;
+ return ((dX1 << 1) * cX + k) / (dX2 << 1);
+ }
+
+ /**
+ * Clipping along X axis
+ */
+ static int clipX(int dx, int dy, int cy, boolean top) {
+ return clip(dy, dx, cy, top);
+ }
+
+ /**
+ * Clipping along Y axis
+ */
+ static int clipY(int dx, int dy, int cx, boolean top) {
+ return clip(dx, dy, cx, top);
+ }
+
+ /**
+ * Rasterizes line using clippind and dashing style
+ * @param x1 - the x coordinate of the first control point
+ * @param y1 - the y coordinate of the first control point
+ * @param x2 - the x coordinate of the second control point
+ * @param y2 - the y coordinate of the second control point
+ * @param clip - the MultiRectArea object of clipping area
+ * @param dasher - the dasher style
+ * @param invert - the invert indicator, always false
+ * @return a MultiRectArea of rasterizer line
+ */
+ public static MultiRectArea rasterize(int x1, int y1, int x2, int y2, MultiRectArea clip, LineDasher dasher, boolean invert) {
+
+ MultiRectArea dst = new MultiRectArea(false);
+ int dx = x2 - x1;
+ int dy = y2 - y1;
+
+ // Point
+ if (dx == 0 && dy == 0) {
+ if ((clip == null || clip.contains(x1, y1)) && (dasher == null || dasher.visible)) {
+ dst = new MultiRectArea(x1, y1, x1, y1);
+ }
+ return dst;
+ }
+
+ if (dy < 0) {
+ return rasterize(x2, y2, x1, y1, clip, dasher, true);
+ }
+
+ Line line;
+ if (dasher == null) {
+ if (dx == 0) {
+ line = new Line.Ortog.Ver(x1, y1, x2, y2, dst);
+ } else
+ if (dy == 0) {
+ line = new Line.Ortog.Hor(x1, y1, x2, y2, dst);
+ } else {
+ if (dy < Math.abs(dx)) {
+ line = new Line.Diag.Hor(x1, y1, x2, y2, dst);
+ } else {
+ line = new Line.Diag.Ver(x1, y1, x2, y2, dst);
+ }
+ }
+ } else {
+ if (dx == 0) {
+ line = new Line.Ortog.VerDashed(x1, y1, x2, y2, dst, dasher, invert);
+ } else
+ if (dy == 0) {
+ line = new Line.Ortog.HorDashed(x1, y1, x2, y2, dst, dasher);
+ } else {
+ if (dy < Math.abs(dx)) {
+ line = new Line.Diag.HorDashed(x1, y1, x2, y2, dst, dasher, invert);
+ } else {
+ line = new Line.Diag.VerDashed(x1, y1, x2, y2, dst, dasher, invert);
+ }
+ }
+ }
+
+
+ if (clip == null || clip.isEmpty()) {
+ line.rasterize();
+ } else {
+ for(int i = 1; i < clip.rect[0]; i += 4) {
+ line.rasterize(clip.rect, i);
+ }
+ }
+
+ return dst;
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java b/awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java
new file mode 100644
index 0000000..dbaaf53
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java
@@ -0,0 +1,475 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.Shape;
+import java.awt.geom.PathIterator;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public class JavaShapeRasterizer {
+
+ static final int POINT_CAPACITY = 16;
+
+ int edgesCount;
+ int edgeCur;
+ int[] edgesX;
+ int[] edgesY;
+ int[] edgesYS; // Y coordinate of edge START point
+ int[] edgesN;
+ int[] edgesDY;
+ int[] bounds;
+ int boundCount;
+ boolean[] edgesExt; // Extremal points
+
+ int activeCount;
+ float[] activeX;
+ int[] activeYEnd;
+ float[] activeXStep;
+ int[] activeDY;
+ boolean[] activeExt;
+
+ int[] crossX;
+ int[] crossDY;
+
+ Filler filler;
+
+ /**
+ * Rasterization filler for different path rules
+ */
+ static abstract class Filler {
+
+ static class NonZero extends Filler {
+ @Override
+ void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y) {
+
+ int[] dst = new int[length];
+ int dstLength = 1;
+ dst[0] = points[0];
+ int count = 0;
+ boolean inside = true;
+ for(int i = 0; i < length; i++) {
+ count += orient[i] > 0 ? 1 : -1;
+ if (count == 0) {
+ dst[dstLength++] = points[i];
+ inside = false;
+ } else {
+ if (!inside) {
+ dst[dstLength++] = points[i];
+ inside = true;
+ }
+ }
+
+ }
+
+ for(int i = 1; i < dstLength; i += 2) {
+ dst[i]--;
+ }
+
+ dstLength = excludeEmpty(dst, dstLength);
+// System.out.println("test");
+
+ dstLength = union(dst, dstLength);
+
+ rect.addLine(dst, dstLength);
+ }
+ }
+
+ static class EvenOdd extends Filler {
+ @Override
+ void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y) {
+ /*
+ int[] buf = new int[length];
+ int j = 0;
+ for(int i = 0; i < length - 1; i++) {
+ if (points[i] != points[i + 1]) {
+ buf[j++] = points[i];
+ }
+ }
+ */
+ for(int i = 1; i < length; i += 2) {
+ points[i]--;
+ }
+
+ length = excludeEmpty(points, length);
+// System.out.println("test");
+
+ length = union(points, length);
+ rect.addLine(points, length);
+ /*
+ for(int i = 0; i < length;) {
+ rect.add(points[i++], y, points[i++], y);
+ }
+ */
+ }
+ }
+
+ abstract void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y);
+
+ static int excludeEmpty(int[] points, int length) {
+ int i = 0;
+ while(i < length) {
+ if (points[i] <= points[i + 1]) {
+ i += 2;
+ } else {
+ length -= 2;
+ System.arraycopy(points, i + 2, points, i, length - i);
+ }
+ }
+ return length;
+ }
+
+ static int union(int[] points, int length) {
+ int i = 1;
+ while(i < length - 1) {
+ if (points[i] < points[i - 1]) {
+ System.arraycopy(points, i + 1, points, i - 1, length - i - 1);
+ length -= 2;
+ } else
+ if (points[i] >= points[i + 1] - 1) {
+ System.arraycopy(points, i + 2, points, i, length - i - 2);
+ length -= 2;
+ } else {
+ i += 2;
+ }
+ }
+ return length;
+ }
+
+ }
+
+ public JavaShapeRasterizer() {
+ }
+
+ /**
+ * Checks buffer size and realloc if necessary
+ */
+ int[] checkBufSize(int[] buf, int size) {
+ if (size == buf.length) {
+ int[] tmp;
+ tmp = new int[size + POINT_CAPACITY];
+ System.arraycopy(buf, 0, tmp, 0, buf.length);
+ buf = tmp;
+ }
+ return buf;
+ }
+
+ /**
+ * Adds to the buffers new edge
+ */
+ void addEdge(int x, int y, int num) {
+ edgesX = checkBufSize(edgesX, edgesCount);
+ edgesY = checkBufSize(edgesY, edgesCount);
+ edgesN = checkBufSize(edgesN, edgesCount);
+ edgesX[edgesCount] = x;
+ edgesY[edgesCount] = y;
+ edgesN[edgesCount] = (num << 16) | edgesCount;
+ edgesCount++;
+ }
+
+ /**
+ * Prepare all buffers and variable to rasterize shape
+ */
+ void makeBuffer(PathIterator path, double flatness) {
+ edgesX = new int[POINT_CAPACITY];
+ edgesY = new int[POINT_CAPACITY];
+ edgesN = new int[POINT_CAPACITY];
+ bounds = new int[POINT_CAPACITY];
+ boundCount = 0;
+ edgesCount = 0;
+
+ if (path.getWindingRule() == PathIterator.WIND_EVEN_ODD) {
+ filler = new Filler.EvenOdd();
+ } else {
+ filler = new Filler.NonZero();
+ }
+ float[] coords = new float[2];
+ boolean closed = true;
+ while (!path.isDone()) {
+ switch(path.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (!closed) {
+ boundCount++;
+ bounds = checkBufSize(bounds, boundCount);
+ bounds[boundCount] = edgesCount;
+ }
+ addEdge((int)coords[0], (int)coords[1], boundCount);
+ closed = false;
+ break;
+ case PathIterator.SEG_LINETO:
+ addEdge((int)coords[0], (int)coords[1], boundCount);
+ break;
+ case PathIterator.SEG_CLOSE:
+ boundCount++;
+ bounds = checkBufSize(bounds, boundCount);
+ bounds[boundCount] = edgesCount;
+ closed = true;
+ break;
+ default:
+ // awt.36=Wrong segment
+ throw new RuntimeException(Messages.getString("awt.36")); //$NON-NLS-1$
+ }
+ path.next();
+ }
+ if (!closed) {
+ boundCount++;
+ bounds = checkBufSize(bounds, boundCount);
+ bounds[boundCount] = edgesCount;
+ }
+ }
+
+ /**
+ * Sort buffers
+ */
+ void sort(int[] master, int[] slave, int length) {
+ for(int i = 0; i < length - 1; i++) {
+ int num = i;
+ int min = master[num];
+ for(int j = i + 1; j < length; j++) {
+ if (master[j] < min) {
+ num = j;
+ min = master[num];
+ }
+ }
+ if (num != i) {
+ master[num] = master[i];
+ master[i] = min;
+ min = slave[num];
+ slave[num] = slave[i];
+ slave[i] = min;
+ }
+ }
+ }
+
+ int getNext(int cur) {
+ int n = edgesN[cur];
+ int bound = n >> 16;
+ int num = (n & 0xFFFF) + 1;
+ if (num == bounds[bound + 1]) {
+ return bounds[bound];
+ }
+ return num;
+ }
+
+ int getPrev(int cur) {
+ int n = edgesN[cur];
+ int bound = n >> 16;
+ int num = (n & 0xFFFF) - 1;
+ if (num < bounds[bound]) {
+ return bounds[bound + 1] - 1;
+ }
+ return num;
+ }
+
+ int getNextShape(int cur) {
+ int bound = edgesN[cur] >> 16;
+ return bounds[bound + 1];
+ }
+
+ void init() {
+
+ edgesYS = new int[edgesCount];
+ System.arraycopy(edgesY, 0, edgesYS, 0, edgesCount);
+ // Create edgesDY
+ edgesDY = new int[edgesCount];
+ for(int i = 0; i < edgesCount; i++) {
+ int dy = edgesY[getNext(i)] - edgesY[i];
+ edgesDY[i] = dy;
+ }
+
+ // Create edgesExt
+ edgesExt = new boolean[edgesCount];
+ int prev = -1;
+ int i = 0;
+ int pos = 0;
+ while(i < edgesCount) {
+
+ TOP: {
+ do {
+ if (edgesDY[i] > 0) {
+ break TOP;
+ }
+ i = getNext(i);
+ } while (i != pos);
+ i = pos = getNextShape(i);
+ continue;
+ }
+
+ BOTTOM: {
+ do {
+ if (edgesDY[i] < 0) {
+ break BOTTOM;
+ }
+ if (edgesDY[i] > 0) {
+ prev = i;
+ }
+ i = getNext(i);
+ } while (i != pos);
+ i = pos = getNextShape(i);
+ continue;
+ }
+
+ if (prev != -1) {
+ edgesExt[prev] = true;
+ }
+ edgesExt[i] = true;
+ }
+
+ // Sort edgesY and edgesN
+ sort(edgesYS, edgesN, edgesCount);
+
+ edgeCur = 0;
+ activeCount = 0;
+ activeX = new float[edgesCount];
+ activeYEnd = new int[edgesCount];
+ activeXStep = new float[edgesCount];
+ activeDY = new int[edgesCount];
+ activeExt = new boolean[edgesCount];
+
+ crossX = new int[edgesCount];
+ crossDY = new int[edgesCount];
+ }
+
+ /**
+ * Marks edge as active
+ */
+ void addActiveEdge(int levelY, int start, int end, boolean back) {
+ int dy = back ? -edgesDY[end] : edgesDY[start];
+ if (dy <= 0) {
+ return;
+ }
+ int x1 = edgesX[start];
+ int dx = edgesX[end] - x1;
+ activeX[activeCount] = x1;
+ activeYEnd[activeCount] = edgesY[end];
+ activeXStep[activeCount] = dx / (float)dy;
+ activeDY[activeCount] = back ? -dy : dy;
+ activeExt[activeCount] = back ? edgesExt[end] : edgesExt[start];
+ activeCount++;
+ }
+
+ /**
+ * Find new active edges
+ */
+ int findActiveEdges(int levelY) {
+
+ int edgeActive = edgeCur;
+ while (edgeActive < edgesCount && edgesYS[edgeActive] == levelY) {
+ edgeActive++;
+ }
+
+ int activeNext = edgeActive;
+
+ while (edgeActive > edgeCur) {
+ edgeActive--;
+ int num = edgesN[edgeActive] & 0xFFFF;
+ addActiveEdge(levelY, num, getPrev(edgeActive), true);
+ addActiveEdge(levelY, num, getNext(edgeActive), false);
+ }
+
+ edgeCur = activeNext;
+
+ if (activeNext == edgesCount) {
+ return edgesY[edgesCount - 1];
+ }
+ return edgesYS[activeNext];
+ }
+
+ /**
+ * Rasterizes shape with particular flatness
+ * @param shape - the souze Shape to be rasterized
+ * @param flatness - the rasterization flatness
+ * @return a MultiRectArea of rasterized shape
+ */
+ public MultiRectArea rasterize(Shape shape, double flatness) {
+
+ PathIterator path = shape.getPathIterator(null, flatness);
+
+ // Shape is empty
+ if (path.isDone()) {
+ return new MultiRectArea();
+ }
+
+ makeBuffer(path, flatness);
+
+ init();
+
+ int y = edgesYS[0];
+ int nextY = y;
+ int crossCount;
+
+ MultiRectArea.LineCash rect = new MultiRectArea.LineCash(edgesCount);
+ rect.setLine(y);
+
+ while(y <= nextY) {
+
+ crossCount = 0;
+
+ if (y == nextY) {
+
+ int i = activeCount;
+ while(i > 0) {
+ i--;
+ if (activeYEnd[i] == y) {
+
+ activeCount--;
+ int length = activeCount - i;
+ if (length != 0) {
+ int pos = i + 1;
+ System.arraycopy(activeX, pos, activeX, i, length);
+ System.arraycopy(activeYEnd, pos, activeYEnd, i, length);
+ System.arraycopy(activeXStep, pos, activeXStep, i, length);
+ System.arraycopy(activeDY, pos, activeDY, i, length);
+ System.arraycopy(activeExt, pos, activeExt, i, length);
+ }
+ }
+ }
+
+ nextY = findActiveEdges(y);
+ }
+
+ // Get X crossings
+ for(int i = 0; i < activeCount; i++) {
+ crossX[crossCount] = (int)Math.ceil(activeX[i]);
+ crossDY[crossCount] = activeDY[i];
+ crossCount++;
+ }
+
+ if (crossCount == 0) {
+ rect.skipLine();
+ } else {
+ // Sort X crossings
+ sort(crossX, crossDY, crossCount);
+ filler.add(rect, crossX, crossDY, crossCount, y);
+ }
+
+ for(int i = 0; i < activeCount; i++) {
+ activeX[i] += activeXStep[i];
+ }
+
+ y++;
+ }
+
+ return rect;
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java b/awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java
new file mode 100644
index 0000000..322ba57
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/JavaTextRenderer.java
@@ -0,0 +1,263 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Ilya S. Okomin
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.*;
+import java.awt.image.*;
+
+
+import java.awt.font.GlyphMetrics;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+
+import org.apache.harmony.awt.gl.TextRenderer;
+import org.apache.harmony.awt.gl.font.CommonGlyphVector;
+import org.apache.harmony.awt.gl.font.FontPeerImpl;
+import org.apache.harmony.awt.gl.font.Glyph;
+import org.apache.harmony.awt.gl.image.BufferedImageGraphics2D;
+
+public class JavaTextRenderer extends TextRenderer {
+
+ public static final JavaTextRenderer inst = new JavaTextRenderer();
+
+ @Override
+ public void drawGlyphVector(Graphics2D g, GlyphVector glyphVector,
+ float x, float y) {
+
+ AffineTransform at = g.getTransform();
+ Rectangle c = g.getClipBounds();
+ if (at != null){
+ int atType = at.getType();
+ if (atType == AffineTransform.TYPE_TRANSLATION) {
+ c.translate((int)Math.round(at.getTranslateX()), (int)Math.round(at.getTranslateY()));
+ }
+ }
+
+ WritableRaster wr = ((BufferedImageGraphics2D)g).getWritableRaster();
+ ColorModel cm = ((BufferedImageGraphics2D)g).getColorModel();
+
+ Rectangle rBounds = wr.getBounds();
+
+ Object color = cm.getDataElements(g.getColor().getRGB(), null);
+
+ drawClipGlyphVector(wr, color, glyphVector, (int)Math.round(x + at.getTranslateX()), (int)Math.round(y + at.getTranslateY()),
+ Math.max(c.x,rBounds.x),
+ Math.max(c.y,rBounds.y),
+ Math.min((int)Math.round(c.getMaxX()), (int)Math.round(rBounds.getMaxX())),
+ Math.min((int)Math.round(c.getMaxY()), (int)Math.round(rBounds.getMaxY())));
+
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void drawString(Graphics2D g, String str, float x, float y) {
+ AffineTransform at = g.getTransform();
+ Rectangle c = g.getClipBounds();
+ if (at != null){
+ int atType = at.getType();
+ if (atType == AffineTransform.TYPE_TRANSLATION) {
+ c.translate((int)Math.round(at.getTranslateX()), (int)Math.round(at.getTranslateY()));
+ }
+ }
+ WritableRaster wr = ((BufferedImageGraphics2D)g).getWritableRaster();
+ ColorModel cm = ((BufferedImageGraphics2D)g).getColorModel();
+ Rectangle rBounds = wr.getBounds();
+
+ Object color = cm.getDataElements(g.getColor().getRGB(), null);
+
+ drawClipString(wr, color, str, (FontPeerImpl) (g.getFont().getPeer()),
+ (int)Math.round(x + at.getTranslateX()), (int)Math.round(y + at.getTranslateY()),
+ Math.max(c.x,rBounds.x),
+ Math.max(c.y,rBounds.y),
+ Math.min((int)Math.round(c.getMaxX()), (int)Math.round(rBounds.getMaxX())),
+ Math.min((int)Math.round(c.getMaxY()), (int)Math.round(rBounds.getMaxY())));
+
+ }
+
+ /**
+ *
+ * Draws string on specified raster at desired position.
+ *
+ * @param raster specified WritableRaster to draw at
+ * @param color color of the text
+ * @param glyphVector GlyphVector object to draw
+ * @param x start X position to draw
+ * @param y start Y position to draw
+ * @param cMinX minimum x of the raster area to draw
+ * @param cMinY minimum y of the raster area to draw
+ * @param cMaxX maximum x of the raster area to draw
+ * @param cMaxY maximum y of the raster area to draw
+ */
+ public void drawClipGlyphVector(WritableRaster raster, Object color,
+ GlyphVector glyphVector, int x, int y,
+ int cMinX, int cMinY, int cMaxX, int cMaxY) {
+ // TODO: implement complex clipping
+
+ int xSrcSurf, ySrcSurf; // Start point in String rectangle
+ int xDstSurf, yDstSurf; // Start point in Surface rectangle
+ int clWidth, clHeight;
+
+ for (int i = 0; i < glyphVector.getNumGlyphs(); i++) {
+ Glyph gl = ((CommonGlyphVector) glyphVector).vector[i];
+
+ if (gl.getPointWidth() == 0) {
+ continue;
+ }
+
+ byte[] data = gl.getBitmap();
+ if (data != null) {
+ Point2D pos = glyphVector.getGlyphPosition(i);
+
+ xSrcSurf = 0;//gl.bmp_left;
+ ySrcSurf = 0;//gl.bmp_rows - gl.bmp_top;
+
+ xDstSurf = x + (int)pos.getX() + (int) gl.getGlyphPointMetrics().getLSB();// + gl.bmp_left;
+ yDstSurf = y - gl.bmp_top/*getPointHeight()*/ + (int) pos.getY();// - (gl.bmp_rows-gl.bmp_top);
+
+ int textWidth = gl.bmp_width;
+ int textHeight = gl.getPointHeight();
+
+ // if Regions don't intersect
+ if ((xDstSurf > cMaxX) || (yDstSurf > cMaxY) || (xDstSurf + textWidth < cMinX)
+ || (yDstSurf + textHeight < cMinY)) {
+ // Nothing to do
+ } else {
+ if (xDstSurf >= cMinX) {
+ clWidth = Math.min(textWidth, cMaxX - xDstSurf);
+ } else {
+ xSrcSurf += cMinX - xDstSurf;
+ clWidth = Math.min(cMaxX - cMinX, textWidth - (cMinX - xDstSurf));
+ xDstSurf = cMinX;
+ }
+ if (yDstSurf >= cMinY) {
+ clHeight = Math.min(textHeight, cMaxY - yDstSurf);
+ } else {
+ ySrcSurf += cMinY - yDstSurf;
+ clHeight = Math.min(cMaxY - cMinY, textHeight - (cMinY - yDstSurf));
+ yDstSurf = cMinY;
+ }
+ // Drawing on the Raster
+ for (int h=0; h<clHeight; h++){
+ for (int w=0; w < clWidth ; w++) {
+ byte currByte = data[(ySrcSurf + h)*gl.bmp_pitch + (xSrcSurf+w)/8];
+ boolean emptyByte = ((currByte & (1 << (7 - ((xSrcSurf+w) % 8)))) != 0);
+ if (emptyByte) {
+ raster.setDataElements(xDstSurf+w, yDstSurf+h, color);
+ } else {
+ // Nothing to do
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Draws string on specified raster at desired position.
+ *
+ * @param raster specified WritableRaster to draw at
+ * @param color color of the text
+ * @param str text to draw
+ * @param font font peer to use for drawing text
+ * @param x start X position to draw
+ * @param y start Y position to draw
+ * @param cMinX minimum x of the raster area to draw
+ * @param cMinY minimum y of the raster area to draw
+ * @param cMaxX maximum x of the raster area to draw
+ * @param cMaxY maximum y of the raster area to draw
+ */
+ public void drawClipString(WritableRaster raster, Object color, String str,
+ FontPeerImpl font, int x, int y, int cMinX, int cMinY, int cMaxX,
+ int cMaxY) {
+ // TODO: implement complex clipping
+
+ int xSrcSurf, ySrcSurf; // Start point in String rectangle
+ int xDstSurf, yDstSurf; // Start point in Surface rectangle
+ int clWidth, clHeight;
+
+ char[] chars = str.toCharArray();
+
+ int xBaseLine = x;
+ int yBaseLine = y;
+
+ for (char element : chars) {
+ Glyph gl = font.getGlyph(element);
+ GlyphMetrics pointMetrics = gl.getGlyphPointMetrics();
+ if (gl.getWidth() == 0) {
+ xBaseLine += pointMetrics.getAdvanceX();
+ continue;
+ }
+
+ byte[] data = gl.getBitmap();
+ if (data == null) {
+ xBaseLine += pointMetrics.getAdvanceX();
+ } else {
+
+ xSrcSurf = 0;
+ ySrcSurf = 0;
+
+ xDstSurf = Math.round(xBaseLine + gl.getGlyphPointMetrics().getLSB());
+ yDstSurf = yBaseLine - gl.bmp_top;
+
+ int textWidth = gl.bmp_width;
+ int textHeight = gl.getPointHeight();
+
+ // if Regions don't intersect
+ if ((xDstSurf > cMaxX) || (yDstSurf > cMaxY) || (xDstSurf + textWidth < cMinX)
+ || (yDstSurf + textHeight < cMinY)) {
+ // Nothing to do
+ } else {
+ if (xDstSurf >= cMinX) {
+ clWidth = Math.min(textWidth, cMaxX - xDstSurf);
+ } else {
+ xSrcSurf += cMinX - xDstSurf;
+ clWidth = Math.min(cMaxX - cMinX, textWidth - (cMinX - xDstSurf));
+ xDstSurf = cMinX;
+ }
+ if (yDstSurf >= cMinY) {
+ clHeight = Math.min(textHeight, cMaxY - yDstSurf);
+ } else {
+ ySrcSurf += cMinY - yDstSurf;
+ clHeight = Math.min(cMaxY - cMinY, textHeight - (cMinY - yDstSurf));
+ yDstSurf = cMinY;
+ }
+
+ // Drawing on the Raster
+ for (int h=0; h<clHeight; h++){
+ for (int w=0; w < clWidth ; w++) {
+ byte currByte = data[(ySrcSurf + h)*gl.bmp_pitch + (xSrcSurf+w)/8];
+ boolean emptyByte = ((currByte & (1 << (7 - ((xSrcSurf+w) % 8)))) != 0);
+ if (emptyByte) {
+ raster.setDataElements(xDstSurf+w, yDstSurf+h, color);
+ } else {
+ // Nothing to do
+ }
+ }
+ }
+ }
+ xBaseLine += pointMetrics.getAdvanceX();
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java b/awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java
new file mode 100644
index 0000000..b0ebc97
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/NativeImageBlitter.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 26.11.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+
+import org.apache.harmony.awt.gl.ImageSurface;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+import org.apache.harmony.awt.gl.XORComposite;
+
+/**
+ * This kind of blitters is intended for drawing one image on the buffered
+ * or volatile image. For the moment we can blit natively Buffered Images which
+ * have sRGB, Linear_RGB, Linear_Gray Color Space and type different
+ * from BufferedImage.TYPE_CUSTOM, Volatile Images and Images which received
+ * using Toolkit and Component classes.
+ */
+public class NativeImageBlitter implements Blitter {
+
+
+ final static NativeImageBlitter inst = new NativeImageBlitter();
+
+ public static NativeImageBlitter getInstance(){
+ return inst;
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ AffineTransform xform, Composite comp, Color bgcolor,
+ MultiRectArea clip) {
+
+ if(!srcSurf.isNativeDrawable()){
+ JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ sysxform, xform, comp, bgcolor, clip);
+ }else{
+ if(xform == null){
+ blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }else{
+ double scaleX = xform.getScaleX();
+ double scaleY = xform.getScaleY();
+ double scaledX = dstX / scaleX;
+ double scaledY = dstY / scaleY;
+ AffineTransform at = new AffineTransform();
+ at.setToTranslation(scaledX, scaledY);
+ xform.concatenate(at);
+ sysxform.concatenate(xform);
+ blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }
+ }
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ Composite comp, Color bgcolor, MultiRectArea clip) {
+
+ if(!srcSurf.isNativeDrawable()){
+ JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }else{
+ int type = sysxform.getType();
+ switch(type){
+ case AffineTransform.TYPE_TRANSLATION:
+ dstX += sysxform.getTranslateX();
+ dstY += sysxform.getTranslateY();
+ case AffineTransform.TYPE_IDENTITY:
+ blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
+ width, height, comp, bgcolor, clip);
+ break;
+ default:
+ // TODO Need to realize Affine Transformation
+ if(srcSurf instanceof ImageSurface){
+ JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY,
+ dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }else{
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ BufferedImage tmp = new BufferedImage(w, h,
+ BufferedImage.TYPE_INT_RGB);
+ Surface tmpSurf = Surface.getImageSurface(tmp);
+ blit(0, 0, srcSurf, 0, 0, tmpSurf,
+ w, h, AlphaComposite.SrcOver, null, null);
+ JavaBlitter.inst.blit(srcX, srcY, tmpSurf, dstX, dstY,
+ dstSurf, width, height,
+ sysxform, comp, bgcolor, clip);
+ }
+ }
+ }
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+
+ if(!srcSurf.isNativeDrawable()){
+ JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height,
+ comp, bgcolor, clip);
+ }else{
+ long dstSurfStruct = dstSurf.getSurfaceDataPtr();
+ Object dstData = dstSurf.getData();
+ int clipRects[];
+ if(clip != null){
+ clipRects = clip.rect;
+ }else{
+ clipRects = new int[]{5, 0, 0, dstSurf.getWidth(),
+ dstSurf.getHeight()};
+ }
+
+ if(!(srcSurf instanceof ImageSurface)){
+ srcSurf = srcSurf.getImageSurface();
+ if(bgcolor != null){
+ bgcolor = null;
+ }
+ }
+
+ long srcSurfStruct = srcSurf.getSurfaceDataPtr();
+ Object srcData = srcSurf.getData();
+ if(comp instanceof AlphaComposite){
+ AlphaComposite ac = (AlphaComposite) comp;
+ int compType = ac.getRule();
+ float alpha = ac.getAlpha();
+ if(bgcolor != null){
+ bltBG(srcX, srcY, srcSurfStruct, srcData,
+ dstX, dstY, dstSurfStruct, dstData,
+ width, height, bgcolor.getRGB(),
+ compType, alpha, clipRects, srcSurf.invalidated());
+ dstSurf.invalidate();
+ srcSurf.validate();
+ }else{
+ blt(srcX, srcY, srcSurfStruct, srcData,
+ dstX, dstY, dstSurfStruct, dstData,
+ width, height, compType, alpha,
+ clipRects, srcSurf.invalidated());
+ dstSurf.invalidate();
+ srcSurf.validate();
+ }
+ }else if(comp instanceof XORComposite){
+ XORComposite xcomp = (XORComposite) comp;
+ xor(srcX, srcY, srcSurfStruct, srcData,
+ dstX, dstY, dstSurfStruct, dstData,
+ width, height, xcomp.getXORColor().getRGB(),
+ clipRects, srcSurf.invalidated());
+ dstSurf.invalidate();
+ srcSurf.validate();
+ }else{
+ if(srcSurf instanceof ImageSurface){
+ JavaBlitter.inst.blit(srcX, srcY, srcSurf, dstX, dstY,
+ dstSurf, width, height,
+ comp, bgcolor, clip);
+ }else{
+ int w = srcSurf.getWidth();
+ int h = srcSurf.getHeight();
+ BufferedImage tmp = new BufferedImage(w, h,
+ BufferedImage.TYPE_INT_RGB);
+ Surface tmpSurf = Surface.getImageSurface(tmp);
+ long tmpSurfStruct = tmpSurf.getSurfaceDataPtr();
+ Object tmpData = tmpSurf.getData();
+ int tmpClip[] = new int[]{5, 0, 0, srcSurf.getWidth(),
+ srcSurf.getHeight()};
+
+ blt(0, 0, srcSurfStruct, srcData, 0, 0,
+ tmpSurfStruct, tmpData, w, h,
+ AlphaComposite.SRC_OVER,
+ 1.0f, tmpClip, srcSurf.invalidated());
+ srcSurf.validate();
+ JavaBlitter.inst.blit(srcX, srcY, tmpSurf, dstX, dstY,
+ dstSurf, width, height,
+ comp, bgcolor, clip);
+ }
+ }
+ }
+
+ }
+
+ private native void bltBG(int srcX, int srcY, long srsSurfDataPtr,
+ Object srcData, int dstX, int dstY, long dstSurfDataPtr,
+ Object dstData, int width, int height, int bgcolor,
+ int compType, float alpha, int clip[], boolean invalidated);
+
+ private native void blt(int srcX, int srcY, long srsSurfDataPtr,
+ Object srcData, int dstX, int dstY, long dstSurfDataPtr,
+ Object dstData, int width, int height, int compType,
+ float alpha, int clip[], boolean invalidated);
+
+ private native void xor(int srcX, int srcY, long srsSurfDataPtr,
+ Object srcData, int dstX, int dstY, long dstSurfDataPtr,
+ Object dstData, int width, int height, int xorcolor,
+ int clip[], boolean invalidated);
+
+
+}
diff --git a/awt/org/apache/harmony/awt/gl/render/NullBlitter.java b/awt/org/apache/harmony/awt/gl/render/NullBlitter.java
new file mode 100644
index 0000000..9032e4e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/render/NullBlitter.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Igor V. Stolyarov
+ * @version $Revision$
+ * Created on 07.12.2005
+ *
+ */
+package org.apache.harmony.awt.gl.render;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.geom.AffineTransform;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.Surface;
+
+
+public class NullBlitter implements Blitter {
+
+ static Blitter inst = new NullBlitter();
+ public static Blitter getInstance(){
+ return inst;
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ AffineTransform xform, Composite comp, Color bgcolor,
+ MultiRectArea clip) {
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, AffineTransform sysxform,
+ Composite comp, Color bgcolor, MultiRectArea clip) {
+ }
+
+ public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY,
+ Surface dstSurf, int width, int height, Composite comp,
+ Color bgcolor, MultiRectArea clip) {
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/im/InputMethodContext.java b/awt/org/apache/harmony/awt/im/InputMethodContext.java
new file mode 100644
index 0000000..45ed11f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/im/InputMethodContext.java
@@ -0,0 +1,563 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.im;
+
+//???AWT
+import java.awt.AWTEvent;
+import java.awt.Component;
+//import java.awt.KeyboardFocusManager;
+import java.awt.Rectangle;
+//import java.awt.Window;
+import java.awt.event.FocusEvent;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.KeyEvent;
+import java.awt.font.TextHitInfo;
+import java.awt.im.InputContext;
+import java.awt.im.InputMethodRequests;
+import java.awt.im.spi.InputMethod;
+import java.awt.im.spi.InputMethodDescriptor;
+import java.lang.Character.Subset;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+//???AWT
+//import javax.swing.JFrame;
+
+import org.apache.harmony.awt.wtk.NativeIM;
+
+/**
+ * Implementation of InputMethodContext
+ * interface, also provides all useful
+ * functionality of InputContext
+ *
+ */
+public class InputMethodContext extends InputContext implements
+ java.awt.im.spi.InputMethodContext {
+
+ //???AWT
+ private InputMethod inputMethod; // current IM
+ private Component client; // current "active" client component
+ //???AWT: private CompositionWindow composeWindow; // composition Window
+ private final Map<InputMethodDescriptor, InputMethod> imInstances; // Map<InputMethodDescriptor, InputMethod>
+ private final Map<Locale, InputMethod> localeIM; // Map<Locale, InputMethod> last user-selected IM for locale
+ private final Set<InputMethod> notifyIM; // set of IMs to notify of client window bounds changes
+
+ /**
+ * a flag indicating that IM should be notified of client window
+ * position/visibility changes as soon as it is activated(new client
+ * appears)
+ */
+ private boolean pendingClientNotify;
+ private Component nextComp; // component to gain focus after endComposition()
+ //???AWT: private final Set<Window> imWindows; // set of all IM windows created by this instance
+ private final NativeIM nativeIM;
+
+
+
+ public InputMethodContext() {
+ notifyIM = new HashSet<InputMethod>();
+//???AWT: imWindows = new HashSet<Window>();
+ imInstances = new HashMap<InputMethodDescriptor, InputMethod>();
+ localeIM = new HashMap<Locale, InputMethod>();
+ selectInputMethod(Locale.US); // not default?
+ nativeIM = (NativeIM) inputMethod;
+ }
+
+ //???AWT
+ /*
+ @Override
+ public void dispatchEvent(AWTEvent event) {
+ int id = event.getID();
+ if ((id >= FocusEvent.FOCUS_FIRST) && (id <=FocusEvent.FOCUS_LAST)) {
+ dispatchFocusEvent((FocusEvent) event);
+ } else {
+ // handle special KEY_PRESSED
+ // event to show IM selection menu
+ if (id == KeyEvent.KEY_PRESSED) {
+ KeyEvent ke = (KeyEvent) event;
+ IMManager.selectIM(ke, this,
+ IMManager.getWindow(ke.getComponent()));
+ }
+ // dispatch all input events to the current IM:
+ if (inputMethod != null) {
+ inputMethod.dispatchEvent(event);
+ }
+ }
+ }
+
+ private void dispatchFocusEvent(FocusEvent fe) {
+ switch (fe.getID()) {
+ case FocusEvent.FOCUS_LOST:
+ if (inputMethod != null) {
+ inputMethod.deactivate(fe.isTemporary());
+ }
+ break;
+ case FocusEvent.FOCUS_GAINED:
+
+ Component comp = fe.getComponent();
+ if (imWindows.contains(comp)) {
+ // prevent activating when IM windows
+ // attached to this context gain focus
+ return;
+ }
+ InputMethodContext lastActive = IMManager.getLastActiveIMC();
+ if ((lastActive != this) && (lastActive != null)) {
+ lastActive.hideWindows();
+ }
+ if (inputMethod != null) {
+ activateIM(inputMethod);
+ if (!getCompositionWindow().isEmpty()) {
+ IMManager.showCompositionWindow(composeWindow);
+ }
+ if (client == comp) {
+ if (nextComp != null) {
+ // temporarily got focus to
+ // end composition
+ endComposition();
+
+ // transfer focus to new client
+ client = nextComp;
+ nextComp = null;
+ client.requestFocusInWindow();
+ }
+ } else if ((client != null) && getCompositionWindow().isVisible()) {
+ // temporarily return focus back
+ // to previous client to be able
+ // to end composition
+ nextComp = comp;
+ client.requestFocusInWindow();
+ } else {
+ client = comp;
+ }
+ }
+ if (pendingClientNotify) {
+ notifyClientWindowChange(IMManager.getWindow(comp).getBounds());
+ }
+ break;
+ }
+
+ }
+
+ private void activateIM(InputMethod im) {
+ im.activate();
+ if ((nativeIM != null) && (im != nativeIM)) {
+ // when Java IM is active
+ // native input method editor must be
+ // explicitly disabled
+ nativeIM.disableIME();
+ }
+ IMManager.setLastActiveIMC(this);
+ }
+
+ @SuppressWarnings("deprecation")
+ private void hideWindows() {
+ if (inputMethod != null) {
+ inputMethod.hideWindows();
+ }
+ if (composeWindow != null) {
+ composeWindow.hide();
+ }
+ }
+
+ private void createCompositionWindow() {
+ composeWindow = new CompositionWindow(client);
+ }
+
+ private CompositionWindow getCompositionWindow() {
+ if (composeWindow == null) {
+ createCompositionWindow();
+ }
+ composeWindow.setClient(client);
+ return composeWindow;
+ }
+ */
+
+ /**
+ * Gets input method requests for the current client
+ * irrespective of input style.
+ * @return input method requests of composition window if
+ * client is passive,
+ * otherwise input method requests of client
+ */
+ private InputMethodRequests getIMRequests() {
+ InputMethodRequests imRequests = null;
+
+ if (client != null) {
+ imRequests = client.getInputMethodRequests();
+ //???AWT
+ /*
+ if (imRequests == null) {
+ imRequests = getCompositionWindow().getInputMethodRequests();
+ }
+ */
+ }
+
+ return imRequests;
+ }
+
+ /**
+ * Gets input method requests for the current client & input style.
+ * @return input method requests of composition window if
+ * input style is "below-the-spot"(or client is passive),
+ * otherwise client input method requests
+ */
+ private InputMethodRequests getStyleIMRequests() {
+ //???AWT
+ /*
+ if (IMManager.belowTheSpot()) {
+ return getCompositionWindow().getInputMethodRequests();
+ }
+ */
+ return getIMRequests();
+ }
+
+ @Override
+ public void dispose() {
+ if (inputMethod != null) {
+ closeIM(inputMethod);
+ inputMethod.dispose();
+ }
+ notifyIM.clear();
+ super.dispose();
+ }
+
+ @Override
+ public void endComposition() {
+ if (inputMethod != null) {
+ inputMethod.endComposition();
+ }
+ super.endComposition();
+ }
+
+ @Override
+ public Object getInputMethodControlObject() {
+ if (inputMethod != null) {
+ return inputMethod.getControlObject();
+ }
+ return super.getInputMethodControlObject();
+ }
+
+ @Override
+ public Locale getLocale() {
+ if (inputMethod != null) {
+ return inputMethod.getLocale();
+ }
+ return super.getLocale();
+ }
+
+ @Override
+ public boolean isCompositionEnabled() {
+ if (inputMethod != null) {
+ return inputMethod.isCompositionEnabled();
+ }
+ return super.isCompositionEnabled();
+ }
+
+ @Override
+ public void reconvert() {
+ if (inputMethod != null) {
+ inputMethod.reconvert();
+ }
+ super.reconvert();
+ }
+
+ //???AWT
+ /*
+ @Override
+ public void removeNotify(Component client) {
+ if ((inputMethod != null) && (client == this.client)) {
+ inputMethod.removeNotify();
+ client = null;
+ // set flag indicating that IM should be notified
+ // as soon as it is activated(new client appears)
+ pendingClientNotify = true;
+ }
+
+ super.removeNotify(client);
+ }
+ */
+
+ @Override
+ public boolean selectInputMethod(Locale locale) {
+
+ if ((inputMethod != null) && inputMethod.setLocale(locale)) {
+ return true;
+ }
+ // first
+ // take last user-selected IM for locale
+ InputMethod newIM = localeIM.get(locale);
+
+ // if not found search through IM descriptors
+ // and take already created instance if exists
+ // or create, store new IM instance in descriptor->instance map
+ //???AWT
+ /*
+ if (newIM == null) {
+ try {
+ newIM = getIMInstance(IMManager.getIMDescriptors().iterator(),
+ locale);
+ } catch (Exception e) {
+ // ignore exceptions - just return false
+ }
+ }
+ */
+
+ return switchToIM(locale, newIM);
+ }
+
+ private boolean switchToIM(Locale locale, InputMethod newIM) {
+ //???AWT
+ /*
+ if (newIM != null) {
+ closeIM(inputMethod);
+ client = KeyboardFocusManager.
+ getCurrentKeyboardFocusManager().getFocusOwner();
+ initIM(newIM, locale);
+ inputMethod = newIM;
+
+ return true;
+ }
+ */
+ return false;
+ }
+
+ /**
+ * Is called when IM is selected from UI
+ */
+ void selectIM(InputMethodDescriptor imd, Locale locale) {
+ try {
+ switchToIM(locale, getIMInstance(imd));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Gets input method instance for the given
+ * locale from the given list of descriptors
+ * @param descriptors iterator of the list of IM descriptors
+ * @param locale the locale to be supported by the IM
+ * @return input method instance
+ * @throws Exception
+ */
+ private InputMethod getIMInstance(Iterator<InputMethodDescriptor> descriptors,
+ Locale locale) throws Exception {
+ while (descriptors.hasNext()) {
+ InputMethodDescriptor desc = descriptors.next();
+ Locale[] locs = desc.getAvailableLocales();
+ for (Locale element : locs) {
+ if (locale.equals(element)) {
+ return getIMInstance(desc);
+ }
+ }
+ }
+ return null;
+ }
+
+ private InputMethod getIMInstance(InputMethodDescriptor imd) throws Exception {
+ InputMethod im = imInstances.get(imd);
+ if (im == null) {
+ im = imd.createInputMethod();
+ im.setInputMethodContext(this);
+ imInstances.put(imd, im);
+ }
+ return im;
+ }
+
+ private void initIM(InputMethod im, Locale locale) {
+ if (im == null) {
+ return;
+ }
+ im.setLocale(locale);
+ im.setCharacterSubsets(null);
+ //???AWT: activateIM(im);
+ try {
+ im.setCompositionEnabled(inputMethod != null ?
+ inputMethod.isCompositionEnabled() : true);
+ } catch (UnsupportedOperationException uoe) {
+
+ }
+
+ }
+
+ private void closeIM(InputMethod im) {
+ if (im == null) {
+ return;
+ }
+ if (im.isCompositionEnabled()) {
+ im.endComposition();
+ }
+
+ im.deactivate(true);
+ im.hideWindows();
+
+ }
+
+ @Override
+ public void setCharacterSubsets(Subset[] subsets) {
+ if (inputMethod != null) {
+ inputMethod.setCharacterSubsets(subsets);
+ }
+ super.setCharacterSubsets(subsets);
+ }
+
+ @Override
+ public void setCompositionEnabled(boolean enable) {
+ if (inputMethod != null) {
+ inputMethod.setCompositionEnabled(enable);
+ }
+ super.setCompositionEnabled(enable);
+ }
+
+ //???AWT
+ /*
+ public JFrame createInputMethodJFrame(String title,
+ boolean attachToInputContext) {
+ JFrame jf = new IMJFrame(title, attachToInputContext ? this : null);
+ imWindows.add(jf);
+ return jf;
+ }
+
+ public Window createInputMethodWindow(String title,
+ boolean attachToInputContext) {
+ Window w = new IMWindow(title, attachToInputContext ? this : null);
+ imWindows.add(w);
+ return w;
+ }
+ */
+
+ @SuppressWarnings("deprecation")
+ public void dispatchInputMethodEvent(int id,
+ AttributedCharacterIterator text,
+ int committedCharacterCount,
+ TextHitInfo caret,
+ TextHitInfo visiblePosition) {
+ if (client == null) {
+ return;
+ }
+ //???AWT
+ /*
+ InputMethodEvent ime = new InputMethodEvent(client, id, text,
+ committedCharacterCount,
+ caret, visiblePosition);
+
+
+ if ((client.getInputMethodRequests() != null) &&
+ !IMManager.belowTheSpot()) {
+
+ client.dispatchEvent(ime);
+ } else {
+
+ // show/hide composition window if necessary
+ if (committedCharacterCount < text.getEndIndex()) {
+ IMManager.showCompositionWindow(getCompositionWindow());
+ } else {
+ getCompositionWindow().hide();
+ }
+ composeWindow.getActiveClient().dispatchEvent(ime);
+ }
+ */
+
+ }
+
+ public void enableClientWindowNotification(InputMethod inputMethod,
+ boolean enable) {
+ if (enable) {
+ notifyIM.add(inputMethod);
+ //???AWT
+ /*
+ if (client != null) {
+ notifyClientWindowChange(IMManager.getWindow(client).getBounds());
+ } else {
+ pendingClientNotify = true;
+ }
+ */
+ } else {
+ notifyIM.remove(inputMethod);
+ }
+
+ }
+
+ public AttributedCharacterIterator cancelLatestCommittedText(
+ Attribute[] attributes) {
+ return getIMRequests().cancelLatestCommittedText(attributes);
+ }
+
+ public AttributedCharacterIterator getCommittedText(int beginIndex,
+ int endIndex,
+ Attribute[] attributes) {
+ return getIMRequests().getCommittedText(beginIndex, endIndex,
+ attributes);
+ }
+
+ public int getCommittedTextLength() {
+ return getIMRequests().getCommittedTextLength();
+ }
+
+ public int getInsertPositionOffset() {
+ return getIMRequests().getInsertPositionOffset();
+ }
+
+ public TextHitInfo getLocationOffset(int x, int y) {
+ InputMethodRequests imr = getStyleIMRequests();
+ if (imr != null) {
+ return imr.getLocationOffset(x, y);
+ }
+ return null;
+ }
+
+ public AttributedCharacterIterator getSelectedText(Attribute[] attributes) {
+ return getIMRequests().getSelectedText(attributes);
+ }
+
+ public Rectangle getTextLocation(TextHitInfo offset) {
+ return getStyleIMRequests().getTextLocation(offset);
+ }
+
+ /**
+ * To be called by AWT when client Window's bounds/visibility/state
+ * change
+ */
+ public void notifyClientWindowChange(Rectangle bounds) {
+ if (notifyIM.contains(inputMethod)) {
+ inputMethod.notifyClientWindowChange(bounds);
+ }
+ pendingClientNotify = false;
+ }
+
+ public final InputMethod getInputMethod() {
+ return inputMethod;
+ }
+
+ public final Component getClient() {
+ return client;
+ }
+
+ public final NativeIM getNativeIM() {
+ return nativeIM;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/internal/nls/Messages.java b/awt/org/apache/harmony/awt/internal/nls/Messages.java
new file mode 100644
index 0000000..96762c9
--- /dev/null
+++ b/awt/org/apache/harmony/awt/internal/nls/Messages.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.awt.internal.nls;
+
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+// BEGIN android-deleted
+/*
+ * For Android, this module is a separate library and not part of the
+ * boot classpath, so its resources won't be found on the boot classpath
+ * as is assumed by MsgHelp.getString(). We instead use a local MsgHelp
+ * which bottoms out in a call to the useful part of its lower-level
+ * namesake.
+ */
+//import org.apache.harmony.kernel.vm.VM;
+//import org.apache.harmony.luni.util.MsgHelp;
+// END android-deleted
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ * org.apache.harmony.awt.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ // BEGIN android-deleted
+ //private static final String sResource =
+ // "org.apache.harmony.awt.internal.nls.messages";
+ // END android-deleted
+
+ /**
+ * Retrieves a message which has no arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg) {
+ return MsgHelp.getString(msg);
+ }
+
+ /**
+ * Retrieves a message which takes 1 argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * Object the object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg) {
+ return getString(msg, new Object[] { arg });
+ }
+
+ /**
+ * Retrieves a message which takes 1 integer argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * int the integer to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, int arg) {
+ return getString(msg, new Object[] { Integer.toString(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 1 character argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * char the character to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, char arg) {
+ return getString(msg, new Object[] { String.valueOf(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 2 arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg1
+ * Object an object to insert in the formatted output.
+ * @param arg2
+ * Object another object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg1, Object arg2) {
+ return getString(msg, new Object[] { arg1, arg2 });
+ }
+
+ /**
+ * Retrieves a message which takes several arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param args
+ * Object[] the objects to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object[] args) {
+ return MsgHelp.getString(msg, args);
+ }
+}
diff --git a/awt/org/apache/harmony/awt/internal/nls/MsgHelp.java b/awt/org/apache/harmony/awt/internal/nls/MsgHelp.java
new file mode 100644
index 0000000..b57fe11
--- /dev/null
+++ b/awt/org/apache/harmony/awt/internal/nls/MsgHelp.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This implementation is based on the class of the same name in
+ * org.apache.harmony.luni.util.
+ */
+
+package org.apache.harmony.awt.internal.nls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.logging.Logger;
+import java.util.Locale;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+import java.util.MissingResourceException;
+
+/**
+ * This class contains helper methods for loading resource bundles and
+ * formatting external message strings.
+ */
+public final class MsgHelp {
+ /** name of the resource for this class */
+ private static final String RESOURCE_NAME =
+ "/org/apache/harmony/awt/internal/nls/messages.properties";
+
+ /** the resource bundle for this class */
+ private static final ResourceBundle THE_BUNDLE;
+
+ static {
+ ResourceBundle rb = null;
+
+ try {
+ InputStream in = MsgHelp.class.getResourceAsStream(
+ RESOURCE_NAME);
+ rb = new PropertyResourceBundle(in);
+ } catch (IOException ex) {
+ Logger.global.warning("Couldn't read resource bundle: " +
+ ex);
+ } catch (RuntimeException ex) {
+ // Shouldn't happen, but deal at least somewhat gracefully.
+ Logger.global.warning("Couldn't find resource bundle: " +
+ ex);
+ }
+
+ THE_BUNDLE = rb;
+ }
+
+ public static String getString(String msg) {
+ if (THE_BUNDLE == null) {
+ return msg;
+ }
+ try {
+ return THE_BUNDLE.getString(msg);
+ } catch (MissingResourceException e) {
+ return "Missing message: " + msg;
+ }
+ }
+
+ static public String getString(String msg, Object[] args) {
+ String format = msg;
+ if (THE_BUNDLE != null) {
+ try {
+ format = THE_BUNDLE.getString(msg);
+ } catch (MissingResourceException e) {
+ }
+ }
+
+ return org.apache.harmony.luni.util.MsgHelp.format(format, args);
+ }
+}
diff --git a/awt/org/apache/harmony/awt/state/MenuItemState.java b/awt/org/apache/harmony/awt/state/MenuItemState.java
new file mode 100644
index 0000000..b13e50b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/state/MenuItemState.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.state;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+
+/**
+ * State of menu item
+ */
+
+public interface MenuItemState {
+
+ String getText();
+ Rectangle getTextBounds();
+ void setTextBounds(int x, int y, int w, int h);
+
+ String getShortcut();
+ Rectangle getShortcutBounds();
+ void setShortcutBounds(int x, int y, int w, int h);
+
+ Rectangle getItemBounds();
+ void setItemBounds(int x, int y, int w, int h);
+
+ boolean isMenu();
+ boolean isChecked();
+ boolean isEnabled();
+
+ boolean isCheckBox();
+ boolean isSeparator();
+
+ Dimension getMenuSize();
+}
diff --git a/awt/org/apache/harmony/awt/state/MenuState.java b/awt/org/apache/harmony/awt/state/MenuState.java
new file mode 100644
index 0000000..564a49a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/state/MenuState.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.state;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Point;
+
+/**
+ * State of pop-up or drop-down menu
+ */
+
+public interface MenuState {
+ int getWidth();
+ int getHeight();
+ Point getLocation();
+
+ void setSize(int w, int h);
+
+ Font getFont();
+ boolean isFontSet();
+ FontMetrics getFontMetrics(Font f);
+
+ int getItemCount();
+ int getSelectedItemIndex();
+
+ MenuItemState getItem(int index);
+}
diff --git a/awt/org/apache/harmony/awt/state/State.java b/awt/org/apache/harmony/awt/state/State.java
new file mode 100644
index 0000000..4b8706d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/state/State.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.state;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Rectangle;
+
+/**
+ * State of the component
+ */
+public interface State {
+
+ boolean isEnabled();
+ boolean isVisible();
+ boolean isFocused();
+
+ Font getFont();
+ boolean isFontSet();
+ FontMetrics getFontMetrics();
+
+ Color getBackground();
+ boolean isBackgroundSet();
+
+ Color getTextColor();
+ boolean isTextColorSet();
+
+ Rectangle getBounds();
+ Dimension getSize();
+
+ Dimension getDefaultMinimumSize();
+ void setDefaultMinimumSize(Dimension size);
+
+ long getWindowId();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/CreationParams.java b/awt/org/apache/harmony/awt/wtk/CreationParams.java
new file mode 100644
index 0000000..63c581d
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/CreationParams.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+/**
+ * This class describes cross-platform NativeWindow creation params
+ * See also WindowFactory.createWindow
+ */
+public class CreationParams {
+ /**
+ * Initial state is maximized verticaly
+ */
+ public final long MAXIMIZED_VERT = 1;
+ /**
+ * Initial state is maximized horizontaly
+ */
+ public final long MAXIMIZED_HORIZ = 2;
+ /**
+ * Initial state is maximized both
+ * horizontaly and verticaly
+ */
+ public final long MAXIMIZED = 3;
+
+ /**
+ * The top-level window that has all possible decorations,
+ * has no owner and is displayed in taskbar
+ */
+ public final static int DECOR_TYPE_FRAME = 1;
+ /**
+ * The dialog window
+ */
+ public final static int DECOR_TYPE_DIALOG = 2;
+ /**
+ * The transient undecorated pop-up window
+ */
+ public final static int DECOR_TYPE_POPUP = 3;
+ /**
+ * The undecoraded pop-up window
+ */
+ public final static int DECOR_TYPE_UNDECOR = 4;
+ /**
+ * Non-MDI child window
+ */
+ public final static int DECOR_TYPE_NONE = 0;
+
+ /**
+ * Initial x.
+ */
+ public int x = 0;
+ /**
+ * Initial y.
+ */
+ public int y = 0;
+ /**
+ * Initial width.
+ */
+ public int w = 1;
+ /**
+ * Initial height.
+ */
+ public int h = 1;
+ /**
+ * The decoration type of the top-level window. The possible values are:
+ * DECOR_TYPE_FRAME, DECOR_TYPE_DIALOG, DECOR_TYPE_POPUP and DECOR_TYPE_UNDECOR
+ */
+ public int decorType = DECOR_TYPE_NONE;
+ /**
+ * Window is child of parent, otherwise it's
+ * toplevel(child of desktop) window owned by parent.
+ */
+ public boolean child = false;
+ /**
+ * Window is resizable
+ */
+ public boolean resizable = true;
+ /**
+ * The window has no decorations
+ */
+ public boolean undecorated = false;
+ /**
+ * Initial visibility state.
+ */
+ public boolean visible = false;
+ /**
+ * Window is ALWAYS topmost in Z order.
+ */
+ public boolean topmost = false;
+ /**
+ * Window is disabled.
+ */
+ public boolean disabled = false;
+ /**
+ * Window initially iconified.
+ */
+ public boolean iconified = false;
+ /**
+ * Bitwise OR of MAXIMIZED_* constants.
+ * Means if window is initially maximized.
+ */
+ public int maximizedState = 0;
+ /**
+ * Tells that window position should be determined by native windowing system
+ */
+ public boolean locationByPlatform = false;
+ /**
+ * Id of parent or owner window, see child field
+ * For non-child window without owner equals 0.
+ */
+ public long parentId = 0;
+ /**
+ * Name wich is displayed on titlebar, taskbar and visible
+ * for system requests.
+ */
+ public String name = null;
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/awt/wtk/CursorFactory.java b/awt/org/apache/harmony/awt/wtk/CursorFactory.java
new file mode 100644
index 0000000..35e7d33
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/CursorFactory.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Dimension;
+import java.awt.Image;
+
+/**
+ * Provides factory for NativeCursor
+ */
+public abstract class CursorFactory {
+ protected NativeCursor[] systemCursors = {
+ null, null, null, null,
+ null, null, null, null,
+ null, null, null, null,
+ null, null,
+ };
+ /**
+ * Creates and returns NativeCursor for predefined
+ * Java Cursor
+ *
+ * @param type - type of predefined Java Cursor
+ * @return created cursor
+ */
+ public abstract NativeCursor createCursor(int type);
+
+ /**
+ * Gets a cached instance of system(predefined) native cursor
+ * or creates a new one. This is a platform-independent method.
+ *
+ * @param type - type of predefined Java Cursor
+ * @return created cursor
+ */
+ public NativeCursor getCursor(int type) {
+ if (type >= 0 && type < systemCursors.length) {
+ NativeCursor cursor = systemCursors[type];
+ if (cursor == null) {
+ cursor = createCursor(type);
+ systemCursors[type] = cursor;
+ }
+ return cursor;
+ }
+ return null;
+ }
+ /**
+ * Creates and returns custom NativeCursor from image
+ *
+ * @param img - image(source) to create cursor from
+ * @param xHotSpot - x coordinate of the hotspot relative to the source's origin
+ * @param yHotSpot - y coordinate of the hotspot relative to the source's origin
+ * @return created cursor
+ */
+ public abstract NativeCursor createCustomCursor(Image img, int xHotSpot, int yHotSpot);
+
+ /**
+ * Query native system for the best cursor size closest to specified dimensions
+ * @param prefWidth - preferred width
+ * @param prefHeight - preferred height
+ * @return closest supported dimensions to ones specified
+ */
+ public abstract Dimension getBestCursorSize(int prefWidth, int prefHeight);
+
+ /**
+ * @return maximum number of colors supported by custom cursors
+ */
+ public abstract int getMaximumCursorColors();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/GraphicsFactory.java b/awt/org/apache/harmony/awt/wtk/GraphicsFactory.java
new file mode 100644
index 0000000..0d7c84f
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/GraphicsFactory.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov, Alexey A. Petrenko, Oleg V. Khaschansky
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.peer.FontPeer;
+import org.apache.harmony.awt.gl.MultiRectArea;
+import org.apache.harmony.awt.gl.font.FontManager;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+
+/**
+ * GraphicsFactory interface defines methods for Graphics2D
+ * and font stuff instances factories.
+ */
+public interface GraphicsFactory {
+ static final FontMetrics cacheFM[] = new FontMetrics[10];
+
+ /**
+ * This method creates Graphics2D instance for specified native window.
+ *
+ * @param win Native window to draw
+ * @param translateX Translation along X axis
+ * @param translateY Translation along Y axis
+ * @param clip Clipping area for a new Graphics2D instance
+ * @return New Graphics2D instance for specified native window
+ * @deprecated
+ */
+ @Deprecated
+ Graphics2D getGraphics2D(NativeWindow win, int translateX, int translateY, MultiRectArea clip);
+
+ /**
+ * This method creates Graphics2D instance for specified native window.
+ *
+ * @param win Native window to draw
+ * @param translateX Translation along X axis
+ * @param translateY Translation along Y axis
+ * @param width Width of drawing area
+ * @param height Height of drawing area
+ * @return New Graphics2D instance for specified native window
+ */
+ Graphics2D getGraphics2D(NativeWindow win, int translateX, int translateY, int width, int height);
+ // ???AWT: not standard harmony
+ Graphics2D getGraphics2D(Canvas c, Paint p);
+
+ /**
+ * Creates instance of GraphicsEnvironment for specified WindowFactory
+ *
+ * @param wf WindowFactory
+ * @return New instance of GraphicsEnvironment
+ */
+ GraphicsEnvironment createGraphicsEnvironment(WindowFactory wf);
+
+ // Font methods
+ FontMetrics getFontMetrics(Font font);
+ FontManager getFontManager();
+ FontPeer getFontPeer(Font font);
+ Font embedFont(String fontFilePath);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/KeyInfo.java b/awt/org/apache/harmony/awt/wtk/KeyInfo.java
new file mode 100644
index 0000000..1f8a29a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/KeyInfo.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.event.KeyEvent;
+
+/**
+ * Keystroke information
+ */
+
+public final class KeyInfo {
+
+ public int vKey;
+ public int keyLocation;
+ public final StringBuffer keyChars;
+
+ public static final int DEFAULT_VKEY = KeyEvent.VK_UNDEFINED;
+ public static final int DEFAULT_LOCATION = KeyEvent.KEY_LOCATION_STANDARD;
+
+ public KeyInfo() {
+ vKey = DEFAULT_VKEY;
+ keyLocation = DEFAULT_LOCATION;
+ keyChars = new StringBuffer();
+ }
+
+ public void setKeyChars(char ch) {
+ keyChars.setLength(0);
+ keyChars.append(ch);
+ }
+
+ public void setKeyChars(StringBuffer sb) {
+ keyChars.setLength(0);
+ keyChars.append(sb);
+ }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeCursor.java b/awt/org/apache/harmony/awt/wtk/NativeCursor.java
new file mode 100644
index 0000000..2c6eb1e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeCursor.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+/**
+ * The interface provides access to platform dependent functionality
+ * for the class java.awt.Cursor.
+ */
+public interface NativeCursor {
+ /**
+ * Sets the current cursor shape
+ * to this cursor when a pointer is inside
+ * @param winID - window(currently used only on X11)
+ */
+ void setCursor(long winID);
+ /**
+ * Destroys the native resource associated with
+ * this cursor
+ */
+ void destroyCursor();
+
+ /**
+ * @return Native handle associated with this cursor
+ */
+ long getId();
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeEvent.java b/awt/org/apache/harmony/awt/wtk/NativeEvent.java
new file mode 100644
index 0000000..1471c1a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeEvent.java
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.Point;
+import java.awt.event.KeyEvent;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+
+/**
+ * The interface describing cross-platform translation of system
+ * messages.
+ *
+ * <p/>Some messages can appear only on specific platform,
+ * but they still can have cross-platform interpretation if the
+ * application should be aware of them and can react using
+ * cross-platform API.
+ *
+ */
+public abstract class NativeEvent {
+
+ /**
+ * Message has no common cross-platform
+ * interpretation and should be skipped.
+ */
+ public static final int ID_PLATFORM = 0;
+
+ /**
+ * Window bounds have changed.
+ */
+ public static final int ID_BOUNDS_CHANGED = -1;
+
+ /**
+ * Window decoration size has changed.
+ */
+ public static final int ID_INSETS_CHANGED = -2;
+
+ /**
+ * Window was just created (WM_CREATE on Windows)
+ */
+ public static final int ID_CREATED = -3;
+
+ /**
+ * Mouse grab was canceled by the native system
+ */
+ public static final int ID_MOUSE_GRAB_CANCELED = -4;
+
+ /**
+ * System color scheme or visual theme was changed
+ */
+ public static final int ID_THEME_CHANGED = -5;
+
+ protected long windowId;
+ protected int eventId;
+ protected long otherWindowId;
+
+ protected Point screenPos;
+ protected Point localPos;
+ protected Rectangle windowRect;
+
+ protected int modifiers;
+ protected int mouseButton;
+ protected int wheelRotation;
+
+ protected KeyInfo keyInfo = new KeyInfo();
+
+ protected int windowState = -1;
+ protected long time;
+
+ /**
+ * Returns the system window id of the event recipient.
+ * @return HWND on Windows, xwindnow on X
+ */
+ public long getWindowId() {
+ return windowId;
+ }
+
+ /**
+ * Returns cross-platform event id
+ * should be one of ID_* constants or
+ * id constants from java.awt.AWTEvent subclasess
+ * @return cross-platform event id
+ */
+ public int getEventId() {
+ return eventId;
+ }
+
+ /**
+ * Returns the position of cursor when event occured relative to
+ * top-left corner of recipient window
+ * @return position of cursor in local coordinates
+ */
+ public Point getLocalPos() {
+ return localPos;
+ }
+
+ /**
+ * Returns the position of cursor when event occured
+ * in screen coordinates.
+ * @return position of cursor in screen coordinates
+ */
+ public Point getScreenPos() {
+ return screenPos;
+ }
+
+ /**
+ * The recipient window bounds when the event occured
+ * @return window bounds
+ */
+ public Rectangle getWindowRect() {
+ return windowRect;
+ }
+
+ /**
+ * Returns the state of keyboard and mouse buttons when the event
+ * occured if event from mouse or keyboard, for other events can
+ * return junk values. The value is bitwise OR of
+ * java.awt.event.InputEvent *_DOWN constants.
+ *
+ * Method is aware of system mouse button swap for left-hand
+ * mouse and return swapped values.
+ * @return bitwise OR of java.awt.event.InputEvent *_DOWN constants
+ */
+ public int getInputModifiers() {
+ return modifiers;
+ }
+
+ /**
+ * Returns the iconified/maximized state of recipient window if
+ * event is state related, for other events can junk values.
+ * The value has the same meaning as Frame.getExtendedState
+ * It's bitwise OR of ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT
+ * @return bitwise OR of ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT
+ */
+ public int getWindowState() {
+ return windowState;
+ }
+
+ /**
+ * The same meaning as java.awt.event.getKeyCode
+ * @return java.awt.event VK_* constant
+ */
+ public int getVKey() {
+ return (keyInfo != null) ? keyInfo.vKey : KeyInfo.DEFAULT_VKEY;
+ }
+
+ /**
+ * The same meaning as java.awt.event.getKeyLocation
+ * @return java.awt.event KEY_LOCATION_* constant
+ */
+ public int getKeyLocation() {
+ return (keyInfo != null) ? keyInfo.keyLocation : KeyInfo.DEFAULT_LOCATION;
+ }
+
+ /**
+ * Return the string of characters associated with the event
+ * Has meaning only for KEY_PRESSED as should be translated to
+ * serie of KEY_TYPED events. For dead keys and input methods
+ * one key press can generate multiple key chars.
+ * @return string of characters
+ */
+ public StringBuffer getKeyChars() {
+ if (keyInfo == null) {
+ return null;
+ }
+ if (keyInfo.vKey == KeyEvent.VK_ENTER) {
+ keyInfo.keyChars.setLength(0);
+ keyInfo.setKeyChars('\n');
+ }
+ return keyInfo.keyChars;
+ }
+
+ public char getLastChar() {
+ if (keyInfo == null || keyInfo.keyChars.length() == 0) {
+ return KeyEvent.CHAR_UNDEFINED;
+ }
+ return keyInfo.keyChars.charAt(keyInfo.keyChars.length()-1);
+ }
+
+ /**
+ * Returns the number of mouse button which changed it's state,
+ * otherwise 0.
+ * Left button is 1, middle button is 2, right button is 3.
+ *
+ * Method is aware of system mouse button swap for left-hand
+ * mouse and return swapped values.
+ * @return mouse button number
+ */
+ public int getMouseButton() {
+ return mouseButton;
+ }
+
+ /**
+ * Returns time when the message was received
+ * @return time in milliseconds
+ */
+ public long getTime() {
+ return time;
+ }
+
+ /**
+ * For the focus event contains the oposite window.
+ * This means it lost focus if recipient gains it,
+ * or will gain focus if recipient looses it.
+ * @return HWND on Windows, xwindnow on X
+ */
+ public long getOtherWindowId() {
+ return otherWindowId;
+ }
+
+ /**
+ * Returns the "dirty" area of the window as set of non-intersecting
+ * rectangles. This area is to be painted.
+ * @return non-empty array of null if empty
+ */
+ public abstract MultiRectArea getClipRects();
+
+ /**
+ * Returns the "dirty" area of the window as one rectangle.
+ * This area is to be painted.
+ * @return non-null Rectangle
+ */
+ public abstract Rectangle getClipBounds();
+
+ /**
+ * Returns the window insets. Insets is area which belongs to
+ * window somehow but is outside of it's client area,
+ * it usually contains system provided border and titlebar.
+ * @return non-null java.awt.Insets
+ */
+ public abstract Insets getInsets();
+
+ /**
+ * Returns true if event is popup menu trigger.
+ * @return boolean flag
+ */
+ public abstract boolean getTrigger();
+
+ /**
+ * Returns the number of "clicks" the mouse wheel was rotated.
+ * @return negative values if the mouse wheel was rotated up/away from the user,
+ * and positive values if the mouse wheel was rotated down/ towards the user
+ */
+ public int getWheelRotation() {
+ return wheelRotation;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeEventQueue.java b/awt/org/apache/harmony/awt/wtk/NativeEventQueue.java
new file mode 100644
index 0000000..0738cd1
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeEventQueue.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.util.LinkedList;
+
+
+/**
+ * Describes the cross-platform native event queue interface
+ *
+ * <p/> The implementation constructor should remember thread it was
+ * created. All other methods would be called obly from this thread,
+ * except awake().
+ */
+public abstract class NativeEventQueue {
+
+ private ShutdownWatchdog shutdownWatchdog;
+ private class EventMonitor {}
+ private final Object eventMonitor = new EventMonitor();
+ private final LinkedList<NativeEvent> eventQueue = new LinkedList<NativeEvent>();
+
+ public static abstract class Task {
+ public volatile Object returnValue;
+
+ public abstract void perform();
+ }
+
+ /**
+ * Blocks current thread until native event queue is not empty
+ * or awaken from other thread by awake().
+ *
+ * <p/>Should be called only on tread which
+ * will process native events.
+ *
+ * @return if event loop should be stopped
+ */
+ public abstract boolean waitEvent();
+
+ /**
+ * Determines whether or not the native event queue is empty.
+ * An queue is empty if it contains no messages waiting.
+ *
+ * @return true if the queue is empty; false otherwise
+ */
+ public boolean isEmpty() {
+ synchronized(eventQueue) {
+ return eventQueue.isEmpty();
+ }
+ }
+
+ public NativeEvent getNextEvent() {
+ synchronized (eventQueue) {
+ if (eventQueue.isEmpty()) {
+ shutdownWatchdog.setNativeQueueEmpty(true);
+ return null;
+ }
+ return eventQueue.remove(0);
+ }
+ }
+
+ protected void addEvent(NativeEvent event) {
+ synchronized (eventQueue) {
+ eventQueue.add(event);
+ shutdownWatchdog.setNativeQueueEmpty(false);
+ }
+ synchronized (eventMonitor) {
+ eventMonitor.notify();
+ }
+ }
+
+ public final Object getEventMonitor() {
+ return eventMonitor;
+ }
+
+ public abstract void awake();
+
+ /**
+ * Gets AWT system window ID.
+ *
+ * @return AWT system window ID
+ */
+ public abstract long getJavaWindow();
+
+ /**
+ * Add NativeEvent to the queue
+ */
+ public abstract void dispatchEvent();
+
+ public abstract void performTask(Task task);
+
+ public abstract void performLater(Task task);
+
+ public final void setShutdownWatchdog(ShutdownWatchdog watchdog) {
+ synchronized (eventQueue) {
+ shutdownWatchdog = watchdog;
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeEventThread.java b/awt/org/apache/harmony/awt/wtk/NativeEventThread.java
new file mode 100644
index 0000000..d50add4
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeEventThread.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+
+/**
+ * NativeEventThread
+ */
+public class NativeEventThread extends Thread {
+
+ public interface Init {
+ WTK init();
+ }
+
+ NativeEventQueue nativeQueue;
+ Init init;
+
+ private WTK wtk;
+
+ public NativeEventThread() {
+ super("AWT-NativeEventThread"); //$NON-NLS-1$
+ setDaemon(true);
+ }
+
+ @Override
+ public void run() {
+ synchronized (this) {
+ try {
+ wtk = init.init();
+ nativeQueue = wtk.getNativeEventQueue();
+ } finally {
+ notifyAll();
+ }
+ }
+
+ runModalLoop();
+ }
+
+ void runModalLoop() {
+ while (nativeQueue.waitEvent()) {
+ nativeQueue.dispatchEvent();
+ }
+ }
+
+ public void start(Init init) {
+ synchronized (this) {
+ this.init = init;
+ super.start();
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public WTK getWTK() {
+ return wtk;
+ }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeIM.java b/awt/org/apache/harmony/awt/wtk/NativeIM.java
new file mode 100644
index 0000000..1626f4a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeIM.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.AWTEvent;
+import java.awt.AWTException;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.im.spi.InputMethod;
+import java.awt.im.spi.InputMethodContext;
+import java.awt.im.spi.InputMethodDescriptor;
+import java.lang.Character.Subset;
+import java.util.Locale;
+
+/**
+ * A cross-platform interface for native input
+ * method sub-system functionality.
+ */
+public abstract class NativeIM implements InputMethod, InputMethodDescriptor {
+ protected InputMethodContext imc;
+
+ public void activate() {
+
+ }
+
+ public void deactivate(boolean isTemporary) {
+
+ }
+
+ public void dispatchEvent(AWTEvent event) {
+
+ }
+
+ public void dispose() {
+
+ }
+
+ public void endComposition() {
+
+ }
+
+ public Object getControlObject() {
+ return null;
+ }
+
+ public Locale getLocale() {
+ return null;
+ }
+
+ public void hideWindows() {
+
+ }
+
+ public boolean isCompositionEnabled() {
+ return false;
+ }
+
+ public void notifyClientWindowChange(Rectangle bounds) {
+
+ }
+
+ public void reconvert() {
+
+ }
+
+ public void removeNotify() {
+
+ }
+
+ public void setCharacterSubsets(Subset[] subsets) {
+
+ }
+
+ public void setCompositionEnabled(boolean enable) {
+
+ }
+
+ public void setInputMethodContext(InputMethodContext context) {
+ imc = context;
+ }
+
+ public boolean setLocale(Locale locale) {
+ return false;
+ }
+
+ public Locale[] getAvailableLocales() throws AWTException {
+ return new Locale[]{Locale.getDefault(), Locale.ENGLISH};
+ //return new Locale[]{Locale.getDefault(), Locale.US};
+ }
+
+ public InputMethod createInputMethod() throws Exception {
+ return this;
+ }
+
+ public String getInputMethodDisplayName(Locale inputLocale,
+ Locale displayLanguage) {
+ return "System input methods"; //$NON-NLS-1$
+ }
+
+ public Image getInputMethodIcon(Locale inputLocale) {
+ return null;
+ }
+
+ public boolean hasDynamicLocaleList() {
+ return false;
+ }
+
+ public abstract void disableIME();
+
+// public abstract void disableIME(long id);
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java b/awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java
new file mode 100644
index 0000000..0696975
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeMouseInfo.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Point;
+
+/**
+ * The interface provides access to platform dependent functionality
+ * for classes java.awt.PointerInfo & java.awt.MouseInfo.
+ */
+public interface NativeMouseInfo {
+
+ /**
+ * Returns the Point that represents
+ * the coordinates of the pointer on the screen.
+ */
+ Point getLocation();
+
+ /**
+ * Returns the number of buttons on the mouse.
+ * If no mouse is installed returns -1.
+ */
+ int getNumberOfButtons();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeRobot.java b/awt/org/apache/harmony/awt/wtk/NativeRobot.java
new file mode 100644
index 0000000..0b354d0
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeRobot.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Dmitry A. Durnev
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+/**
+ * A cross-platform interface for java.awt.Robot implementation
+ */
+public interface NativeRobot {
+
+ /**
+ * @see java.awt.Robot#createScreenCapture(Rectangle)
+ * @param screenRect rectangle to capture in screen coordinates
+ * @return the captured image or null if
+ * capture failed.
+ */
+ BufferedImage createScreenCapture(Rectangle screenRect);
+
+ /**
+ * @see java.awt.Robot#getPixelColor(int, int)
+ */
+ Color getPixel(int x, int y);
+
+ /**
+ * Generate a native system keyboard input event.
+ * @param keycode A Java virtual key code
+ * @param press A key is pressed if true, released otherwise
+ * @see java.awt.Robot#keyPress(int)
+ * @throws IllegalArgumentException if keycode is invalid in the native system
+ */
+ void keyEvent(int keycode, boolean press);
+
+ /**
+ * Generate a native system mouse button(s) press or release event.
+ * @param buttons A mask of Java mouse button flags
+ * @param press buttons are pressed if true, released otherwise
+ * @see java.awt.Robot#mousePress(int)
+ */
+ void mouseButton(int buttons, boolean press);
+
+ /**
+ * Generate a native system mouse motion event.
+ *
+ * @see java.awt.Robot#mouseMove(int, int)
+ */
+ void mouseMove(int x, int y);
+
+ /**
+ * Generate a native system mouse wheel event.
+ *
+ * @see java.awt.Robot#mouseWheel(int)
+ */
+ void mouseWheel(int wheelAmt);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/NativeWindow.java b/awt/org/apache/harmony/awt/wtk/NativeWindow.java
new file mode 100644
index 0000000..73fd6c0
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/NativeWindow.java
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+
+import org.apache.harmony.awt.gl.MultiRectArea;
+
+
+/**
+ * Provides cross-platform way to manipulate native window.
+ *
+ * Results of methods are reported through native messages.
+ */
+public interface NativeWindow {
+ /**
+ * Returns system id of the associated window
+ * @return HWND on Windows, xwindow on X
+ */
+ long getId();
+
+ /**
+ * Shows/hides window
+ * @param v - new visibility
+ */
+ void setVisible(boolean v);
+
+ /**
+ * Means only size should be changed
+ */
+ static final int BOUNDS_NOMOVE = 1;
+
+ /**
+ * Means only position should be changed
+ */
+ static final int BOUNDS_NOSIZE = 2;
+
+ /**
+ * Tries to set desired window bounds. It's not gurantied the
+ * property will have the desired value. The value change
+ * should be reported by system event (as for other properties).
+ *
+ * <p/> If child, position is relative to parent window.
+ * @param x - desired x
+ * @param y - desired y
+ * @param w - desired width
+ * @param h - desired height
+ * @param boundsMask - bitwise OR of BOUNDS_* constants.
+ * Governs the new bounds interpretation.
+ */
+ void setBounds(int x, int y, int w, int h, int boundsMask);
+
+ /**
+ * Returns last notified window bounds. This means the last bounds
+ * reported by system event.
+ *
+ * <p/> If child, position is relative to parent window.
+ * @return last notified window bounds
+ */
+ Rectangle getBounds();
+
+ /**
+ * Returns last notified insets. This means the last insets
+ * reported by system event. Insets are margins around client area
+ * ocupied by system provided decor, ususally border and titlebar.
+ * @return last notified insets
+ */
+ Insets getInsets();
+
+ /**
+ * Enables/disables processing of input (key, mouse) event
+ * by window. If disabled input events are ignored.
+ * @param value - if enabled
+ */
+ void setEnabled(boolean value);
+
+ /**
+ * Sets the "focusable" window state.
+ * @param value - if true makes window focusable
+ */
+ void setFocusable(boolean value);
+
+ /**
+ *
+ * @return current focusable window state
+ */
+ boolean isFocusable();
+
+ /**
+ * Tries to set application input focus to the window or clear
+ * current focus from focused window.
+ *
+ * <p/> For toplevel windows it's not gurantied focus will land in
+ * desired window even if function returns true. Focus traversal should be tracked
+ * by processing system events.
+ *
+ * @param focus - if true sets focus, else clears focus
+ * @return if success
+ */
+ boolean setFocus(boolean focus);
+
+ /**
+ * Destroys the asscoiated window.
+ * Attempts to use it thereafter can result in
+ * unpredictable bechavior.
+ */
+ void dispose();
+
+ /**
+ * Changes window Z-order to place this window under, If w is null
+ * places places this window on the top. Z-order is per parent.
+ * Toplevels a children of desktop in terms of Z-order.
+ * @param w - window to place under.
+ */
+ void placeAfter(NativeWindow w);
+
+ /**
+ * Places window on top of Z-order
+ */
+ void toFront();
+
+ /**
+ * Places window on bottom of Z-order
+ */
+ void toBack();
+
+ /**
+ * Makes the window resizable/not resizable by user
+ * @param value - if resizable
+ */
+ void setResizable(boolean value);
+
+ /**
+ * Sets the window caption
+ * @param title - caption text
+ */
+ void setTitle(String title);
+
+ /**
+ * Activate the mouse event capturing
+ */
+ void grabMouse();
+
+ /**
+ * Deactivate mouse event capturing
+ */
+ void ungrabMouse();
+
+ /**
+ * Set extended state for top-level window.
+ *
+ * @param state - new state, bitmask of ICONIFIED, MAXIMIZED_BOTH, etc.
+ */
+ void setState(int state);
+
+ /**
+ * Set the image to be displayed in the minimized icon for
+ * top-level [decorated] window.
+ * @param image the icon image to be displayed
+ */
+ void setIconImage(Image image);
+
+ /**
+ * Makes window top-most if value is true,
+ * non-topmost(normal) otherwise.
+ */
+ void setAlwaysOnTop(boolean value);
+
+ /**
+ * Set desired [top-level] window bounds when being in maximized state.
+ * Fields set to Integer.MAX_VALUE are ignored[system-supplied values are
+ * used instead]
+ */
+ void setMaximizedBounds(Rectangle bounds);
+
+ /**
+ * Get absolute position on the screen
+ */
+ Point getScreenPos();
+
+ /**
+ * Set a window "packed" flag:
+ * the flag indicates that if insets change
+ * client area shouldn't be resized, but frame
+ * must be resized instead
+ */
+ void setPacked(boolean packed);
+
+ /**
+ * Make window an "input method window" by setting
+ * special window style, e. g. small title bar, no
+ * close, minimize/maximize buttons. For internal
+ * use by input method framework.
+ *
+ */
+ void setIMStyle();
+
+ MultiRectArea getObscuredRegion(Rectangle part);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/ShutdownThread.java b/awt/org/apache/harmony/awt/wtk/ShutdownThread.java
new file mode 100644
index 0000000..701eb46
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/ShutdownThread.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Michael Danilov, Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+public final class ShutdownThread extends Thread {
+
+ public static final class Watchdog {
+ }
+
+ public ShutdownThread() {
+ setName("AWT-Shutdown"); //$NON-NLS-1$
+ setDaemon(false);
+ }
+
+ private boolean shouldStop = false;
+
+ @Override
+ public void run() {
+ synchronized (this) {
+ notifyAll(); // synchronize the startup
+
+ while (true) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+
+ if (shouldStop) {
+ notifyAll(); // synchronize the shutdown
+ return;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void start() {
+ synchronized (this) {
+ super.start();
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ // awt.26=Shutdown thread was interrupted while starting
+ throw new RuntimeException(
+ Messages.getString("awt.26")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ public void shutdown() {
+ synchronized (this) {
+ shouldStop = true;
+ notifyAll();
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ // awt.27=Shutdown thread was interrupted while stopping
+ throw new RuntimeException(
+ Messages.getString("awt.27")); //$NON-NLS-1$
+ }
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java b/awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java
new file mode 100644
index 0000000..6efa519
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/ShutdownWatchdog.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+/**
+ * Shutdown Watchdog
+ */
+public final class ShutdownWatchdog {
+
+ private boolean nativeQueueEmpty = true;
+ private boolean awtQueueEmpty = true;
+ private boolean windowListEmpty = true;
+
+ private boolean forcedShutdown = false;
+
+ private ShutdownThread thread;
+
+ public synchronized void setNativeQueueEmpty(boolean empty) {
+ nativeQueueEmpty = empty;
+ checkShutdown();
+ }
+
+ public synchronized void setAwtQueueEmpty(boolean empty) {
+ awtQueueEmpty = empty;
+ checkShutdown();
+ }
+
+ public synchronized void setWindowListEmpty(boolean empty) {
+ windowListEmpty = empty;
+ checkShutdown();
+ }
+
+ public synchronized void forceShutdown() {
+ forcedShutdown = true;
+ shutdown();
+ }
+
+ public synchronized void start() {
+ keepAlive();
+ }
+
+ private void checkShutdown() {
+ if (canShutdown()) {
+ shutdown();
+ } else {
+ keepAlive();
+ }
+ }
+
+ private boolean canShutdown() {
+ return (nativeQueueEmpty && awtQueueEmpty && windowListEmpty) ||
+ forcedShutdown;
+ }
+
+ private void keepAlive() {
+ if (thread == null) {
+ thread = new ShutdownThread();
+ thread.start();
+ }
+ }
+
+ private void shutdown() {
+ if (thread != null) {
+ thread.shutdown();
+ thread = null;
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/awt/wtk/Synchronizer.java b/awt/org/apache/harmony/awt/wtk/Synchronizer.java
new file mode 100644
index 0000000..3eeaa0b
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/Synchronizer.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.util.Hashtable;
+import java.util.LinkedList;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * Class synchronizer is to protect AWT state integrity in multithreading environment.
+ * It is supposed to have a child class per native platform.
+ * The only instance is created on the first use of one of the core AWT classes.
+ * Registers WTK on the dispatch thread startup.
+ * It is just a special kind of mutex.
+ *
+ */
+
+public class Synchronizer {
+ //TODO: think about java.util.concurrent use for faster blocking/awaking operations
+ //TODO: think about all synchronized methods. Is there need to synchronize everything?
+
+ /**
+ * This field holds the counter of lock operation.
+ * To free synchronizer unlock method must be called $acquestCounter times.
+ * Equals to 0 when synchronizer is free.
+ */
+ protected int acquestCounter;
+
+ /**
+ * This field holds the owner of synchronizer.
+ * Owner of synchronizer is a last thread that successfully locked synchronizer and
+ * still havn't freed it. Equals to null when synchronizer is free.
+ */
+ protected Thread owner;
+
+ /**
+ * This field holds the wait queue.
+ * Wait queue is a queue where thread wait for synchronizer access.
+ * Empty when synchronizer is free.
+ */
+ protected final LinkedList<Thread> waitQueue = new LinkedList<Thread>();
+
+ /**
+ * The event dispatch thread
+ */
+ protected Thread dispatchThread;
+
+ private final Hashtable<Thread, Integer> storedStates = new Hashtable<Thread, Integer>();
+
+ /**
+ * Acquire the lock for this synchronizer. Nested lock is supported.
+ * If the mutex is already locked by another thread, the current thread will be put
+ * into wait queue until the lock becomes available.
+ * All user threads are served in FIFO order. Dispatch thread has higher priority.
+ * Supposed to be used in Toolkit.lockAWT() only.
+ */
+ public void lock() {
+ synchronized (this) {
+ Thread curThread = Thread.currentThread();
+
+ if (acquestCounter == 0) {
+ acquestCounter = 1;
+ owner = curThread;
+ } else {
+ if (owner == curThread) {
+ acquestCounter++;
+ } else {
+ if (curThread == dispatchThread) {
+ waitQueue.addFirst(curThread);
+ } else {
+ waitQueue.addLast(curThread);
+ }
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ if (owner != curThread) {
+ waitQueue.remove(curThread);
+ // awt.1F=Waiting for resource access thread interrupted not from unlock method.
+ throw new RuntimeException(Messages
+ .getString("awt.1F")); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Release the lock for this synchronizer.
+ * If wait queue is not empty the first waiting thread acquires the lock.
+ * Supposed to be used in Toolkit.unlockAWT() only.
+ */
+ public void unlock() {
+ synchronized (this) {
+ if (acquestCounter == 0) {
+ // awt.20=Can't unlock not locked resource.
+ throw new RuntimeException(Messages.getString("awt.20")); //$NON-NLS-1$
+ }
+ if (owner != Thread.currentThread()) {
+ // awt.21=Not owner can't unlock resource.
+ throw new RuntimeException(Messages.getString("awt.21")); //$NON-NLS-1$
+ }
+
+ acquestCounter--;
+ if (acquestCounter == 0) {
+ if (waitQueue.size() > 0) {
+ acquestCounter = 1;
+ owner = waitQueue.removeFirst();
+ owner.interrupt();
+ } else {
+ owner = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Stores state of this synchronizer and frees it.
+ * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with
+ * lockAndRestoreState().
+ * Do not call it directly.
+ */
+ public void storeStateAndFree() {
+ synchronized (this) {
+ Thread curThread = Thread.currentThread();
+
+ if (owner != curThread) {
+ // awt.22=Not owner can't free resource.
+ throw new RuntimeException(Messages.getString("awt.22")); //$NON-NLS-1$
+ }
+ if (storedStates.containsKey(curThread)) {
+ // awt.23=One thread can't store state several times in a row.
+ throw new RuntimeException(Messages.getString("awt.23")); //$NON-NLS-1$
+ }
+
+ storedStates.put(curThread, new Integer(acquestCounter));
+ acquestCounter = 1;
+ unlock();
+ }
+ }
+
+ /**
+ * Locks this synchronizer and restores it's state.
+ * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with
+ * storeStateAndFree().
+ * Do not call it directly.
+ */
+ public void lockAndRestoreState() {
+ synchronized (this) {
+ Thread curThread = Thread.currentThread();
+
+ if (owner == curThread) {
+ // awt.24=Owner can't overwrite resource state. Lock operations may be lost.
+ throw new RuntimeException(
+ Messages.getString("awt.24")); //$NON-NLS-1$
+ }
+ if (!storedStates.containsKey(curThread)) {
+ // awt.25=No state stored for current thread.
+ throw new RuntimeException(Messages.getString("awt.25")); //$NON-NLS-1$
+ }
+
+ lock();
+ acquestCounter = storedStates.get(curThread).intValue();
+ storedStates.remove(curThread);
+ }
+ }
+
+ /**
+ * Sets references to WTK and event dispatch thread.
+ * Called on toolkit startup.
+ *
+ * @param wtk - reference to WTK instance
+ * @param dispatchThread - reference to event dispatch thread
+ */
+ public void setEnvironment(WTK wtk, Thread dispatchThread) {
+ synchronized (this) {
+ this.dispatchThread = dispatchThread;
+ }
+ }
+
+}
diff --git a/awt/org/apache/harmony/awt/wtk/SystemProperties.java b/awt/org/apache/harmony/awt/wtk/SystemProperties.java
new file mode 100644
index 0000000..6b59f0e
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/SystemProperties.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Font;
+import java.awt.font.TextAttribute;
+import java.awt.im.InputMethodHighlight;
+import java.util.Map;
+
+/**
+ * NativeProperties
+ */
+
+public interface SystemProperties {
+
+ /**
+ * Get current value of a system color
+ * @param index - one of java.awt.SystemColor constants
+ * @return ARGB value of requested system color
+ */
+ int getSystemColorARGB(int index);
+
+ /**
+ * Get default font for GUI elements such as menus and buttons
+ * @return the font object
+ */
+ Font getDefaultFont();
+
+ /**
+ * Fill the given Map with system properties
+ */
+ void init(Map<String, ?> desktopProperties);
+
+ /**
+ * Fills the given map with system-dependent visual text
+ * attributes for the abstract description
+ * of the given input method highlight
+ * @see java.awt.Toolkit.mapInputMethodHighlight()
+ */
+ void mapInputMethodHighlight(InputMethodHighlight highlight, Map<TextAttribute, ?> map);
+}
diff --git a/awt/org/apache/harmony/awt/wtk/WTK.java b/awt/org/apache/harmony/awt/wtk/WTK.java
new file mode 100644
index 0000000..4162fbd
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/WTK.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Pavel Dolgov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.GraphicsDevice;
+
+
+public abstract class WTK {
+
+ public abstract GraphicsFactory getGraphicsFactory();
+ public abstract NativeEventQueue getNativeEventQueue();
+ public abstract WindowFactory getWindowFactory();
+
+ /**
+ * Returns platform specific implementation of the interface
+ * org.apache.harmony.awt.wtk.CursorFactory.
+ * @return implementation of CursorFactory
+ */
+ public abstract CursorFactory getCursorFactory();
+
+ /**
+ * Returns platform specific implementation of the interface
+ * org.apache.harmony.awt.wtk.NativeMouseInfo.
+ * @return implementation of NativeMouseInfo
+ */
+ public abstract NativeMouseInfo getNativeMouseInfo();
+
+ public abstract SystemProperties getSystemProperties();
+
+ /**
+ * Returns platform specific implementation of the interface
+ * org.apache.harmony.awt.wtk.NativeRobot.
+ * @return implementation of NativeRobot
+ */
+ public abstract NativeRobot getNativeRobot(GraphicsDevice screen);
+
+ /**
+ * Returns platform specific implementation of the abstract
+ * class org.apache.harmony.awt.wtk.NativeIM.
+ * @return implementation of NativeIM
+ */
+ public abstract NativeIM getNativeIM();
+}
diff --git a/awt/org/apache/harmony/awt/wtk/WindowFactory.java b/awt/org/apache/harmony/awt/wtk/WindowFactory.java
new file mode 100644
index 0000000..23604da
--- /dev/null
+++ b/awt/org/apache/harmony/awt/wtk/WindowFactory.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Danilov
+ * @version $Revision$
+ */
+package org.apache.harmony.awt.wtk;
+
+import java.awt.Dimension;
+import java.awt.Point;
+
+/**
+ * Provides factory for NativeWindow
+ */
+public interface WindowFactory {
+ /**
+ * Creates and returns NativeWindow with desired
+ * creation params
+ *
+ * @param p - initial window properties
+ * @return created window
+ */
+ NativeWindow createWindow(CreationParams p);
+ /**
+ * Create NativeWindow instance connected to existing native resource
+ * @param nativeWindowId - id of existing window
+ * @return created NativeWindow instance
+ */
+ NativeWindow attachWindow(long nativeWindowId);
+ /**
+ * Returns NativeWindow instance if created by this instance of
+ * WindowFactory, otherwise null
+ *
+ * @param id - HWND on Windows xwindow on X
+ * @return NativeWindow or null if unknown
+ */
+ NativeWindow getWindowById(long id);
+ /**
+ * Returns NativeWindow instance of the top-level window
+ * that contains a specified point and was
+ * created by this instance of WindowFactory
+ * @param p - Point to check
+ * @return NativeWindow or null if the point is
+ * not within a window created by this WindowFactory
+ */
+ NativeWindow getWindowFromPoint(Point p);
+
+ /**
+ * Returns whether native system supports the state for windows.
+ * This method tells whether the UI concept of, say, maximization or iconification is supported.
+ * It will always return false for "compound" states like Frame.ICONIFIED|Frame.MAXIMIZED_VERT.
+ * In other words, the rule of thumb is that only queries with a single frame state
+ * constant as an argument are meaningful.
+ *
+ * @param state - one of named frame state constants.
+ * @return true is this frame state is supported by this Toolkit implementation, false otherwise.
+ */
+ boolean isWindowStateSupported(int state);
+
+ /**
+ * @see org.apache.harmony.awt.ComponentInternals
+ */
+ void setCaretPosition(int x, int y);
+
+ /**
+ * Request size of arbitrary native window
+ * @param id - window ID
+ * @return window size
+ */
+ Dimension getWindowSizeById(long id);
+} \ No newline at end of file
diff --git a/awt/org/apache/harmony/beans/internal/nls/Messages.java b/awt/org/apache/harmony/beans/internal/nls/Messages.java
new file mode 100644
index 0000000..727c757
--- /dev/null
+++ b/awt/org/apache/harmony/beans/internal/nls/Messages.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.beans.internal.nls;
+
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import org.apache.harmony.kernel.vm.VM;
+import org.apache.harmony.luni.util.MsgHelp;
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ * org.apache.harmony.beans.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ private static final String sResource =
+ "org.apache.harmony.beans.internal.nls.messages"; //$NON-NLS-1$
+
+ /**
+ * Retrieves a message which has no arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg) {
+ return MsgHelp.getString(sResource, msg);
+ }
+
+ /**
+ * Retrieves a message which takes 1 argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * Object the object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg) {
+ return getString(msg, new Object[] { arg });
+ }
+
+ /**
+ * Retrieves a message which takes 1 integer argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * int the integer to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, int arg) {
+ return getString(msg, new Object[] { Integer.toString(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 1 character argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * char the character to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, char arg) {
+ return getString(msg, new Object[] { String.valueOf(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 2 arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg1
+ * Object an object to insert in the formatted output.
+ * @param arg2
+ * Object another object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg1, Object arg2) {
+ return getString(msg, new Object[] { arg1, arg2 });
+ }
+
+ /**
+ * Retrieves a message which takes several arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param args
+ * Object[] the objects to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object[] args) {
+ return MsgHelp.getString(sResource, msg, args);
+ }
+}
diff --git a/awt/org/apache/harmony/beans/internal/nls/messages.properties b/awt/org/apache/harmony/beans/internal/nls/messages.properties
new file mode 100644
index 0000000..72b1c8c
--- /dev/null
+++ b/awt/org/apache/harmony/beans/internal/nls/messages.properties
@@ -0,0 +1,103 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# messages for EN locale
+beans.00=no getter for {0} property
+beans.01=no property for name {0} is found
+beans.02=in DefaultPersistenceDelegate.mutatesTo() {0} : {1}
+beans.03=Target Bean class is null
+beans.04=bad property name
+beans.05=Modifier for setter method should be public.
+beans.06=Number of parameters in setter method is not equal to 1.
+beans.07=Parameter type in setter method does not corresponds to predefined.
+beans.08=Number of parameters in getter method is not equal to 0.
+beans.09=Parameter type in getter method does not corresponds to predefined.
+beans.0A=Modifier for getter method should be public.
+beans.0B=Exception in command execution
+beans.0C=source is null
+beans.0D=Error in expression: {0}
+beans.0E=Changes are null
+beans.0F=The new BeanContext can not be set
+beans.10=no node is found for statement with target = {0}
+beans.11=no getter for property {0} found
+beans.12=cannot access property {0} getter
+beans.13=no setter for property {0} found
+beans.14=Exception while finding property descriptor
+beans.15=The listener is null
+beans.16=The provider is null
+beans.17=The child is null
+beans.18=The requestor is null
+beans.19=The service class is null
+beans.1A=The service selector is null
+beans.1B=The service is null
+beans.1C=The event is null
+beans.1D=bean is null
+beans.1E=Illegal class name: {0}
+beans.1F=Method not found: get{0}
+beans.20=Method not found: set{0}
+beans.21=Modifier for indexed getter method should be public.
+beans.22=Number of parameters in getter method is not equal to 1.
+beans.23=Parameter in indexed getter method is not of integer type.
+beans.24=Parameter type in indexed getter method does not correspond to predefined.
+beans.25=Modifier for indexed setter method should be public.
+beans.26=Number of parameters in indexed setter method is not equal to 2.
+beans.27=First parameter type in indexed setter method should be int.
+beans.28=Second parameter type in indexed setter method does not corresponds to predefined.
+beans.29=Membership listener is null
+beans.2A=Target child can not be null
+beans.2B=Resource name can not be null
+beans.2C=The child can not be null
+beans.2D=Invalid resource
+beans.2E=PropertyVetoException was thrown while removing a child: {0}; Original error message:{1}
+beans.2F=Target child is null
+beans.30=PropertyVetoException was thrown while adding a child: {0}; Original error message:{1}
+beans.31=No valid method {0} for {1} found.
+beans.32=Cannot acquire event type from {0} listener.
+beans.33={0} does not return <void>
+beans.34={0} should have a single input parameter
+beans.35=Single parameter does not match to {0} class
+beans.36=No input params are allowed for getListenerMethod
+beans.37=Return type of getListenerMethod is not an array of listeners
+beans.38=Add and remove methods are not available
+beans.39=Cannot generate event set descriptor for name {0}.
+beans.3A=Event type with name {0} is not found.
+beans.3B=skipping expression {0}...
+beans.3C=Unknown method name for array
+beans.3D=First parameter in array getter(setter) is not of Integer type
+beans.3E=Illegal number of arguments in array getter
+beans.3F=Illegal number of arguments in array setter
+beans.40=No constructor for class {0} found
+beans.41=No method with name {0} is found
+beans.42=target is not generated: classname {0} is not found
+beans.43=Cannot convert {0} to char
+beans.44=for property {0} no getter(setter) is found
+beans.45=method name is not generated: error in getMethodName()
+beans.46=Not a valid child
+beans.47=Unable to instantiate property editor
+beans.48=Property editor is not assignable from the PropertyEditor interface
+beans.49=Child cannot implement both BeanContextChild and BeanContextProxy
+beans.4A=newInstance is null
+beans.4B=type is null
+beans.4C=encoder is null
+beans.4D=Invalid method call
+beans.4E=stopClass is not ancestor of beanClass
+beans.4F=search path is null
+beans.50=not an indexed property
+beans.51=Listener method {0} should have parameter of type {1}
+beans.52=listenerMethodName(s) is null
+beans.53=eventSetName is null
+beans.54=listenerType is null
+beans.55=Method is null
diff --git a/awt/org/apache/harmony/x/imageio/internal/nls/Messages.java b/awt/org/apache/harmony/x/imageio/internal/nls/Messages.java
new file mode 100644
index 0000000..498e1bb
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/internal/nls/Messages.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.x.imageio.internal.nls;
+
+import org.apache.harmony.luni.util.MsgHelp;
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ * org.apache.harmony.x.imageio.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ private static final String sResource =
+ "org.apache.harmony.x.imageio.internal.nls.messages"; //$NON-NLS-1$
+
+ /**
+ * Retrieves a message which has no arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg) {
+ return MsgHelp.getString(sResource, msg);
+ }
+
+ /**
+ * Retrieves a message which takes 1 argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * Object the object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg) {
+ return getString(msg, new Object[] { arg });
+ }
+
+ /**
+ * Retrieves a message which takes 1 integer argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * int the integer to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, int arg) {
+ return getString(msg, new Object[] { Integer.toString(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 1 character argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * char the character to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, char arg) {
+ return getString(msg, new Object[] { String.valueOf(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 2 arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg1
+ * Object an object to insert in the formatted output.
+ * @param arg2
+ * Object another object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg1, Object arg2) {
+ return getString(msg, new Object[] { arg1, arg2 });
+ }
+
+ /**
+ * Retrieves a message which takes several arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param args
+ * Object[] the objects to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object[] args) {
+ return MsgHelp.getString(sResource, msg, args);
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/internal/nls/messages.properties b/awt/org/apache/harmony/x/imageio/internal/nls/messages.properties
new file mode 100644
index 0000000..8a49dd8
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/internal/nls/messages.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# messages for EN locale
+imageio.1=Wrong bitDepth-numBands composition \ No newline at end of file
diff --git a/awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java b/awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java
new file mode 100644
index 0000000..caeefdd
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.metadata;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import javax.imageio.metadata.IIOMetadataFormat;
+import javax.imageio.metadata.IIOMetadataFormatImpl;
+
+public class IIOMetadataUtils {
+ private IIOMetadataUtils() {}
+
+ public static IIOMetadataFormat instantiateMetadataFormat(
+ String formatName, boolean standardFormatSupported,
+ String nativeMetadataFormatName, String nativeMetadataFormatClassName,
+ String [] extraMetadataFormatNames, String [] extraMetadataFormatClassNames
+ ) {
+ if (formatName == null) {
+ throw new IllegalArgumentException("formatName == null!");
+ }
+ if (formatName.equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
+ if (standardFormatSupported) {
+ return IIOMetadataFormatImpl.getStandardFormatInstance();
+ }
+ }
+
+ String className = null;
+
+ if (formatName.equals(nativeMetadataFormatName)) {
+ className = nativeMetadataFormatClassName;
+ } else if (extraMetadataFormatNames != null) {
+ for (int i = 0; i < extraMetadataFormatNames.length; i++) {
+ if (formatName.equals(extraMetadataFormatNames[i])) {
+ className = extraMetadataFormatClassNames[i];
+ break;
+ }
+ }
+ }
+
+ if (className == null) {
+ throw new IllegalArgumentException("Unsupported format name");
+ }
+
+ // Get the context class loader and try to use it first
+ ClassLoader contextClassloader = AccessController.doPrivileged(
+ new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+
+ Class cls;
+
+ try {
+ cls = Class.forName(className, true, contextClassloader);
+ } catch (ClassNotFoundException e) {
+ try {
+ // Use current class loader
+ cls = Class.forName(className);
+ } catch (ClassNotFoundException e1) {
+ throw new IllegalStateException ("Can't obtain format");
+ }
+ }
+
+ try {
+ //???AWT:
+ //Method getInstance = cls.getMethod("getInstance");
+ //return (IIOMetadataFormat) getInstance.invoke(null);
+ return null;
+ } catch (Exception e) {
+ IllegalStateException e1 = new IllegalStateException("Can't obtain format");
+ e1.initCause(e); // Add some details to the message
+ throw e1;
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java
new file mode 100644
index 0000000..051f906
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import javax.imageio.stream.ImageInputStream;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This allows usage of the java2d jpegdecoder with ImageInputStream in
+ * the JPEGImageReader. Temporary, only to make JPEGImageReader#read(..)
+ * working.
+ *
+ */
+public class IISDecodingImageSource extends DecodingImageSource {
+
+ private final InputStream is;
+
+ public IISDecodingImageSource(ImageInputStream iis) {
+ is = new IISToInputStreamWrapper(iis);
+ }
+
+ @Override
+ protected boolean checkConnection() {
+ return true;
+ }
+
+ @Override
+ protected InputStream getInputStream() {
+ return is;
+ }
+
+ static class IISToInputStreamWrapper extends InputStream {
+
+ private ImageInputStream input;
+
+ public IISToInputStreamWrapper(ImageInputStream input) {
+ this.input=input;
+ }
+
+ @Override
+ public int read() throws IOException {
+ return input.read();
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return input.read(b);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ return input.read(b, off, len);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return input.skipBytes(n);
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true; // This is orig
+
+ // ???AWT: FIXME
+ // This is an error in Harmony. Not all input streams
+ // have mark support and it is not ok to just return true.
+ // There should be an input.markSupported(). However, if
+ // this call returns false, nothing works anymore.
+
+ // The backside is that BitmapFactory uses a call to markSupport()
+ // to find out if it needs to warp the stream in a
+ // BufferedInputStream to get mark support, and this fails!
+
+ // Currently, the hack is in BitmapFactory, where we always
+ // wrap the stream in a BufferedInputStream.
+ }
+
+ @Override
+ public void mark(int readlimit) {
+ input.mark();
+ }
+
+ @Override
+ public void reset() throws IOException {
+ input.reset();
+ }
+
+ @Override
+ public void close() throws IOException {
+ input.close();
+ }
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java
new file mode 100644
index 0000000..067a825
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+public class JPEGConsts {
+
+ private JPEGConsts() {}
+
+ public static final int SOI = 0xD8;
+
+ //-- IJG (Independed JPEG Group) color spaces
+ public static final int JCS_UNKNOW = 0;
+ public static final int JCS_GRAYSCALE = 1;
+ public static final int JCS_RGB = 2;
+ public static final int JCS_YCbCr = 3;
+ public static final int JCS_CMYK = 4;
+ public static final int JCS_YCC = 5;
+ public static final int JCS_RGBA = 6;
+ public static final int JCS_YCbCrA = 7;
+ public static final int JCS_YCCA = 10;
+ public static final int JCS_YCCK = 11;
+
+ public static int[][] BAND_OFFSETS = {{}, {0}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}};
+
+ public static final float DEFAULT_JPEG_COMPRESSION_QUALITY = 0.75f;
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java
new file mode 100644
index 0000000..110ed23
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.4 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+
+import javax.imageio.ImageReader;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.plugins.jpeg.JPEGImageReadParam;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageReaderSpi;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.awt.image.BufferedImage;
+
+/**
+ * This implementation uses org.apache.harmony.awt.gl.image.JpegDecoder to read
+ * an image. The only implemented method is read(..);
+ *
+ * TODO: Implements generic decoder to be used by javad2 and imageio
+ *
+ * @see org.apache.harmony.awt.gl.image.JpegDecoder
+ * @see org.apache.harmony.x.imageio.plugins.jpeg.IISDecodingImageSource
+ */
+public class JPEGImageReader extends ImageReader {
+
+ ImageInputStream iis;
+
+ public JPEGImageReader(ImageReaderSpi imageReaderSpi) {
+ super(imageReaderSpi);
+ }
+
+ @Override
+ public int getHeight(int i) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public int getWidth(int i) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public int getNumImages(boolean b) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public Iterator<ImageTypeSpecifier> getImageTypes(int i) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public IIOMetadata getStreamMetadata() throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public IIOMetadata getImageMetadata(int i) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public BufferedImage read(int i, ImageReadParam imageReadParam) throws IOException {
+ if (iis == null) {
+ throw new IllegalArgumentException("input stream == null");
+ }
+
+ DecodingImageSource source = new IISDecodingImageSource(iis);
+ OffscreenImage image = new OffscreenImage(source);
+ source.addConsumer(image);
+ source.load();
+ // The interrupted flag should be cleared because ImageDecoder interrupts
+ // current thread while decoding. The same technique is used in
+ // ImageLoader#run(). Another solution can be to create
+ // a separate decoding thread. However, decoder keeps its own pool
+ // of threads so creating a new thread will be just a waste of resources.
+ Thread.interrupted();
+ return image.getBufferedImage();
+ }
+
+ @Override
+ public BufferedImage read(int i) throws IOException {
+ return read(i, null);
+ }
+
+ @Override
+ public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
+ super.setInput(input, seekForwardOnly, ignoreMetadata);
+ iis = (ImageInputStream) input;
+ }
+
+ @Override
+ public ImageReadParam getDefaultReadParam() {
+ return new JPEGImageReadParam();
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java
new file mode 100644
index 0000000..c719ce7
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import java.io.IOException;
+import java.util.Locale;
+import javax.imageio.ImageReader;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.spi.ServiceRegistry;
+import javax.imageio.stream.ImageInputStream;
+
+public class JPEGImageReaderSpi extends ImageReaderSpi {
+
+ public JPEGImageReaderSpi() {
+ super(JPEGSpiConsts.vendorName, JPEGSpiConsts.version,
+ JPEGSpiConsts.names, JPEGSpiConsts.suffixes,
+ JPEGSpiConsts.MIMETypes, JPEGSpiConsts.readerClassName,
+ STANDARD_INPUT_TYPE, JPEGSpiConsts.writerSpiNames,
+ JPEGSpiConsts.supportsStandardStreamMetadataFormat,
+ JPEGSpiConsts.nativeStreamMetadataFormatName,
+ JPEGSpiConsts.nativeStreamMetadataFormatClassName,
+ JPEGSpiConsts.extraStreamMetadataFormatNames,
+ JPEGSpiConsts.extraStreamMetadataFormatClassNames,
+ JPEGSpiConsts.supportsStandardImageMetadataFormat,
+ JPEGSpiConsts.nativeImageMetadataFormatName,
+ JPEGSpiConsts.nativeImageMetadataFormatClassName,
+ JPEGSpiConsts.extraImageMetadataFormatNames,
+ JPEGSpiConsts.extraImageMetadataFormatClassNames);
+ }
+
+
+ @Override
+ public boolean canDecodeInput(Object source) throws IOException {
+ ImageInputStream markable = (ImageInputStream) source;
+ try {
+ markable.mark();
+
+ byte[] signature = new byte[3];
+ markable.seek(0);
+ markable.read(signature, 0, 3);
+ markable.reset();
+
+ if ((signature[0] & 0xFF) == 0xFF &&
+ (signature[1] & 0xFF) == JPEGConsts.SOI &&
+ (signature[2] & 0xFF) == 0xFF) { // JPEG
+ return true;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ @Override
+ public ImageReader createReaderInstance(Object extension) throws IOException {
+ return new JPEGImageReader(this);
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "DRL JPEG decoder";
+ }
+
+ @Override
+ public void onRegistration(ServiceRegistry registry, Class<?> category) {
+ // super.onRegistration(registry, category);
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java
new file mode 100644
index 0000000..ae3e876
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java
@@ -0,0 +1,402 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import com.android.internal.awt.ImageOutputStreamWrapper;
+
+import javax.imageio.ImageWriter;
+import javax.imageio.IIOImage;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.metadata.IIOMetadata;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap.CompressFormat;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.awt.image.*;
+import java.awt.*;
+import java.awt.color.ColorSpace;
+
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+public class JPEGImageWriter extends ImageWriter {
+
+ // /* ???AWT: Debugging
+ private static final boolean DEBUG = false;
+ private static Bitmap bm;
+ public static Bitmap getBitmap() {
+ return bm;
+ }
+ private static BufferedImage bufImg;
+ public static BufferedImage getBufImage() {
+ return bufImg;
+ }
+ static private RenderedImage renImg;
+ static public RenderedImage getRenImage() {
+ return renImg;
+ }
+ // */
+
+ private long cinfo;
+ private RenderedImage image;
+ private Raster sourceRaster;
+ private WritableRaster scanRaster;
+ private int srcXOff = 0;
+ private int srcYOff = 0;
+ private int srcWidth;
+ private int srcHeight;
+
+ //-- y step for image subsampling
+ private int deltaY = 1;
+ //-- x step for image subsampling
+ private int deltaX = 1;
+
+ private ImageOutputStream ios;
+
+ public JPEGImageWriter(ImageWriterSpi imageWriterSpi) {
+ super(imageWriterSpi);
+ //???AWT: cinfo = initCompressionObj();
+ cinfo = System.currentTimeMillis();
+ }
+
+ static {
+ //???AWT
+ /*
+ System.loadLibrary("jpegencoder");
+ initWriterIds(ImageOutputStream.class);
+ */
+ }
+
+ @Override
+ public void write(IIOMetadata iioMetadata, IIOImage iioImage, ImageWriteParam param)
+ throws IOException {
+
+ if (ios == null) {
+ throw new IllegalArgumentException("ios == null");
+ }
+ if (iioImage == null) {
+ throw new IllegalArgumentException("Image equals null");
+ }
+
+ RenderedImage img = null;
+ if (!iioImage.hasRaster()) {
+ img = iioImage.getRenderedImage();
+ if (img instanceof BufferedImage) {
+ sourceRaster = ((BufferedImage) img).getRaster();
+ } else {
+ sourceRaster = img.getData();
+ }
+ } else {
+ sourceRaster = iioImage.getRaster();
+ }
+
+ // AWT???: Debugging
+ if (DEBUG) {
+ if( img==null ) {
+ System.out.println("****J: Image is NULL");
+ } else {
+ renImg = img;
+ bufImg = (BufferedImage)img;
+ }
+ }
+
+ int numBands = sourceRaster.getNumBands();
+ int sourceIJGCs = img == null ? JPEGConsts.JCS_UNKNOW : getSourceCSType(img);
+
+ srcWidth = sourceRaster.getWidth();
+ srcHeight = sourceRaster.getHeight();
+
+ int destWidth = srcWidth;
+ int destHeight = srcHeight;
+
+ boolean progressive = false;
+
+ if (param != null) {
+ Rectangle reg = param.getSourceRegion();
+ if (reg != null) {
+ srcXOff = reg.x;
+ srcYOff = reg.y;
+
+ srcWidth = reg.width + srcXOff > srcWidth
+ ? srcWidth - srcXOff
+ : reg.width;
+ srcHeight = reg.height + srcYOff > srcHeight
+ ? srcHeight - srcYOff
+ : reg.height;
+ }
+
+ //-- TODO uncomment when JPEGImageWriteParam be implemented
+ //-- Only default progressive mode yet
+ // progressive = param.getProgressiveMode() == ImageWriteParam.MODE_DEFAULT;
+
+ //-- def is 1
+ deltaX = param.getSourceXSubsampling();
+ deltaY = param.getSourceYSubsampling();
+
+ //-- def is 0
+ int offsetX = param.getSubsamplingXOffset();
+ int offsetY = param.getSubsamplingYOffset();
+
+ srcXOff += offsetX;
+ srcYOff += offsetY;
+ srcWidth -= offsetX;
+ srcHeight -= offsetY;
+
+ destWidth = (srcWidth + deltaX - 1) / deltaX;
+ destHeight = (srcHeight + deltaY - 1) / deltaY;
+ }
+
+ //-- default DQTs (see JPEGQTable java doc and JPEG spec K1 & K2 tables)
+ //-- at http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ //-- Only figuring out how to set DQT in IJG library for future metadata
+ //-- support. IJG def tables are the same.
+ //JPEGQTable[] dqt = new JPEGQTable[2];
+// int[][] dqt = null;
+// int[][] dqt = new int[2][];
+// dqt[0] = JPEGQTable.K1Div2Luminance.getTable();
+// dqt[1] = JPEGQTable.K2Div2Chrominance.getTable();
+
+ //???AWT: I think we don't need this amymore
+ /*
+ //-- using default color space
+ //-- TODO: Take destination cs from param or use default if there is no cs
+ int destIJGCs = img == null ? JPEGConsts.JCS_UNKNOW : getDestinationCSType(img);
+
+ DataBufferByte dbuffer = new DataBufferByte(numBands * srcWidth);
+
+ scanRaster = Raster.createInterleavedRaster(dbuffer, srcWidth, 1,
+ numBands * srcWidth, numBands, JPEGConsts.BAND_OFFSETS[numBands], null);
+
+ encode(dbuffer.getData(), srcWidth, destWidth, destHeight, deltaX,
+ sourceIJGCs, destIJGCs, numBands, progressive,
+ null, cinfo);
+ */
+
+ SampleModel model = sourceRaster.getSampleModel();
+
+ if (model instanceof SinglePixelPackedSampleModel) {
+ DataBufferInt ibuf = (DataBufferInt)sourceRaster.getDataBuffer();
+ int[] pixels = ibuf.getData();
+
+ // Create a bitmap with the pixel
+ bm = Bitmap.createBitmap(pixels, srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
+
+ // Use Bitmap.compress() to write the image
+ ImageOutputStreamWrapper iosw = new ImageOutputStreamWrapper(ios);
+ bm.compress(CompressFormat.JPEG, 100, iosw);
+ } else {
+ // ???AWT: Add support for other color models
+ throw new RuntimeException("Color model not supported yet");
+ }
+
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (cinfo != 0) {
+ //???AWT: dispose(cinfo);
+ cinfo = 0;
+ ios = null;
+ }
+ }
+
+
+ public IIOMetadata getDefaultStreamMetadata(ImageWriteParam imageWriteParam) {
+ throw new UnsupportedOperationException("not supported yet");
+ }
+
+ public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam) {
+ throw new UnsupportedOperationException("not supported yet");
+ }
+
+ @Override
+ public IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata, ImageWriteParam imageWriteParam) {
+ throw new UnsupportedOperationException("not supported yet");
+ }
+
+ @Override
+ public IIOMetadata convertImageMetadata(IIOMetadata iioMetadata, ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam) {
+ throw new UnsupportedOperationException("not supported yet");
+ }
+
+ @Override
+ public void setOutput(Object output) {
+ super.setOutput(output);
+ ios = (ImageOutputStream) output;
+ //???AWT: setIOS(ios, cinfo);
+ sourceRaster = null;
+ scanRaster = null;
+ srcXOff = 0;
+ srcYOff = 0;
+ srcWidth = 0;
+ srcHeight = 0;
+ deltaY = 1;
+ }
+
+ /**
+ * Frees resources
+ * @param structPointer
+ */
+ //???AWT: private native void dispose(long structPointer);
+
+ /**
+ * Inits methods Ids for native to java callbacks
+ * @param iosClass
+ */
+ //???AWT: private native static void initWriterIds(Class<ImageOutputStream> iosClass);
+
+ /**
+ * Inits compression objects
+ * @return pointer to the native structure
+ */
+ //???AWT: private native long initCompressionObj();
+
+ /**
+ * Sets image output stream in IJG layer
+ * @param stream
+ */
+ //???AWT: private native void setIOS(ImageOutputStream stream, long structPointer);
+
+ /**
+ * Runs encoding process.
+ *
+ * @param data image data buffer to encode
+ * @param srcWidth - source width
+ * @param width - destination width
+ * @param height destination height
+ * @param deltaX - x subsampling step
+ * @param inColorSpace - original color space
+ * @param outColorSpace - destination color space
+ * @param numBands - number of bands
+ * @param cinfo - native handler
+ * @return
+ */
+ //???AWT:
+ /*
+ private native boolean encode(byte[] data, int srcWidth,
+ int width, int height, int deltaX,
+ int inColorSpace, int outColorSpace,
+ int numBands, boolean progressive,
+ int[][] dqt,
+ long cinfo);
+ */
+
+ /**
+ * Callback for getting a next scanline
+ * @param scanline scan line number
+ */
+ @SuppressWarnings("unused")
+ private void getScanLine(int scanline) {
+ //-- TODO: processImageProgress in ImageWriter
+ Raster child = sourceRaster.createChild(srcXOff,
+ srcYOff + scanline * deltaY, srcWidth, 1, 0, 0, null);
+
+ scanRaster.setRect(child);
+ }
+
+ /**
+ * Maps color space types to IJG color spaces
+ * @param image
+ * @return
+ */
+ private int getSourceCSType(RenderedImage image) {
+ int type = JPEGConsts.JCS_UNKNOW;
+ ColorModel cm = image.getColorModel();
+
+ if (null == cm) {
+ return type;
+ }
+
+ if (cm instanceof IndexColorModel) {
+ throw new UnsupportedOperationException("IndexColorModel is not supported yet");
+ }
+
+ boolean hasAlpha = cm.hasAlpha();
+ ColorSpace cs = cm.getColorSpace();
+ switch(cs.getType()) {
+ case ColorSpace.TYPE_GRAY:
+ type = JPEGConsts.JCS_GRAYSCALE;
+ break;
+ case ColorSpace.TYPE_RGB:
+ type = hasAlpha ? JPEGConsts.JCS_RGBA : JPEGConsts.JCS_RGB;
+ break;
+ case ColorSpace.TYPE_YCbCr:
+ type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
+ break;
+ case ColorSpace.TYPE_3CLR:
+ type = hasAlpha ? JPEGConsts.JCS_YCCA : JPEGConsts.JCS_YCC;
+ break;
+ case ColorSpace.TYPE_CMYK:
+ type = JPEGConsts.JCS_CMYK;
+ break;
+ }
+ return type;
+ }
+
+ /**
+ * Returns destination color space.
+ * (YCbCr[A] for RGB)
+ *
+ * @param image
+ * @return
+ */
+ private int getDestinationCSType(RenderedImage image) {
+ int type = JPEGConsts.JCS_UNKNOW;
+ ColorModel cm = image.getColorModel();
+ if (null != cm) {
+ boolean hasAlpha = cm.hasAlpha();
+ ColorSpace cs = cm.getColorSpace();
+
+ switch(cs.getType()) {
+ case ColorSpace.TYPE_GRAY:
+ type = JPEGConsts.JCS_GRAYSCALE;
+ break;
+ case ColorSpace.TYPE_RGB:
+ type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
+ break;
+ case ColorSpace.TYPE_YCbCr:
+ type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr;
+ break;
+ case ColorSpace.TYPE_3CLR:
+ type = hasAlpha ? JPEGConsts.JCS_YCCA : JPEGConsts.JCS_YCC;
+ break;
+ case ColorSpace.TYPE_CMYK:
+ type = JPEGConsts.JCS_CMYK;
+ break;
+ }
+ }
+ return type;
+ }
+
+ public ImageWriteParam getDefaultWriteParam() {
+ return new JPEGImageWriteParam(getLocale());
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java
new file mode 100644
index 0000000..b7990e0
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.ImageWriter;
+import javax.imageio.ImageTypeSpecifier;
+import java.io.IOException;
+import java.util.Locale;
+
+public class JPEGImageWriterSpi extends ImageWriterSpi {
+
+ public JPEGImageWriterSpi() {
+ super(JPEGSpiConsts.vendorName, JPEGSpiConsts.version,
+ JPEGSpiConsts.names, JPEGSpiConsts.suffixes, JPEGSpiConsts.MIMETypes,
+ JPEGSpiConsts.writerClassName, STANDARD_OUTPUT_TYPE,
+ JPEGSpiConsts.readerSpiNames, JPEGSpiConsts.supportsStandardStreamMetadataFormat /*TODO: support st. metadata format*/,
+ JPEGSpiConsts.nativeStreamMetadataFormatName, JPEGSpiConsts.nativeStreamMetadataFormatClassName,
+ JPEGSpiConsts.extraStreamMetadataFormatNames, JPEGSpiConsts.extraStreamMetadataFormatClassNames,
+ JPEGSpiConsts.supportsStandardImageMetadataFormat, JPEGSpiConsts.nativeImageMetadataFormatName, JPEGSpiConsts.nativeImageMetadataFormatClassName,
+ JPEGSpiConsts.extraImageMetadataFormatNames, JPEGSpiConsts.extraImageMetadataFormatClassNames);
+ }
+
+ @Override
+ public boolean canEncodeImage(ImageTypeSpecifier imageTypeSpecifier) {
+ return true;
+ }
+
+ @Override
+ public ImageWriter createWriterInstance(Object o) throws IOException {
+ return new JPEGImageWriter(this);
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "DRL JPEG Encoder";
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java
new file mode 100644
index 0000000..c3b4a50
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.plugins.jpeg;
+
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+public class JPEGSpiConsts {
+ private JPEGSpiConsts() {}
+
+ public static final String vendorName = "Intel Corporation";
+ public static final String version = "0.1 beta";
+
+ static final String readerClassName = "org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReader";
+ static final String writerClassName = "org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriter";
+
+ static final String[] names = {"jpeg", "jpg", "JPEG", "JPG"};
+ static final String[] suffixes = {"jpeg", "jpg"};
+ static final String[] MIMETypes = {"image/jpeg"};
+
+ static final String[] writerSpiNames = {"org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriterSpi"};
+ static final String[] readerSpiNames = {"org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReaderSpi"};
+
+ //-- TODO fill this stuff with correct data
+ static final boolean supportsStandardStreamMetadataFormat = false;
+ static final String nativeStreamMetadataFormatName = null;
+ static final String nativeStreamMetadataFormatClassName = null;
+ static final String[] extraStreamMetadataFormatNames = null;
+ static final String[] extraStreamMetadataFormatClassNames = null;
+ static final boolean supportsStandardImageMetadataFormat = false;
+ static final String nativeImageMetadataFormatName =
+ "org.apache.harmony.x.imageio.plugins.jpeg.MyFormatMetadata_1.0";
+ static final String nativeImageMetadataFormatClassName =
+ "org.apache.harmony.x.imageio.plugins.jpeg.MyFormatMetadata";
+ static final String[] extraImageMetadataFormatNames = null;
+ static final String[] extraImageMetadataFormatClassNames = null;
+
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java
new file mode 100644
index 0000000..480041c
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.plugins.png;
+
+import org.apache.harmony.awt.gl.image.DecodingImageSource;
+import org.apache.harmony.awt.gl.image.OffscreenImage;
+import org.apache.harmony.x.imageio.plugins.jpeg.IISDecodingImageSource;
+
+import javax.imageio.ImageReader;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageReadParam;
+import javax.imageio.plugins.jpeg.JPEGImageReadParam;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.metadata.IIOMetadata;
+import java.io.IOException;
+import java.util.Iterator;
+import java.awt.image.BufferedImage;
+
+public class PNGImageReader extends ImageReader {
+ ImageInputStream iis;
+
+ public PNGImageReader(ImageReaderSpi imageReaderSpi) {
+ super(imageReaderSpi);
+ }
+
+ public int getNumImages(boolean allowSearch) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ public int getWidth(int imageIndex) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ public int getHeight(int imageIndex) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public IIOMetadata getStreamMetadata() throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
+ //-- TODO imlement
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public BufferedImage read(int i, ImageReadParam imageReadParam) throws IOException {
+ if (iis == null) {
+ throw new IllegalArgumentException("input stream == null");
+ }
+
+ DecodingImageSource source = new IISDecodingImageSource(iis);
+ OffscreenImage image = new OffscreenImage(source);
+ source.addConsumer(image);
+ source.load();
+ // The interrupted flag should be cleared because ImageDecoder interrupts
+ // current thread while decoding (due its architecture).
+ Thread.interrupted();
+ return image.getBufferedImage();
+ }
+
+ @Override
+ public BufferedImage read(int i) throws IOException {
+ return read(i, null);
+ }
+
+ @Override
+ public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
+ super.setInput(input, seekForwardOnly, ignoreMetadata);
+ iis = (ImageInputStream) input;
+ }
+
+ @Override
+ public ImageReadParam getDefaultReadParam() {
+ return new ImageReadParam();
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java
new file mode 100644
index 0000000..50f8b10
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.plugins.png;
+
+import org.apache.harmony.x.imageio.plugins.jpeg.JPEGSpiConsts;
+
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.spi.ServiceRegistry;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+import java.io.IOException;
+import java.util.Locale;
+
+public class PNGImageReaderSpi extends ImageReaderSpi {
+ static final String PNG_NAMES[] = new String[] {"png", "PNG"};
+ static final String PNG_SUFFIXES[] = new String[] {"png"};
+ static final String PNG_MIME_TYPES[] = new String[] {"image/png"};
+ static final String PNG_READER_CLASS_NAME = "org.apache.harmony.x.imageio.plugins.png.PNGImageReader";
+ static final String PNG_READER_SPI_NAMES[] = {"org.apache.harmony.x.imageio.plugins.png.PNGImageReaderSpi"};
+
+ public PNGImageReaderSpi() {
+ super(
+ JPEGSpiConsts.vendorName, JPEGSpiConsts.version,
+ PNG_NAMES, PNG_SUFFIXES,
+ PNG_MIME_TYPES, PNG_READER_CLASS_NAME,
+ STANDARD_INPUT_TYPE, null,
+ false, null,
+ null, null,
+ null, false,
+ null, null,
+ null, null
+ );
+ }
+
+ @Override
+ public boolean canDecodeInput(Object source) throws IOException {
+ ImageInputStream markable = (ImageInputStream) source;
+ markable.mark();
+
+ byte[] signature = new byte[8];
+ markable.seek(0);
+
+ int nBytes = markable.read(signature, 0, 8);
+ if(nBytes != 8) markable.read(signature, nBytes, 8-nBytes);
+ markable.reset();
+
+ // PNG signature: 137 80 78 71 13 10 26 10
+ return (signature[0] & 0xFF) == 137 &&
+ (signature[1] & 0xFF) == 80 &&
+ (signature[2] & 0xFF) == 78 &&
+ (signature[3] & 0xFF) == 71 &&
+ (signature[4] & 0xFF) == 13 &&
+ (signature[5] & 0xFF) == 10 &&
+ (signature[6] & 0xFF) == 26 &&
+ (signature[7] & 0xFF) == 10;
+ }
+
+ @Override
+ public ImageReader createReaderInstance(Object extension) throws IOException {
+ return new PNGImageReader(this);
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "DRL PNG decoder";
+ }
+
+ @Override
+ public void onRegistration(ServiceRegistry registry, Class<?> category) {
+ super.onRegistration(registry, category);
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java
new file mode 100644
index 0000000..e2a8d7d
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Viskov Nikolay
+ * @version $Revision$
+ */
+package org.apache.harmony.x.imageio.plugins.png;
+
+import com.android.internal.awt.ImageOutputStreamWrapper;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+
+import javax.imageio.IIOImage;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.stream.ImageOutputStream;
+
+import org.apache.harmony.x.imageio.internal.nls.Messages;
+
+import org.apache.harmony.luni.util.NotImplementedException;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+
+public class PNGImageWriter extends ImageWriter {
+
+ // /* ???AWT: Debugging
+ private static final boolean DEBUG = false;
+ private static Bitmap bm;
+ public static Bitmap getBitmap() {
+ return bm;
+ }
+ // */
+
+ private static int[][] BAND_OFFSETS = {
+ {}, {
+ 0 }, {
+ 0, 1 }, {
+ 0, 1, 2 }, {
+ 0, 1, 2, 3 } };
+
+ // Each pixel is a grayscale sample.
+ private static final int PNG_COLOR_TYPE_GRAY = 0;
+ // Each pixel is an R,G,B triple.
+ private static final int PNG_COLOR_TYPE_RGB = 2;
+ // Each pixel is a palette index, a PLTE chunk must appear.
+ private static final int PNG_COLOR_TYPE_PLTE = 3;
+ // Each pixel is a grayscale sample, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4;
+ // Each pixel is an R,G,B triple, followed by an alpha sample.
+ private static final int PNG_COLOR_TYPE_RGBA = 6;
+
+ //???AWT: private static native void initIDs(Class<ImageOutputStream> iosClass);
+
+ static {
+ //???AWT
+ /*
+ System.loadLibrary("pngencoder"); //$NON-NLS-1$
+ initIDs(ImageOutputStream.class);
+ */
+ }
+
+ /*
+ private native int encode(byte[] input, int bytesInBuffer, int bytePixelSize, Object ios, int imageWidth,
+ int imageHeight, int bitDepth, int colorType, int[] palette, int i, boolean b);
+ */
+
+ protected PNGImageWriter(ImageWriterSpi iwSpi) {
+ super(iwSpi);
+ }
+
+ @Override
+ public IIOMetadata convertStreamMetadata(IIOMetadata arg0, ImageWriteParam arg1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IIOMetadata convertImageMetadata(IIOMetadata arg0, ImageTypeSpecifier arg1, ImageWriteParam arg2) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier arg0, ImageWriteParam arg1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IIOMetadata getDefaultStreamMetadata(ImageWriteParam arg0) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void write(IIOMetadata streamMetadata, IIOImage iioImage, ImageWriteParam param) throws IOException {
+ if (output == null) {
+ throw new IllegalStateException("Output not been set");
+ }
+ if (iioImage == null) {
+ throw new IllegalArgumentException("Image equals null");
+ }
+ // AWT???: I think this is not needed anymore
+ // if (iioImage.hasRaster() && !canWriteRasters()) {
+ // throw new UnsupportedOperationException("Can't write raster");
+ //}// ImageOutputStreamImpl
+
+ Raster sourceRaster;
+ RenderedImage img = null;
+ if (!iioImage.hasRaster()) {
+ img = iioImage.getRenderedImage();
+ if (img instanceof BufferedImage) {
+ sourceRaster = ((BufferedImage) img).getRaster();
+ } else {
+ sourceRaster = img.getData();
+ }
+ } else {
+ sourceRaster = iioImage.getRaster();
+ }
+
+ SampleModel model = sourceRaster.getSampleModel();
+ int srcWidth = sourceRaster.getWidth();
+ int srcHeight = sourceRaster.getHeight();
+ int numBands = model.getNumBands();
+
+ ColorModel colorModel = img.getColorModel();
+ int pixelSize = colorModel.getPixelSize();
+ int bytePixelSize = pixelSize / 8;
+ int bitDepth = pixelSize / numBands;
+
+ // byte per band
+ int bpb = bitDepth > 8 ? 2 : 1;
+
+ boolean isInterlace = true;
+ if (param instanceof PNGImageWriterParam) {
+ isInterlace = ((PNGImageWriterParam) param).getInterlace();
+ }
+
+ int colorType = PNG_COLOR_TYPE_GRAY;
+ int[] palette = null;
+
+ if (colorModel instanceof IndexColorModel) {
+ if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8) {
+// Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+ }
+ if (numBands != 1) {
+// Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+ }
+
+ IndexColorModel icm = (IndexColorModel) colorModel;
+ palette = new int[icm.getMapSize()];
+ icm.getRGBs(palette);
+ colorType = PNG_COLOR_TYPE_PLTE;
+ }
+ else if (numBands == 1) {
+ if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8 && bitDepth != 16) {
+// Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+ }
+ colorType = PNG_COLOR_TYPE_GRAY;
+ }
+ else if (numBands == 2) {
+ if (bitDepth != 8 && bitDepth != 16) {
+// Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$
+ }
+ colorType = PNG_COLOR_TYPE_GRAY_ALPHA;
+ }
+ else if (numBands == 3) {
+ if (bitDepth != 8 && bitDepth != 16) {
+// Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1")); //$NON-NLS-1$
+ }
+ colorType = PNG_COLOR_TYPE_RGB;
+ }
+ else if (numBands == 4) {
+ if (bitDepth != 8 && bitDepth != 16) {
+ //Wrong bitDepth-numBands composition
+ throw new IllegalArgumentException(Messages.getString("imageio.1")); //$NON-NLS-1$
+ }
+ colorType = PNG_COLOR_TYPE_RGBA;
+ }
+
+ /* ???AWT: I think this is not needed anymore
+ int dbufferLenght = bytePixelSize * imageHeight * imageWidth;
+ DataBufferByte dbuffer = new DataBufferByte(dbufferLenght);
+
+ WritableRaster scanRaster = Raster.createInterleavedRaster(dbuffer, imageWidth, imageHeight, bpb * numBands
+ * imageWidth, bpb * numBands, BAND_OFFSETS[numBands], null);
+
+ scanRaster.setRect(((BufferedImage) image).getRaster()// image.getData()
+ .createChild(0, 0, imageWidth, imageHeight, 0, 0, null));
+ */
+
+ if (DEBUG) {
+ System.out.println("**** raster:" + sourceRaster);
+ System.out.println("**** model:" + model);
+ System.out.println("**** type:" + colorType);
+ }
+
+ if (model instanceof SinglePixelPackedSampleModel) {
+ DataBufferInt ibuf = (DataBufferInt)sourceRaster.getDataBuffer();
+ int[] pixels = ibuf.getData();
+
+ // Create a bitmap with the pixel
+ bm = Bitmap.createBitmap(pixels, srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
+
+ // Use Bitmap.compress() to write the image
+ ImageOutputStream ios = (ImageOutputStream) getOutput();
+ ImageOutputStreamWrapper iosw = new ImageOutputStreamWrapper(ios);
+ bm.compress(CompressFormat.PNG, 100, iosw);
+ } else {
+ // ???AWT: Add support for other color models
+ throw new RuntimeException("Color model not supported yet");
+ }
+ }
+
+ public ImageWriteParam getDefaultWriteParam() {
+ return new PNGImageWriterParam();
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java
new file mode 100644
index 0000000..bf3a000
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Viskov Nikolay
+ * @version $Revision$
+ */
+package org.apache.harmony.x.imageio.plugins.png;
+
+import javax.imageio.ImageWriteParam;
+
+public class PNGImageWriterParam extends ImageWriteParam {
+
+ private boolean isInterlace = true;
+
+ public PNGImageWriterParam() {
+ super();
+ }
+
+ public boolean getInterlace() {
+ return isInterlace;
+ }
+
+ public void setInterlace(boolean b) {
+ isInterlace = b;
+ }
+
+}
diff --git a/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java
new file mode 100644
index 0000000..6eed14d
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Viskov Nikolay
+ * @version $Revision$
+ */
+package org.apache.harmony.x.imageio.plugins.png;
+
+import java.awt.image.ColorModel;
+import java.awt.image.DataBufferByte;
+import java.awt.image.IndexColorModel;
+import java.io.IOException;
+import java.util.Locale;
+
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriter;
+import javax.imageio.spi.ImageWriterSpi;
+
+public class PNGImageWriterSpi extends ImageWriterSpi {
+
+ public PNGImageWriterSpi() {
+ super("Intel Corporation",// vendorName
+ "1.0",// version
+ new String[] {
+ "png", "PNG" },// names
+ new String[] {
+ "png", "PNG" },// suffixes
+ new String[] {
+ "image/png" },// MIMETypes
+ "org.apache.harmony.x.imageio.plugins.png.PNGImageWriter",// writerClassName
+ STANDARD_OUTPUT_TYPE,// outputTypes
+ new String[] {
+ "org.apache.harmony.x.imageio.plugins.png.PNGImageWriterSpi" },// readerSpiNames
+ false,// supportsStandardStreamMetadataFormat
+ null,// nativeStreamMetadataFormatName
+ null,// nativeStreamMetadataFormatClassName
+ null,// extraStreamMetadataFormatNames
+ null,// extraStreamMetadataFormatClassNames
+ false,// supportsStandardImageMetadataFormat
+ null,// nativeImageMetadataFormatName
+ null,// nativeImageMetadataFormatClassName
+ null,// extraImageMetadataFormatNames
+ null// extraImageMetadataFormatClassNames
+ );
+ }
+
+ @Override
+ public boolean canEncodeImage(ImageTypeSpecifier type) {
+ boolean canEncode = true;
+
+ int numBands = type.getSampleModel().getNumBands();
+
+ ColorModel colorModel = type.getColorModel();
+
+ int bitDepth = colorModel.getPixelSize() / numBands;
+
+ if (colorModel instanceof IndexColorModel) {
+ if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8) {
+ canEncode = false;
+ }
+ if (numBands != 1) {
+ canEncode = false;
+ }
+ }
+ else if (numBands == 1) {
+ if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8 && bitDepth != 16) {
+ canEncode = false;
+ }
+ }
+ else if (numBands == 2) {
+ if (bitDepth != 8 && bitDepth != 16) {
+ canEncode = false;
+ }
+ }
+ else if (numBands == 3) {
+ if (bitDepth != 8 && bitDepth != 16) {
+ canEncode = false;
+ }
+ }
+ else if (numBands == 4) {
+ if (bitDepth != 8 && bitDepth != 16) {
+ canEncode = false;
+ }
+ }
+
+ return canEncode;
+ }
+
+ @Override
+ public ImageWriter createWriterInstance(Object arg0) throws IOException {
+ return new PNGImageWriter(this);
+ }
+
+ @Override
+ public String getDescription(Locale arg0) {
+ return "DRL PNG encoder";
+ }
+
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java b/awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java
new file mode 100644
index 0000000..d4fdd76
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/FileIISSpi.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageInputStreamSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.FileImageOutputStream;
+import javax.imageio.stream.FileImageInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+
+public class FileIISSpi extends ImageInputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public FileIISSpi() {
+ super(vendor, ver, File.class);
+ }
+
+ @Override
+ public ImageInputStream createInputStreamInstance(Object input, boolean useCache,
+ File cacheDir) throws IOException {
+ if (File.class.isInstance(input)) {
+ return new FileImageInputStream((File) input);
+ }
+ throw new IllegalArgumentException("input is not an instance of java.io.File");
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "File IIS Spi";
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java b/awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java
new file mode 100644
index 0000000..acda6a1
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/FileIOSSpi.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageOutputStreamSpi;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.FileImageOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+
+public class FileIOSSpi extends ImageOutputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public FileIOSSpi() {
+ super(vendor, ver, File.class);
+ }
+
+ @Override
+ public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache,
+ File cacheDir) throws IOException {
+ if (output instanceof File) {
+ return new FileImageOutputStream((File) output);
+ }
+ throw new IllegalArgumentException("output is not instance of File");
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "File IOS Spi";
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java b/awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java
new file mode 100644
index 0000000..ed2fef0
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageInputStreamSpi;
+import javax.imageio.stream.*;
+import java.io.OutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+
+public class InputStreamIISSpi extends ImageInputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public InputStreamIISSpi() {
+ super(vendor, ver, InputStream.class);
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "Output Stream IOS Spi";
+ }
+
+ @Override
+ public boolean canUseCacheFile() {
+ return true;
+ }
+
+ @Override
+ public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) throws IOException {
+ if (input instanceof InputStream) {
+ if (useCache) {
+ return new FileCacheImageInputStream((InputStream) input, cacheDir);
+ } else {
+ return new MemoryCacheImageInputStream((InputStream) input);
+ }
+ }
+ throw new IllegalArgumentException("Output is not an instance of InputStream");
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java b/awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java
new file mode 100644
index 0000000..dd1e88d
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageOutputStreamSpi;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.FileCacheImageOutputStream;
+import javax.imageio.stream.MemoryCacheImageOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Locale;
+
+public class OutputStreamIOSSpi extends ImageOutputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public OutputStreamIOSSpi() {
+ super(vendor, ver, OutputStream.class);
+ }
+
+ @Override
+ public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) throws IOException {
+ if (output instanceof OutputStream) {
+ if (useCache) {
+ return new FileCacheImageOutputStream((OutputStream) output, cacheDir);
+ } else {
+ return new MemoryCacheImageOutputStream((OutputStream) output);
+ }
+ }
+ throw new IllegalArgumentException("Output is not an instance of OutputStream");
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "Output Stream IOS Spi";
+ }
+
+ @Override
+ public boolean canUseCacheFile() {
+ return true;
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java b/awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java
new file mode 100644
index 0000000..f97eb87
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/RAFIISSpi.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageInputStreamSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.FileImageInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Locale;
+
+public class RAFIISSpi extends ImageInputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public RAFIISSpi() {
+ super(vendor, ver, RandomAccessFile.class);
+ }
+
+ @Override
+ public ImageInputStream createInputStreamInstance(Object input, boolean useCache,
+ File cacheDir) throws IOException {
+ if (RandomAccessFile.class.isInstance(input)) {
+ return new FileImageInputStream((RandomAccessFile) input);
+ }
+ throw new IllegalArgumentException(
+ "input is not an instance of java.io.RandomAccessFile");
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "RandomAccessFile IIS Spi";
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java b/awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java
new file mode 100644
index 0000000..a9d3649
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.2 $
+ */
+package org.apache.harmony.x.imageio.spi;
+
+import javax.imageio.spi.ImageOutputStreamSpi;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.FileImageOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Locale;
+
+public class RAFIOSSpi extends ImageOutputStreamSpi {
+ private static final String vendor = "Apache";
+
+ private static final String ver = "0.1";
+
+ public RAFIOSSpi() {
+ super(vendor, ver, RandomAccessFile.class);
+ }
+
+ @Override
+ public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache,
+ File cacheDir) throws IOException {
+ if (output instanceof RandomAccessFile) {
+ return new FileImageOutputStream((RandomAccessFile) output);
+ }
+ throw new IllegalArgumentException("output is not instance of java.io.RandomAccessFile");
+ }
+
+ @Override
+ public String getDescription(Locale locale) {
+ return "RandomAccessFile IOS Spi";
+ }
+}
diff --git a/awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java b/awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java
new file mode 100644
index 0000000..64f7b2a
--- /dev/null
+++ b/awt/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.harmony.x.imageio.stream;
+
+import java.util.ArrayList;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public final class RandomAccessMemoryCache {
+ private static final int BLOCK_SHIFT = 9;
+ private static final int BLOCK_SIZE = 1 << BLOCK_SHIFT;
+ private static final int BLOCK_MASK = BLOCK_SIZE - 1;
+
+ private long length;
+
+ private int firstUndisposed = 0;
+
+ private ArrayList<byte[]> blocks = new ArrayList<byte[]>();
+
+ public RandomAccessMemoryCache() {
+ }
+
+ public long length() {
+ return length;
+ }
+
+ public void close() {
+ blocks.clear();
+ length = 0;
+ }
+
+ private void grow(long pos) {
+ int blocksNeeded = (int)(pos >> BLOCK_SHIFT) - blocks.size() + 1;
+ for (int i=0; i < blocksNeeded; i++) {
+ blocks.add(new byte[BLOCK_SIZE]);
+ }
+
+ length = pos + 1;
+ }
+
+ public void putData(int oneByte, long pos) {
+ if (pos >= length) {
+ grow(pos);
+ }
+
+ byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+ block[(int)(pos & BLOCK_MASK)] = (byte) oneByte;
+ }
+
+ public void putData(byte[] buffer, int offset, int count, long pos) {
+ if (count > buffer.length - offset || count < 0 || offset < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (count == 0){
+ return;
+ }
+
+ long lastPos = pos + count - 1;
+ if (lastPos >= length) {
+ grow(lastPos);
+ }
+
+ while (count > 0) {
+ byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+ int blockOffset = (int)(pos & BLOCK_MASK);
+ int toCopy = Math.min(BLOCK_SIZE - blockOffset, count);
+ System.arraycopy(buffer, offset, block, blockOffset, toCopy);
+ pos += toCopy;
+ count -= toCopy;
+ offset += toCopy;
+ }
+ }
+
+ public int getData(long pos) {
+ if (pos >= length) {
+ return -1;
+ }
+
+ byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+ return block[(int)(pos & BLOCK_MASK)] & 0xFF;
+ }
+
+ public int getData(byte[] buffer, int offset, int count, long pos) {
+ if (count > buffer.length - offset || count < 0 || offset < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (count == 0) {
+ return 0;
+ }
+ if (pos >= length) {
+ return -1;
+ }
+
+ if (count + pos > length) {
+ count = (int) (length - pos);
+ }
+
+ byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT));
+ int nbytes = Math.min(count, BLOCK_SIZE - (int)(pos & BLOCK_MASK));
+ System.arraycopy(block, (int)(pos & BLOCK_MASK), buffer, offset, nbytes);
+
+ return nbytes;
+ }
+ /*
+ public void seek(long pos) throws IOException {
+ if (pos < 0) {
+ throw new IOException("seek position is negative");
+ }
+ this.pos = pos;
+ }
+
+ public void readFully(byte[] buffer) throws IOException {
+ readFully(buffer, 0, buffer.length);
+ }
+
+ public void readFully(byte[] buffer, int offset, int count) throws IOException {
+ if (0 <= offset && offset <= buffer.length && 0 <= count && count <= buffer.length - offset) {
+ while (count > 0) {
+ int result = read(buffer, offset, count);
+ if (result >= 0) {
+ offset += result;
+ count -= result;
+ } else {
+ throw new EOFException();
+ }
+ }
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public long getFilePointer() {
+ return pos;
+ }
+*/
+
+ public void freeBefore(long pos) {
+ int blockIdx = (int)(pos >> BLOCK_SHIFT);
+ if (blockIdx <= firstUndisposed) { // Nothing to do
+ return;
+ }
+
+ for (int i = firstUndisposed; i < blockIdx; i++) {
+ blocks.set(i, null);
+ }
+
+ firstUndisposed = blockIdx;
+ }
+
+ public int appendData(InputStream is, int count) throws IOException {
+ if (count <= 0) {
+ return 0;
+ }
+
+ long startPos = length;
+ long lastPos = length + count - 1;
+ grow(lastPos); // Changes length
+
+ int blockIdx = (int)(startPos >> BLOCK_SHIFT);
+ int offset = (int) (startPos & BLOCK_MASK);
+
+ int bytesAppended = 0;
+
+ while (count > 0) {
+ byte[] block = blocks.get(blockIdx);
+ int toCopy = Math.min(BLOCK_SIZE - offset, count);
+ count -= toCopy;
+
+ while (toCopy > 0) {
+ int bytesRead = is.read(block, offset, toCopy);
+
+ if (bytesRead < 0) {
+ length -= (count - bytesAppended);
+ return bytesAppended;
+ }
+
+ toCopy -= bytesRead;
+ offset += bytesRead;
+ }
+
+ blockIdx++;
+ offset = 0;
+ }
+
+ return count;
+ }
+
+ public void getData(OutputStream os, int count, long pos) throws IOException {
+ if (pos + count > length) {
+ throw new IndexOutOfBoundsException("Argument out of cache");
+ }
+
+ int blockIdx = (int)(pos >> BLOCK_SHIFT);
+ int offset = (int) (pos & BLOCK_MASK);
+ if (blockIdx < firstUndisposed) {
+ throw new IndexOutOfBoundsException("The requested data are already disposed");
+ }
+
+ while (count > 0) {
+ byte[] block = blocks.get(blockIdx);
+ int toWrite = Math.min(BLOCK_SIZE - offset, count);
+ os.write(block, offset, toWrite);
+
+ blockIdx++;
+ offset = 0;
+ count -= toWrite;
+ }
+ }
+}
diff --git a/awt/resources/org/apache/harmony/awt/internal/nls/messages.properties b/awt/resources/org/apache/harmony/awt/internal/nls/messages.properties
new file mode 100644
index 0000000..9f647e9
--- /dev/null
+++ b/awt/resources/org/apache/harmony/awt/internal/nls/messages.properties
@@ -0,0 +1,495 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# messages for EN locale
+awt.00=FontRenderContext is null
+awt.01='{0}' parameter is null
+awt.02='{0}' parameter has zero length
+awt.03='{0}' iterator parameter is null
+awt.04='{0}' iterator parameter has zero length
+awt.05=Operation cannot be null
+awt.06=Unexpected type of the internal data buffer
+awt.07=Transfer data is not available
+awt.08=xfld parse string error: {0}
+awt.09=min range bound value is greater than max range bound
+awt.0A=Cannot use SinglePixedPackedSampleModel for bpp = {0}
+awt.0B=Wrong color model created for drawable
+awt.0C=Unknown visual class
+awt.0D=Invalid transparency
+awt.0E=Dimensions of the image should be positive
+awt.0F=Cannot open display '{0}'
+awt.10=Only 32-bit format is supported for window state operations.
+awt.11=Invalid key code
+awt.12=XTest is not supported by your X server\!
+awt.13=Cannot allocate color named '{0}'
+awt.14=Transfer data is not available
+awt.15=Can not get monitor info
+awt.16=Can not create DC for device
+awt.17=Unknown Composite type : {0}
+awt.18=Transparency is not supported
+awt.19=Illegal size of volatile image
+awt.1A=Failed to register window class {0} GetLastError returned {1}
+awt.1B=Invalid key code
+awt.1C=Failure to create JavaWindow GetLastError returned {0}
+awt.1D=Cannot get data from OLE clipboard
+awt.1E=Attempt to replace WindowProc handler
+awt.1F=Waiting for resource access thread interrupted not from unlock method
+awt.20=Can't unlock not locked resource
+awt.21=Not owner can't unlock resource
+awt.22=Not owner can't free resource
+awt.23=One thread can't store state several times in a row
+awt.24=Owner can't overwrite resource state. Lock operations may be lost
+awt.25=No state stored for current thread
+awt.26=Shutdown thread was interrupted while starting
+awt.27=Shutdown thread was interrupted while stopping
+awt.28=bad index: {0}
+awt.29=Invalid range
+awt.2A=Position not represented by view
+awt.2B=No word at {0}
+awt.2C=Invalid position: {0}
+awt.2D=Invalid direction
+awt.2E={0} not in range {1},{2}
+awt.2F=No more words
+awt.30=wrong number of elements to copy: {0}, size: {1}
+awt.31=no room to copy: {0}, size: {1}
+awt.32=String: '{0}' does not fit
+awt.33=index is out of range
+awt.34=Initial offset in the destination array is wrong: {0}
+awt.35=Wrong number of elements to copy: {0}
+awt.36=Wrong segment
+awt.37=Unknown composite type {0}
+awt.38=Property name is not defined
+awt.39=This method is not implemented for image obtained from ImageProducer
+awt.3A=Color Model is null
+awt.3B=Incorrect ImageConsumer completion status
+awt.3C=Unknown PNG color type
+awt.3D=Unknown colorspace
+awt.3E=Clone not supported
+awt.3F=Invalid baseline index
+awt.40=Wrong number of metrics\!
+awt.41=Font returned unsupported type of line metrics. This case is known, but not supported yet.
+awt.42=TextHitInfo out of range
+awt.43=glyphIndex is out of vector's limits
+awt.44=beginGlyphIndex is out of vector's range
+awt.45=numEntries is out of vector's range
+awt.46=length of setPositions array differs from the length of positions array
+awt.47=First argument should be byte or short array
+awt.48=The srcIn raster is incompatible with src ColorModel
+awt.49=The dstIn raster is incompatible with dst ColorModel
+awt.4A=The dstOut raster is incompatible with dst ColorModel
+awt.4B=Iterator out of bounds
+awt.4C=Invalid MultiRectArea in method {0}
+awt.4D=The raster is incompatible with this ColorModel
+awt.4E=Unknown native platform.
+awt.4F=Data is not available
+awt.50=Iterator is read-only
+awt.51=Component expected to be a parent
+awt.52=Time interval can't be <= 0
+awt.53=Handler can't be null
+awt.54=Key event for unfocused component
+awt.55=Double mouse enter event for component
+awt.56=Double mouse exit event for component
+awt.57=Double focus gained event for component
+awt.58=Double focus lost event for component
+awt.59=Application has run out of context thread group
+awt.5A=Default class for PrinterJob is not found
+awt.5B=No access to default class for PrinterJob
+awt.5C=Instantiation exception for PrinterJob
+awt.5D={0} is not supported
+awt.5E=pageIndex is more than book size
+awt.5F=wrong orientation
+awt.60=Width and Height mustn't be equal zero both
+awt.61=Unsupported data type: {0}
+awt.62=Wrong mask : {0}
+awt.63=Coordinates are not in bounds
+awt.64=The number of the bands in the subset is greater than the number of bands in the sample model
+awt.65=null argument
+awt.66=Invalid format
+awt.67=subclass is not derived from AWTKeyStroke
+awt.68=subclass could not be instantiated
+awt.69=columns less than zero.
+awt.6A=rows less than zero.
+awt.6B=Queue stack is empty
+awt.6C=Event queue stack is broken
+awt.6D=Point is null
+awt.6E=Color is null
+awt.6F=Index less than zero
+awt.70=MenuItem is null
+awt.71=Parent is null
+awt.72=Key event for unfocused component
+awt.73=no such item
+awt.74=Input parameters a and b should not be null
+awt.75=rows and cols cannot both be zero
+awt.76=rows and cols cannot be negative
+awt.77=default focus traversal policy cannot be null
+awt.78=invalid focus traversal key identifier
+awt.79=cannot set null focus traversal key
+awt.7A=focus traversal keys cannot map to KEY_TYPED events
+awt.7B=focus traversal keys must be unique for a Component
+awt.7C=this KeyboardFocusManager is not installed in the current thread's context
+awt.7D=Property name is null
+awt.7E=invalid hotSpot
+awt.7F=AddLayoutComponent: attempt to add null component
+awt.80=AddLayoutComponent: constraint object must be GridBagConstraints
+awt.81=AddLayoutComponent: {0}
+awt.82=RemoveLayoutComponent: attempt to remove null component
+awt.83=SetConstraints: attempt to get constraints of null component
+awt.84=SetConstraints: attempt to set null constraints
+awt.85=SetConstraints: {0}
+awt.86=MinimumLayoutSize: {0}
+awt.87=PreferredLayoutSize: {0}
+awt.88=LayoutContainer: {0}
+awt.89=LookupConstraints: attempt to get constraints of null component
+awt.8A=AdjustForGravity: attempt to use null constraints
+awt.8B=AdjustForGravity: attempt to use null rectangle
+awt.8C=AdjustForGravity: {0}
+awt.8D=REMINDER component expected after RELATIVE one
+awt.8E=component is out of grid's range
+awt.8F=Weights' overrides array is too long
+awt.90=Lengths' overrides array is too long
+awt.91=Unsupported constraints object: {0}
+awt.92=Constraints object must be String
+awt.93=cannot get component: invalid constraint: {0}
+awt.94=transform can not be null
+awt.95=Wrong start index: {0}
+awt.96=Wrong finish index: {0}
+awt.97=Wrong range length: {0}
+awt.98=Wrong count value, can not be negative: {0}
+awt.99=Wrong [start + count] is out of range: {0}
+awt.9A=Unsupported font format
+awt.9B=Can't create font - bad font data
+awt.9C=wrong value of GridBagConstraints: {0}
+awt.9D=relative grid size parameter goes after absolute grid coordinate
+awt.9E=wrong values sum of GridBagConstraints' gridwidth and gridx
+awt.9F=wrong values sum of GridBagConstraints' gridheight and gridy
+awt.100=component has RELATIVE width and height
+awt.101=position less than zero.
+awt.102=columns less than zero.
+awt.103=item is null
+awt.104=item doesn't exist in the choice menu
+awt.105=index less than zero
+awt.106=specified position is greater than the number of items
+awt.107=Color parameter outside of expected range: component {0}
+awt.108=Alpha value outside of expected range
+awt.109=Color parameter outside of expected range
+awt.10A=Priority must be a value between 0 and 1, inclusive
+awt.10B=aContainer and aComponent cannot be null
+awt.10C=aContainer is not a focus cycle root of aComponent
+awt.10D=aContainer should be focus cycle root or focus traversal policy provider
+awt.10E=focusCycleRoot cannot be null
+awt.10F=improper alignment: {0}
+awt.110=Iterator out of bounds
+awt.111=Parameter npoints is greater than array length
+awt.112=Negative number of points
+awt.113=illegal scrollbar orientation
+awt.114=Image is null
+awt.115=Anchor is null
+awt.116=Invalid value for media
+awt.117=Invalid value for orientationRequested
+awt.118=Invalid value for printerResolution
+awt.119=Invalid value for origin
+awt.11A=Invalid value for printQuality
+awt.11B=Invalid value for printerResolution[]
+awt.11C=Invalid value for color
+awt.11D=Unknown rule
+awt.11E=Wrong alpha value
+awt.11F=parent is not a component
+awt.120=origin is not a descendant of parent
+awt.121=parent must be showing on the screen
+awt.122=Does not support display mode changes
+awt.123=Unsupported display mode: {0}
+awt.124=Cannot change the modality while the dialog is visible
+awt.125=null owner window
+awt.126=Window is showing
+awt.127=Cannot change the decorations while the window is visible
+awt.128=Graphics environment is headless
+awt.129=Not a screen device
+awt.12A=illegal component position
+awt.12B=adding container to itself
+awt.12C=adding container's parent to itself
+awt.12D=adding a window to a container
+awt.12E=Unknown component event id
+awt.12F=Attempt to start nested mouse grab
+awt.130=Attempt to grab mouse in not displayable window
+awt.131=AddLayoutComponent: constraint object must be String
+awt.132=wrong parent for CardLayout
+awt.133=Negative width
+awt.134=Illegal cap
+awt.135=Illegal join
+awt.136=miterLimit less than 1.0f
+awt.137=Negative dashPhase
+awt.138=Zero dash length
+awt.139=Negative dash[{0}]
+awt.13A=All dash lengths zero
+awt.13B=offset off is out of range
+awt.13C=number of elemets len is out of range
+awt.13D=Rectangle width and height must be > 0
+awt.13E=Cannot call method from the event dispatcher thread
+awt.13F=Delay must be to 0 to 60,000ms
+awt.140=Invalid combination of button flags
+awt.141=failed to parse hotspot property for cursor:
+awt.142=Exception: class {0} {1} occurred while loading: {2}
+awt.143=illegal cursor type
+awt.144=Can be set by scrollpane only
+awt.145=illegal file dialog mode
+awt.146=illegal scrollbar display policy
+awt.147=position greater than 0
+awt.148=child is null
+awt.149=ScrollPane controls layout
+awt.14A=Can not create VolatileImage with specified capabilities
+awt.14B=Only Canvas or Window is allowed
+awt.14C=Number of buffers must be greater than one
+awt.14D=Buffer capabilities should support flipping
+awt.14E=Component should be displayable
+awt.14F=invalid focus traversal key identifier
+awt.150=no parent
+awt.151=component must be showing on the screen to determine its location
+awt.152=Invalid number of copies
+awt.153=Invalid value for maxPage
+awt.154=Invalid value for minPage
+awt.155=Invalid value for fromPage
+awt.156=Invalid value for toPage
+awt.157=Invalid value for pageRanges
+awt.158=Invalid value for destination
+awt.159=Invalid value for dialog
+awt.15A=Invalid value for defaultSelection
+awt.15B=Invalid value for multipleDocumentHandling
+awt.15C=Invalid value for attribute sides
+awt.15D=Invalid colorspace
+awt.15E=Unknown component. Must be REDCOMPONENT, GREENCOMPONENT or BLUECOMPONENT.
+awt.15F=Profile class does not comply with ICC specification
+awt.160=Color space doesn't comply with ICC specification
+awt.161=Unable to open file {0}
+awt.162=Invalid ICC Profile Data
+awt.163=Can't open color profile
+awt.164=Not a predefined color space
+awt.165=Color space doesn't comply with ICC specification
+awt.166=TRC is not a simple gamma value
+awt.167=TRC is a gamma value, not a table
+awt.168=Invalid profile class
+awt.169=Component index out of range
+awt.16A=Invalid component index: {0}
+awt.16B=Not a predefined colorspace
+awt.16C=Can't load class: {0}
+awt.16D=Can't parse MIME type: {0}
+awt.16E=Transferable has null data
+awt.16F=Can't create reader for this representation class
+awt.170=Can't create default D&D cursor: {0}
+awt.171=Attempt to start a drag while an existing drag operation is still executing
+awt.172=Drag source is null
+awt.173=One listener is already exist
+awt.174=dgl is not current listener
+awt.175=Listener mismatch
+awt.176=DropTarget cannot be added as listener to itself
+awt.177=Invalid user action
+awt.178=Invalid source action
+awt.179=Context peer is null
+awt.17A=Trigger event is null
+awt.17B=Can't init ACTION_NONE drag
+awt.17C=Image offset is null
+awt.17D=Transferable is null
+awt.17E=Component associated with the trigger event is null
+awt.17F=DragSource for the trigger event is null
+awt.180=Source actions for the DragGestureRecognizer associated with the trigger event are equal to DnDConstants.ACTION_NONE
+awt.181=Attempt to register context as its listener
+awt.182=dsl is not current listener
+awt.183=Invalid status
+awt.184=Invalid action
+awt.185=Component is null
+awt.186=DragSource is null
+awt.187=Origin is null
+awt.188=Event list is null
+awt.189=Event list is empty
+awt.18A=Context is null
+awt.18B=Invalid button value
+awt.18C=Cannot invoke null runnable
+awt.18D=Source is null
+awt.18E=Wrong event id
+awt.18F=Text must be null for CARET_POSITION_CHANGED
+awt.190=Wrong committedCharacterCount
+awt.191=Invalid keyCode for KEY_TYPED event, must be VK_UNDEFINED
+awt.192=Invalid keyChar for KEY_TYPED event, can't be CHAR_UNDEFINED
+awt.193=Listener can't be zero
+awt.194=Unknown attribute name
+awt.195=Offset is out of bounds
+awt.196=Justification impossible, layout already justified
+awt.197=Endpoints are out of range
+awt.198=Illegal alignment argument
+awt.199=Illegal range argument value: {0}
+awt.19A=start or count arguments are out of text range
+awt.19B=count argument must be positive
+awt.19C=weight must be a positive number
+awt.19D=growLeftLimit must be a positive number
+awt.19E=growRightLimit must be a positive number
+awt.19F=incorrect value for shrinkPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value
+awt.200=incorrect value for growPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value
+awt.201=shrinkLeftLimit must be a positive number
+awt.202=shrinkRightLimit must be a positive number
+awt.203=Offset limit should be greater than current position
+awt.204=Determinant is zero
+awt.205=Invalid type of Arc: {0}
+awt.206=Flatness is less then zero
+awt.207=Limit is less then zero
+awt.208=Path is null
+awt.209=Invalid winding rule value
+awt.20A=First segment should be SEG_MOVETO type
+awt.20B=unknown input method highlight state
+awt.20C=Number of Bits equals to zero
+awt.20D=The number of bits per pixel is not a power of 2 or pixels span data element boundaries
+awt.20E=Data Bit offset is not a multiple of pixel bit stride
+awt.20F=Number of bands must be only 1
+awt.210=The component value for this ColorModel is signed
+awt.211=Pixel values for this ColorModel are not conveniently representable as a single int
+awt.212=There is more than one component in this ColorModel
+awt.213=This ComponentColorModel does not support the unnormalized form
+awt.214=This Color Model doesn't support this transferType
+awt.215=transferType is not one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE
+awt.216=The components array is not large enough to hold all the color and alpha components
+awt.217=The transfer type of this ComponentColorModel is not one of the following transfer types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+awt.218=The components array is not large enough to hold all the color and alpha components
+awt.219=This transferType is not supported by this color model
+awt.21A=This ComponentColorModel does not support this transferType
+awt.21B=The length of normComponents minus normOffset is less than numComponents
+awt.21C=The number of scale factors should not be zero
+awt.21D=Number of src bands ({0}) does not match number of dst bands ({1})
+awt.21E=Number of scaling constants is not equal to the number of bands
+awt.21F=Unable to transform source
+awt.220=Source should not have IndexColorModel
+awt.221=The imageType is TYPE_BYTE_BINARY and the color map has more than 16 entries
+awt.222=The imageType is not TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED
+awt.223=The imageType is not compatible with ColorModel
+awt.224=Unknown image type
+awt.225=Property name is null
+awt.226=Both tileX and tileY are not equal to 0
+awt.227=This image type can't have alpha
+awt.228=minX or minY of this raster not equal to zero
+awt.229=Number of components in the LUT does not match the number of bands
+awt.22A=Wrong type of pixels array
+awt.22B=Length of data should not be less than width*height
+awt.22C=Unknown data type {0}
+awt.22D=This transferType ( {0} ) is not supported by this color model
+awt.22E=w or h is less than or equal to zero
+awt.22F=The product of w and h is greater than Integer.MAX_VALUE
+awt.230=dataType is not one of the supported data types
+awt.231=Number of bands must be more then 0
+awt.232=Offset should be not less than zero
+awt.233=Number of components should be positive
+awt.234=Width or Height equals zero
+awt.235=Wrong Data Buffer type : {0}
+awt.236=The bits is less than 1 or greater than 32
+awt.237=Source and destinations rasters do not have the same number of bands
+awt.238=The number of arrays in the LookupTable does not meet the restrictions
+awt.239=The space is not a TYPE_RGB space
+awt.23A=The min/max normalized component values are not 0.0/1.0
+awt.23B=The mask of the {0} component is not contiguous
+awt.23C=The mask of the alpha component is not contiguous
+awt.23D=The mask of the red component is not contiguous
+awt.23E=The mask of the green component is not contiguous
+awt.23F=The mask of the blue component is not contiguous
+awt.240=The transferType not is one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT
+awt.241=Any offset between bands is greater than the Scanline stride
+awt.242=Pixel stride is less than any offset between bands
+awt.243=Product of Pixel stride and w is greater than Scanline stride
+awt.244=Width or Height of child Raster is less than or equal to zero
+awt.245=parentX disposes outside Raster
+awt.246=parentY disposes outside Raster
+awt.247=parentX + w results in integer overflow
+awt.248=parentY + h results in integer overflow
+awt.249=childMinX + w results in integer overflow
+awt.24A=childMinY + h results in integer overflow
+awt.24B=Pixel stride must be >= 0
+awt.24C=Scanline stride must be >= 0
+awt.24D=Bank Indices length must be equal Bank Offsets length
+awt.24E=Index of {0} bank must be >= 0
+awt.24F=Unable to invert transform {0}
+awt.250=Unknown interpolation type: {0}
+awt.251=Transformed width ({0}) and height ({1}) should be greater than 0
+awt.252=Source can't be same as the destination
+awt.253=Different number of bands in source and destination
+awt.254=Number of bands in the source raster ({0}) is incompatible with the matrix [{1}x{2}]
+awt.255=Number of bands in the destination raster ({0}) is incompatible with the matrix [{1}x{2}]
+awt.256=Source raster is null
+awt.257=Source raster is equal to destination
+awt.258=Number of source bands ({0}) is not equal to number of destination bands ({1})
+awt.259=Source image is null
+awt.25A=Source equals to destination
+awt.25B=Null ColorSpace passed as a parameter
+awt.25C=Null profiles passed as a parameter
+awt.25D=Source or destination color space is not defined
+awt.25E=Incorrect number of source raster bands. Should be equal to the number of color components of source colorspace.
+awt.25F=Incorrect number of destination raster bands. Should be equal to the number of color components of destination colorspace.
+awt.260=Incompatible rasters - width or height differs
+awt.261=Destination color space is undefined
+awt.262=Destionation color space should be defined
+awt.263=Incompatible images - width or height differs
+awt.264=Size of the color map is less than 1
+awt.265=The raster argument is not compatible with this IndexColorModel
+awt.266=The number of bits in a pixel is greater than 16
+awt.267=The transferType is invalid
+awt.268=The pixel is not a primitive array of type transferType
+awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT
+awt.26A=Incorrect ImageConsumer completion status
+awt.26B=The number of bits in the pixel values is less than 1
+awt.26C=bits is null
+awt.26D=The elements in bits is less than 0
+awt.26E=The sum of the number of bits in bits is less than 1
+awt.26F=The cspace is null
+awt.270=The transparency is not a valid value
+awt.271=The number of bits in bits is less than 1
+awt.272=The length of components minus offset is less than numComponents
+awt.273=The length of normComponents minus normOffset is less than numComponents
+awt.274=componentIdx is greater than the number of components or less than zero
+awt.275=This pixel representation is not suuported by tis Color Model
+awt.276=location.x + w or location.y + h results in integer overflow
+awt.277=bankIndices or bandOffsets is null
+awt.278=dataBuffer is null
+awt.279=bands is less than 1
+awt.27A=dataBuffer has more than one bank
+awt.27B=bandOffsets is null
+awt.27C=bandMasks is null
+awt.27D=bitsPerBand or bands is not greater than zero
+awt.27E=The product of bitsPerBand and bands is greater than the number of bits held by dataType
+awt.27F=SampleModel or DataBuffer is null
+awt.280=SampleModel is null
+awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate is null
+awt.282=aRegion has width or height less than or equal to zero
+awt.283=Overflow X coordinate of Raster
+awt.284=Overflow Y coordinate of Raster
+awt.285=Width or Height of child Raster is less than or equal to zero
+awt.286=parentX disposes outside Raster
+awt.287=parentY disposes outside Raster
+awt.288=parentX + width results in integer overflow
+awt.289=parentY + height results in integer overflow
+awt.28A=childMinX + width results in integer overflow
+awt.28B=childMinY + height results in integer overflow
+awt.28C=Rect is null
+awt.28D=Length of dataArray[{0}] is less than size + offset[{1}]
+awt.28E=Length of dataArray is less than size + offset
+awt.28F=Source and destination rasters do not have the same width!
+awt.290=Source and destination rasters do not have the same height!
+awt.291=Source and destination images do not have the same width!
+awt.292=Source and destination images do not have the same height!
+awt.294=pixel is null
+awt.295=data is null
+awt.296=can't allocate memory on video card to create new display list
+awt.297=Invalid keyLocation
+awt.298=dataBuffer is too small
+
+awt.err.00=file dialog {0} error!
+awt.err.01=error: {0}
+awt.err.02=GDIPlus DrawDriverString error status = {0}
+awt.err.03=gdipDrawCompositeGlyphVector: GDIPlus DrawDriverString error status = {0}
+awt.err.04=gdipDrawCompositeGlyphVector: GDIPlus DrawDriverString error status = {0}
diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk
new file mode 100644
index 0000000..4e7d6d2
--- /dev/null
+++ b/camera/libcameraservice/Android.mk
@@ -0,0 +1,58 @@
+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 ($(BOARD_CAMERA_LIBRARIES),)
+USE_CAMERA_STUB:=true
+else
+USE_CAMERA_STUB:=false
+endif #libcamerastub
+
+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 += $(BOARD_CAMERA_LIBRARIES)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
new file mode 100644
index 0000000..ea21af8
--- /dev/null
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -0,0 +1,357 @@
+/*
+**
+** 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 <utils/Log.h>
+
+#include "CameraHardwareStub.h"
+#include <utils/threads.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "CannedJpeg.h"
+
+namespace android {
+
+CameraHardwareStub::CameraHardwareStub()
+ : mParameters(),
+ mHeap(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()
+{
+ int width, height;
+ mParameters.getPreviewSize(&width, &height);
+
+ LOGD("initHeapLocked: preview size=%dx%d", width, height);
+
+ // Note that we enforce yuv422 in setParameters().
+ int how_big = width * 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
+ mHeap = 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(mHeap, i * mPreviewFrameSize, mPreviewFrameSize);
+ }
+
+ // Recreate the fake camera to reflect the current size.
+ delete mFakeCamera;
+ mFakeCamera = new FakeCamera(width, height);
+}
+
+CameraHardwareStub::~CameraHardwareStub()
+{
+ delete mFakeCamera;
+ mFakeCamera = 0; // paranoia
+ singleton.clear();
+}
+
+sp<IMemoryHeap> CameraHardwareStub::getPreviewHeap() const
+{
+ return mHeap;
+}
+
+// ---------------------------------------------------------------------------
+
+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<MemoryHeapBase> heap = mHeap;
+
+ // this assumes the internal state of fake camera doesn't change
+ // (or is thread safe)
+ FakeCamera* fakeCamera = mFakeCamera;
+
+ sp<MemoryBase> 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> 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();
+}
+
+// ---------------------------------------------------------------------------
+
+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<MemoryHeapBase> heap = new MemoryHeapBase(w * 2 * h);
+ sp<MemoryBase> mem = new MemoryBase(heap, 0, w * 2 * h);
+ FakeCamera cam(w, h);
+ cam.getNextFrameAsYuv422((uint8_t *)heap->base());
+ if (mRawPictureCallback)
+ mRawPictureCallback(mem, mPictureCallbackCookie);
+ }
+
+ if (mJpegPictureCallback) {
+ sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
+ sp<MemoryBase> 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<String16>& 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<CameraHardwareInterface> CameraHardwareStub::singleton;
+
+sp<CameraHardwareInterface> CameraHardwareStub::createInstance()
+{
+ if (singleton != 0) {
+ sp<CameraHardwareInterface> hardware = singleton.promote();
+ if (hardware != 0) {
+ return hardware;
+ }
+ }
+ sp<CameraHardwareInterface> hardware(new CameraHardwareStub());
+ singleton = hardware;
+ return hardware;
+}
+
+extern "C" sp<CameraHardwareInterface> openCameraHardware()
+{
+ return CameraHardwareStub::createInstance();
+}
+
+}; // namespace android
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
new file mode 100644
index 0000000..5b445d3
--- /dev/null
+++ b/camera/libcameraservice/CameraHardwareStub.h
@@ -0,0 +1,115 @@
+/*
+**
+** 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 <utils/threads.h>
+#include <ui/CameraHardwareInterface.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class CameraHardwareStub : public CameraHardwareInterface {
+public:
+ virtual sp<IMemoryHeap> getPreviewHeap() const;
+
+ virtual status_t startPreview(preview_callback cb, void* user);
+ virtual void stopPreview();
+ 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<String16>& args) const;
+ virtual status_t setParameters(const CameraParameters& params);
+ virtual CameraParameters getParameters() const;
+ virtual void release();
+
+ static sp<CameraHardwareInterface> createInstance();
+
+private:
+ CameraHardwareStub();
+ virtual ~CameraHardwareStub();
+
+ static wp<CameraHardwareInterface> 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<MemoryHeapBase> mHeap;
+ sp<MemoryBase> mBuffers[kBufferCount];
+
+ FakeCamera *mFakeCamera;
+ bool mPreviewRunning;
+ int mPreviewFrameSize;
+
+ shutter_callback mShutterCallback;
+ raw_callback mRawPictureCallback;
+ jpeg_callback mJpegPictureCallback;
+ void *mPictureCallbackCookie;
+
+ // protected by mLock
+ sp<PreviewThread> 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 0000000..5784c4b
--- /dev/null
+++ b/camera/libcameraservice/CameraService.cpp
@@ -0,0 +1,757 @@
+/*
+**
+** 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 "CameraService"
+#include <utils/Log.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+#include <utils/String16.h>
+#include <utils/Errors.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapBase.h>
+#include <ui/ICameraService.h>
+
+#include "CameraService.h"
+
+namespace android {
+
+extern "C" {
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+}
+
+// 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<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient)
+{
+ LOGD("Connect E from ICameraClient %p", cameraClient->asBinder().get());
+
+ Mutex::Autolock lock(mLock);
+ if (mClient != 0) {
+ sp<Client> currentClient = mClient.promote();
+ if (currentClient != 0) {
+ sp<ICameraClient> currentCameraClient(currentClient->getCameraClient());
+ if (cameraClient->asBinder() == currentCameraClient->asBinder()) {
+ // this is the same client reconnecting...
+ LOGD("Connect X same client is reconnecting...");
+ return currentClient;
+ } else {
+ // it's another client... boot the previous one...
+ LOGD("new client connecting, booting the old one...");
+ mClient.clear();
+ }
+ } else {
+ // can't promote, the previous client has died...
+ LOGD("new client connecting, old reference was dangling...");
+ mClient.clear();
+ }
+ }
+
+ // create a new Client object
+ sp<Client> client = new Client(this, cameraClient);
+ 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<ICameraClient>& cameraClient)
+{
+ // declar this outside the lock to make absolutely sure the
+ // destructor won't be called with the lock held.
+ sp<Client> 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>& cameraService,
+ const sp<ICameraClient>& cameraClient) :
+ mCameraService(cameraService), mCameraClient(cameraClient), mHardware(0)
+{
+ LOGD("Client E constructor");
+ mHardware = openCameraHardware();
+ mHasFrameCallback = false;
+ LOGD("Client X constructor");
+}
+
+#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()
+{
+ // spin down hardware
+ LOGD("Client E destructor");
+ if (mSurface != 0) {
+#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
+ }
+
+ disconnect();
+ LOGD("Client X destructor");
+}
+
+void CameraService::Client::disconnect()
+{
+ LOGD("Client E disconnect");
+ Mutex::Autolock lock(mLock);
+ mCameraService->removeClient(mCameraClient);
+ if (mHardware != 0) {
+ // 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<ISurface>& surface)
+{
+ LOGD("setPreviewDisplay(%p)", surface.get());
+ Mutex::Autolock lock(mLock);
+ Mutex::Autolock surfaceLock(mSurfaceLock);
+ // asBinder() is safe on NULL (returns NULL)
+ if (surface->asBinder() != mSurface->asBinder()) {
+ if (mSurface != 0) {
+ LOGD("clearing old preview surface %p", mSurface.get());
+ mSurface->unregisterBuffers();
+ }
+ mSurface = surface;
+ }
+ return NO_ERROR;
+}
+
+// tell the service whether to callback with each preview frame
+void CameraService::Client::setHasFrameCallback(bool installed)
+{
+ Mutex::Autolock lock(mLock);
+ mHasFrameCallback = installed;
+ // If installed is false, mPreviewBuffer will be released in stopPreview().
+}
+
+// start preview mode, must call setPreviewDisplay first
+status_t CameraService::Client::startPreview()
+{
+ LOGD("startPreview()");
+
+ /* we cannot call into mHardware with mLock held because
+ * mHardware has callbacks onto us which acquire this lock
+ */
+
+ Mutex::Autolock lock(mLock);
+
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return INVALID_OPERATION;
+ }
+
+ if (mSurface == 0) {
+ LOGE("setPreviewDisplay must be called before startPreview!");
+ return INVALID_OPERATION;
+ }
+
+ // XXX: This needs to be improved. remove all hardcoded stuff
+
+ int w, h;
+ CameraParameters params(mHardware->getParameters());
+ params.getPreviewSize(&w, &h);
+
+ mSurface->unregisterBuffers();
+
+#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+ debug_frame_cnt = 0;
+#endif
+
+ status_t ret = mHardware->startPreview(previewCallback,
+ mCameraService.get());
+ if (ret == NO_ERROR) {
+ mSurface->registerBuffers(w,h,w,h,
+ PIXEL_FORMAT_YCbCr_420_SP,
+ mHardware->getPreviewHeap());
+ }
+ else LOGE("mHardware->startPreview() failed with status %d\n",
+ ret);
+
+ return ret;
+}
+
+// stop preview mode
+void CameraService::Client::stopPreview()
+{
+ LOGD("stopPreview()");
+
+ Mutex::Autolock lock(mLock);
+
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return;
+ }
+
+ mHardware->stopPreview();
+ LOGD("stopPreview(), hardware stopped OK");
+
+ if (mSurface != 0) {
+ mSurface->unregisterBuffers();
+ }
+ mPreviewBuffer.clear();
+}
+
+// Safely retrieves a strong pointer to the client during a hardware callback.
+sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user)
+{
+ sp<Client> client = 0;
+ CameraService *service = static_cast<CameraService*>(user);
+ if (service != NULL) {
+ Mutex::Autolock ourLock(service->mLock);
+ if (service->mClient != 0) {
+ client = service->mClient.promote();
+ if (client == 0) {
+ LOGE("getClientFromCookie: client appears to have died");
+ service->mClient.clear();
+ }
+ } else {
+ LOGE("getClientFromCookie: got callback but client was NULL");
+ }
+ }
+ return client;
+}
+
+
+#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE || \
+ DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE || \
+ DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+static void dump_to_file(const char *fname,
+ uint8_t *buf, uint32_t size)
+{
+ int nw, cnt = 0;
+ uint32_t written = 0;
+
+ LOGD("opening file [%s]\n", fname);
+ int fd = open(fname, O_RDWR | O_CREAT);
+ if (fd < 0) {
+ LOGE("failed to create file [%s]: %s", fname, strerror(errno));
+ return;
+ }
+
+ LOGD("writing %d bytes to file [%s]\n", size, fname);
+ while (written < size) {
+ nw = ::write(fd,
+ buf + written,
+ size - written);
+ if (nw < 0) {
+ LOGE("failed to write to file [%s]: %s",
+ fname, strerror(errno));
+ break;
+ }
+ written += nw;
+ cnt++;
+ }
+ LOGD("done writing %d bytes to file [%s] in %d passes\n",
+ size, fname, cnt);
+ ::close(fd);
+}
+#endif
+
+// preview callback - frame buffer update
+void CameraService::Client::previewCallback(const sp<IMemory>& mem, void* user)
+{
+ sp<Client> client = getClientFromCookie(user);
+ if (client == 0) {
+ return;
+ }
+
+#if DEBUG_HEAP_LEAKS && 0 // debugging
+ if (gWeakHeap == NULL) {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ if (gWeakHeap != heap) {
+ LOGD("SETTING PREVIEW HEAP");
+ heap->trackMe(true, true);
+ gWeakHeap = heap;
+ }
+ }
+#endif
+
+#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+ {
+ if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ dump_to_file("/data/preview.yuv",
+ (uint8_t *)heap->base() + offset, size);
+ }
+ }
+#endif
+
+ // The strong pointer guarantees the client will exist, but no lock is held.
+ client->postFrame(mem);
+
+#if DEBUG_CLIENT_REFERENCES
+ //**** if the client's refcount is 1, then we are about to destroy it here,
+ // which is bad--print all refcounts.
+ if (client->getStrongCount() == 1) {
+ LOGE("++++++++++++++++ (PREVIEW) THIS WILL CAUSE A LOCKUP!");
+ client->printRefs();
+ }
+#endif
+}
+
+// take a picture - image is returned in callback
+status_t CameraService::Client::autoFocus()
+{
+ LOGV("autoFocus");
+
+ Mutex::Autolock lock(mLock);
+
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return INVALID_OPERATION;
+ }
+
+ return mHardware->autoFocus(autoFocusCallback,
+ mCameraService.get());
+}
+
+// take a picture - image is returned in callback
+status_t CameraService::Client::takePicture()
+{
+ LOGD("takePicture");
+
+ Mutex::Autolock lock(mLock);
+
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return INVALID_OPERATION;
+ }
+
+ if (mSurface != NULL)
+ mSurface->unregisterBuffers();
+
+ return mHardware->takePicture(shutterCallback,
+ yuvPictureCallback,
+ jpegPictureCallback,
+ mCameraService.get());
+}
+
+// picture callback - snapshot taken
+void CameraService::Client::shutterCallback(void *user)
+{
+ sp<Client> client = getClientFromCookie(user);
+ if (client == 0) {
+ return;
+ }
+
+ client->postShutter();
+}
+
+// picture callback - raw image ready
+void CameraService::Client::yuvPictureCallback(const sp<IMemory>& mem,
+ void *user)
+{
+ sp<Client> client = getClientFromCookie(user);
+ if (client == 0) {
+ return;
+ }
+ if (mem == NULL) {
+ client->postRaw(NULL);
+ client->postError(UNKNOWN_ERROR);
+ return;
+ }
+
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+#if DEBUG_HEAP_LEAKS && 0 // debugging
+ gWeakHeap = heap; // debugging
+#endif
+
+ //LOGV("yuvPictureCallback(%d, %d, %p)", offset, size, user);
+#if DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE // for testing pursposes only
+ dump_to_file("/data/photo.yuv",
+ (uint8_t *)heap->base() + offset, size);
+#endif
+
+ // Put the YUV version of the snapshot in the preview display.
+ int w, h;
+ CameraParameters params(client->mHardware->getParameters());
+ params.getPictureSize(&w, &h);
+
+// Mutex::Autolock clientLock(client->mLock);
+ if (client->mSurface != 0) {
+ client->mSurface->unregisterBuffers();
+ client->mSurface->registerBuffers(w,h,w,h,
+ PIXEL_FORMAT_YCbCr_420_SP, heap);
+ client->mSurface->postBuffer(offset);
+ }
+
+ client->postRaw(mem);
+
+#if DEBUG_CLIENT_REFERENCES
+ //**** if the client's refcount is 1, then we are about to destroy it here,
+ // which is bad--print all refcounts.
+ if (client->getStrongCount() == 1) {
+ LOGE("++++++++++++++++ (RAW) THIS WILL CAUSE A LOCKUP!");
+ client->printRefs();
+ }
+#endif
+}
+
+// picture callback - jpeg ready
+void CameraService::Client::jpegPictureCallback(const sp<IMemory>& mem, void *user)
+{
+ sp<Client> client = getClientFromCookie(user);
+ if (client == 0) {
+ return;
+ }
+ if (mem == NULL) {
+ client->postJpeg(NULL);
+ client->postError(UNKNOWN_ERROR);
+ return;
+ }
+
+ /** We absolutely CANNOT call into user code with a lock held **/
+
+#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE // for testing pursposes only
+ {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ dump_to_file("/data/photo.jpg",
+ (uint8_t *)heap->base() + offset, size);
+ }
+#endif
+
+ client->postJpeg(mem);
+
+#if DEBUG_CLIENT_REFERENCES
+ //**** if the client's refcount is 1, then we are about to destroy it here,
+ // which is bad--print all refcounts.
+ if (client->getStrongCount() == 1) {
+ LOGE("++++++++++++++++ (JPEG) THIS WILL CAUSE A LOCKUP!");
+ client->printRefs();
+ }
+#endif
+}
+
+void CameraService::Client::autoFocusCallback(bool focused, void *user)
+{
+ LOGV("autoFocusCallback");
+
+ sp<Client> client = getClientFromCookie(user);
+ if (client == 0) {
+ return;
+ }
+
+ client->postAutoFocus(focused);
+
+#if DEBUG_CLIENT_REFERENCES
+ if (client->getStrongCount() == 1) {
+ LOGE("++++++++++++++++ (AUTOFOCUS) THIS WILL CAUSE A LOCKUP!");
+ client->printRefs();
+ }
+#endif
+}
+
+// set preview/capture parameters - key/value pairs
+status_t CameraService::Client::setParameters(const String8& params)
+{
+ LOGD("setParameters(%s)", params.string());
+
+ Mutex::Autolock lock(mLock);
+
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return INVALID_OPERATION;
+ }
+
+ CameraParameters p(params);
+ mHardware->setParameters(p);
+ return NO_ERROR;
+}
+
+// get preview/capture parameters - key/value pairs
+String8 CameraService::Client::getParameters() const
+{
+ LOGD("getParameters");
+
+ Mutex::Autolock lock(mLock);
+
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return String8();
+ }
+
+ return mHardware->getParameters().flatten();
+}
+
+void CameraService::Client::postAutoFocus(bool focused)
+{
+ LOGV("postAutoFocus");
+ mCameraClient->autoFocusCallback(focused);
+}
+
+void CameraService::Client::postShutter()
+{
+ mCameraClient->shutterCallback();
+}
+
+void CameraService::Client::postRaw(const sp<IMemory>& mem)
+{
+ LOGD("postRaw");
+ mCameraClient->rawCallback(mem);
+}
+
+void CameraService::Client::postJpeg(const sp<IMemory>& mem)
+{
+ LOGD("postJpeg");
+ mCameraClient->jpegCallback(mem);
+}
+
+void CameraService::Client::postFrame(const sp<IMemory>& mem)
+{
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+ sp<MemoryBase> frame;
+
+ {
+ Mutex::Autolock surfaceLock(mSurfaceLock);
+ if (mSurface != NULL)
+ mSurface->postBuffer(offset);
+ }
+
+ // It is necessary to copy out of pmem before sending this to the callback.
+ // For efficiency, reuse the same MemoryHeapBase provided it's big enough.
+ // Don't allocate the memory or perform the copy if there's no callback.
+ if (mHasFrameCallback) {
+ if (mPreviewBuffer == 0) {
+ mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+ } else if (size > mPreviewBuffer->virtualSize()) {
+ mPreviewBuffer.clear();
+ mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+ }
+ memcpy(mPreviewBuffer->base(), (uint8_t *)heap->base() + offset, size);
+ frame = new MemoryBase(mPreviewBuffer, 0, size);
+ }
+
+ // Do not hold the client lock while calling back.
+ if (frame != 0) {
+ mCameraClient->frameCallback(frame);
+ }
+}
+
+void CameraService::Client::postError(status_t error) {
+ mCameraClient->errorCallback(error);
+}
+
+status_t CameraService::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump CameraService from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ } else {
+ AutoMutex lock(&mLock);
+ if (mClient != 0) {
+ sp<Client> currentClient = mClient.promote();
+ currentClient->mHardware->dump(fd, args);
+ } else {
+ result.append("No camera client yet.\n");
+ write(fd, result.string(), result.size());
+ }
+ }
+ return NO_ERROR;
+}
+
+
+#if DEBUG_HEAP_LEAKS
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t CameraService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ // permission checks...
+ switch (code) {
+ case BnCameraService::CONNECT:
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int self_pid = getpid();
+ if (pid != self_pid) {
+ // we're called from a different process, do the real check
+ if (!checkCallingPermission(
+ String16("android.permission.CAMERA")))
+ {
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't use the camera pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ break;
+ }
+
+ status_t err = BnCameraService::onTransact(code, data, reply, flags);
+
+ LOGD("+++ onTransact err %d code %d", err, code);
+
+ if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
+ // the 'service' command interrogates this binder for its name, and then supplies it
+ // even for the debugging commands. that means we need to check for it here, using
+ // ISurfaceComposer (since we delegated the INTERFACE_TRANSACTION handling to
+ // BnSurfaceComposer before falling through to this code).
+
+ LOGD("+++ onTransact code %d", code);
+
+ CHECK_INTERFACE(ICameraService, data, reply);
+
+ switch(code) {
+ case 1000:
+ {
+ if (gWeakHeap != 0) {
+ sp<IMemoryHeap> h = gWeakHeap.promote();
+ IMemoryHeap *p = gWeakHeap.unsafe_get();
+ LOGD("CHECKING WEAK REFERENCE %p (%p)", h.get(), p);
+ if (h != 0)
+ h->printRefs();
+ bool attempt_to_delete = data.readInt32() == 1;
+ if (attempt_to_delete) {
+ // NOT SAFE!
+ LOGD("DELETING WEAK REFERENCE %p (%p)", h.get(), p);
+ if (p) delete p;
+ }
+ return NO_ERROR;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return err;
+}
+
+#endif // DEBUG_HEAP_LEAKS
+
+}; // namespace android
+
+
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
new file mode 100644
index 0000000..683c51b
--- /dev/null
+++ b/camera/libcameraservice/CameraService.h
@@ -0,0 +1,160 @@
+/*
+**
+** 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_SERVERS_CAMERA_CAMERASERVICE_H
+#define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
+
+#include <ui/ICameraService.h>
+#include <ui/CameraHardwareInterface.h>
+class android::MemoryHeapBase;
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// When enabled, this feature allows you to send an event to the CameraService
+// so that you can cause all references to the heap object gWeakHeap, defined
+// below, to be printed. You will also need to set DEBUG_REFS=1 and
+// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp. You just have to
+// set gWeakHeap to the appropriate heap you want to track.
+
+#define DEBUG_HEAP_LEAKS 0
+
+// ----------------------------------------------------------------------------
+
+class CameraService : public BnCameraService
+{
+ class Client;
+
+public:
+ static void instantiate();
+
+ // ICameraService interface
+ virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient);
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ void removeClient(const sp<ICameraClient>& cameraClient);
+
+#if DEBUG_HEAP_LEAKS
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+#endif
+
+private:
+
+// ----------------------------------------------------------------------------
+
+ class Client : public BnCamera {
+
+ public:
+ virtual void disconnect();
+
+ // pass the buffered ISurface to the camera service
+ virtual status_t setPreviewDisplay(const sp<ISurface>& surface);
+
+ // tell the service whether to callback with each preview frame
+ virtual void setHasFrameCallback(bool installed);
+
+ // start preview mode, must call setPreviewDisplay first
+ virtual status_t startPreview();
+
+ // stop preview mode
+ virtual void stopPreview();
+
+ // auto focus
+ virtual status_t autoFocus();
+
+ // take a picture - returns an IMemory (ref-counted mmap)
+ virtual status_t takePicture();
+
+ // set preview/capture parameters - key/value pairs
+ virtual status_t setParameters(const String8& params);
+
+ // get preview/capture parameters - key/value pairs
+ virtual String8 getParameters() const;
+
+ // our client...
+ const sp<ICameraClient>& getCameraClient() const { return mCameraClient; }
+
+ private:
+ friend class CameraService;
+ Client( const sp<CameraService>& cameraService,
+ const sp<ICameraClient>& cameraClient);
+ Client();
+ virtual ~Client();
+
+ static void previewCallback(const sp<IMemory>& mem, void* user);
+ static void shutterCallback(void *user);
+ static void yuvPictureCallback(const sp<IMemory>& mem, void* user);
+ static void jpegPictureCallback(const sp<IMemory>& mem, void* user);
+ static void autoFocusCallback(bool focused, void* user);
+ static sp<Client> getClientFromCookie(void* user);
+
+ void postShutter();
+ void postRaw(const sp<IMemory>& mem);
+ void postJpeg(const sp<IMemory>& mem);
+ void postFrame(const sp<IMemory>& mem);
+ void postError(status_t error);
+ void postAutoFocus(bool focused);
+
+ // Ensures atomicity among the public methods
+ mutable Mutex mLock;
+ // mSurfaceLock synchronizes access to mSurface between
+ // setPreviewSurface() and postFrame(). Note that among
+ // the public methods, all accesses to mSurface are
+ // syncrhonized by mLock. However, postFrame() is called
+ // by the CameraHardwareInterface callback, and needs to
+ // access mSurface. It cannot hold mLock, however, because
+ // stopPreview() may be holding that lock while attempting
+ // top stop preview, and stopPreview itself will block waiting
+ // for a callback from CameraHardwareInterface. If this
+ // happens, it will cause a deadlock.
+ mutable Mutex mSurfaceLock;
+ mutable Condition mReady;
+ sp<CameraService> mCameraService;
+ sp<ISurface> mSurface;
+ sp<MemoryHeapBase> mPreviewBuffer;
+ bool mHasFrameCallback;
+
+ // these are immutable once the object is created,
+ // they don't need to be protected by a lock
+ sp<ICameraClient> mCameraClient;
+ sp<CameraHardwareInterface> mHardware;
+ };
+
+// ----------------------------------------------------------------------------
+
+ CameraService();
+ virtual ~CameraService();
+
+ mutable Mutex mLock;
+ wp<Client> mClient;
+
+#if DEBUG_HEAP_LEAKS
+ wp<IMemoryHeap> gWeakHeap;
+#endif
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif
diff --git a/camera/libcameraservice/CannedJpeg.h b/camera/libcameraservice/CannedJpeg.h
new file mode 100644
index 0000000..532560a
--- /dev/null
+++ b/camera/libcameraservice/CannedJpeg.h
@@ -0,0 +1,1546 @@
+const int kCannedJpegWidth = 213;
+const int kCannedJpegHeight = 350;
+const int kCannedJpegSize = 18474;
+
+const char kCannedJpeg[] = {
+ 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
+ 0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43,
+ 0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04, 0x04, 0x05,
+ 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b,
+ 0x0b, 0x09, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f, 0x11, 0x11, 0x13,
+ 0x16, 0x1c, 0x17, 0x13, 0x14, 0x1a, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18,
+ 0x1a, 0x1d, 0x1d, 0x1f, 0x1f, 0x1f, 0x13, 0x17, 0x22, 0x24, 0x22, 0x1e,
+ 0x24, 0x1c, 0x1e, 0x1f, 0x1e, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x05, 0x05,
+ 0x05, 0x07, 0x06, 0x07, 0x0e, 0x08, 0x08, 0x0e, 0x1e, 0x14, 0x11, 0x14,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x01, 0x5e, 0x00, 0xd5, 0x03,
+ 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00,
+ 0x1c, 0x00, 0x00, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05, 0x07, 0x01, 0x03,
+ 0x04, 0x02, 0x08, 0xff, 0xc4, 0x00, 0x55, 0x10, 0x00, 0x01, 0x03, 0x04,
+ 0x00, 0x03, 0x03, 0x05, 0x0a, 0x09, 0x08, 0x09, 0x02, 0x06, 0x03, 0x00,
+ 0x01, 0x02, 0x03, 0x04, 0x00, 0x05, 0x06, 0x11, 0x07, 0x12, 0x21, 0x13,
+ 0x31, 0x41, 0x14, 0x22, 0x51, 0x61, 0x71, 0x15, 0x23, 0x32, 0x34, 0x37,
+ 0x72, 0x75, 0x81, 0xb1, 0xb3, 0x08, 0x17, 0x33, 0x42, 0x52, 0x62, 0x76,
+ 0x93, 0xb2, 0x16, 0x24, 0x43, 0x53, 0x56, 0x91, 0xa1, 0xd2, 0x25, 0x36,
+ 0x63, 0x73, 0x82, 0x92, 0xa2, 0xc1, 0xd1, 0x65, 0xf0, 0x26, 0x27, 0x64,
+ 0x66, 0x74, 0xe1, 0x83, 0xc2, 0xf1, 0xff, 0xc4, 0x00, 0x1b, 0x01, 0x01,
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff,
+ 0xc4, 0x00, 0x35, 0x11, 0x00, 0x02, 0x01, 0x03, 0x03, 0x01, 0x05, 0x05,
+ 0x07, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x11, 0x12, 0x21, 0x31, 0x41, 0x05, 0x22, 0x32, 0x51, 0x61, 0x06,
+ 0x13, 0x71, 0x81, 0xb1, 0x14, 0x33, 0x42, 0x91, 0xa1, 0xc1, 0xd1, 0x15,
+ 0x23, 0xe1, 0xf0, 0x24, 0x53, 0x92, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
+ 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xfb, 0x2e, 0x8a, 0x2b,
+ 0xca, 0x95, 0xae, 0xfe, 0xea, 0x03, 0xd5, 0x15, 0x8d, 0xfb, 0x28, 0xdf,
+ 0xb2, 0x80, 0xcd, 0x15, 0x8d, 0xfb, 0x28, 0xdf, 0xb2, 0x80, 0xcd, 0x15,
+ 0x8d, 0xfb, 0x28, 0xe6, 0xa0, 0x33, 0x45, 0x63, 0x9a, 0xb3, 0x40, 0x14,
+ 0x51, 0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x45, 0x14, 0x50, 0x05, 0x14,
+ 0x56, 0x37, 0x40, 0x66, 0x8a, 0x37, 0xd6, 0xb1, 0xbf, 0x65, 0x01, 0x9a,
+ 0x2b, 0x1b, 0xf6, 0x51, 0xbf, 0x65, 0x01, 0x9a, 0x2b, 0x1b, 0xf6, 0x51,
+ 0xbf, 0x65, 0x01, 0x9a, 0x2b, 0xc9, 0x56, 0xbb, 0xeb, 0xd0, 0xa0, 0x0a,
+ 0x2b, 0xca, 0x95, 0xa3, 0x45, 0x01, 0xea, 0x93, 0x78, 0xe1, 0xb1, 0xc1,
+ 0xec, 0xb8, 0x82, 0x41, 0xf7, 0x1e, 0x4f, 0x71, 0xd7, 0xf4, 0x66, 0x9c,
+ 0xa9, 0x37, 0x8e, 0x5f, 0x23, 0xb9, 0x77, 0xd0, 0xf2, 0x7e, 0xec, 0xd0,
+ 0x15, 0xb3, 0x5c, 0x3c, 0xc1, 0xd4, 0xd2, 0x14, 0x71, 0x7b, 0x69, 0x25,
+ 0x20, 0x9f, 0x7a, 0xaf, 0x5f, 0x8b, 0xbc, 0x1b, 0xfb, 0x2d, 0x6c, 0xfd,
+ 0xd5, 0x33, 0x31, 0xf9, 0x16, 0xfe, 0x68, 0xfb, 0x2b, 0xdd, 0x7b, 0x9a,
+ 0x23, 0xe4, 0x78, 0x9a, 0xe5, 0xe6, 0x2b, 0x7e, 0x2e, 0xf0, 0x6f, 0xec,
+ 0xb5, 0xb3, 0xf7, 0x54, 0x1e, 0x1e, 0x60, 0xc3, 0xaf, 0xf2, 0x5a, 0xd9,
+ 0xaf, 0xf7, 0x54, 0xc7, 0x36, 0x54, 0x68, 0x50, 0xde, 0x99, 0x32, 0x43,
+ 0x51, 0xa3, 0x30, 0x92, 0xb7, 0x5e, 0x75, 0x41, 0x28, 0x42, 0x40, 0xea,
+ 0x54, 0x4f, 0x40, 0x2a, 0x2e, 0xcf, 0x13, 0x28, 0xcd, 0xf9, 0x5c, 0xb3,
+ 0x07, 0xb1, 0xcc, 0x7d, 0x63, 0x7e, 0xeb, 0x49, 0x67, 0xf9, 0xd4, 0x94,
+ 0xfa, 0x63, 0x34, 0xaf, 0x80, 0x93, 0xe0, 0xe3, 0x83, 0xae, 0xf6, 0x10,
+ 0x7a, 0x1a, 0xce, 0xa4, 0xa9, 0x53, 0x59, 0x92, 0x46, 0x94, 0xe3, 0x52,
+ 0xa3, 0xc4, 0x5b, 0x17, 0x2f, 0x98, 0xdf, 0x0b, 0xec, 0xaa, 0x65, 0xa9,
+ 0xf6, 0x1b, 0x60, 0x92, 0xff, 0x00, 0x48, 0xf1, 0x19, 0x8c, 0xa7, 0xa4,
+ 0x3e, 0x7d, 0x08, 0x69, 0x00, 0xad, 0x5f, 0x50, 0xd7, 0xa7, 0x55, 0x98,
+ 0x1c, 0x28, 0x93, 0x91, 0x84, 0x2a, 0x0e, 0x09, 0x62, 0xc5, 0x20, 0xa8,
+ 0xef, 0xca, 0x6e, 0xcc, 0x87, 0xe5, 0x91, 0xae, 0xf4, 0xc7, 0x42, 0xb9,
+ 0x50, 0x7e, 0x7a, 0xf6, 0x3f, 0x46, 0xae, 0x9c, 0x33, 0x0a, 0xc7, 0x71,
+ 0x46, 0xd6, 0xbb, 0x4c, 0x1f, 0xe7, 0x6f, 0x0f, 0xe7, 0x33, 0xa4, 0x2c,
+ 0xbb, 0x2a, 0x41, 0xf4, 0xad, 0xd5, 0x79, 0xc7, 0xbb, 0xbb, 0xa2, 0x47,
+ 0x80, 0x14, 0xc5, 0xaa, 0xf3, 0xea, 0x5c, 0x6a, 0xf0, 0xa4, 0x8e, 0xfa,
+ 0x74, 0x34, 0xee, 0xdb, 0x65, 0x47, 0x8e, 0x7e, 0x0f, 0x1c, 0x37, 0xb6,
+ 0xbe, 0x26, 0x5c, 0x6d, 0xef, 0xdf, 0x26, 0xeb, 0xf2, 0x93, 0x1c, 0xe5,
+ 0x6d, 0x3e, 0x90, 0x96, 0x5b, 0xe5, 0x6c, 0x0f, 0x68, 0x27, 0xd7, 0x4c,
+ 0xbf, 0x8a, 0x2e, 0x19, 0xff, 0x00, 0x62, 0xac, 0xff, 0x00, 0xb8, 0xa7,
+ 0x8a, 0x2b, 0x9c, 0xe8, 0x12, 0x3f, 0x14, 0x7c, 0x33, 0xfe, 0xc5, 0x59,
+ 0xff, 0x00, 0x71, 0x47, 0xe2, 0x8f, 0x86, 0x7f, 0xd8, 0xab, 0x3f, 0xee,
+ 0x29, 0xde, 0x8a, 0x01, 0x09, 0xce, 0x16, 0x70, 0xad, 0xb7, 0xd0, 0xc3,
+ 0x98, 0x8d, 0x89, 0x0e, 0xb9, 0xf0, 0x10, 0xa6, 0xc0, 0x52, 0xbd, 0x83,
+ 0x7d, 0x6b, 0x77, 0xe2, 0x8f, 0x86, 0x7f, 0xd8, 0xab, 0x3f, 0xee, 0x2b,
+ 0xb6, 0xef, 0xef, 0x9c, 0x40, 0xb5, 0x23, 0xaf, 0x98, 0xca, 0xd5, 0xf6,
+ 0xd3, 0x55, 0x72, 0xdb, 0xd7, 0x75, 0x65, 0x51, 0x63, 0xc2, 0xf1, 0xfa,
+ 0x27, 0xfb, 0x90, 0x9e, 0x44, 0x8f, 0xc5, 0x1f, 0x0c, 0xff, 0x00, 0xb1,
+ 0x56, 0x7f, 0xdc, 0x51, 0xf8, 0xa3, 0xe1, 0x9f, 0xf6, 0x2a, 0xcf, 0xfb,
+ 0x8a, 0x77, 0xa2, 0xba, 0x89, 0x12, 0x3f, 0x14, 0x7c, 0x33, 0xfe, 0xc5,
+ 0x59, 0xff, 0x00, 0x71, 0x58, 0x57, 0x08, 0xb8, 0x66, 0xa4, 0x94, 0x9c,
+ 0x2a, 0xd1, 0xa2, 0x34, 0x74, 0xce, 0xa9, 0xe2, 0x8a, 0x02, 0x91, 0xbe,
+ 0x7e, 0x0e, 0x38, 0x70, 0x75, 0xd9, 0x58, 0xa9, 0x16, 0xa7, 0xd4, 0x76,
+ 0x23, 0x4c, 0x6b, 0xcb, 0xa1, 0xa8, 0xfa, 0x0a, 0x1c, 0x3c, 0xe9, 0xdf,
+ 0xea, 0xad, 0x3e, 0xca, 0x58, 0xb8, 0x61, 0x36, 0xcc, 0x68, 0x7f, 0xf1,
+ 0x8f, 0x0c, 0xe0, 0x37, 0x19, 0x3f, 0x0a, 0xeb, 0x68, 0x69, 0x52, 0xa2,
+ 0x01, 0xae, 0xf5, 0xa3, 0x5d, 0xab, 0x43, 0xd6, 0x52, 0xa4, 0x8f, 0xd2,
+ 0xf1, 0xaf, 0xa5, 0x48, 0x1b, 0xdd, 0x63, 0x42, 0xb4, 0x85, 0x47, 0x0e,
+ 0x0c, 0xe7, 0x4d, 0x4f, 0x93, 0xe7, 0xfb, 0x76, 0x11, 0xc3, 0xab, 0x94,
+ 0x26, 0xe6, 0xdb, 0xac, 0x36, 0x59, 0x91, 0x9d, 0x1b, 0x6d, 0xe6, 0x12,
+ 0x16, 0x85, 0x8f, 0x51, 0x49, 0x23, 0xff, 0x00, 0x7a, 0xae, 0x81, 0xc3,
+ 0xbc, 0x1b, 0x5f, 0xea, 0xb5, 0xb3, 0xf7, 0x54, 0xf1, 0x95, 0x70, 0xce,
+ 0xdf, 0x2a, 0x73, 0xf7, 0x8c, 0x56, 0x51, 0xc6, 0xef, 0x4e, 0x9e, 0x67,
+ 0x1c, 0x61, 0xb0, 0xa8, 0xb2, 0x95, 0xff, 0x00, 0xd4, 0x31, 0xd1, 0x2b,
+ 0xdf, 0xe9, 0x0e, 0x55, 0x8f, 0xd2, 0xf0, 0xa5, 0x58, 0xb7, 0x89, 0xd0,
+ 0xef, 0x28, 0xc7, 0xb2, 0xab, 0x7a, 0x2d, 0x17, 0x85, 0x82, 0x63, 0x94,
+ 0xb8, 0x57, 0x16, 0x78, 0x1d, 0xea, 0x8e, 0xe1, 0x1d, 0x74, 0x3a, 0x94,
+ 0x11, 0xcc, 0x91, 0xe9, 0x1e, 0x75, 0x77, 0xd2, 0xad, 0x4e, 0xa6, 0xcd,
+ 0x24, 0xce, 0x0a, 0xb4, 0x6a, 0x53, 0xdd, 0x36, 0xd1, 0xc3, 0xf8, 0xbb,
+ 0xc1, 0xbf, 0xb2, 0xd6, 0xcf, 0xdd, 0x51, 0xf8, 0xbb, 0xc1, 0xbf, 0xb2,
+ 0xd6, 0xcf, 0xdd, 0x53, 0x48, 0xee, 0xa2, 0xba, 0x74, 0x47, 0xc8, 0xe7,
+ 0xd7, 0x2f, 0x31, 0x0e, 0xf1, 0x88, 0xe3, 0x36, 0x4b, 0xc6, 0x2d, 0x3a,
+ 0xd1, 0x65, 0x87, 0x06, 0x50, 0xc9, 0x2d, 0xe8, 0xed, 0x59, 0x47, 0x2a,
+ 0xb9, 0x4b, 0xa0, 0x11, 0xbf, 0x41, 0x15, 0xf4, 0x60, 0xee, 0xaa, 0x3f,
+ 0x33, 0xf8, 0xd6, 0x2d, 0xfb, 0x4f, 0x6e, 0xfb, 0xe1, 0x57, 0x80, 0xee,
+ 0xaf, 0x36, 0xed, 0x25, 0x53, 0x63, 0xd2, 0xb5, 0x6d, 0xc3, 0x73, 0x04,
+ 0x6c, 0xf7, 0xd1, 0x59, 0xa2, 0xb9, 0x4e, 0x90, 0xa4, 0xde, 0x39, 0x7c,
+ 0x8e, 0xe5, 0xdf, 0x43, 0xc9, 0xfb, 0xb3, 0x4e, 0x54, 0x9b, 0xc7, 0x2f,
+ 0x91, 0xdc, 0xbb, 0xe8, 0x79, 0x3f, 0x76, 0x68, 0x05, 0xe6, 0x3f, 0x22,
+ 0xdf, 0xcd, 0x1f, 0x65, 0x68, 0xbb, 0xdc, 0x61, 0x5a, 0x2d, 0x92, 0x2e,
+ 0x57, 0x29, 0x08, 0x8f, 0x12, 0x3a, 0x39, 0xdd, 0x71, 0x5b, 0xd0, 0x1e,
+ 0xaf, 0x49, 0x27, 0x40, 0x01, 0xd4, 0x92, 0x05, 0x74, 0x31, 0xf9, 0x26,
+ 0xc7, 0xa5, 0x20, 0x0e, 0x9e, 0xaa, 0xe0, 0xe1, 0xed, 0xa1, 0x19, 0xbe,
+ 0x42, 0x8c, 0xba, 0x7a, 0x79, 0xf1, 0xfb, 0x5c, 0x85, 0x26, 0xc6, 0xc2,
+ 0xbe, 0x0c, 0x99, 0x08, 0x3c, 0xab, 0x98, 0xa1, 0xe2, 0x12, 0xa0, 0x52,
+ 0xd8, 0x3d, 0x3a, 0x15, 0xf7, 0x94, 0x91, 0xec, 0xd6, 0xaa, 0xa9, 0x47,
+ 0x27, 0x8f, 0x46, 0x93, 0xa9, 0x2c, 0x1d, 0x18, 0x8e, 0x17, 0x33, 0x29,
+ 0x97, 0x1f, 0x22, 0xcd, 0xa1, 0xae, 0x3c, 0x26, 0x5c, 0x4b, 0xd6, 0xcb,
+ 0x0b, 0xa3, 0xa3, 0x64, 0x1d, 0xa5, 0xf9, 0x43, 0xb9, 0x4e, 0xf8, 0x86,
+ 0xfa, 0xa5, 0xbf, 0x5a, 0xb6, 0x45, 0xb0, 0x07, 0x4a, 0x00, 0x1a, 0xe9,
+ 0xfe, 0x15, 0x9a, 0xf2, 0x25, 0x27, 0x37, 0x96, 0x7a, 0xd1, 0x82, 0x8a,
+ 0xc2, 0x0a, 0x2b, 0x92, 0xee, 0xfc, 0xa8, 0xd0, 0x1c, 0x7a, 0x1c, 0x6f,
+ 0x29, 0x79, 0x23, 0xcd, 0x6f, 0x7a, 0xdd, 0x71, 0xe3, 0xf7, 0xf8, 0x77,
+ 0x64, 0x72, 0x02, 0x59, 0x92, 0x9e, 0x8e, 0x32, 0xbe, 0x8a, 0x07, 0xfe,
+ 0xf5, 0xcd, 0x2b, 0x9a, 0x71, 0xaa, 0xa9, 0x49, 0xe1, 0xbe, 0x3d, 0x49,
+ 0xcf, 0x42, 0x5e, 0x8a, 0xd7, 0x25, 0xf6, 0x63, 0x30, 0xa7, 0x9f, 0x71,
+ 0x2d, 0xb6, 0x91, 0xb2, 0xa5, 0x1d, 0x0a, 0xae, 0xb2, 0x8c, 0xe9, 0xf7,
+ 0xd4, 0xb8, 0xd6, 0x8f, 0x7a, 0x6b, 0xb8, 0xbc, 0x7e, 0x12, 0xbd, 0x9e,
+ 0x8a, 0xe6, 0xbf, 0xed, 0x3a, 0x16, 0x30, 0xd5, 0x55, 0xef, 0xd1, 0x75,
+ 0x64, 0x4a, 0x49, 0x72, 0x3e, 0x5c, 0xae, 0xd6, 0xdb, 0x72, 0x79, 0xa6,
+ 0xcc, 0x69, 0x9f, 0x51, 0x3d, 0x7f, 0xb8, 0x75, 0xa5, 0xc9, 0x9c, 0x40,
+ 0xb4, 0xb4, 0x48, 0x61, 0x97, 0xdf, 0xf5, 0xeb, 0x42, 0xab, 0x17, 0x9d,
+ 0x75, 0xe7, 0x0b, 0x8f, 0x38, 0xa7, 0x16, 0x7b, 0xd4, 0xa3, 0xb3, 0x5e,
+ 0x2b, 0xe3, 0xae, 0x7d, 0xab, 0xb9, 0x9b, 0xfe, 0xd4, 0x54, 0x57, 0xe6,
+ 0xff, 0x00, 0xdf, 0x91, 0x93, 0xaa, 0xfa, 0x0d, 0xef, 0x66, 0x0c, 0xb9,
+ 0x93, 0xb5, 0x77, 0x30, 0x97, 0xc8, 0xdb, 0x25, 0xb0, 0x8e, 0x71, 0xbe,
+ 0xbe, 0x34, 0xc7, 0x0f, 0x88, 0x16, 0x87, 0x54, 0x03, 0xed, 0x3e, 0xc6,
+ 0xfc, 0x48, 0xd8, 0xff, 0x00, 0x0a, 0xab, 0x40, 0x24, 0x80, 0x01, 0x24,
+ 0xf7, 0x01, 0x5d, 0x73, 0x6d, 0x97, 0x08, 0x4d, 0x21, 0xd9, 0x51, 0x1d,
+ 0x65, 0x0b, 0xf8, 0x2a, 0x52, 0x7a, 0x1a, 0xe3, 0xb6, 0xed, 0xcb, 0xfa,
+ 0x5a, 0xa7, 0x1d, 0xd3, 0x79, 0x7b, 0x10, 0xa7, 0x22, 0xea, 0xb7, 0x5d,
+ 0x20, 0x5c, 0x51, 0xcf, 0x0e, 0x53, 0x6e, 0x8f, 0x40, 0x3d, 0x47, 0xd5,
+ 0x5d, 0x95, 0x41, 0x46, 0x90, 0xfc, 0x67, 0x43, 0xb1, 0xdd, 0x5b, 0x4b,
+ 0x1d, 0xca, 0x49, 0xd1, 0xab, 0x07, 0x10, 0xcd, 0xbb, 0x65, 0xa2, 0x15,
+ 0xdd, 0x41, 0x2b, 0x3d, 0x10, 0xf7, 0x70, 0x3e, 0xda, 0xfa, 0x5e, 0xcd,
+ 0xf6, 0x9a, 0x95, 0xc4, 0x95, 0x3a, 0xeb, 0x4b, 0x7d, 0x7a, 0x7f, 0x83,
+ 0x48, 0xd4, 0x4f, 0x91, 0xf2, 0x8a, 0x01, 0x04, 0x6c, 0x1d, 0x83, 0x45,
+ 0x7d, 0x41, 0xa0, 0x51, 0x45, 0x14, 0x06, 0x0a, 0x41, 0x3b, 0xa8, 0x7c,
+ 0xbf, 0x1b, 0xb3, 0xe5, 0x56, 0x47, 0xac, 0xf7, 0xa8, 0xbe, 0x51, 0x19,
+ 0xc5, 0x05, 0xa4, 0xa4, 0xf2, 0xad, 0xa7, 0x13, 0xd5, 0x2e, 0x21, 0x43,
+ 0xaa, 0x16, 0x93, 0xd4, 0x28, 0x75, 0x15, 0x33, 0x46, 0xa8, 0x0a, 0x45,
+ 0x2e, 0x5d, 0x71, 0x5b, 0xf3, 0x58, 0xae, 0x51, 0x24, 0x4a, 0x32, 0x36,
+ 0x2c, 0xf7, 0x52, 0x9e, 0x41, 0x38, 0x24, 0x6c, 0xb4, 0xe0, 0xee, 0x4b,
+ 0xe9, 0x03, 0x67, 0x5d, 0x16, 0x3c, 0xe1, 0xae, 0xa2, 0xa7, 0xa9, 0xdb,
+ 0x33, 0xc6, 0xed, 0x99, 0x56, 0x3f, 0x2a, 0xcb, 0x74, 0x6d, 0x65, 0x87,
+ 0x80, 0x28, 0x71, 0xb5, 0x72, 0xba, 0xcb, 0x89, 0xea, 0x87, 0x1b, 0x50,
+ 0xea, 0x95, 0xa4, 0x80, 0xa0, 0x7d, 0x35, 0x57, 0xe3, 0x13, 0x2e, 0x3d,
+ 0xa4, 0xeb, 0x05, 0xfb, 0x93, 0xdd, 0xcb, 0x3b, 0x81, 0x89, 0x6a, 0x42,
+ 0x42, 0x53, 0x21, 0x24, 0x73, 0x35, 0x21, 0x00, 0x77, 0x25, 0xc4, 0xec,
+ 0xeb, 0xc1, 0x41, 0x43, 0xc3, 0x55, 0xe9, 0x5a, 0xd7, 0xd5, 0xdd, 0x97,
+ 0x27, 0x9b, 0x73, 0x43, 0x4f, 0x7a, 0x3c, 0x1a, 0x73, 0x3f, 0x8d, 0x62,
+ 0xdf, 0xb4, 0xf6, 0xef, 0xbe, 0x15, 0x78, 0x0e, 0xea, 0xa3, 0xb3, 0x3f,
+ 0x8d, 0x62, 0xdf, 0xb4, 0xf6, 0xdf, 0xbe, 0x15, 0x78, 0x8e, 0xea, 0xe7,
+ 0xbc, 0xfb, 0xcf, 0x91, 0xd1, 0x69, 0xf7, 0x61, 0x45, 0x14, 0x57, 0x29,
+ 0xd4, 0x14, 0x9b, 0xc7, 0x2f, 0x91, 0xdc, 0xbb, 0xe8, 0x79, 0x3f, 0x76,
+ 0x69, 0xca, 0x93, 0x38, 0xe4, 0x7f, 0xf9, 0x3d, 0x97, 0x74, 0xdf, 0xfa,
+ 0x22, 0x4f, 0xdd, 0x9a, 0x01, 0x03, 0x28, 0x12, 0xae, 0x49, 0xb5, 0x62,
+ 0x56, 0xd7, 0x96, 0xcc, 0xdb, 0xfb, 0xbe, 0x4c, 0xa7, 0x50, 0x74, 0xa6,
+ 0x22, 0xa5, 0x1c, 0xd2, 0x1d, 0x1e, 0x82, 0x10, 0x39, 0x47, 0xeb, 0x2d,
+ 0x35, 0x74, 0x5a, 0xa0, 0x44, 0xb6, 0x5b, 0x23, 0x5b, 0x60, 0x30, 0x88,
+ 0xf1, 0x22, 0xb4, 0x96, 0x58, 0x69, 0x03, 0xcd, 0x42, 0x12, 0x34, 0x90,
+ 0x3d, 0x80, 0x0a, 0xac, 0x78, 0x51, 0x10, 0xdc, 0xf8, 0x87, 0x90, 0xdf,
+ 0x1d, 0x4f, 0x33, 0x56, 0x98, 0xac, 0x59, 0xe2, 0x1d, 0xf4, 0x0b, 0x52,
+ 0x43, 0xf2, 0x0e, 0xbd, 0x27, 0x99, 0x81, 0xbf, 0xd4, 0xab, 0x60, 0x56,
+ 0xf7, 0x35, 0x35, 0xcd, 0xfa, 0x18, 0x5b, 0x43, 0x44, 0x17, 0xa8, 0x01,
+ 0xa1, 0xaa, 0x28, 0xa2, 0xb0, 0x37, 0x0a, 0x81, 0xc8, 0xf1, 0xf8, 0xb3,
+ 0x41, 0x9a, 0xc3, 0x9e, 0x47, 0x31, 0xa1, 0xcc, 0x97, 0xd1, 0xd3, 0xbb,
+ 0xd3, 0x53, 0xd4, 0x9d, 0xc4, 0xfb, 0xb9, 0x87, 0x6d, 0x4d, 0xbd, 0x95,
+ 0x69, 0xd9, 0x3f, 0x0b, 0xd4, 0x8a, 0xf3, 0xfb, 0x52, 0x74, 0x69, 0xda,
+ 0xca, 0x75, 0x96, 0x52, 0xfa, 0xf4, 0xc1, 0x59, 0x63, 0x1b, 0x89, 0x59,
+ 0x06, 0x45, 0x73, 0xb9, 0xb4, 0x88, 0x72, 0x5f, 0x4a, 0x9b, 0x6b, 0xcd,
+ 0x25, 0x1d, 0x03, 0x84, 0x78, 0x9a, 0x84, 0xad, 0x91, 0x63, 0xbd, 0x29,
+ 0xf4, 0xb3, 0x1d, 0xa5, 0x38, 0xe2, 0xbb, 0x92, 0x91, 0xd4, 0xd7, 0xb9,
+ 0xd0, 0xa5, 0x41, 0x7b, 0xb1, 0x96, 0xc2, 0xd9, 0x5e, 0xb7, 0xa5, 0x0d,
+ 0x57, 0xe5, 0xd5, 0xaa, 0x56, 0xb8, 0x6e, 0xad, 0x4c, 0xbe, 0x99, 0xfd,
+ 0xb2, 0x73, 0xbc, 0xbd, 0xcd, 0x14, 0x51, 0x45, 0x73, 0x10, 0x74, 0x5b,
+ 0x24, 0x08, 0x97, 0x06, 0x24, 0xa9, 0x1c, 0xe1, 0xa5, 0x85, 0x14, 0xfa,
+ 0x75, 0x4e, 0x19, 0x9e, 0x59, 0x6f, 0xba, 0xd9, 0x84, 0x38, 0x8d, 0x2c,
+ 0xad, 0x6a, 0x05, 0x45, 0x69, 0xd7, 0x2e, 0xa9, 0x1e, 0x8a, 0xee, 0xb7,
+ 0xed, 0x0a, 0xd6, 0xf4, 0x67, 0x46, 0x1c, 0x4b, 0x92, 0x54, 0x9a, 0x58,
+ 0x0a, 0x28, 0x48, 0x2a, 0x3a, 0x00, 0x92, 0x7c, 0x05, 0x30, 0x59, 0xb1,
+ 0x3b, 0x9c, 0xf4, 0x87, 0x5d, 0x48, 0x8b, 0x1f, 0xbc, 0xb8, 0xef, 0x4e,
+ 0x9e, 0xca, 0xc2, 0x85, 0xb5, 0x5b, 0x89, 0x69, 0xa5, 0x16, 0xd8, 0x49,
+ 0xbe, 0x06, 0xae, 0x1a, 0xe4, 0x0a, 0x96, 0xd1, 0xb5, 0x4b, 0x5e, 0xdd,
+ 0x6c, 0x6d, 0xa5, 0x1e, 0xf5, 0x27, 0xd1, 0xed, 0xa7, 0x47, 0xdd, 0x6d,
+ 0x86, 0x56, 0xf3, 0xcb, 0x4a, 0x1b, 0x40, 0xda, 0x94, 0x4e, 0x80, 0x15,
+ 0x5d, 0xc7, 0x93, 0x8c, 0xe3, 0x0e, 0x85, 0xb0, 0xa5, 0xcf, 0x9a, 0x9e,
+ 0x9c, 0xe0, 0xf4, 0x4d, 0x4a, 0x71, 0x16, 0xe0, 0x5f, 0xc4, 0xa3, 0xbf,
+ 0x15, 0x5e, 0xf3, 0x25, 0x69, 0xe6, 0x23, 0xd1, 0xa2, 0x75, 0xff, 0x00,
+ 0xbf, 0x45, 0x7d, 0xf5, 0x8f, 0x68, 0x3b, 0x6b, 0x29, 0x46, 0xac, 0x94,
+ 0xa7, 0x4d, 0x70, 0x9e, 0x76, 0xe9, 0x96, 0x6d, 0x19, 0x61, 0x6e, 0x78,
+ 0x9f, 0xc4, 0x38, 0x4d, 0x3e, 0x5b, 0x8b, 0x0d, 0xc7, 0xd0, 0x0f, 0xc3,
+ 0x2a, 0xe5, 0x07, 0xd8, 0x2a, 0x6f, 0x1a, 0xc9, 0x60, 0x5f, 0x01, 0x43,
+ 0x04, 0xb6, 0xfa, 0x46, 0xd4, 0xd2, 0xfb, 0xf5, 0xe9, 0x1e, 0x9a, 0xa6,
+ 0x6b, 0xb2, 0xcb, 0x3d, 0xcb, 0x65, 0xd1, 0x89, 0xad, 0x13, 0xb6, 0xd5,
+ 0xb2, 0x07, 0x88, 0xf1, 0x1f, 0xdd, 0x5e, 0x0d, 0xaf, 0xb4, 0xf7, 0x4a,
+ 0xba, 0x75, 0x9a, 0x71, 0x7c, 0xac, 0x71, 0xf0, 0x28, 0xaa, 0x3c, 0xee,
+ 0x5e, 0xb4, 0x56, 0xa8, 0x8f, 0xb7, 0x2a, 0x2b, 0x52, 0x1a, 0x50, 0x53,
+ 0x6e, 0x24, 0x29, 0x24, 0x78, 0x83, 0x5b, 0x6b, 0xf4, 0x24, 0xd4, 0x96,
+ 0x51, 0xb8, 0x6b, 0xae, 0xea, 0xae, 0xe3, 0x5c, 0x1f, 0x72, 0x2e, 0x16,
+ 0x9c, 0xfa, 0x38, 0xe5, 0x4c, 0x25, 0xa6, 0x05, 0xdf, 0x47, 0x41, 0x70,
+ 0x9e, 0x58, 0x01, 0x47, 0xfd, 0xd3, 0xa5, 0x0b, 0x1e, 0x80, 0x57, 0xe9,
+ 0xab, 0x46, 0xa3, 0xb2, 0x5b, 0x4c, 0x5b, 0xf5, 0x82, 0xe1, 0x64, 0x9a,
+ 0x9e, 0x68, 0xd3, 0xe3, 0x39, 0x19, 0xdf, 0x9a, 0xb4, 0x94, 0x9d, 0x7a,
+ 0xfa, 0xd5, 0xe3, 0x2d, 0x2d, 0x34, 0x56, 0x51, 0x52, 0x4d, 0x32, 0xa0,
+ 0xcc, 0xc1, 0x12, 0xb1, 0x60, 0x7b, 0xc6, 0x4f, 0x6e, 0xfb, 0xe1, 0x57,
+ 0x80, 0xee, 0xaf, 0x9b, 0xad, 0xd3, 0xa4, 0xcf, 0xc5, 0x70, 0x57, 0x27,
+ 0x12, 0x67, 0x31, 0x92, 0x5b, 0xe2, 0x4b, 0xdf, 0x7f, 0x6e, 0xcc, 0x8e,
+ 0xc9, 0xcd, 0xfa, 0xca, 0x90, 0x4f, 0xd7, 0x5f, 0x48, 0x8e, 0xea, 0xde,
+ 0xed, 0xea, 0x9a, 0x7e, 0x86, 0x16, 0xab, 0x4c, 0x1a, 0xf5, 0x0a, 0x28,
+ 0xa2, 0xb9, 0x8e, 0x90, 0xa4, 0xde, 0x37, 0x8d, 0xf0, 0x7f, 0x2e, 0x1b,
+ 0xd7, 0xfa, 0x22, 0x47, 0xdd, 0x9a, 0x72, 0xa4, 0xee, 0x37, 0x74, 0xe1,
+ 0x06, 0x5c, 0x7d, 0x16, 0x89, 0x1f, 0x76, 0x68, 0x08, 0x8f, 0xc1, 0xcd,
+ 0x21, 0xee, 0x1b, 0x0b, 0xc7, 0x4e, 0xd2, 0xef, 0x73, 0x9b, 0x35, 0x64,
+ 0x7a, 0xe4, 0x2d, 0x09, 0xff, 0x00, 0xa1, 0x08, 0x15, 0x64, 0x55, 0x7b,
+ 0xf8, 0x37, 0xa5, 0x23, 0x81, 0xb8, 0x98, 0x1e, 0x30, 0x42, 0x8f, 0xb4,
+ 0xad, 0x44, 0xff, 0x00, 0x89, 0x35, 0x61, 0x51, 0xee, 0xf2, 0x42, 0xd8,
+ 0x28, 0xa2, 0x8a, 0x12, 0x15, 0x4e, 0xf1, 0x02, 0x62, 0xa5, 0xe4, 0xf2,
+ 0x7c, 0xe2, 0x52, 0xc9, 0xec, 0xd2, 0x3d, 0x1a, 0xab, 0x88, 0xf7, 0x55,
+ 0x17, 0x7e, 0x25, 0x57, 0xa9, 0xa4, 0xf7, 0xf6, 0xea, 0xfb, 0x6b, 0xe4,
+ 0xfd, 0xad, 0xa8, 0xe3, 0x6f, 0x08, 0x2e, 0xaf, 0xe8, 0x8c, 0xaa, 0xf0,
+ 0x76, 0xe1, 0x97, 0x76, 0x6c, 0xd7, 0x94, 0xca, 0x90, 0xd9, 0x5b, 0x65,
+ 0x25, 0x27, 0x97, 0xbc, 0x6f, 0xc6, 0xbb, 0x33, 0xdb, 0xf4, 0x5b, 0xdc,
+ 0x96, 0x3c, 0x91, 0xb5, 0x04, 0x34, 0x0f, 0x9e, 0xa1, 0xa2, 0x77, 0x4b,
+ 0x34, 0x57, 0xc7, 0xc7, 0xb4, 0x2b, 0x46, 0xd5, 0xda, 0xaf, 0x0b, 0x79,
+ 0x32, 0xd4, 0xf1, 0x80, 0xa2, 0xbd, 0xb2, 0xd3, 0xaf, 0x38, 0x1b, 0x65,
+ 0xb5, 0x38, 0xb3, 0xdc, 0x12, 0x36, 0x69, 0x9a, 0xd9, 0x87, 0x48, 0x53,
+ 0x42, 0x4d, 0xd9, 0xf4, 0x41, 0x8e, 0x3a, 0x9e, 0x63, 0xe7, 0x1a, 0xce,
+ 0xda, 0xce, 0xb5, 0xcb, 0xc5, 0x28, 0xe7, 0xe9, 0xf3, 0x61, 0x26, 0xc5,
+ 0x74, 0x21, 0x6e, 0x28, 0x25, 0x09, 0x2a, 0x51, 0xee, 0x00, 0x6e, 0x99,
+ 0x2d, 0x18, 0x7c, 0xf9, 0x2d, 0x89, 0x13, 0x54, 0x98, 0x51, 0xfb, 0xca,
+ 0x9c, 0x3a, 0x3a, 0xf6, 0x54, 0x83, 0x97, 0xcb, 0x05, 0x89, 0x05, 0xab,
+ 0x2c, 0x31, 0x25, 0xf1, 0xd0, 0xbe, 0xe0, 0xe9, 0x4b, 0x77, 0x7b, 0xdd,
+ 0xca, 0xe8, 0xe1, 0x54, 0xb9, 0x2b, 0x52, 0x7c, 0x10, 0x0e, 0x92, 0x3e,
+ 0xaa, 0xed, 0xf7, 0x36, 0x76, 0xbf, 0x7b, 0x2f, 0x79, 0x2f, 0x28, 0xf1,
+ 0xf3, 0x7d, 0x7e, 0x44, 0xe1, 0x21, 0x94, 0xdc, 0x71, 0x9c, 0x78, 0x72,
+ 0xdb, 0xd8, 0xf7, 0x42, 0x58, 0xfe, 0x95, 0x7f, 0x04, 0x1a, 0x5f, 0xbc,
+ 0xe4, 0x57, 0x4b, 0xa2, 0x88, 0x7e, 0x41, 0x43, 0x5e, 0x0d, 0xa3, 0xa2,
+ 0x45, 0x44, 0xd1, 0x58, 0x57, 0xed, 0x2a, 0xd5, 0x63, 0xee, 0xe3, 0xdd,
+ 0x8f, 0x92, 0xd9, 0x7c, 0xfc, 0xfe, 0x64, 0x39, 0x36, 0x14, 0xed, 0x87,
+ 0x38, 0x8b, 0xd6, 0x39, 0x37, 0x1d, 0x7d, 0x43, 0xb4, 0x4a, 0x7b, 0x48,
+ 0xe4, 0xf8, 0x1f, 0xff, 0x00, 0xdf, 0xfb, 0xd2, 0x4d, 0x77, 0x58, 0x2e,
+ 0x0e, 0x5b, 0x2e, 0xcc, 0x4c, 0x6c, 0xfc, 0x05, 0x79, 0xc3, 0xd2, 0x3c,
+ 0x45, 0x57, 0xb3, 0xae, 0x55, 0xbd, 0x74, 0xe7, 0xe1, 0x7b, 0x3f, 0x83,
+ 0xe4, 0x45, 0xe1, 0x9c, 0x6e, 0xb6, 0xb6, 0x9d, 0x5b, 0x4e, 0x24, 0xa5,
+ 0x68, 0x51, 0x4a, 0x81, 0xf0, 0x23, 0xbc, 0x57, 0x9a, 0x6a, 0xe2, 0x35,
+ 0xbd, 0xb6, 0xae, 0x0d, 0x5d, 0x62, 0xf5, 0x8d, 0x39, 0x21, 0x7b, 0x1e,
+ 0x0a, 0xd7, 0xfd, 0xc7, 0xfd, 0xe9, 0x56, 0xb2, 0xbc, 0xb6, 0x76, 0xd5,
+ 0xa5, 0x49, 0xf4, 0xfd, 0x57, 0x47, 0xf9, 0x06, 0xb0, 0xf0, 0x59, 0x7c,
+ 0x2b, 0xbb, 0x76, 0xf0, 0x1c, 0xb5, 0xba, 0xad, 0xad, 0x8f, 0x39, 0xbd,
+ 0xf8, 0xa4, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xda, 0x9d, 0xaa, 0x8e, 0xc7,
+ 0x2e, 0x4b, 0xb5, 0x5e, 0x18, 0x98, 0x92, 0x79, 0x52, 0xad, 0x2c, 0x7a,
+ 0x52, 0x7b, 0xea, 0xee, 0x65, 0xc4, 0x3c, 0xca, 0x1d, 0x6c, 0x85, 0x21,
+ 0x60, 0x10, 0x47, 0x88, 0xaf, 0xbe, 0xf6, 0x6a, 0xfb, 0xed, 0x16, 0xbe,
+ 0xea, 0x4f, 0xbd, 0x0d, 0xbe, 0x5d, 0x3f, 0x83, 0x6a, 0x72, 0xca, 0x3d,
+ 0xd6, 0x08, 0xeb, 0x59, 0xa3, 0x55, 0xf4, 0x66, 0x87, 0xce, 0x37, 0x58,
+ 0xc2, 0xdb, 0x9b, 0xcf, 0xb5, 0x05, 0xf3, 0x06, 0xf8, 0x8b, 0x6f, 0x96,
+ 0x9f, 0x52, 0x64, 0x86, 0x5e, 0x3f, 0xf5, 0x29, 0x75, 0xf4, 0x70, 0xee,
+ 0xaf, 0x9e, 0x33, 0x51, 0xae, 0x33, 0xdc, 0xff, 0x00, 0x6a, 0x71, 0xd3,
+ 0xf5, 0xf2, 0x01, 0xff, 0x00, 0x8a, 0xfa, 0x1c, 0x77, 0x56, 0x93, 0x79,
+ 0xc7, 0xc0, 0xce, 0x1c, 0xbf, 0x8f, 0xf0, 0x14, 0x51, 0x45, 0x66, 0x68,
+ 0x14, 0x9b, 0xc6, 0xf3, 0xae, 0x10, 0x65, 0xa7, 0xff, 0x00, 0x48, 0x91,
+ 0xf7, 0x66, 0x9c, 0xa9, 0x33, 0x8e, 0x5f, 0x23, 0xb9, 0x77, 0xd0, 0xf2,
+ 0x7e, 0xec, 0xd0, 0x11, 0x9f, 0x83, 0x79, 0x2d, 0xf0, 0x82, 0xd5, 0x05,
+ 0x67, 0xdf, 0x60, 0x3f, 0x2e, 0x1b, 0xa0, 0xf7, 0x82, 0xdc, 0x97, 0x53,
+ 0xaf, 0xee, 0x03, 0xfb, 0xea, 0xc6, 0xaa, 0xb7, 0x82, 0xb2, 0xbc, 0x87,
+ 0x22, 0xcb, 0x31, 0xb7, 0x34, 0x92, 0x64, 0xb5, 0x78, 0x8f, 0xb3, 0xf0,
+ 0x9b, 0x90, 0xd8, 0x4a, 0xf4, 0x3d, 0x01, 0xd6, 0x9c, 0xff, 0x00, 0x98,
+ 0x7a, 0x6a, 0xd2, 0x1d, 0xd5, 0x69, 0xad, 0x32, 0x68, 0xac, 0x25, 0xaa,
+ 0x29, 0x85, 0x14, 0x51, 0x55, 0x2c, 0x15, 0x4a, 0xe6, 0x71, 0x8c, 0x4c,
+ 0x9a, 0x6b, 0x44, 0x10, 0x0b, 0x9c, 0xc3, 0xd8, 0x7a, 0xd5, 0xd5, 0x4a,
+ 0xd9, 0x8d, 0x86, 0xd7, 0x26, 0x4a, 0x6e, 0xd7, 0x17, 0xd4, 0xcb, 0x4d,
+ 0x23, 0x95, 0xce, 0x51, 0xf0, 0xbd, 0x15, 0xe0, 0xfb, 0x43, 0x61, 0x2b,
+ 0xcb, 0x65, 0xa3, 0x98, 0xbc, 0xef, 0xb6, 0xdd, 0x4a, 0x4e, 0x39, 0x45,
+ 0x59, 0x16, 0x34, 0x89, 0x4e, 0x86, 0xa3, 0xb2, 0xb7, 0x56, 0x7b, 0x82,
+ 0x46, 0xe9, 0xa6, 0x06, 0x1e, 0x19, 0x68, 0x4a, 0xbe, 0xcb, 0x6e, 0x1b,
+ 0x3d, 0xfc, 0x9b, 0xf3, 0x8d, 0x7b, 0x97, 0x96, 0x43, 0xb7, 0xb4, 0x63,
+ 0x63, 0xd0, 0x50, 0xca, 0x7b, 0xbb, 0x65, 0x8f, 0x38, 0xfa, 0xe9, 0x5a,
+ 0x7c, 0xe9, 0x73, 0x9e, 0x2e, 0xcb, 0x90, 0xb7, 0x54, 0x7f, 0x48, 0xd7,
+ 0xc5, 0x62, 0xca, 0xd7, 0x9f, 0xee, 0xcb, 0xf2, 0x8f, 0xf2, 0xcc, 0x76,
+ 0x43, 0x5b, 0xf9, 0x2d, 0xa6, 0xd0, 0xd9, 0x63, 0x1f, 0x82, 0x92, 0xbe,
+ 0xe2, 0xfb, 0x83, 0xad, 0x2c, 0x5c, 0xee, 0x93, 0xee, 0x4e, 0x97, 0x26,
+ 0x49, 0x5b, 0x87, 0xd1, 0xbe, 0x83, 0xea, 0xae, 0x3a, 0x2b, 0x9a, 0xe7,
+ 0xb4, 0x2b, 0xdc, 0x2d, 0x2d, 0xe2, 0x3e, 0x4b, 0x65, 0xf9, 0x10, 0xe4,
+ 0xd8, 0x51, 0x45, 0x15, 0xc2, 0x40, 0x51, 0x45, 0x14, 0x01, 0x45, 0x14,
+ 0x50, 0x0f, 0x18, 0xe2, 0x86, 0x41, 0x88, 0xca, 0xb2, 0x38, 0x41, 0x93,
+ 0x18, 0x76, 0x91, 0xc9, 0xff, 0x00, 0x0f, 0xfc, 0x7d, 0x74, 0x8e, 0xa0,
+ 0x52, 0xa2, 0x95, 0x02, 0x08, 0x3a, 0x20, 0xf8, 0x54, 0x9e, 0x2f, 0x73,
+ 0x55, 0xaa, 0xf4, 0xc4, 0xa0, 0x4f, 0x20, 0x57, 0x2b, 0x83, 0xd2, 0x93,
+ 0xdf, 0x52, 0x5c, 0x42, 0xb6, 0x26, 0x1d, 0xe0, 0x4c, 0x8e, 0x37, 0x1a,
+ 0x6a, 0x7b, 0x54, 0x11, 0xdd, 0xbf, 0x1f, 0xfc, 0xfd, 0x75, 0xec, 0x57,
+ 0xff, 0x00, 0x95, 0x67, 0x1a, 0xdf, 0x8a, 0x9f, 0x75, 0xfc, 0x3f, 0x0b,
+ 0xfd, 0xbf, 0x22, 0xcf, 0x75, 0x91, 0x6a, 0xad, 0x2e, 0x18, 0x5d, 0xbc,
+ 0xb2, 0xd0, 0x60, 0x3a, 0xad, 0xbb, 0x17, 0xa2, 0x77, 0xe2, 0x83, 0xdd,
+ 0xfd, 0xdd, 0xd5, 0x56, 0xd4, 0xc6, 0x19, 0x71, 0x5d, 0xb7, 0x21, 0x8c,
+ 0xea, 0x49, 0xe4, 0x71, 0x41, 0xb7, 0x07, 0xa4, 0x13, 0xaf, 0xfc, 0x1a,
+ 0xaf, 0x62, 0xde, 0xbb, 0x3b, 0xb8, 0xc9, 0xf0, 0xf6, 0x7f, 0x07, 0xfc,
+ 0x08, 0x3c, 0x32, 0xe9, 0xac, 0x13, 0xaa, 0xcd, 0x68, 0x9b, 0x25, 0x98,
+ 0x91, 0x9e, 0x95, 0x25, 0xc4, 0xb4, 0xc3, 0x2d, 0xa9, 0xc7, 0x16, 0xa3,
+ 0xa0, 0x94, 0xa4, 0x6c, 0x93, 0xec, 0x15, 0xfa, 0xa1, 0xd2, 0x7c, 0xf9,
+ 0x92, 0x3c, 0xdc, 0xde, 0x27, 0x5c, 0xee, 0x0c, 0xab, 0x99, 0x07, 0x3b,
+ 0xb3, 0xc3, 0xdf, 0xeb, 0x32, 0xdb, 0x01, 0x5f, 0xf5, 0x28, 0xd7, 0xd1,
+ 0x43, 0xba, 0xbe, 0x69, 0xb3, 0xa1, 0xd7, 0x71, 0xfc, 0x56, 0xef, 0x25,
+ 0xb2, 0xdc, 0x9b, 0xde, 0x63, 0x16, 0xec, 0xf2, 0x7d, 0x06, 0x44, 0xa2,
+ 0xb4, 0x8f, 0xa9, 0x05, 0x03, 0xea, 0xaf, 0xa5, 0x85, 0x6b, 0x56, 0x3a,
+ 0x70, 0xbd, 0x0c, 0x68, 0xcb, 0x56, 0x5f, 0xa8, 0x51, 0x45, 0x15, 0x91,
+ 0xb0, 0x52, 0x67, 0x1c, 0xbe, 0x47, 0x72, 0xef, 0xa1, 0xe4, 0xfd, 0xd9,
+ 0xa7, 0x3a, 0x4c, 0xe3, 0x91, 0xd7, 0x07, 0x72, 0xfd, 0xf7, 0x7b, 0x91,
+ 0x27, 0xee, 0xcd, 0x00, 0x83, 0x74, 0x98, 0x31, 0x9c, 0x8e, 0xc3, 0x9a,
+ 0x95, 0x72, 0x44, 0x86, 0x0c, 0x1b, 0xa9, 0x1e, 0x10, 0xde, 0x29, 0xf7,
+ 0xc5, 0x78, 0xe9, 0xb7, 0x03, 0x6b, 0xf9, 0xbc, 0xf5, 0x78, 0xa7, 0xb8,
+ 0x55, 0x65, 0x1a, 0xd0, 0xf5, 0xde, 0x12, 0xa2, 0x18, 0x7e, 0x53, 0x1d,
+ 0xe6, 0xbb, 0x37, 0x50, 0xe0, 0xd2, 0x16, 0x92, 0x34, 0x52, 0x49, 0xf0,
+ 0x20, 0x91, 0x5d, 0x5c, 0x36, 0x9f, 0x37, 0x19, 0x9c, 0x9e, 0x1c, 0xe4,
+ 0x6f, 0xf3, 0xbf, 0x19, 0x92, 0xbb, 0x1c, 0xc5, 0x9d, 0xf9, 0x7c, 0x34,
+ 0xfe, 0x66, 0xfc, 0x5e, 0x6b, 0xa2, 0x54, 0x3b, 0xca, 0x79, 0x55, 0xd7,
+ 0x6a, 0xd7, 0x5d, 0xdc, 0x62, 0xa5, 0x94, 0xce, 0x4b, 0x49, 0x4b, 0x4e,
+ 0x1a, 0xe0, 0xb0, 0xea, 0x37, 0x23, 0xbb, 0xb3, 0x65, 0xb6, 0x2e, 0x63,
+ 0xc3, 0x98, 0x8e, 0x88, 0x46, 0xf5, 0xcc, 0xaf, 0x45, 0x49, 0x0a, 0x4a,
+ 0xe2, 0xd3, 0x2e, 0xae, 0xd5, 0x15, 0xd4, 0x6c, 0xa1, 0x0e, 0x9e, 0x7d,
+ 0x7a, 0xc7, 0x4a, 0xf1, 0xbb, 0x4e, 0xe2, 0x76, 0xf6, 0x93, 0xab, 0x4f,
+ 0x94, 0x8e, 0xa9, 0x3c, 0x21, 0x5a, 0x5e, 0x69, 0x7e, 0x7d, 0xf2, 0xe2,
+ 0x25, 0x06, 0x53, 0xbe, 0x88, 0x42, 0x46, 0xa9, 0x8b, 0x1b, 0xc8, 0x7f,
+ 0x94, 0x71, 0x9e, 0xb2, 0x5d, 0x12, 0x8e, 0xd9, 0xc6, 0xc8, 0x42, 0xc0,
+ 0xd0, 0x57, 0xff, 0x00, 0xba, 0xae, 0xab, 0x7d, 0xbe, 0x53, 0x90, 0xa6,
+ 0xb3, 0x2d, 0xa3, 0xa5, 0xb4, 0xb0, 0xa1, 0x5f, 0x9d, 0x5a, 0xf6, 0xc5,
+ 0xcd, 0x3a, 0xba, 0xaa, 0xcd, 0xca, 0x2f, 0x94, 0xf7, 0xca, 0xea, 0x73,
+ 0xa9, 0xbc, 0xee, 0x17, 0x08, 0xae, 0x42, 0x9a, 0xf4, 0x57, 0x46, 0x96,
+ 0xd2, 0x8a, 0x4d, 0x68, 0xa7, 0x1e, 0x20, 0x45, 0x6e, 0x5c, 0x78, 0x99,
+ 0x04, 0x50, 0x0b, 0x72, 0x10, 0x03, 0x9a, 0xf0, 0x55, 0x27, 0x57, 0x25,
+ 0xf5, 0xb7, 0xd9, 0xab, 0xca, 0x9a, 0xe3, 0x95, 0xea, 0x9f, 0x04, 0x49,
+ 0x61, 0x85, 0x14, 0x51, 0x5c, 0x64, 0x05, 0x14, 0x51, 0x40, 0x14, 0x51,
+ 0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x4f, 0x56, 0x84, 0xff, 0x00, 0x29,
+ 0xf0, 0xb7, 0x2d, 0xa4, 0x83, 0x36, 0x11, 0xe6, 0x64, 0x9e, 0xf2, 0x3c,
+ 0x07, 0xda, 0x3e, 0xb1, 0x48, 0xb5, 0x33, 0x86, 0xdd, 0x0d, 0xa6, 0xfa,
+ 0xcb, 0xe4, 0x9e, 0xc9, 0x67, 0x91, 0xc1, 0xea, 0x35, 0xe9, 0x76, 0x65,
+ 0x78, 0x52, 0xad, 0xa2, 0xa7, 0x82, 0x7d, 0xd7, 0xf0, 0x7d, 0x7e, 0x5c,
+ 0x96, 0x8b, 0xc3, 0x22, 0xa4, 0xc7, 0x7a, 0x33, 0xca, 0x65, 0xf6, 0x94,
+ 0xdb, 0x89, 0x3a, 0x29, 0x50, 0xd5, 0x32, 0xf0, 0xff, 0x00, 0x1f, 0x7e,
+ 0xe3, 0x74, 0x6e, 0x6b, 0xc8, 0x28, 0x89, 0x1d, 0x41, 0x44, 0x91, 0xf0,
+ 0xd4, 0x3b, 0x92, 0x3f, 0xef, 0x56, 0x83, 0xd0, 0xe1, 0x4a, 0xe5, 0x71,
+ 0xd8, 0xcc, 0xbb, 0xe2, 0x14, 0xa4, 0x03, 0x5b, 0x9b, 0x42, 0x1b, 0x40,
+ 0x43, 0x68, 0x4a, 0x12, 0x3b, 0x82, 0x46, 0x80, 0xaf, 0xab, 0xb4, 0xf6,
+ 0x5a, 0x14, 0xab, 0xaa, 0x93, 0x9e, 0xa8, 0xad, 0xd2, 0xc7, 0xd4, 0xd1,
+ 0x53, 0xc3, 0x3d, 0x55, 0x75, 0xc7, 0x7b, 0x82, 0xd7, 0x8e, 0x47, 0xc4,
+ 0x22, 0x3a, 0x51, 0x37, 0x25, 0x7b, 0xc8, 0xc9, 0x49, 0xf3, 0x9b, 0x88,
+ 0x00, 0x54, 0xa7, 0x3d, 0x81, 0xbd, 0xa3, 0xda, 0xe2, 0x69, 0xea, 0xf1,
+ 0x72, 0x83, 0x67, 0xb5, 0xca, 0xba, 0x5c, 0xa5, 0x37, 0x16, 0x14, 0x46,
+ 0x94, 0xf3, 0xef, 0x38, 0x74, 0x94, 0x21, 0x23, 0x64, 0x93, 0x54, 0xed,
+ 0x95, 0xc9, 0xb9, 0x0d, 0xfe, 0x6e, 0x6f, 0x75, 0x8c, 0xe4, 0x77, 0xa6,
+ 0xb6, 0x23, 0xdb, 0x62, 0x3a, 0x34, 0xb8, 0x70, 0x41, 0xda, 0x42, 0xc7,
+ 0x83, 0x8e, 0x1f, 0x3d, 0x43, 0xbc, 0x6d, 0x29, 0xfc, 0xda, 0xfb, 0x3a,
+ 0x14, 0x9d, 0x49, 0xe0, 0x8a, 0xd5, 0x55, 0x38, 0xe7, 0xa9, 0xa7, 0x2e,
+ 0x43, 0x6d, 0x3d, 0x8a, 0xb4, 0xd2, 0x02, 0x1b, 0x4e, 0x4b, 0x6d, 0x4a,
+ 0x52, 0x06, 0x82, 0x40, 0x78, 0x68, 0x0f, 0x65, 0x5e, 0x63, 0xba, 0xa8,
+ 0xec, 0xcb, 0xe3, 0x38, 0xb7, 0x7f, 0xfa, 0xcf, 0x6e, 0xfb, 0xe1, 0x57,
+ 0x88, 0xee, 0xad, 0x2f, 0x3e, 0xf3, 0xe4, 0x67, 0x67, 0xf7, 0x61, 0x45,
+ 0x14, 0x57, 0x29, 0xd4, 0x14, 0x99, 0xc7, 0x1f, 0x91, 0xec, 0xb7, 0xe8,
+ 0x89, 0x1f, 0xc0, 0x69, 0xce, 0x93, 0x38, 0xe3, 0xf2, 0x3d, 0x97, 0x7d,
+ 0x11, 0x23, 0xf8, 0x0d, 0x00, 0xdb, 0x11, 0x09, 0x4c, 0x56, 0x92, 0x90,
+ 0x00, 0x09, 0x1d, 0x00, 0xa8, 0x5c, 0xe7, 0x17, 0x81, 0x95, 0xd9, 0xc4,
+ 0x09, 0x6b, 0x76, 0x3b, 0xec, 0xb8, 0x99, 0x10, 0x66, 0xb2, 0x74, 0xf4,
+ 0x39, 0x09, 0xf8, 0x0e, 0xb6, 0x7f, 0x48, 0x1f, 0x0e, 0xe2, 0x36, 0x08,
+ 0x20, 0x9a, 0x9c, 0x8d, 0xf1, 0x76, 0xfe, 0x60, 0xfb, 0x2b, 0x61, 0x1b,
+ 0xa0, 0x11, 0xf1, 0x3c, 0xb6, 0x74, 0x7b, 0xab, 0x78, 0x96, 0x6c, 0xdb,
+ 0x30, 0xaf, 0xda, 0x3e, 0x47, 0x29, 0x03, 0x96, 0x35, 0xd9, 0x03, 0xf3,
+ 0xd9, 0x27, 0xb9, 0xc0, 0x3a, 0xa9, 0xa3, 0xe7, 0x0e, 0xa4, 0x6d, 0x3d,
+ 0x69, 0xbe, 0xe1, 0x12, 0x3d, 0xc2, 0x13, 0x91, 0x24, 0xa0, 0x2d, 0xa7,
+ 0x06, 0x88, 0xae, 0x3c, 0x9b, 0x1f, 0xb3, 0xe4, 0x96, 0x87, 0x2d, 0x57,
+ 0xb8, 0x2d, 0xcc, 0x88, 0xb2, 0x15, 0xc8, 0xad, 0x82, 0x85, 0x0e, 0xe5,
+ 0xa1, 0x43, 0xaa, 0x14, 0x3b, 0xc2, 0x92, 0x41, 0x07, 0xba, 0x93, 0xfb,
+ 0x4c, 0xd7, 0x05, 0x46, 0x9f, 0x4c, 0xbc, 0xd3, 0x1e, 0x47, 0x73, 0xad,
+ 0x80, 0x6e, 0xb1, 0x13, 0xd7, 0xe1, 0x27, 0xa2, 0x64, 0xa4, 0x00, 0x3a,
+ 0x8e, 0x57, 0x3d, 0x4b, 0x3d, 0x4d, 0x65, 0x15, 0x24, 0xe3, 0x25, 0x94,
+ 0xc1, 0x1d, 0x91, 0xe1, 0x17, 0x1b, 0x79, 0x53, 0xf0, 0x42, 0xa6, 0xc6,
+ 0xef, 0xf3, 0x47, 0xbe, 0x27, 0xda, 0x3c, 0x7d, 0xa2, 0x95, 0x08, 0x20,
+ 0x90, 0x41, 0x04, 0x74, 0x20, 0xd5, 0xd1, 0x8a, 0xe4, 0xf6, 0x2c, 0xa2,
+ 0x07, 0x97, 0x58, 0xae, 0x6c, 0x4d, 0x69, 0x27, 0x95, 0xc0, 0x82, 0x43,
+ 0x8c, 0xab, 0xf4, 0x5c, 0x41, 0xd2, 0x90, 0xaf, 0xd5, 0x50, 0x07, 0xd5,
+ 0x5e, 0xaf, 0x58, 0xed, 0xa2, 0xef, 0xb5, 0x4a, 0x8a, 0x90, 0xef, 0xf5,
+ 0xad, 0xf9, 0xab, 0xfe, 0xf1, 0xdf, 0xf5, 0xee, 0xbe, 0x46, 0xff, 0x00,
+ 0xd9, 0x58, 0xcd, 0xb9, 0xda, 0xcb, 0x1e, 0x8f, 0x8f, 0x93, 0x32, 0x95,
+ 0x3f, 0x21, 0x27, 0x06, 0x7d, 0xbb, 0xa5, 0xa2, 0x66, 0x3b, 0x24, 0xef,
+ 0x99, 0x25, 0x6c, 0x6f, 0xc0, 0xd2, 0x7c, 0xa6, 0x1c, 0x8d, 0x25, 0xc6,
+ 0x1d, 0x1a, 0x5b, 0x6a, 0x29, 0x22, 0xac, 0x04, 0x61, 0x13, 0xad, 0x77,
+ 0x26, 0x67, 0xda, 0x26, 0xa1, 0xde, 0xc9, 0x7b, 0xec, 0xdd, 0x1c, 0xaa,
+ 0x23, 0xc4, 0x6c, 0x74, 0x3f, 0xe1, 0x5c, 0x5c, 0x48, 0xb1, 0xc9, 0xf2,
+ 0xe4, 0x5c, 0xe3, 0x45, 0x71, 0x49, 0x79, 0x3e, 0xfc, 0x10, 0x92, 0xae,
+ 0x55, 0x7a, 0xf5, 0x5e, 0x55, 0xef, 0x67, 0x5c, 0xfd, 0x8d, 0x3a, 0xb0,
+ 0x7a, 0xa9, 0xed, 0xe7, 0x98, 0xbe, 0x38, 0xf2, 0x7f, 0xa1, 0x57, 0x17,
+ 0x8d, 0xc4, 0x8a, 0x28, 0x20, 0x82, 0x41, 0x04, 0x11, 0xe0, 0x68, 0xaf,
+ 0x9a, 0x33, 0x0a, 0x28, 0xa2, 0x80, 0x28, 0xa2, 0xbd, 0x34, 0xd3, 0x8f,
+ 0x2c, 0x21, 0xa6, 0xd6, 0xe2, 0x8f, 0x72, 0x52, 0x9d, 0x9a, 0x94, 0x9b,
+ 0xd9, 0x03, 0xcd, 0x15, 0x39, 0x6f, 0xc4, 0xaf, 0xf3, 0x48, 0x29, 0x80,
+ 0xb6, 0x50, 0x7f, 0x39, 0xff, 0x00, 0x33, 0x5f, 0x51, 0xeb, 0xfe, 0x14,
+ 0xd3, 0x69, 0xe1, 0xdb, 0x28, 0x21, 0x77, 0x49, 0xa5, 0xc3, 0xe2, 0xdb,
+ 0x03, 0x43, 0xfe, 0x63, 0xd4, 0xff, 0x00, 0x70, 0xaf, 0x4e, 0xdb, 0xb1,
+ 0xaf, 0x6e, 0x5f, 0x76, 0x9b, 0x4b, 0xcd, 0xec, 0xbf, 0x5f, 0xd8, 0xb2,
+ 0x83, 0x65, 0x7d, 0x16, 0x3b, 0xf2, 0x9f, 0x4b, 0x11, 0x99, 0x5b, 0xce,
+ 0xab, 0xb9, 0x28, 0x4e, 0xc9, 0xa7, 0xbc, 0x67, 0x02, 0x51, 0x52, 0x24,
+ 0xde, 0xd5, 0xca, 0x06, 0x88, 0x8e, 0x85, 0x75, 0x3f, 0x38, 0x8f, 0xb0,
+ 0x7f, 0x7d, 0x3b, 0xdb, 0x2d, 0x90, 0x2d, 0x8c, 0xf6, 0x50, 0x62, 0xb6,
+ 0xc2, 0x7c, 0x4a, 0x47, 0x53, 0xed, 0x3d, 0xe7, 0xeb, 0xae, 0xa2, 0x48,
+ 0xaf, 0xad, 0xec, 0xff, 0x00, 0x66, 0x28, 0xd1, 0x6a, 0x77, 0x0f, 0x53,
+ 0xf2, 0xe9, 0xfe, 0x7f, 0xdd, 0x8d, 0x63, 0x4d, 0x2e, 0x41, 0xb4, 0x25,
+ 0xb6, 0xd2, 0xda, 0x12, 0x12, 0x94, 0x80, 0x12, 0x07, 0x70, 0x02, 0xb9,
+ 0x6e, 0xd7, 0x18, 0x36, 0x9b, 0x74, 0x8b, 0x95, 0xca, 0x5b, 0x10, 0xe1,
+ 0x46, 0x6c, 0xb8, 0xfb, 0xef, 0x2c, 0x25, 0x0d, 0xa4, 0x77, 0x92, 0x4f,
+ 0x41, 0x4b, 0x79, 0x46, 0x7d, 0x6c, 0xb5, 0x5c, 0x7d, 0xc4, 0xb5, 0xc7,
+ 0x7f, 0x20, 0xc8, 0x54, 0x3c, 0xcb, 0x5d, 0xbf, 0x4b, 0x71, 0x1e, 0x85,
+ 0x3c, 0xb2, 0x79, 0x18, 0x47, 0x77, 0x9c, 0xb2, 0x3d, 0x41, 0x47, 0xa5,
+ 0x70, 0x5b, 0xf0, 0xeb, 0xa5, 0xfe, 0xe6, 0xc5, 0xef, 0x88, 0x72, 0x62,
+ 0xcd, 0x5c, 0x77, 0x03, 0xb0, 0xac, 0xb1, 0x49, 0x30, 0x21, 0xac, 0x1f,
+ 0x35, 0x6a, 0xe6, 0x00, 0xbe, 0xe8, 0xfd, 0x25, 0x00, 0x94, 0x9f, 0x82,
+ 0x90, 0x7a, 0xd7, 0xd4, 0xf0, 0x68, 0x72, 0x44, 0x8b, 0x33, 0x89, 0x37,
+ 0x18, 0xd7, 0x7b, 0xc4, 0x57, 0xe0, 0xe2, 0x11, 0x1e, 0x43, 0xf6, 0xeb,
+ 0x73, 0xc9, 0x28, 0x76, 0xe8, 0xea, 0x4e, 0xd3, 0x21, 0xf4, 0x9e, 0xa9,
+ 0x65, 0x24, 0x02, 0xdb, 0x67, 0xaa, 0x88, 0xe7, 0x5e, 0x86, 0x93, 0x4e,
+ 0xf7, 0x3b, 0x34, 0x19, 0xe9, 0xdb, 0x8d, 0xf2, 0x39, 0xe0, 0xb4, 0x74,
+ 0x23, 0xff, 0x00, 0x35, 0x22, 0x00, 0xd5, 0x1a, 0x1a, 0xa9, 0x8c, 0x9c,
+ 0x5e, 0x51, 0x59, 0x45, 0x49, 0x61, 0x95, 0x17, 0x12, 0xec, 0xd2, 0x6d,
+ 0xd2, 0x31, 0x67, 0x54, 0xa4, 0xb8, 0xc9, 0xca, 0x2d, 0xa0, 0x2c, 0x74,
+ 0x23, 0xdf, 0x87, 0x78, 0xab, 0x78, 0x77, 0x52, 0x27, 0x19, 0x47, 0xf3,
+ 0x2c, 0x5f, 0xf6, 0xaa, 0xd9, 0xf7, 0xe2, 0x9e, 0xea, 0xd5, 0x2a, 0x4a,
+ 0xa3, 0xcc, 0x88, 0xa7, 0x4d, 0x53, 0x58, 0x41, 0x45, 0x79, 0x24, 0x83,
+ 0xa0, 0x01, 0xfa, 0xe8, 0xaa, 0x17, 0x3d, 0x52, 0x67, 0x1c, 0x7e, 0x47,
+ 0xb2, 0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa7, 0x3a, 0x4c, 0xe3, 0x8f, 0xc8,
+ 0xf6, 0x5d, 0xf4, 0x44, 0x8f, 0xe0, 0x34, 0x03, 0x7c, 0x6f, 0x8b, 0xb7,
+ 0xf3, 0x07, 0xd9, 0x5b, 0x2b, 0x5c, 0x6f, 0x8b, 0xb7, 0xf3, 0x07, 0xd9,
+ 0x5b, 0x28, 0x03, 0x5d, 0x68, 0xd5, 0x14, 0x50, 0x0a, 0xd9, 0x3e, 0x07,
+ 0x8e, 0xdf, 0xa7, 0x7b, 0xa6, 0xe4, 0x77, 0xad, 0xf7, 0x74, 0x8d, 0x22,
+ 0xe9, 0x6e, 0x78, 0xc6, 0x96, 0x9f, 0x57, 0x68, 0x8d, 0x15, 0x0f, 0xd5,
+ 0x5f, 0x32, 0x7d, 0x55, 0x14, 0x22, 0xf1, 0x37, 0x1e, 0xf8, 0x94, 0xfb,
+ 0x5e, 0x63, 0x0d, 0x00, 0xe9, 0xa9, 0xc3, 0xc8, 0x66, 0x81, 0xe0, 0x03,
+ 0xa8, 0x49, 0x69, 0x67, 0xda, 0x84, 0x7b, 0x7c, 0x69, 0xf7, 0x5d, 0x77,
+ 0x47, 0x28, 0xa0, 0x11, 0x07, 0x13, 0x6d, 0xd6, 0xf0, 0x53, 0x95, 0xd8,
+ 0x72, 0x1c, 0x64, 0xa0, 0x00, 0xa7, 0x66, 0x40, 0x53, 0xb1, 0xb7, 0xea,
+ 0x7d, 0x9e, 0x76, 0xf5, 0xeb, 0x51, 0x4f, 0xd5, 0x4c, 0xb6, 0x2c, 0x9f,
+ 0x1d, 0xbf, 0xa4, 0xaa, 0xc7, 0x7d, 0xb6, 0x5c, 0xf4, 0x36, 0x44, 0x59,
+ 0x48, 0x70, 0x81, 0xeb, 0x09, 0x24, 0x8a, 0x96, 0xd5, 0x2e, 0x5f, 0xf0,
+ 0x2c, 0x2a, 0xfc, 0xb5, 0x39, 0x77, 0xc5, 0xad, 0x12, 0xde, 0x57, 0x7b,
+ 0xca, 0x8a, 0x80, 0xef, 0xd4, 0xb0, 0x02, 0x87, 0xd4, 0x68, 0x09, 0xc9,
+ 0x31, 0x22, 0x49, 0x1f, 0xce, 0x62, 0x30, 0xf8, 0xff, 0x00, 0x68, 0xd8,
+ 0x57, 0xdb, 0x51, 0xee, 0xe3, 0x36, 0x07, 0xb7, 0xcf, 0x69, 0x8c, 0x3e,
+ 0x6a, 0x79, 0x7e, 0xca, 0x5b, 0x5f, 0x0b, 0xac, 0x6c, 0x21, 0x2d, 0xd9,
+ 0x6f, 0x59, 0x55, 0x91, 0x29, 0xee, 0x4c, 0x2b, 0xe4, 0x8e, 0x41, 0xff,
+ 0x00, 0x03, 0x8a, 0x5a, 0x7f, 0xc2, 0xa1, 0x32, 0xf0, 0x30, 0xb8, 0x61,
+ 0xdb, 0x9f, 0x1c, 0xa6, 0xd9, 0x5a, 0xd7, 0x98, 0x2e, 0xc8, 0x82, 0xea,
+ 0x97, 0xec, 0x05, 0xa4, 0xa9, 0x5f, 0x56, 0xeb, 0x1a, 0x96, 0xd4, 0x6a,
+ 0x78, 0xe0, 0x9f, 0xc5, 0x26, 0x46, 0x10, 0xee, 0xac, 0x37, 0x1b, 0x27,
+ 0xad, 0xb0, 0x7d, 0x4f, 0x38, 0x3f, 0xfe, 0xd5, 0x94, 0x61, 0xf8, 0xda,
+ 0x4f, 0x4b, 0x62, 0x4f, 0xb5, 0xd5, 0x9f, 0xb5, 0x55, 0x4e, 0x5a, 0xb8,
+ 0x99, 0x16, 0x74, 0xd1, 0x16, 0x0f, 0xe1, 0x11, 0x8b, 0x29, 0xd3, 0xf0,
+ 0x53, 0x70, 0xb0, 0x25, 0x90, 0xaf, 0x62, 0x94, 0xeb, 0x60, 0xfd, 0x54,
+ 0xfd, 0x0a, 0xdb, 0xc4, 0xc9, 0xb1, 0xd1, 0x26, 0x1f, 0x12, 0x31, 0xb9,
+ 0x0c, 0x2c, 0x6d, 0x0e, 0x35, 0x8f, 0x73, 0x21, 0x43, 0xd2, 0x08, 0x93,
+ 0xa3, 0x58, 0x7f, 0x4e, 0xb3, 0xff, 0x00, 0xaa, 0x3f, 0xf9, 0x5f, 0xc0,
+ 0xd2, 0xbc, 0x87, 0x06, 0x31, 0xeb, 0x13, 0x3d, 0x5b, 0xb4, 0xc4, 0xd8,
+ 0xf1, 0x53, 0x41, 0x5f, 0x6e, 0xea, 0x41, 0x96, 0x9a, 0x65, 0x1c, 0xac,
+ 0xb4, 0xdb, 0x49, 0xf4, 0x21, 0x3a, 0x14, 0x88, 0x31, 0xae, 0x26, 0x39,
+ 0xf9, 0x7e, 0x27, 0xc5, 0x6f, 0xff, 0x00, 0xc7, 0xc7, 0x1a, 0x4e, 0xbf,
+ 0xe7, 0x71, 0x75, 0xb5, 0x58, 0x3e, 0x41, 0x2d, 0xbe, 0x5b, 0xa7, 0x13,
+ 0xb2, 0x97, 0x7f, 0xfc, 0x36, 0xe2, 0x45, 0x1f, 0xf4, 0x33, 0xbf, 0xf1,
+ 0xae, 0x8a, 0x74, 0x29, 0xd3, 0xf0, 0x45, 0x2f, 0x82, 0x27, 0x08, 0x79,
+ 0x27, 0xd5, 0x50, 0xf9, 0x56, 0x51, 0x60, 0xc5, 0xa1, 0x22, 0x66, 0x43,
+ 0x75, 0x8d, 0x6f, 0x65, 0xc5, 0x72, 0x34, 0x5d, 0x57, 0x9c, 0xe2, 0xb5,
+ 0xbe, 0x54, 0x24, 0x75, 0x51, 0xd7, 0x80, 0x04, 0xd2, 0x3d, 0x8e, 0xcc,
+ 0xdd, 0x87, 0x8c, 0xf0, 0x6d, 0x71, 0x2f, 0x77, 0xe9, 0xe3, 0xf9, 0x3f,
+ 0x26, 0x4c, 0xb1, 0x71, 0xb9, 0xbd, 0x27, 0x9b, 0x6f, 0xb0, 0x86, 0xcf,
+ 0x2a, 0x89, 0x48, 0xf8, 0x2e, 0x6b, 0x40, 0x78, 0xd4, 0x8c, 0x12, 0x32,
+ 0x6e, 0x31, 0xbf, 0x3d, 0xb0, 0x95, 0xdb, 0xb1, 0x58, 0x8b, 0x84, 0xdb,
+ 0x9e, 0x06, 0x7c, 0x8e, 0x55, 0x3a, 0x12, 0x7c, 0x7b, 0x36, 0x92, 0xda,
+ 0x4f, 0xa0, 0xba, 0x47, 0x78, 0xad, 0x41, 0xb1, 0x59, 0xf5, 0xd2, 0xea,
+ 0x4a, 0x31, 0x0c, 0x22, 0xf5, 0x73, 0x04, 0x8e, 0x59, 0x77, 0x04, 0x7b,
+ 0x9b, 0x17, 0x94, 0xfe, 0x76, 0xde, 0x1d, 0xaa, 0x87, 0xcd, 0x6c, 0xd7,
+ 0x93, 0x8a, 0xe6, 0x39, 0x01, 0xde, 0x5f, 0x96, 0x98, 0x90, 0xd4, 0x7c,
+ 0xeb, 0x66, 0x3e, 0x95, 0x46, 0x42, 0x87, 0x5e, 0x8b, 0x90, 0xad, 0xbc,
+ 0xa0, 0x47, 0x7f, 0x2f, 0x67, 0xec, 0xa7, 0xd0, 0x01, 0x1e, 0x04, 0x1f,
+ 0x55, 0x67, 0x42, 0x80, 0x8a, 0xc6, 0x71, 0xdb, 0x1e, 0x37, 0x6d, 0x16,
+ 0xfb, 0x0d, 0xae, 0x35, 0xba, 0x30, 0x3c, 0xca, 0x43, 0x28, 0xd7, 0x3a,
+ 0xbc, 0x54, 0xa3, 0xde, 0xa5, 0x1f, 0x15, 0x12, 0x49, 0xf4, 0xd4, 0xae,
+ 0xba, 0x6a, 0x8a, 0x28, 0x02, 0x8a, 0x28, 0xa0, 0x11, 0x38, 0xcb, 0xf1,
+ 0x2c, 0x5f, 0xf6, 0xaa, 0xd9, 0xf7, 0xe2, 0x9e, 0xe9, 0x13, 0x8c, 0xbf,
+ 0x12, 0xc5, 0xff, 0x00, 0x6a, 0xad, 0x9f, 0x7e, 0x29, 0xee, 0x80, 0xc1,
+ 0xef, 0xdd, 0x14, 0x1a, 0x2a, 0x51, 0x56, 0xcc, 0xd2, 0x67, 0x1c, 0x7e,
+ 0x47, 0xb2, 0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa7, 0x3a, 0x4c, 0xe3, 0x8f,
+ 0xc8, 0xf6, 0x5d, 0xf4, 0x44, 0x8f, 0xe0, 0x35, 0x05, 0x86, 0xf8, 0xdf,
+ 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x56, 0xb8, 0xdf, 0x17, 0x6f, 0xe6,
+ 0x0f, 0xb2, 0xb6, 0x50, 0x05, 0x14, 0x56, 0x09, 0x3b, 0xee, 0xa0, 0x33,
+ 0x58, 0x2a, 0xd7, 0x7d, 0x28, 0xe7, 0x3c, 0x48, 0xc3, 0xf0, 0xd7, 0x51,
+ 0x16, 0xf5, 0x77, 0x47, 0xba, 0x2e, 0xfe, 0x42, 0xdb, 0x15, 0xb5, 0x48,
+ 0x98, 0xf1, 0xf0, 0x09, 0x65, 0xb0, 0x56, 0x77, 0xd3, 0xa9, 0x00, 0x7a,
+ 0xe9, 0x64, 0xe4, 0x1c, 0x56, 0xcc, 0x55, 0xc9, 0x8c, 0xe3, 0x4c, 0xe1,
+ 0x16, 0xc5, 0x74, 0xf7, 0x4f, 0x21, 0x48, 0x7a, 0x62, 0x87, 0xfb, 0x38,
+ 0x8d, 0xab, 0x49, 0x3f, 0xef, 0x56, 0x3d, 0x94, 0x05, 0x8d, 0x7d, 0xbd,
+ 0x5a, 0x6c, 0x36, 0xc7, 0x6e, 0x77, 0xbb, 0x94, 0x4b, 0x6c, 0x26, 0x46,
+ 0xdc, 0x91, 0x29, 0xd4, 0xb6, 0x84, 0xff, 0x00, 0xc4, 0xa2, 0x05, 0x57,
+ 0x6b, 0xe2, 0xe4, 0x8b, 0xfa, 0x8b, 0x3c, 0x34, 0xc2, 0xaf, 0x19, 0x60,
+ 0x3b, 0xd5, 0xc5, 0xd1, 0xee, 0x7d, 0xb8, 0x6b, 0xd0, 0xfb, 0xc3, 0x6b,
+ 0xeb, 0xfa, 0x09, 0x57, 0xb6, 0xba, 0xac, 0x7c, 0x1d, 0xc7, 0xd3, 0x76,
+ 0x66, 0xff, 0x00, 0x97, 0xcf, 0xb8, 0x66, 0xb7, 0xc6, 0xba, 0xb7, 0x2a,
+ 0xf2, 0xb0, 0xb6, 0x59, 0x3f, 0xec, 0xa3, 0xa4, 0x06, 0x9b, 0x1f, 0xf0,
+ 0x93, 0xeb, 0xab, 0x19, 0x29, 0x4a, 0x3c, 0xd4, 0x80, 0x00, 0x1d, 0x00,
+ 0x1d, 0x05, 0x01, 0x56, 0x1c, 0x3b, 0x89, 0xb9, 0x67, 0xfa, 0xeb, 0x9d,
+ 0x33, 0x62, 0x80, 0xb1, 0xe7, 0xdb, 0x31, 0x56, 0x94, 0xd2, 0xd4, 0x35,
+ 0xf0, 0x57, 0x2d, 0xcd, 0xb9, 0xed, 0xe4, 0x4a, 0x37, 0x4c, 0x18, 0x8f,
+ 0x0a, 0x38, 0x77, 0x8b, 0xc8, 0x13, 0x2d, 0x38, 0xa5, 0xbc, 0x4e, 0xef,
+ 0x33, 0x64, 0xa4, 0xc9, 0x90, 0x4f, 0xa4, 0xba, 0xe9, 0x52, 0xf7, 0xf5,
+ 0xd3, 0xa8, 0x03, 0x54, 0x6f, 0xc3, 0x54, 0x07, 0x0d, 0xda, 0xc9, 0x67,
+ 0xbb, 0xb1, 0xe4, 0xf7, 0x6b, 0x54, 0x1b, 0x83, 0x3a, 0xd7, 0x67, 0x2a,
+ 0x3a, 0x1d, 0x4e, 0xbd, 0x1a, 0x50, 0x22, 0xaa, 0x9c, 0xb3, 0x0d, 0x77,
+ 0x86, 0x12, 0x3f, 0x96, 0xdc, 0x31, 0xb7, 0x3e, 0xd4, 0x16, 0x17, 0xcf,
+ 0x7d, 0xc6, 0xe2, 0x28, 0xf9, 0x3c, 0xd8, 0xff, 0x00, 0x9e, 0xeb, 0x2d,
+ 0x1e, 0x88, 0x7d, 0x03, 0xa8, 0xe5, 0xd0, 0x50, 0x04, 0x6b, 0x75, 0x70,
+ 0xbc, 0xf3, 0x6c, 0xb4, 0xb7, 0x5d, 0x71, 0x08, 0x6d, 0x00, 0x95, 0x29,
+ 0x6a, 0xd0, 0x48, 0x1e, 0x24, 0xf8, 0x57, 0x05, 0x9a, 0xf9, 0x65, 0xbd,
+ 0xa1, 0xc7, 0xac, 0xd7, 0x68, 0x17, 0x24, 0x34, 0xa0, 0x97, 0x15, 0x16,
+ 0x4a, 0x1d, 0x4a, 0x0f, 0xa0, 0xf2, 0x93, 0xa3, 0x40, 0x18, 0xcd, 0xf2,
+ 0xd7, 0x91, 0xe3, 0xf0, 0x6f, 0xb6, 0x59, 0xad, 0xcc, 0xb7, 0x4d, 0x64,
+ 0x3c, 0xc3, 0xe8, 0xee, 0x52, 0x4f, 0xd8, 0x7c, 0x08, 0x3d, 0xc4, 0x1a,
+ 0x90, 0xd9, 0x1b, 0xd8, 0xaa, 0x93, 0x07, 0xe5, 0xe1, 0xd7, 0x16, 0xae,
+ 0x58, 0x33, 0xde, 0xf3, 0x60, 0xc9, 0x9c, 0x76, 0xed, 0x8f, 0x1e, 0xe4,
+ 0x35, 0x23, 0xbe, 0x54, 0x51, 0xd3, 0x43, 0xaf, 0xbe, 0xa4, 0x0f, 0x05,
+ 0x2b, 0xd1, 0x56, 0x85, 0xf2, 0x1b, 0xd7, 0x1b, 0x34, 0xeb, 0x7c, 0x79,
+ 0x8e, 0xc2, 0x7a, 0x4c, 0x77, 0x19, 0x44, 0x96, 0xc6, 0xd6, 0xca, 0x94,
+ 0x92, 0x02, 0xc0, 0xf4, 0x8d, 0xef, 0xea, 0xa0, 0x29, 0xd8, 0x99, 0x2d,
+ 0xc2, 0xe5, 0x95, 0xe4, 0x17, 0x1c, 0x6c, 0xb7, 0x2a, 0xfb, 0x90, 0x3a,
+ 0x9b, 0x6d, 0x88, 0x2c, 0x05, 0xb7, 0x0e, 0xdf, 0x14, 0xad, 0x0e, 0x4e,
+ 0x70, 0x8e, 0xe6, 0x8b, 0xca, 0x78, 0xa4, 0x7f, 0x48, 0x42, 0x12, 0x37,
+ 0xbd, 0x8b, 0x5f, 0x0d, 0xc7, 0x60, 0xe3, 0x18, 0xe4, 0x5b, 0x34, 0x12,
+ 0xb5, 0xa1, 0x90, 0x54, 0xeb, 0xce, 0x1d, 0xb8, 0xfb, 0xaa, 0x3c, 0xce,
+ 0x3a, 0xb3, 0xe2, 0xb5, 0x28, 0x95, 0x13, 0xe9, 0x3e, 0x8d, 0x0a, 0x89,
+ 0xe1, 0x6e, 0x01, 0x69, 0xc0, 0xac, 0x29, 0x83, 0x0d, 0xc7, 0x26, 0x4d,
+ 0x75, 0x0d, 0x89, 0x93, 0xde, 0xfc, 0xa4, 0x82, 0x84, 0xf2, 0xa0, 0x7a,
+ 0x12, 0x84, 0x8e, 0x89, 0x40, 0xe8, 0x3a, 0x9e, 0xa4, 0x92, 0x5b, 0xc7,
+ 0x41, 0x40, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x45, 0x14,
+ 0x50, 0x08, 0x9c, 0x65, 0xf8, 0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1,
+ 0x4f, 0x74, 0x89, 0xc6, 0x5f, 0x89, 0x62, 0xff, 0x00, 0xb5, 0x56, 0xcf,
+ 0xbf, 0x14, 0xf7, 0x40, 0x79, 0x51, 0xeb, 0x45, 0x64, 0x8d, 0x9e, 0xf3,
+ 0x45, 0x0a, 0xb4, 0xf2, 0x66, 0x93, 0x38, 0xe3, 0xf2, 0x3d, 0x97, 0x7d,
+ 0x11, 0x23, 0xf8, 0x0d, 0x39, 0xd2, 0x67, 0x1c, 0x7e, 0x47, 0xb2, 0xef,
+ 0xa2, 0x24, 0x7f, 0x01, 0xa1, 0x61, 0xbe, 0x37, 0xc5, 0xdb, 0xf9, 0x83,
+ 0xec, 0xaf, 0x64, 0xfb, 0x2a, 0x2e, 0xf5, 0x7b, 0xb5, 0xe3, 0xb8, 0xeb,
+ 0xd7, 0x9b, 0xd4, 0xe6, 0x60, 0xdb, 0xe2, 0x32, 0x1c, 0x7d, 0xf7, 0x4e,
+ 0x92, 0x81, 0xd0, 0x0f, 0x59, 0x24, 0x90, 0x00, 0x1d, 0x49, 0x20, 0x0d,
+ 0x93, 0x55, 0xea, 0xa6, 0x71, 0x03, 0x89, 0x40, 0xa2, 0xd6, 0x64, 0x60,
+ 0x98, 0xaa, 0xf5, 0xb9, 0x6f, 0x37, 0xfe, 0x98, 0x98, 0x8f, 0x1e, 0xcd,
+ 0xb3, 0xd2, 0x32, 0x4f, 0x82, 0x95, 0xb5, 0xeb, 0x44, 0x04, 0xee, 0x80,
+ 0x60, 0xce, 0xb8, 0x9d, 0x8d, 0x62, 0x93, 0x5b, 0xb5, 0x28, 0xca, 0xbc,
+ 0xdf, 0x9e, 0xd8, 0x62, 0xcb, 0x69, 0x6b, 0xca, 0x66, 0xb9, 0xeb, 0x28,
+ 0x07, 0xcc, 0x4f, 0xeb, 0x2c, 0xa4, 0x7a, 0xfa, 0x54, 0x0f, 0xb9, 0x5c,
+ 0x5b, 0xcd, 0x00, 0x55, 0xea, 0xf1, 0x13, 0x01, 0xb4, 0x3a, 0x36, 0x61,
+ 0x5a, 0x08, 0x93, 0x72, 0x52, 0x4f, 0xe6, 0xb9, 0x21, 0x63, 0x91, 0xa5,
+ 0x6b, 0xc5, 0xb4, 0xa8, 0x8d, 0xfc, 0x2a, 0x73, 0xc1, 0xf0, 0xac, 0x5f,
+ 0x0c, 0xb7, 0x18, 0x98, 0xe5, 0xa1, 0x88, 0x7d, 0xa7, 0x57, 0xdf, 0xd7,
+ 0x33, 0xf2, 0x15, 0xbd, 0x95, 0x3a, 0xe9, 0xda, 0xdc, 0x56, 0xc9, 0xea,
+ 0xa2, 0x69, 0x87, 0x42, 0x80, 0x56, 0xc1, 0xb0, 0x0c, 0x4f, 0x0c, 0x69,
+ 0xc3, 0x60, 0xb4, 0x32, 0xcc, 0xb7, 0xb6, 0x64, 0x4d, 0x74, 0x97, 0x65,
+ 0x48, 0x51, 0xea, 0x4b, 0x8f, 0x2b, 0x6b, 0x56, 0xcf, 0xa4, 0xeb, 0xd0,
+ 0x05, 0x77, 0xe5, 0xf9, 0x56, 0x3b, 0x88, 0xda, 0xcd, 0xcf, 0x24, 0xbc,
+ 0x44, 0xb6, 0x45, 0xdf, 0x2a, 0x56, 0xf2, 0xf4, 0xa7, 0x15, 0xfa, 0x28,
+ 0x48, 0xf3, 0x96, 0xaf, 0xd5, 0x48, 0x24, 0xfa, 0x2b, 0xb2, 0xf0, 0xdd,
+ 0xcd, 0xd4, 0x47, 0x4d, 0xae, 0x54, 0x78, 0xea, 0x12, 0x5b, 0x53, 0xe5,
+ 0xe6, 0x4b, 0x9c, 0xcc, 0x83, 0xe7, 0xa5, 0x3a, 0x50, 0xd2, 0x88, 0xee,
+ 0x27, 0x60, 0x7a, 0x0d, 0x7b, 0x93, 0x6f, 0x81, 0x2e, 0x5c, 0x69, 0x72,
+ 0xa0, 0xc6, 0x7a, 0x4c, 0x55, 0x15, 0x47, 0x75, 0xc6, 0x92, 0xa5, 0xb2,
+ 0x4f, 0x42, 0x52, 0x48, 0xda, 0x77, 0xea, 0xa0, 0x12, 0x71, 0x9c, 0xdf,
+ 0x27, 0xcb, 0x2f, 0xd1, 0x95, 0x63, 0xc3, 0x26, 0x5b, 0xf1, 0x94, 0xa8,
+ 0x99, 0x17, 0x4b, 0xde, 0xe3, 0x3b, 0x21, 0x3a, 0xe8, 0x23, 0xc7, 0xf8,
+ 0x7d, 0x49, 0x07, 0x99, 0xce, 0x51, 0xaf, 0x0a, 0x71, 0x9b, 0x69, 0x89,
+ 0x32, 0xed, 0x6f, 0xbb, 0x3c, 0x5f, 0x12, 0x60, 0x07, 0x7b, 0x00, 0x87,
+ 0x96, 0x94, 0x7b, 0xe2, 0x42, 0x54, 0x54, 0x90, 0x74, 0xae, 0x83, 0xa7,
+ 0x30, 0x3a, 0xeb, 0x50, 0x39, 0x7f, 0x11, 0x71, 0x1c, 0x5e, 0x4f, 0x90,
+ 0x4e, 0xb9, 0xf9, 0x4d, 0xd5, 0x63, 0x6d, 0xdb, 0x20, 0xb6, 0x64, 0xcc,
+ 0x70, 0xeb, 0x63, 0x4d, 0x23, 0x6a, 0x03, 0xf5, 0x95, 0xa4, 0xfa, 0xe9,
+ 0x32, 0xe3, 0x96, 0x71, 0x13, 0x26, 0xda, 0x2d, 0xb1, 0xa3, 0x61, 0x56,
+ 0xe5, 0x7f, 0x4d, 0x24, 0x22, 0x65, 0xc5, 0x43, 0xd4, 0xd8, 0x3d, 0x93,
+ 0x47, 0xe7, 0x17, 0x08, 0xf4, 0x78, 0x55, 0xe1, 0x4e, 0x53, 0xf0, 0xa2,
+ 0x93, 0xa9, 0x18, 0x78, 0x99, 0x67, 0x64, 0x79, 0x05, 0x8f, 0x1a, 0xb5,
+ 0xae, 0xe5, 0x7f, 0xba, 0xc2, 0xb5, 0x42, 0x6f, 0xbd, 0xe9, 0x6f, 0xa5,
+ 0xb4, 0x7b, 0x01, 0x27, 0xa9, 0xf5, 0x0e, 0xb5, 0x40, 0x66, 0x9f, 0x85,
+ 0x35, 0xad, 0x4d, 0xb8, 0xd6, 0x01, 0x66, 0x55, 0xdf, 0x5c, 0xc9, 0xf7,
+ 0x42, 0x66, 0xda, 0x8e, 0x08, 0x3a, 0x25, 0x28, 0x1e, 0x7a, 0x87, 0xb7,
+ 0x93, 0xeb, 0x15, 0x3a, 0xce, 0x03, 0x89, 0xcc, 0xf2, 0xa1, 0x94, 0x44,
+ 0x93, 0x92, 0xbb, 0x3a, 0x3a, 0xa3, 0xc9, 0x9d, 0x75, 0x78, 0xc8, 0x92,
+ 0x94, 0x2b, 0xc5, 0xb5, 0x2b, 0xa3, 0x5a, 0xef, 0x01, 0x01, 0x35, 0xf2,
+ 0xb7, 0x10, 0x30, 0xeb, 0xcf, 0xe0, 0xff, 0x00, 0xc4, 0x98, 0xee, 0xa5,
+ 0x5e, 0xe9, 0x62, 0xd7, 0x25, 0x15, 0x42, 0x98, 0xa6, 0xd2, 0xa2, 0xe3,
+ 0x40, 0x8e, 0x61, 0xd4, 0x69, 0x0f, 0xa0, 0x11, 0xd4, 0x68, 0xf5, 0x04,
+ 0x6b, 0x7d, 0x34, 0x9d, 0x19, 0x53, 0x6b, 0x51, 0x48, 0x56, 0x55, 0x13,
+ 0xd2, 0x36, 0xe4, 0x57, 0x2c, 0xeb, 0x88, 0x6e, 0x89, 0x19, 0x9d, 0xfe,
+ 0x6c, 0x88, 0x0b, 0x21, 0x4d, 0xc0, 0x1e, 0xf1, 0x11, 0x43, 0x7f, 0x9a,
+ 0xd2, 0x01, 0x2e, 0xfb, 0x40, 0x77, 0x5e, 0x24, 0x77, 0xd3, 0x9e, 0x26,
+ 0xfc, 0xdc, 0x32, 0x74, 0x5c, 0xb6, 0xd7, 0xda, 0x49, 0x55, 0x95, 0xb0,
+ 0x6e, 0x6d, 0x34, 0x94, 0xa4, 0x3d, 0x6d, 0xd0, 0x4b, 0x88, 0x3a, 0x51,
+ 0x0a, 0x28, 0x00, 0x2d, 0x03, 0x99, 0x44, 0x14, 0x7c, 0x14, 0x6e, 0xba,
+ 0x20, 0x45, 0x81, 0x21, 0xbf, 0x2d, 0x66, 0x42, 0x66, 0x25, 0xd4, 0x25,
+ 0xe5, 0x3c, 0x09, 0x29, 0x29, 0x50, 0x04, 0x29, 0x44, 0xe8, 0x9e, 0x84,
+ 0x69, 0x4b, 0xec, 0xfe, 0x79, 0xa6, 0x2b, 0x25, 0xb8, 0xb8, 0xa6, 0xa4,
+ 0x06, 0x10, 0x88, 0xa1, 0xc4, 0xee, 0x43, 0x9c, 0x9c, 0xbd, 0x7f, 0x45,
+ 0x4a, 0x1c, 0xbc, 0xde, 0xb4, 0x25, 0x64, 0xef, 0xf2, 0x86, 0xb7, 0x8d,
+ 0x14, 0xd6, 0x0e, 0x79, 0x56, 0x79, 0xc9, 0x6c, 0x71, 0x5b, 0x19, 0x6f,
+ 0x3f, 0xe1, 0xfb, 0x4e, 0xd8, 0xa6, 0x36, 0x9b, 0xa4, 0x62, 0xdd, 0xdb,
+ 0x1f, 0x9e, 0xda, 0xb6, 0x1b, 0x92, 0x81, 0xce, 0xd2, 0xc2, 0xbf, 0x41,
+ 0x40, 0xf2, 0x9f, 0x4a, 0x56, 0x6a, 0x53, 0x85, 0x99, 0x6b, 0x19, 0xce,
+ 0x05, 0x6b, 0xc9, 0x1a, 0x6b, 0xb0, 0x72, 0x4b, 0x5c, 0xb2, 0xa3, 0x9e,
+ 0xf6, 0x24, 0x20, 0x94, 0x3a, 0xd9, 0x1f, 0xaa, 0xb4, 0xa8, 0x75, 0xf0,
+ 0xd1, 0xf1, 0xa4, 0xee, 0x09, 0x5c, 0x06, 0x3f, 0x73, 0x9b, 0xc3, 0x49,
+ 0x4e, 0x28, 0xb1, 0x15, 0x06, 0x75, 0x85, 0x6b, 0x3d, 0x5c, 0x84, 0xa5,
+ 0x79, 0xcc, 0xef, 0xc4, 0xb2, 0xe1, 0xd7, 0x7f, 0xc0, 0x52, 0x3d, 0x15,
+ 0xaa, 0x12, 0x87, 0x0d, 0x78, 0xd8, 0xfc, 0x27, 0x13, 0xd9, 0xe3, 0x19,
+ 0xe4, 0x8e, 0xda, 0x2a, 0x87, 0xc0, 0x8b, 0x76, 0x08, 0xf7, 0xc4, 0x1f,
+ 0x40, 0x7d, 0x29, 0xe6, 0x1f, 0xac, 0x92, 0x3c, 0x6b, 0x8e, 0x51, 0x71,
+ 0x78, 0x67, 0x64, 0x64, 0xa4, 0xb2, 0x8b, 0x7c, 0x74, 0x14, 0x56, 0x12,
+ 0x76, 0x90, 0x6b, 0x35, 0x52, 0xc1, 0x45, 0x14, 0x50, 0x05, 0x14, 0x51,
+ 0x40, 0x1d, 0x68, 0xa2, 0x8a, 0x01, 0x13, 0x8c, 0xbf, 0x12, 0xc5, 0xff,
+ 0x00, 0x6a, 0xad, 0x9f, 0x7e, 0x29, 0xee, 0x91, 0x38, 0xcb, 0xf1, 0x2c,
+ 0x5f, 0xf6, 0xaa, 0xd9, 0xf7, 0xe2, 0x9e, 0xe8, 0x02, 0x8a, 0xf2, 0xa2,
+ 0x41, 0xe8, 0x07, 0xd6, 0x75, 0x45, 0x01, 0xea, 0x93, 0x38, 0xe3, 0xbf,
+ 0xc4, 0xfe, 0x5c, 0x3f, 0xf4, 0x89, 0x1a, 0xff, 0x00, 0x90, 0xd3, 0x9d,
+ 0x26, 0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0, 0x1a, 0x02,
+ 0xbe, 0x9f, 0x7f, 0x63, 0x27, 0xe2, 0x52, 0xfd, 0xd2, 0x61, 0x4f, 0xdb,
+ 0xac, 0x37, 0x37, 0x2d, 0xb6, 0x78, 0xab, 0xd7, 0x66, 0x67, 0x30, 0xca,
+ 0x5c, 0x7e, 0x63, 0xa9, 0x3d, 0xe5, 0x1c, 0xe8, 0x43, 0x60, 0xef, 0x44,
+ 0x95, 0x0e, 0xa7, 0xa5, 0xdb, 0x05, 0x96, 0xd9, 0x8a, 0x84, 0xa0, 0xa8,
+ 0x82, 0x36, 0x54, 0x7b, 0xd4, 0x4f, 0x79, 0x3e, 0xb3, 0x5f, 0x38, 0x71,
+ 0x36, 0x1c, 0xcc, 0x3f, 0x8d, 0xb6, 0xf9, 0x69, 0x98, 0xd4, 0x7b, 0x3e,
+ 0x50, 0xfa, 0x6e, 0x2c, 0xad, 0xf0, 0x7b, 0x36, 0x67, 0x32, 0xcf, 0x65,
+ 0x25, 0xae, 0x80, 0xeb, 0xb6, 0x60, 0x82, 0x0e, 0xba, 0xb8, 0xda, 0x47,
+ 0xa6, 0xaf, 0x5c, 0x16, 0xf0, 0xc5, 0xdf, 0x1f, 0x8c, 0xf3, 0x0f, 0x07,
+ 0x51, 0xd9, 0x25, 0x6d, 0xab, 0x44, 0x15, 0x36, 0xa1, 0xb4, 0xab, 0x47,
+ 0xaf, 0x71, 0xf1, 0xeb, 0x5a, 0xe3, 0x34, 0xf2, 0xba, 0x33, 0x27, 0x2c,
+ 0x54, 0xc3, 0xea, 0x86, 0x02, 0x75, 0xe1, 0xd2, 0xbc, 0xb8, 0xe2, 0x5b,
+ 0x6d, 0x4b, 0x71, 0x49, 0x42, 0x52, 0x36, 0xa2, 0x4e, 0x80, 0x1e, 0x93,
+ 0x54, 0x1f, 0x1c, 0x7f, 0x08, 0x85, 0x61, 0xb9, 0x14, 0x9c, 0x4f, 0x14,
+ 0xc5, 0x9f, 0xbe, 0x5e, 0x59, 0x21, 0xb7, 0x64, 0x3c, 0x4a, 0x22, 0xb4,
+ 0xb2, 0x90, 0xae, 0x5f, 0x37, 0x6a, 0x70, 0x80, 0x46, 0xc0, 0xe5, 0x03,
+ 0x7a, 0xdf, 0x7d, 0x7c, 0x77, 0xc6, 0xee, 0x29, 0x71, 0x47, 0x29, 0xbb,
+ 0x48, 0xb4, 0xe6, 0x17, 0xf9, 0x09, 0x8e, 0x9d, 0x1f, 0x20, 0x8b, 0xef,
+ 0x51, 0x8a, 0x48, 0xd8, 0xf3, 0x52, 0x7c, 0xee, 0x84, 0x7c, 0x22, 0xa2,
+ 0x3b, 0xab, 0x34, 0x8d, 0x32, 0x8f, 0xbe, 0xaf, 0x3c, 0x60, 0xc7, 0x3c,
+ 0xb6, 0x45, 0xaf, 0x11, 0x62, 0x46, 0x63, 0x75, 0x60, 0xf2, 0xbc, 0xd5,
+ 0xad, 0x49, 0x31, 0xd8, 0x57, 0x87, 0x6b, 0x21, 0x47, 0xb3, 0x47, 0x71,
+ 0xe8, 0x0a, 0x95, 0xea, 0xa5, 0x6b, 0xa3, 0xb9, 0xb6, 0x44, 0xdb, 0xb2,
+ 0x32, 0xec, 0x95, 0x18, 0xfd, 0xaf, 0xbc, 0xdb, 0xac, 0x8e, 0x96, 0x7c,
+ 0xcf, 0x43, 0xd2, 0xd4, 0x03, 0x87, 0xbf, 0x44, 0x36, 0x10, 0x3d, 0xb5,
+ 0xf3, 0x77, 0xe0, 0x29, 0x74, 0x4b, 0x79, 0x16, 0x4b, 0x66, 0x5b, 0x89,
+ 0xdc, 0x88, 0x8d, 0x49, 0x42, 0x09, 0xe8, 0x7b, 0x35, 0x94, 0x9e, 0x9f,
+ 0xff, 0x00, 0x20, 0xfe, 0xea, 0xfa, 0x1b, 0x89, 0x39, 0x26, 0x3f, 0x89,
+ 0xdb, 0x5b, 0xbc, 0xde, 0xd2, 0xec, 0xb7, 0xb9, 0xbb, 0x2b, 0x7c, 0x06,
+ 0x93, 0xda, 0x3b, 0x25, 0xef, 0x00, 0xdb, 0x7e, 0x2a, 0xfd, 0x63, 0xdd,
+ 0xea, 0xf1, 0xee, 0xa1, 0x46, 0x1a, 0x35, 0xb3, 0x8a, 0xbd, 0x59, 0xeb,
+ 0xd0, 0x89, 0x1c, 0x42, 0xdd, 0x8e, 0xdb, 0x61, 0x29, 0xac, 0x72, 0xdc,
+ 0xcc, 0x46, 0x15, 0xd5, 0x6b, 0x6d, 0x82, 0x92, 0xf1, 0xfd, 0x25, 0x2c,
+ 0x8d, 0xb8, 0x77, 0xe2, 0x49, 0xf6, 0xd4, 0xd8, 0xef, 0xdf, 0xd5, 0xeb,
+ 0xff, 0x00, 0xdf, 0xfe, 0xfa, 0xd5, 0x28, 0xde, 0x47, 0xc7, 0x4b, 0xc5,
+ 0xd1, 0x0b, 0x6e, 0x0e, 0x2f, 0x8c, 0x32, 0xe8, 0xe7, 0x8f, 0x6d, 0x98,
+ 0xdb, 0xb3, 0x26, 0x2d, 0x1e, 0x1c, 0xc8, 0x68, 0x29, 0x43, 0xfb, 0x93,
+ 0x56, 0x74, 0x1b, 0xe2, 0xd9, 0x87, 0x1e, 0x3d, 0xd1, 0xb7, 0x5c, 0xbd,
+ 0xa5, 0x09, 0x12, 0x22, 0xc7, 0x86, 0xeb, 0x6a, 0xe7, 0x00, 0x15, 0x28,
+ 0x21, 0xcd, 0x29, 0x0d, 0xf5, 0xd8, 0x52, 0xb4, 0x3c, 0x37, 0xba, 0xea,
+ 0x85, 0x58, 0xbd, 0x8e, 0x49, 0xd3, 0x97, 0x2c, 0x52, 0xce, 0xf8, 0x83,
+ 0x73, 0x4d, 0xe9, 0x78, 0xa6, 0x05, 0x6f, 0x66, 0xe7, 0x7b, 0x6d, 0xc0,
+ 0xdc, 0xb9, 0x92, 0x12, 0x7c, 0x92, 0x0a, 0x94, 0x36, 0x12, 0x79, 0x7c,
+ 0xe7, 0x5d, 0xd7, 0x5e, 0xcd, 0x20, 0x91, 0xe3, 0xdc, 0x45, 0x42, 0x71,
+ 0x1f, 0x0c, 0xcd, 0xee, 0xdc, 0x10, 0xc9, 0x23, 0x66, 0xf7, 0x0b, 0xcd,
+ 0xde, 0x40, 0x69, 0x12, 0xed, 0xe5, 0x56, 0xb6, 0x23, 0xc5, 0x86, 0xf3,
+ 0x67, 0x98, 0x94, 0x84, 0x92, 0xf0, 0x0a, 0x4f, 0x32, 0x36, 0xa0, 0x07,
+ 0x9d, 0xb2, 0x07, 0x78, 0xb5, 0xb8, 0x67, 0x62, 0xf2, 0x0c, 0x4a, 0xf6,
+ 0xee, 0x2b, 0x6b, 0x89, 0x03, 0x23, 0x5d, 0xc5, 0xe6, 0x82, 0xa7, 0x28,
+ 0x2c, 0x47, 0x0b, 0x58, 0x57, 0x3a, 0xb4, 0x4f, 0x36, 0xd2, 0xb0, 0xb3,
+ 0xa2, 0x79, 0x95, 0xa0, 0x4e, 0x80, 0xd4, 0x8e, 0x2f, 0x8d, 0xdc, 0x71,
+ 0xbc, 0x22, 0xf5, 0x74, 0xcf, 0x6e, 0xfe, 0xe8, 0xdd, 0x5d, 0x8c, 0xff,
+ 0x00, 0x96, 0x48, 0x12, 0xde, 0x71, 0x92, 0xc9, 0x4f, 0x41, 0xd9, 0xa8,
+ 0x84, 0x03, 0xd0, 0x9f, 0x35, 0x09, 0xd7, 0x37, 0x28, 0xf4, 0x9f, 0x3a,
+ 0xbd, 0x69, 0x4d, 0xb4, 0xcf, 0x46, 0x85, 0x18, 0xc1, 0x26, 0x8a, 0x43,
+ 0xf0, 0x66, 0x4a, 0xae, 0x3c, 0x26, 0xb2, 0xc6, 0x90, 0x1b, 0x66, 0xec,
+ 0xd0, 0x71, 0x71, 0x15, 0x29, 0xb5, 0x3a, 0x04, 0x60, 0xe9, 0x48, 0x75,
+ 0xa4, 0x28, 0x84, 0x92, 0x0e, 0xd2, 0x48, 0xee, 0x29, 0xeb, 0xd7, 0xa5,
+ 0x59, 0x4c, 0xdb, 0x2e, 0x2b, 0x9c, 0x5e, 0x4b, 0x49, 0x0e, 0x21, 0x5a,
+ 0x33, 0xae, 0x0b, 0x12, 0x1e, 0x23, 0x7f, 0xd1, 0xb6, 0x9f, 0x31, 0x03,
+ 0xbf, 0xd1, 0xf3, 0x69, 0x62, 0xdd, 0x65, 0x5e, 0x15, 0x87, 0x18, 0x32,
+ 0x16, 0x96, 0xdd, 0xc7, 0x6e, 0x91, 0xee, 0xb1, 0x47, 0x2f, 0x9c, 0xcc,
+ 0x19, 0xea, 0x4a, 0x1f, 0x6b, 0xe6, 0x85, 0xad, 0xcd, 0x81, 0xd3, 0x6d,
+ 0x83, 0xe1, 0x56, 0x3a, 0x18, 0x6d, 0xb7, 0x9d, 0x71, 0x3c, 0xdc, 0xee,
+ 0x1f, 0x3c, 0x95, 0x13, 0xdd, 0xd3, 0xa0, 0x3d, 0x00, 0xe9, 0xdc, 0x34,
+ 0x2b, 0xb6, 0xdd, 0xeb, 0x8f, 0xc0, 0xe3, 0xb8, 0x5a, 0x65, 0xb7, 0x52,
+ 0x07, 0x37, 0xb7, 0xdc, 0x9c, 0x89, 0x0a, 0xf9, 0x61, 0xda, 0xaf, 0xf6,
+ 0x27, 0xbc, 0xb6, 0x07, 0x5d, 0x76, 0xe4, 0x27, 0x4e, 0xb0, 0xaf, 0xd5,
+ 0x75, 0xbe, 0x64, 0x6b, 0xa6, 0x8f, 0x29, 0xf0, 0xa7, 0x3c, 0x9a, 0xdd,
+ 0x67, 0xe2, 0xff, 0x00, 0x08, 0x35, 0x06, 0x49, 0x43, 0x57, 0x38, 0xc8,
+ 0x97, 0x6e, 0x97, 0xdc, 0xe4, 0x49, 0x29, 0x3c, 0xcd, 0x2f, 0xd2, 0x95,
+ 0x21, 0xc4, 0x80, 0x47, 0xa9, 0x42, 0xa3, 0x7c, 0x7f, 0xfd, 0xd4, 0x77,
+ 0x0d, 0xa7, 0x7f, 0x24, 0x78, 0x83, 0x2f, 0x16, 0x78, 0xf2, 0xd9, 0xf2,
+ 0x45, 0xb9, 0x3e, 0xd4, 0x4f, 0x44, 0xb3, 0x30, 0x0e, 0x69, 0x2c, 0x0f,
+ 0x40, 0x58, 0xf7, 0xd4, 0x8e, 0x9d, 0x7b, 0x5a, 0xca, 0xf2, 0x96, 0x7b,
+ 0xe8, 0xd2, 0xce, 0xa6, 0x3b, 0x8c, 0x6b, 0xe0, 0xce, 0x62, 0xfe, 0x5f,
+ 0x86, 0x21, 0xeb, 0xa2, 0x11, 0x1e, 0xff, 0x00, 0x6d, 0x75, 0x76, 0xfb,
+ 0xdc, 0x6d, 0xe8, 0xb1, 0x31, 0xa3, 0xca, 0xe7, 0x41, 0xf9, 0xaa, 0xe8,
+ 0xb4, 0xfa, 0x42, 0x85, 0x3b, 0x8e, 0xea, 0xa7, 0xf3, 0x34, 0xa3, 0x86,
+ 0xdc, 0x5d, 0x83, 0x9e, 0x35, 0xef, 0x58, 0xf6, 0x50, 0xb6, 0xad, 0x59,
+ 0x10, 0x1d, 0x10, 0xc4, 0xae, 0xe8, 0x92, 0xc8, 0xde, 0x86, 0xff, 0x00,
+ 0x24, 0xa3, 0xdc, 0x01, 0x49, 0xab, 0x80, 0x77, 0x77, 0x6a, 0xbc, 0xf3,
+ 0xd0, 0x0a, 0x28, 0xa2, 0x80, 0x28, 0xa2, 0x8a, 0x00, 0xa2, 0x8a, 0x28,
+ 0x04, 0x4e, 0x32, 0xfc, 0x4b, 0x17, 0xfd, 0xaa, 0xb6, 0x7d, 0xf8, 0xa7,
+ 0xba, 0x44, 0xe3, 0x2f, 0xc4, 0xb1, 0x7f, 0xda, 0xab, 0x67, 0xdf, 0x8a,
+ 0x7b, 0xa0, 0x30, 0x40, 0x3d, 0xe2, 0x8a, 0xcd, 0x15, 0x00, 0x29, 0x33,
+ 0x8e, 0x3f, 0x23, 0xd9, 0x77, 0xd1, 0x12, 0x3f, 0x80, 0xd3, 0x9d, 0x26,
+ 0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0, 0x1a, 0x90, 0x47,
+ 0x71, 0xcf, 0x06, 0x56, 0x7d, 0xc3, 0x27, 0xed, 0x70, 0xdc, 0x2c, 0x5e,
+ 0x22, 0xf6, 0x73, 0xad, 0x12, 0x12, 0x74, 0xa6, 0x65, 0xb5, 0xd5, 0xb2,
+ 0x0f, 0x86, 0xfa, 0xa7, 0xfe, 0x2a, 0xae, 0xb8, 0x23, 0xc4, 0xc9, 0x37,
+ 0x9b, 0xb3, 0x6f, 0xdd, 0x96, 0xb4, 0xc8, 0xb8, 0xb6, 0xb7, 0x54, 0xd2,
+ 0xc6, 0xbb, 0x09, 0x0c, 0xf2, 0xb7, 0x36, 0x31, 0xf4, 0x14, 0x2f, 0x95,
+ 0xd4, 0x83, 0xbf, 0x31, 0xe1, 0xd4, 0xf2, 0x93, 0x5f, 0x42, 0xc6, 0x1f,
+ 0xcd, 0xdb, 0xf9, 0x83, 0xec, 0xaf, 0x97, 0x38, 0xd5, 0x8d, 0x3b, 0x85,
+ 0x71, 0xa2, 0x2d, 0xda, 0xdc, 0x43, 0x16, 0xec, 0xb2, 0x5a, 0x24, 0x44,
+ 0x70, 0xab, 0x95, 0xb8, 0xd7, 0xa6, 0xc1, 0x00, 0x2c, 0x9e, 0xe4, 0x48,
+ 0x42, 0x94, 0xda, 0xba, 0x8e, 0xae, 0x15, 0x77, 0x23, 0x55, 0x7a, 0x72,
+ 0xd2, 0xf7, 0xe0, 0xa5, 0x48, 0x6a, 0x5e, 0xa6, 0x38, 0xf7, 0x89, 0x7b,
+ 0x93, 0xc4, 0x77, 0x6e, 0x03, 0xb4, 0x5c, 0x2c, 0x97, 0xdf, 0xe1, 0xba,
+ 0x56, 0x02, 0x1a, 0x94, 0x84, 0xfb, 0xf3, 0x2a, 0x3a, 0x27, 0x4a, 0x4a,
+ 0x52, 0xea, 0x7b, 0x81, 0xe5, 0x70, 0x78, 0x0a, 0xa0, 0xb8, 0xfb, 0x83,
+ 0xad, 0x8b, 0x14, 0x3c, 0xa2, 0x31, 0x71, 0xd5, 0xb6, 0xbe, 0xc2, 0x52,
+ 0x95, 0xe6, 0xf3, 0x20, 0x9f, 0x35, 0x69, 0x0a, 0xeb, 0xca, 0x15, 0xe6,
+ 0x9e, 0xa7, 0x5d, 0x37, 0xaa, 0xfb, 0x3d, 0xf8, 0x70, 0xb8, 0xa5, 0xc2,
+ 0xd5, 0xdb, 0x19, 0x77, 0xb1, 0x93, 0xca, 0x89, 0x76, 0xc7, 0x5d, 0x48,
+ 0x2b, 0x8d, 0x21, 0xb5, 0x6d, 0x05, 0x40, 0xef, 0xaa, 0x16, 0x0a, 0x14,
+ 0x3d, 0x1c, 0xc2, 0xab, 0xfc, 0x52, 0x20, 0xc9, 0x2c, 0x4f, 0x35, 0x32,
+ 0xce, 0xd6, 0xa4, 0x87, 0x21, 0x5e, 0x22, 0x38, 0xb0, 0xdb, 0x4c, 0x3a,
+ 0x93, 0xc8, 0xf3, 0x2a, 0x00, 0xa9, 0xd7, 0x14, 0x0f, 0xc1, 0x2a, 0x3a,
+ 0xd1, 0x4a, 0x93, 0xaa, 0xe9, 0x8d, 0x3d, 0x59, 0x83, 0x39, 0xe5, 0x53,
+ 0x18, 0x99, 0xf1, 0x7f, 0x07, 0xb3, 0x17, 0x70, 0x4e, 0x21, 0x5b, 0x32,
+ 0x24, 0x85, 0x29, 0x86, 0x97, 0xc9, 0x29, 0xb1, 0xde, 0xe3, 0x2b, 0x1a,
+ 0x58, 0x1e, 0xbd, 0x1d, 0x8f, 0x58, 0x15, 0xf7, 0x8b, 0x96, 0xbb, 0x45,
+ 0xeb, 0x29, 0xb3, 0x5f, 0x6d, 0xf2, 0x58, 0x5d, 0xce, 0x74, 0x51, 0x16,
+ 0x04, 0xc5, 0xa9, 0x2a, 0x4c, 0x78, 0xaa, 0xdb, 0x8b, 0x75, 0xb4, 0x2b,
+ 0xa7, 0x31, 0x1a, 0x1b, 0xf1, 0xe6, 0x48, 0x3b, 0x1b, 0x07, 0xe5, 0xfb,
+ 0xcf, 0xe0, 0xd7, 0x73, 0x57, 0x11, 0xe6, 0xe3, 0xf6, 0x9b, 0xf4, 0x36,
+ 0x20, 0xf9, 0x11, 0xb8, 0x42, 0x7a, 0x5f, 0x31, 0x51, 0x6f, 0xb4, 0x08,
+ 0x2d, 0xab, 0x94, 0x7c, 0x24, 0x92, 0x36, 0x7c, 0x41, 0x07, 0x43, 0x7a,
+ 0xab, 0x9f, 0xf0, 0x79, 0xb6, 0x5c, 0x2d, 0xf8, 0x7d, 0xc7, 0x0d, 0xc8,
+ 0x63, 0x2a, 0x25, 0xfa, 0xc3, 0x2c, 0x32, 0x64, 0x20, 0xed, 0x4a, 0x68,
+ 0xfb, 0xe4, 0x77, 0x1b, 0x59, 0xef, 0x48, 0x3b, 0x09, 0xf6, 0x68, 0x8e,
+ 0xfa, 0xbd, 0x18, 0xcd, 0x66, 0x18, 0xe7, 0xea, 0x56, 0xb4, 0xa9, 0xc9,
+ 0xa9, 0xa7, 0xc7, 0xd0, 0xb5, 0xaf, 0x37, 0x0b, 0xc6, 0x2f, 0x7d, 0xb6,
+ 0x62, 0x98, 0x56, 0x2a, 0xf3, 0x30, 0xe6, 0x48, 0x4b, 0x53, 0xaf, 0xcf,
+ 0xc3, 0x5c, 0xb0, 0x1d, 0x52, 0x79, 0xb9, 0x96, 0x94, 0xa9, 0x2a, 0x59,
+ 0xf3, 0x81, 0x2e, 0x2d, 0x40, 0x0e, 0xa0, 0x6f, 0x5a, 0x12, 0x7c, 0x40,
+ 0x61, 0x4c, 0x5d, 0x31, 0x89, 0x4f, 0xbc, 0xd3, 0xb7, 0x25, 0x97, 0x61,
+ 0xc8, 0x5b, 0x4d, 0x72, 0x25, 0xe6, 0xcb, 0x45, 0xc5, 0x2b, 0x94, 0x92,
+ 0x40, 0x0b, 0x6d, 0x1a, 0x1b, 0x3a, 0xe7, 0xef, 0xf1, 0xa1, 0x8c, 0xb3,
+ 0x29, 0x62, 0x38, 0x61, 0xfb, 0x6d, 0xa6, 0x73, 0xc0, 0x69, 0x32, 0x44,
+ 0xa5, 0xb0, 0x17, 0xe8, 0x25, 0xae, 0x45, 0x6b, 0xea, 0x57, 0xf7, 0x77,
+ 0x54, 0x59, 0x4c, 0xe9, 0xb7, 0x33, 0x75, 0xbd, 0xcb, 0x6e, 0x54, 0xd0,
+ 0xd9, 0x69, 0xb4, 0xb4, 0x8e, 0x46, 0x63, 0x20, 0x9d, 0xa9, 0x2d, 0x8d,
+ 0x93, 0xb2, 0x40, 0xda, 0x89, 0x24, 0xe8, 0x77, 0x0e, 0x95, 0x4a, 0x56,
+ 0xf5, 0x35, 0xa6, 0xcb, 0x56, 0xaf, 0x4f, 0x46, 0x16, 0xe6, 0xf8, 0x51,
+ 0xe7, 0x37, 0x70, 0x5c, 0xcb, 0x2d, 0xc4, 0xc0, 0xb8, 0x3a, 0xda, 0x52,
+ 0xb0, 0xa6, 0x43, 0xad, 0x48, 0x09, 0xde, 0x92, 0xa4, 0x6c, 0x1e, 0x61,
+ 0xcc, 0x74, 0xa0, 0x47, 0x4e, 0x87, 0x63, 0x40, 0x72, 0x4b, 0x89, 0x2e,
+ 0xe6, 0xf3, 0x6f, 0x5f, 0xee, 0x92, 0x6e, 0xaa, 0x69, 0x41, 0x6d, 0xb2,
+ 0xb0, 0x1b, 0x8e, 0x85, 0x0e, 0xe2, 0x1a, 0x4f, 0x42, 0x47, 0xeb, 0xf3,
+ 0x11, 0x5d, 0x85, 0xc4, 0xb4, 0x0b, 0xcb, 0x58, 0x42, 0x5b, 0x1c, 0xe5,
+ 0x65, 0x5d, 0x12, 0x07, 0x5d, 0x93, 0xe0, 0x3a, 0x75, 0xde, 0xbb, 0xaa,
+ 0x2f, 0x1a, 0xbb, 0xcb, 0xbf, 0xc6, 0x95, 0x76, 0x90, 0x91, 0xe4, 0xf2,
+ 0x26, 0x3a, 0x60, 0xac, 0x34, 0x51, 0xda, 0xc6, 0x07, 0x48, 0x73, 0x5d,
+ 0xfe, 0x76, 0x89, 0x07, 0x5d, 0x46, 0x8e, 0xba, 0xd7, 0x67, 0xbb, 0x8f,
+ 0xbc, 0xce, 0x39, 0x38, 0x95, 0x49, 0x7b, 0xbc, 0x67, 0x82, 0x03, 0x8d,
+ 0xf2, 0x53, 0x12, 0xd0, 0x89, 0xcb, 0x4b, 0x8b, 0x4d, 0xde, 0xc3, 0x3a,
+ 0xc8, 0xe6, 0xfa, 0x8e, 0xdd, 0x1a, 0x76, 0x3f, 0xd6, 0x7d, 0xf3, 0x54,
+ 0xe9, 0xa2, 0x3a, 0x13, 0xb2, 0x3b, 0xcf, 0xa6, 0x97, 0xf8, 0x98, 0x5a,
+ 0x46, 0x04, 0xbb, 0x83, 0xa3, 0x9f, 0xdc, 0x4b, 0xb4, 0x0b, 0x98, 0x04,
+ 0x6f, 0xcd, 0x0f, 0x25, 0xb7, 0x3a, 0x1f, 0xd4, 0x5a, 0xa9, 0x85, 0x40,
+ 0x85, 0x28, 0x1e, 0xfd, 0x9a, 0xad, 0x18, 0xe9, 0x9c, 0x91, 0x6a, 0xd2,
+ 0xd5, 0x18, 0xb3, 0x15, 0x09, 0x9a, 0x59, 0x5d, 0xbd, 0xd8, 0xd4, 0xc4,
+ 0x29, 0x02, 0x2d, 0xce, 0x33, 0xc8, 0x97, 0x6d, 0x92, 0x7f, 0xa0, 0x94,
+ 0xd1, 0xe6, 0x6d, 0x7e, 0xb1, 0xbe, 0x84, 0x78, 0xa4, 0xa8, 0x78, 0xd4,
+ 0xdd, 0x1a, 0xad, 0xe4, 0x93, 0x4d, 0x33, 0x14, 0xda, 0x69, 0xa2, 0x4e,
+ 0xda, 0xed, 0xa3, 0x8b, 0xfc, 0x23, 0x91, 0x0e, 0xe9, 0x14, 0xb2, 0xd5,
+ 0xce, 0x33, 0x90, 0xae, 0x51, 0x4f, 0x55, 0xc4, 0x92, 0x92, 0x52, 0xe2,
+ 0x0f, 0xa1, 0x48, 0x70, 0x6c, 0x1f, 0x52, 0x4d, 0x72, 0x70, 0x13, 0x24,
+ 0xb9, 0x5c, 0xb1, 0x99, 0x58, 0xbe, 0x48, 0xe7, 0x3e, 0x51, 0x8b, 0x48,
+ 0xf7, 0x32, 0xe6, 0x4f, 0x7b, 0xe1, 0x23, 0xde, 0x64, 0xf5, 0xea, 0x52,
+ 0xeb, 0x7c, 0xaa, 0xdf, 0xa7, 0x9b, 0xd1, 0x4b, 0x76, 0x19, 0xa9, 0xc2,
+ 0xf8, 0x9e, 0xdc, 0x92, 0xae, 0x4b, 0x1e, 0x58, 0xe2, 0x22, 0xcc, 0x04,
+ 0xf9, 0x91, 0xee, 0x21, 0x3a, 0x65, 0xdf, 0x50, 0x75, 0x29, 0xec, 0xcf,
+ 0xeb, 0x25, 0xbf, 0x4d, 0x76, 0x71, 0x83, 0x9f, 0x02, 0xcd, 0xac, 0xfc,
+ 0x5b, 0x88, 0x85, 0x26, 0xde, 0x90, 0x8b, 0x4e, 0x50, 0x84, 0x0e, 0x8a,
+ 0x86, 0xb5, 0x69, 0xa9, 0x07, 0xd2, 0x59, 0x71, 0x43, 0x67, 0xbf, 0x95,
+ 0x44, 0x77, 0x0a, 0xf1, 0x6a, 0x41, 0xd3, 0x93, 0x89, 0xec, 0x52, 0x9e,
+ 0xb8, 0xa6, 0x5b, 0xe9, 0x24, 0x80, 0x4d, 0x66, 0xbc, 0xb4, 0xb4, 0x38,
+ 0xd2, 0x5c, 0x6d, 0x49, 0x5a, 0x16, 0x02, 0x92, 0xa4, 0x9d, 0x82, 0x0f,
+ 0x71, 0x15, 0xea, 0xa8, 0x68, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14,
+ 0x02, 0x27, 0x19, 0x7e, 0x25, 0x8b, 0xfe, 0xd5, 0x5b, 0x3e, 0xfc, 0x53,
+ 0xdd, 0x22, 0x71, 0x97, 0xe2, 0x58, 0xbf, 0xed, 0x55, 0xb3, 0xef, 0xc5,
+ 0x3d, 0xd0, 0x05, 0x14, 0x51, 0x50, 0x02, 0x93, 0x38, 0xe3, 0xf2, 0x3d,
+ 0x97, 0x7d, 0x11, 0x23, 0xf8, 0x0d, 0x39, 0xd2, 0x67, 0x1c, 0x7e, 0x47,
+ 0xb2, 0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa9, 0x03, 0x7c, 0x6f, 0x8b, 0xb7,
+ 0xf3, 0x07, 0xd9, 0x4a, 0x9c, 0x5f, 0xc2, 0x21, 0x71, 0x0b, 0x01, 0xb9,
+ 0xe3, 0x12, 0xc8, 0x69, 0xd7, 0xdb, 0xe7, 0x87, 0x23, 0xf3, 0xa3, 0xc8,
+ 0x4f, 0x56, 0xdc, 0x49, 0xef, 0x04, 0x2b, 0xbf, 0x5e, 0x04, 0x8f, 0x1a,
+ 0x6b, 0x8d, 0xf1, 0x76, 0xfe, 0x60, 0xfb, 0x2b, 0x66, 0xba, 0xd0, 0x1f,
+ 0x30, 0x70, 0x4f, 0x2e, 0xb8, 0x31, 0x3d, 0xbf, 0x75, 0x12, 0x63, 0xce,
+ 0x7a, 0x5b, 0xb0, 0xae, 0xb1, 0xd6, 0x75, 0xe4, 0xf7, 0x86, 0x47, 0xbf,
+ 0x7b, 0x13, 0x25, 0xb4, 0xf6, 0xc3, 0xd2, 0xb4, 0x3d, 0xaf, 0x0a, 0x70,
+ 0xe2, 0x45, 0xa6, 0x35, 0x83, 0x38, 0x87, 0x96, 0xc6, 0x49, 0x66, 0xcd,
+ 0x92, 0xad, 0xb8, 0xb3, 0xdc, 0x46, 0x93, 0xe4, 0xb3, 0xb5, 0xca, 0xc4,
+ 0x8e, 0xbb, 0xe5, 0xed, 0x13, 0xef, 0x2a, 0x3e, 0x9e, 0xcf, 0xd3, 0x4a,
+ 0xff, 0x00, 0x84, 0x36, 0x3a, 0xac, 0x53, 0x89, 0x51, 0xf2, 0xc8, 0x6f,
+ 0x26, 0x0d, 0xa3, 0x2c, 0x2c, 0xdb, 0xee, 0x2f, 0x9e, 0x8d, 0xc2, 0xba,
+ 0x34, 0x79, 0xa0, 0xcc, 0x57, 0x4e, 0x83, 0x98, 0x04, 0x28, 0xfe, 0x81,
+ 0x5f, 0xe9, 0x55, 0x8b, 0x89, 0x49, 0xb6, 0xf1, 0x13, 0x02, 0xb8, 0x63,
+ 0x77, 0x98, 0xab, 0x65, 0x32, 0xdb, 0x76, 0x24, 0xc8, 0x8a, 0x50, 0xed,
+ 0x21, 0xc8, 0x41, 0xd3, 0x8d, 0xfa, 0x94, 0x85, 0x8e, 0x64, 0x9f, 0x50,
+ 0x23, 0xc2, 0xba, 0x21, 0x37, 0xa7, 0x57, 0x58, 0xfd, 0x0e, 0x7a, 0x90,
+ 0x5a, 0xb1, 0xd2, 0x5f, 0x51, 0x53, 0x88, 0x96, 0xb9, 0x8a, 0x11, 0x72,
+ 0x2b, 0x4c, 0x11, 0x3e, 0x75, 0xb4, 0x38, 0x87, 0xa0, 0x68, 0x1f, 0x2f,
+ 0x86, 0xe6, 0xbb, 0x66, 0x3a, 0xf4, 0x2a, 0xf3, 0x52, 0xb4, 0x6f, 0xf3,
+ 0x90, 0x07, 0x8d, 0x6b, 0xc1, 0xee, 0xd6, 0xe7, 0x25, 0x88, 0xd6, 0xd9,
+ 0xce, 0x4b, 0xb4, 0xce, 0x8a, 0x89, 0x36, 0x97, 0x16, 0x95, 0x29, 0x48,
+ 0x4e, 0xd6, 0x1c, 0x60, 0xac, 0xf5, 0xf7, 0xb2, 0x9d, 0xf2, 0x28, 0xf3,
+ 0x27, 0x98, 0x8f, 0x01, 0x52, 0x38, 0x3c, 0xeb, 0x8b, 0x90, 0xe4, 0xd9,
+ 0x6f, 0xaa, 0xdd, 0xfa, 0xc8, 0xf1, 0x83, 0x71, 0x3d, 0xdd, 0xa9, 0x00,
+ 0x16, 0xdf, 0x1f, 0xaa, 0xeb, 0x7c, 0xab, 0x07, 0xd3, 0xcc, 0x2b, 0x92,
+ 0xe3, 0x88, 0x3c, 0x8b, 0x9c, 0x9b, 0xae, 0x2d, 0x7e, 0x91, 0x8f, 0x4b,
+ 0x98, 0xae, 0x79, 0xad, 0xb7, 0x1d, 0x12, 0x22, 0xc9, 0x5f, 0xf5, 0x8a,
+ 0x61, 0x5d, 0x03, 0x9f, 0xac, 0x92, 0x92, 0x7c, 0x77, 0x5e, 0x8a, 0xef,
+ 0x62, 0x71, 0x3c, 0xe6, 0xf1, 0xdd, 0x90, 0xd5, 0xcc, 0x90, 0x4a, 0x7d,
+ 0x03, 0x7a, 0xf4, 0xd6, 0x36, 0x08, 0x1d, 0x41, 0x1d, 0xfb, 0xdf, 0x4a,
+ 0x53, 0xb8, 0x31, 0x79, 0xc7, 0x6d, 0x89, 0xba, 0x19, 0xf3, 0xb2, 0x0e,
+ 0xc5, 0x3c, 0xd7, 0x36, 0x94, 0x84, 0x07, 0x1e, 0x46, 0xce, 0xdd, 0x65,
+ 0x09, 0x00, 0x25, 0x69, 0xd8, 0xf3, 0x07, 0x45, 0x25, 0x24, 0x7c, 0x2e,
+ 0xa6, 0x4e, 0xcd, 0x78, 0xb7, 0x5f, 0x2d, 0x2d, 0xdd, 0xad, 0x13, 0xd9,
+ 0x9b, 0x09, 0xf4, 0x85, 0x21, 0xe6, 0x55, 0xb4, 0xe8, 0xf5, 0x3b, 0xf1,
+ 0x49, 0xee, 0x1a, 0x20, 0x1a, 0xbe, 0xbd, 0xf0, 0xca, 0x69, 0xd8, 0xd5,
+ 0x9b, 0x65, 0x10, 0x31, 0x9b, 0x58, 0x97, 0x35, 0x89, 0x92, 0xbb, 0x55,
+ 0x16, 0xd9, 0x62, 0x2c, 0x72, 0xea, 0xdd, 0x57, 0xa3, 0x5d, 0xc9, 0x1e,
+ 0x92, 0xa2, 0x07, 0x77, 0xb2, 0xa0, 0x31, 0x5b, 0x86, 0x7d, 0x7e, 0xbe,
+ 0xc7, 0x9f, 0x73, 0x85, 0x17, 0x1d, 0xb0, 0x20, 0x29, 0x42, 0x1b, 0x88,
+ 0x0b, 0x95, 0x2b, 0xa1, 0x09, 0x04, 0xab, 0xaa, 0x52, 0x0e, 0x89, 0xf3,
+ 0x52, 0x7d, 0x1b, 0xef, 0xa7, 0x1e, 0x77, 0x5b, 0x49, 0xf3, 0x94, 0x95,
+ 0x12, 0x41, 0x00, 0xf8, 0xfe, 0x77, 0xd5, 0xbe, 0x83, 0x7e, 0x83, 0x5c,
+ 0x71, 0x6d, 0xb1, 0x63, 0x4c, 0x7e, 0x4c, 0x66, 0xb9, 0x64, 0x48, 0x57,
+ 0xbe, 0xbc, 0x56, 0x56, 0xa5, 0x1d, 0x6c, 0x9d, 0x92, 0x74, 0x94, 0x8e,
+ 0xe0, 0x08, 0x03, 0xaf, 0xa2, 0xab, 0x24, 0xdb, 0xce, 0x4b, 0x45, 0xa4,
+ 0xb1, 0x83, 0x4f, 0x10, 0xdc, 0x67, 0xf1, 0x6b, 0x9a, 0xa5, 0xc2, 0x39,
+ 0x3d, 0xc2, 0x92, 0x4a, 0x89, 0x1a, 0x4a, 0xb5, 0xe6, 0x7f, 0xd4, 0x05,
+ 0x78, 0x91, 0x9b, 0x62, 0x50, 0x18, 0x40, 0x9d, 0x93, 0xda, 0x1b, 0x75,
+ 0x28, 0x1d, 0xa2, 0x04, 0xa4, 0x29, 0x49, 0x3a, 0xea, 0x08, 0x49, 0x24,
+ 0x52, 0xd5, 0xd6, 0xee, 0xde, 0x4f, 0x2a, 0x0d, 0xa2, 0x03, 0x25, 0xdc,
+ 0x57, 0xdd, 0x46, 0x99, 0xba, 0xdc, 0x92, 0x90, 0x59, 0x79, 0xf4, 0x92,
+ 0xe3, 0x51, 0x1b, 0x27, 0xa2, 0xd0, 0x5c, 0x6d, 0x01, 0x6a, 0x1d, 0x36,
+ 0x94, 0x24, 0x1d, 0xa8, 0xd4, 0x9e, 0x4b, 0x17, 0x12, 0xc7, 0x67, 0x22,
+ 0xe6, 0xed, 0xe7, 0xf9, 0x3d, 0x71, 0x90, 0xb1, 0xd8, 0xf9, 0x1a, 0x00,
+ 0x90, 0xfe, 0xcf, 0xc1, 0x42, 0x5a, 0x48, 0x75, 0x67, 0xd0, 0x3c, 0xf4,
+ 0xfa, 0x50, 0x77, 0x58, 0x4a, 0x72, 0x52, 0x94, 0xe2, 0xb2, 0x74, 0x46,
+ 0x11, 0x71, 0x8c, 0x24, 0xf0, 0x6d, 0x1c, 0x4e, 0xc0, 0xd5, 0xae, 0x4c,
+ 0x8d, 0x85, 0xef, 0xbb, 0x91, 0x87, 0x95, 0xf6, 0x20, 0xd7, 0xa3, 0xc4,
+ 0xdc, 0x05, 0x09, 0x2a, 0x7b, 0x27, 0x87, 0x1d, 0x20, 0xeb, 0x9a, 0x42,
+ 0x56, 0xc8, 0x27, 0xd0, 0x0a, 0xd2, 0x36, 0x7d, 0x5d, 0xf5, 0x2d, 0x64,
+ 0xfc, 0x70, 0x64, 0x6c, 0xa1, 0xa8, 0x52, 0x17, 0x8f, 0xc0, 0x0a, 0x20,
+ 0x5d, 0x6f, 0x51, 0x80, 0x9a, 0xea, 0x37, 0xd1, 0x49, 0x86, 0x83, 0xca,
+ 0x85, 0x6b, 0xbc, 0xb8, 0x47, 0xa7, 0x90, 0x77, 0x54, 0xef, 0xf2, 0x67,
+ 0x06, 0xc3, 0xe5, 0xc6, 0xbc, 0xe5, 0x97, 0x69, 0x37, 0xcb, 0xe6, 0xf5,
+ 0x1a, 0x65, 0xe5, 0xf3, 0x2e, 0x49, 0x56, 0xc1, 0xe5, 0x8e, 0xc0, 0x1a,
+ 0x49, 0xdf, 0x83, 0x48, 0x07, 0xdb, 0x59, 0x4a, 0xee, 0x4b, 0xc8, 0xd2,
+ 0x36, 0x91, 0x7e, 0x68, 0x4c, 0x75, 0xbb, 0x97, 0x12, 0x63, 0x37, 0x67,
+ 0xb3, 0x63, 0xb7, 0x01, 0x61, 0x90, 0xfb, 0x2a, 0x97, 0x79, 0x9c, 0x83,
+ 0x15, 0xae, 0xc9, 0x2e, 0x25, 0x64, 0xc7, 0x42, 0xbd, 0xf1, 0xc5, 0x1e,
+ 0x5d, 0x05, 0x04, 0x84, 0x83, 0xa3, 0xba, 0xbb, 0xef, 0x76, 0xd8, 0x37,
+ 0x9b, 0x34, 0xbb, 0x4d, 0xd2, 0x23, 0x72, 0xe1, 0x4c, 0x61, 0x4c, 0x48,
+ 0x65, 0xc1, 0xb4, 0xb8, 0x85, 0x0e, 0x55, 0x24, 0x8f, 0x58, 0x26, 0x93,
+ 0x66, 0x64, 0x99, 0x35, 0xe1, 0x61, 0x9b, 0x4c, 0x36, 0xb1, 0xf8, 0xca,
+ 0xde, 0xa4, 0x4e, 0x6f, 0xb7, 0x98, 0xb1, 0xaf, 0xe8, 0xe3, 0x24, 0xe9,
+ 0x1d, 0x47, 0x7b, 0xaa, 0x1e, 0xb4, 0x50, 0x71, 0x3b, 0x84, 0xc0, 0xa7,
+ 0x1f, 0xbe, 0xe5, 0x6e, 0x38, 0x76, 0x4b, 0xcb, 0xbb, 0x79, 0x31, 0x3e,
+ 0xc6, 0xda, 0x48, 0x40, 0x1e, 0xa2, 0x2b, 0x9e, 0xa3, 0x9d, 0x47, 0xaa,
+ 0x47, 0x45, 0x35, 0x0a, 0x6b, 0x4a, 0x22, 0xb8, 0x0b, 0x73, 0x99, 0x67,
+ 0x55, 0xdb, 0x85, 0x37, 0xd9, 0x2a, 0x7a, 0xe7, 0x8a, 0xa9, 0x29, 0x84,
+ 0xfb, 0xa7, 0xce, 0x99, 0x6d, 0x5e, 0xcc, 0x77, 0x7d, 0x65, 0x23, 0x6d,
+ 0xab, 0x5d, 0xc5, 0x03, 0xd3, 0x56, 0xb0, 0xee, 0xaf, 0x9c, 0x38, 0xca,
+ 0xbc, 0x8f, 0x87, 0x79, 0x26, 0x3b, 0xc4, 0x19, 0x6e, 0xc9, 0xbb, 0x35,
+ 0x69, 0x77, 0xb0, 0x33, 0x4b, 0x68, 0x0f, 0xbd, 0x05, 0xdf, 0xcb, 0x43,
+ 0x91, 0xc8, 0x02, 0x54, 0xb4, 0xe9, 0x2e, 0x36, 0xb0, 0x00, 0x25, 0x2a,
+ 0x07, 0xa9, 0x05, 0x5f, 0x42, 0xdb, 0x27, 0x45, 0xb9, 0x5b, 0x63, 0x5c,
+ 0x60, 0xbe, 0xdc, 0x88, 0x92, 0x99, 0x43, 0xcc, 0x3a, 0x83, 0xb4, 0xad,
+ 0x0b, 0x00, 0xa5, 0x43, 0xd4, 0x41, 0x06, 0xb1, 0x36, 0x3a, 0xa8, 0xa2,
+ 0x8a, 0x00, 0xa2, 0x8a, 0x28, 0x04, 0x4e, 0x32, 0xfc, 0x4b, 0x17, 0xfd,
+ 0xaa, 0xb6, 0x7d, 0xf8, 0xa7, 0xba, 0x44, 0xe3, 0x2f, 0xc4, 0xb1, 0x7f,
+ 0xda, 0xab, 0x67, 0xdf, 0x8a, 0x7b, 0xa0, 0x0a, 0x28, 0xa2, 0xa0, 0x05,
+ 0x26, 0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0, 0x1a, 0x73,
+ 0xa4, 0xce, 0x38, 0xfc, 0x8f, 0x65, 0xdf, 0x44, 0x48, 0xfe, 0x03, 0x52,
+ 0x06, 0xf8, 0xdf, 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x56, 0xb8, 0xdf,
+ 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x50, 0x0b, 0xbc, 0x47, 0xc5, 0x2d,
+ 0xd9, 0xc6, 0x15, 0x77, 0xc5, 0xae, 0xa8, 0xdc, 0x5b, 0x8c, 0x72, 0xd7,
+ 0x37, 0x79, 0x6d, 0x7d, 0xe8, 0x58, 0xf5, 0xa5, 0x40, 0x28, 0x7b, 0x2b,
+ 0xe7, 0x0e, 0x13, 0xe4, 0x57, 0x3b, 0x3e, 0x4a, 0x18, 0xbd, 0x2b, 0xb0,
+ 0xbd, 0x46, 0x98, 0x8c, 0x7f, 0x22, 0x04, 0xf4, 0x33, 0x9b, 0x49, 0xf2,
+ 0x29, 0x87, 0xd2, 0x99, 0x0d, 0x20, 0xb4, 0x4f, 0x8a, 0x9b, 0x41, 0x3f,
+ 0x0b, 0xaf, 0xd6, 0x04, 0x6c, 0xee, 0xbe, 0x75, 0xfc, 0x28, 0x71, 0x88,
+ 0x96, 0x4c, 0x92, 0x27, 0x10, 0x9c, 0x4b, 0x8d, 0xd8, 0xee, 0x8c, 0x26,
+ 0xc5, 0x95, 0xa9, 0xad, 0xed, 0xa6, 0x56, 0xa0, 0x63, 0xcd, 0x1a, 0xfc,
+ 0xe6, 0x5d, 0x08, 0x3b, 0xef, 0xd2, 0x52, 0x3c, 0x4d, 0x5a, 0x12, 0x70,
+ 0x92, 0x68, 0xac, 0xe2, 0xa7, 0x1c, 0x31, 0xa3, 0x8b, 0x0d, 0xb5, 0x69,
+ 0x97, 0x6e, 0xe2, 0x9c, 0x24, 0x94, 0xc4, 0x6d, 0xa4, 0xc1, 0xc8, 0x50,
+ 0x91, 0xbf, 0xe6, 0x85, 0x5e, 0x63, 0xe7, 0xd2, 0x59, 0x70, 0x92, 0x7f,
+ 0x51, 0x6b, 0xf4, 0x0a, 0x91, 0xd8, 0x52, 0x76, 0x0a, 0x54, 0x9d, 0x7c,
+ 0x20, 0x76, 0x35, 0xe9, 0xad, 0x1c, 0x1d, 0xbf, 0x2e, 0xfd, 0x65, 0x9d,
+ 0x8e, 0xe4, 0xad, 0x32, 0xed, 0xc1, 0x85, 0xb9, 0x6e, 0xbb, 0x33, 0xa0,
+ 0x5b, 0x71, 0xd0, 0x81, 0xb5, 0x8f, 0x02, 0xdb, 0xcd, 0xa9, 0x2e, 0x27,
+ 0xc0, 0x85, 0x74, 0xa4, 0x76, 0xe7, 0x5f, 0x31, 0x0b, 0x83, 0xdc, 0x32,
+ 0x85, 0x01, 0xcb, 0xa5, 0xee, 0x17, 0x5b, 0x43, 0xf2, 0x02, 0xbb, 0x03,
+ 0x6e, 0x27, 0x4d, 0x3e, 0xfb, 0x80, 0x75, 0x0d, 0x7e, 0x49, 0x40, 0x0e,
+ 0x65, 0x29, 0x03, 0x5d, 0xfb, 0x1d, 0xf4, 0x2a, 0x28, 0x37, 0x1e, 0x8f,
+ 0x74, 0x70, 0x56, 0xa6, 0xe6, 0xb5, 0x75, 0x5b, 0x32, 0x53, 0x89, 0x79,
+ 0x14, 0xab, 0x3c, 0x38, 0xb6, 0xdb, 0x53, 0xed, 0xb1, 0x78, 0xba, 0x2d,
+ 0xc4, 0xc7, 0x75, 0x63, 0x98, 0x46, 0x69, 0x09, 0x2a, 0x7a, 0x41, 0x4f,
+ 0xe7, 0x72, 0xa0, 0x69, 0x23, 0xc5, 0x45, 0x20, 0xf4, 0xde, 0x97, 0xb1,
+ 0xcc, 0x42, 0xd5, 0x6f, 0xc9, 0x67, 0x58, 0x12, 0xbb, 0x94, 0x09, 0x26,
+ 0x3a, 0x67, 0xdb, 0xa7, 0xc7, 0x94, 0x5a, 0x94, 0xa6, 0xd4, 0x40, 0x79,
+ 0xb7, 0x14, 0x9f, 0x35, 0xc2, 0x97, 0x7a, 0xe9, 0x41, 0x40, 0x07, 0x07,
+ 0x80, 0x15, 0x1d, 0x27, 0x14, 0x5c, 0x4e, 0x28, 0xb7, 0x2a, 0x7c, 0xb7,
+ 0xae, 0x72, 0x9e, 0xb4, 0x36, 0xb9, 0x97, 0x17, 0xbc, 0xd0, 0x49, 0x9c,
+ 0xc8, 0x52, 0x52, 0x37, 0xca, 0xdb, 0x69, 0x6d, 0x04, 0x04, 0xfa, 0x09,
+ 0x24, 0x92, 0x49, 0xa6, 0xb7, 0xef, 0x71, 0x32, 0x1b, 0xfc, 0x37, 0x70,
+ 0xfb, 0x4c, 0xec, 0xaa, 0xe7, 0x6e, 0x53, 0xa8, 0x4b, 0x90, 0x48, 0x44,
+ 0x36, 0xfb, 0x44, 0x72, 0xad, 0x0e, 0xc9, 0x5f, 0xbd, 0x81, 0xd0, 0x1d,
+ 0x27, 0x99, 0x5b, 0x48, 0xe9, 0xd2, 0xb5, 0x72, 0x59, 0x72, 0x9e, 0xd8,
+ 0x32, 0x51, 0x78, 0x4a, 0x3b, 0xe4, 0xda, 0xac, 0x77, 0x32, 0x6d, 0x7c,
+ 0x90, 0xb3, 0xc4, 0xad, 0xa1, 0xa0, 0x8f, 0x2a, 0xb2, 0x32, 0xeb, 0x80,
+ 0x0e, 0xef, 0x39, 0x2a, 0x40, 0x3f, 0xf2, 0xee, 0x96, 0xee, 0xb1, 0x6d,
+ 0x2f, 0x5c, 0x7d, 0xc8, 0xbe, 0xe4, 0xb7, 0xfc, 0xe6, 0xe6, 0x01, 0xff,
+ 0x00, 0x41, 0x5a, 0x99, 0x4a, 0x50, 0xaf, 0xf7, 0xad, 0xb0, 0x12, 0x00,
+ 0xf5, 0xba, 0xb0, 0x9f, 0x4d, 0x58, 0x8d, 0xf0, 0xf2, 0xf7, 0x75, 0x8a,
+ 0xe4, 0xbe, 0x21, 0xe5, 0x48, 0x83, 0x6e, 0x09, 0xe6, 0x76, 0xd7, 0x65,
+ 0x71, 0x51, 0x98, 0x09, 0x1e, 0x0f, 0x49, 0x56, 0x9c, 0x58, 0xd7, 0x7f,
+ 0x2f, 0x66, 0x2a, 0x52, 0xd7, 0x7d, 0xb0, 0x58, 0x2d, 0xf1, 0xac, 0x9c,
+ 0x35, 0xc5, 0x11, 0x2d, 0x97, 0x5d, 0x0c, 0xb2, 0xb8, 0xe9, 0x4c, 0x68,
+ 0x6a, 0x57, 0x5e, 0x65, 0x17, 0x48, 0xdb, 0xba, 0x00, 0x92, 0xa4, 0x25,
+ 0x7e, 0x3b, 0x3b, 0xae, 0x6a, 0x97, 0x31, 0xe2, 0x08, 0xea, 0xa7, 0x6b,
+ 0x27, 0xbc, 0xc8, 0x3b, 0x4e, 0x0b, 0x9b, 0x5f, 0xed, 0xe9, 0x83, 0x74,
+ 0x7e, 0x1e, 0x13, 0x61, 0xd2, 0x12, 0x2d, 0xd6, 0xc0, 0x87, 0xe6, 0x14,
+ 0x21, 0x5c, 0xc9, 0x05, 0xd2, 0x3b, 0x26, 0x74, 0x40, 0x23, 0xb3, 0x4a,
+ 0x88, 0xf0, 0x50, 0xa9, 0x9b, 0x24, 0x6e, 0x1d, 0x60, 0xb2, 0xe4, 0xb7,
+ 0x8d, 0xda, 0x9f, 0xbc, 0x5f, 0xca, 0x7f, 0x9c, 0xae, 0x1a, 0x55, 0x3e,
+ 0x7b, 0x87, 0xb8, 0xf6, 0xaf, 0x28, 0x9e, 0x4d, 0x9f, 0x05, 0xa9, 0x23,
+ 0xd5, 0x5b, 0x9d, 0xb1, 0x5f, 0x72, 0x85, 0x2c, 0x5e, 0xef, 0x0b, 0x93,
+ 0x10, 0x9d, 0x2a, 0x34, 0x5e, 0x68, 0xf0, 0xfd, 0x69, 0xd0, 0x3d, 0xa3,
+ 0xa0, 0x1f, 0x15, 0x2b, 0x94, 0xfe, 0x88, 0xae, 0xe6, 0xda, 0xc5, 0x6c,
+ 0xcd, 0x1b, 0x70, 0x9a, 0x48, 0x6b, 0x6a, 0x54, 0x6b, 0x73, 0x2a, 0xe4,
+ 0x6b, 0x43, 0x64, 0xa9, 0x0c, 0xa4, 0xf2, 0xf4, 0xf1, 0x3a, 0xac, 0x24,
+ 0x9b, 0x79, 0x9b, 0x36, 0x86, 0x23, 0xb4, 0x11, 0xc8, 0xc5, 0xd3, 0x2b,
+ 0xc9, 0xdd, 0x72, 0x3b, 0x6f, 0x0c, 0x70, 0xa0, 0x02, 0xe4, 0x06, 0xd2,
+ 0x0c, 0xe4, 0xa0, 0xec, 0x05, 0x29, 0xc7, 0x13, 0xca, 0x90, 0x7a, 0xe8,
+ 0xb6, 0x95, 0xf5, 0xfc, 0xfa, 0x85, 0x98, 0xc4, 0x1c, 0x5a, 0xfb, 0x3d,
+ 0xc5, 0xa1, 0x8f, 0x29, 0x66, 0x10, 0x93, 0x21, 0xd9, 0x4b, 0x70, 0x3f,
+ 0x3c, 0x12, 0x41, 0x6d, 0x12, 0x16, 0x76, 0xa2, 0x34, 0x8f, 0x37, 0x67,
+ 0xaa, 0xc0, 0x09, 0x14, 0xe9, 0x76, 0xb6, 0x48, 0x7a, 0xd6, 0xd5, 0xd2,
+ 0xd1, 0x2b, 0xca, 0x67, 0x43, 0x49, 0x91, 0x6d, 0x73, 0x63, 0xdf, 0x50,
+ 0x40, 0x25, 0x95, 0x1e, 0xe5, 0x21, 0x60, 0x01, 0xea, 0x3c, 0xa7, 0xc0,
+ 0x54, 0xcc, 0x05, 0x5b, 0x2f, 0x50, 0xe0, 0x5d, 0x9a, 0x65, 0xa7, 0xd1,
+ 0xc8, 0x1d, 0x8c, 0xb7, 0x10, 0x0a, 0x9a, 0xe6, 0x1d, 0x75, 0xe2, 0x95,
+ 0x78, 0x1f, 0x66, 0xaa, 0x9a, 0xb4, 0xec, 0x8b, 0xe9, 0xd5, 0xbb, 0x23,
+ 0xaf, 0xb2, 0x11, 0x69, 0xc3, 0xe4, 0xdc, 0xed, 0x4c, 0xa1, 0x9e, 0x46,
+ 0x12, 0xe9, 0x51, 0x68, 0x92, 0x86, 0xfa, 0x73, 0x2c, 0xa4, 0xe8, 0x9e,
+ 0x54, 0x95, 0x2b, 0x47, 0xd1, 0x48, 0x37, 0x34, 0x4c, 0x91, 0x2a, 0x6b,
+ 0xa8, 0x8f, 0xe5, 0x51, 0xa2, 0x2f, 0x4e, 0x4f, 0xba, 0xca, 0x71, 0x29,
+ 0x3e, 0x71, 0x1c, 0xfc, 0xfc, 0xe8, 0x42, 0x46, 0x87, 0x37, 0xbd, 0x27,
+ 0xa2, 0x4a, 0x0f, 0x52, 0x48, 0x16, 0xeb, 0x8d, 0xa1, 0xd6, 0xd6, 0xdb,
+ 0x89, 0x0a, 0x42, 0x81, 0x0a, 0x4a, 0xba, 0x82, 0x0f, 0x81, 0x07, 0xec,
+ 0xa5, 0x17, 0x31, 0x1c, 0x26, 0xca, 0x91, 0x71, 0x9e, 0xdb, 0x48, 0x8d,
+ 0x0c, 0x73, 0x36, 0x67, 0xcb, 0x52, 0xd8, 0x8c, 0x3d, 0x21, 0x2b, 0x57,
+ 0x22, 0x40, 0xf0, 0x3e, 0x15, 0x55, 0xbf, 0x24, 0xf8, 0x78, 0x34, 0x5d,
+ 0x2c, 0xf2, 0x32, 0x7e, 0x14, 0x5c, 0xec, 0x93, 0x16, 0xa9, 0x2e, 0xbf,
+ 0x19, 0xe6, 0xa2, 0xc8, 0x74, 0xef, 0xb6, 0xe5, 0x24, 0xc7, 0x78, 0xfa,
+ 0x49, 0xd3, 0x6a, 0x27, 0xc4, 0xee, 0x90, 0x7f, 0x06, 0x7b, 0xfa, 0xac,
+ 0xee, 0x1e, 0x1c, 0x5c, 0x14, 0xa4, 0xb0, 0xa8, 0x2d, 0xde, 0xb1, 0xb5,
+ 0xac, 0xec, 0x39, 0x01, 0xf1, 0xcc, 0xa6, 0x01, 0x3d, 0xea, 0x65, 0xc2,
+ 0xa4, 0x7c, 0xde, 0x5f, 0x0a, 0x73, 0xb9, 0xe6, 0x17, 0x3c, 0x9a, 0x03,
+ 0xf0, 0x78, 0x7d, 0x67, 0x93, 0x30, 0x3c, 0x92, 0xd2, 0x6f, 0x32, 0x47,
+ 0x61, 0x09, 0xad, 0x82, 0x39, 0xd0, 0x55, 0xe7, 0xbb, 0xaf, 0xd4, 0x49,
+ 0x1e, 0xba, 0x82, 0xe2, 0xa6, 0x0f, 0x2a, 0xd1, 0xc3, 0xfc, 0x76, 0xf3,
+ 0x88, 0x23, 0xb7, 0xc8, 0x70, 0x26, 0xd1, 0x22, 0xdf, 0xe6, 0xf2, 0xaa,
+ 0x63, 0x0d, 0xa0, 0x26, 0x43, 0x0a, 0xd7, 0xf5, 0x8d, 0x83, 0xd3, 0xf4,
+ 0x80, 0xf4, 0xd1, 0xac, 0x12, 0x9e, 0x4b, 0x84, 0x51, 0x50, 0xf8, 0x6e,
+ 0x45, 0x6c, 0xca, 0xf1, 0x6b, 0x6e, 0x47, 0x67, 0x7b, 0xb6, 0x81, 0x71,
+ 0x8e, 0x99, 0x0c, 0xab, 0x5d, 0x74, 0xa1, 0xdc, 0x47, 0x82, 0x81, 0xe8,
+ 0x47, 0x81, 0x06, 0xa6, 0x07, 0x75, 0x41, 0x21, 0x45, 0x14, 0x50, 0x08,
+ 0x9c, 0x65, 0xf8, 0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1, 0x4f, 0x74,
+ 0x89, 0xc6, 0x5f, 0x89, 0x62, 0xff, 0x00, 0xb5, 0x56, 0xcf, 0xbf, 0x14,
+ 0xf7, 0x40, 0x1e, 0x26, 0x8a, 0xf2, 0xa4, 0x82, 0x7a, 0xd1, 0x4c, 0x11,
+ 0x94, 0x7a, 0xa4, 0xce, 0x38, 0xfc, 0x8f, 0x65, 0xdf, 0x44, 0x48, 0xfe,
+ 0x03, 0x4e, 0x74, 0x99, 0xc7, 0x1f, 0x91, 0xec, 0xbb, 0xe8, 0x89, 0x1f,
+ 0xc0, 0x68, 0x48, 0xdf, 0x1b, 0xe2, 0xed, 0xfc, 0xc1, 0xf6, 0x56, 0xca,
+ 0xd7, 0x1b, 0xe2, 0xed, 0xfc, 0xc1, 0xf6, 0x56, 0xca, 0x00, 0xa8, 0xdc,
+ 0xa2, 0xc9, 0x6e, 0xc8, 0xf1, 0xe9, 0xf6, 0x1b, 0xb3, 0x01, 0xf8, 0x37,
+ 0x06, 0x17, 0x1d, 0xf6, 0xcf, 0x8a, 0x54, 0x34, 0x75, 0xe8, 0x23, 0xbc,
+ 0x1f, 0x02, 0x05, 0x49, 0x50, 0x46, 0xe8, 0x0f, 0x98, 0x78, 0x35, 0x12,
+ 0xe5, 0x6a, 0xbf, 0x5c, 0x71, 0xa9, 0x31, 0x5e, 0x93, 0x96, 0xe3, 0x4b,
+ 0x6a, 0xd3, 0x3e, 0x40, 0x92, 0x1b, 0x4c, 0x8b, 0x5a, 0x52, 0xb7, 0x21,
+ 0x4d, 0xe4, 0x57, 0xe5, 0x54, 0x01, 0x4b, 0x5b, 0x1d, 0x42, 0x4a, 0x7b,
+ 0xf5, 0xd2, 0xea, 0xbe, 0x63, 0x16, 0x6c, 0xe6, 0x14, 0x2b, 0x84, 0x97,
+ 0x26, 0x41, 0xb9, 0x45, 0x4a, 0x90, 0xc4, 0xe8, 0x2f, 0x76, 0x6f, 0xb4,
+ 0x15, 0xae, 0x64, 0x83, 0xd5, 0x2a, 0x42, 0xb4, 0x0f, 0x2a, 0x82, 0x87,
+ 0xab, 0x75, 0x5b, 0xfe, 0x14, 0x56, 0x24, 0x58, 0xe6, 0xc0, 0xe2, 0x9c,
+ 0x78, 0x4b, 0x95, 0x12, 0x2b, 0x0a, 0xb4, 0xe5, 0x31, 0x5a, 0xe8, 0xa9,
+ 0x76, 0xb7, 0xcf, 0x2a, 0x95, 0xd3, 0xbd, 0x4d, 0x28, 0xf3, 0x27, 0xd0,
+ 0x48, 0x3e, 0x15, 0xd7, 0xc3, 0xec, 0xe2, 0x4d, 0x9b, 0x1a, 0xbd, 0x43,
+ 0x9e, 0xfa, 0x27, 0xdc, 0xed, 0x2c, 0x37, 0xd9, 0xbe, 0x0e, 0xd1, 0x3d,
+ 0x0e, 0x24, 0x2a, 0x24, 0x90, 0x7f, 0x45, 0xd4, 0xa9, 0x3c, 0xc7, 0xc1,
+ 0x41, 0x60, 0xf7, 0x56, 0xf1, 0x7a, 0xa1, 0x8e, 0xab, 0x74, 0x63, 0x35,
+ 0x89, 0xe7, 0xa3, 0xd9, 0x93, 0x33, 0xb8, 0x67, 0x8a, 0x42, 0x3e, 0xeb,
+ 0xf1, 0x13, 0x25, 0x95, 0x7e, 0x65, 0xae, 0x8d, 0xb5, 0x73, 0x75, 0xb6,
+ 0x22, 0x0d, 0x1d, 0x8d, 0xb0, 0xd8, 0x4a, 0x5d, 0x57, 0x41, 0xf0, 0xf9,
+ 0xb6, 0x7b, 0x85, 0x4b, 0xff, 0x00, 0x29, 0x6e, 0x0e, 0x46, 0x6a, 0xdf,
+ 0x88, 0x63, 0xed, 0x5b, 0xa1, 0x25, 0x01, 0x2c, 0x3b, 0x35, 0x82, 0xde,
+ 0x93, 0xe1, 0xd9, 0xc5, 0x4e, 0x95, 0xad, 0x77, 0x73, 0x96, 0xfd, 0x84,
+ 0x57, 0xa4, 0x5a, 0x62, 0xc1, 0x71, 0xe9, 0xf7, 0x29, 0x4d, 0xbd, 0x36,
+ 0x1b, 0x7c, 0xf3, 0xaf, 0x52, 0x92, 0x14, 0xe3, 0x67, 0x5b, 0x28, 0x64,
+ 0x11, 0xef, 0x69, 0xeb, 0xa0, 0x94, 0xf5, 0xf4, 0xec, 0x9d, 0x9e, 0xaf,
+ 0x76, 0xcd, 0xa2, 0x3a, 0x1e, 0x8d, 0x8f, 0xad, 0xa6, 0x1d, 0x58, 0x4b,
+ 0x66, 0x64, 0xa4, 0xb3, 0x26, 0x5a, 0xbf, 0x45, 0xa6, 0xc8, 0x25, 0x4a,
+ 0xd0, 0xe8, 0x95, 0x14, 0x13, 0xd0, 0x55, 0x5a, 0x4b, 0x79, 0xee, 0xc9,
+ 0x59, 0x7b, 0x43, 0x64, 0x29, 0xdd, 0xe2, 0x39, 0xee, 0xaa, 0xff, 0x00,
+ 0x94, 0x88, 0xb8, 0xde, 0xa5, 0x44, 0x60, 0xcc, 0x71, 0x52, 0x92, 0x84,
+ 0xb0, 0xc3, 0x69, 0x03, 0x65, 0xa6, 0xce, 0x9b, 0x2a, 0xea, 0x35, 0xa0,
+ 0xa5, 0x6c, 0xe8, 0xa8, 0x1a, 0x67, 0xca, 0xd9, 0x66, 0xd2, 0x6c, 0x19,
+ 0x33, 0x2b, 0x75, 0xd8, 0xd0, 0xa4, 0x28, 0x48, 0x52, 0x94, 0x4e, 0xda,
+ 0x7d, 0x01, 0x1c, 0xe7, 0x7d, 0xc0, 0x1e, 0xcf, 0xd8, 0x37, 0x4c, 0xa1,
+ 0x9b, 0x2e, 0x45, 0x0a, 0x15, 0xc1, 0x71, 0xa3, 0x4f, 0x8e, 0x42, 0x5f,
+ 0x8c, 0xb7, 0x1b, 0xe6, 0xd6, 0xc7, 0x42, 0x37, 0xdd, 0xe1, 0xf5, 0x8f,
+ 0x55, 0x73, 0xb1, 0x75, 0xc7, 0xb2, 0x36, 0xa4, 0xda, 0xdb, 0x9b, 0x1a,
+ 0x62, 0x56, 0x1c, 0x61, 0xf8, 0xea, 0x24, 0x29, 0x40, 0x12, 0x85, 0x8e,
+ 0x53, 0xa3, 0xae, 0xf1, 0xb1, 0xd3, 0xae, 0xf7, 0xdd, 0x51, 0xef, 0x1f,
+ 0x1d, 0x0b, 0x7b, 0xb5, 0xf3, 0x35, 0x65, 0xad, 0x16, 0xf1, 0x07, 0xd3,
+ 0x05, 0xa7, 0x54, 0xcb, 0x61, 0x0b, 0x5b, 0x4c, 0x13, 0xce, 0xe3, 0x01,
+ 0x69, 0x53, 0x89, 0x4e, 0x8e, 0xf6, 0x50, 0x14, 0x06, 0xbb, 0xf7, 0xaa,
+ 0x8f, 0x5e, 0x61, 0x8b, 0x5b, 0x61, 0x35, 0x16, 0xcd, 0xd9, 0xca, 0x5b,
+ 0x9f, 0x90, 0x87, 0x01, 0xae, 0x65, 0xaf, 0xd8, 0x84, 0x8d, 0x8f, 0x6e,
+ 0xb5, 0xe9, 0xae, 0x4c, 0x5a, 0xf6, 0xab, 0x03, 0xea, 0xc5, 0x6f, 0xcf,
+ 0xab, 0xb6, 0x8a, 0x79, 0x22, 0xbe, 0xbe, 0x8a, 0x90, 0xcf, 0xe6, 0x2c,
+ 0x0f, 0x1e, 0x9d, 0x0e, 0xbb, 0x94, 0x15, 0xe1, 0x5e, 0xae, 0x39, 0xde,
+ 0x23, 0x64, 0x9c, 0xb8, 0x16, 0xe6, 0x0c, 0xfb, 0xb3, 0xbe, 0x71, 0x85,
+ 0x6c, 0x8d, 0xda, 0x48, 0x70, 0xfa, 0x54, 0x94, 0x8d, 0x8f, 0x6a, 0xb4,
+ 0x3d, 0x75, 0x3a, 0x1e, 0x73, 0x8c, 0x94, 0xd6, 0xb1, 0x8c, 0xe0, 0x9b,
+ 0xc1, 0x21, 0x4f, 0x83, 0x8f, 0xa1, 0x8b, 0x83, 0x6d, 0xb0, 0xb2, 0xf3,
+ 0xae, 0x37, 0x19, 0x27, 0x7d, 0x83, 0x6a, 0x59, 0x52, 0x5b, 0x27, 0xc7,
+ 0x40, 0xeb, 0xd5, 0xdd, 0xd7, 0x5b, 0xa5, 0xb7, 0x33, 0x2c, 0x7b, 0x0f,
+ 0xba, 0xdf, 0x20, 0x5c, 0x27, 0xb4, 0xdb, 0x1e, 0x54, 0x89, 0x11, 0x9a,
+ 0x49, 0x2b, 0x5a, 0x94, 0xf2, 0x76, 0xb4, 0x21, 0x23, 0x65, 0x47, 0x9c,
+ 0x29, 0x5a, 0x48, 0x27, 0xcf, 0xee, 0xa0, 0xc3, 0xe2, 0x0e, 0x57, 0xb3,
+ 0x3a, 0x43, 0x78, 0x7d, 0xad, 0x47, 0x5d, 0x83, 0x1c, 0x92, 0x27, 0x38,
+ 0x9f, 0x5a, 0xba, 0xb6, 0xd7, 0x4d, 0x78, 0x38, 0x7e, 0x6d, 0x6e, 0xb5,
+ 0xc1, 0xc1, 0xb0, 0xc7, 0x1f, 0x55, 0xad, 0xa6, 0x27, 0x5f, 0x56, 0xb4,
+ 0xb4, 0xe1, 0xf2, 0x84, 0xc8, 0xb8, 0x48, 0x5a, 0xb4, 0x90, 0x95, 0x29,
+ 0x67, 0x98, 0x0e, 0x83, 0xa6, 0xc2, 0x40, 0xf0, 0x00, 0x55, 0x70, 0x97,
+ 0x25, 0xd3, 0x6c, 0xd6, 0x9b, 0xd6, 0x7f, 0x92, 0x91, 0xee, 0x25, 0x8d,
+ 0xbc, 0x76, 0x0a, 0xbb, 0xa6, 0x5e, 0x01, 0xed, 0x88, 0xf1, 0xe5, 0x8e,
+ 0x93, 0xcd, 0xbf, 0x9e, 0x51, 0xec, 0xaf, 0x5f, 0xc8, 0x9b, 0x0d, 0xb9,
+ 0xa5, 0xdf, 0xf3, 0x4b, 0x8b, 0xd9, 0x0c, 0x98, 0xa9, 0xed, 0x94, 0xfd,
+ 0xcf, 0xce, 0x61, 0x92, 0x3c, 0x5b, 0x60, 0x0e, 0x40, 0x7c, 0x07, 0x45,
+ 0x2b, 0x7d, 0xc4, 0x9a, 0xdd, 0x94, 0x5c, 0xf2, 0xf8, 0x56, 0xa5, 0x4b,
+ 0x92, 0xc5, 0xba, 0x0c, 0x27, 0x56, 0xdb, 0x72, 0x1d, 0x8e, 0xea, 0x96,
+ 0xf4, 0x06, 0x94, 0xb4, 0x85, 0x3a, 0x49, 0x01, 0x2b, 0xe5, 0x49, 0x3d,
+ 0xc0, 0x68, 0xf5, 0xea, 0x07, 0x5d, 0x13, 0x2c, 0x38, 0xbd, 0xc9, 0x33,
+ 0xa0, 0x59, 0xdc, 0x8c, 0x32, 0x0b, 0x7b, 0xe8, 0x70, 0x49, 0x92, 0xb5,
+ 0x38, 0xf7, 0x6e, 0x8e, 0x57, 0x00, 0x75, 0x44, 0xf3, 0x29, 0xb3, 0xe6,
+ 0xec, 0x77, 0x68, 0xf4, 0xd7, 0x4a, 0x8d, 0x4d, 0xf0, 0x4a, 0x8a, 0x5c,
+ 0x9d, 0x97, 0xfc, 0x96, 0xfd, 0x0e, 0xc1, 0x26, 0xe5, 0x0f, 0x18, 0x71,
+ 0x88, 0xa8, 0x48, 0x4a, 0x1c, 0x92, 0xf0, 0x0e, 0xb4, 0x0e, 0x87, 0x6a,
+ 0xa6, 0x40, 0x3e, 0x62, 0x77, 0xcc, 0x41, 0x50, 0x56, 0x81, 0xe8, 0x3b,
+ 0xab, 0x51, 0xb5, 0xc0, 0x98, 0x99, 0x5e, 0x45, 0x92, 0x4c, 0x7a, 0xfb,
+ 0x15, 0x40, 0x26, 0x73, 0xb3, 0x09, 0x4a, 0x1e, 0xd0, 0x50, 0x4f, 0x66,
+ 0x92, 0x1b, 0xe4, 0x3b, 0x00, 0xa4, 0x24, 0x74, 0x57, 0xac, 0x1a, 0x8f,
+ 0xb4, 0x66, 0x37, 0x79, 0xee, 0xbe, 0xb5, 0xda, 0x44, 0xfb, 0x7c, 0xc8,
+ 0xe8, 0x7d, 0x88, 0xe1, 0x87, 0x52, 0xe2, 0x02, 0xdb, 0x4e, 0xda, 0x59,
+ 0x5a, 0x03, 0x3d, 0x9e, 0xf9, 0x8f, 0x69, 0xcf, 0xd4, 0x1f, 0x83, 0x50,
+ 0x36, 0x9b, 0x6d, 0xbe, 0x3a, 0xa2, 0xa6, 0xdf, 0x7f, 0x85, 0x72, 0xbd,
+ 0xba, 0xc3, 0x70, 0xd4, 0xd5, 0xa8, 0x36, 0x99, 0x0e, 0x04, 0xa3, 0xb8,
+ 0xbe, 0x49, 0xf7, 0xb4, 0x84, 0xeb, 0xb5, 0xe5, 0xe7, 0x00, 0x00, 0x15,
+ 0xbd, 0x26, 0xa3, 0x65, 0xc9, 0x3b, 0xbe, 0x0e, 0x1e, 0x0a, 0xdc, 0xc6,
+ 0x23, 0x9f, 0xc9, 0xc2, 0xd6, 0xd7, 0x93, 0x58, 0xf2, 0x64, 0xbd, 0x79,
+ 0xc7, 0xdb, 0xdf, 0x9b, 0x19, 0xf0, 0xa2, 0x26, 0xc2, 0x1e, 0x1a, 0x4b,
+ 0x9b, 0x71, 0x3a, 0xd7, 0x9a, 0xaf, 0xee, 0xbd, 0x53, 0xdc, 0x2a, 0x92,
+ 0xe3, 0x1e, 0x31, 0x90, 0xbb, 0x86, 0x5b, 0x1a, 0x81, 0x12, 0xd5, 0x0a,
+ 0xe3, 0x68, 0x94, 0x89, 0x58, 0xf3, 0xf0, 0xb9, 0xcf, 0x92, 0x4c, 0x47,
+ 0xe4, 0xda, 0x71, 0x4b, 0xea, 0xb4, 0x3c, 0x36, 0xd9, 0x3e, 0x6e, 0xd4,
+ 0xb4, 0xec, 0x1d, 0xee, 0xac, 0x6e, 0x16, 0xe6, 0x50, 0x73, 0xcc, 0x12,
+ 0xdb, 0x93, 0xc0, 0x41, 0x64, 0x49, 0x6f, 0x4f, 0xc7, 0x51, 0xf3, 0xe3,
+ 0xbe, 0x93, 0xca, 0xe3, 0x4a, 0x1e, 0x05, 0x2a, 0x04, 0x75, 0xf0, 0xd1,
+ 0xf1, 0xa8, 0x24, 0x68, 0xa2, 0x81, 0xdd, 0x45, 0x00, 0x89, 0xc6, 0x5f,
+ 0x89, 0x62, 0xff, 0x00, 0xb5, 0x56, 0xcf, 0xbf, 0x14, 0xf7, 0x48, 0x9c,
+ 0x65, 0xf8, 0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1, 0x4f, 0x74, 0x07,
+ 0x95, 0x10, 0x0f, 0x52, 0x07, 0xb6, 0x8a, 0xc9, 0x1d, 0x68, 0xa8, 0x18,
+ 0x46, 0x69, 0x33, 0x8e, 0x3f, 0x23, 0xd9, 0x77, 0xd1, 0x12, 0x3f, 0x80,
+ 0xd3, 0x9d, 0x26, 0x71, 0xc7, 0xe4, 0x7b, 0x2e, 0xfa, 0x22, 0x47, 0xf0,
+ 0x1a, 0x90, 0x37, 0xc6, 0xf8, 0xbb, 0x7f, 0x30, 0x7d, 0x95, 0xb2, 0xb5,
+ 0xc6, 0xf8, 0xbb, 0x7f, 0x30, 0x7d, 0x95, 0xb2, 0x80, 0x28, 0xa2, 0x8a,
+ 0x03, 0x96, 0xe9, 0x0a, 0x2d, 0xca, 0xdf, 0x26, 0xdf, 0x39, 0x86, 0xe4,
+ 0x45, 0x94, 0xd2, 0x99, 0x7d, 0xa5, 0x8d, 0xa5, 0xc4, 0x28, 0x10, 0xa4,
+ 0x91, 0xe8, 0x20, 0x9a, 0xf8, 0xda, 0xe3, 0x06, 0xe1, 0x84, 0xca, 0xbd,
+ 0xe2, 0x73, 0x24, 0x2f, 0xb4, 0xc5, 0xd8, 0x54, 0x54, 0xba, 0xb5, 0x12,
+ 0x5e, 0xb1, 0x49, 0x73, 0x9e, 0x24, 0x8d, 0xf8, 0xf9, 0x2c, 0x92, 0x02,
+ 0xbf, 0x55, 0xc5, 0x78, 0x26, 0xbe, 0xd3, 0xd5, 0x52, 0xff, 0x00, 0x84,
+ 0xee, 0x3e, 0xfc, 0x7b, 0x7c, 0x0e, 0x26, 0x5a, 0x20, 0x26, 0x74, 0xfc,
+ 0x68, 0x38, 0x9b, 0x8c, 0x32, 0x9e, 0x61, 0x70, 0xb5, 0x3a, 0x39, 0x65,
+ 0x30, 0xa1, 0xe3, 0xe6, 0x92, 0xa1, 0xbe, 0xef, 0x38, 0xd4, 0xa7, 0x87,
+ 0x92, 0x1a, 0xca, 0xc0, 0xd9, 0x8f, 0x4c, 0x63, 0x39, 0xc0, 0x24, 0xbd,
+ 0x09, 0xc1, 0x1d, 0xeb, 0x83, 0x45, 0x44, 0xf7, 0x86, 0x24, 0x00, 0x02,
+ 0x90, 0xaf, 0x5a, 0x1c, 0x49, 0x04, 0x7a, 0x3d, 0xbb, 0xa8, 0x35, 0xe3,
+ 0xf7, 0x97, 0xef, 0x82, 0x5a, 0xec, 0x97, 0x17, 0xee, 0x4b, 0x5f, 0x94,
+ 0x11, 0x2e, 0x7e, 0xed, 0xd1, 0x5d, 0x56, 0x8a, 0x96, 0x00, 0xf3, 0x97,
+ 0xa2, 0x94, 0xe9, 0x1d, 0x7a, 0x01, 0xbd, 0x68, 0x6a, 0xbd, 0xe0, 0x62,
+ 0xe7, 0x40, 0x99, 0x2e, 0xd9, 0x88, 0xdf, 0x18, 0x2f, 0xc6, 0xec, 0x96,
+ 0xc3, 0x53, 0xb9, 0x95, 0x16, 0xef, 0x6f, 0x75, 0x3c, 0xd0, 0xe4, 0x12,
+ 0x9f, 0x39, 0xb7, 0x83, 0x7e, 0xf4, 0xa7, 0x12, 0x0f, 0x9c, 0xce, 0x94,
+ 0x09, 0xd6, 0xad, 0xe7, 0xa4, 0x71, 0x56, 0x6a, 0xfb, 0x36, 0xad, 0x18,
+ 0xa5, 0xa9, 0x24, 0xf5, 0x7d, 0x77, 0x17, 0xa4, 0x94, 0x8f, 0x48, 0x40,
+ 0x65, 0x1c, 0xc7, 0xda, 0xa4, 0xee, 0xb4, 0x97, 0x39, 0x7d, 0x4c, 0xa3,
+ 0xc6, 0x17, 0x41, 0xaa, 0xdb, 0x1e, 0x2d, 0xa2, 0xd4, 0xdc, 0x65, 0xba,
+ 0xda, 0x52, 0x9e, 0x75, 0x2d, 0x4a, 0x3c, 0xa9, 0x2a, 0x51, 0x2a, 0x5a,
+ 0xb4, 0x4f, 0x40, 0x4a, 0x94, 0x75, 0xe1, 0xba, 0xae, 0x63, 0xdd, 0xf1,
+ 0x96, 0xaf, 0x32, 0x15, 0x83, 0xd8, 0xe6, 0xe5, 0x77, 0x30, 0xf1, 0x2d,
+ 0xba, 0xcf, 0x9d, 0x16, 0x0a, 0xb9, 0x74, 0xa4, 0x26, 0x42, 0xf4, 0x96,
+ 0xd2, 0x76, 0x49, 0x4a, 0x49, 0x3b, 0x27, 0xa7, 0x85, 0x48, 0xdc, 0xb0,
+ 0xfb, 0x5b, 0x4d, 0x0b, 0x8f, 0x10, 0xf2, 0x49, 0x57, 0xd4, 0x95, 0x84,
+ 0x88, 0xee, 0x0e, 0xc2, 0x22, 0xd5, 0xde, 0x12, 0x23, 0xb7, 0xb2, 0xe9,
+ 0xef, 0xf3, 0x54, 0x57, 0xbf, 0x01, 0x52, 0x3f, 0xca, 0x44, 0xf6, 0xf0,
+ 0xf1, 0xbb, 0x05, 0xad, 0xcb, 0x5c, 0x97, 0x50, 0xa5, 0x23, 0xcb, 0x60,
+ 0xa9, 0xa6, 0x63, 0xc6, 0x40, 0xf3, 0x9d, 0x08, 0x1a, 0x0a, 0x1b, 0x29,
+ 0x48, 0x4e, 0xd2, 0x76, 0xa1, 0xbd, 0x78, 0xd3, 0xba, 0xbd, 0x4d, 0x31,
+ 0x26, 0x45, 0x4e, 0xc3, 0x2e, 0xd9, 0x34, 0x65, 0x4a, 0xe2, 0x4d, 0xf6,
+ 0x3b, 0x76, 0xe4, 0x12, 0xb3, 0x6c, 0xb7, 0x9e, 0xcd, 0x84, 0x27, 0xd0,
+ 0xe4, 0x85, 0x0e, 0xd1, 0x5d, 0x3b, 0xca, 0x7b, 0x31, 0xed, 0xef, 0x3d,
+ 0xb6, 0x6b, 0xbe, 0x19, 0x8f, 0x43, 0x62, 0xcb, 0x85, 0xdb, 0x61, 0xf6,
+ 0xd2, 0x57, 0xd9, 0xc5, 0x89, 0x15, 0xae, 0xc1, 0x32, 0x08, 0x07, 0x6b,
+ 0xed, 0x0a, 0x74, 0xb4, 0xa4, 0x02, 0x54, 0xb1, 0xcc, 0x40, 0x1e, 0x24,
+ 0xea, 0x8c, 0x8e, 0xdb, 0x2e, 0x0c, 0xbb, 0x44, 0xeb, 0xcd, 0xdd, 0xfb,
+ 0xbd, 0x99, 0x12, 0xd2, 0x27, 0x35, 0x21, 0xa6, 0x92, 0x84, 0x2d, 0x63,
+ 0x91, 0xa7, 0x00, 0x4a, 0x53, 0xef, 0x69, 0x5a, 0x86, 0xc1, 0x27, 0x5d,
+ 0x0f, 0x81, 0xdf, 0x1e, 0x53, 0x95, 0x44, 0xb8, 0x40, 0x76, 0x33, 0x31,
+ 0xa6, 0xb1, 0x90, 0xdb, 0x66, 0x03, 0x09, 0xa5, 0xc7, 0x5b, 0x6e, 0x29,
+ 0xe0, 0xa2, 0x11, 0xca, 0x08, 0x1c, 0xe8, 0x71, 0x3c, 0xc0, 0x94, 0xed,
+ 0x3c, 0xaa, 0x3d, 0x7c, 0x43, 0x79, 0x0d, 0xa2, 0x75, 0xe5, 0x09, 0xc9,
+ 0x9a, 0x89, 0x0d, 0xdb, 0xe4, 0xf8, 0x66, 0xce, 0xf4, 0x94, 0x22, 0xe8,
+ 0x88, 0x0d, 0xad, 0xb5, 0xb0, 0xc9, 0xd8, 0x1a, 0x70, 0xaf, 0x6a, 0x6c,
+ 0xa8, 0xa4, 0x2c, 0xe9, 0x27, 0x97, 0x64, 0x68, 0x6e, 0xb9, 0xae, 0x93,
+ 0x71, 0x69, 0xf8, 0x9c, 0x89, 0xd6, 0x01, 0x12, 0x14, 0x8b, 0x13, 0x8e,
+ 0x48, 0x8e, 0x52, 0xc0, 0x40, 0x8a, 0xfb, 0x64, 0x82, 0x85, 0x80, 0x07,
+ 0x2f, 0x3e, 0x8a, 0x0a, 0x4f, 0x52, 0x15, 0xd0, 0x6f, 0xbb, 0x86, 0xea,
+ 0xac, 0x95, 0x84, 0x5c, 0x2d, 0xd7, 0x69, 0x66, 0x34, 0x2b, 0xa2, 0xdd,
+ 0x69, 0x84, 0x3e, 0xda, 0x1d, 0x7d, 0x28, 0x73, 0x7c, 0xe8, 0x69, 0xb6,
+ 0x4a, 0x94, 0xf9, 0x01, 0x5e, 0x6a, 0x94, 0x11, 0xcb, 0xd3, 0x98, 0x2a,
+ 0xb3, 0x1e, 0x1d, 0xae, 0x45, 0xfb, 0xc8, 0xa0, 0x44, 0x99, 0x6d, 0x7d,
+ 0x96, 0xd3, 0x31, 0xf7, 0xef, 0x21, 0x6e, 0x96, 0x93, 0xbe, 0x46, 0xd4,
+ 0xd2, 0x16, 0xa2, 0x85, 0x2c, 0xe8, 0x80, 0xb3, 0xcd, 0xc9, 0xa0, 0x35,
+ 0xd4, 0x0a, 0x61, 0x2f, 0x52, 0x77, 0x61, 0x75, 0xbc, 0x65, 0x2b, 0x5d,
+ 0xd3, 0xca, 0x9b, 0x44, 0x3b, 0x2c, 0xb6, 0x88, 0x6f, 0xdd, 0x56, 0x92,
+ 0xc8, 0x8c, 0xb5, 0xa3, 0x45, 0x2a, 0x5f, 0x31, 0xed, 0x53, 0xde, 0x52,
+ 0x84, 0x27, 0x98, 0x95, 0x00, 0x48, 0xd1, 0xad, 0x46, 0xd9, 0x69, 0x97,
+ 0x39, 0x8b, 0x55, 0xad, 0xe9, 0x97, 0x5b, 0x9b, 0xd1, 0x42, 0x5c, 0x6e,
+ 0xe0, 0xc9, 0x88, 0x83, 0x1d, 0xb4, 0x80, 0x16, 0xf2, 0x83, 0x49, 0x79,
+ 0xe6, 0xb9, 0x88, 0xd2, 0x0a, 0x94, 0x92, 0x49, 0x04, 0xe8, 0x13, 0x5d,
+ 0xf9, 0x63, 0xb3, 0x31, 0x0b, 0x94, 0x4c, 0x8e, 0x52, 0xee, 0x39, 0x2c,
+ 0x34, 0x32, 0xb6, 0x63, 0xb6, 0xe2, 0x5a, 0x2e, 0xb0, 0xfa, 0x88, 0x25,
+ 0x69, 0xe5, 0x4a, 0x76, 0x14, 0x84, 0xab, 0x43, 0x5b, 0xd8, 0xe5, 0x1f,
+ 0x0c, 0x01, 0x9c, 0x9e, 0xe9, 0x6e, 0xca, 0xd8, 0xb6, 0x2b, 0x1e, 0x91,
+ 0x2d, 0x37, 0x49, 0x0a, 0x53, 0x29, 0xec, 0x42, 0x98, 0x7d, 0x31, 0x5c,
+ 0x1c, 0xae, 0xa9, 0x5b, 0x4e, 0xdb, 0x48, 0xe8, 0xa0, 0xa5, 0x27, 0xe1,
+ 0xa1, 0x3a, 0x07, 0xb8, 0xc6, 0xfd, 0x42, 0xc6, 0x76, 0x3d, 0x64, 0xb1,
+ 0xe7, 0x5a, 0x97, 0x6b, 0x39, 0x1c, 0x86, 0x6e, 0x78, 0xf2, 0x0a, 0xca,
+ 0xe3, 0x46, 0x83, 0xc8, 0x90, 0xf2, 0x53, 0xef, 0x2d, 0xf2, 0x02, 0x79,
+ 0x9b, 0x24, 0x10, 0x90, 0x7f, 0x3f, 0x90, 0x75, 0xde, 0x86, 0xcc, 0xc2,
+ 0xe3, 0x68, 0xbb, 0xe1, 0xd0, 0x32, 0x4b, 0x1c, 0x94, 0xa2, 0x53, 0x0b,
+ 0x47, 0xb9, 0x6e, 0xb2, 0x00, 0x52, 0xcb, 0xba, 0x4a, 0x99, 0x6f, 0xa6,
+ 0x94, 0x54, 0x9d, 0x8d, 0x0e, 0xe2, 0x90, 0x7f, 0x36, 0xb8, 0x15, 0xee,
+ 0xd0, 0xb6, 0x44, 0xc7, 0xf2, 0x89, 0x6e, 0x2c, 0x95, 0x36, 0xeb, 0xad,
+ 0x36, 0x80, 0xf4, 0xd9, 0x49, 0x6d, 0x61, 0x49, 0x09, 0x6d, 0x91, 0xca,
+ 0xda, 0x76, 0x9d, 0x15, 0x92, 0x77, 0xa3, 0xd1, 0x35, 0xd7, 0x60, 0xb7,
+ 0xc4, 0xb9, 0xde, 0x64, 0x2e, 0xc0, 0xc3, 0xb6, 0x56, 0xe0, 0x14, 0xc7,
+ 0x7a, 0x4c, 0xb6, 0xd4, 0xec, 0xd4, 0xb8, 0xa4, 0xf3, 0x29, 0xa6, 0xbb,
+ 0x62, 0xa0, 0xd2, 0x42, 0x54, 0x36, 0x40, 0x21, 0x5b, 0xe9, 0xd0, 0x6c,
+ 0xb6, 0x5c, 0x05, 0x97, 0xc9, 0xcf, 0x70, 0x99, 0x7b, 0x7b, 0x11, 0x36,
+ 0x5c, 0x91, 0xf4, 0xc6, 0x0f, 0x28, 0x33, 0x26, 0xe5, 0x35, 0x86, 0xe3,
+ 0x02, 0x90, 0xa1, 0xd1, 0x96, 0x50, 0xe2, 0xd4, 0xb7, 0x48, 0x1b, 0x04,
+ 0x10, 0x90, 0x41, 0x23, 0xc0, 0x52, 0xde, 0x39, 0x78, 0xb7, 0xe1, 0x7c,
+ 0x74, 0x90, 0xc4, 0x09, 0x04, 0xe2, 0xd9, 0xd3, 0xca, 0x5a, 0x02, 0x90,
+ 0xa4, 0x08, 0x77, 0x94, 0x24, 0x17, 0x10, 0x52, 0xad, 0x29, 0x3d, 0xb3,
+ 0x7a, 0x5f, 0x51, 0xd5, 0x43, 0xa7, 0x4a, 0x6d, 0x9c, 0x6e, 0x18, 0xbe,
+ 0x47, 0x32, 0x53, 0xd1, 0x65, 0xe4, 0xd2, 0x9c, 0x8a, 0x85, 0xda, 0x82,
+ 0x8b, 0x61, 0xfe, 0xc5, 0xb5, 0x7f, 0x38, 0x69, 0x04, 0x04, 0x82, 0xe0,
+ 0x0b, 0xe7, 0x1d, 0x01, 0x58, 0xd2, 0x76, 0x4a, 0x77, 0x4b, 0xfc, 0x51,
+ 0xb1, 0x46, 0xe2, 0x4c, 0x66, 0xad, 0xb6, 0xc4, 0x49, 0xb7, 0xde, 0x25,
+ 0xc5, 0x53, 0xea, 0xed, 0x11, 0xca, 0xec, 0x07, 0x99, 0xdb, 0x91, 0x24,
+ 0x38, 0x01, 0xf3, 0x16, 0x1c, 0xf3, 0x40, 0xef, 0x52, 0x1d, 0x5f, 0x78,
+ 0x1d, 0x0f, 0x7d, 0xc2, 0xc7, 0x05, 0xcc, 0x93, 0xb1, 0xba, 0xcd, 0x23,
+ 0xf0, 0x57, 0x34, 0x73, 0x36, 0xc1, 0x63, 0xcf, 0x9e, 0xcf, 0x92, 0xde,
+ 0xa1, 0x2d, 0x50, 0x2f, 0x31, 0x08, 0xd2, 0x98, 0x9a, 0xd1, 0xe5, 0x71,
+ 0x24, 0x78, 0x02, 0x7c, 0xe1, 0xea, 0x50, 0xf4, 0x53, 0xc0, 0xa8, 0x24,
+ 0x44, 0xe3, 0x2f, 0xc4, 0xb1, 0x7f, 0xda, 0xab, 0x67, 0xdf, 0x8a, 0x7b,
+ 0xa4, 0x4e, 0x32, 0xfc, 0x4b, 0x17, 0xfd, 0xaa, 0xb6, 0x7d, 0xf8, 0xa7,
+ 0xba, 0x00, 0xa2, 0x8a, 0x28, 0x02, 0x93, 0x38, 0xe3, 0xf2, 0x3d, 0x97,
+ 0x7d, 0x11, 0x23, 0xf8, 0x0d, 0x39, 0xd2, 0x67, 0x1c, 0x7e, 0x47, 0xb2,
+ 0xef, 0xa2, 0x24, 0x7f, 0x01, 0xa0, 0x1b, 0xe3, 0x7c, 0x5d, 0xbf, 0x98,
+ 0x3e, 0xca, 0xd9, 0x5a, 0xe3, 0x7c, 0x5d, 0xbf, 0x98, 0x3e, 0xca, 0xd9,
+ 0x40, 0x14, 0x51, 0x45, 0x00, 0x56, 0xb9, 0x0d, 0xb4, 0xfb, 0x4e, 0x32,
+ 0xf3, 0x68, 0x75, 0xb7, 0x12, 0x52, 0xb4, 0x28, 0x6c, 0x28, 0x11, 0xd4,
+ 0x11, 0xe8, 0x22, 0xb6, 0x50, 0x46, 0xe8, 0x0f, 0x8d, 0xe5, 0x43, 0x93,
+ 0xc2, 0x6e, 0x21, 0xcb, 0xb4, 0x27, 0xb7, 0xec, 0xf1, 0xc4, 0xae, 0x75,
+ 0xb1, 0x5d, 0x49, 0x99, 0x8f, 0xbe, 0xef, 0x33, 0xec, 0x8e, 0xed, 0xae,
+ 0x2b, 0xa7, 0xb6, 0x1f, 0xaa, 0x1d, 0xf0, 0xd5, 0x7d, 0x29, 0x22, 0xf4,
+ 0xed, 0xd8, 0x5a, 0x62, 0xc4, 0xbb, 0xa2, 0xdf, 0x1e, 0x63, 0x2b, 0x71,
+ 0xf9, 0x6d, 0xf2, 0xa9, 0x6a, 0xd1, 0x6d, 0x29, 0x43, 0x65, 0x5b, 0x00,
+ 0xab, 0xb4, 0x07, 0x98, 0x82, 0x75, 0xad, 0x75, 0x3b, 0x0b, 0x5f, 0x84,
+ 0xc6, 0x29, 0x2e, 0xed, 0x89, 0xc7, 0xcb, 0x2c, 0x31, 0x9b, 0x7b, 0x23,
+ 0xc5, 0x5c, 0x55, 0xc2, 0x23, 0x6b, 0x40, 0x50, 0x94, 0xc7, 0x2e, 0xa4,
+ 0x46, 0x50, 0xf1, 0x43, 0x8d, 0xf3, 0x02, 0x9f, 0x1d, 0x6b, 0xc6, 0xab,
+ 0xbe, 0x0f, 0x3f, 0x65, 0xc8, 0xac, 0xab, 0xc1, 0x9e, 0x90, 0xe2, 0xed,
+ 0x6a, 0x8e, 0xdd, 0xc7, 0x1e, 0x92, 0xb5, 0xed, 0xc1, 0x01, 0xd5, 0x1e,
+ 0xcd, 0x25, 0x43, 0x47, 0x99, 0x87, 0x02, 0x98, 0x5e, 0x88, 0x20, 0xa1,
+ 0x27, 0x7d, 0xc6, 0xb5, 0x87, 0x7a, 0x3a, 0x4c, 0xa7, 0xdd, 0x96, 0xaf,
+ 0xcc, 0xb5, 0xf3, 0x08, 0xa7, 0x0b, 0x76, 0x26, 0x59, 0x1d, 0x37, 0x0b,
+ 0xac, 0x78, 0xad, 0xad, 0x87, 0xe3, 0x48, 0x96, 0xb7, 0x8a, 0x14, 0xe1,
+ 0x48, 0x4b, 0xc8, 0x2e, 0x12, 0x42, 0xb6, 0x02, 0x08, 0x04, 0x0d, 0x2f,
+ 0x7a, 0x1a, 0x3b, 0xf5, 0x93, 0xdd, 0x6d, 0x19, 0x44, 0x68, 0x11, 0xec,
+ 0xaa, 0x71, 0xfb, 0xa0, 0x79, 0xb5, 0x32, 0x1a, 0x0a, 0x4a, 0x98, 0x69,
+ 0x7a, 0x4b, 0xa5, 0xc2, 0x9e, 0xad, 0xa0, 0xb4, 0xa5, 0x8e, 0xba, 0x24,
+ 0x81, 0xad, 0x90, 0x35, 0xc9, 0x0a, 0xc9, 0x72, 0x6a, 0x5a, 0x2c, 0xad,
+ 0xca, 0x7a, 0xfc, 0x6d, 0xa5, 0x0b, 0x59, 0x94, 0xe2, 0x9a, 0x8a, 0xd3,
+ 0x9a, 0xe6, 0x41, 0x74, 0xa8, 0xad, 0xc7, 0xdc, 0xd6, 0x94, 0x13, 0xbe,
+ 0x51, 0xb0, 0x4e, 0x8e, 0xb5, 0xee, 0x0a, 0x2d, 0xe6, 0xf5, 0x22, 0xd3,
+ 0x96, 0x08, 0x76, 0xce, 0x49, 0x0d, 0x31, 0x0a, 0xd9, 0x11, 0xc2, 0xd4,
+ 0x59, 0x5c, 0xe8, 0x2a, 0x0e, 0xe8, 0x04, 0x95, 0x95, 0x14, 0x38, 0x9e,
+ 0x53, 0xb0, 0x9e, 0xcc, 0x8e, 0xbb, 0xd9, 0xcf, 0x2b, 0x84, 0x69, 0xbf,
+ 0x2c, 0xe7, 0x72, 0xdf, 0x77, 0x65, 0x11, 0xb1, 0xdb, 0xc2, 0x9c, 0xba,
+ 0x3e, 0x5b, 0x42, 0x9f, 0x62, 0x22, 0xbb, 0x67, 0xe5, 0x34, 0x95, 0x12,
+ 0x90, 0xeb, 0xab, 0x4b, 0x6d, 0xb2, 0xd9, 0x29, 0x00, 0xe8, 0x6d, 0x5a,
+ 0x3a, 0x3d, 0xf5, 0xd1, 0x6f, 0x66, 0x12, 0xf2, 0x09, 0x76, 0xf5, 0x5b,
+ 0x93, 0x88, 0x88, 0xec, 0xb6, 0xb9, 0x09, 0x8d, 0xd9, 0x87, 0xe5, 0x17,
+ 0x56, 0xae, 0x50, 0xdb, 0xa9, 0xea, 0x1a, 0xf3, 0x34, 0x79, 0x79, 0x4f,
+ 0x31, 0xd6, 0xc6, 0xba, 0xe9, 0xbf, 0x2d, 0x78, 0x54, 0xe9, 0x0e, 0x63,
+ 0x22, 0x0a, 0x18, 0xba, 0x21, 0x12, 0x5a, 0x43, 0xc5, 0x7d, 0x92, 0x0b,
+ 0x2b, 0x42, 0x5d, 0x68, 0x29, 0x29, 0x57, 0x66, 0x85, 0x25, 0xcd, 0xa5,
+ 0x5a, 0x29, 0x42, 0x81, 0xd8, 0x00, 0xf4, 0x32, 0x26, 0x1a, 0xce, 0x13,
+ 0x01, 0xe9, 0x2d, 0xb5, 0x02, 0x23, 0x1c, 0xe1, 0xdb, 0x83, 0xe9, 0x53,
+ 0x4d, 0xad, 0x4a, 0xe5, 0x28, 0x6d, 0xad, 0xa9, 0x0a, 0x59, 0x0b, 0x4a,
+ 0x55, 0xce, 0x92, 0x91, 0xe6, 0x8e, 0x52, 0x77, 0x53, 0xcf, 0x21, 0x7a,
+ 0x1b, 0x72, 0x36, 0x64, 0xe1, 0x73, 0xdd, 0xba, 0x59, 0x48, 0x96, 0x99,
+ 0x90, 0xcc, 0x78, 0x88, 0x9f, 0x35, 0x4a, 0x4c, 0x77, 0x9b, 0x25, 0xd5,
+ 0x36, 0x97, 0x1c, 0x3d, 0x03, 0x88, 0x0b, 0xd6, 0xce, 0x82, 0xd0, 0x91,
+ 0xd0, 0x1e, 0x9a, 0x72, 0x67, 0xd9, 0xcf, 0x1a, 0x83, 0x12, 0x04, 0x1e,
+ 0x69, 0x6b, 0x49, 0x4c, 0xa1, 0xdb, 0x10, 0x18, 0x8e, 0xb4, 0x12, 0xa4,
+ 0x3c, 0xb4, 0x6c, 0x21, 0x5c, 0xe9, 0x6d, 0x49, 0x48, 0x25, 0x41, 0x48,
+ 0x0a, 0xd6, 0x87, 0x5e, 0xeb, 0x5c, 0x2b, 0x8c, 0x9b, 0x82, 0x9e, 0x87,
+ 0x1d, 0xab, 0xc1, 0x82, 0xa7, 0x18, 0x44, 0x89, 0x4a, 0xf2, 0x58, 0x2d,
+ 0x2f, 0x5c, 0xae, 0x06, 0x9a, 0x48, 0x52, 0x9c, 0x57, 0x52, 0x92, 0xb5,
+ 0x6f, 0xf3, 0x82, 0x4f, 0x78, 0xad, 0x56, 0x85, 0xda, 0x2e, 0x4b, 0x2c,
+ 0xe4, 0xea, 0x4c, 0x17, 0x55, 0x31, 0xf8, 0x91, 0xec, 0xa8, 0x7f, 0xb3,
+ 0x8e, 0xc1, 0x6b, 0x44, 0xec, 0x23, 0x41, 0xc2, 0x52, 0x52, 0xbe, 0x65,
+ 0x7e, 0x6a, 0xc6, 0x80, 0xa8, 0xf4, 0x43, 0x18, 0xdd, 0x9e, 0x11, 0x1e,
+ 0x43, 0x92, 0x23, 0x59, 0x27, 0x34, 0xe5, 0xe0, 0x5b, 0x56, 0x97, 0x15,
+ 0x02, 0x17, 0xbe, 0x6d, 0xc0, 0x9f, 0x35, 0x72, 0xa4, 0x3a, 0x10, 0x92,
+ 0xad, 0x1e, 0x60, 0x80, 0x12, 0x49, 0xd1, 0xea, 0x3a, 0x57, 0x45, 0x85,
+ 0x16, 0xfb, 0x83, 0xaf, 0xb6, 0xe1, 0x56, 0x35, 0x08, 0x4f, 0x30, 0xda,
+ 0xb5, 0x45, 0xe4, 0x88, 0xe3, 0xaf, 0x21, 0x1c, 0xca, 0xed, 0x16, 0xd9,
+ 0xd9, 0x24, 0x12, 0x52, 0x10, 0xa0, 0x39, 0x00, 0x3e, 0x76, 0xfa, 0x46,
+ 0x48, 0xbb, 0xcb, 0xc2, 0x2e, 0x09, 0xb5, 0xdb, 0x5c, 0x81, 0x22, 0x02,
+ 0xe5, 0x19, 0xc9, 0x12, 0xa5, 0x76, 0x6b, 0x7a, 0x3b, 0xdc, 0xc1, 0x49,
+ 0xed, 0x57, 0xb1, 0xce, 0xda, 0xd3, 0xd0, 0x28, 0xf9, 0xe8, 0x20, 0x03,
+ 0xb4, 0x9a, 0xd3, 0x92, 0xa6, 0xdd, 0x7e, 0x9a, 0xf5, 0xc6, 0xe8, 0x20,
+ 0x43, 0xb7, 0x4a, 0x69, 0xa4, 0xa5, 0xb9, 0xb0, 0x9c, 0x71, 0x73, 0x9e,
+ 0x6d, 0x4b, 0xe5, 0x75, 0x96, 0x92, 0xa4, 0xbd, 0xb4, 0xa5, 0x5a, 0x0b,
+ 0x1a, 0x2a, 0xde, 0x80, 0x29, 0xd1, 0xa9, 0xf5, 0x61, 0x3e, 0x88, 0x90,
+ 0x7e, 0x65, 0xc3, 0x0d, 0xbb, 0xdc, 0x59, 0x86, 0xca, 0x2f, 0x0e, 0xca,
+ 0x71, 0xb9, 0x6d, 0x2a, 0x54, 0xb0, 0x97, 0xde, 0x8a, 0x90, 0x1b, 0x53,
+ 0x08, 0x5a, 0xf4, 0x14, 0xe3, 0x6a, 0x01, 0x40, 0x28, 0xf9, 0xc9, 0x5f,
+ 0x53, 0xbe, 0xfe, 0x6b, 0xec, 0x37, 0x33, 0x5b, 0xda, 0x24, 0x58, 0x5b,
+ 0x7e, 0x32, 0xd2, 0xca, 0x57, 0x2e, 0x43, 0x72, 0x43, 0x69, 0x6d, 0xf6,
+ 0xd6, 0x92, 0xc8, 0x0e, 0xa5, 0x2b, 0x47, 0x6c, 0x02, 0x9d, 0x49, 0xd0,
+ 0x58, 0x01, 0x5a, 0x3f, 0x9b, 0xae, 0xeb, 0x65, 0xb6, 0xec, 0x51, 0x22,
+ 0x6f, 0xf2, 0x69, 0x37, 0x2e, 0x66, 0x12, 0x82, 0x6e, 0xce, 0xa1, 0x82,
+ 0xe3, 0x60, 0xf3, 0x76, 0x4c, 0xb0, 0x94, 0xa8, 0x36, 0x36, 0x01, 0xf3,
+ 0xc8, 0x24, 0xeb, 0x98, 0x9d, 0x74, 0xf3, 0x61, 0x56, 0x35, 0x77, 0x66,
+ 0xdc, 0x9b, 0xf4, 0xe5, 0xbd, 0x71, 0x9b, 0x0d, 0x52, 0xd9, 0x88, 0x1d,
+ 0x5b, 0x4c, 0xc4, 0x6c, 0x1e, 0x55, 0x21, 0xb4, 0x20, 0x84, 0xa4, 0xb6,
+ 0x4f, 0x29, 0x3d, 0x55, 0xb4, 0xf7, 0xd1, 0x79, 0x24, 0x1e, 0xdb, 0xb3,
+ 0xc3, 0x71, 0xdd, 0xb9, 0xcd, 0xd4, 0xfb, 0x5b, 0x99, 0x2f, 0x90, 0xa5,
+ 0x6c, 0x25, 0x86, 0x02, 0x53, 0x15, 0x85, 0x13, 0xa7, 0x09, 0x75, 0xd2,
+ 0x0b, 0xce, 0xf4, 0xd7, 0x9a, 0x00, 0x4f, 0x51, 0xa4, 0x9a, 0xdf, 0x89,
+ 0x37, 0x6f, 0xbb, 0xc7, 0x42, 0x3c, 0xb1, 0xfb, 0x2b, 0x4f, 0x17, 0x9c,
+ 0x62, 0xcf, 0x0b, 0xf9, 0xa2, 0xda, 0x4a, 0x16, 0x5b, 0x2a, 0x78, 0xa7,
+ 0xcf, 0x53, 0x9b, 0x1e, 0x77, 0x50, 0x90, 0x7a, 0x10, 0x7b, 0xcc, 0x6d,
+ 0xbf, 0x2c, 0x95, 0x88, 0xcf, 0x67, 0x19, 0x7a, 0x33, 0x52, 0x60, 0xc2,
+ 0x0b, 0x60, 0xcb, 0x0b, 0xf3, 0xc9, 0x3c, 0xae, 0x34, 0xe2, 0x81, 0xea,
+ 0xbd, 0xa1, 0x7a, 0x50, 0x47, 0x32, 0xf9, 0x82, 0x8f, 0x2e, 0x88, 0xae,
+ 0x94, 0x61, 0xf2, 0xb2, 0x0b, 0xf3, 0xd9, 0x2a, 0xa1, 0xb1, 0x6c, 0x25,
+ 0xd4, 0xb9, 0x19, 0x32, 0x59, 0x74, 0x39, 0xbe, 0x44, 0x87, 0x1c, 0x28,
+ 0x6d, 0xd4, 0x68, 0x28, 0xa1, 0x3e, 0xf6, 0xe7, 0x36, 0xf9, 0x41, 0x20,
+ 0x12, 0x45, 0x31, 0xd5, 0x8c, 0xf4, 0x42, 0x54, 0x59, 0xb2, 0x78, 0x6b,
+ 0xc7, 0x74, 0xcc, 0x9a, 0xe9, 0x5d, 0x9b, 0x27, 0x71, 0x9b, 0x6d, 0xd5,
+ 0xfe, 0x81, 0x02, 0x61, 0x49, 0xf2, 0x39, 0x67, 0xb8, 0x02, 0xea, 0x12,
+ 0xa6, 0x96, 0x75, 0xd5, 0x6d, 0x95, 0x78, 0x81, 0x5f, 0x42, 0x27, 0xaa,
+ 0x77, 0x55, 0xf6, 0x4d, 0x82, 0xda, 0x72, 0x0b, 0x15, 0xdf, 0x11, 0xb9,
+ 0xba, 0xec, 0xd7, 0x2f, 0x11, 0xb9, 0xe5, 0xce, 0x70, 0x8e, 0xd5, 0xb7,
+ 0x11, 0xae, 0xc9, 0x68, 0x4a, 0x40, 0x08, 0x08, 0x57, 0x54, 0x81, 0xad,
+ 0x7a, 0xce, 0xc9, 0xcf, 0x00, 0xb2, 0x4b, 0xae, 0x43, 0xc3, 0xe4, 0x35,
+ 0x90, 0x68, 0xdf, 0x6c, 0xb2, 0xdf, 0xb3, 0xdd, 0x17, 0xbd, 0x87, 0x24,
+ 0x47, 0x57, 0x21, 0x5e, 0xff, 0x00, 0x58, 0x72, 0xa8, 0xfa, 0xc9, 0xa8,
+ 0x69, 0xa0, 0x9a, 0x66, 0xee, 0x32, 0xfc, 0x4b, 0x17, 0xfd, 0xaa, 0xb6,
+ 0x7d, 0xf8, 0xa7, 0xba, 0x44, 0xe3, 0x27, 0xc4, 0x71, 0x7f, 0xda, 0xab,
+ 0x67, 0xdf, 0x8a, 0x7b, 0xa8, 0x24, 0x28, 0xac, 0x6f, 0x47, 0xa9, 0x14,
+ 0x50, 0x19, 0xa4, 0xce, 0x38, 0xfc, 0x8f, 0x65, 0xdf, 0x44, 0x48, 0xfe,
+ 0x03, 0x4e, 0x74, 0x99, 0xc7, 0x1f, 0x91, 0xec, 0xbb, 0xe8, 0x89, 0x1f,
+ 0xc0, 0x68, 0x06, 0xf8, 0xdf, 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x56,
+ 0xb8, 0xdf, 0x17, 0x6f, 0xe6, 0x0f, 0xb2, 0xb6, 0x50, 0x05, 0x14, 0x51,
+ 0x40, 0x14, 0x51, 0x45, 0x01, 0xe5, 0x40, 0x6f, 0x64, 0x6f, 0xd1, 0x5f,
+ 0x22, 0x66, 0x56, 0x29, 0x9c, 0x37, 0xe2, 0x5c, 0xbb, 0x55, 0xa9, 0x82,
+ 0x5b, 0x8c, 0xb7, 0xf2, 0x4c, 0x5d, 0xa1, 0xd0, 0x48, 0x8c, 0xa1, 0xfe,
+ 0x93, 0xb6, 0xa7, 0xfe, 0x11, 0xdb, 0x20, 0x78, 0x14, 0x0e, 0xf2, 0xaa,
+ 0xfa, 0xf7, 0x5d, 0x77, 0x55, 0xa7, 0xe1, 0x11, 0x88, 0x4f, 0xc9, 0xb0,
+ 0x74, 0xdc, 0x71, 0xef, 0x33, 0x28, 0xc7, 0xa4, 0x26, 0xeb, 0x65, 0x74,
+ 0x0d, 0xab, 0xb6, 0x6f, 0xaa, 0x9b, 0xf5, 0x85, 0xa4, 0x14, 0xeb, 0xb8,
+ 0x9d, 0x6e, 0xa5, 0x3c, 0x3c, 0xa2, 0x1a, 0xca, 0xc3, 0x39, 0x58, 0xbc,
+ 0x5c, 0x6e, 0xb6, 0x06, 0xb2, 0x1c, 0x4e, 0x63, 0xef, 0xa2, 0x77, 0x93,
+ 0xcb, 0x0e, 0x34, 0xc7, 0x6c, 0x95, 0x72, 0xa4, 0x75, 0x5a, 0x01, 0xe6,
+ 0x28, 0x71, 0xbd, 0x24, 0x94, 0xed, 0x49, 0x52, 0x47, 0x4e, 0xfa, 0xd3,
+ 0x96, 0x47, 0xb7, 0x64, 0x13, 0xe3, 0x9c, 0xae, 0xe2, 0xdd, 0x99, 0xb8,
+ 0xcc, 0xa8, 0x30, 0xdb, 0xaa, 0x6f, 0xca, 0x9c, 0x25, 0x6d, 0xac, 0x38,
+ 0xe2, 0x13, 0xcc, 0x1a, 0x6d, 0x1d, 0x98, 0xd1, 0xde, 0xf6, 0x49, 0x25,
+ 0x3d, 0xc5, 0x03, 0xf0, 0x78, 0xcc, 0xa0, 0xc7, 0xb8, 0xb7, 0x12, 0x22,
+ 0x15, 0x12, 0xcd, 0x7a, 0x4b, 0x97, 0x2b, 0x43, 0x24, 0x79, 0xb1, 0xce,
+ 0xff, 0x00, 0x9e, 0xc2, 0xf5, 0x16, 0x5e, 0x25, 0x49, 0x4f, 0xe8, 0x2d,
+ 0x26, 0xad, 0x7c, 0x66, 0xfd, 0x6a, 0xb2, 0x3b, 0x02, 0xc3, 0x36, 0xdd,
+ 0x26, 0x3c, 0xc9, 0xcd, 0x6d, 0xd9, 0x4b, 0x68, 0xac, 0x4b, 0x94, 0x14,
+ 0xa0, 0xe2, 0x54, 0xb1, 0xf0, 0x96, 0x48, 0xe6, 0xd1, 0xef, 0x4a, 0x86,
+ 0xba, 0x77, 0x6b, 0x35, 0x9c, 0x38, 0xf5, 0x32, 0x83, 0x4b, 0x2a, 0x5d,
+ 0x0f, 0x78, 0xcc, 0x5b, 0xbc, 0x80, 0x6f, 0x96, 0x64, 0x44, 0x58, 0x7d,
+ 0xae, 0x56, 0x27, 0x5d, 0x54, 0xa7, 0x1e, 0x92, 0xd7, 0x7a, 0x42, 0x10,
+ 0xdf, 0x2a, 0x18, 0x69, 0x47, 0x44, 0x72, 0xef, 0x7d, 0x09, 0x4e, 0xc5,
+ 0x73, 0xe3, 0x32, 0xb1, 0xb9, 0x8e, 0xc6, 0x56, 0x4d, 0xe4, 0xf2, 0x32,
+ 0x19, 0xa2, 0x40, 0x75, 0xb9, 0xa9, 0x0b, 0x0c, 0xa9, 0xa5, 0x00, 0xeb,
+ 0x0d, 0x85, 0x0d, 0x24, 0x24, 0x29, 0x3d, 0xc3, 0x6a, 0x1a, 0x51, 0xde,
+ 0xf7, 0x51, 0x96, 0xd5, 0x5e, 0xe3, 0xde, 0x55, 0xfc, 0x9a, 0x7e, 0x74,
+ 0xcb, 0x04, 0x27, 0x9d, 0x8b, 0x1d, 0x2d, 0x21, 0xa5, 0x32, 0xa6, 0xb9,
+ 0x42, 0xf4, 0x87, 0x16, 0xe2, 0x79, 0x3b, 0x35, 0xa9, 0x48, 0xe7, 0xd2,
+ 0xd2, 0x52, 0x90, 0x06, 0x94, 0x9e, 0xba, 0xe7, 0x2b, 0x1d, 0x94, 0xd4,
+ 0xab, 0xcd, 0xf6, 0x6b, 0xd2, 0xa6, 0x2e, 0x68, 0x7d, 0x84, 0x5b, 0x3b,
+ 0x43, 0x19, 0x2f, 0x04, 0x25, 0xb6, 0x9a, 0x43, 0xfc, 0xbc, 0x85, 0xd2,
+ 0x12, 0x91, 0xce, 0x0a, 0x4e, 0xce, 0x86, 0x87, 0x4a, 0xc9, 0x63, 0x93,
+ 0x5d, 0xfa, 0x1b, 0x99, 0x99, 0x79, 0xc7, 0xee, 0xc6, 0xcf, 0x8c, 0x29,
+ 0x32, 0x6d, 0x96, 0xd7, 0xc8, 0xf2, 0x61, 0x15, 0xd7, 0x90, 0x58, 0x7c,
+ 0x07, 0x12, 0x9e, 0x66, 0xc2, 0x8a, 0x5d, 0x41, 0xe6, 0xd7, 0x30, 0xe5,
+ 0x52, 0x14, 0x01, 0x20, 0xf5, 0x39, 0xbd, 0xc6, 0x6a, 0xeb, 0x75, 0x91,
+ 0x26, 0xe6, 0x86, 0xd8, 0x9a, 0xe9, 0x8e, 0xa6, 0x2d, 0x6d, 0xc2, 0x6a,
+ 0x74, 0x82, 0xa6, 0x82, 0xf9, 0x5e, 0x71, 0x07, 0x61, 0xa5, 0xf9, 0xe3,
+ 0x4a, 0xe6, 0x00, 0x04, 0xf5, 0x27, 0xc2, 0x55, 0xfb, 0x06, 0x4f, 0x1b,
+ 0x17, 0x96, 0xcd, 0x9a, 0xe1, 0x02, 0xdf, 0x24, 0x36, 0xa5, 0x26, 0xdb,
+ 0x0d, 0x80, 0x5b, 0x20, 0xef, 0x69, 0x53, 0xaa, 0x3c, 0xea, 0x75, 0x49,
+ 0xfe, 0x93, 0xcd, 0xf3, 0xba, 0x90, 0x6b, 0x7c, 0x0c, 0xab, 0x1e, 0xb2,
+ 0xdb, 0x10, 0xa8, 0x16, 0x0b, 0xb3, 0x76, 0xf7, 0x58, 0x4c, 0x96, 0x5c,
+ 0x85, 0x6c, 0x75, 0xf4, 0x39, 0xcc, 0x3c, 0xee, 0x65, 0x36, 0x93, 0xca,
+ 0xe0, 0x20, 0x85, 0x73, 0x90, 0x7a, 0x6f, 0x7a, 0xeb, 0x4c, 0x92, 0x92,
+ 0x36, 0x58, 0xf1, 0xfb, 0xe8, 0x71, 0xe7, 0xd7, 0x2c, 0x5a, 0xd7, 0x2b,
+ 0x97, 0xb7, 0x79, 0x4b, 0x12, 0x67, 0x3a, 0x90, 0x4e, 0x92, 0x56, 0x40,
+ 0x69, 0xa0, 0x37, 0xf0, 0x50, 0x82, 0x91, 0xb3, 0xae, 0xbb, 0x35, 0x3f,
+ 0x6c, 0xb4, 0xda, 0x2c, 0x85, 0xd7, 0xd9, 0x6c, 0x99, 0x2b, 0x47, 0xbf,
+ 0x49, 0x79, 0x6a, 0x75, 0xf7, 0x40, 0xfd, 0x25, 0x2b, 0x6a, 0x23, 0xd5,
+ 0xdd, 0xe8, 0x14, 0x82, 0xac, 0xc3, 0x3a, 0xcb, 0xd6, 0x23, 0xe1, 0xf6,
+ 0x2f, 0x72, 0x20, 0x13, 0xa5, 0x5c, 0x66, 0x29, 0x0e, 0xb8, 0x47, 0x4f,
+ 0x82, 0x06, 0xda, 0x49, 0xf5, 0xed, 0xd2, 0x3c, 0x51, 0xba, 0x9b, 0xc6,
+ 0xb8, 0x7e, 0x98, 0xf1, 0x94, 0x6f, 0xf7, 0x17, 0xee, 0x2e, 0x3e, 0x42,
+ 0xa4, 0x36, 0x1d, 0x51, 0x4b, 0xe7, 0xfd, 0xaa, 0xcf, 0x9e, 0xe8, 0xfd,
+ 0x52, 0x43, 0x7e, 0x84, 0x01, 0xa1, 0x50, 0x49, 0x2e, 0xac, 0xba, 0xd9,
+ 0x21, 0x45, 0x8b, 0x33, 0x32, 0xaf, 0x32, 0x47, 0x9a, 0x5a, 0x88, 0xdf,
+ 0x44, 0x1f, 0xd7, 0x5a, 0xb4, 0x94, 0x7b, 0x14, 0x77, 0xea, 0xa8, 0x36,
+ 0x30, 0x69, 0x97, 0x15, 0x22, 0x7d, 0xd6, 0x44, 0x68, 0x72, 0x7c, 0xbd,
+ 0xc9, 0xcd, 0xc7, 0x66, 0x3b, 0x72, 0x04, 0x45, 0x2f, 0x5f, 0x93, 0x71,
+ 0xc4, 0xed, 0x2b, 0x3a, 0xda, 0xba, 0x14, 0xec, 0x9e, 0x9e, 0x25, 0xbd,
+ 0xd9, 0x16, 0xbb, 0x34, 0x34, 0x30, 0x90, 0xcc, 0x66, 0x90, 0x34, 0xdb,
+ 0x2d, 0x20, 0x0d, 0x7a, 0x82, 0x45, 0x25, 0x66, 0xbc, 0x47, 0xb7, 0x59,
+ 0x5b, 0x6c, 0x4a, 0x96, 0x88, 0x21, 0xf3, 0xca, 0xc3, 0x41, 0x25, 0xd9,
+ 0x2f, 0x9f, 0x43, 0x6d, 0xa7, 0x6a, 0x51, 0xf5, 0x24, 0x13, 0xec, 0xad,
+ 0x69, 0xd1, 0x94, 0xf7, 0x5c, 0x79, 0x98, 0xce, 0xb4, 0x61, 0xb7, 0x51,
+ 0xb6, 0x0c, 0x6b, 0x46, 0x37, 0x01, 0x4d, 0xa5, 0xd5, 0x24, 0xb8, 0xe1,
+ 0x75, 0xd7, 0x1e, 0x70, 0xb8, 0xf3, 0xee, 0x10, 0x01, 0x5a, 0x89, 0xea,
+ 0xa5, 0x74, 0x03, 0xd0, 0x00, 0x00, 0x68, 0x00, 0x2a, 0x26, 0xe5, 0x92,
+ 0x3c, 0xf7, 0xbd, 0x42, 0x41, 0x65, 0x04, 0xeb, 0x9c, 0x80, 0x54, 0x7d,
+ 0x9e, 0x03, 0xed, 0xaa, 0xba, 0xff, 0x00, 0x94, 0x5c, 0xa3, 0x34, 0xdd,
+ 0xeb, 0x2c, 0x9f, 0x17, 0x03, 0xc7, 0xcf, 0x9c, 0xa9, 0x17, 0x87, 0x02,
+ 0xee, 0x72, 0x87, 0xa1, 0x98, 0xe9, 0x27, 0x93, 0x7d, 0xdb, 0x57, 0x31,
+ 0xd7, 0xe6, 0x8a, 0x81, 0xfc, 0x6e, 0x66, 0x19, 0xb3, 0x6e, 0xc3, 0xe0,
+ 0x16, 0x07, 0x22, 0x5b, 0x68, 0xf3, 0x1e, 0xc8, 0xaf, 0x49, 0x4b, 0x4c,
+ 0xa3, 0xae, 0xbd, 0xed, 0x2a, 0x20, 0x28, 0xf8, 0xf5, 0x3b, 0xfd, 0x4a,
+ 0xd5, 0x7b, 0xaa, 0x5b, 0xbe, 0xf3, 0xfd, 0x0c, 0xa4, 0xab, 0x55, 0xf4,
+ 0x45, 0xb9, 0x75, 0xc9, 0x2c, 0x7c, 0x3c, 0xc5, 0xa7, 0x65, 0x59, 0x7d,
+ 0xc1, 0xb8, 0x2c, 0x84, 0x79, 0x89, 0x71, 0x5e, 0xfa, 0xf1, 0xd7, 0x44,
+ 0x21, 0x3d, 0xea, 0x52, 0x8e, 0xb4, 0x3c, 0x3b, 0xfb, 0xb6, 0x6b, 0x9b,
+ 0xf0, 0x6f, 0xb3, 0x5c, 0xed, 0xbc, 0x37, 0x17, 0x5b, 0xdb, 0x45, 0x9b,
+ 0xae, 0x47, 0x3a, 0x45, 0xf2, 0x63, 0x47, 0xbd, 0xb5, 0x49, 0x5f, 0x3a,
+ 0x52, 0x7d, 0x61, 0x1c, 0x80, 0x8f, 0x03, 0xb1, 0x4b, 0xdc, 0x3b, 0xe0,
+ 0x44, 0x66, 0xae, 0x4d, 0x65, 0x9c, 0x54, 0xba, 0x39, 0x9c, 0x65, 0x9b,
+ 0xe6, 0x4b, 0x93, 0x09, 0x5c, 0x48, 0x7d, 0x76, 0x12, 0xcb, 0x47, 0xcd,
+ 0xe9, 0xd3, 0xa9, 0x1a, 0xd8, 0xd8, 0x02, 0xae, 0xc0, 0x3a, 0x77, 0x56,
+ 0x15, 0x26, 0xe7, 0x27, 0x26, 0x6f, 0x4e, 0x0a, 0x11, 0xd2, 0x84, 0x5e,
+ 0x32, 0x7c, 0x47, 0x17, 0xfd, 0xaa, 0xb6, 0x7d, 0xf8, 0xa7, 0xba, 0x44,
+ 0xe3, 0x20, 0xd4, 0x1c, 0x5c, 0x7f, 0xf7, 0x55, 0xb3, 0xef, 0xc5, 0x3d,
+ 0xd5, 0x0b, 0x9e, 0x57, 0xdf, 0xd0, 0x91, 0x45, 0x64, 0x8d, 0x9a, 0x28,
+ 0x43, 0xc9, 0x9a, 0x4c, 0xe3, 0x8f, 0xc8, 0xf6, 0x5d, 0xf4, 0x44, 0x8f,
+ 0xe0, 0x34, 0xe7, 0x50, 0x1c, 0x45, 0xb2, 0xc8, 0xc9, 0x30, 0x5b, 0xe6,
+ 0x3f, 0x11, 0xd6, 0xd9, 0x91, 0x70, 0x82, 0xec, 0x66, 0x9c, 0x73, 0x7c,
+ 0x89, 0x52, 0xd2, 0x40, 0x2a, 0xd7, 0x5d, 0x6e, 0x84, 0x93, 0x71, 0xbe,
+ 0x2e, 0xdf, 0xcc, 0x1f, 0x65, 0x6c, 0xaa, 0xfd, 0xbf, 0xc7, 0x2a, 0x1b,
+ 0x4a, 0x03, 0x58, 0x11, 0x09, 0x1a, 0xdf, 0x69, 0x2f, 0xaf, 0xfd, 0x35,
+ 0xeb, 0x9b, 0x8c, 0xbf, 0xd4, 0xe0, 0x3f, 0xbd, 0x97, 0xfe, 0x5a, 0x01,
+ 0xfa, 0x8a, 0x41, 0xe7, 0xe3, 0x2f, 0xf5, 0x58, 0x0f, 0xef, 0x65, 0xff,
+ 0x00, 0x96, 0x8e, 0x6e, 0x32, 0xff, 0x00, 0x53, 0x80, 0xfe, 0xf6, 0x5f,
+ 0xf9, 0x68, 0x07, 0xea, 0x29, 0x07, 0x9b, 0x8c, 0xbf, 0xd4, 0xe0, 0x3f,
+ 0xbd, 0x97, 0xfe, 0x5a, 0x39, 0xf8, 0xcb, 0xfd, 0x56, 0x03, 0xfb, 0xd9,
+ 0x7f, 0xe5, 0xa0, 0x1f, 0xa8, 0x23, 0x74, 0x83, 0xcf, 0xc6, 0x5f, 0xea,
+ 0xb0, 0x1f, 0xde, 0x4b, 0xff, 0x00, 0x2d, 0x1c, 0xfc, 0x65, 0xfe, 0xab,
+ 0x01, 0xfd, 0xe4, 0xbf, 0xf2, 0xd0, 0x14, 0x97, 0x15, 0x71, 0x49, 0x58,
+ 0x87, 0x12, 0xe5, 0x5a, 0xac, 0xc8, 0x4b, 0x31, 0xf2, 0x49, 0x26, 0xfd,
+ 0x8b, 0x2f, 0x5a, 0x44, 0x7b, 0xdb, 0x29, 0xf7, 0xf8, 0xbb, 0xee, 0x4a,
+ 0x24, 0xb5, 0xb4, 0xf5, 0xe8, 0x49, 0x00, 0x7c, 0x1a, 0xb3, 0x2c, 0x37,
+ 0x9b, 0x06, 0x55, 0x83, 0xc5, 0xc8, 0x5a, 0xb7, 0x31, 0x29, 0xf9, 0x4c,
+ 0x33, 0xe4, 0xe2, 0x43, 0x8a, 0x42, 0x3c, 0xe5, 0xa5, 0x1c, 0x8f, 0x80,
+ 0x47, 0x30, 0x6d, 0x44, 0xec, 0x1f, 0xd1, 0x23, 0xa5, 0x70, 0x71, 0x73,
+ 0x0c, 0xe2, 0xb6, 0x77, 0x88, 0xb9, 0x6b, 0x94, 0x30, 0xc8, 0xf2, 0xa3,
+ 0x3c, 0xdc, 0xdb, 0x7c, 0x98, 0xae, 0xc9, 0x0f, 0x47, 0x92, 0xd2, 0xb9,
+ 0x90, 0xb4, 0x15, 0x27, 0x5b, 0xef, 0x1d, 0x7a, 0x75, 0x35, 0x5f, 0xf0,
+ 0xb7, 0x26, 0x8e, 0xbb, 0x82, 0x15, 0x36, 0x30, 0x8d, 0x6b, 0xcb, 0x5f,
+ 0x75, 0x46, 0x3a, 0xba, 0x22, 0x05, 0xe9, 0x03, 0x53, 0xa1, 0x11, 0xde,
+ 0x8e, 0xd0, 0xe9, 0xe4, 0x0e, 0x9b, 0xe6, 0x20, 0x75, 0xad, 0xa9, 0x62,
+ 0x59, 0x83, 0xeb, 0xf5, 0x32, 0xab, 0x98, 0xe2, 0x6b, 0xa7, 0xd0, 0xbb,
+ 0xaf, 0xd8, 0xcc, 0xc7, 0xf1, 0xc7, 0x84, 0x6b, 0xf4, 0xab, 0x84, 0x86,
+ 0x39, 0x43, 0x90, 0x92, 0x50, 0xd4, 0x57, 0xd0, 0x85, 0x02, 0xa8, 0xdd,
+ 0x92, 0x46, 0x90, 0x14, 0x01, 0x47, 0x7f, 0x30, 0xd8, 0xd9, 0x22, 0xb5,
+ 0x8c, 0xaa, 0xd7, 0x7a, 0xb5, 0xcf, 0x85, 0x75, 0xb7, 0xaa, 0x1d, 0x95,
+ 0xc4, 0x21, 0x31, 0xe5, 0x1f, 0x35, 0x0f, 0x34, 0xb4, 0x05, 0x20, 0xb4,
+ 0x40, 0x3b, 0x75, 0x2a, 0xf3, 0x79, 0x13, 0xe7, 0x25, 0x43, 0xbb, 0xbb,
+ 0x7a, 0x2d, 0x38, 0xeb, 0x8e, 0x4f, 0x9d, 0x2e, 0x35, 0xf2, 0x34, 0x06,
+ 0x27, 0xbc, 0x1f, 0x7c, 0xb4, 0x55, 0xdb, 0x73, 0x84, 0xf2, 0xa9, 0x49,
+ 0x42, 0xd4, 0x5b, 0x6d, 0x64, 0x6b, 0x99, 0x41, 0x24, 0x12, 0x37, 0xa0,
+ 0x69, 0x86, 0x1c, 0x3c, 0x36, 0xc4, 0x96, 0x97, 0x0a, 0x0d, 0xbd, 0x0f,
+ 0x32, 0xd8, 0x6d, 0x0e, 0x34, 0xca, 0x54, 0xe9, 0x00, 0x6b, 0xaa, 0xb5,
+ 0xb2, 0x75, 0xe2, 0x4d, 0x46, 0x86, 0x9e, 0x31, 0xb8, 0xf7, 0x89, 0xac,
+ 0xb7, 0xb0, 0xaf, 0x8b, 0xd8, 0xf3, 0x56, 0xe7, 0xfb, 0xae, 0x97, 0x0c,
+ 0x65, 0xdc, 0x63, 0xb2, 0xf4, 0xc6, 0xe5, 0xc8, 0x05, 0xae, 0xdc, 0x34,
+ 0x84, 0x17, 0x0b, 0x49, 0x6c, 0x2c, 0x2f, 0x49, 0x1b, 0x6f, 0x9c, 0x27,
+ 0x7b, 0x3b, 0x1b, 0xd5, 0x34, 0xda, 0xb0, 0x7c, 0x7a, 0x24, 0x66, 0x53,
+ 0x2e, 0x13, 0x57, 0x09, 0x28, 0xda, 0xdd, 0x7d, 0xf4, 0x03, 0xdb, 0x38,
+ 0x54, 0x54, 0xa5, 0xa9, 0x3f, 0x07, 0x7b, 0x51, 0xd7, 0x4e, 0x9d, 0x00,
+ 0xee, 0xa2, 0x46, 0x54, 0x80, 0x9d, 0x45, 0x8a, 0x48, 0x00, 0xf9, 0xce,
+ 0x2b, 0xa0, 0xf6, 0xeb, 0xff, 0x00, 0x35, 0x5d, 0x5d, 0xb8, 0xb3, 0x06,
+ 0xe5, 0x70, 0x55, 0xaa, 0xc2, 0xec, 0xdc, 0xa2, 0xe2, 0x09, 0x06, 0x05,
+ 0x81, 0xae, 0xdf, 0x93, 0xc3, 0xdf, 0x1c, 0x04, 0x36, 0xd8, 0xdf, 0x8a,
+ 0xd6, 0x2b, 0x4f, 0xb3, 0xcf, 0x99, 0xec, 0x67, 0xf6, 0x88, 0x7e, 0x0d,
+ 0xcb, 0x66, 0x7d, 0xe2, 0xdd, 0x01, 0x1d, 0x99, 0x70, 0x2d, 0x69, 0xee,
+ 0x6d, 0xbe, 0xba, 0xff, 0x00, 0xb0, 0xa4, 0x1c, 0xd7, 0x89, 0x96, 0xfb,
+ 0x4b, 0xad, 0xc4, 0x93, 0x38, 0x31, 0x2a, 0x47, 0x48, 0xf0, 0x22, 0xb6,
+ 0xa7, 0xe6, 0x3e, 0x7c, 0x39, 0x5b, 0x40, 0x2b, 0x3f, 0xdc, 0x07, 0xaf,
+ 0xc6, 0xa9, 0x0e, 0x23, 0x71, 0x3d, 0x16, 0x82, 0xa8, 0xd9, 0x4e, 0x55,
+ 0x1e, 0xc8, 0xe9, 0x25, 0x3e, 0xe0, 0x62, 0xee, 0x22, 0x75, 0xcd, 0x5d,
+ 0xfe, 0x63, 0xd2, 0xcf, 0xbd, 0x47, 0x3b, 0xef, 0xe4, 0x05, 0x5d, 0x7a,
+ 0x1a, 0xe3, 0xe1, 0xe5, 0x87, 0x8c, 0xb9, 0x84, 0x59, 0x3f, 0x8b, 0xfc,
+ 0x5e, 0x17, 0x0a, 0xec, 0x32, 0x92, 0xa5, 0x2a, 0xeb, 0x24, 0x2d, 0xcb,
+ 0x8c, 0xde, 0xa3, 0x5d, 0xa3, 0xee, 0x6d, 0xe5, 0x6f, 0x5b, 0xda, 0x42,
+ 0x53, 0x4d, 0x54, 0xe9, 0xf8, 0x56, 0x5f, 0x9b, 0x1a, 0x2a, 0x54, 0xf1,
+ 0x3c, 0x21, 0xcb, 0x39, 0xce, 0xa5, 0x5b, 0x23, 0x2e, 0x5e, 0x53, 0x7d,
+ 0x87, 0xc3, 0xd8, 0x4b, 0x47, 0x3a, 0x1a, 0x92, 0x53, 0x32, 0xfb, 0x21,
+ 0x3d, 0x3a, 0xa2, 0x32, 0x49, 0x43, 0x3b, 0xde, 0xb9, 0x96, 0x54, 0x47,
+ 0x88, 0x14, 0x85, 0x88, 0x5d, 0xf8, 0x8b, 0x9a, 0xce, 0x77, 0xf1, 0x29,
+ 0x83, 0x39, 0x61, 0x8d, 0x23, 0x68, 0x7f, 0x31, 0xbf, 0xab, 0xb7, 0x9c,
+ 0xfa, 0x77, 0xa3, 0xa7, 0x9c, 0x05, 0x29, 0x1f, 0xa8, 0xd8, 0x56, 0xb5,
+ 0xd3, 0x54, 0xcf, 0x80, 0xfe, 0x0b, 0xd7, 0xcc, 0x76, 0xf0, 0x6f, 0x77,
+ 0xa4, 0xe2, 0xb9, 0x75, 0xd7, 0xb5, 0xed, 0x43, 0xd7, 0x79, 0x12, 0x94,
+ 0xdf, 0x30, 0x3b, 0x0a, 0x2d, 0x84, 0xe9, 0x67, 0xe7, 0x95, 0x0a, 0xbc,
+ 0x59, 0x6f, 0x8c, 0x0c, 0x34, 0x86, 0x99, 0x8d, 0xc3, 0xf6, 0xdb, 0x6d,
+ 0x21, 0x28, 0x4a, 0x57, 0x2d, 0x21, 0x29, 0x1d, 0xc0, 0x00, 0x9e, 0x83,
+ 0xa7, 0x75, 0x65, 0x3a, 0xb2, 0x9f, 0x2c, 0xda, 0x14, 0xa3, 0x0e, 0x0a,
+ 0xfb, 0x02, 0xfc, 0x18, 0xf1, 0xd8, 0xd7, 0x04, 0xe4, 0x1c, 0x4a, 0xbb,
+ 0x4e, 0xce, 0xef, 0xeb, 0x57, 0x3b, 0x8b, 0x9c, 0xea, 0x8c, 0x60, 0xae,
+ 0x9d, 0x39, 0x09, 0x25, 0x7a, 0x3d, 0x34, 0xa2, 0x53, 0xa1, 0xf0, 0x45,
+ 0x5f, 0x70, 0xe1, 0xc5, 0x87, 0x11, 0xa8, 0x90, 0xe3, 0xb5, 0x1a, 0x3b,
+ 0x29, 0x08, 0x6d, 0xa6, 0x90, 0x10, 0x94, 0x24, 0x78, 0x00, 0x3a, 0x01,
+ 0xec, 0xa4, 0x7d, 0xf1, 0x93, 0xfa, 0xac, 0x07, 0xf7, 0x92, 0xff, 0x00,
+ 0xcb, 0x59, 0x0a, 0xe3, 0x2f, 0xf5, 0x38, 0x0f, 0xef, 0x65, 0xff, 0x00,
+ 0x96, 0xb3, 0x2e, 0x3e, 0xe8, 0x56, 0x47, 0x4a, 0x41, 0xe7, 0xe3, 0x2f,
+ 0xf5, 0x58, 0x0f, 0xef, 0x65, 0xff, 0x00, 0x96, 0x8e, 0x7e, 0x32, 0xff,
+ 0x00, 0x55, 0x80, 0xfe, 0xf2, 0x5f, 0xf9, 0x68, 0x0f, 0x7c, 0x65, 0xf8,
+ 0x96, 0x2f, 0xfb, 0x55, 0x6c, 0xfb, 0xf1, 0x4f, 0x75, 0x58, 0xdd, 0xac,
+ 0x5c, 0x4d, 0xc8, 0x66, 0x59, 0x5a, 0xbe, 0xaf, 0x10, 0x62, 0x04, 0x1b,
+ 0xb4, 0x6b, 0x83, 0xa6, 0x12, 0xa4, 0x17, 0x54, 0x19, 0x58, 0x57, 0x2a,
+ 0x42, 0xc6, 0xba, 0xea, 0xac, 0xea, 0x00, 0xa2, 0xb0, 0x49, 0xf0, 0xa2,
+ 0x80, 0xcd, 0x1a, 0xeb, 0x45, 0x14, 0x01, 0x45, 0x14, 0x50, 0x05, 0x14,
+ 0x51, 0x40, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14, 0x01, 0x5f, 0x2b,
+ 0x7e, 0x11, 0x38, 0x75, 0xcf, 0x0a, 0xc9, 0xef, 0x79, 0x7c, 0x1c, 0x7d,
+ 0xeb, 0xf6, 0x09, 0x91, 0x86, 0x9c, 0xc8, 0xe0, 0x43, 0x51, 0x4c, 0xa8,
+ 0x12, 0xdb, 0xdf, 0x24, 0xe6, 0x08, 0xf8, 0x0b, 0x1f, 0x0b, 0x98, 0x74,
+ 0xdf, 0x30, 0x57, 0x42, 0x0d, 0x7d, 0x53, 0x58, 0x52, 0x42, 0xba, 0x28,
+ 0x6c, 0x1e, 0x84, 0x50, 0x1f, 0x19, 0xe3, 0x3c, 0x46, 0xe2, 0x5c, 0x7b,
+ 0x12, 0x2e, 0x96, 0x9b, 0x64, 0x1e, 0x28, 0x63, 0xcd, 0x68, 0x79, 0x75,
+ 0xad, 0x65, 0xab, 0x93, 0x49, 0xf0, 0x12, 0x23, 0x8d, 0xa9, 0x0e, 0x01,
+ 0xde, 0x42, 0x08, 0xdf, 0xe7, 0x10, 0x76, 0x58, 0xec, 0xdc, 0x52, 0xcb,
+ 0xb2, 0x08, 0xcb, 0x7e, 0xd5, 0xc3, 0x29, 0x76, 0x88, 0x6d, 0x90, 0x97,
+ 0xae, 0x99, 0x1c, 0xe4, 0xdb, 0xe1, 0x32, 0x77, 0xd4, 0xa9, 0x6a, 0x4e,
+ 0xd5, 0xeb, 0x09, 0xd9, 0xf5, 0x55, 0x8d, 0xc4, 0x0f, 0xc1, 0xd7, 0x05,
+ 0xc8, 0xee, 0xc6, 0xfb, 0x65, 0x72, 0xe3, 0x87, 0xde, 0xf7, 0xbf, 0x2d,
+ 0xb1, 0xbd, 0xe4, 0xfc, 0xc7, 0xd2, 0xa4, 0x01, 0xad, 0xf8, 0xec, 0x68,
+ 0x93, 0xd4, 0x9a, 0xe6, 0xb4, 0x7e, 0x0d, 0xb8, 0x6a, 0xee, 0xcd, 0xdd,
+ 0xf3, 0x4b, 0xce, 0x49, 0x9c, 0xce, 0x6c, 0x0e, 0x53, 0x7c, 0xb8, 0x29,
+ 0xd6, 0xc6, 0xbf, 0x50, 0x6b, 0x63, 0xa0, 0xe8, 0x49, 0x1e, 0xaa, 0xdd,
+ 0x5c, 0xd4, 0x4b, 0x19, 0x30, 0x76, 0xd4, 0xdb, 0xcb, 0x45, 0x4d, 0x17,
+ 0x3f, 0x72, 0x6d, 0xc3, 0xdc, 0xeb, 0x42, 0x2e, 0x9c, 0x5e, 0xc9, 0x04,
+ 0x80, 0xf0, 0x62, 0xcc, 0xca, 0xe1, 0x59, 0xa0, 0x10, 0x85, 0x23, 0xb3,
+ 0x2b, 0xef, 0x79, 0x1e, 0x79, 0x27, 0x9f, 0xcd, 0x3a, 0x1d, 0xd4, 0xe9,
+ 0x03, 0x83, 0xfc, 0x55, 0xcc, 0xed, 0xcd, 0xc3, 0xcd, 0xf2, 0xe8, 0x18,
+ 0x56, 0x3c, 0x47, 0xfa, 0xb7, 0x8a, 0x47, 0x0d, 0x23, 0x93, 0xa7, 0x9a,
+ 0xb7, 0x3b, 0xbc, 0x07, 0x7f, 0x38, 0xaf, 0xa1, 0x6c, 0xf6, 0x9b, 0x5d,
+ 0x9a, 0x0a, 0x60, 0x5a, 0x2d, 0xd1, 0x2d, 0xf1, 0x11, 0xf0, 0x59, 0x8a,
+ 0xca, 0x5a, 0x40, 0xf6, 0x25, 0x20, 0x0a, 0xec, 0x00, 0x0a, 0xca, 0x53,
+ 0x94, 0xb9, 0x35, 0x8c, 0x23, 0x1e, 0x11, 0x5f, 0x70, 0xe3, 0x82, 0xfc,
+ 0x36, 0xc0, 0x43, 0x4e, 0xe3, 0xd8, 0xcc, 0x51, 0x35, 0xb1, 0xf1, 0xe9,
+ 0x43, 0xb7, 0x92, 0x4f, 0xa7, 0x9d, 0x7b, 0xe5, 0x3f, 0x37, 0x43, 0xd5,
+ 0x56, 0x0f, 0x28, 0xac, 0x81, 0xae, 0xea, 0x2a, 0xa5, 0x8c, 0x68, 0x56,
+ 0x68, 0xa2, 0x80, 0x28, 0xa2, 0x8a, 0x00, 0xa2, 0x8a, 0x28, 0x03, 0x42,
+ 0x8a, 0x28, 0xa0, 0x30, 0x52, 0x0f, 0x7d, 0x15, 0x9a, 0x28, 0x02, 0x8a,
+ 0x28, 0xa0, 0x0a, 0x28, 0xa2, 0x80, 0x28, 0xa2, 0x8a, 0x00, 0xa2, 0x8a,
+ 0x28, 0x02, 0x8a, 0x28, 0xa0, 0x0a, 0x28, 0xa2, 0x80, 0x35, 0x45, 0x14,
+ 0x50, 0x05, 0x14, 0x51, 0x40, 0x14, 0x51, 0x45, 0x00, 0x51, 0x45, 0x14,
+ 0x01, 0x45, 0x14, 0x50, 0x05, 0x14, 0x51, 0x40, 0x14, 0x51, 0x45, 0x00,
+ 0x51, 0x45, 0x14, 0x07, 0xff, 0xd9
+};
diff --git a/camera/libcameraservice/FakeCamera.cpp b/camera/libcameraservice/FakeCamera.cpp
new file mode 100644
index 0000000..3592eab
--- /dev/null
+++ b/camera/libcameraservice/FakeCamera.cpp
@@ -0,0 +1,404 @@
+#define LOG_TAG "FakeCamera"
+#include <utils/Log.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include "FakeCamera.h"
+
+namespace android {
+
+static int tables_initialized = 0;
+uint8_t *gYTable, *gCbTable, *gCrTable;
+
+static int
+clamp(int x)
+{
+ if (x > 255) return 255;
+ if (x < 0) return 0;
+ return x;
+}
+
+/* the equation used by the video code to translate YUV to RGB looks like this
+ *
+ * Y = (Y0 - 16)*k0
+ * Cb = Cb0 - 128
+ * Cr = Cr0 - 128
+ *
+ * G = ( Y - k1*Cr - k2*Cb )
+ * R = ( Y + k3*Cr )
+ * B = ( Y + k4*Cb )
+ *
+ */
+
+static const double k0 = 1.164;
+static const double k1 = 0.813;
+static const double k2 = 0.391;
+static const double k3 = 1.596;
+static const double k4 = 2.018;
+
+/* let's try to extract the value of Y
+ *
+ * G + k1/k3*R + k2/k4*B = Y*( 1 + k1/k3 + k2/k4 )
+ *
+ * Y = ( G + k1/k3*R + k2/k4*B ) / (1 + k1/k3 + k2/k4)
+ * Y0 = ( G0 + k1/k3*R0 + k2/k4*B0 ) / ((1 + k1/k3 + k2/k4)*k0) + 16
+ *
+ * let define:
+ * kYr = k1/k3
+ * kYb = k2/k4
+ * kYy = k0 * ( 1 + kYr + kYb )
+ *
+ * we have:
+ * Y = ( G + kYr*R + kYb*B )
+ * Y0 = clamp[ Y/kYy + 16 ]
+ */
+
+static const double kYr = k1/k3;
+static const double kYb = k2/k4;
+static const double kYy = k0*( 1. + kYr + kYb );
+
+static void
+initYtab( void )
+{
+ const int imax = (int)( (kYr + kYb)*(31 << 2) + (61 << 3) + 0.1 );
+ int i;
+
+ gYTable = (uint8_t *)malloc(imax);
+
+ for(i=0; i<imax; i++) {
+ int x = (int)(i/kYy + 16.5);
+ if (x < 16) x = 16;
+ else if (x > 235) x = 235;
+ gYTable[i] = (uint8_t) x;
+ }
+}
+
+/*
+ * the source is RGB565, so adjust for 8-bit range of input values:
+ *
+ * G = (pixels >> 3) & 0xFC;
+ * R = (pixels >> 8) & 0xF8;
+ * B = (pixels & 0x1f) << 3;
+ *
+ * R2 = (pixels >> 11) R = R2*8
+ * B2 = (pixels & 0x1f) B = B2*8
+ *
+ * kYr*R = kYr2*R2 => kYr2 = kYr*8
+ * kYb*B = kYb2*B2 => kYb2 = kYb*8
+ *
+ * we want to use integer multiplications:
+ *
+ * SHIFT1 = 9
+ *
+ * (ALPHA*R2) >> SHIFT1 == R*kYr => ALPHA = kYr*8*(1 << SHIFT1)
+ *
+ * ALPHA = kYr*(1 << (SHIFT1+3))
+ * BETA = kYb*(1 << (SHIFT1+3))
+ */
+
+static const int SHIFT1 = 9;
+static const int ALPHA = (int)( kYr*(1 << (SHIFT1+3)) + 0.5 );
+static const int BETA = (int)( kYb*(1 << (SHIFT1+3)) + 0.5 );
+
+/*
+ * now let's try to get the values of Cb and Cr
+ *
+ * R-B = (k3*Cr - k4*Cb)
+ *
+ * k3*Cr = k4*Cb + (R-B)
+ * k4*Cb = k3*Cr - (R-B)
+ *
+ * R-G = (k1+k3)*Cr + k2*Cb
+ * = (k1+k3)*Cr + k2/k4*(k3*Cr - (R-B)/k0)
+ * = (k1 + k3 + k2*k3/k4)*Cr - k2/k4*(R-B)
+ *
+ * kRr*Cr = (R-G) + kYb*(R-B)
+ *
+ * Cr = ((R-G) + kYb*(R-B))/kRr
+ * Cr0 = clamp(Cr + 128)
+ */
+
+static const double kRr = (k1 + k3 + k2*k3/k4);
+
+static void
+initCrtab( void )
+{
+ uint8_t *pTable;
+ int i;
+
+ gCrTable = (uint8_t *)malloc(768*2);
+
+ pTable = gCrTable + 384;
+ for(i=-384; i<384; i++)
+ pTable[i] = (uint8_t) clamp( i/kRr + 128.5 );
+}
+
+/*
+ * B-G = (k2 + k4)*Cb + k1*Cr
+ * = (k2 + k4)*Cb + k1/k3*(k4*Cb + (R-B))
+ * = (k2 + k4 + k1*k4/k3)*Cb + k1/k3*(R-B)
+ *
+ * kBb*Cb = (B-G) - kYr*(R-B)
+ *
+ * Cb = ((B-G) - kYr*(R-B))/kBb
+ * Cb0 = clamp(Cb + 128)
+ *
+ */
+
+static const double kBb = (k2 + k4 + k1*k4/k3);
+
+static void
+initCbtab( void )
+{
+ uint8_t *pTable;
+ int i;
+
+ gCbTable = (uint8_t *)malloc(768*2);
+
+ pTable = gCbTable + 384;
+ for(i=-384; i<384; i++)
+ pTable[i] = (uint8_t) clamp( i/kBb + 128.5 );
+}
+
+/*
+ * SHIFT2 = 16
+ *
+ * DELTA = kYb*(1 << SHIFT2)
+ * GAMMA = kYr*(1 << SHIFT2)
+ */
+
+static const int SHIFT2 = 16;
+static const int DELTA = kYb*(1 << SHIFT2);
+static const int GAMMA = kYr*(1 << SHIFT2);
+
+int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16,uint8_t *yuv422,uint32_t *param,uint8_t *table[])
+{
+ uint16_t *inputRGB = (uint16_t*)rgb16;
+ uint8_t *outYUV = yuv422;
+ int32_t width_dst = param[0];
+ int32_t height_dst = param[1];
+ int32_t pitch_dst = param[2];
+ int32_t mheight_dst = param[3];
+ int32_t pitch_src = param[4];
+ uint8_t *y_tab = table[0];
+ uint8_t *cb_tab = table[1];
+ uint8_t *cr_tab = table[2];
+
+ int32_t size16 = pitch_dst*mheight_dst;
+ int32_t i,j,count;
+ int32_t ilimit,jlimit;
+ uint8_t *tempY,*tempU,*tempV;
+ uint16_t pixels;
+ int tmp;
+uint32_t temp;
+
+ tempY = outYUV;
+ tempU = outYUV + (height_dst * pitch_dst);
+ tempV = tempU + 1;
+
+ jlimit = height_dst;
+ ilimit = width_dst;
+
+ for(j=0; j<jlimit; j+=1)
+ {
+ for (i=0; i<ilimit; i+=2)
+ {
+ int32_t G_ds = 0, B_ds = 0, R_ds = 0;
+ uint8_t y0, y1, u, v;
+
+ pixels = inputRGB[i];
+ temp = (ALPHA*(pixels & 0x001F) + BETA*(pixels>>11) );
+ y0 = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
+
+ G_ds += (pixels>>1) & 0x03E0;
+ B_ds += (pixels<<5) & 0x03E0;
+ R_ds += (pixels>>6) & 0x03E0;
+
+ pixels = inputRGB[i+1];
+ temp = (ALPHA*(pixels & 0x001F) + BETA*(pixels>>11) );
+ y1 = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
+
+ G_ds += (pixels>>1) & 0x03E0;
+ B_ds += (pixels<<5) & 0x03E0;
+ R_ds += (pixels>>6) & 0x03E0;
+
+ R_ds >>= 1;
+ B_ds >>= 1;
+ G_ds >>= 1;
+
+ tmp = R_ds - B_ds;
+
+ u = cb_tab[(((R_ds-G_ds)<<SHIFT2) + DELTA*tmp)>>(SHIFT2+2)];
+ v = cr_tab[(((B_ds-G_ds)<<SHIFT2) - GAMMA*tmp)>>(SHIFT2+2)];
+
+ tempY[0] = y0;
+ tempY[1] = y1;
+ tempU[0] = u;
+ tempV[0] = v;
+
+ tempY += 2;
+ tempU += 2;
+ tempV += 2;
+ }
+
+ inputRGB += pitch_src;
+ }
+
+ return 1;
+}
+
+#define min(a,b) ((a)<(b)?(a):(b))
+#define max(a,b) ((a)>(b)?(a):(b))
+
+static void convert_rgb16_to_yuv422(uint8_t *rgb, uint8_t *yuv, int width, int height)
+{
+ if (!tables_initialized) {
+ initYtab();
+ initCrtab();
+ initCbtab();
+ tables_initialized = 1;
+ }
+
+ uint32_t param[6];
+ param[0] = (uint32_t) width;
+ param[1] = (uint32_t) height;
+ param[2] = (uint32_t) width;
+ param[3] = (uint32_t) height;
+ param[4] = (uint32_t) width;
+ param[5] = (uint32_t) 0;
+
+ uint8_t *table[3];
+ table[0] = gYTable;
+ table[1] = gCbTable + 384;
+ table[2] = gCrTable + 384;
+
+ ccrgb16toyuv_wo_colorkey(rgb, yuv, param, table);
+}
+
+const int FakeCamera::kRed;
+const int FakeCamera::kGreen;
+const int FakeCamera::kBlue;
+
+FakeCamera::FakeCamera(int width, int height)
+ : mTmpRgb16Buffer(0)
+{
+ setSize(width, height);
+}
+
+FakeCamera::~FakeCamera()
+{
+ delete[] mTmpRgb16Buffer;
+}
+
+void FakeCamera::setSize(int width, int height)
+{
+ mWidth = width;
+ mHeight = height;
+ mCounter = 0;
+ mCheckX = 0;
+ mCheckY = 0;
+
+ // This will cause it to be reallocated on the next call
+ // to getNextFrameAsYuv422().
+ delete[] mTmpRgb16Buffer;
+ mTmpRgb16Buffer = 0;
+}
+
+void FakeCamera::getNextFrameAsRgb565(uint16_t *buffer)
+{
+ int size = mWidth / 10;
+
+ drawCheckerboard(buffer, size);
+
+ int x = ((mCounter*3)&255);
+ if(x>128) x = 255 - x;
+ int y = ((mCounter*5)&255);
+ if(y>128) y = 255 - y;
+
+ drawSquare(buffer, x*size/32, y*size/32, (size*5)>>1, (mCounter&0x100)?kRed:kGreen, kBlue);
+
+ mCounter++;
+}
+
+void FakeCamera::getNextFrameAsYuv422(uint8_t *buffer)
+{
+ if (mTmpRgb16Buffer == 0)
+ mTmpRgb16Buffer = new uint16_t[mWidth * mHeight];
+
+ getNextFrameAsRgb565(mTmpRgb16Buffer);
+ convert_rgb16_to_yuv422((uint8_t*)mTmpRgb16Buffer, buffer, mWidth, mHeight);
+}
+
+void FakeCamera::drawSquare(uint16_t *dst, int x, int y, int size, int color, int shadow)
+{
+ int square_xstop, square_ystop, shadow_xstop, shadow_ystop;
+
+ square_xstop = min(mWidth, x+size);
+ square_ystop = min(mHeight, y+size);
+ shadow_xstop = min(mWidth, x+size+(size/4));
+ shadow_ystop = min(mHeight, y+size+(size/4));
+
+ // Do the shadow.
+ uint16_t *sh = &dst[(y+(size/4))*mWidth];
+ for (int j = y + (size/4); j < shadow_ystop; j++) {
+ for (int i = x + (size/4); i < shadow_xstop; i++) {
+ sh[i] &= shadow;
+ }
+ sh += mWidth;
+ }
+
+ // Draw the square.
+ uint16_t *sq = &dst[y*mWidth];
+ for (int j = y; j < square_ystop; j++) {
+ for (int i = x; i < square_xstop; i++) {
+ sq[i] = color;
+ }
+ sq += mWidth;
+ }
+}
+
+void FakeCamera::drawCheckerboard(uint16_t *dst, int size)
+{
+ bool black = true;
+
+ if((mCheckX/size)&1)
+ black = false;
+ if((mCheckY/size)&1)
+ black = !black;
+
+ int county = mCheckY%size;
+ int checkxremainder = mCheckX%size;
+
+ for(int y=0;y<mHeight;y++) {
+ int countx = checkxremainder;
+ bool current = black;
+ for(int x=0;x<mWidth;x++) {
+ dst[y*mWidth+x] = current?0:0xffff;
+ if(countx++ >= size) {
+ countx=0;
+ current = !current;
+ }
+ }
+ if(county++ >= size) {
+ county=0;
+ black = !black;
+ }
+ }
+ mCheckX += 3;
+ mCheckY++;
+}
+
+
+status_t FakeCamera::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, 255, " width x height (%d x %d), counter (%d), check x-y coordinate(%d, %d)\n", mWidth, mHeight, mCounter, mCheckX, mCheckY);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+
+}; // namespace android
diff --git a/camera/libcameraservice/FakeCamera.h b/camera/libcameraservice/FakeCamera.h
new file mode 100644
index 0000000..77c994c
--- /dev/null
+++ b/camera/libcameraservice/FakeCamera.h
@@ -0,0 +1,51 @@
+/*
+**
+** 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_FAKECAMERA_H
+#define ANDROID_HARDWARE_FAKECAMERA_H
+
+#include <ui/CameraHardwareInterface.h>
+
+namespace android {
+
+class FakeCamera {
+public:
+ FakeCamera(int width, int height);
+ ~FakeCamera();
+
+ void setSize(int width, int height);
+ void getNextFrameAsRgb565(uint16_t *buffer);
+ void getNextFrameAsYuv422(uint8_t *buffer);
+ status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ void drawSquare(uint16_t *buffer, int x, int y, int size, int color, int shadow);
+ void drawCheckerboard(uint16_t *buffer, int size);
+
+ static const int kRed = 0xf800;
+ static const int kGreen = 0x07c0;
+ static const int kBlue = 0x003e;
+
+ int mWidth, mHeight;
+ int mCounter;
+ int mCheckX, mCheckY;
+ uint16_t *mTmpRgb16Buffer;
+};
+
+}; // namespace android
+
+#endif // ANDROID_HARDWARE_FAKECAMERA_H
diff --git a/cmds/runtime/Android.mk b/cmds/runtime/Android.mk
new file mode 100644
index 0000000..00fa8a2
--- /dev/null
+++ b/cmds/runtime/Android.mk
@@ -0,0 +1,29 @@
+ifeq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ ServiceManager.cpp \
+ SignalHandler.cpp \
+ main_runtime.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libandroid_runtime \
+ libcutils \
+ libui \
+ libsystem_server \
+ libhardware
+
+LOCAL_C_INCLUDES := \
+ $(JNI_H_INCLUDE)
+
+ifeq ($(TARGET_OS),linux)
+ LOCAL_CFLAGS += -DXP_UNIX
+endif
+
+LOCAL_MODULE:= runtime
+
+include $(BUILD_EXECUTABLE)
+endif
diff --git a/cmds/runtime/MODULE_LICENSE_APACHE2 b/cmds/runtime/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/runtime/MODULE_LICENSE_APACHE2
diff --git a/cmds/runtime/NOTICE b/cmds/runtime/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/runtime/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the 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/cmds/runtime/ServiceManager.cpp b/cmds/runtime/ServiceManager.cpp
new file mode 100644
index 0000000..758a95c
--- /dev/null
+++ b/cmds/runtime/ServiceManager.cpp
@@ -0,0 +1,74 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+
+#define LOG_TAG "ServiceManager"
+
+#include "ServiceManager.h"
+#include "SignalHandler.h"
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/String8.h>
+#include <utils/ProcessState.h>
+
+#include <private/utils/Static.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+namespace android {
+
+BServiceManager::BServiceManager()
+{
+}
+
+sp<IBinder> BServiceManager::getService(const String16& name) const
+{
+ AutoMutex _l(mLock);
+ ssize_t i = mServices.indexOfKey(name);
+ LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i);
+ if (i >= 0) return mServices.valueAt(i);
+ return NULL;
+}
+
+sp<IBinder> BServiceManager::checkService(const String16& name) const
+{
+ AutoMutex _l(mLock);
+ ssize_t i = mServices.indexOfKey(name);
+ LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i);
+ if (i >= 0) return mServices.valueAt(i);
+ return NULL;
+}
+
+status_t BServiceManager::addService(const String16& name, const sp<IBinder>& service)
+{
+ AutoMutex _l(mLock);
+ LOGI("ServiceManager: addService(%s, %p)\n", String8(name).string(), service.get());
+ const ssize_t res = mServices.add(name, service);
+ if (res >= NO_ERROR) {
+ mChanged.broadcast();
+ return NO_ERROR;
+ }
+ return res;
+}
+
+Vector<String16> BServiceManager::listServices()
+{
+ Vector<String16> res;
+
+ AutoMutex _l(mLock);
+ const size_t N = mServices.size();
+ for (size_t i=0; i<N; i++) {
+ res.add(mServices.keyAt(i));
+ }
+
+ return res;
+}
+
+}; // namespace android
diff --git a/cmds/runtime/ServiceManager.h b/cmds/runtime/ServiceManager.h
new file mode 100644
index 0000000..d09cec8
--- /dev/null
+++ b/cmds/runtime/ServiceManager.h
@@ -0,0 +1,38 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+#ifndef ANDROID_SERVICE_MANAGER_H
+#define ANDROID_SERVICE_MANAGER_H
+
+#include <utils/IServiceManager.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BServiceManager : public BnServiceManager
+{
+public:
+ BServiceManager();
+
+ virtual sp<IBinder> getService( const String16& name) const;
+ virtual sp<IBinder> checkService( const String16& name) const;
+ virtual status_t addService( const String16& name,
+ const sp<IBinder>& service);
+ virtual Vector<String16> listServices();
+
+
+private:
+ mutable Mutex mLock;
+ mutable Condition mChanged;
+ sp<IPermissionController> mPermissionController;
+ KeyedVector<String16, sp<IBinder> > mServices;
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_SERVICE_MANAGER_H
diff --git a/cmds/runtime/SignalHandler.cpp b/cmds/runtime/SignalHandler.cpp
new file mode 100644
index 0000000..cccaabf
--- /dev/null
+++ b/cmds/runtime/SignalHandler.cpp
@@ -0,0 +1,249 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+
+#define LOG_TAG "SignalHandler"
+
+#include "SignalHandler.h"
+
+#include <utils/Atomic.h>
+#include <utils/Debug.h>
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+namespace android {
+
+class SignalHandler::ProcessThread : public Thread
+{
+public:
+ ProcessThread(SignalHandler& sh)
+ : Thread(false)
+ , mOwner(sh)
+ {
+ }
+
+ virtual bool threadLoop()
+ {
+ char buffer[32];
+ read(mOwner.mAvailMsg[0], buffer, sizeof(buffer));
+
+ LOGV("Signal command processing thread woke up!");
+
+ if (mOwner.mLostCommands) {
+ LOGE("Lost %d signals!", mOwner.mLostCommands);
+ mOwner.mLostCommands = 0;
+ }
+
+ int cur;
+ while ((cur=mOwner.mCommandBottom) != mOwner.mCommandTop) {
+ if (mOwner.mCommands[cur].filled == 0) {
+ LOGV("Command at %d is not yet filled", cur);
+ break;
+ }
+
+ LOGV("Processing command at %d, top is %d",
+ cur, mOwner.mCommandTop);
+ processCommand(mOwner.mCommands[cur]);
+ mOwner.mCommands[cur].filled = 0;
+
+ int next = mOwner.mCommandBottom+1;
+ if (next >= COMMAND_QUEUE_SIZE) {
+ next = 0;
+ }
+
+ mOwner.mCommandBottom = next;
+ }
+
+ return true;
+ }
+
+ void processCommand(const CommandEntry& entry)
+ {
+ switch (entry.signum) {
+ case SIGCHLD: {
+ mOwner.mLock.lock();
+ ssize_t i = mOwner.mChildHandlers.indexOfKey(entry.info.si_pid);
+ ChildHandler ch;
+ if (i >= 0) {
+ ch = mOwner.mChildHandlers.valueAt(i);
+ mOwner.mChildHandlers.removeItemsAt(i);
+ }
+ mOwner.mLock.unlock();
+
+ LOGD("SIGCHLD: pid=%d, handle index=%d", entry.info.si_pid, i);
+
+ if (i >= 0) {
+ int res = waitpid(entry.info.si_pid, NULL, WNOHANG);
+ LOGW_IF(res == 0,
+ "Received SIGCHLD, but pid %d is not yet stopped",
+ entry.info.si_pid);
+ if (ch.handler) {
+ ch.handler(entry.info.si_pid, ch.userData);
+ }
+ } else {
+ LOGW("Unhandled SIGCHLD for pid %d", entry.info.si_pid);
+ }
+ } break;
+ }
+ }
+
+ SignalHandler& mOwner;
+};
+
+
+Mutex SignalHandler::mInstanceLock;
+SignalHandler* SignalHandler::mInstance = NULL;
+
+status_t SignalHandler::setChildHandler(pid_t childPid,
+ int tag,
+ child_callback_t handler,
+ void* userData)
+{
+ SignalHandler* const self = getInstance();
+
+ self->mLock.lock();
+
+ // First make sure this child hasn't already exited.
+ pid_t res = waitpid(childPid, NULL, WNOHANG);
+ if (res != 0) {
+ if (res < 0) {
+ LOGW("setChildHandler waitpid of %d failed: %d (%s)",
+ childPid, res, strerror(errno));
+ } else {
+ LOGW("setChildHandler waitpid of %d said %d already dead",
+ childPid, res);
+ }
+
+ // Some kind of error... just handle the exit now.
+ self->mLock.unlock();
+
+ if (handler) {
+ handler(childPid, userData);
+ }
+
+ // Return an error code -- 0 means it already exited.
+ return (status_t)res;
+ }
+
+ ChildHandler entry;
+ entry.childPid = childPid;
+ entry.tag = tag;
+ entry.handler = handler;
+ entry.userData = userData;
+
+ // Note: this replaces an existing entry for this pid, if there already
+ // is one. This is the required behavior.
+ LOGD("setChildHandler adding pid %d, tag %d, handler %p, data %p",
+ childPid, tag, handler, userData);
+ self->mChildHandlers.add(childPid, entry);
+
+ self->mLock.unlock();
+
+ return NO_ERROR;
+}
+
+void SignalHandler::killAllChildren(int tag)
+{
+ SignalHandler* const self = getInstance();
+
+ AutoMutex _l (self->mLock);
+ const size_t N = self->mChildHandlers.size();
+ for (size_t i=0; i<N; i++) {
+ const ChildHandler& ch(self->mChildHandlers.valueAt(i));
+ if (tag == 0 || ch.tag == tag) {
+ const pid_t pid = ch.childPid;
+ LOGI("Killing child %d (tag %d)\n", pid, ch.tag);
+ kill(pid, SIGKILL);
+ }
+ }
+}
+
+SignalHandler::SignalHandler()
+ : mCommandTop(0)
+ , mCommandBottom(0)
+ , mLostCommands(0)
+{
+ memset(mCommands, 0, sizeof(mCommands));
+
+ int res = pipe(mAvailMsg);
+ LOGE_IF(res != 0, "Unable to create signal handler pipe: %s", strerror(errno));
+
+ mProcessThread = new ProcessThread(*this);
+ mProcessThread->run("SignalHandler", PRIORITY_HIGHEST);
+
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = sigAction;
+ sa.sa_flags = SA_NOCLDSTOP|SA_SIGINFO;
+ sigaction(SIGCHLD, &sa, NULL);
+}
+
+SignalHandler::~SignalHandler()
+{
+}
+
+SignalHandler* SignalHandler::getInstance()
+{
+ AutoMutex _l(mInstanceLock);
+ if (mInstance == NULL) {
+ mInstance = new SignalHandler();
+ }
+ return mInstance;
+}
+
+void SignalHandler::sigAction(int signum, siginfo_t* info, void*)
+{
+ static const char wakeupMsg[1] = { 0xff };
+
+ // If our signal handler is being called, then we know we have
+ // already initialized the SignalHandler class and thus mInstance
+ // is valid.
+ SignalHandler* const self = mInstance;
+
+ // XXX This is not safe!
+ #if 0
+ LOGV("Signal %d: signo=%d, errno=%d, code=%d, pid=%d\n",
+ signum,
+ info->si_signo, info->si_errno, info->si_code,
+ info->si_pid);
+ #endif
+
+ int32_t oldTop, newTop;
+
+ // Find the next command slot...
+ do {
+ oldTop = self->mCommandTop;
+
+ newTop = oldTop + 1;
+ if (newTop >= COMMAND_QUEUE_SIZE) {
+ newTop = 0;
+ }
+
+ if (newTop == self->mCommandBottom) {
+ // The buffer is filled up! Ouch!
+ // XXX This is not safe!
+ #if 0
+ LOGE("Command buffer overflow! newTop=%d\n", newTop);
+ #endif
+ android_atomic_add(1, &self->mLostCommands);
+ write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
+ return;
+ }
+ } while(android_atomic_cmpxchg(oldTop, newTop, &(self->mCommandTop)));
+
+ // Fill in the command data...
+ self->mCommands[oldTop].signum = signum;
+ self->mCommands[oldTop].info = *info;
+
+ // And now make this command available.
+ self->mCommands[oldTop].filled = 1;
+
+ // Wake up the processing thread.
+ write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
+}
+
+}; // namespace android
+
diff --git a/cmds/runtime/SignalHandler.h b/cmds/runtime/SignalHandler.h
new file mode 100644
index 0000000..7f4ef8e
--- /dev/null
+++ b/cmds/runtime/SignalHandler.h
@@ -0,0 +1,137 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+#ifndef ANDROID_SIGNAL_HANDLER_H
+#define ANDROID_SIGNAL_HANDLER_H
+
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+#include <signal.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+enum {
+ DEFAULT_PROCESS_TAG = 1
+};
+
+class SignalHandler
+{
+public:
+ typedef void (*child_callback_t)(pid_t child, void* userData);
+
+ /**
+ * Set a handler for when a child process exits. By calling
+ * this, a waitpid() will be done when the child exits to remove
+ * it from the zombie state. You can also optionally specify a
+ * handler to be called when the child exits.
+ *
+ * If there is already a handler for this child process, it is
+ * replaced by this new handler. In this case the old handler's
+ * function is not called.
+ *
+ * @param childPid Process ID of child to watch.
+ * @param childTag User-defined tag for this child. Must be
+ * greater than zero.
+ * @param handler If non-NULL, this will be called when the
+ * child exits. It may be called in either a
+ * separate signal handling thread, or
+ * immediately if the child has already exited.
+ * @param userData Propageted as-is to handler.
+ *
+ * @return status_t NO_ERROR if all is well.
+ */
+ static status_t setChildHandler(pid_t childPid,
+ int childTag = DEFAULT_PROCESS_TAG,
+ child_callback_t handler = NULL,
+ void* userData = NULL);
+
+ /**
+ * Kill all of the child processes for which we have a waiting
+ * handler, whose tag is the given value. If tag is 0, all
+ * children are killed.
+ *
+ * @param tag
+ */
+ static void killAllChildren(int tag = 0);
+
+private:
+ SignalHandler();
+ ~SignalHandler();
+
+ static SignalHandler* getInstance();
+
+ static void sigAction(int, siginfo_t*, void*);
+
+ // --------------------------------------------------
+ // Shared state... all of this is protected by mLock.
+ // --------------------------------------------------
+
+ mutable Mutex mLock;
+
+ struct ChildHandler
+ {
+ pid_t childPid;
+ int tag;
+ child_callback_t handler;
+ void* userData;
+ };
+ KeyedVector<pid_t, ChildHandler> mChildHandlers;
+
+ // --------------------------------------------------
+ // Commmand queue... data is inserted by the signal
+ // handler using atomic ops, and retrieved by the
+ // signal processing thread. Because these are touched
+ // by the signal handler, no lock is used.
+ // --------------------------------------------------
+
+ enum {
+ COMMAND_QUEUE_SIZE = 64
+ };
+ struct CommandEntry
+ {
+ int filled;
+ int signum;
+ siginfo_t info;
+ };
+
+ // The top of the queue. This is incremented atomically by the
+ // signal handler before placing a command in the queue.
+ volatile int32_t mCommandTop;
+
+ // The bottom of the queue. Only modified by the processing
+ // thread; the signal handler reads it only to determine if the
+ // queue is full.
+ int32_t mCommandBottom;
+
+ // Incremented each time we receive a signal and don't have room
+ // for it on the command queue.
+ volatile int32_t mLostCommands;
+
+ // The command processing thread.
+ class ProcessThread;
+ sp<Thread> mProcessThread;
+
+ // Pipe used to tell command processing thread when new commands.
+ // are available. The thread blocks on the read end, the signal
+ // handler writes when it enqueues new commands.
+ int mAvailMsg[2];
+
+ // The commands.
+ CommandEntry mCommands[COMMAND_QUEUE_SIZE];
+
+ // --------------------------------------------------
+ // Singleton.
+ // --------------------------------------------------
+
+ static Mutex mInstanceLock;
+ static SignalHandler* mInstance;
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_SIGNAL_HANDLER_H
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
new file mode 100644
index 0000000..1531a9e
--- /dev/null
+++ b/cmds/runtime/main_runtime.cpp
@@ -0,0 +1,514 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+// Main entry point for runtime.
+//
+
+#include "ServiceManager.h"
+#include "SignalHandler.h"
+
+#include <utils.h>
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/Log.h>
+#include <cutils/zygote.h>
+
+#include <cutils/properties.h>
+
+#include <private/utils/Static.h>
+
+#include <ui/ISurfaceComposer.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <linux/capability.h>
+#include <linux/ioctl.h>
+#ifdef HAVE_ANDROID_OS
+# include <linux/android_alarm.h>
+#endif
+
+#undef LOG_TAG
+#define LOG_TAG "runtime"
+
+static const char* ZYGOTE_ARGV[] = {
+ "--setuid=1000",
+ "--setgid=1000",
+ "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
+ /* CAP_SYS_TTY_CONFIG & CAP_SYS_RESOURCE & CAP_NET_BROADCAST &
+ * CAP_NET_ADMIN & CAP_NET_RAW & CAP_NET_BIND_SERVICE & CAP_KILL &
+ * CAP_SYS_BOOT
+ */
+ "--capabilities=88161312,88161312",
+ "--runtime-init",
+ "--nice-name=system_server",
+ "com.android.server.SystemServer"
+};
+
+using namespace android;
+
+extern "C" status_t system_init();
+
+enum {
+ SYSTEM_PROCESS_TAG = DEFAULT_PROCESS_TAG+1
+};
+
+extern Mutex gEventQMutex;
+extern Condition gEventQCondition;
+
+namespace android {
+
+extern status_t app_init(const char* className);
+extern void set_finish_init_func(void (*func)());
+
+
+/**
+ * This class is used to kill this process (runtime) when the system_server dies.
+ */
+class GrimReaper : public IBinder::DeathRecipient {
+public:
+ GrimReaper() { }
+
+ virtual void binderDied(const wp<IBinder>& who)
+ {
+ LOGI("Grim Reaper killing runtime...");
+ kill(getpid(), SIGKILL);
+ }
+};
+
+extern void QuickTests();
+
+/*
+ * Print usage info.
+ */
+static void usage(const char* argv0)
+{
+ fprintf(stderr,
+ "Usage: runtime [-g gamma] [-l logfile] [-n] [-s]\n"
+ " [-j app-component] [-v app-verb] [-d app-data]\n"
+ "\n"
+ "-l: File to send log messages to\n"
+ "-n: Don't print to stdout/stderr\n"
+ "-s: Force single-process mode\n"
+ "-j: Custom home app component name\n"
+ "-v: Custom home app intent verb\n"
+ "-d: Custom home app intent data\n"
+ );
+ exit(1);
+}
+
+// Selected application to run.
+static const char* gInitialApplication = NULL;
+static const char* gInitialVerb = NULL;
+static const char* gInitialData = NULL;
+
+static void writeStringToParcel(Parcel& parcel, const char* str)
+{
+ if (str) {
+ parcel.writeString16(String16(str));
+ } else {
+ parcel.writeString16(NULL, 0);
+ }
+}
+
+/*
+ * Starting point for program logic.
+ *
+ * Returns with an exit status code (0 on success, nonzero on error).
+ */
+static int run(sp<ProcessState>& proc)
+{
+ // Temporary hack to call startRunning() on the activity manager.
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> am;
+ while ((am = sm->getService(String16("activity"))) == NULL) {
+ LOGI("Waiting for activity manager...");
+ }
+ Parcel data, reply;
+ // XXX Need to also supply a package name for this to work again.
+ // IActivityManager::getInterfaceDescriptor() is the token for invoking on this interface;
+ // hardcoding it here avoids having to link with the full Activity Manager library
+ data.writeInterfaceToken(String16("android.app.IActivityManager"));
+ writeStringToParcel(data, NULL);
+ writeStringToParcel(data, gInitialApplication);
+ writeStringToParcel(data, gInitialVerb);
+ writeStringToParcel(data, gInitialData);
+LOGI("run() sending FIRST_CALL_TRANSACTION to activity manager");
+ am->transact(IBinder::FIRST_CALL_TRANSACTION, data, &reply);
+
+ if (proc->supportsProcesses()) {
+ // Now we link to the Activity Manager waiting for it to die. If it does kill ourself.
+ // initd will restart this process and bring the system back up.
+ sp<GrimReaper> grim = new GrimReaper();
+ am->linkToDeath(grim, grim.get(), 0);
+
+ // Now join the thread pool. Note this is needed so that the message enqueued in the driver
+ // for the linkToDeath gets processed.
+ IPCThreadState::self()->joinThreadPool();
+ } else {
+ // Keep this thread running forever...
+ while (1) {
+ usleep(100000);
+ }
+ }
+ return 1;
+}
+
+
+}; // namespace android
+
+
+/*
+ * Post-system-process initialization.
+ *
+ * This function continues initialization after the system process
+ * has been initialized. It needs to be separate because the system
+ * initialization needs to care of starting the Android runtime if it is not
+ * running in its own process, which doesn't return until the runtime is
+ * being shut down. So it will call back to here from inside of Dalvik,
+ * to allow us to continue booting up.
+ */
+static void finish_system_init(sp<ProcessState>& proc)
+{
+ // If we are running multiprocess, we now need to have the
+ // thread pool started here. We don't do this in boot_init()
+ // because when running single process we need to start the
+ // thread pool after the Android runtime has been started (so
+ // the pool uses Dalvik threads).
+ if (proc->supportsProcesses()) {
+ proc->startThreadPool();
+ }
+}
+
+
+// This function can be used to enforce security to different
+// root contexts. For now, we just give every access.
+static bool contextChecker(
+ const String16& name, const sp<IBinder>& caller, void* userData)
+{
+ return true;
+}
+
+/*
+ * Initialization of boot services.
+ *
+ * This is where we perform initialization of all of our low-level
+ * boot services. Most importantly, here we become the context
+ * manager and use that to publish the service manager that will provide
+ * access to all other services.
+ */
+static void boot_init()
+{
+ LOGI("Entered boot_init()!\n");
+
+ sp<ProcessState> proc(ProcessState::self());
+ LOGD("ProcessState: %p\n", proc.get());
+ proc->becomeContextManager(contextChecker, NULL);
+
+ if (proc->supportsProcesses()) {
+ LOGI("Binder driver opened. Multiprocess enabled.\n");
+ } else {
+ LOGI("Binder driver not found. Processes not supported.\n");
+ }
+
+ sp<BServiceManager> sm = new BServiceManager;
+ proc->setContextObject(sm);
+}
+
+/*
+ * Redirect stdin/stdout/stderr to /dev/null.
+ */
+static void redirectStdFds(void)
+{
+ int fd = open("/dev/null", O_RDWR, 0);
+ if (fd < 0) {
+ LOGW("Unable to open /dev/null: %s\n", strerror(errno));
+ } else {
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+ }
+}
+
+static int hasDir(const char* dir)
+{
+ struct stat s;
+ int res = stat(dir, &s);
+ if (res == 0) {
+ return S_ISDIR(s.st_mode);
+ }
+ return 0;
+}
+
+static void validateTime()
+{
+#if HAVE_ANDROID_OS
+ int fd;
+ int res;
+ time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year
+ struct timespec ts;
+
+ fd = open("/dev/alarm", O_RDWR);
+ if(fd < 0) {
+ LOGW("Unable to open alarm driver: %s\n", strerror(errno));
+ return;
+ }
+ res = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_RTC_WAKEUP), &ts);
+ if(res < 0) {
+ LOGW("Unable to read rtc, %s\n", strerror(errno));
+ }
+ else if(ts.tv_sec >= min_time) {
+ goto done;
+ }
+ LOGW("Invalid time detected, %ld set to %ld\n", ts.tv_sec, min_time);
+ ts.tv_sec = min_time;
+ ts.tv_nsec = 0;
+ res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+ if(res < 0) {
+ LOGW("Unable to set rtc to %ld: %s\n", ts.tv_sec, strerror(errno));
+ }
+done:
+ close(fd);
+#endif
+}
+
+#ifndef HAVE_ANDROID_OS
+class QuickRuntime : public AndroidRuntime
+{
+public:
+ QuickRuntime() {}
+
+ virtual void onStarted()
+ {
+ printf("QuickRuntime: onStarted\n");
+ }
+};
+#endif
+
+static status_t start_process(const char* name);
+
+static void restart_me(pid_t child, void* userData)
+{
+ start_process((const char*)userData);
+}
+
+static status_t start_process(const char* name)
+{
+ String8 path(name);
+ Vector<const char*> args;
+ String8 leaf(path.getPathLeaf());
+ String8 parentDir(path.getPathDir());
+ args.insertAt(leaf.string(), 0);
+ args.add(parentDir.string());
+ args.add(NULL);
+ pid_t child = fork();
+ if (child < 0) {
+ status_t err = errno;
+ LOGE("*** fork of child %s failed: %s", leaf.string(), strerror(err));
+ return -errno;
+ } else if (child == 0) {
+ LOGI("Executing: %s", path.string());
+ execv(path.string(), const_cast<char**>(args.array()));
+ int err = errno;
+ LOGE("Exec failed: %s\n", strerror(err));
+ _exit(err);
+ } else {
+ SignalHandler::setChildHandler(child, DEFAULT_PROCESS_TAG,
+ restart_me, (void*)name);
+ }
+ return -errno;
+}
+
+/*
+ * Application entry point.
+ *
+ * Parse arguments, set some values, and pass control off to Run().
+ *
+ * This is redefined to "SDL_main" on SDL simulator builds, and
+ * "runtime_main" on wxWidgets builds.
+ */
+extern "C"
+int main(int argc, char* const argv[])
+{
+ bool singleProcess = false;
+ const char* logFile = NULL;
+ int ic;
+ int result = 1;
+ pid_t systemPid;
+
+ sp<ProcessState> proc;
+
+#ifndef HAVE_ANDROID_OS
+ /* Set stdout/stderr to unbuffered for MinGW/MSYS. */
+ //setvbuf(stdout, NULL, _IONBF, 0);
+ //setvbuf(stderr, NULL, _IONBF, 0);
+
+ LOGI("commandline args:\n");
+ for (int i = 0; i < argc; i++)
+ LOGI(" %2d: '%s'\n", i, argv[i]);
+#endif
+
+ while (1) {
+ ic = getopt(argc, argv, "g:j:v:d:l:ns");
+ if (ic < 0)
+ break;
+
+ switch (ic) {
+ case 'g':
+ break;
+ case 'j':
+ gInitialApplication = optarg;
+ break;
+ case 'v':
+ gInitialVerb = optarg;
+ break;
+ case 'd':
+ gInitialData = optarg;
+ break;
+ case 'l':
+ logFile = optarg;
+ break;
+ case 'n':
+ redirectStdFds();
+ break;
+ case 's':
+ singleProcess = true;
+ break;
+ case '?':
+ default:
+ LOGE("runtime: unrecognized flag -%c\n", ic);
+ usage(argv[0]);
+ break;
+ }
+ }
+ if (optind < argc) {
+ LOGE("runtime: extra stuff: %s\n", argv[optind]);
+ usage(argv[0]);
+ }
+
+ if (singleProcess) {
+ ProcessState::setSingleProcess(true);
+ }
+
+ if (logFile != NULL) {
+ android_logToFile(NULL, logFile);
+ }
+
+ /*
+ * Set up ANDROID_* environment variables.
+ *
+ * TODO: the use of $ANDROID_PRODUCT_OUT will go away soon.
+ */
+ static const char* kSystemDir = "/system";
+ static const char* kDataDir = "/data";
+ static const char* kAppSubdir = "/app";
+ const char* out = NULL;
+#ifndef HAVE_ANDROID_OS
+ //out = getenv("ANDROID_PRODUCT_OUT");
+#endif
+ if (out == NULL)
+ out = "";
+
+ char* systemDir = (char*) malloc(strlen(out) + strlen(kSystemDir) +1);
+ char* dataDir = (char*) malloc(strlen(out) + strlen(kDataDir) +1);
+
+ sprintf(systemDir, "%s%s", out, kSystemDir);
+ sprintf(dataDir, "%s%s", out, kDataDir);
+ setenv("ANDROID_ROOT", systemDir, 1);
+ setenv("ANDROID_DATA", dataDir, 1);
+
+ char* assetDir = (char*) malloc(strlen(systemDir) + strlen(kAppSubdir) +1);
+ sprintf(assetDir, "%s%s", systemDir, kAppSubdir);
+
+ LOGI("Startup: sys='%s' asset='%s' data='%s'\n",
+ systemDir, assetDir, dataDir);
+ free(systemDir);
+ free(dataDir);
+
+#ifdef HAVE_ANDROID_OS
+ /* set up a process group for easier killing on the device */
+ setpgid(0, getpid());
+#endif
+
+ // Change to asset dir. This is only necessary if we've changed to
+ // a different directory, but there's little harm in doing it regardless.
+ //
+ // Expecting assets to live in the current dir is not a great idea,
+ // because some of our code or one of our libraries could change the
+ // directory out from under us. Preserve the behavior for now.
+ if (chdir(assetDir) != 0) {
+ LOGW("WARNING: could not change dir to '%s': %s\n",
+ assetDir, strerror(errno));
+ }
+ free(assetDir);
+
+#if 0
+ // Hack to keep libc from beating the filesystem to death. It's
+ // hitting /etc/localtime frequently,
+ //
+ // This statement locks us into Pacific time. We could do better,
+ // but there's not much point until we're sure that the library
+ // can't be changed to do more along the lines of what we want.
+#ifndef XP_WIN
+ setenv("TZ", "PST+8PDT,M4.1.0/2,M10.5.0/2", true);
+#endif
+#endif
+
+ /* track our progress through the boot sequence */
+ const int LOG_BOOT_PROGRESS_START = 3000;
+ LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
+ ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+
+ validateTime();
+
+ proc = ProcessState::self();
+
+ boot_init();
+
+ /* If we are in multiprocess mode, have zygote spawn the system
+ * server process and call system_init(). If we are running in
+ * single process mode just call system_init() directly.
+ */
+ if (proc->supportsProcesses()) {
+ // If stdio logging is on, system_server should not inherit our stdio
+ // The dalvikvm instance will copy stdio to the log on its own
+ char propBuf[PROPERTY_VALUE_MAX];
+ bool logStdio = false;
+ property_get("log.redirect-stdio", propBuf, "");
+ logStdio = (strcmp(propBuf, "true") == 0);
+
+ zygote_run_oneshot((int)(!logStdio),
+ sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),
+ ZYGOTE_ARGV);
+
+ //start_process("/system/bin/mediaserver");
+
+ } else {
+#ifndef HAVE_ANDROID_OS
+ QuickRuntime* runt = new QuickRuntime();
+ runt->start("com/android/server/SystemServer",
+ false /* spontaneously fork system server from zygote */);
+#endif
+ }
+
+ //printf("+++ post-zygote\n");
+
+ finish_system_init(proc);
+ run(proc);
+
+bail:
+ if (proc != NULL) {
+ proc->setContextObject(NULL);
+ }
+
+ return 0;
+}
diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk
new file mode 100644
index 0000000..37c3d94
--- /dev/null
+++ b/cmds/surfaceflinger/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main_surfaceflinger.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libsurfaceflinger \
+ libutils
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../../libs/surfaceflinger
+
+LOCAL_MODULE:= surfaceflinger
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp
new file mode 100644
index 0000000..7c89578
--- /dev/null
+++ b/cmds/surfaceflinger/main_surfaceflinger.cpp
@@ -0,0 +1,18 @@
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <SurfaceFlinger.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ LOGI("ServiceManager: %p", sm.get());
+ SurfaceFlinger::instantiate();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/include/GLES/egl.h b/include/GLES/egl.h
new file mode 100644
index 0000000..08834ab
--- /dev/null
+++ b/include/GLES/egl.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_EGL_H
+#define ANDROID_EGL_H
+
+#include <GLES/gl.h>
+#include <GLES/egltypes.h>
+#include <GLES/eglnatives.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EGL_VERSION_1_0 1
+#define EGL_VERSION_1_1 1
+#define EGL_VERSION_1_2 1
+
+#define EGL_FALSE 0
+#define EGL_TRUE 1
+
+/* Errors */
+#define EGL_SUCCESS 0x3000
+#define EGL_NOT_INITIALIZED 0x3001
+#define EGL_BAD_ACCESS 0x3002
+#define EGL_BAD_ALLOC 0x3003
+#define EGL_BAD_ATTRIBUTE 0x3004
+#define EGL_BAD_CONFIG 0x3005
+#define EGL_BAD_CONTEXT 0x3006
+#define EGL_BAD_CURRENT_SURFACE 0x3007
+#define EGL_BAD_DISPLAY 0x3008
+#define EGL_BAD_MATCH 0x3009
+#define EGL_BAD_NATIVE_PIXMAP 0x300A
+#define EGL_BAD_NATIVE_WINDOW 0x300B
+#define EGL_BAD_PARAMETER 0x300C
+#define EGL_BAD_SURFACE 0x300D
+#define EGL_CONTEXT_LOST 0x300E
+
+/* Config attributes */
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_RED_SIZE 0x3024
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_STENCIL_SIZE 0x3026
+#define EGL_CONFIG_CAVEAT 0x3027
+#define EGL_CONFIG_ID 0x3028
+#define EGL_LEVEL 0x3029
+#define EGL_MAX_PBUFFER_HEIGHT 0x302A
+#define EGL_MAX_PBUFFER_PIXELS 0x302B
+#define EGL_MAX_PBUFFER_WIDTH 0x302C
+#define EGL_NATIVE_RENDERABLE 0x302D
+#define EGL_NATIVE_VISUAL_ID 0x302E
+#define EGL_NATIVE_VISUAL_TYPE 0x302F
+#define EGL_SAMPLES 0x3031
+#define EGL_SAMPLE_BUFFERS 0x3032
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_TRANSPARENT_TYPE 0x3034
+#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
+#define EGL_TRANSPARENT_RED_VALUE 0x3037
+#define EGL_NONE 0x3038
+#define EGL_BIND_TO_TEXTURE_RGB 0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
+#define EGL_MIN_SWAP_INTERVAL 0x303B
+#define EGL_MAX_SWAP_INTERVAL 0x303C
+#define EGL_LUMINANCE_SIZE 0x303D
+#define EGL_ALPHA_MASK_SIZE 0x303E
+#define EGL_COLOR_BUFFER_TYPE 0x303F
+#define EGL_RENDERABLE_TYPE 0x3040
+
+/* Config values */
+#define EGL_DONT_CARE ((EGLint)-1)
+
+#define EGL_SLOW_CONFIG 0x3050
+#define EGL_NON_CONFORMANT_CONFIG 0x3051
+#define EGL_TRANSPARENT_RGB 0x3052
+#define EGL_NO_TEXTURE 0x305C
+#define EGL_TEXTURE_RGB 0x305D
+#define EGL_TEXTURE_RGBA 0x305E
+#define EGL_TEXTURE_2D 0x305F
+#define EGL_RGB_BUFFER 0x308E
+#define EGL_LUMINANCE_BUFFER 0x308F
+
+/* Config attribute mask bits */
+#define EGL_PBUFFER_BIT 0x01
+#define EGL_PIXMAP_BIT 0x02
+#define EGL_WINDOW_BIT 0x04
+#define EGL_OPENGL_ES_BIT 0x01
+#define EGL_OPENVG_BIT 0x02
+
+/* String names */
+#define EGL_VENDOR 0x3053
+#define EGL_VERSION 0x3054
+#define EGL_EXTENSIONS 0x3055
+#define EGL_CLIENT_APIS 0x308D
+
+/* Surface attributes */
+#define EGL_HEIGHT 0x3056
+#define EGL_WIDTH 0x3057
+#define EGL_LARGEST_PBUFFER 0x3058
+#define EGL_TEXTURE_FORMAT 0x3080
+#define EGL_TEXTURE_TARGET 0x3081
+#define EGL_MIPMAP_TEXTURE 0x3082
+#define EGL_MIPMAP_LEVEL 0x3083
+#define EGL_RENDER_BUFFER 0x3086
+#define EGL_COLORSPACE 0x3087
+#define EGL_ALPHA_FORMAT 0x3088
+#define EGL_HORIZONTAL_RESOLUTION 0x3090
+#define EGL_VERTICAL_RESOLUTION 0x3091
+#define EGL_PIXEL_ASPECT_RATIO 0x3092
+#define EGL_SWAP_BEHAVIOR 0x3093
+
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_SINGLE_BUFFER 0x3085
+
+#define EGL_DISPLAY_SCALING 10000
+
+#define EGL_UNKNOWN ((EGLint)-1)
+
+/* Back buffer swap behaviors */
+#define EGL_BUFFER_PRESERVED 0x3094
+#define EGL_BUFFER_DESTROYED 0x3095
+
+/* CreatePbufferFromClientBuffer buffer types */
+#define EGL_OPENVG_IMAGE 0x3096
+
+/* QueryContext targets */
+#define EGL_CONTEXT_CLIENT_TYPE 0x3097
+
+/* BindAPI/QueryAPI targets */
+#define EGL_OPENGL_ES_API 0x30A0
+#define EGL_OPENVG_API 0x30A1
+
+/* WaitNative engines */
+#define EGL_CORE_NATIVE_ENGINE 0x305B
+
+/* Current surfaces */
+#define EGL_DRAW 0x3059
+#define EGL_READ 0x305A
+
+
+EGLDisplay eglGetDisplay(NativeDisplayType display);
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLBoolean eglTerminate(EGLDisplay dpy);
+
+EGLBoolean eglGetConfigs( EGLDisplay dpy,
+ EGLConfig *configs,
+ EGLint config_size, EGLint *num_config);
+
+EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config);
+
+EGLBoolean eglGetConfigAttrib( EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value);
+
+EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
+ NativeWindowType window,
+ const EGLint *attrib_list);
+
+EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
+ NativePixmapType pixmap,
+ const EGLint *attrib_list);
+
+EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list);
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
+
+EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint *value);
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_list, const EGLint *attrib_list);
+
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
+
+EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx);
+
+EGLContext eglGetCurrentContext(void);
+EGLSurface eglGetCurrentSurface(EGLint readdraw);
+EGLDisplay eglGetCurrentDisplay(void);
+EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
+ EGLint attribute, EGLint *value);
+
+EGLBoolean eglWaitGL(void);
+EGLBoolean eglWaitNative(EGLint engine);
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
+EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
+ NativePixmapType target);
+
+EGLint eglGetError(void);
+const char* eglQueryString(EGLDisplay dpy, EGLint name);
+void (*eglGetProcAddress (const char *procname))();
+
+/* ----------------------------------------------------------------------------
+ * EGL 1.1
+ * ----------------------------------------------------------------------------
+ */
+
+EGLBoolean eglSurfaceAttrib(
+ EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
+EGLBoolean eglBindTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLBoolean eglReleaseTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval);
+
+/* ----------------------------------------------------------------------------
+ * EGL 1.2
+ * ----------------------------------------------------------------------------
+ */
+
+EGLBoolean eglBindAPI(EGLenum api);
+EGLenum eglQueryAPI(void);
+EGLBoolean eglWaitClient(void);
+EGLBoolean eglReleaseThread(void);
+EGLSurface eglCreatePbufferFromClientBuffer(
+ EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+ EGLConfig config, const EGLint *attrib_list);
+
+/* ----------------------------------------------------------------------------
+ * Android extentions
+ * ----------------------------------------------------------------------------
+ */
+
+EGLBoolean eglSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+ EGLint l, EGLint t, EGLint w, EGLint h);
+
+EGLBoolean eglCopyFrontToBackANDROID(EGLDisplay dpy,
+ EGLSurface surface,
+ EGLint l, EGLint t, EGLint w, EGLint h);
+
+const char* eglQueryStringConfigANDROID(
+ EGLDisplay dpy, EGLConfig config, EGLint name);
+
+void* eglGetRenderBufferAddressANDROID(EGLDisplay dpy, EGLSurface surface);
+
+EGLBoolean eglCopyBitsANDROID(EGLDisplay dpy,
+ NativeWindowType draw, EGLint x, EGLint y,
+ NativeWindowType read,
+ EGLint crop_x, EGLint crop_y, EGLint crop_w, EGLint crop_h,
+ EGLint flags);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /*ANDROID_EGL_H*/
diff --git a/include/GLES/eglnatives.h b/include/GLES/eglnatives.h
new file mode 100644
index 0000000..f9e544c
--- /dev/null
+++ b/include/GLES/eglnatives.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_EGLNATIVES_H
+#define ANDROID_EGLNATIVES_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*****************************************************************************/
+
+struct egl_native_window_t;
+struct egl_native_pixmap_t;
+
+
+typedef struct egl_native_window_t* NativeWindowType;
+typedef struct egl_native_pixmap_t* NativePixmapType;
+typedef void* NativeDisplayType;
+
+/*
+ * This a conveniance function to create a NativeWindowType surface
+ * that maps to the whole screen
+ * This function is actually implemented in libui.so
+ */
+
+NativeWindowType android_createDisplaySurface();
+
+/* flags returned from swapBuffer */
+#define EGL_NATIVES_FLAG_SIZE_CHANGED 0x00000001
+
+/* surface flags */
+#define EGL_NATIVES_FLAG_DESTROY_BACKBUFFER 0x00000001
+
+enum native_pixel_format_t
+{
+ NATIVE_PIXEL_FORMAT_RGBA_8888 = 1,
+ NATIVE_PIXEL_FORMAT_RGB_565 = 4,
+ NATIVE_PIXEL_FORMAT_RGBA_5551 = 6,
+ NATIVE_PIXEL_FORMAT_RGBA_4444 = 7,
+ NATIVE_PIXEL_FORMAT_YCbCr_422_SP= 0x10,
+ NATIVE_PIXEL_FORMAT_YCbCr_420_SP= 0x11,
+};
+
+enum native_memory_type_t
+{
+ NATIVE_MEMORY_TYPE_PMEM = 0,
+ NATIVE_MEMORY_TYPE_GPU = 1,
+ NATIVE_MEMORY_TYPE_FB = 2,
+ NATIVE_MEMORY_TYPE_HEAP = 128
+};
+
+
+struct egl_native_window_t
+{
+ /*
+ * magic must be set to 0x600913
+ */
+ uint32_t magic;
+
+ /*
+ * must be sizeof(egl_native_window_t)
+ */
+ uint32_t version;
+
+ /*
+ * ident is reserved for the Android platform
+ */
+ uint32_t ident;
+
+ /*
+ * width, height and stride of the window in pixels
+ * Any of these value can be nul in which case GL commands are
+ * accepted and processed as usual, but not rendering occurs.
+ */
+ int width; // w=h=0 is legal
+ int height;
+ int stride;
+
+ /*
+ * format of the native window (see ui/PixelFormat.h)
+ */
+ int format;
+
+ /*
+ * Offset of the bits in the VRAM
+ */
+ intptr_t offset;
+
+ /*
+ * flags describing some attributes of this surface
+ * EGL_NATIVES_FLAG_DESTROY_BACKBUFFER: backbuffer not preserved after
+ * eglSwapBuffers
+ */
+ uint32_t flags;
+
+ /*
+ * horizontal and vertical resolution in DPI
+ */
+ float xdpi;
+ float ydpi;
+
+ /*
+ * refresh rate in frames per second (Hz)
+ */
+ float fps;
+
+
+ /*
+ * Base memory virtual address of the surface in the CPU side
+ */
+ intptr_t base;
+
+ /*
+ * Heap the offset above is based from
+ */
+ int fd;
+
+ /*
+ * Memory type the surface resides into
+ */
+ uint8_t memory_type;
+
+ /*
+ * Reserved for future use. MUST BE ZERO.
+ */
+ uint8_t reserved_pad[3];
+ int reserved[8];
+
+ /*
+ * Vertical stride (only relevant with planar formats)
+ */
+
+ int vstride;
+
+ /*
+ * Hook called by EGL to hold a reference on this structure
+ */
+ void (*incRef)(NativeWindowType window);
+
+ /*
+ * Hook called by EGL to release a reference on this structure
+ */
+ void (*decRef)(NativeWindowType window);
+
+ /*
+ * Hook called by EGL to perform a page flip. This function
+ * may update the size attributes above, in which case it returns
+ * the EGL_NATIVES_FLAG_SIZE_CHANGED bit set.
+ */
+ uint32_t (*swapBuffers)(NativeWindowType window);
+
+ /*
+ * Hook called by EGL to set the swap rectangle. this hook can be
+ * null (operation not supported)
+ */
+ void (*setSwapRectangle)(NativeWindowType window, int l, int t, int w, int h);
+
+ /*
+ * Reserved for future use. MUST BE ZERO.
+ */
+ void (*reserved_proc_0)(void);
+
+
+ /*
+ * Hook called by EGL to retrieve the next buffer to render into.
+ * This call updates this structure.
+ */
+ uint32_t (*nextBuffer)(NativeWindowType window);
+
+ /*
+ * Hook called by EGL when the native surface is associated to EGL
+ * (eglCreateWindowSurface). Can be NULL.
+ */
+ void (*connect)(NativeWindowType window);
+
+ /*
+ * Hook called by EGL when eglDestroySurface is called. Can be NULL.
+ */
+ void (*disconnect)(NativeWindowType window);
+
+ /*
+ * Reserved for future use. MUST BE ZERO.
+ */
+ void (*reserved_proc[11])(void);
+
+ /*
+ * Some storage reserved for the oem driver.
+ */
+ intptr_t oem[4];
+};
+
+
+struct egl_native_pixmap_t
+{
+ int32_t version; /* must be 32 */
+ int32_t width;
+ int32_t height;
+ int32_t stride;
+ uint8_t* data;
+ uint8_t format;
+ uint8_t rfu[3];
+ union {
+ uint32_t compressedFormat;
+ int32_t vstride;
+ };
+ int32_t reserved;
+};
+
+/*****************************************************************************/
+
+/*
+ * OEM's egl's library (libhgl.so) must imlement these hooks to allocate
+ * the GPU memory they need
+ */
+
+
+typedef struct
+{
+ // for internal use
+ void* user;
+ // virtual address of this area
+ void* base;
+ // size of this area in bytes
+ size_t size;
+ // physical address of this area
+ void* phys;
+ // offset in this area available to the GPU
+ size_t offset;
+ // fd of this area
+ int fd;
+} gpu_area_t;
+
+typedef struct
+{
+ // area where GPU registers are mapped
+ gpu_area_t regs;
+ // number of extra areas (currently limited to 2)
+ int32_t count;
+ // extra GPU areas (currently limited to 2)
+ gpu_area_t gpu[2];
+} request_gpu_t;
+
+
+typedef request_gpu_t* (*OEM_EGL_acquire_gpu_t)(void* user);
+typedef int (*OEM_EGL_release_gpu_t)(void* user, request_gpu_t* handle);
+typedef void (*register_gpu_t)
+ (void* user, OEM_EGL_acquire_gpu_t, OEM_EGL_release_gpu_t);
+
+void oem_register_gpu(
+ void* user,
+ OEM_EGL_acquire_gpu_t acquire,
+ OEM_EGL_release_gpu_t release);
+
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANDROID_EGLNATIVES_H */
diff --git a/include/GLES/egltypes.h b/include/GLES/egltypes.h
new file mode 100644
index 0000000..698239b
--- /dev/null
+++ b/include/GLES/egltypes.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_EGL_TYPES_H
+#define ANDROID_EGL_TYPES_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned int EGLBoolean;
+typedef int32_t EGLint;
+typedef int EGLenum;
+typedef void *EGLDisplay;
+typedef void *EGLConfig;
+typedef void *EGLSurface;
+typedef void *EGLContext;
+typedef void *EGLClientBuffer;
+
+#define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0)
+
+#define EGL_NO_CONTEXT ((EGLContext)0)
+#define EGL_NO_DISPLAY ((EGLDisplay)0)
+#define EGL_NO_SURFACE ((EGLSurface)0)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* ANDROID_EGL_TYPES_H */
diff --git a/include/GLES/gl.h b/include/GLES/gl.h
new file mode 100644
index 0000000..50b6ac4
--- /dev/null
+++ b/include/GLES/gl.h
@@ -0,0 +1,639 @@
+/*
+ * Copyright (C) 2006 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 __gl_h_
+#define __gl_h_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+typedef int8_t GLbyte; // b
+typedef int16_t GLshort; // s
+typedef int32_t GLint; // i
+typedef ssize_t GLsizei; // i
+typedef int32_t GLfixed; // x
+typedef int32_t GLclampx; // x
+typedef float GLfloat; // f
+typedef float GLclampf; // f
+typedef uint8_t GLubyte; // ub
+typedef uint8_t GLboolean; // ub
+typedef uint16_t GLushort; // us
+typedef uint32_t GLuint; // ui
+typedef unsigned int GLenum; // ui
+typedef unsigned int GLbitfield; // ui
+typedef void GLvoid;
+typedef intptr_t GLintptr;
+typedef int GLsizeiptr;
+typedef GLintptr GLintptrARB;
+typedef GLsizeiptr GLsizeiptrARB;
+
+/*****************************************************************************/
+
+#define GL_VERSION_ES_CM_1_0 1
+#define GL_VERSION_ES_CL_1_0 1
+#define GL_VERSION_ES_CM_1_1 1
+#define GL_VERSION_ES_CL_1_1 1
+
+#define GL_OES_byte_coordinates 1
+#define GL_OES_fixed_point 1
+#define GL_OES_single_precision 1
+#define GL_OES_read_format 1
+#define GL_OES_compressed_paletted_texture 1
+#define GL_OES_draw_texture 1
+#define GL_OES_matrix_get 1
+#define GL_OES_query_matrix 1
+#define GL_OES_vertex_buffer_object 1
+#define GL_OES_point_size_array 1
+#define GL_OES_point_sprite 1
+#define GL_ARB_texture_non_power_of_two 1
+
+/*****************************************************************************/
+/* OpenGL ES 1.0 names */
+
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* begin mode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* clear mask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* enable/disable */
+#define GL_FOG 0x0B60
+#define GL_LIGHTING 0x0B50
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_ALPHA_TEST 0x0BC0
+#define GL_BLEND 0x0BE2
+#define GL_COLOR_LOGIC_OP 0x0BF2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_POINT_SMOOTH 0x0B10
+#define GL_LINE_SMOOTH 0x0B20
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_COLOR_MATERIAL 0x0B57
+#define GL_NORMALIZE 0x0BA1
+#define GL_RESCALE_NORMAL 0x803A
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_VERTEX_ARRAY 0x8074
+#define GL_NORMAL_ARRAY 0x8075
+#define GL_COLOR_ARRAY 0x8076
+#define GL_TEXTURE_COORD_ARRAY 0x8078
+#define GL_MULTISAMPLE 0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* gets */
+#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
+#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_MAX_LIGHTS 0x0D31
+#define GL_MAX_CLIP_PLANES 0x0D32
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36
+#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38
+#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_MAX_ELEMENTS_VERTICES 0x80E8
+#define GL_MAX_ELEMENTS_INDICES 0x80E9
+#define GL_MAX_TEXTURE_UNITS 0x84E2
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+
+/* clip planes */
+#define GL_CLIP_PLANE0 0x3000
+#define GL_CLIP_PLANE1 0x3001
+#define GL_CLIP_PLANE2 0x3002
+#define GL_CLIP_PLANE3 0x3003
+#define GL_CLIP_PLANE4 0x3004
+#define GL_CLIP_PLANE5 0x3005
+
+/* errors */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_STACK_OVERFLOW 0x0503
+#define GL_STACK_UNDERFLOW 0x0504
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* fog */
+#define GL_EXP 0x0800
+#define GL_EXP2 0x0801
+#define GL_FOG_DENSITY 0x0B62
+#define GL_FOG_START 0x0B63
+#define GL_FOG_END 0x0B64
+#define GL_FOG_MODE 0x0B65
+#define GL_FOG_COLOR 0x0B66
+
+/* culling */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* hints */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
+#define GL_POINT_SMOOTH_HINT 0x0C51
+#define GL_LINE_SMOOTH_HINT 0x0C52
+#define GL_POLYGON_SMOOTH_HINT 0x0C53
+#define GL_FOG_HINT 0x0C54
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* lights */
+#define GL_LIGHT_MODEL_AMBIENT 0x0B53
+#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52
+
+#define GL_AMBIENT 0x1200
+#define GL_DIFFUSE 0x1201
+#define GL_SPECULAR 0x1202
+#define GL_POSITION 0x1203
+#define GL_SPOT_DIRECTION 0x1204
+#define GL_SPOT_EXPONENT 0x1205
+#define GL_SPOT_CUTOFF 0x1206
+#define GL_CONSTANT_ATTENUATION 0x1207
+#define GL_LINEAR_ATTENUATION 0x1208
+#define GL_QUADRATIC_ATTENUATION 0x1209
+
+#define GL_LIGHT0 0x4000
+#define GL_LIGHT1 0x4001
+#define GL_LIGHT2 0x4002
+#define GL_LIGHT3 0x4003
+#define GL_LIGHT4 0x4004
+#define GL_LIGHT5 0x4005
+#define GL_LIGHT6 0x4006
+#define GL_LIGHT7 0x4007
+
+/* material */
+#define GL_EMISSION 0x1600
+#define GL_SHININESS 0x1601
+#define GL_AMBIENT_AND_DIFFUSE 0x1602
+
+/* matrix */
+#define GL_MODELVIEW 0x1700
+#define GL_PROJECTION 0x1701
+#define GL_TEXTURE 0x1702
+
+/* types */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* pixel formats */
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* pixel store */
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+
+/* pixel types */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* logic op */
+#define GL_CLEAR 0x1500 // 0
+#define GL_AND 0x1501 // s & d
+#define GL_AND_REVERSE 0x1502 // s & ~d
+#define GL_COPY 0x1503 // s
+#define GL_AND_INVERTED 0x1504 // ~s & d
+#define GL_NOOP 0x1505 // d
+#define GL_XOR 0x1506 // s ^ d
+#define GL_OR 0x1507 // s | d
+#define GL_NOR 0x1508 // ~(s | d)
+#define GL_EQUIV 0x1509 // ~(s ^ d)
+#define GL_INVERT 0x150A // ~d
+#define GL_OR_REVERSE 0x150B // s | ~d
+#define GL_COPY_INVERTED 0x150C // ~s
+#define GL_OR_INVERTED 0x150D // ~s | d
+#define GL_NAND 0x150E // ~(s & d)
+#define GL_SET 0x150F // 1
+
+/* shade model */
+#define GL_FLAT 0x1D00
+#define GL_SMOOTH 0x1D01
+
+/* strings */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* stencil */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+
+/* alpha & stencil */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* blending equation & function */
+#define GL_ZERO 0 // SD
+#define GL_ONE 1 // SD
+#define GL_SRC_COLOR 0x0300 // D
+#define GL_ONE_MINUS_SRC_COLOR 0x0301 // D
+#define GL_SRC_ALPHA 0x0302 // SD
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303 // SD
+#define GL_DST_ALPHA 0x0304 // SD
+#define GL_ONE_MINUS_DST_ALPHA 0x0305 // SD
+#define GL_DST_COLOR 0x0306 // S
+#define GL_ONE_MINUS_DST_COLOR 0x0307 // S
+#define GL_SRC_ALPHA_SATURATE 0x0308 // S
+
+/* Texture parameter name */
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_GENERATE_MIPMAP 0x8191
+#define GL_TEXTURE_CROP_RECT_OES 0x8B9D
+
+/* Texture Filter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* Texture Wrap Mode */
+#define GL_CLAMP 0x2900
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+
+/* Texture Env Mode */
+#define GL_REPLACE 0x1E01
+#define GL_MODULATE 0x2100
+#define GL_DECAL 0x2101
+#define GL_ADD 0x0104
+
+/* Texture Env Parameter */
+#define GL_TEXTURE_ENV_MODE 0x2200
+#define GL_TEXTURE_ENV_COLOR 0x2201
+
+/* Texture Env Target */
+#define GL_TEXTURE_ENV 0x2300
+
+/* TMUs */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+
+/*****************************************************************************/
+/* OpenGL ES 1.1 additions */
+
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
+
+/*****************************************************************************/
+/* Required extensions */
+
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
+
+#define GL_POINT_SPRITE_OES 0x8861
+#define GL_COORD_REPLACE_OES 0x8862
+
+#define GL_POINT_SIZE_ARRAY_OES 0x8B9C
+#define GL_POINT_SIZE_ARRAY_TYPE_OES 0x898A
+#define GL_POINT_SIZE_ARRAY_STRIDE_OES 0x898B
+#define GL_POINT_SIZE_ARRAY_POINTER_OES 0x898C
+#define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F
+
+/*****************************************************************************/
+/* Extensions */
+
+#define GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES 0x898D
+#define GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES 0x898E
+#define GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES 0x898F
+
+#define GL_DIRECT_TEXTURE_2D_QUALCOMM 0x7E80
+
+
+
+
+/*****************************************************************************/
+/* OpenGL ES 1.0 functions */
+
+void glActiveTexture(GLenum texture);
+void glAlphaFunc(GLenum func, GLclampf ref);
+void glAlphaFuncx(GLenum func, GLclampx ref);
+void glBindTexture(GLenum target, GLuint texture);
+void glBlendFunc(GLenum sfactor, GLenum dfactor);
+void glClear(GLbitfield mask);
+void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+void glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+void glClearDepthf(GLclampf depth);
+void glClearDepthx(GLclampx depth);
+void glClearStencil(GLint s);
+void glClientActiveTexture(GLenum texture);
+void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void glColor4x(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+void glColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
+void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLsizei imageSize, const GLvoid *data);
+void glCompressedTexSubImage2D( GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize,
+ const GLvoid *data);
+void glCopyTexImage2D( GLenum target, GLint level, GLenum internalformat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border);
+void glCopyTexSubImage2D( GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLint x, GLint y, GLsizei width,
+ GLsizei height);
+void glCullFace(GLenum mode);
+void glDeleteTextures(GLsizei n, const GLuint *textures);
+void glDepthFunc(GLenum func);
+void glDepthMask(GLboolean flag);
+void glDepthRangef(GLclampf zNear, GLclampf zFar);
+void glDepthRangex(GLclampx zNear, GLclampx zFar);
+void glDisable(GLenum cap);
+void glDisableClientState(GLenum array);
+void glDrawArrays(GLenum mode, GLint first, GLsizei count);
+void glDrawElements(GLenum mode, GLsizei count,
+ GLenum type, const GLvoid *indices);
+void glEnable(GLenum cap);
+void glEnableClientState(GLenum array);
+void glFinish(void);
+void glFlush(void);
+void glFogf(GLenum pname, GLfloat param);
+void glFogfv(GLenum pname, const GLfloat *params);
+void glFogx(GLenum pname, GLfixed param);
+void glFogxv(GLenum pname, const GLfixed *params);
+void glFrontFace(GLenum mode);
+void glFrustumf(GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar);
+void glFrustumx(GLfixed left, GLfixed right,
+ GLfixed bottom, GLfixed top,
+ GLfixed zNear, GLfixed zFar);
+void glGenTextures(GLsizei n, GLuint *textures);
+GLenum glGetError(void);
+void glGetIntegerv(GLenum pname, GLint *params);
+const GLubyte * glGetString(GLenum name);
+void glHint(GLenum target, GLenum mode);
+void glLightModelf(GLenum pname, GLfloat param);
+void glLightModelfv(GLenum pname, const GLfloat *params);
+void glLightModelx(GLenum pname, GLfixed param);
+void glLightModelxv(GLenum pname, const GLfixed *params);
+void glLightf(GLenum light, GLenum pname, GLfloat param);
+void glLightfv(GLenum light, GLenum pname, const GLfloat *params);
+void glLightx(GLenum light, GLenum pname, GLfixed param);
+void glLightxv(GLenum light, GLenum pname, const GLfixed *params);
+void glLineWidth(GLfloat width);
+void glLineWidthx(GLfixed width);
+void glLoadIdentity(void);
+void glLoadMatrixf(const GLfloat *m);
+void glLoadMatrixx(const GLfixed *m);
+void glLogicOp(GLenum opcode);
+void glMaterialf(GLenum face, GLenum pname, GLfloat param);
+void glMaterialfv(GLenum face, GLenum pname, const GLfloat *params);
+void glMaterialx(GLenum face, GLenum pname, GLfixed param);
+void glMaterialxv(GLenum face, GLenum pname, const GLfixed *params);
+void glMatrixMode(GLenum mode);
+void glMultMatrixf(const GLfloat *m);
+void glMultMatrixx(const GLfixed *m);
+void glMultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+void glMultiTexCoord4x(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz);
+void glNormal3x(GLfixed nx, GLfixed ny, GLfixed nz);
+void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer);
+void glOrthof( GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar);
+void glOrthox( GLfixed left, GLfixed right,
+ GLfixed bottom, GLfixed top,
+ GLfixed zNear, GLfixed zFar);
+void glPixelStorei(GLenum pname, GLint param);
+void glPointSize(GLfloat size);
+void glPointSizex(GLfixed size);
+void glPolygonOffset(GLfloat factor, GLfloat units);
+void glPolygonOffsetx(GLfixed factor, GLfixed units);
+void glPopMatrix(void);
+void glPushMatrix(void);
+void glReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid *pixels);
+void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+void glRotatex(GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+void glSampleCoverage(GLclampf value, GLboolean invert);
+void glSampleCoveragex(GLclampx value, GLboolean invert);
+void glScalef(GLfloat x, GLfloat y, GLfloat z);
+void glScalex(GLfixed x, GLfixed y, GLfixed z);
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
+void glShadeModel(GLenum mode);
+void glStencilFunc(GLenum func, GLint ref, GLuint mask);
+void glStencilMask(GLuint mask);
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass);
+void glTexCoordPointer( GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer);
+void glTexEnvf(GLenum target, GLenum pname, GLfloat param);
+void glTexEnvfv(GLenum target, GLenum pname, const GLfloat *params);
+void glTexEnvx(GLenum target, GLenum pname, GLfixed param);
+void glTexEnvxv(GLenum target, GLenum pname, const GLfixed *params);
+void glTexImage2D( GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border, GLenum format,
+ GLenum type, const GLvoid *pixels);
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param);
+void glTexParameterx(GLenum target, GLenum pname, GLfixed param);
+void glTexSubImage2D( GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid *pixels);
+void glTranslatef(GLfloat x, GLfloat y, GLfloat z);
+void glTranslatex(GLfixed x, GLfixed y, GLfixed z);
+void glVertexPointer( GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer);
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
+
+/*****************************************************************************/
+/* OpenGL ES 1.1 functions */
+
+void glClipPlanef(GLenum plane, const GLfloat* equation);
+void glClipPlanex(GLenum plane, const GLfixed* equation);
+
+void glBindBuffer(GLenum target, GLuint buffer);
+void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+void glDeleteBuffers(GLsizei n, const GLuint* buffers);
+void glGenBuffers(GLsizei n, GLuint* buffers);
+
+void glGetBooleanv(GLenum pname, GLboolean *params);
+void glGetFixedv(GLenum pname, GLfixed *params);
+void glGetFloatv(GLenum pname, GLfloat *params);
+void glGetPointerv(GLenum pname, void **params);
+void glGetBufferParameteriv(GLenum target, GLenum pname, GLint *params);
+void glGetClipPlanef(GLenum pname, GLfloat eqn[4]);
+void glGetClipPlanex(GLenum pname, GLfixed eqn[4]);
+void glGetLightxv(GLenum light, GLenum pname, GLfixed *params);
+void glGetLightfv(GLenum light, GLenum pname, GLfloat *params);
+void glGetMaterialxv(GLenum face, GLenum pname, GLfixed *params);
+void glGetMaterialfv(GLenum face, GLenum pname, GLfloat *params);
+void glGetTexEnvfv(GLenum env, GLenum pname, GLfloat *params);
+void glGetTexEnviv(GLenum env, GLenum pname, GLint *params);
+void glGetTexEnvxv(GLenum env, GLenum pname, GLfixed *params);
+void glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params);
+void glGetTexParameteriv(GLenum target, GLenum pname, GLint *params);
+void glGetTexParameterxv(GLenum target, GLenum pname, GLfixed *params);
+GLboolean glIsBuffer(GLuint buffer);
+GLboolean glIsEnabled(GLenum cap);
+GLboolean glIsTexture(GLuint texture);
+void glPointParameterf(GLenum pname, GLfloat param);
+void glPointParameterfv(GLenum pname, const GLfloat *params);
+void glPointParameterx(GLenum pname, GLfixed param);
+void glPointParameterxv(GLenum pname, const GLfixed *params);
+void glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+void glTexEnvi(GLenum target, GLenum pname, GLint param);
+void glTexEnviv(GLenum target, GLenum pname, const GLint *params);
+void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params);
+void glTexParameteriv(GLenum target, GLenum pname, const GLint *params);
+void glTexParameteri(GLenum target, GLenum pname, GLint param);
+void glTexParameterxv(GLenum target, GLenum pname, const GLfixed *params);
+
+/*****************************************************************************/
+/* Required extensions functions */
+
+void glPointSizePointerOES(GLenum type, GLsizei stride, const GLvoid *pointer);
+
+
+/*****************************************************************************/
+/* Extensions functions */
+
+void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h);
+void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h);
+void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h);
+void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h);
+void glDrawTexsvOES(const GLshort* coords);
+void glDrawTexivOES(const GLint* coords);
+void glDrawTexfvOES(const GLfloat* coords);
+void glDrawTexxvOES(const GLfixed* coords);
+GLbitfield glQueryMatrixxOES(GLfixed* mantissa, GLint* exponent);
+
+/* called by dalvik */
+void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+ const GLvoid *ptr, GLsizei count);
+void glNormalPointerBounds(GLenum type, GLsizei stride,
+ const GLvoid *pointer, GLsizei count);
+void glTexCoordPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+void glVertexPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl_h_ */
diff --git a/include/pim/EventRecurrence.h b/include/pim/EventRecurrence.h
new file mode 100644
index 0000000..1ceda41
--- /dev/null
+++ b/include/pim/EventRecurrence.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006 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 _PIM_EVENT_RECURRENCE_H
+#define _PIM_EVENT_RECURRENCE_H
+
+#include <utils/String16.h>
+
+namespace android {
+
+struct EventRecurrence
+{
+public:
+ EventRecurrence();
+ ~EventRecurrence();
+
+ status_t parse(const String16&);
+
+
+ enum freq_t {
+ SECONDLY = 1,
+ MINUTELY = 2,
+ HOURLY = 3,
+ DAILY = 4,
+ WEEKLY = 5,
+ MONTHLY = 6,
+ YEARLY = 7
+ };
+
+ enum {
+ SU = 0x00010000,
+ MO = 0x00020000,
+ TU = 0x00040000,
+ WE = 0x00080000,
+ TH = 0x00100000,
+ FR = 0x00200000,
+ SA = 0x00400000
+ };
+
+ freq_t freq;
+ String16 until;
+ int count;
+ int interval;
+ int* bysecond;
+ int bysecondCount;
+ int* byminute;
+ int byminuteCount;
+ int* byhour;
+ int byhourCount;
+ int* byday;
+ int* bydayNum;
+ int bydayCount;
+ int* bymonthday;
+ int bymonthdayCount;
+ int* byyearday;
+ int byyeardayCount;
+ int* byweekno;
+ int byweeknoCount;
+ int* bymonth;
+ int bymonthCount;
+ int* bysetpos;
+ int bysetposCount;
+ int wkst;
+};
+
+}; // namespace android
+
+#endif // _PIM_EVENT_RECURRENCE_H
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
new file mode 100644
index 0000000..67d50fd
--- /dev/null
+++ b/include/private/opengles/gl_context.h
@@ -0,0 +1,624 @@
+/*
+ * Copyright (C) 2006 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_OPENGLES_CONTEXT_H
+#define ANDROID_OPENGLES_CONTEXT_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <pthread.h>
+#ifdef HAVE_ANDROID_OS
+#include <sys/tls.h>
+#endif
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+namespace android {
+
+const unsigned int OGLES_NUM_COMPRESSED_TEXTURE_FORMATS = 10;
+
+class EGLTextureObject;
+class EGLSurfaceManager;
+class EGLBufferObjectManager;
+
+namespace gl {
+
+struct ogles_context_t;
+struct matrixx_t;
+struct transform_t;
+struct buffer_t;
+
+ogles_context_t* getGlContext();
+
+template<typename T>
+static inline void swap(T& a, T& b) {
+ T t(a); a = b; b = t;
+}
+template<typename T>
+inline T max(T a, T b) {
+ return a<b ? b : a;
+}
+template<typename T>
+inline T max(T a, T b, T c) {
+ return max(a, max(b, c));
+}
+template<typename T>
+inline T min(T a, T b) {
+ return a<b ? a : b;
+}
+template<typename T>
+inline T min(T a, T b, T c) {
+ return min(a, min(b, c));
+}
+template<typename T>
+inline T min(T a, T b, T c, T d) {
+ return min(min(a,b), min(c,d));
+}
+
+// ----------------------------------------------------------------------------
+// vertices
+// ----------------------------------------------------------------------------
+
+struct vec3_t {
+ union {
+ struct { GLfixed x, y, z; };
+ struct { GLfixed r, g, b; };
+ struct { GLfixed S, T, R; };
+ GLfixed v[3];
+ };
+};
+
+struct vec4_t {
+ union {
+ struct { GLfixed x, y, z, w; };
+ struct { GLfixed r, g, b, a; };
+ struct { GLfixed S, T, R, Q; };
+ GLfixed v[4];
+ };
+};
+
+struct vertex_t {
+ enum {
+ // these constant matter for our clipping
+ CLIP_L = 0x0001, // clipping flags
+ CLIP_R = 0x0002,
+ CLIP_B = 0x0004,
+ CLIP_T = 0x0008,
+ CLIP_N = 0x0010,
+ CLIP_F = 0x0020,
+
+ EYE = 0x0040,
+ RESERVED = 0x0080,
+
+ USER_CLIP_0 = 0x0100, // user clipping flags
+ USER_CLIP_1 = 0x0200,
+ USER_CLIP_2 = 0x0400,
+ USER_CLIP_3 = 0x0800,
+ USER_CLIP_4 = 0x1000,
+ USER_CLIP_5 = 0x2000,
+
+ LIT = 0x4000, // lighting has been applied
+ TT = 0x8000, // texture coords transformed
+
+ FRUSTUM_CLIP_ALL= 0x003F,
+ USER_CLIP_ALL = 0x3F00,
+ CLIP_ALL = 0x3F3F,
+ };
+
+ // the fields below are arranged to minimize d-cache usage
+ // we group together, by cache-line, the fields most likely to be used
+
+ union {
+ vec4_t obj;
+ vec4_t eye;
+ };
+ vec4_t clip;
+
+ uint32_t flags;
+ size_t index; // cache tag, and vertex index
+ GLfixed fog;
+ uint8_t locked;
+ uint8_t mru;
+ uint8_t reserved[2];
+ vec4_t window;
+
+ vec4_t color;
+ vec4_t texture[GGL_TEXTURE_UNIT_COUNT];
+ uint32_t reserved1[4];
+
+ inline void clear() {
+ flags = index = locked = mru = 0;
+ }
+};
+
+struct point_size_t {
+ GGLcoord size;
+ GLboolean smooth;
+};
+
+struct line_width_t {
+ GGLcoord width;
+ GLboolean smooth;
+};
+
+struct polygon_offset_t {
+ GLfixed factor;
+ GLfixed units;
+ GLboolean enable;
+};
+
+// ----------------------------------------------------------------------------
+// arrays
+// ----------------------------------------------------------------------------
+
+struct array_t {
+ typedef void (*fetcher_t)(ogles_context_t*, GLfixed*, const GLvoid*);
+ fetcher_t fetch;
+ GLvoid const* physical_pointer;
+ GLint size;
+ GLsizei stride;
+ GLvoid const* pointer;
+ buffer_t const* bo;
+ uint16_t type;
+ GLboolean enable;
+ GLboolean pad;
+ GLsizei bounds;
+ void init(GLint, GLenum, GLsizei, const GLvoid *, const buffer_t*, GLsizei);
+ inline void resolve();
+ inline const GLubyte* element(GLint i) const {
+ return (const GLubyte*)physical_pointer + i * stride;
+ }
+};
+
+struct array_machine_t {
+ array_t vertex;
+ array_t normal;
+ array_t color;
+ array_t texture[GGL_TEXTURE_UNIT_COUNT];
+ uint8_t activeTexture;
+ uint8_t tmu;
+ uint16_t cull;
+ uint32_t flags;
+ GLenum indicesType;
+ buffer_t const* array_buffer;
+ buffer_t const* element_array_buffer;
+
+ void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei);
+ void (*compileElement)(ogles_context_t*, vertex_t*, GLint);
+
+ void (*mvp_transform)(transform_t const*, vec4_t*, vec4_t const*);
+ void (*mv_transform)(transform_t const*, vec4_t*, vec4_t const*);
+ void (*tex_transform[2])(transform_t const*, vec4_t*, vec4_t const*);
+ void (*perspective)(ogles_context_t*c, vertex_t* v);
+ void (*clipVertex)(ogles_context_t* c, vertex_t* nv,
+ GGLfixed t, const vertex_t* s, const vertex_t* p);
+ void (*clipEye)(ogles_context_t* c, vertex_t* nv,
+ GGLfixed t, const vertex_t* s, const vertex_t* p);
+};
+
+struct vertex_cache_t {
+ enum {
+ // must be at least 4
+ // 3 vertice for triangles
+ // or 2 + 2 for indexed triangles w/ cache contention
+ VERTEX_BUFFER_SIZE = 8,
+ // must be a power of two and at least 3
+ VERTEX_CACHE_SIZE = 64, // 8 KB
+
+ INDEX_BITS = 16,
+ INDEX_MASK = ((1LU<<INDEX_BITS)-1),
+ INDEX_SEQ = 1LU<<INDEX_BITS,
+ };
+ vertex_t* vBuffer;
+ vertex_t* vCache;
+ uint32_t sequence;
+ void* base;
+ uint32_t total;
+ uint32_t misses;
+ int64_t startTime;
+ void init();
+ void uninit();
+ void clear();
+ void dump_stats(GLenum mode);
+};
+
+// ----------------------------------------------------------------------------
+// fog
+// ----------------------------------------------------------------------------
+
+struct fog_t {
+ GLfixed density;
+ GLfixed start;
+ GLfixed end;
+ GLfixed invEndMinusStart;
+ GLenum mode;
+ GLfixed (*fog)(ogles_context_t* c, GLfixed z);
+};
+
+// ----------------------------------------------------------------------------
+// user clip planes
+// ----------------------------------------------------------------------------
+
+const unsigned int OGLES_MAX_CLIP_PLANES = 6;
+
+struct clip_plane_t {
+ vec4_t equation;
+};
+
+struct user_clip_planes_t {
+ clip_plane_t plane[OGLES_MAX_CLIP_PLANES];
+ uint32_t enable;
+};
+
+// ----------------------------------------------------------------------------
+// lighting
+// ----------------------------------------------------------------------------
+
+const unsigned int OGLES_MAX_LIGHTS = 8;
+
+struct light_t {
+ vec4_t ambient;
+ vec4_t diffuse;
+ vec4_t specular;
+ vec4_t implicitAmbient;
+ vec4_t implicitDiffuse;
+ vec4_t implicitSpecular;
+ vec4_t position; // position in eye space
+ vec4_t objPosition;
+ vec4_t normalizedObjPosition;
+ vec4_t spotDir;
+ vec4_t normalizedSpotDir;
+ GLfixed spotExp;
+ GLfixed spotCutoff;
+ GLfixed spotCutoffCosine;
+ GLfixed attenuation[3];
+ GLfixed rConstAttenuation;
+ GLboolean enable;
+};
+
+struct material_t {
+ vec4_t ambient;
+ vec4_t diffuse;
+ vec4_t specular;
+ vec4_t emission;
+ GLfixed shininess;
+};
+
+struct light_model_t {
+ vec4_t ambient;
+ GLboolean twoSide;
+};
+
+struct color_material_t {
+ GLenum face;
+ GLenum mode;
+ GLboolean enable;
+};
+
+struct lighting_t {
+ light_t lights[OGLES_MAX_LIGHTS];
+ material_t front;
+ light_model_t lightModel;
+ color_material_t colorMaterial;
+ uint32_t enabledLights;
+ GLboolean enable;
+ vec4_t implicitSceneEmissionAndAmbient;
+ GLenum shadeModel;
+ typedef void (*light_fct_t)(ogles_context_t*, vertex_t*);
+ void (*lightVertex)(ogles_context_t* c, vertex_t* v);
+ void (*lightTriangle)(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+};
+
+struct culling_t {
+ GLenum cullFace;
+ GLenum frontFace;
+ GLboolean enable;
+};
+
+// ----------------------------------------------------------------------------
+// textures
+// ----------------------------------------------------------------------------
+
+struct texture_unit_t {
+ GLuint name;
+ EGLTextureObject* texture;
+ uint8_t dirty;
+};
+
+struct texture_state_t
+{
+ texture_unit_t tmu[GGL_TEXTURE_UNIT_COUNT];
+ int active; // active tmu
+ EGLTextureObject* defaultTexture;
+ GGLContext* ggl;
+ uint8_t packAlignment;
+ uint8_t unpackAlignment;
+};
+
+// ----------------------------------------------------------------------------
+// transformation and matrices
+// ----------------------------------------------------------------------------
+
+struct matrixf_t;
+
+struct matrixx_t {
+ GLfixed m[16];
+ void load(const matrixf_t& rhs);
+};
+
+struct matrix_stack_t;
+
+
+struct matrixf_t {
+ void loadIdentity();
+ void load(const matrixf_t& rhs);
+
+ inline GLfloat* editElements() { return m; }
+ inline GLfloat const* elements() const { return m; }
+
+ void set(const GLfixed* rhs);
+ void set(const GLfloat* rhs);
+
+ static void multiply(matrixf_t& r,
+ const matrixf_t& lhs, const matrixf_t& rhs);
+
+ void dump(const char* what);
+
+private:
+ friend struct matrix_stack_t;
+ GLfloat m[16];
+ void load(const GLfixed* rhs);
+ void load(const GLfloat* rhs);
+ void multiply(const matrixf_t& rhs);
+ void translate(GLfloat x, GLfloat y, GLfloat z);
+ void scale(GLfloat x, GLfloat y, GLfloat z);
+ void rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z);
+};
+
+enum {
+ OP_IDENTITY = 0x00,
+ OP_TRANSLATE = 0x01,
+ OP_UNIFORM_SCALE = 0x02,
+ OP_SCALE = 0x05,
+ OP_ROTATE = 0x08,
+ OP_SKEW = 0x10,
+ OP_ALL = 0x1F
+};
+
+struct transform_t {
+ enum {
+ FLAGS_2D_PROJECTION = 0x1
+ };
+ matrixx_t matrix;
+ uint32_t flags;
+ uint32_t ops;
+
+ union {
+ struct {
+ void (*point2)(transform_t const* t, vec4_t*, vec4_t const*);
+ void (*point3)(transform_t const* t, vec4_t*, vec4_t const*);
+ void (*point4)(transform_t const* t, vec4_t*, vec4_t const*);
+ };
+ void (*pointv[3])(transform_t const* t, vec4_t*, vec4_t const*);
+ };
+
+ void loadIdentity();
+ void picker();
+ void dump(const char* what);
+};
+
+struct mvui_transform_t : public transform_t
+{
+ void picker();
+};
+
+struct matrix_stack_t {
+ enum {
+ DO_PICKER = 0x1,
+ DO_FLOAT_TO_FIXED = 0x2
+ };
+ transform_t transform;
+ uint8_t maxDepth;
+ uint8_t depth;
+ uint8_t dirty;
+ uint8_t reserved;
+ matrixf_t *stack;
+ uint8_t *ops;
+ void init(int depth);
+ void uninit();
+ void loadIdentity();
+ void load(const GLfixed* rhs);
+ void load(const GLfloat* rhs);
+ void multiply(const matrixf_t& rhs);
+ void translate(GLfloat x, GLfloat y, GLfloat z);
+ void scale(GLfloat x, GLfloat y, GLfloat z);
+ void rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z);
+ GLint push();
+ GLint pop();
+ void validate();
+ matrixf_t& top() { return stack[depth]; }
+ const matrixf_t& top() const { return stack[depth]; }
+ const uint32_t top_ops() const { return ops[depth]; }
+ inline bool isRigidBody() const {
+ return !(ops[depth] & ~(OP_TRANSLATE|OP_UNIFORM_SCALE|OP_ROTATE));
+ }
+};
+
+struct vp_transform_t {
+ transform_t transform;
+ matrixf_t matrix;
+ GLfloat zNear;
+ GLfloat zFar;
+ void loadIdentity();
+};
+
+struct transform_state_t {
+ enum {
+ MODELVIEW = 0x01,
+ PROJECTION = 0x02,
+ VIEWPORT = 0x04,
+ TEXTURE = 0x08,
+ MVUI = 0x10,
+ MVIT = 0x20,
+ MVP = 0x40,
+ };
+ matrix_stack_t *current;
+ matrix_stack_t modelview;
+ matrix_stack_t projection;
+ matrix_stack_t texture[GGL_TEXTURE_UNIT_COUNT];
+
+ // modelview * projection
+ transform_t mvp __attribute__((aligned(32)));
+ // viewport transformation
+ vp_transform_t vpt __attribute__((aligned(32)));
+ // same for 4-D vertices
+ transform_t mvp4;
+ // full modelview inverse transpose
+ transform_t mvit4;
+ // upper 3x3 of mv-inverse-transpose (for normals)
+ mvui_transform_t mvui;
+
+ GLenum matrixMode;
+ GLenum rescaleNormals;
+ uint32_t dirty;
+ void invalidate();
+ void update_mvp();
+ void update_mvit();
+ void update_mvui();
+};
+
+struct viewport_t {
+ GLint x;
+ GLint y;
+ GLsizei w;
+ GLsizei h;
+ struct {
+ GLint x;
+ GLint y;
+ } surfaceport;
+ struct {
+ GLint x;
+ GLint y;
+ GLsizei w;
+ GLsizei h;
+ } scissor;
+};
+
+// ----------------------------------------------------------------------------
+// Lerping
+// ----------------------------------------------------------------------------
+
+struct compute_iterators_t
+{
+ void initTriangle(
+ vertex_t const* v0,
+ vertex_t const* v1,
+ vertex_t const* v2);
+
+ inline void initLerp(vertex_t const* v0, uint32_t enables);
+
+ int iteratorsScale(int32_t it[3],
+ int32_t c0, int32_t c1, int32_t c2) const;
+
+ void iterators1616(GGLfixed it[3],
+ GGLfixed c0, GGLfixed c1, GGLfixed c2) const;
+
+ void iterators0032(int32_t it[3],
+ int32_t c0, int32_t c1, int32_t c2) const;
+
+ GGLcoord area() const { return m_area; }
+
+private:
+ // don't change order of members here -- used by iterators.S
+ GGLcoord m_dx01, m_dy10, m_dx20, m_dy02;
+ GGLcoord m_x0, m_y0;
+ GGLcoord m_area;
+ uint8_t m_scale;
+ uint8_t m_area_scale;
+ uint8_t m_reserved[2];
+
+};
+
+// ----------------------------------------------------------------------------
+// state
+// ----------------------------------------------------------------------------
+
+#ifdef HAVE_ANDROID_OS
+ // We have a dedicated TLS slot in bionic
+ inline void setGlThreadSpecific(ogles_context_t *value) {
+ ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL] = (uint32_t)value;
+ }
+ inline ogles_context_t* getGlThreadSpecific() {
+ return (ogles_context_t *)(((unsigned *)__get_tls())[TLS_SLOT_OPENGL]);
+ }
+#else
+ extern pthread_key_t gGLKey;
+ inline void setGlThreadSpecific(ogles_context_t *value) {
+ pthread_setspecific(gGLKey, value);
+ }
+ inline ogles_context_t* getGlThreadSpecific() {
+ return static_cast<ogles_context_t*>(pthread_getspecific(gGLKey));
+ }
+#endif
+
+
+struct prims_t {
+ typedef ogles_context_t* GL;
+ void (*renderPoint)(GL, vertex_t*);
+ void (*renderLine)(GL, vertex_t*, vertex_t*);
+ void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
+};
+
+struct ogles_context_t {
+ context_t rasterizer;
+ array_machine_t arrays __attribute__((aligned(32)));
+ texture_state_t textures;
+ transform_state_t transforms;
+ vertex_cache_t vc;
+ prims_t prims;
+ culling_t cull;
+ lighting_t lighting;
+ user_clip_planes_t clipPlanes;
+ compute_iterators_t lerp; __attribute__((aligned(32)));
+ vertex_t current;
+ vec4_t currentColorClamped;
+ vec3_t currentNormal;
+ viewport_t viewport;
+ point_size_t point;
+ line_width_t line;
+ polygon_offset_t polygonOffset;
+ fog_t fog;
+ uint32_t perspective : 1;
+ uint32_t transformTextures : 1;
+ EGLSurfaceManager* surfaceManager;
+ EGLBufferObjectManager* bufferObjectManager;
+ GLenum error;
+
+ static inline ogles_context_t* get() {
+ return getGlThreadSpecific();
+ }
+
+};
+
+}; // namespace gl
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_CONTEXT_H
+
diff --git a/include/private/ui/LayerState.h b/include/private/ui/LayerState.h
new file mode 100644
index 0000000..b6fcd80
--- /dev/null
+++ b/include/private/ui/LayerState.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_COMPOSER_LAYER_STATE_H
+#define ANDROID_COMPOSER_LAYER_STATE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <ui/ISurfaceFlingerClient.h>
+#include <ui/Region.h>
+
+#include <private/ui/SharedState.h>
+
+namespace android {
+
+class Parcel;
+
+struct layer_state_t {
+
+ layer_state_t()
+ : surface(0), what(0),
+ x(0), y(0), z(0), w(0), h(0),
+ alpha(0), tint(0), flags(0), mask(0),
+ reserved(0)
+ {
+ matrix.dsdx = matrix.dtdy = 1.0f;
+ matrix.dsdy = matrix.dtdx = 0.0f;
+ }
+
+ status_t write(Parcel& output) const;
+ status_t read(const Parcel& input);
+
+ struct matrix22_t {
+ float dsdx;
+ float dtdx;
+ float dsdy;
+ float dtdy;
+ };
+ SurfaceID surface;
+ uint32_t what;
+ int32_t x;
+ int32_t y;
+ uint32_t z;
+ uint32_t w;
+ uint32_t h;
+ float alpha;
+ uint32_t tint;
+ uint8_t flags;
+ uint8_t mask;
+ uint8_t reserved;
+ matrix22_t matrix;
+ // non POD must be last. see write/read
+ Region transparentRegion;
+};
+
+}; // namespace android
+
+#endif // ANDROID_COMPOSER_LAYER_STATE_H
+
diff --git a/include/private/ui/SharedState.h b/include/private/ui/SharedState.h
new file mode 100644
index 0000000..546d0ad
--- /dev/null
+++ b/include/private/ui/SharedState.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_UI_SHARED_STATE_H
+#define ANDROID_UI_SHARED_STATE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+namespace android {
+
+/*
+ * These structures are shared between the composer process and its clients
+ */
+
+// ---------------------------------------------------------------------------
+
+struct surface_info_t { // 4 longs, 16 bytes
+ enum {
+ eBufferDirty = 0x01
+ };
+ uint16_t w;
+ uint16_t h;
+ uint16_t stride;
+ uint16_t bpr;
+ uint16_t reserved;
+ uint8_t format;
+ uint8_t flags;
+ ssize_t bits_offset;
+};
+
+// ---------------------------------------------------------------------------
+
+const uint32_t NUM_LAYERS_MAX = 31;
+
+enum { // layer_cblk_t swapState
+ eIndex = 0x00000001,
+ eFlipRequested = 0x00000002,
+
+ eResizeBuffer0 = 0x00000004,
+ eResizeBuffer1 = 0x00000008,
+ eResizeRequested = eResizeBuffer0 | eResizeBuffer1,
+
+ eBusy = 0x00000010,
+ eLocked = 0x00000020,
+ eNextFlipPending = 0x00000040,
+ eInvalidSurface = 0x00000080
+};
+
+enum { // layer_cblk_t flags
+ eLayerNotPosted = 0x00000001,
+ eNoCopyBack = 0x00000002,
+ eReserved = 0x0000007C,
+ eBufferIndexShift = 7,
+ eBufferIndex = 1<<eBufferIndexShift,
+};
+
+struct flat_region_t // 40 bytes
+{
+ int32_t count;
+ int16_t l;
+ int16_t t;
+ int16_t r;
+ int16_t b;
+ uint16_t runs[14];
+};
+
+struct layer_cblk_t // (128 bytes)
+{
+ volatile int32_t swapState; // 4
+ volatile int32_t flags; // 4
+ volatile int32_t identity; // 4
+ int32_t reserved; // 4
+ surface_info_t surface[2]; // 32
+ flat_region_t region[2]; // 80
+
+ static inline int backBuffer(uint32_t state) {
+ return ((state & eIndex) ^ ((state & eFlipRequested)>>1));
+ }
+ static inline int frontBuffer(uint32_t state) {
+ return 1 - backBuffer(state);
+ }
+};
+
+// ---------------------------------------------------------------------------
+
+struct per_client_cblk_t // 4KB max
+{
+ Mutex lock;
+ Condition cv;
+ layer_cblk_t layers[NUM_LAYERS_MAX] __attribute__((aligned(32)));
+
+ enum {
+ BLOCKING = 0x00000001,
+ INSPECT = 0x00000002
+ };
+
+ per_client_cblk_t();
+
+ // these functions are used by the clients
+ status_t validate(size_t i) const;
+ int32_t lock_layer(size_t i, uint32_t flags);
+ uint32_t unlock_layer_and_post(size_t i);
+ void unlock_layer(size_t i);
+};
+// ---------------------------------------------------------------------------
+
+const uint32_t NUM_DISPLAY_MAX = 4;
+
+struct display_cblk_t
+{
+ uint16_t w;
+ uint16_t h;
+ uint8_t format;
+ uint8_t orientation;
+ uint8_t reserved[2];
+ float fps;
+ float density;
+ float xdpi;
+ float ydpi;
+ uint32_t pad[2];
+};
+
+struct surface_flinger_cblk_t // 4KB max
+{
+ surface_flinger_cblk_t();
+
+ uint8_t connected;
+ uint8_t reserved[3];
+ uint32_t pad[7];
+
+ display_cblk_t displays[NUM_DISPLAY_MAX];
+};
+
+// ---------------------------------------------------------------------------
+
+template<bool> struct CTA;
+template<> struct CTA<true> { };
+
+// compile-time assertions. just to avoid catastrophes.
+inline void compile_time_asserts() {
+ CTA<sizeof(layer_cblk_t) == 128> sizeof__layer_cblk_t__eq_128;
+ (void)sizeof__layer_cblk_t__eq_128; // we don't want a warning
+ CTA<sizeof(per_client_cblk_t) <= 4096> sizeof__per_client_cblk_t__le_4096;
+ (void)sizeof__per_client_cblk_t__le_4096; // we don't want a warning
+ CTA<sizeof(surface_flinger_cblk_t) <= 4096> sizeof__surface_flinger_cblk_t__le_4096;
+ (void)sizeof__surface_flinger_cblk_t__le_4096; // we don't want a warning
+}
+
+}; // namespace android
+
+#endif // ANDROID_UI_SHARED_STATE_H
+
diff --git a/include/private/ui/SurfaceFlingerSynchro.h b/include/private/ui/SurfaceFlingerSynchro.h
new file mode 100644
index 0000000..ff91b61
--- /dev/null
+++ b/include/private/ui/SurfaceFlingerSynchro.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ANDROID_SURFACE_FLINGER_SYNCHRO_H
+#define ANDROID_SURFACE_FLINGER_SYNCHRO_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <ui/ISurfaceComposer.h>
+
+namespace android {
+
+class SurfaceFlinger;
+
+class SurfaceFlingerSynchro
+{
+public:
+
+ // client constructor
+ SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger);
+ ~SurfaceFlingerSynchro();
+
+ // signal surfaceflinger for some work
+ status_t signal();
+
+private:
+ class Barrier {
+ public:
+ Barrier();
+ ~Barrier();
+ void open();
+ void close();
+ void waitAndClose();
+ status_t waitAndClose(nsecs_t timeout);
+ private:
+ enum { OPENED, CLOSED };
+ mutable Mutex lock;
+ mutable Condition cv;
+ volatile int state;
+ };
+
+ friend class SurfaceFlinger;
+
+ // server constructor
+ SurfaceFlingerSynchro();
+
+ void open();
+
+ // wait until there is some work to do
+ status_t wait();
+ status_t wait(nsecs_t timeout);
+
+ sp<ISurfaceComposer> mSurfaceComposer;
+ Barrier mBarrier;
+};
+
+}; // namespace android
+
+#endif // ANDROID_SURFACE_FLINGER_SYNCHRO_H
+
diff --git a/include/private/utils/Static.h b/include/private/utils/Static.h
new file mode 100644
index 0000000..f1439b7
--- /dev/null
+++ b/include/private/utils/Static.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#ifndef LIBUTILS_NATIVE
+#include <utils/IBinder.h>
+#include <utils/IMemory.h>
+#include <utils/ProcessState.h>
+#include <utils/IPermissionController.h>
+#include <utils/IServiceManager.h>
+#endif
+
+namespace android {
+// For TextStream.cpp
+extern Vector<int32_t> gTextBuffers;
+
+// For String8.cpp
+extern void initialize_string8();
+extern void terminate_string8();
+
+// For String16.cpp
+extern void initialize_string16();
+extern void terminate_string16();
+
+
+
+#ifndef LIBUTILS_NATIVE
+
+// For ProcessState.cpp
+extern Mutex gProcessMutex;
+extern sp<ProcessState> gProcess;
+
+// For ServiceManager.cpp
+extern Mutex gDefaultServiceManagerLock;
+extern sp<IServiceManager> gDefaultServiceManager;
+extern sp<IPermissionController> gPermissionController;
+
+#endif
+
+} // namespace android
diff --git a/include/private/utils/binder_module.h b/include/private/utils/binder_module.h
new file mode 100644
index 0000000..fdf327e
--- /dev/null
+++ b/include/private/utils/binder_module.h
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#ifndef _BINDER_MODULE_H_
+#define _BINDER_MODULE_H_
+
+#ifdef __cplusplus
+namespace android {
+#endif
+
+#if defined(HAVE_ANDROID_OS)
+
+/* obtain structures and constants from the kernel header */
+
+#include <sys/ioctl.h>
+#include <linux/binder.h>
+
+#else
+
+/* Some parts of the simulator need fake versions of this
+ * stuff in order to compile. Really this should go away
+ * entirely...
+ */
+
+#define BINDER_CURRENT_PROTOCOL_VERSION 7
+
+#define BINDER_TYPE_BINDER 1
+#define BINDER_TYPE_WEAK_BINDER 2
+#define BINDER_TYPE_HANDLE 3
+#define BINDER_TYPE_WEAK_HANDLE 4
+#define BINDER_TYPE_FD 5
+
+struct flat_binder_object {
+ unsigned long type;
+ unsigned long flags;
+ union {
+ void *binder;
+ signed long handle;
+ };
+ void *cookie;
+};
+
+struct binder_write_read {
+ signed long write_size;
+ signed long write_consumed;
+ unsigned long write_buffer;
+ signed long read_size;
+ signed long read_consumed;
+ unsigned long read_buffer;
+};
+
+struct binder_transaction_data {
+ union {
+ size_t handle;
+ void *ptr;
+ } target;
+ void *cookie;
+ unsigned int code;
+
+ unsigned int flags;
+ pid_t sender_pid;
+ uid_t sender_euid;
+ size_t data_size;
+ size_t offsets_size;
+
+ union {
+ struct {
+ const void *buffer;
+ const void *offsets;
+ } ptr;
+ uint8_t buf[8];
+ } data;
+};
+
+enum transaction_flags {
+ TF_ONE_WAY = 0x01,
+ TF_ROOT_OBJECT = 0x04,
+ TF_STATUS_CODE = 0x08,
+ TF_ACCEPT_FDS = 0x10,
+};
+
+
+enum {
+ FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
+ FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
+};
+
+enum BinderDriverReturnProtocol {
+ BR_ERROR,
+ BR_OK,
+ BR_TRANSACTION,
+ BR_REPLY,
+ BR_ACQUIRE_RESULT,
+ BR_DEAD_REPLY,
+ BR_TRANSACTION_COMPLETE,
+ BR_INCREFS,
+ BR_ACQUIRE,
+ BR_RELEASE,
+ BR_DECREFS,
+ BR_ATTEMPT_ACQUIRE,
+ BR_NOOP,
+ BR_SPAWN_LOOPER,
+ BR_FINISHED,
+ BR_DEAD_BINDER,
+ BR_CLEAR_DEATH_NOTIFICATION_DONE,
+ BR_FAILED_REPLY,
+};
+
+enum BinderDriverCommandProtocol {
+ BC_TRANSACTION,
+ BC_REPLY,
+ BC_ACQUIRE_RESULT,
+ BC_FREE_BUFFER,
+ BC_INCREFS,
+ BC_ACQUIRE,
+ BC_RELEASE,
+ BC_DECREFS,
+ BC_INCREFS_DONE,
+ BC_ACQUIRE_DONE,
+ BC_ATTEMPT_ACQUIRE,
+ BC_REGISTER_LOOPER,
+ BC_ENTER_LOOPER,
+ BC_EXIT_LOOPER,
+ BC_REQUEST_DEATH_NOTIFICATION,
+ BC_CLEAR_DEATH_NOTIFICATION,
+ BC_DEAD_BINDER_DONE,
+};
+
+#endif
+
+#ifdef __cplusplus
+} // namespace android
+#endif
+
+#endif // _BINDER_MODULE_H_
diff --git a/include/private/utils/futex_synchro.h b/include/private/utils/futex_synchro.h
new file mode 100644
index 0000000..ac2ab19
--- /dev/null
+++ b/include/private/utils/futex_synchro.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef _FUTEX_SYNCHRO_H
+#define _FUTEX_SYNCHRO_H
+
+#ifndef HAVE_FUTEX
+#error "HAVE_FUTEX not defined"
+#endif
+
+#define FUTEX_WAIT_INFINITE (0)
+
+typedef struct futex_mutex_t futex_mutex_t;
+
+struct futex_mutex_t
+{
+ volatile int value;
+};
+
+typedef struct futex_cond_t futex_cond_t;
+
+struct futex_cond_t
+{
+ volatile int value;
+};
+
+
+#if __cplusplus
+extern "C" {
+#endif
+
+void futex_mutex_init(futex_mutex_t *m);
+int futex_mutex_lock(futex_mutex_t *m, unsigned msec);
+void futex_mutex_unlock(futex_mutex_t *m);
+int futex_mutex_trylock(futex_mutex_t *m);
+
+void futex_cond_init(futex_cond_t *c);
+int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec);
+void futex_cond_signal(futex_cond_t *c);
+void futex_cond_broadcast(futex_cond_t *c);
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _FUTEX_SYNCHRO_H
+
diff --git a/include/ui/BlitHardware.h b/include/ui/BlitHardware.h
new file mode 100644
index 0000000..4de1c12
--- /dev/null
+++ b/include/ui/BlitHardware.h
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BLIT_HARDWARE_H
+#define ANDROID_BLIT_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************/
+
+/* supported pixel-formats. these must be compatible with
+ * graphics/PixelFormat.java, ui/PixelFormat.h, pixelflinger/format.h
+ */
+
+enum
+{
+ COPYBIT_RGBA_8888 = 1,
+ COPYBIT_RGB_565 = 4,
+ COPYBIT_RGBA_5551 = 6,
+ COPYBIT_RGBA_4444 = 7,
+ COPYBIT_YCbCr_422_SP = 0x10,
+ COPYBIT_YCbCr_420_SP = 0x11
+};
+
+/* name for copybit_set_parameter */
+enum
+{
+ /* rotation of the source image in degrees (0 to 359) */
+ COPYBIT_ROTATION_DEG = 1,
+ /* plane alpha value */
+ COPYBIT_PLANE_ALPHA = 2,
+ /* enable or disable dithering */
+ COPYBIT_DITHER = 3,
+ /* transformation applied (this is a superset of COPYBIT_ROTATION_DEG) */
+ COPYBIT_TRANSFORM = 4,
+};
+
+/* values for copybit_set_parameter(COPYBIT_TRANSFORM) */
+enum {
+ /* flip source image horizontally */
+ COPYBIT_TRANSFORM_FLIP_H = 0x01,
+ /* flip source image vertically */
+ COPYBIT_TRANSFORM_FLIP_V = 0x02,
+ /* rotate source image 90 degres */
+ COPYBIT_TRANSFORM_ROT_90 = 0x04,
+ /* rotate source image 180 degres */
+ COPYBIT_TRANSFORM_ROT_180 = 0x03,
+ /* rotate source image 270 degres */
+ COPYBIT_TRANSFORM_ROT_270 = 0x07,
+};
+
+/* enable/disable value copybit_set_parameter */
+enum {
+ COPYBIT_DISABLE = 0,
+ COPYBIT_ENABLE = 1
+};
+
+/* use get() to query static informations about the hardware */
+enum {
+ /* Maximum amount of minification supported by the hardware*/
+ COPYBIT_MINIFICATION_LIMIT = 1,
+ /* Maximum amount of magnification supported by the hardware */
+ COPYBIT_MAGNIFICATION_LIMIT = 2,
+ /* Number of fractional bits support by the scaling engine */
+ COPYBIT_SCALING_FRAC_BITS = 3,
+ /* Supported rotation step in degres. */
+ COPYBIT_ROTATION_STEP_DEG = 4,
+};
+
+struct copybit_image_t {
+ uint32_t w;
+ uint32_t h;
+ int32_t format;
+ uint32_t offset;
+ void* base;
+ int fd;
+};
+
+
+struct copybit_rect_t {
+ int l;
+ int t;
+ int r;
+ int b;
+};
+
+struct copybit_region_t {
+ int (*next)(copybit_region_t const*, copybit_rect_t* rect);
+};
+
+struct copybit_t
+{
+ int (*set_parameter)(struct copybit_t* handle, int name, int value);
+
+ int (*get)(struct copybit_t* handle, int name);
+
+ int (*blit)(
+ struct copybit_t* handle,
+ struct copybit_image_t const* dst,
+ struct copybit_image_t const* src,
+ struct copybit_region_t const* region);
+
+ int (*stretch)(
+ struct copybit_t* handle,
+ struct copybit_image_t const* dst,
+ struct copybit_image_t const* src,
+ struct copybit_rect_t const* dst_rect,
+ struct copybit_rect_t const* src_rect,
+ struct copybit_region_t const* region);
+};
+
+/******************************************************************************/
+
+struct copybit_t* copybit_init();
+
+int copybit_term(struct copybit_t* handle);
+
+
+/******************************************************************************/
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // ANDROID_BLIT_HARDWARE_H
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
new file mode 100644
index 0000000..562a0a2
--- /dev/null
+++ b/include/ui/Camera.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_H
+#define ANDROID_HARDWARE_CAMERA_H
+
+#include <ui/ICameraClient.h>
+
+namespace android {
+
+class ICameraService;
+class ICamera;
+class Surface;
+class Mutex;
+class String8;
+
+typedef void (*shutter_callback)(void *cookie);
+typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie);
+typedef void (*autofocus_callback)(bool focused, void *cookie);
+typedef void (*error_callback)(status_t err, void *cookie);
+
+class Camera : public BnCameraClient, public IBinder::DeathRecipient
+{
+public:
+ static sp<Camera> connect();
+ ~Camera();
+
+ void disconnect();
+
+ status_t getStatus() { return mStatus; }
+
+ // pass the buffered ISurface to the camera service
+ status_t setPreviewDisplay(const sp<Surface>& surface);
+
+ // start preview mode, must call setPreviewDisplay first
+ status_t startPreview();
+
+ // stop preview mode
+ void stopPreview();
+
+ // autoFocus - status returned from callback
+ status_t autoFocus();
+
+ // take a picture - picture returned from callback
+ status_t takePicture();
+
+ // set preview/capture parameters - key/value pairs
+ status_t setParameters(const String8& params);
+
+ // get preview/capture parameters - key/value pairs
+ String8 getParameters() const;
+
+ void setShutterCallback(shutter_callback cb, void *cookie);
+ void setRawCallback(frame_callback cb, void *cookie);
+ void setJpegCallback(frame_callback cb, void *cookie);
+ void setFrameCallback(frame_callback cb, void *cookie);
+ void setErrorCallback(error_callback cb, void *cookie);
+ void setAutoFocusCallback(autofocus_callback cb, void *cookie);
+ // ICameraClient interface
+ virtual void shutterCallback();
+ virtual void rawCallback(const sp<IMemory>& picture);
+ virtual void jpegCallback(const sp<IMemory>& picture);
+ virtual void frameCallback(const sp<IMemory>& frame);
+ virtual void errorCallback(status_t error);
+ virtual void autoFocusCallback(bool focused);
+
+
+private:
+ Camera();
+ virtual void binderDied(const wp<IBinder>& who);
+
+ class DeathNotifier: public IBinder::DeathRecipient
+ {
+ public:
+ DeathNotifier() {
+ }
+
+ virtual void binderDied(const wp<IBinder>& who);
+ };
+
+ static sp<DeathNotifier> mDeathNotifier;
+
+ // helper function to obtain camera service handle
+ static const sp<ICameraService>& getCameraService();
+
+ sp<ICamera> mCamera;
+ status_t mStatus;
+
+ shutter_callback mShutterCallback;
+ void *mShutterCallbackCookie;
+ frame_callback mRawCallback;
+ void *mRawCallbackCookie;
+ frame_callback mJpegCallback;
+ void *mJpegCallbackCookie;
+ frame_callback mFrameCallback;
+ void *mFrameCallbackCookie;
+ error_callback mErrorCallback;
+ void *mErrorCallbackCookie;
+ autofocus_callback mAutoFocusCallback;
+ void *mAutoFocusCallbackCookie;
+
+ friend class DeathNotifier;
+
+ static Mutex mLock;
+ static sp<ICameraService> mCameraService;
+
+};
+
+}; // namespace android
+
+#endif
+
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
new file mode 100644
index 0000000..5fa933f
--- /dev/null
+++ b/include/ui/CameraHardwareInterface.h
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+
+#include <utils/IMemory.h>
+#include <utils/RefBase.h>
+#include <ui/CameraParameters.h>
+
+namespace android {
+
+/** Callback for startPreview() */
+typedef void (*preview_callback)(const sp<IMemory>& mem, void* user);
+
+/** Callback for takePicture() */
+typedef void (*shutter_callback)(void* user);
+
+/** Callback for takePicture() */
+typedef void (*raw_callback)(const sp<IMemory>& mem, void* user);
+
+/** Callback for takePicture() */
+typedef void (*jpeg_callback)(const sp<IMemory>& mem, void* user);
+
+/** Callback for autoFocus() */
+typedef void (*autofocus_callback)(bool focused, void* user);
+
+/**
+ * This defines the interface to the camera hardware abstraction
+ * layer. It supports setting and getting parameters, live
+ * previewing and taking pictures. It is a referenced counted
+ * interface with RefBase as its base class.
+ *
+ * The openCameraHardware function is used to
+ * retrieve a strong pointer to the instance of this interface
+ * and may be called multiple times.
+ *
+ * After calling openCameraHardware the getParameters and
+ * setParameters are used to initialize the camera instance.
+ *
+ * Then getPreviewHeap is called to get access to the preview
+ * heap so it can be registered with the SurfaceFlinger for efficient
+ * display updating while in the preview mode.
+ *
+ * Next startPreview is called which is passed a preview_callback
+ * function and a user parameter. The camera instance then
+ * periodically calls preview_callback each time a new
+ * preview frame is available. The call back routine has
+ * two parameters, the first is a pointer to the the IMemory containing
+ * the frame and the other is the user parameter. If the preview_callback
+ * code needs to use this memory after returning it must copy
+ * the data.
+ *
+ * Prior to taking a picture the autoFocus method is usually called with a
+ * autofocus_callback and a user parameter. When auto focusing
+ * has completed the camera instance calls autofocus_callback which
+ * informs the application if focusing was successful or not.
+ * The camera instance only calls the autofocus_callback once and it
+ * is up to the application to call autoFocus again if refocusing is desired.
+ *
+ * The method takePicture is called to request that the camera instance take a
+ * picture. This method has three callbacks: shutter_callback, raw_callback,
+ * and jpeg_callback. As soon as the shutter snaps and it is safe to move the
+ * camera, shutter_callback is called. Typically, you would want to play the
+ * shutter sound at this moment. Later, when the raw image is available the
+ * raw_callback is called with a pointer to the IMemory containing the raw
+ * image. Finally, when the encoded jpeg image is available the jpeg_callback
+ * will be called with a pointer to the IMemory containing the jpeg image. As
+ * with the preview_callback the memory must be copied if it's needed after
+ * returning.
+ */
+class CameraHardwareInterface : public virtual RefBase {
+public:
+ virtual ~CameraHardwareInterface() { }
+
+ /** Return the IMemoryHeap for the preview image heap */
+ virtual sp<IMemoryHeap> getPreviewHeap() const = 0;
+
+ /**
+ * Start preview mode. When a preview image is available
+ * preview_callback is called with the user parameter. The
+ * call back parameter may be null.
+ */
+ virtual status_t startPreview(preview_callback cb, void* user) = 0;
+
+ /**
+ * Stop a previously started preview.
+ */
+ virtual void stopPreview() = 0;
+
+ /**
+ * Start auto focus, the callback routine is called
+ * once when focusing is complete. autoFocus() will
+ * be called agained if another auto focus is needed.
+ */
+ virtual status_t autoFocus(autofocus_callback,
+ void* user) = 0;
+
+ /**
+ * Take a picture. The raw_callback is called when
+ * the uncompressed image is available. The jpeg_callback
+ * is called when the compressed image is available. These
+ * call backs may be null. The user parameter is passed
+ * to each of the call back routines.
+ */
+ virtual status_t takePicture(shutter_callback,
+ raw_callback,
+ jpeg_callback,
+ void* user) = 0;
+
+ /**
+ * Cancel a picture that was started with takePicture. You may cancel any
+ * of the shutter, raw, or jpeg callbacks. Calling this method when no
+ * picture is being taken is a no-op.
+ */
+ virtual status_t cancelPicture(bool cancel_shutter,
+ bool cancel_raw,
+ bool cancel_jpeg) = 0;
+
+ /** Set the camera parameters. */
+ virtual status_t setParameters(const CameraParameters& params) = 0;
+
+ /** Return the camera parameters. */
+ virtual CameraParameters getParameters() const = 0;
+
+ /**
+ * Release the hardware resources owned by this object. Note that this is
+ * *not* done in the destructor.
+ */
+ virtual void release() = 0;
+
+ /**
+ * Dump state of the camera hardware
+ */
+ virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
+};
+
+/** factory function to instantiate a camera hardware object */
+extern "C" sp<CameraHardwareInterface> openCameraHardware();
+
+}; // namespace android
+
+#endif
diff --git a/include/ui/CameraParameters.h b/include/ui/CameraParameters.h
new file mode 100644
index 0000000..e35a054
--- /dev/null
+++ b/include/ui/CameraParameters.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PARAMETERS_H
+#define ANDROID_HARDWARE_CAMERA_PARAMETERS_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class CameraParameters
+{
+public:
+ CameraParameters();
+ CameraParameters(const String8 &params) { unflatten(params); }
+ ~CameraParameters();
+
+ String8 flatten() const;
+ void unflatten(const String8 &params);
+
+ void set(const char *key, const char *value);
+ void set(const char *key, int value);
+ const char *get(const char *key) const;
+ int getInt(const char *key) const;
+
+ /* preview-size=176x144 */
+ void setPreviewSize(int width, int height);
+ void getPreviewSize(int *width, int *height) const;
+
+ /* preview-fps=15 */
+ void setPreviewFrameRate(int fps);
+ int getPreviewFrameRate() const;
+
+ /* preview-format=rgb565|yuv422 */
+ void setPreviewFormat(const char *format);
+ const char *getPreviewFormat() const;
+
+ /* picture-size=1024x768 */
+ void setPictureSize(int width, int height);
+ void getPictureSize(int *width, int *height) const;
+
+ /* picture-format=yuv422|jpeg */
+ void setPictureFormat(const char *format);
+ const char *getPictureFormat() const;
+
+ void dump() const;
+ status_t dump(int fd, const Vector<String16>& args) const;
+
+private:
+ DefaultKeyedVector<String8,String8> mMap;
+};
+
+
+}; // namespace android
+
+#endif
diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h
new file mode 100644
index 0000000..c419efe
--- /dev/null
+++ b/include/ui/DisplayInfo.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 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.
+ */
+
+
+#ifndef ANDROID_UI_DISPLAY_INFO_H
+#define ANDROID_UI_DISPLAY_INFO_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/PixelFormat.h>
+
+namespace android {
+
+struct DisplayInfo {
+ uint32_t w;
+ uint32_t h;
+ PixelFormatInfo pixelFormatInfo;
+ uint8_t orientation;
+ uint8_t reserved[3];
+ float fps;
+ float density;
+ float xdpi;
+ float ydpi;
+};
+
+}; // namespace android
+
+#endif // ANDROID_COMPOSER_DISPLAY_INFO_H
+
diff --git a/include/ui/EGLDisplaySurface.h b/include/ui/EGLDisplaySurface.h
new file mode 100644
index 0000000..a9cfd5a
--- /dev/null
+++ b/include/ui/EGLDisplaySurface.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_EGL_DISPLAY_SURFACE_H
+#define ANDROID_EGL_DISPLAY_SURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Timers.h>
+
+#include <ui/EGLNativeSurface.h>
+#include <ui/BlitHardware.h>
+
+#include <pixelflinger/pixelflinger.h>
+#include <linux/fb.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Region;
+class Rect;
+
+class EGLDisplaySurface : public EGLNativeSurface<EGLDisplaySurface>
+{
+public:
+ EGLDisplaySurface();
+ ~EGLDisplaySurface();
+
+ int32_t getPageFlipCount() const;
+ void copyFrontToBack(const Region& copyback);
+
+private:
+ static void hook_incRef(NativeWindowType window);
+ static void hook_decRef(NativeWindowType window);
+ static uint32_t hook_swapBuffers(NativeWindowType window);
+ static void hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h);
+ static uint32_t hook_nextBuffer(NativeWindowType window);
+
+ uint32_t swapBuffers();
+ uint32_t nextBuffer();
+ void setSwapRectangle(int l, int t, int w, int h);
+
+ status_t mapFrameBuffer();
+
+ enum {
+ PAGE_FLIP = 0x00000001
+ };
+ GGLSurface mFb[2];
+ int mIndex;
+ uint32_t mFlags;
+ size_t mSize;
+ fb_var_screeninfo mInfo;
+ fb_fix_screeninfo mFinfo;
+ int32_t mPageFlipCount;
+ nsecs_t mTime;
+ int32_t mSwapCount;
+ nsecs_t mSleep;
+ uint32_t mFeatureFlags;
+ copybit_t* mBlitEngine;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_DISPLAY_SURFACE_H
+
diff --git a/include/ui/EGLNativeSurface.h b/include/ui/EGLNativeSurface.h
new file mode 100644
index 0000000..7c9ce99
--- /dev/null
+++ b/include/ui/EGLNativeSurface.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_EGL_NATIVE_SURFACE_H
+#define ANDROID_EGL_NATIVE_SURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/atomic.h>
+#include <utils/RefBase.h>
+
+#include <GLES/eglnatives.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+template <class TYPE>
+class EGLNativeSurface : public egl_native_window_t
+{
+public:
+ EGLNativeSurface() : mCount(0) {
+ memset(egl_native_window_t::reserved, 0,
+ sizeof(egl_native_window_t::reserved));
+ memset(egl_native_window_t::reserved_proc, 0,
+ sizeof(egl_native_window_t::reserved_proc));
+ memset(egl_native_window_t::oem, 0,
+ sizeof(egl_native_window_t::oem));
+ }
+ inline void incStrong(void*) const {
+ android_atomic_inc(&mCount);
+ }
+ inline void decStrong(void*) const {
+ if (android_atomic_dec(&mCount) == 1) {
+ delete static_cast<const TYPE*>(this);
+ }
+ }
+protected:
+ EGLNativeSurface& operator = (const EGLNativeSurface& rhs);
+ EGLNativeSurface(const EGLNativeSurface& rhs);
+ inline ~EGLNativeSurface() { };
+ mutable volatile int32_t mCount;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_SURFACE_H
+
diff --git a/include/ui/EGLNativeWindowSurface.h b/include/ui/EGLNativeWindowSurface.h
new file mode 100644
index 0000000..058479a
--- /dev/null
+++ b/include/ui/EGLNativeWindowSurface.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
+#define ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <ui/EGLNativeSurface.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Surface;
+
+class EGLNativeWindowSurface : public EGLNativeSurface<EGLNativeWindowSurface>
+{
+public:
+ EGLNativeWindowSurface(const sp<Surface>& surface);
+ ~EGLNativeWindowSurface();
+
+private:
+ static void hook_incRef(NativeWindowType window);
+ static void hook_decRef(NativeWindowType window);
+ static uint32_t hook_swapBuffers(NativeWindowType window);
+ static uint32_t hook_nextBuffer(NativeWindowType window);
+ static void hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h);
+ static void hook_connect(NativeWindowType window);
+ static void hook_disconnect(NativeWindowType window);
+
+ uint32_t swapBuffers();
+ uint32_t nextBuffer();
+ void setSwapRectangle(int l, int t, int w, int h);
+ void connect();
+ void disconnect();
+
+ sp<Surface> mSurface;
+ bool mConnected;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
+
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
new file mode 100644
index 0000000..101a920
--- /dev/null
+++ b/include/ui/EventHub.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2005 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 _RUNTIME_EVENT_HUB_H
+#define _RUNTIME_EVENT_HUB_H
+
+#include <utils/String8.h>
+#include <utils/threads.h>
+#include <utils.h>
+
+#include <linux/input.h>
+
+struct pollfd;
+
+namespace android {
+
+class KeyLayoutMap;
+
+/*
+ * Grand Central Station for events. With a single call to waitEvent()
+ * you can wait for:
+ * - input events from the keypad of a real device
+ * - input events and meta-events (e.g. "quit") from the simulator
+ * - synthetic events from the runtime (e.g. "URL fetch completed")
+ * - real or forged "vsync" events
+ *
+ * Do not instantiate this class. Instead, call startUp().
+ */
+class EventHub : public RefBase
+{
+public:
+ EventHub();
+
+ status_t errorCheck() const;
+
+ // bit fields for classes of devices.
+ enum {
+ CLASS_KEYBOARD = 0x00000001,
+ CLASS_TOUCHSCREEN = 0x00000002,
+ CLASS_TRACKBALL = 0x00000004
+ };
+ uint32_t getDeviceClasses(int32_t deviceId) const;
+
+ String8 getDeviceName(int32_t deviceId) const;
+
+ int getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
+ int* outMaxValue, int* outFlat, int* outFuzz) const;
+
+ int getSwitchState(int sw) const;
+ int getSwitchState(int32_t deviceId, int sw) const;
+
+ int getScancodeState(int key) const;
+ int getScancodeState(int32_t deviceId, int key) const;
+
+ int getKeycodeState(int key) const;
+ int getKeycodeState(int32_t deviceId, int key) const;
+
+ // special type codes when devices are added/removed.
+ enum {
+ DEVICE_ADDED = 0x10000000,
+ DEVICE_REMOVED = 0x20000000
+ };
+
+ virtual bool getEvent(int32_t* outDeviceId, int32_t* outType,
+ int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
+ int32_t* outValue, nsecs_t* outWhen);
+
+protected:
+ virtual ~EventHub();
+ virtual void onFirstRef();
+
+private:
+ bool openPlatformInput(void);
+ int32_t convertDeviceKey_TI_P2(int code);
+
+ int open_device(const char *device);
+ int close_device(const char *device);
+ int scan_dir(const char *dirname);
+ int read_notify(int nfd);
+
+ status_t mError;
+
+ struct device_t {
+ const int32_t id;
+ const String8 path;
+ String8 name;
+ uint32_t classes;
+ KeyLayoutMap* layoutMap;
+ String8 keylayoutFilename;
+ device_t* next;
+
+ device_t(int32_t _id, const char* _path);
+ ~device_t();
+ };
+
+ device_t* getDevice(int32_t deviceId) const;
+
+ // Protect all internal state.
+ mutable Mutex mLock;
+
+ bool mHaveFirstKeyboard;
+ int32_t mFirstKeyboardId; // the API is that the build in keyboard is id 0, so map it
+
+ struct device_ent {
+ device_t* device;
+ uint32_t seq;
+ };
+ device_ent *mDevicesById;
+ int mNumDevicesById;
+
+ device_t *mOpeningDevices;
+ device_t *mClosingDevices;
+
+ device_t **mDevices;
+ struct pollfd *mFDs;
+ int mFDCount;
+
+ // device ids that report particular switches.
+#ifdef EV_SW
+ int32_t mSwitches[SW_MAX+1];
+#endif
+
+ KeyLayoutMap * mLayoutMap;
+};
+
+}; // namespace android
+
+#endif // _RUNTIME_EVENT_HUB_H
diff --git a/include/ui/ICamera.h b/include/ui/ICamera.h
new file mode 100644
index 0000000..6aa3940
--- /dev/null
+++ b/include/ui/ICamera.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_ICAMERA_H
+#define ANDROID_HARDWARE_ICAMERA_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+#include <ui/ISurface.h>
+#include <utils/IMemory.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class ICamera: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(Camera);
+
+ virtual void disconnect() = 0;
+
+ // pass the buffered ISurface to the camera service
+ virtual status_t setPreviewDisplay(const sp<ISurface>& surface) = 0;
+
+ // tell the service whether to callback with each preview frame
+ virtual void setHasFrameCallback(bool installed) = 0;
+
+ // start preview mode, must call setPreviewDisplay first
+ virtual status_t startPreview() = 0;
+
+ // stop preview mode
+ virtual void stopPreview() = 0;
+
+ // auto focus
+ virtual status_t autoFocus() = 0;
+
+ // take a picture
+ virtual status_t takePicture() = 0;
+
+ // set preview/capture parameters - key/value pairs
+ virtual status_t setParameters(const String8& params) = 0;
+
+ // get preview/capture parameters - key/value pairs
+ virtual String8 getParameters() const = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCamera: public BnInterface<ICamera>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/ui/ICameraClient.h b/include/ui/ICameraClient.h
new file mode 100644
index 0000000..a286b8e
--- /dev/null
+++ b/include/ui/ICameraClient.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_ICAMERA_APP_H
+#define ANDROID_HARDWARE_ICAMERA_APP_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+#include <utils/IMemory.h>
+
+namespace android {
+
+class ICameraClient: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(CameraClient);
+
+ virtual void shutterCallback() = 0;
+ virtual void rawCallback(const sp<IMemory>& picture) = 0;
+ virtual void jpegCallback(const sp<IMemory>& picture) = 0;
+ virtual void frameCallback(const sp<IMemory>& frame) = 0;
+ virtual void errorCallback(status_t error) = 0;
+ virtual void autoFocusCallback(bool focused) = 0;
+
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraClient: public BnInterface<ICameraClient>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/ui/ICameraService.h b/include/ui/ICameraService.h
new file mode 100644
index 0000000..dfd8923
--- /dev/null
+++ b/include/ui/ICameraService.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_ICAMERASERVICE_H
+#define ANDROID_HARDWARE_ICAMERASERVICE_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+#include <ui/ICameraClient.h>
+#include <ui/ICamera.h>
+
+namespace android {
+
+class ICameraService : public IInterface
+{
+protected:
+ enum {
+ CONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ };
+
+public:
+ DECLARE_META_INTERFACE(CameraService);
+
+ virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraService: public BnInterface<ICameraService>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h
new file mode 100644
index 0000000..ca691f5
--- /dev/null
+++ b/include/ui/ISurface.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_ISURFACE_H
+#define ANDROID_ISURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <utils/RefBase.h>
+#include <ui/PixelFormat.h>
+
+namespace android {
+
+typedef int32_t SurfaceID;
+
+class IMemoryHeap;
+
+class ISurface : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(Surface);
+
+ virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
+ PixelFormat format, const sp<IMemoryHeap>& heap) = 0;
+
+ virtual void postBuffer(ssize_t offset) = 0; // one-way
+
+ virtual void unregisterBuffers() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSurface : public BnInterface<ISurface>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISURFACE_H
diff --git a/include/ui/ISurfaceComposer.h b/include/ui/ISurfaceComposer.h
new file mode 100644
index 0000000..f9eeb30
--- /dev/null
+++ b/include/ui/ISurfaceComposer.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2006 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_ISURFACE_COMPOSER_H
+#define ANDROID_ISURFACE_COMPOSER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/ISurfaceFlingerClient.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class DisplayInfo;
+class IGPUCallback;
+
+class ISurfaceComposer : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(SurfaceComposer);
+
+ enum { // (keep in sync with Surface.java)
+ eHidden = 0x00000004,
+ eGPU = 0x00000008,
+ eHardware = 0x00000010,
+ eDestroyBackbuffer = 0x00000020,
+ eSecure = 0x00000080,
+ eNonPremultiplied = 0x00000100,
+ ePushBuffers = 0x00000200,
+
+ eFXSurfaceNormal = 0x00000000,
+ eFXSurfaceBlur = 0x00010000,
+ eFXSurfaceDim = 0x00020000,
+ eFXSurfaceMask = 0x000F0000,
+ };
+
+ enum {
+ ePositionChanged = 0x00000001,
+ eLayerChanged = 0x00000002,
+ eSizeChanged = 0x00000004,
+ eAlphaChanged = 0x00000008,
+ eMatrixChanged = 0x00000010,
+ eTransparentRegionChanged = 0x00000020,
+ eVisibilityChanged = 0x00000040,
+ eFreezeTintChanged = 0x00000080,
+ eDestroyed = 0x00000100
+ };
+
+ enum {
+ eLayerHidden = 0x01,
+ eLayerFrozen = 0x02,
+ eLayerDither = 0x04,
+ eLayerFilter = 0x08,
+ eLayerBlurFreeze = 0x10
+ };
+
+ enum {
+ eOrientationDefault = 0,
+ eOrientation90 = 1,
+ eOrientation180 = 2,
+ eOrientation270 = 3,
+ eOrientationSwapMask = 0x01
+ };
+
+ /* create connection with surface flinger, requires
+ * ACCESS_SURFACE_FLINGER permission
+ */
+
+ virtual sp<ISurfaceFlingerClient> createConnection() = 0;
+
+ /* retrieve the control block */
+ virtual sp<IMemory> getCblk() const = 0;
+
+ /* open/close transactions. recquires ACCESS_SURFACE_FLINGER permission */
+ virtual void openGlobalTransaction() = 0;
+ virtual void closeGlobalTransaction() = 0;
+
+ /* [un]freeze display. recquires ACCESS_SURFACE_FLINGER permission */
+ virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags) = 0;
+ virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags) = 0;
+
+ /* Set display orientation. recquires ACCESS_SURFACE_FLINGER permission */
+ virtual int setOrientation(DisplayID dpy, int orientation) = 0;
+
+ /* signal that we're done booting.
+ * recquires ACCESS_SURFACE_FLINGER permission
+ */
+ virtual void bootFinished() = 0;
+
+ /* get access to the GPU. Access is relinquished when releasing regs */
+ struct gpu_info_t {
+ struct gpu_region_t {
+ sp<IMemory> region;
+ size_t reserved;
+ };
+ sp<IMemory> regs;
+ size_t count;
+ gpu_region_t regions[2];
+ };
+ virtual status_t requestGPU(
+ const sp<IGPUCallback>& callback,
+ gpu_info_t* gpu) = 0;
+
+ /* take the gpu back from any apps using it. They'll get a
+ * EGL_CONTEXT_LOST error */
+ virtual status_t revokeGPU() = 0;
+
+ /* Signal surfaceflinger that there might be some work to do
+ * This is an ASYNCHRONOUS call.
+ */
+ virtual void signal() const = 0;
+};
+
+class IGPUCallback : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(GPUCallback);
+ virtual void gpuLost() = 0; //one-way
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSurfaceComposer : public BnInterface<ISurfaceComposer>
+{
+public:
+ enum {
+ // Note: BOOT_FINISHED must remain this value, it is called from
+ // Java by ActivityManagerService.
+ BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
+ CREATE_CONNECTION,
+ GET_CBLK,
+ OPEN_GLOBAL_TRANSACTION,
+ CLOSE_GLOBAL_TRANSACTION,
+ SET_ORIENTATION,
+ FREEZE_DISPLAY,
+ UNFREEZE_DISPLAY,
+ REQUEST_GPU,
+ REVOKE_GPU,
+ SIGNAL
+ };
+
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+class BnGPUCallback : public BnInterface<IGPUCallback>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISURFACE_COMPOSER_H
diff --git a/include/ui/ISurfaceFlingerClient.h b/include/ui/ISurfaceFlingerClient.h
new file mode 100644
index 0000000..bb2d39f
--- /dev/null
+++ b/include/ui/ISurfaceFlingerClient.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_ISURFACE_FLINGER_CLIENT_H
+#define ANDROID_ISURFACE_FLINGER_CLIENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <utils/RefBase.h>
+
+#include <ui/ISurface.h>
+
+#include <ui/PixelFormat.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class Rect;
+class Point;
+class IMemory;
+class ISurface;
+
+typedef int32_t ClientID;
+typedef int32_t DisplayID;
+
+// ----------------------------------------------------------------------------
+
+class layer_state_t;
+
+class ISurfaceFlingerClient : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(SurfaceFlingerClient);
+
+ struct surface_data_t {
+ int32_t token;
+ int32_t identity;
+ int32_t type;
+ sp<IMemoryHeap> heap[2];
+ status_t readFromParcel(const Parcel& parcel);
+ status_t writeToParcel(Parcel* parcel) const;
+ };
+
+ virtual void getControlBlocks(sp<IMemory>* ctl) const = 0;
+
+ virtual sp<ISurface> createSurface( surface_data_t* data,
+ int pid,
+ DisplayID display,
+ uint32_t w,
+ uint32_t h,
+ PixelFormat format,
+ uint32_t flags) = 0;
+
+ virtual status_t destroySurface(SurfaceID sid) = 0;
+
+ virtual status_t setState(int32_t count, const layer_state_t* states) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSurfaceFlingerClient : public BnInterface<ISurfaceFlingerClient>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISURFACE_FLINGER_CLIENT_H
diff --git a/include/ui/KeyCharacterMap.h b/include/ui/KeyCharacterMap.h
new file mode 100644
index 0000000..bad2cf8
--- /dev/null
+++ b/include/ui/KeyCharacterMap.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef _UI_KEY_CHARACTER_MAP_H
+#define _UI_KEY_CHARACTER_MAP_H
+
+#include <stdint.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+class KeyCharacterMap
+{
+public:
+ ~KeyCharacterMap();
+
+ // see the javadoc for android.text.method.KeyCharacterMap for what
+ // these do
+ unsigned short get(int keycode, int meta);
+ unsigned short getNumber(int keycode);
+ unsigned short getMatch(int keycode, const unsigned short* chars,
+ int charsize, uint32_t modifiers);
+ unsigned short getDisplayLabel(int keycode);
+ bool getKeyData(int keycode, unsigned short *displayLabel,
+ unsigned short *number, unsigned short* results);
+ inline unsigned int getKeyboardType() { return m_type; }
+ bool getEvents(uint16_t* chars, size_t len,
+ Vector<int32_t>* keys, Vector<uint32_t>* modifiers);
+
+ static KeyCharacterMap* load(int id);
+
+ enum {
+ NUMERIC = 1,
+ Q14 = 2,
+ QWERTY = 3 // or AZERTY or whatever
+ };
+
+#define META_MASK 3
+
+private:
+ struct Key
+ {
+ int32_t keycode;
+ uint16_t display_label;
+ uint16_t number;
+ uint16_t data[META_MASK + 1];
+ };
+
+ KeyCharacterMap();
+ static KeyCharacterMap* try_file(const char* filename);
+ Key* find_key(int keycode);
+ bool find_char(uint16_t c, uint32_t* key, uint32_t* mods);
+
+ unsigned int m_type;
+ unsigned int m_keyCount;
+ Key* m_keys;
+};
+
+#endif // _UI_KEY_CHARACTER_MAP_H
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
new file mode 100644
index 0000000..747925d
--- /dev/null
+++ b/include/ui/KeycodeLabels.h
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+#ifndef _UI_KEYCODE_LABELS_H
+#define _UI_KEYCODE_LABELS_H
+
+struct KeycodeLabel {
+ const char *literal;
+ int value;
+};
+
+static const KeycodeLabel KEYCODES[] = {
+ { "SOFT_LEFT", 1 },
+ { "SOFT_RIGHT", 2 },
+ { "HOME", 3 },
+ { "BACK", 4 },
+ { "CALL", 5 },
+ { "ENDCALL", 6 },
+ { "0", 7 },
+ { "1", 8 },
+ { "2", 9 },
+ { "3", 10 },
+ { "4", 11 },
+ { "5", 12 },
+ { "6", 13 },
+ { "7", 14 },
+ { "8", 15 },
+ { "9", 16 },
+ { "STAR", 17 },
+ { "POUND", 18 },
+ { "DPAD_UP", 19 },
+ { "DPAD_DOWN", 20 },
+ { "DPAD_LEFT", 21 },
+ { "DPAD_RIGHT", 22 },
+ { "DPAD_CENTER", 23 },
+ { "VOLUME_UP", 24 },
+ { "VOLUME_DOWN", 25 },
+ { "POWER", 26 },
+ { "CAMERA", 27 },
+ { "CLEAR", 28 },
+ { "A", 29 },
+ { "B", 30 },
+ { "C", 31 },
+ { "D", 32 },
+ { "E", 33 },
+ { "F", 34 },
+ { "G", 35 },
+ { "H", 36 },
+ { "I", 37 },
+ { "J", 38 },
+ { "K", 39 },
+ { "L", 40 },
+ { "M", 41 },
+ { "N", 42 },
+ { "O", 43 },
+ { "P", 44 },
+ { "Q", 45 },
+ { "R", 46 },
+ { "S", 47 },
+ { "T", 48 },
+ { "U", 49 },
+ { "V", 50 },
+ { "W", 51 },
+ { "X", 52 },
+ { "Y", 53 },
+ { "Z", 54 },
+ { "COMMA", 55 },
+ { "PERIOD", 56 },
+ { "ALT_LEFT", 57 },
+ { "ALT_RIGHT", 58 },
+ { "SHIFT_LEFT", 59 },
+ { "SHIFT_RIGHT", 60 },
+ { "TAB", 61 },
+ { "SPACE", 62 },
+ { "SYM", 63 },
+ { "EXPLORER", 64 },
+ { "ENVELOPE", 65 },
+ { "ENTER", 66 },
+ { "DEL", 67 },
+ { "GRAVE", 68 },
+ { "MINUS", 69 },
+ { "EQUALS", 70 },
+ { "LEFT_BRACKET", 71 },
+ { "RIGHT_BRACKET", 72 },
+ { "BACKSLASH", 73 },
+ { "SEMICOLON", 74 },
+ { "APOSTROPHE", 75 },
+ { "SLASH", 76 },
+ { "AT", 77 },
+ { "NUM", 78 },
+ { "HEADSETHOOK", 79 },
+ { "FOCUS", 80 },
+ { "PLUS", 81 },
+ { "MENU", 82 },
+ { "NOTIFICATION", 83 },
+ { "SEARCH", 84 },
+
+ // NOTE: If you add a new keycode here you must also add it to:
+ // (enum KeyCode, in this file)
+ // java/android/android/view/KeyEvent.java
+ // tools/puppet_master/PuppetMaster.nav_keys.py
+ // apps/common/res/values/attrs.xml
+
+ { NULL, 0 }
+};
+
+// These constants need to match the above mappings.
+typedef enum KeyCode {
+ kKeyCodeUnknown = 0,
+
+ kKeyCodeSoftLeft = 1,
+ kKeyCodeSoftRight = 2,
+ kKeyCodeHome = 3,
+ kKeyCodeBack = 4,
+ kKeyCodeCall = 5,
+ kKeyCodeEndCall = 6,
+ kKeyCode0 = 7,
+ kKeyCode1 = 8,
+ kKeyCode2 = 9,
+ kKeyCode3 = 10,
+ kKeyCode4 = 11,
+ kKeyCode5 = 12,
+ kKeyCode6 = 13,
+ kKeyCode7 = 14,
+ kKeyCode8 = 15,
+ kKeyCode9 = 16,
+ kKeyCodeStar = 17,
+ kKeyCodePound = 18,
+ kKeyCodeDpadUp = 19,
+ kKeyCodeDpadDown = 20,
+ kKeyCodeDpadLeft = 21,
+ kKeyCodeDpadRight = 22,
+ kKeyCodeDpadCenter = 23,
+ kKeyCodeVolumeUp = 24,
+ kKeyCodeVolumeDown = 25,
+ kKeyCodePower = 26,
+ kKeyCodeCamera = 27,
+ kKeyCodeClear = 28,
+ kKeyCodeA = 29,
+ kKeyCodeB = 30,
+ kKeyCodeC = 31,
+ kKeyCodeD = 32,
+ kKeyCodeE = 33,
+ kKeyCodeF = 34,
+ kKeyCodeG = 35,
+ kKeyCodeH = 36,
+ kKeyCodeI = 37,
+ kKeyCodeJ = 38,
+ kKeyCodeK = 39,
+ kKeyCodeL = 40,
+ kKeyCodeM = 41,
+ kKeyCodeN = 42,
+ kKeyCodeO = 43,
+ kKeyCodeP = 44,
+ kKeyCodeQ = 45,
+ kKeyCodeR = 46,
+ kKeyCodeS = 47,
+ kKeyCodeT = 48,
+ kKeyCodeU = 49,
+ kKeyCodeV = 50,
+ kKeyCodeW = 51,
+ kKeyCodeX = 52,
+ kKeyCodeY = 53,
+ kKeyCodeZ = 54,
+ kKeyCodeComma = 55,
+ kKeyCodePeriod = 56,
+ kKeyCodeAltLeft = 57,
+ kKeyCodeAltRight = 58,
+ kKeyCodeShiftLeft = 59,
+ kKeyCodeShiftRight = 60,
+ kKeyCodeTab = 61,
+ kKeyCodeSpace = 62,
+ kKeyCodeSym = 63,
+ kKeyCodeExplorer = 64,
+ kKeyCodeEnvelope = 65,
+ kKeyCodeNewline = 66,
+ kKeyCodeDel = 67,
+ kKeyCodeGrave = 68,
+ kKeyCodeMinus = 69,
+ kKeyCodeEquals = 70,
+ kKeyCodeLeftBracket = 71,
+ kKeyCodeRightBracket = 72,
+ kKeyCodeBackslash = 73,
+ kKeyCodeSemicolon = 74,
+ kKeyCodeApostrophe = 75,
+ kKeyCodeSlash = 76,
+ kKeyCodeAt = 77,
+ kKeyCodeNum = 78,
+ kKeyCodeHeadSetHook = 79,
+ kKeyCodeFocus = 80,
+ kKeyCodePlus = 81,
+ kKeyCodeMenu = 82,
+ kKeyCodeNotification = 83,
+ kKeyCodeSearch = 84
+} KeyCode;
+
+static const KeycodeLabel FLAGS[] = {
+ { "WAKE", 0x00000001 },
+ { "WAKE_DROPPED", 0x00000002 },
+ { "SHIFT", 0x00000004 },
+ { "CAPS_LOCK", 0x00000008 },
+ { "ALT", 0x00000010 },
+ { "ALT_GR", 0x00000020 },
+ { "MENU", 0x00000040 },
+ { "LAUNCHER", 0x00000080 },
+ { NULL, 0 }
+};
+
+#endif // _UI_KEYCODE_LABELS_H
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
new file mode 100644
index 0000000..d56a4a7
--- /dev/null
+++ b/include/ui/PixelFormat.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+
+// Pixel formats used across the system.
+// These formats might not all be supported by all renderers, for instance
+// skia or SurfaceFlinger are not required to support all of these formats
+// (either as source or destination)
+
+// XXX: we should consolidate these formats and skia's
+
+#ifndef UI_PIXELFORMAT_H
+#define UI_PIXELFORMAT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <pixelflinger/format.h>
+
+namespace android {
+
+enum {
+ //
+ // these constants need to match those
+ // in graphics/PixelFormat.java & pixelflinger/format.h
+ //
+ PIXEL_FORMAT_UNKNOWN = 0,
+ PIXEL_FORMAT_NONE = 0,
+
+ // logical pixel formats used by the SurfaceFlinger -----------------------
+ PIXEL_FORMAT_CUSTOM = -4,
+ // Custom pixel-format described by a PixelFormatInfo sructure
+
+ PIXEL_FORMAT_TRANSLUCENT = -3,
+ // System chooses a format that supports translucency (many alpha bits)
+
+ PIXEL_FORMAT_TRANSPARENT = -2,
+ // System chooses a format that supports transparency
+ // (at least 1 alpha bit)
+
+ PIXEL_FORMAT_OPAQUE = -1,
+ // System chooses an opaque format (no alpha bits required)
+
+ // real pixel formats supported for rendering -----------------------------
+
+ PIXEL_FORMAT_RGBA_8888 = GGL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
+ PIXEL_FORMAT_RGBX_8888 = GGL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0
+ PIXEL_FORMAT_RGB_888 = GGL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB
+ PIXEL_FORMAT_RGB_565 = GGL_PIXEL_FORMAT_RGB_565, // 16-bit RGB
+ PIXEL_FORMAT_RGBA_5551 = GGL_PIXEL_FORMAT_RGBA_5551, // 16-bit ARGB
+ PIXEL_FORMAT_RGBA_4444 = GGL_PIXEL_FORMAT_RGBA_4444, // 16-bit ARGB
+ PIXEL_FORMAT_A_8 = GGL_PIXEL_FORMAT_A_8, // 8-bit A
+ PIXEL_FORMAT_L_8 = GGL_PIXEL_FORMAT_L_8, // 8-bit L (R=G=B=L)
+ PIXEL_FORMAT_LA_88 = GGL_PIXEL_FORMAT_LA_88, // 16-bit LA
+ PIXEL_FORMAT_RGB_332 = GGL_PIXEL_FORMAT_RGB_332, // 8-bit RGB
+
+ PIXEL_FORMAT_YCbCr_422_SP= GGL_PIXEL_FORMAT_YCbCr_422_SP,
+ PIXEL_FORMAT_YCbCr_420_SP= GGL_PIXEL_FORMAT_YCbCr_420_SP,
+
+ // New formats can be added if they're also defined in
+ // pixelflinger/format.h
+};
+
+typedef int32_t PixelFormat;
+
+struct PixelFormatInfo
+{
+ inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
+ size_t version;
+ PixelFormat format;
+ size_t bytesPerPixel;
+ size_t bitsPerPixel;
+ uint8_t h_alpha;
+ uint8_t l_alpha;
+ uint8_t h_red;
+ uint8_t l_red;
+ uint8_t h_green;
+ uint8_t l_green;
+ uint8_t h_blue;
+ uint8_t l_blue;
+ uint32_t reserved[2];
+};
+
+// considere caching the results of these functions are they're not
+// guaranteed to be fast.
+ssize_t bytesPerPixel(PixelFormat format);
+ssize_t bitsPerPixel(PixelFormat format);
+status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info);
+
+}; // namespace android
+
+#endif // UI_PIXELFORMAT_H
diff --git a/include/ui/Point.h b/include/ui/Point.h
new file mode 100644
index 0000000..dbbad1e
--- /dev/null
+++ b/include/ui/Point.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2006 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_UI_POINT
+#define ANDROID_UI_POINT
+
+#include <utils/TypeHelpers.h>
+
+namespace android {
+
+class Point
+{
+public:
+ int x;
+ int y;
+
+ // we don't provide copy-ctor and operator= on purpose
+ // because we want the compiler generated versions
+
+ // Default constructor doesn't initialize the Point
+ inline Point()
+ {
+ }
+
+ inline Point(int _x, int _y) : x(_x), y(_y)
+ {
+ }
+
+ inline bool operator == (const Point& rhs) const {
+ return (x == rhs.x) && (y == rhs.y);
+ }
+ inline bool operator != (const Point& rhs) const {
+ return !operator == (rhs);
+ }
+
+ inline bool isOrigin() const {
+ return !(x|y);
+ }
+
+ // operator < defines an order which allows to use points in sorted
+ // vectors.
+ bool operator < (const Point& rhs) const {
+ return y<rhs.y || (y==rhs.y && x<rhs.x);
+ }
+
+ inline Point& operator - () {
+ x=-x;
+ y=-y;
+ return *this;
+ }
+
+ inline Point& operator += (const Point& rhs) {
+ x += rhs.x;
+ y += rhs.y;
+ return *this;
+ }
+ inline Point& operator -= (const Point& rhs) {
+ x -= rhs.x;
+ y -= rhs.y;
+ return *this;
+ }
+
+ Point operator + (const Point& rhs) const {
+ return Point(x+rhs.x, y+rhs.y);
+ }
+ Point operator - (const Point& rhs) const {
+ return Point(x-rhs.x, y-rhs.y);
+ }
+};
+
+ANDROID_BASIC_TYPES_TRAITS(Point)
+
+}; // namespace android
+
+#endif // ANDROID_UI_POINT
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
new file mode 100644
index 0000000..d232847
--- /dev/null
+++ b/include/ui/Rect.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2006 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_UI_RECT
+#define ANDROID_UI_RECT
+
+#include <utils/TypeHelpers.h>
+#include <ui/Point.h>
+
+namespace android {
+
+class Rect
+{
+public:
+ int left;
+ int top;
+ int right;
+ int bottom;
+
+ // we don't provide copy-ctor and operator= on purpose
+ // because we want the compiler generated versions
+
+ inline Rect()
+ {
+ }
+
+ inline Rect(int w, int h)
+ : left(0), top(0), right(w), bottom(h)
+ {
+ }
+
+ inline Rect(int l, int t, int r, int b)
+ : left(l), top(t), right(r), bottom(b)
+ {
+ }
+
+ inline Rect(const Point& lt, const Point& rb)
+ : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y)
+ {
+ }
+
+ void makeInvalid();
+
+ // a valid rectangle has a non negative width and height
+ inline bool isValid() const {
+ return (width()>=0) && (height()>=0);
+ }
+
+ // an empty rect has a zero width or height, or is invalid
+ inline bool isEmpty() const {
+ return (width()<=0) || (height()<=0);
+ }
+
+ inline void set(const Rect& rhs) {
+ operator = (rhs);
+ }
+
+ // rectangle's width
+ inline int width() const {
+ return right-left;
+ }
+
+ // rectangle's height
+ inline int height() const {
+ return bottom-top;
+ }
+
+ // returns left-top Point non-const reference, can be assigned
+ inline Point& leftTop() {
+ return reinterpret_cast<Point&>(left);
+ }
+ // returns right bottom non-const reference, can be assigned
+ inline Point& rightBottom() {
+ return reinterpret_cast<Point&>(right);
+ }
+
+ // the following 4 functions return the 4 corners of the rect as Point
+ inline const Point& leftTop() const {
+ return reinterpret_cast<const Point&>(left);
+ }
+ inline const Point& rightBottom() const {
+ return reinterpret_cast<const Point&>(right);
+ }
+ Point rightTop() const {
+ return Point(right, top);
+ }
+ Point leftBottom() const {
+ return Point(left, bottom);
+ }
+
+ // comparisons
+ inline bool operator == (const Rect& rhs) const {
+ return (left == rhs.left) && (top == rhs.top) &&
+ (right == rhs.right) && (bottom == rhs.bottom);
+ }
+
+ inline bool operator != (const Rect& rhs) const {
+ return !operator == (rhs);
+ }
+
+ // operator < defines an order which allows to use rectangles in sorted
+ // vectors.
+ bool operator < (const Rect& rhs) const;
+
+ Rect& offsetToOrigin() {
+ right -= left;
+ bottom -= top;
+ left = top = 0;
+ return *this;
+ }
+ Rect& offsetTo(const Point& p) {
+ return offsetTo(p.x, p.y);
+ }
+ Rect& offsetBy(const Point& dp) {
+ return offsetBy(dp.x, dp.y);
+ }
+ Rect& operator += (const Point& rhs) {
+ return offsetBy(rhs.x, rhs.y);
+ }
+ Rect& operator -= (const Point& rhs) {
+ return offsetBy(-rhs.x, -rhs.y);
+ }
+ Rect operator + (const Point& rhs) const;
+ Rect operator - (const Point& rhs) const;
+
+ void translate(int dx, int dy) { // legacy, don't use.
+ offsetBy(dx, dy);
+ }
+
+ Rect& offsetTo(int x, int y);
+ Rect& offsetBy(int x, int y);
+ bool intersect(const Rect& with, Rect* result) const;
+};
+
+ANDROID_BASIC_TYPES_TRAITS(Rect)
+
+}; // namespace android
+
+#endif // ANDROID_UI_RECT
diff --git a/include/ui/Region.h b/include/ui/Region.h
new file mode 100644
index 0000000..a86e630
--- /dev/null
+++ b/include/ui/Region.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_UI_REGION_H
+#define ANDROID_UI_REGION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Vector.h>
+#include <utils/Parcel.h>
+
+#include <ui/Rect.h>
+#include <ui/BlitHardware.h>
+
+#include <corecg/SkRegion.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class String8;
+
+// ---------------------------------------------------------------------------
+class Region
+{
+public:
+ Region();
+ Region(const Region& rhs);
+ explicit Region(const SkRegion& rhs);
+ explicit Region(const Rect& rhs);
+ explicit Region(const Parcel& parcel);
+ explicit Region(const void* buffer);
+ ~Region();
+
+ Region& operator = (const Region& rhs);
+
+ inline bool isEmpty() const { return mRegion.isEmpty(); }
+ inline bool isRect() const { return mRegion.isRect(); }
+
+ Rect bounds() const;
+
+ const SkRegion& toSkRegion() const;
+
+ void clear();
+ void set(const Rect& r);
+
+ Region& orSelf(const Rect& rhs);
+ Region& andSelf(const Rect& rhs);
+
+ // boolean operators, applied on this
+ Region& orSelf(const Region& rhs);
+ Region& andSelf(const Region& rhs);
+ Region& subtractSelf(const Region& rhs);
+
+ // these translate rhs first
+ Region& translateSelf(int dx, int dy);
+ Region& orSelf(const Region& rhs, int dx, int dy);
+ Region& andSelf(const Region& rhs, int dx, int dy);
+ Region& subtractSelf(const Region& rhs, int dx, int dy);
+
+ // boolean operators
+ Region merge(const Region& rhs) const;
+ Region intersect(const Region& rhs) const;
+ Region subtract(const Region& rhs) const;
+
+ // these translate rhs first
+ Region translate(int dx, int dy) const;
+ Region merge(const Region& rhs, int dx, int dy) const;
+ Region intersect(const Region& rhs, int dx, int dy) const;
+ Region subtract(const Region& rhs, int dx, int dy) const;
+
+ // convenience operators overloads
+ inline Region operator | (const Region& rhs) const;
+ inline Region operator & (const Region& rhs) const;
+ inline Region operator - (const Region& rhs) const;
+ inline Region operator + (const Point& pt) const;
+
+ inline Region& operator |= (const Region& rhs);
+ inline Region& operator &= (const Region& rhs);
+ inline Region& operator -= (const Region& rhs);
+ inline Region& operator += (const Point& pt);
+
+ class iterator {
+ SkRegion::Iterator mIt;
+ public:
+ iterator(const Region& r);
+ inline operator bool () const { return !done(); }
+ int iterate(Rect* rect);
+ private:
+ inline bool done() const {
+ return const_cast<SkRegion::Iterator&>(mIt).done();
+ }
+ };
+
+ size_t rects(Vector<Rect>& rectList) const;
+
+ // flatten/unflatten a region to/from a Parcel
+ status_t write(Parcel& parcel) const;
+ status_t read(const Parcel& parcel);
+
+ // flatten/unflatten a region to/from a raw buffer
+ ssize_t write(void* buffer, size_t size) const;
+ static ssize_t writeEmpty(void* buffer, size_t size);
+
+ ssize_t read(const void* buffer);
+ static bool isEmpty(void* buffer);
+
+ void dump(String8& out, const char* what, uint32_t flags=0) const;
+ void dump(const char* what, uint32_t flags=0) const;
+
+private:
+ SkRegion mRegion;
+};
+
+
+Region Region::operator | (const Region& rhs) const {
+ return merge(rhs);
+}
+Region Region::operator & (const Region& rhs) const {
+ return intersect(rhs);
+}
+Region Region::operator - (const Region& rhs) const {
+ return subtract(rhs);
+}
+Region Region::operator + (const Point& pt) const {
+ return translate(pt.x, pt.y);
+}
+
+
+Region& Region::operator |= (const Region& rhs) {
+ return orSelf(rhs);
+}
+Region& Region::operator &= (const Region& rhs) {
+ return andSelf(rhs);
+}
+Region& Region::operator -= (const Region& rhs) {
+ return subtractSelf(rhs);
+}
+Region& Region::operator += (const Point& pt) {
+ return translateSelf(pt.x, pt.y);
+}
+
+// ---------------------------------------------------------------------------
+
+struct region_iterator : public copybit_region_t {
+ region_iterator(const Region& region) : i(region) {
+ this->next = iterate;
+ }
+private:
+ static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
+ return static_cast<const region_iterator*>(self)
+ ->i.iterate(reinterpret_cast<Rect*>(rect));
+ }
+ mutable Region::iterator i;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_UI_REGION_H
+
diff --git a/include/ui/Surface.h b/include/ui/Surface.h
new file mode 100644
index 0000000..0a75bf3
--- /dev/null
+++ b/include/ui/Surface.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_UI_SURFACE_H
+#define ANDROID_UI_SURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+#include <ui/ISurface.h>
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+#include <ui/ISurfaceFlingerClient.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Rect;
+class SurfaceComposerClient;
+
+class Surface : public RefBase
+{
+
+public:
+ struct SurfaceInfo {
+ uint32_t w;
+ uint32_t h;
+ uint32_t bpr;
+ PixelFormat format;
+ void* bits;
+ void* base;
+ uint32_t reserved[2];
+ };
+
+ bool isValid() const { return this && mToken>=0 && mClient!=0; }
+ SurfaceID ID() const { return mToken; }
+
+ status_t lock(SurfaceInfo* info, bool blocking = true);
+ status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
+ status_t unlockAndPost();
+ status_t unlock();
+
+ void* heapBase(int i) const;
+ uint32_t getFlags() const { return mFlags; }
+ int getMemoryType() const { return mMemoryType; }
+
+ // setSwapRectangle() is mainly used by EGL
+ void setSwapRectangle(const Rect& r);
+ const Rect& swapRectangle() const;
+ status_t nextBuffer(SurfaceInfo* info);
+
+ sp<Surface> dup() const;
+ static sp<Surface> readFromParcel(Parcel* parcel);
+ static status_t writeToParcel(const sp<Surface>& surface, Parcel* parcel);
+ static bool isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs);
+
+ status_t setLayer(int32_t layer);
+ status_t setPosition(int32_t x, int32_t y);
+ status_t setSize(uint32_t w, uint32_t h);
+ status_t hide();
+ status_t show(int32_t layer = -1);
+ status_t freeze();
+ status_t unfreeze();
+ status_t setFlags(uint32_t flags, uint32_t mask);
+ status_t setTransparentRegionHint(const Region& transparent);
+ status_t setAlpha(float alpha=1.0f);
+ status_t setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
+ status_t setFreezeTint(uint32_t tint);
+
+ uint32_t getIdentity() const { return mIdentity; }
+private:
+ friend class SurfaceComposerClient;
+
+ // camera needs access to the ISurface binder interface for preview
+ friend class Camera;
+ // mediaplayer needs access to ISurface for display
+ friend class MediaPlayer;
+ const sp<ISurface>& getISurface() const { return mSurface; }
+
+ // can't be copied
+ Surface& operator = (Surface& rhs);
+ Surface(const Surface& rhs);
+
+ Surface(const sp<SurfaceComposerClient>& client,
+ const sp<ISurface>& surface,
+ const ISurfaceFlingerClient::surface_data_t& data,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
+ bool owner = true);
+
+ Surface(Surface const* rhs);
+
+ ~Surface();
+
+ Region dirtyRegion() const;
+ void setDirtyRegion(const Region& region) const;
+
+ // this locks protects calls to lockSurface() / unlockSurface()
+ // and is called by SurfaceComposerClient.
+ Mutex& getLock() const { return mSurfaceLock; }
+
+ sp<SurfaceComposerClient> mClient;
+ sp<ISurface> mSurface;
+ sp<IMemoryHeap> mHeap[2];
+ int mMemoryType;
+ SurfaceID mToken;
+ uint32_t mIdentity;
+ PixelFormat mFormat;
+ uint32_t mFlags;
+ const bool mOwner;
+ mutable void* mSurfaceHeapBase[2];
+ mutable Region mDirtyRegion;
+ mutable Rect mSwapRectangle;
+ mutable uint8_t mBackbufferIndex;
+ mutable Mutex mSurfaceLock;
+};
+
+}; // namespace android
+
+#endif // ANDROID_UI_SURFACE_H
+
diff --git a/include/ui/SurfaceComposerClient.h b/include/ui/SurfaceComposerClient.h
new file mode 100644
index 0000000..3b875be
--- /dev/null
+++ b/include/ui/SurfaceComposerClient.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_SURFACE_COMPOSER_CLIENT_H
+#define ANDROID_SURFACE_COMPOSER_CLIENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/Region.h>
+#include <ui/Surface.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Region;
+class SurfaceFlingerSynchro;
+struct per_client_cblk_t;
+struct layer_cblk_t;
+
+class SurfaceComposerClient : virtual public RefBase
+{
+public:
+ SurfaceComposerClient();
+ virtual ~SurfaceComposerClient();
+
+ // Always make sure we could initialize
+ status_t initCheck() const;
+
+ // Return the connection of this client
+ sp<IBinder> connection() const;
+
+ // Retrieve a client for an existing connection.
+ static sp<SurfaceComposerClient>
+ clientForConnection(const sp<IBinder>& conn);
+
+ // Forcibly remove connection before all references have gone away.
+ void dispose();
+
+ // ------------------------------------------------------------------------
+ // surface creation / destruction
+
+ //! Create a surface
+ sp<Surface> createSurface(
+ int pid, //!< pid of the process the surfacec is for
+ DisplayID display, //!< Display to create this surface on
+ uint32_t w, //!< width in pixel
+ uint32_t h, //!< height in pixel
+ PixelFormat format, //!< pixel-format desired
+ uint32_t flags = 0 //!< usage flags
+ );
+
+ // ------------------------------------------------------------------------
+ // Composer paramters
+ // All composer parameters must be changed within a transaction
+ // several surfaces can be updated in one transaction, all changes are
+ // committed at once when the transaction is closed.
+ // CloseTransaction() usually requires an IPC with the server.
+
+ //! Open a composer transaction
+ status_t openTransaction();
+
+ //! commit the transaction
+ status_t closeTransaction();
+
+ //! Open a composer transaction on all active SurfaceComposerClients.
+ static void openGlobalTransaction();
+
+ //! Close a composer transaction on all active SurfaceComposerClients.
+ static void closeGlobalTransaction();
+
+ //! Freeze the specified display but not transactions.
+ static status_t freezeDisplay(DisplayID dpy, uint32_t flags = 0);
+
+ //! Resume updates on the specified display.
+ static status_t unfreezeDisplay(DisplayID dpy, uint32_t flags = 0);
+
+ //! Set the orientation of the given display
+ static int setOrientation(DisplayID dpy, int orientation);
+
+ // Query the number of displays
+ static ssize_t getNumberOfDisplays();
+
+ // Get information about a display
+ static status_t getDisplayInfo(DisplayID dpy, DisplayInfo* info);
+ static ssize_t getDisplayWidth(DisplayID dpy);
+ static ssize_t getDisplayHeight(DisplayID dpy);
+ static ssize_t getDisplayOrientation(DisplayID dpy);
+
+
+private:
+ friend class Surface;
+
+ SurfaceComposerClient(const sp<ISurfaceComposer>& sm,
+ const sp<IBinder>& conn);
+
+ status_t hide(Surface* surface);
+ status_t show(Surface* surface, int32_t layer = -1);
+ status_t freeze(Surface* surface);
+ status_t unfreeze(Surface* surface);
+ status_t setFlags(Surface* surface, uint32_t flags, uint32_t mask);
+ status_t setTransparentRegionHint(Surface* surface, const Region& transparent);
+ status_t setLayer(Surface* surface, int32_t layer);
+ status_t setAlpha(Surface* surface, float alpha=1.0f);
+ status_t setFreezeTint(Surface* surface, uint32_t tint);
+ status_t setMatrix(Surface* surface, float dsdx, float dtdx, float dsdy, float dtdy);
+ status_t setPosition(Surface* surface, int32_t x, int32_t y);
+ status_t setSize(Surface* surface, uint32_t w, uint32_t h);
+
+ //! Unlock the surface, and specify the dirty region if any
+ status_t unlockAndPostSurface(Surface* surface);
+ status_t unlockSurface(Surface* surface);
+
+ status_t lockSurface(Surface* surface,
+ Surface::SurfaceInfo* info,
+ Region* dirty,
+ bool blocking = true);
+
+ status_t nextBuffer(Surface* surface,
+ Surface::SurfaceInfo* info);
+
+ status_t destroySurface(SurfaceID sid);
+
+ void _init(const sp<ISurfaceComposer>& sm,
+ const sp<ISurfaceFlingerClient>& conn);
+ void _signal_server();
+ static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty);
+
+ inline layer_state_t* _get_state_l(const sp<Surface>& surface);
+ layer_state_t* _lockLayerState(const sp<Surface>& surface);
+ inline void _unlockLayerState();
+
+ status_t validateSurface(
+ per_client_cblk_t const* cblk, Surface const * surface);
+
+ void pinHeap(const sp<IMemoryHeap>& heap);
+
+ mutable Mutex mLock;
+ layer_state_t* mPrebuiltLayerState;
+ SortedVector<layer_state_t> mStates;
+ int32_t mTransactionOpen;
+
+ // these don't need to be protected because they never change
+ // after assignment
+ status_t mStatus;
+ per_client_cblk_t* mControl;
+ sp<IMemory> mControlMemory;
+ sp<ISurfaceFlingerClient> mClient;
+ sp<IMemoryHeap> mSurfaceHeap;
+ uint8_t* mSurfaceHeapBase;
+ void* mGL;
+ SurfaceFlingerSynchro* mSignalServer;
+};
+
+}; // namespace android
+
+#endif // ANDROID_SURFACE_COMPOSER_CLIENT_H
+
diff --git a/include/utils.h b/include/utils.h
new file mode 100644
index 0000000..30648b1
--- /dev/null
+++ b/include/utils.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Handy utility functions and portability code. This file includes all
+// of the generally-useful headers in the "utils" directory.
+//
+#ifndef _LIBS_UTILS_H
+#define _LIBS_UTILS_H
+
+#include <utils/ported.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/List.h>
+#include <utils/string_array.h>
+#include <utils/misc.h>
+#include <utils/Errors.h>
+
+#endif // _LIBS_UTILS_H
diff --git a/include/utils/AndroidUnicode.h b/include/utils/AndroidUnicode.h
new file mode 100644
index 0000000..563fcd0
--- /dev/null
+++ b/include/utils/AndroidUnicode.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2006 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_UNICODE_H
+#define ANDROID_UNICODE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define REPLACEMENT_CHAR (0xFFFD)
+
+// this part of code is copied from umachine.h under ICU
+/**
+ * Define UChar32 as a type for single Unicode code points.
+ * UChar32 is a signed 32-bit integer (same as int32_t).
+ *
+ * The Unicode code point range is 0..0x10ffff.
+ * All other values (negative or >=0x110000) are illegal as Unicode code points.
+ * They may be used as sentinel values to indicate "done", "error"
+ * or similar non-code point conditions.
+ *
+ * @stable ICU 2.4
+ */
+typedef int32_t UChar32;
+
+namespace android {
+
+ class Encoding;
+ /**
+ * \class Unicode
+ *
+ * Helper class for getting properties of Unicode characters. Characters
+ * can have one of the types listed in CharType and each character can have the
+ * directionality of Direction.
+ */
+ class Unicode
+ {
+ public:
+ /**
+ * Directions specified in the Unicode standard. These directions map directly
+ * to java.lang.Character.
+ */
+ enum Direction {
+ DIRECTIONALITY_UNDEFINED = -1,
+ DIRECTIONALITY_LEFT_TO_RIGHT,
+ DIRECTIONALITY_RIGHT_TO_LEFT,
+ DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC,
+ DIRECTIONALITY_EUROPEAN_NUMBER,
+ DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR,
+ DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR,
+ DIRECTIONALITY_ARABIC_NUMBER,
+ DIRECTIONALITY_COMMON_NUMBER_SEPARATOR,
+ DIRECTIONALITY_NONSPACING_MARK,
+ DIRECTIONALITY_BOUNDARY_NEUTRAL,
+ DIRECTIONALITY_PARAGRAPH_SEPARATOR,
+ DIRECTIONALITY_SEGMENT_SEPARATOR,
+ DIRECTIONALITY_WHITESPACE,
+ DIRECTIONALITY_OTHER_NEUTRALS,
+ DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING,
+ DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE,
+ DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING,
+ DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE,
+ DIRECTIONALITY_POP_DIRECTIONAL_FORMAT
+ };
+
+ /**
+ * Character types as specified in the Unicode standard. These map directly to
+ * java.lang.Character.
+ */
+ enum CharType {
+ CHARTYPE_UNASSIGNED = 0,
+ CHARTYPE_UPPERCASE_LETTER,
+ CHARTYPE_LOWERCASE_LETTER,
+ CHARTYPE_TITLECASE_LETTER,
+ CHARTYPE_MODIFIER_LETTER,
+ CHARTYPE_OTHER_LETTER,
+ CHARTYPE_NON_SPACING_MARK,
+ CHARTYPE_ENCLOSING_MARK,
+ CHARTYPE_COMBINING_SPACING_MARK,
+ CHARTYPE_DECIMAL_DIGIT_NUMBER,
+ CHARTYPE_LETTER_NUMBER,
+ CHARTYPE_OTHER_NUMBER,
+ CHARTYPE_SPACE_SEPARATOR,
+ CHARTYPE_LINE_SEPARATOR,
+ CHARTYPE_PARAGRAPH_SEPARATOR,
+ CHARTYPE_CONTROL,
+ CHARTYPE_FORMAT,
+ CHARTYPE_MISSING_VALUE_FOR_JAVA, /* This is the mysterious missing 17 value from the java constants */
+ CHARTYPE_PRIVATE_USE,
+ CHARTYPE_SURROGATE,
+ CHARTYPE_DASH_PUNCTUATION,
+ CHARTYPE_START_PUNCTUATION,
+ CHARTYPE_END_PUNCTUATION,
+ CHARTYPE_CONNECTOR_PUNCTUATION,
+ CHARTYPE_OTHER_PUNCTUATION,
+ CHARTYPE_MATH_SYMBOL,
+ CHARTYPE_CURRENCY_SYMBOL,
+ CHARTYPE_MODIFIER_SYMBOL,
+ CHARTYPE_OTHER_SYMBOL,
+ CHARTYPE_INITIAL_QUOTE_PUNCTUATION,
+ CHARTYPE_FINAL_QUOTE_PUNCTUATION
+ };
+
+ /**
+ * Decomposition types as described by the unicode standard. These values map to
+ * the same values in uchar.h in ICU.
+ */
+ enum DecompositionType {
+ DECOMPOSITION_NONE = 0,
+ DECOMPOSITION_CANONICAL,
+ DECOMPOSITION_COMPAT,
+ DECOMPOSITION_CIRCLE,
+ DECOMPOSITION_FINAL,
+ DECOMPOSITION_FONT,
+ DECOMPOSITION_FRACTION,
+ DECOMPOSITION_INITIAL,
+ DECOMPOSITION_ISOLATED,
+ DECOMPOSITION_MEDIAL,
+ DECOMPOSITION_NARROW,
+ DECOMPOSITION_NOBREAK,
+ DECOMPOSITION_SMALL,
+ DECOMPOSITION_SQUARE,
+ DECOMPOSITION_SUB,
+ DECOMPOSITION_SUPER,
+ DECOMPOSITION_VERTICAL,
+ DECOMPOSITION_WIDE
+ };
+
+ /**
+ * Returns the packed data for java calls
+ * @param c The unicode character.
+ * @return The packed data for the character.
+ *
+ * Copied from java.lang.Character implementation:
+ * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ * F E D C B A 9 8 7 6 5 4 3 2 1 0 F E D C B A 9 8 7 6 5 4 3 2 1 0
+ *
+ * 31 types ---------
+ * 18 directionalities ---------
+ * 2 mirroreds -
+ * ----------- 56 toupper diffs
+ * ----------- 48 tolower diffs
+ * --- 4 totitlecase diffs
+ * ------------- 84 numeric values
+ * --------- 24 mirror char diffs
+ */
+ static uint32_t getPackedData(UChar32 c);
+
+ /**
+ * Get the Character type.
+ * @param c The unicode character.
+ * @return The character's type or CHARTYPE_UNASSIGNED if the character is invalid
+ * or has an unassigned class.
+ */
+ static CharType getType(UChar32 c);
+
+ /**
+ * Get the Character's decomposition type.
+ * @param c The unicode character.
+ * @return The character's decomposition type or DECOMPOSITION_NONE is there
+ * is no decomposition.
+ */
+ static DecompositionType getDecompositionType(UChar32 c);
+
+ /**
+ * Returns the digit value of a character or -1 if the character
+ * is not within the specified radix.
+ *
+ * The digit value is computed for integer characters and letters
+ * within the given radix. This function does not handle Roman Numerals,
+ * fractions, or any other characters that may represent numbers.
+ *
+ * @param c The unicode character
+ * @param radix The intended radix.
+ * @return The digit value or -1 if there is no digit value or if the value is outside the radix.
+ */
+ static int getDigitValue(UChar32 c, int radix = 10);
+
+ /**
+ * Return the numeric value of a character
+ *
+ * @param c The unicode character.
+ * @return The numeric value of the character. -1 if the character has no numeric value,
+ * -2 if the character has a numeric value that is not representable by an integer.
+ */
+ static int getNumericValue(UChar32 c);
+
+ /**
+ * Convert the character to lowercase
+ * @param c The unicode character.
+ * @return The lowercase character equivalent of c. If c does not have a lowercase equivalent,
+ * the original character is returned.
+ */
+ static UChar32 toLower(UChar32 c);
+
+ /**
+ * Convert the character to uppercase
+ * @param c The unicode character.
+ * @return The uppercase character equivalent of c. If c does not have an uppercase equivalent,
+ * the original character is returned.
+ */
+ static UChar32 toUpper(UChar32 c);
+
+ /**
+ * Get the directionality of the character.
+ * @param c The unicode character.
+ * @return The direction of the character or DIRECTIONALITY_UNDEFINED.
+ */
+ static Direction getDirectionality(UChar32 c);
+
+ /**
+ * Check if the character is a mirrored character. This means that the character
+ * has an equivalent character that is the mirror image of itself.
+ * @param c The unicode character.
+ * @return True iff c has a mirror equivalent.
+ */
+ static bool isMirrored(UChar32 c);
+
+ /**
+ * Return the mirror of the given character.
+ * @param c The unicode character.
+ * @return The mirror equivalent of c. If c does not have a mirror equivalent,
+ * the original character is returned.
+ * @see isMirrored
+ */
+ static UChar32 toMirror(UChar32 c);
+
+ /**
+ * Convert the character to title case.
+ * @param c The unicode character.
+ * @return The titlecase equivalent of c. If c does not have a titlecase equivalent,
+ * the original character is returned.
+ */
+ static UChar32 toTitle(UChar32 c);
+
+ };
+
+}
+
+#endif
diff --git a/include/utils/Asset.h b/include/utils/Asset.h
new file mode 100644
index 0000000..d8351f5
--- /dev/null
+++ b/include/utils/Asset.h
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Class providing access to a read-only asset. Asset objects are NOT
+// thread-safe, and should not be shared across threads.
+//
+#ifndef __LIBS_ASSET_H
+#define __LIBS_ASSET_H
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "FileMap.h"
+#include "String8.h"
+#include "Errors.h"
+
+namespace android {
+
+/*
+ * Instances of this class provide read-only operations on a byte stream.
+ *
+ * Access may be optimized for streaming, random, or whole buffer modes. All
+ * operations are supported regardless of how the file was opened, but some
+ * things will be less efficient. [pass that in??]
+ *
+ * "Asset" is the base class for all types of assets. The classes below
+ * provide most of the implementation. The AssetManager uses one of the
+ * static "create" functions defined here to create a new instance.
+ */
+class Asset {
+public:
+ virtual ~Asset(void);
+
+ static int32_t getGlobalCount();
+
+ /* used when opening an asset */
+ typedef enum AccessMode {
+ ACCESS_UNKNOWN = 0,
+
+ /* read chunks, and seek forward and backward */
+ ACCESS_RANDOM,
+
+ /* read sequentially, with an occasional forward seek */
+ ACCESS_STREAMING,
+
+ /* caller plans to ask for a read-only buffer with all data */
+ ACCESS_BUFFER,
+ } AccessMode;
+
+ enum {
+ /* data larger than this does not get uncompressed into a buffer */
+ UNCOMPRESS_DATA_MAX = 1 * 1024 * 1024
+ };
+
+ /*
+ * Read data from the current offset. Returns the actual number of
+ * bytes read, 0 on EOF, or -1 on error.
+ */
+ virtual ssize_t read(void* buf, size_t count) = 0;
+
+ /*
+ * Seek to the specified offset. "whence" uses the same values as
+ * lseek/fseek. Returns the new position on success, or (off_t) -1
+ * on failure.
+ */
+ virtual off_t seek(off_t offset, int whence) = 0;
+
+ /*
+ * Close the asset, freeing all associated resources.
+ */
+ virtual void close(void) = 0;
+
+ /*
+ * Get a pointer to a buffer with the entire contents of the file.
+ */
+ virtual const void* getBuffer(bool wordAligned) = 0;
+
+ /*
+ * Get the total amount of data that can be read.
+ */
+ virtual off_t getLength(void) const = 0;
+
+ /*
+ * Get the total amount of data that can be read from the current position.
+ */
+ virtual off_t getRemainingLength(void) const = 0;
+
+ /*
+ * Open a new file descriptor that can be used to read this asset.
+ * Returns -1 if you can not use the file descriptor (for example if the
+ * asset is compressed).
+ */
+ virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const = 0;
+
+ /*
+ * Get a string identifying the asset's source. This might be a full
+ * path, it might be a colon-separated list of identifiers.
+ *
+ * This is NOT intended to be used for anything except debug output.
+ * DO NOT try to parse this or use it to open a file.
+ */
+ const char* getAssetSource(void) const { return mAssetSource.string(); }
+
+protected:
+ Asset(void); // constructor; only invoked indirectly
+
+ /* handle common seek() housekeeping */
+ off_t handleSeek(off_t offset, int whence, off_t curPosn, off_t maxPosn);
+
+ /* set the asset source string */
+ void setAssetSource(const String8& path) { mAssetSource = path; }
+
+ AccessMode getAccessMode(void) const { return mAccessMode; }
+
+private:
+ /* these operations are not implemented */
+ Asset(const Asset& src);
+ Asset& operator=(const Asset& src);
+
+ /* AssetManager needs access to our "create" functions */
+ friend class AssetManager;
+
+ /*
+ * Create the asset from a named file on disk.
+ */
+ static Asset* createFromFile(const char* fileName, AccessMode mode);
+
+ /*
+ * Create the asset from a named, compressed file on disk (e.g. ".gz").
+ */
+ static Asset* createFromCompressedFile(const char* fileName,
+ AccessMode mode);
+
+#if 0
+ /*
+ * Create the asset from a segment of an open file. This will fail
+ * if "offset" and "length" don't fit within the bounds of the file.
+ *
+ * The asset takes ownership of the file descriptor.
+ */
+ static Asset* createFromFileSegment(int fd, off_t offset, size_t length,
+ AccessMode mode);
+
+ /*
+ * Create from compressed data. "fd" should be seeked to the start of
+ * the compressed data. This could be inside a gzip file or part of a
+ * Zip archive.
+ *
+ * The asset takes ownership of the file descriptor.
+ *
+ * This may not verify the validity of the compressed data until first
+ * use.
+ */
+ static Asset* createFromCompressedData(int fd, off_t offset,
+ int compressionMethod, size_t compressedLength,
+ size_t uncompressedLength, AccessMode mode);
+#endif
+
+ /*
+ * Create the asset from a memory-mapped file segment.
+ *
+ * The asset takes ownership of the FileMap.
+ */
+ static Asset* createFromUncompressedMap(FileMap* dataMap, AccessMode mode);
+
+ /*
+ * Create the asset from a memory-mapped file segment with compressed
+ * data. "method" is a Zip archive compression method constant.
+ *
+ * The asset takes ownership of the FileMap.
+ */
+ static Asset* createFromCompressedMap(FileMap* dataMap, int method,
+ size_t uncompressedLen, AccessMode mode);
+
+
+ /*
+ * Create from a reference-counted chunk of shared memory.
+ */
+ // TODO
+
+ AccessMode mAccessMode; // how the asset was opened
+ String8 mAssetSource; // debug string
+};
+
+
+/*
+ * ===========================================================================
+ *
+ * Innards follow. Do not use these classes directly.
+ */
+
+/*
+ * An asset based on an uncompressed file on disk. It may encompass the
+ * entire file or just a piece of it. Access is through fread/fseek.
+ */
+class _FileAsset : public Asset {
+public:
+ _FileAsset(void);
+ virtual ~_FileAsset(void);
+
+ /*
+ * Use a piece of an already-open file.
+ *
+ * On success, the object takes ownership of "fd".
+ */
+ status_t openChunk(const char* fileName, int fd, off_t offset, size_t length);
+
+ /*
+ * Use a memory-mapped region.
+ *
+ * On success, the object takes ownership of "dataMap".
+ */
+ status_t openChunk(FileMap* dataMap);
+
+ /*
+ * Standard Asset interfaces.
+ */
+ virtual ssize_t read(void* buf, size_t count);
+ virtual off_t seek(off_t offset, int whence);
+ virtual void close(void);
+ virtual const void* getBuffer(bool wordAligned);
+ virtual off_t getLength(void) const { return mLength; }
+ virtual off_t getRemainingLength(void) const { return mLength-mOffset; }
+ virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const;
+
+private:
+ off_t mStart; // absolute file offset of start of chunk
+ off_t mLength; // length of the chunk
+ off_t mOffset; // current local offset, 0 == mStart
+ FILE* mFp; // for read/seek
+ char* mFileName; // for opening
+
+ /*
+ * To support getBuffer() we either need to read the entire thing into
+ * a buffer or memory-map it. For small files it's probably best to
+ * just read them in.
+ */
+ enum { kReadVsMapThreshold = 4096 };
+
+ FileMap* mMap; // for memory map
+ unsigned char* mBuf; // for read
+
+ const void* ensureAlignment(FileMap* map);
+};
+
+
+/*
+ * An asset based on compressed data in a file.
+ */
+class _CompressedAsset : public Asset {
+public:
+ _CompressedAsset(void);
+ virtual ~_CompressedAsset(void);
+
+ /*
+ * Use a piece of an already-open file.
+ *
+ * On success, the object takes ownership of "fd".
+ */
+ status_t openChunk(int fd, off_t offset, int compressionMethod,
+ size_t uncompressedLen, size_t compressedLen);
+
+ /*
+ * Use a memory-mapped region.
+ *
+ * On success, the object takes ownership of "fd".
+ */
+ status_t openChunk(FileMap* dataMap, int compressionMethod,
+ size_t uncompressedLen);
+
+ /*
+ * Standard Asset interfaces.
+ */
+ virtual ssize_t read(void* buf, size_t count);
+ virtual off_t seek(off_t offset, int whence);
+ virtual void close(void);
+ virtual const void* getBuffer(bool wordAligned);
+ virtual off_t getLength(void) const { return mUncompressedLen; }
+ virtual off_t getRemainingLength(void) const { return mUncompressedLen-mOffset; }
+ virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const { return -1; }
+
+private:
+ off_t mStart; // offset to start of compressed data
+ off_t mCompressedLen; // length of the compressed data
+ off_t mUncompressedLen; // length of the uncompressed data
+ off_t mOffset; // current offset, 0 == start of uncomp data
+
+ FileMap* mMap; // for memory-mapped input
+ int mFd; // for file input
+
+ unsigned char* mBuf; // for getBuffer()
+};
+
+// need: shared mmap version?
+
+}; // namespace android
+
+#endif // __LIBS_ASSET_H
diff --git a/include/utils/AssetDir.h b/include/utils/AssetDir.h
new file mode 100644
index 0000000..abf8a35
--- /dev/null
+++ b/include/utils/AssetDir.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Access a chunk of the asset hierarchy as if it were a single directory.
+//
+#ifndef __LIBS_ASSETDIR_H
+#define __LIBS_ASSETDIR_H
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <utils/misc.h>
+#include <sys/types.h>
+
+namespace android {
+
+/*
+ * This provides vector-style access to a directory. We do this rather
+ * than modeling opendir/readdir access because it's simpler and the
+ * nature of the operation requires us to have all data on hand anyway.
+ *
+ * The list of files will be sorted in ascending order by ASCII value.
+ *
+ * The contents are populated by our friend, the AssetManager.
+ */
+class AssetDir {
+public:
+ AssetDir(void)
+ : mFileInfo(NULL)
+ {}
+ virtual ~AssetDir(void) {
+ delete mFileInfo;
+ }
+
+ /*
+ * Vector-style access.
+ */
+ size_t getFileCount(void) { return mFileInfo->size(); }
+ const String8& getFileName(int idx) {
+ return mFileInfo->itemAt(idx).getFileName();
+ }
+ const String8& getSourceName(int idx) {
+ return mFileInfo->itemAt(idx).getSourceName();
+ }
+
+ /*
+ * Get the type of a file (usually regular or directory).
+ */
+ FileType getFileType(int idx) {
+ return mFileInfo->itemAt(idx).getFileType();
+ }
+
+private:
+ /* these operations are not implemented */
+ AssetDir(const AssetDir& src);
+ const AssetDir& operator=(const AssetDir& src);
+
+ friend class AssetManager;
+
+ /*
+ * This holds information about files in the asset hierarchy.
+ */
+ class FileInfo {
+ public:
+ FileInfo(void) {}
+ FileInfo(const String8& path) // useful for e.g. svect.indexOf
+ : mFileName(path), mFileType(kFileTypeUnknown)
+ {}
+ ~FileInfo(void) {}
+ FileInfo(const FileInfo& src) {
+ copyMembers(src);
+ }
+ const FileInfo& operator= (const FileInfo& src) {
+ if (this != &src)
+ copyMembers(src);
+ return *this;
+ }
+
+ void copyMembers(const FileInfo& src) {
+ mFileName = src.mFileName;
+ mFileType = src.mFileType;
+ mSourceName = src.mSourceName;
+ }
+
+ /* need this for SortedVector; must compare only on file name */
+ bool operator< (const FileInfo& rhs) const {
+ return mFileName < rhs.mFileName;
+ }
+
+ /* used by AssetManager */
+ bool operator== (const FileInfo& rhs) const {
+ return mFileName == rhs.mFileName;
+ }
+
+ void set(const String8& path, FileType type) {
+ mFileName = path;
+ mFileType = type;
+ }
+
+ const String8& getFileName(void) const { return mFileName; }
+ void setFileName(const String8& path) { mFileName = path; }
+
+ FileType getFileType(void) const { return mFileType; }
+ void setFileType(FileType type) { mFileType = type; }
+
+ const String8& getSourceName(void) const { return mSourceName; }
+ void setSourceName(const String8& path) { mSourceName = path; }
+
+ /*
+ * Handy utility for finding an entry in a sorted vector of FileInfo.
+ * Returns the index of the matching entry, or -1 if none found.
+ */
+ static int findEntry(const SortedVector<FileInfo>* pVector,
+ const String8& fileName);
+
+ private:
+ String8 mFileName; // filename only
+ FileType mFileType; // regular, directory, etc
+
+ String8 mSourceName; // currently debug-only
+ };
+
+ /* AssetManager uses this to initialize us */
+ void setFileList(SortedVector<FileInfo>* list) { mFileInfo = list; }
+
+ SortedVector<FileInfo>* mFileInfo;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ASSETDIR_H
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
new file mode 100644
index 0000000..e94c0e8
--- /dev/null
+++ b/include/utils/AssetManager.h
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Asset management class. AssetManager objects are thread-safe.
+//
+#ifndef __LIBS_ASSETMANAGER_H
+#define __LIBS_ASSETMANAGER_H
+
+#include <utils/Asset.h>
+#include <utils/AssetDir.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+#include <utils/ZipFileRO.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class Asset; // fwd decl for things that include Asset.h first
+class ResTable;
+struct ResTable_config;
+
+/*
+ * Every application that uses assets needs one instance of this. A
+ * single instance may be shared across multiple threads, and a single
+ * thread may have more than one instance (the latter is discouraged).
+ *
+ * The purpose of the AssetManager is to create Asset objects. To do
+ * this efficiently it may cache information about the locations of
+ * files it has seen. This can be controlled with the "cacheMode"
+ * argument.
+ *
+ * The asset hierarchy may be examined like a filesystem, using
+ * AssetDir objects to peruse a single directory.
+ */
+class AssetManager {
+public:
+ typedef enum CacheMode {
+ CACHE_UNKNOWN = 0,
+ CACHE_OFF, // don't try to cache file locations
+ CACHE_DEFER, // construct cache as pieces are needed
+ //CACHE_SCAN, // scan full(!) asset hierarchy at init() time
+ } CacheMode;
+
+ AssetManager(CacheMode cacheMode = CACHE_OFF);
+ virtual ~AssetManager(void);
+
+ static int32_t getGlobalCount();
+
+ /*
+ * Add a new source for assets. This can be called multiple times to
+ * look in multiple places for assets. It can be either a directory (for
+ * finding assets as raw files on the disk) or a ZIP file. This newly
+ * added asset path will be examined first when searching for assets,
+ * before any that were previously added.
+ *
+ * Returns "true" on success, "false" on failure. If 'cookie' is non-NULL,
+ * then on success, *cookie is set to the value corresponding to the
+ * newly-added asset source.
+ */
+ bool addAssetPath(const String8& path, void** cookie);
+
+ /*
+ * Convenience for adding the standard system assets. Uses the
+ * ANDROID_ROOT environment variable to find them.
+ */
+ bool addDefaultAssets();
+
+ /*
+ * Iterate over the asset paths in this manager. (Previously
+ * added via addAssetPath() and addDefaultAssets().) On first call,
+ * 'cookie' must be NULL, resulting in the first cookie being returned.
+ * Each next cookie will be returned there-after, until NULL indicating
+ * the end has been reached.
+ */
+ void* nextAssetPath(void* cookie) const;
+
+ /*
+ * Return an asset path in the manager. 'which' must be between 0 and
+ * countAssetPaths().
+ */
+ String8 getAssetPath(void* cookie) const;
+
+ /*
+ * Set the current locale and vendor. The locale can change during
+ * the lifetime of an AssetManager if the user updates the device's
+ * language setting. The vendor is less likely to change.
+ *
+ * Pass in NULL to indicate no preference.
+ */
+ void setLocale(const char* locale);
+ void setVendor(const char* vendor);
+
+ /*
+ * Choose screen orientation for resources values returned.
+ */
+ void setConfiguration(const ResTable_config& config, const char* locale = NULL);
+
+ typedef Asset::AccessMode AccessMode; // typing shortcut
+
+ /*
+ * Open an asset.
+ *
+ * This will search through locale-specific and vendor-specific
+ * directories and packages to find the file.
+ *
+ * The object returned does not depend on the AssetManager. It should
+ * be freed by calling Asset::close().
+ */
+ Asset* open(const char* fileName, AccessMode mode);
+
+ /*
+ * Open a non-asset file as an asset.
+ *
+ * This is for opening files that are included in an asset package
+ * but aren't assets. These sit outside the usual "locale/vendor"
+ * path hierarchy, and will not be seen by "AssetDir" or included
+ * in our filename cache.
+ */
+ Asset* openNonAsset(const char* fileName, AccessMode mode);
+
+ /*
+ * Explicit non-asset file. The file explicitly named by the cookie (the
+ * resource set to look in) and fileName will be opened and returned.
+ */
+ Asset* openNonAsset(void* cookie, const char* fileName, AccessMode mode);
+
+ /*
+ * Open a directory within the asset hierarchy.
+ *
+ * The contents of the directory are an amalgam of vendor-specific,
+ * locale-specific, and generic assets stored loosely or in asset
+ * packages. Depending on the cache setting and previous accesses,
+ * this call may incur significant disk overhead.
+ *
+ * To open the top-level directory, pass in "".
+ */
+ AssetDir* openDir(const char* dirName);
+
+ /*
+ * Get the type of a file in the asset hierarchy. They will either
+ * be "regular" or "directory". [Currently only works for "regular".]
+ *
+ * Can also be used as a quick test for existence of a file.
+ */
+ FileType getFileType(const char* fileName);
+
+ /*
+ * Return the complete resource table to find things in the package.
+ */
+ const ResTable& getResources(bool required = true) const;
+
+ /*
+ * Discard cached filename information. This only needs to be called
+ * if somebody has updated the set of "loose" files, and we want to
+ * discard our cached notion of what's where.
+ */
+ void purge(void) { purgeFileNameCacheLocked(); }
+
+ /*
+ * Return true if the files this AssetManager references are all
+ * up-to-date (have not been changed since it was created). If false
+ * is returned, you will need to create a new AssetManager to get
+ * the current data.
+ */
+ bool isUpToDate();
+
+ /**
+ * Get the known locales for this asset manager object.
+ */
+ void getLocales(Vector<String8>* locales) const;
+
+private:
+ struct asset_path
+ {
+ String8 path;
+ FileType type;
+ };
+
+ Asset* openInPathLocked(const char* fileName, AccessMode mode,
+ const asset_path& path);
+ Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
+ const asset_path& path);
+ Asset* openInLocaleVendorLocked(const char* fileName, AccessMode mode,
+ const asset_path& path, const char* locale, const char* vendor);
+ String8 createPathNameLocked(const asset_path& path, const char* locale,
+ const char* vendor);
+ String8 createPathNameLocked(const asset_path& path, const char* rootDir);
+ String8 createZipSourceNameLocked(const String8& zipFileName,
+ const String8& dirName, const String8& fileName);
+
+ ZipFileRO* getZipFileLocked(const asset_path& path);
+ Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode);
+ Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile,
+ const ZipEntryRO entry, AccessMode mode, const String8& entryName);
+
+ bool scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+ const asset_path& path, const char* rootDir, const char* dirName);
+ SortedVector<AssetDir::FileInfo>* scanDirLocked(const String8& path);
+ bool scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+ const asset_path& path, const char* rootDir, const char* dirName);
+ void mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+ const SortedVector<AssetDir::FileInfo>* pContents);
+
+ void loadFileNameCacheLocked(void);
+ void fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+ const char* dirName);
+ bool fncScanAndMergeDirLocked(
+ SortedVector<AssetDir::FileInfo>* pMergedInfo,
+ const asset_path& path, const char* locale, const char* vendor,
+ const char* dirName);
+ void purgeFileNameCacheLocked(void);
+
+ const ResTable* getResTable(bool required = true) const;
+ void setLocaleLocked(const char* locale);
+ void updateResourceParamsLocked() const;
+
+ class SharedZip : public RefBase {
+ public:
+ static sp<SharedZip> get(const String8& path);
+
+ ZipFileRO* getZip();
+
+ Asset* getResourceTableAsset();
+ Asset* setResourceTableAsset(Asset* asset);
+
+ bool isUpToDate();
+
+ protected:
+ ~SharedZip();
+
+ private:
+ SharedZip(const String8& path, time_t modWhen);
+ SharedZip(); // <-- not implemented
+
+ String8 mPath;
+ ZipFileRO* mZipFile;
+ time_t mModWhen;
+
+ Asset* mResourceTableAsset;
+
+ static Mutex gLock;
+ static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
+ };
+
+ /*
+ * Manage a set of Zip files. For each file we need a pointer to the
+ * ZipFile and a time_t with the file's modification date.
+ *
+ * We currently only have two zip files (current app, "common" app).
+ * (This was originally written for 8, based on app/locale/vendor.)
+ */
+ class ZipSet {
+ public:
+ ZipSet(void);
+ ~ZipSet(void);
+
+ /*
+ * Return a ZipFileRO structure for a ZipFileRO with the specified
+ * parameters.
+ */
+ ZipFileRO* getZip(const String8& path);
+
+ Asset* getZipResourceTable(const String8& path);
+ Asset* setZipResourceTable(const String8& path, Asset* asset);
+
+ // generate path, e.g. "common/en-US-noogle.zip"
+ static String8 getPathName(const char* path);
+
+ bool isUpToDate();
+
+ private:
+ void closeZip(int idx);
+
+ int getIndex(const String8& zip) const;
+ mutable Vector<String8> mZipPath;
+ mutable Vector<sp<SharedZip> > mZipFile;
+ };
+
+ // Protect all internal state.
+ mutable Mutex mLock;
+
+ ZipSet mZipSet;
+
+ Vector<asset_path> mAssetPaths;
+ char* mLocale;
+ char* mVendor;
+
+ mutable ResTable* mResources;
+ ResTable_config* mConfig;
+
+ /*
+ * Cached data for "loose" files. This lets us avoid poking at the
+ * filesystem when searching for loose assets. Each entry is the
+ * "extended partial" path, e.g. "default/default/foo/bar.txt". The
+ * full set of files is present, including ".EXCLUDE" entries.
+ *
+ * We do not cache directory names. We don't retain the ".gz",
+ * because to our clients "foo" and "foo.gz" both look like "foo".
+ */
+ CacheMode mCacheMode; // is the cache enabled?
+ bool mCacheValid; // clear when locale or vendor changes
+ SortedVector<AssetDir::FileInfo> mCache;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ASSETMANAGER_H
diff --git a/include/utils/Atomic.h b/include/utils/Atomic.h
new file mode 100644
index 0000000..7eb476c
--- /dev/null
+++ b/include/utils/Atomic.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2005 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_UTILS_ATOMIC_H
+#define ANDROID_UTILS_ATOMIC_H
+
+#include <cutils/atomic.h>
+
+#endif // ANDROID_UTILS_ATOMIC_H
diff --git a/include/utils/Binder.h b/include/utils/Binder.h
new file mode 100644
index 0000000..b5b8d98
--- /dev/null
+++ b/include/utils/Binder.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BINDER_H
+#define ANDROID_BINDER_H
+
+#include <utils/IBinder.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BBinder : public IBinder
+{
+public:
+ BBinder();
+
+ virtual String16 getInterfaceDescriptor() const;
+ virtual bool isBinderAlive() const;
+ virtual status_t pingBinder();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ virtual status_t transact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+ virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0);
+
+ virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0,
+ wp<DeathRecipient>* outRecipient = NULL);
+
+ virtual void attachObject( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ object_cleanup_func func);
+ virtual void* findObject(const void* objectID) const;
+ virtual void detachObject(const void* objectID);
+
+ virtual BBinder* localBinder();
+
+protected:
+ virtual ~BBinder();
+
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+private:
+ BBinder(const BBinder& o);
+ BBinder& operator=(const BBinder& o);
+
+ class Extras;
+
+ Extras* mExtras;
+ void* mReserved0;
+};
+
+// ---------------------------------------------------------------------------
+
+class BpRefBase : public virtual RefBase
+{
+protected:
+ BpRefBase(const sp<IBinder>& o);
+ virtual ~BpRefBase();
+ virtual void onFirstRef();
+ virtual void onLastStrongRef(const void* id);
+ virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
+
+ inline IBinder* remote() { return mRemote; }
+ inline IBinder* remote() const { return mRemote; }
+
+private:
+ BpRefBase(const BpRefBase& o);
+ BpRefBase& operator=(const BpRefBase& o);
+
+ IBinder* const mRemote;
+ RefBase::weakref_type* mRefs;
+ volatile int32_t mState;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BINDER_H
diff --git a/include/utils/BpBinder.h b/include/utils/BpBinder.h
new file mode 100644
index 0000000..7b96e29
--- /dev/null
+++ b/include/utils/BpBinder.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2005 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_BPBINDER_H
+#define ANDROID_BPBINDER_H
+
+#include <utils/IBinder.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BpBinder : public IBinder
+{
+public:
+ BpBinder(int32_t handle);
+
+ inline int32_t handle() const { return mHandle; }
+
+ virtual String16 getInterfaceDescriptor() const;
+ virtual bool isBinderAlive() const;
+ virtual status_t pingBinder();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ virtual status_t transact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+ virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0);
+ virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0,
+ wp<DeathRecipient>* outRecipient = NULL);
+
+ virtual void attachObject( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ object_cleanup_func func);
+ virtual void* findObject(const void* objectID) const;
+ virtual void detachObject(const void* objectID);
+
+ virtual BpBinder* remoteBinder();
+
+ status_t setConstantData(const void* data, size_t size);
+ void sendObituary();
+
+ class ObjectManager
+ {
+ public:
+ ObjectManager();
+ ~ObjectManager();
+
+ void attach( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ IBinder::object_cleanup_func func);
+ void* find(const void* objectID) const;
+ void detach(const void* objectID);
+
+ void kill();
+
+ private:
+ ObjectManager(const ObjectManager&);
+ ObjectManager& operator=(const ObjectManager&);
+
+ struct entry_t
+ {
+ void* object;
+ void* cleanupCookie;
+ IBinder::object_cleanup_func func;
+ };
+
+ KeyedVector<const void*, entry_t> mObjects;
+ };
+
+protected:
+ virtual ~BpBinder();
+ virtual void onFirstRef();
+ virtual void onLastStrongRef(const void* id);
+ virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
+
+private:
+ const int32_t mHandle;
+
+ struct Obituary {
+ wp<DeathRecipient> recipient;
+ void* cookie;
+ uint32_t flags;
+ };
+
+ void reportOneDeath(const Obituary& obit);
+
+ mutable Mutex mLock;
+ volatile int32_t mAlive;
+ volatile int32_t mObitsSent;
+ Vector<Obituary>* mObituaries;
+ ObjectManager mObjects;
+ Parcel* mConstantData;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BPBINDER_H
diff --git a/include/utils/Buffer.h b/include/utils/Buffer.h
new file mode 100644
index 0000000..8e22b0f
--- /dev/null
+++ b/include/utils/Buffer.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#ifndef __UTILS_BUFFER_H__
+#define __UTILS_BUFFER_H__ 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace android {
+
+class Buffer
+{
+private:
+ char *buf;
+ int bufsiz;
+ int used;
+ void ensureCapacity(int len);
+
+ void
+ makeRoomFor(int len)
+ {
+ if (len + used >= bufsiz) {
+ bufsiz = (len + used) * 3/2 + 2;
+ char *blah = new char[bufsiz];
+
+ memcpy(blah, buf, used);
+ delete[] buf;
+ buf = blah;
+ }
+ }
+
+public:
+ Buffer()
+ {
+ bufsiz = 16;
+ buf = new char[bufsiz];
+ clear();
+ }
+
+ ~Buffer()
+ {
+ delete[] buf;
+ }
+
+ void
+ clear()
+ {
+ buf[0] = '\0';
+ used = 0;
+ }
+
+ int
+ length()
+ {
+ return used;
+ }
+
+ void
+ append(const char c)
+ {
+ makeRoomFor(1);
+ buf[used] = c;
+ used++;
+ buf[used] = '\0';
+ }
+
+ void
+ append(const char *s, int len)
+ {
+ makeRoomFor(len);
+
+ memcpy(buf + used, s, len);
+ used += len;
+ buf[used] = '\0';
+ }
+
+ void
+ append(const char *s)
+ {
+ append(s, strlen(s));
+ }
+
+ char *
+ getBytes()
+ {
+ return buf;
+ }
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/utils/BufferedTextOutput.h b/include/utils/BufferedTextOutput.h
new file mode 100644
index 0000000..69c6240
--- /dev/null
+++ b/include/utils/BufferedTextOutput.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2006 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_BUFFEREDTEXTOUTPUT_H
+#define ANDROID_BUFFEREDTEXTOUTPUT_H
+
+#include <utils/TextOutput.h>
+#include <utils/threads.h>
+#include <cutils/uio.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BufferedTextOutput : public TextOutput
+{
+public:
+ //** Flags for constructor */
+ enum {
+ MULTITHREADED = 0x0001
+ };
+
+ BufferedTextOutput(uint32_t flags = 0);
+ virtual ~BufferedTextOutput();
+
+ virtual status_t print(const char* txt, size_t len);
+ virtual void moveIndent(int delta);
+
+ virtual void pushBundle();
+ virtual void popBundle();
+
+protected:
+ virtual status_t writeLines(const struct iovec& vec, size_t N) = 0;
+
+private:
+ struct BufferState;
+ struct ThreadState;
+
+ static ThreadState*getThreadState();
+ static void threadDestructor(void *st);
+
+ BufferState*getBuffer() const;
+
+ uint32_t mFlags;
+ const int32_t mSeq;
+ const int32_t mIndex;
+
+ Mutex mLock;
+ BufferState* mGlobalState;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_BUFFEREDTEXTOUTPUT_H
diff --git a/include/utils/ByteOrder.h b/include/utils/ByteOrder.h
new file mode 100644
index 0000000..4c06067
--- /dev/null
+++ b/include/utils/ByteOrder.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2006 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 _LIBS_UTILS_BYTE_ORDER_H
+#define _LIBS_UTILS_BYTE_ORDER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#ifdef HAVE_WINSOCK
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#endif
+
+/*
+ * These macros are like the hton/ntoh byte swapping macros,
+ * except they allow you to swap to and from the "device" byte
+ * order. The device byte order is the endianness of the target
+ * device -- for the ARM CPUs we use today, this is little endian.
+ *
+ * Note that the byte swapping functions have not been optimized
+ * much; performance is currently not an issue for them since the
+ * intent is to allow us to avoid byte swapping on the device.
+ */
+
+#define DEVICE_BYTE_ORDER LITTLE_ENDIAN
+
+#if BYTE_ORDER == DEVICE_BYTE_ORDER
+
+#define dtohl(x) (x)
+#define dtohs(x) (x)
+#define htodl(x) (x)
+#define htods(x) (x)
+
+#else
+
+static inline uint32_t android_swap_long(uint32_t v)
+{
+ return (v<<24) | ((v<<8)&0x00FF0000) | ((v>>8)&0x0000FF00) | (v>>24);
+}
+
+static inline uint16_t android_swap_short(uint16_t v)
+{
+ return (v<<8) | (v>>8);
+}
+
+#define dtohl(x) (android_swap_long(x))
+#define dtohs(x) (android_swap_short(x))
+#define htodl(x) (android_swap_long(x))
+#define htods(x) (android_swap_short(x))
+
+#endif
+
+#endif // _LIBS_UTILS_BYTE_ORDER_H
diff --git a/include/utils/CallStack.h b/include/utils/CallStack.h
new file mode 100644
index 0000000..c2c8ce5
--- /dev/null
+++ b/include/utils/CallStack.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_CALLSTACK_H
+#define ANDROID_CALLSTACK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/String8.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class CallStack
+{
+public:
+ enum {
+ MAX_DEPTH = 31
+ };
+
+ CallStack();
+ CallStack(const CallStack& rhs);
+ ~CallStack();
+
+ CallStack& operator = (const CallStack& rhs);
+
+ bool operator == (const CallStack& rhs) const;
+ bool operator != (const CallStack& rhs) const;
+ bool operator < (const CallStack& rhs) const;
+ bool operator >= (const CallStack& rhs) const;
+ bool operator > (const CallStack& rhs) const;
+ bool operator <= (const CallStack& rhs) const;
+
+ const void* operator [] (int index) const;
+
+ void clear();
+
+ void update(int32_t ignoreDepth=0, int32_t maxDepth=MAX_DEPTH);
+
+ // Dump a stack trace to the log
+ void dump(const char* prefix = 0) const;
+
+ // Return a string (possibly very long) containing the complete stack trace
+ String8 toString(const char* prefix = 0) const;
+
+ size_t size() const { return mCount; }
+
+private:
+ // Internal helper function
+ String8 toStringSingleLevel(const char* prefix, int32_t level) const;
+
+ size_t mCount;
+ const void* mStack[MAX_DEPTH];
+};
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_CALLSTACK_H
diff --git a/include/utils/Debug.h b/include/utils/Debug.h
new file mode 100644
index 0000000..a662b9c
--- /dev/null
+++ b/include/utils/Debug.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Debugging tools. These should be able to be stripped
+// in release builds.
+//
+#ifndef ANDROID_DEBUG_H
+#define ANDROID_DEBUG_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+
+template<bool> struct CompileTimeAssert;
+template<> struct CompileTimeAssert<true> {};
+
+const char* stringForIndent(int32_t indentLevel);
+
+typedef void (*debugPrintFunc)(void* cookie, const char* txt);
+
+void printTypeCode(uint32_t typeCode,
+ debugPrintFunc func = 0, void* cookie = 0);
+void printHexData(int32_t indent, const void *buf, size_t length,
+ size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16,
+ size_t alignment=0, bool cArrayStyle=false,
+ debugPrintFunc func = 0, void* cookie = 0);
+
+}; // namespace android
+
+#endif // ANDROID_DEBUG_H
diff --git a/include/utils/Endian.h b/include/utils/Endian.h
new file mode 100644
index 0000000..19f2504
--- /dev/null
+++ b/include/utils/Endian.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Android endian-ness defines.
+//
+#ifndef _LIBS_UTILS_ENDIAN_H
+#define _LIBS_UTILS_ENDIAN_H
+
+#if defined(HAVE_ENDIAN_H)
+
+#include <endian.h>
+
+#else /*not HAVE_ENDIAN_H*/
+
+#define __BIG_ENDIAN 0x1000
+#define __LITTLE_ENDIAN 0x0001
+
+#if defined(HAVE_LITTLE_ENDIAN)
+# define __BYTE_ORDER __LITTLE_ENDIAN
+#else
+# define __BYTE_ORDER __BIG_ENDIAN
+#endif
+
+#endif /*not HAVE_ENDIAN_H*/
+
+#endif /*_LIBS_UTILS_ENDIAN_H*/
diff --git a/include/utils/Errors.h b/include/utils/Errors.h
new file mode 100644
index 0000000..1bf9e6f
--- /dev/null
+++ b/include/utils/Errors.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_ERRORS_H
+#define ANDROID_ERRORS_H
+
+#include <sys/types.h>
+#include <errno.h>
+
+namespace android {
+
+// use this type to return error codes
+#ifdef HAVE_MS_C_RUNTIME
+typedef int status_t;
+#else
+typedef int32_t status_t;
+#endif
+
+/* the MS C runtime lacks a few error codes */
+
+/*
+ * Error codes.
+ * All error codes are negative values.
+ */
+
+// Win32 #defines NO_ERROR as well. It has the same value, so there's no
+// real conflict, though it's a bit awkward.
+#ifdef _WIN32
+# undef NO_ERROR
+#endif
+
+enum {
+ OK = 0, // Everything's swell.
+ NO_ERROR = 0, // No errors.
+
+ UNKNOWN_ERROR = 0x80000000,
+
+ NO_MEMORY = -ENOMEM,
+ INVALID_OPERATION = -ENOSYS,
+ BAD_VALUE = -EINVAL,
+ BAD_TYPE = 0x80000001,
+ NAME_NOT_FOUND = -ENOENT,
+ PERMISSION_DENIED = -EPERM,
+ NO_INIT = -ENODEV,
+ ALREADY_EXISTS = -EEXIST,
+ DEAD_OBJECT = -EPIPE,
+ FAILED_TRANSACTION = 0x80000002,
+ JPARKS_BROKE_IT = -EPIPE,
+#if !defined(HAVE_MS_C_RUNTIME)
+ BAD_INDEX = -EOVERFLOW,
+ NOT_ENOUGH_DATA = -ENODATA,
+ WOULD_BLOCK = -EWOULDBLOCK,
+ TIMED_OUT = -ETIME,
+ UNKNOWN_TRANSACTION = -EBADMSG,
+#else
+ BAD_INDEX = -E2BIG,
+ NOT_ENOUGH_DATA = 0x80000003,
+ WOULD_BLOCK = 0x80000004,
+ TIMED_OUT = 0x80000005,
+ UNKNOWN_TRANSACTION = 0x80000006,
+#endif
+};
+
+// Restore define; enumeration is in "android" namespace, so the value defined
+// there won't work for Win32 code in a different namespace.
+#ifdef _WIN32
+# define NO_ERROR 0L
+#endif
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_ERRORS_H
diff --git a/include/utils/FileMap.h b/include/utils/FileMap.h
new file mode 100644
index 0000000..8dfd3be
--- /dev/null
+++ b/include/utils/FileMap.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Encapsulate a shared file mapping.
+//
+#ifndef __LIBS_FILE_MAP_H
+#define __LIBS_FILE_MAP_H
+
+#include <sys/types.h>
+
+#ifdef HAVE_WIN32_FILEMAP
+#include <windows.h>
+#endif
+
+namespace android {
+
+/*
+ * This represents a memory-mapped file. It might be the entire file or
+ * only part of it. This requires a little bookkeeping because the mapping
+ * needs to be aligned on page boundaries, and in some cases we'd like to
+ * have multiple references to the mapped area without creating additional
+ * maps.
+ *
+ * This always uses MAP_SHARED.
+ *
+ * TODO: we should be able to create a new FileMap that is a subset of
+ * an existing FileMap and shares the underlying mapped pages. Requires
+ * completing the refcounting stuff and possibly introducing the notion
+ * of a FileMap hierarchy.
+ */
+class FileMap {
+public:
+ FileMap(void);
+
+ /*
+ * Create a new mapping on an open file.
+ *
+ * Closing the file descriptor does not unmap the pages, so we don't
+ * claim ownership of the fd.
+ *
+ * Returns "false" on failure.
+ */
+ bool create(const char* origFileName, int fd,
+ off_t offset, size_t length, bool readOnly);
+
+ /*
+ * Return the name of the file this map came from, if known.
+ */
+ const char* getFileName(void) const { return mFileName; }
+
+ /*
+ * Get a pointer to the piece of the file we requested.
+ */
+ void* getDataPtr(void) const { return mDataPtr; }
+
+ /*
+ * Get the length we requested.
+ */
+ size_t getDataLength(void) const { return mDataLength; }
+
+ /*
+ * Get the data offset used to create this map.
+ */
+ off_t getDataOffset(void) const { return mDataOffset; }
+
+ /*
+ * Get a "copy" of the object.
+ */
+ FileMap* acquire(void) { mRefCount++; return this; }
+
+ /*
+ * Call this when mapping is no longer needed.
+ */
+ void release(void) {
+ if (--mRefCount <= 0)
+ delete this;
+ }
+
+ /*
+ * This maps directly to madvise() values, but allows us to avoid
+ * including <sys/mman.h> everywhere.
+ */
+ enum MapAdvice {
+ NORMAL, RANDOM, SEQUENTIAL, WILLNEED, DONTNEED
+ };
+
+ /*
+ * Apply an madvise() call to the entire file.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+ int advise(MapAdvice advice);
+
+protected:
+ // don't delete objects; call release()
+ ~FileMap(void);
+
+private:
+ // these are not implemented
+ FileMap(const FileMap& src);
+ const FileMap& operator=(const FileMap& src);
+
+ int mRefCount; // reference count
+ char* mFileName; // original file name, if known
+ void* mBasePtr; // base of mmap area; page aligned
+ size_t mBaseLength; // length, measured from "mBasePtr"
+ off_t mDataOffset; // offset used when map was created
+ void* mDataPtr; // start of requested data, offset from base
+ size_t mDataLength; // length, measured from "mDataPtr"
+#ifdef HAVE_WIN32_FILEMAP
+ HANDLE mFileHandle; // Win32 file handle
+ HANDLE mFileMapping; // Win32 file mapping handle
+#endif
+
+ static long mPageSize;
+};
+
+}; // namespace android
+
+#endif // __LIBS_FILE_MAP_H
diff --git a/include/utils/IBinder.h b/include/utils/IBinder.h
new file mode 100644
index 0000000..7370330
--- /dev/null
+++ b/include/utils/IBinder.h
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IBINDER_H
+#define ANDROID_IBINDER_H
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+
+#define B_PACK_CHARS(c1, c2, c3, c4) \
+ ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BBinder;
+class BpBinder;
+class IInterface;
+class Parcel;
+
+/**
+ * Base class and low-level protocol for a remotable object.
+ * You can derive from this class to create an object for which other
+ * processes can hold references to it. Communication between processes
+ * (method calls, property get and set) is down through a low-level
+ * protocol implemented on top of the transact() API.
+ */
+class IBinder : public virtual RefBase
+{
+public:
+ enum {
+ FIRST_CALL_TRANSACTION = 0x00000001,
+ LAST_CALL_TRANSACTION = 0x00ffffff,
+
+ PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'),
+ DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'),
+ INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
+
+ // Corresponds to tfOneWay -- an asynchronous call.
+ FLAG_ONEWAY = 0x00000001
+ };
+
+ inline IBinder() { }
+
+ /**
+ * Check if this IBinder implements the interface named by
+ * @a descriptor. If it does, the base pointer to it is returned,
+ * which you can safely static_cast<> to the concrete C++ interface.
+ */
+ virtual sp<IInterface> queryLocalInterface(const String16& descriptor);
+
+ /**
+ * Return the canonical name of the interface provided by this IBinder
+ * object.
+ */
+ virtual String16 getInterfaceDescriptor() const = 0;
+
+ virtual bool isBinderAlive() const = 0;
+ virtual status_t pingBinder() = 0;
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+ virtual status_t transact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0) = 0;
+
+ /**
+ * This method allows you to add data that is transported through
+ * IPC along with your IBinder pointer. When implementing a Binder
+ * object, override it to write your desired data in to @a outData.
+ * You can then call getConstantData() on your IBinder to retrieve
+ * that data, from any process. You MUST return the number of bytes
+ * written in to the parcel (including padding).
+ */
+ class DeathRecipient : public virtual RefBase
+ {
+ public:
+ virtual void binderDied(const wp<IBinder>& who) = 0;
+ };
+
+ /**
+ * Register the @a recipient for a notification if this binder
+ * goes away. If this binder object unexpectedly goes away
+ * (typically because its hosting process has been killed),
+ * then DeathRecipient::binderDied() will be called with a referene
+ * to this.
+ *
+ * The @a cookie is optional -- if non-NULL, it should be a
+ * memory address that you own (that is, you know it is unique).
+ *
+ * @note You will only receive death notifications for remote binders,
+ * as local binders by definition can't die without you dying as well.
+ * Trying to use this function on a local binder will result in an
+ * INVALID_OPERATION code being returned and nothing happening.
+ *
+ * @note This link always holds a weak reference to its recipient.
+ *
+ * @note You will only receive a weak reference to the dead
+ * binder. You should not try to promote this to a strong reference.
+ * (Nor should you need to, as there is nothing useful you can
+ * directly do with it now that it has passed on.)
+ */
+ virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0) = 0;
+
+ /**
+ * Remove a previously registered death notification.
+ * The @a recipient will no longer be called if this object
+ * dies. The @a cookie is optional. If non-NULL, you can
+ * supply a NULL @a recipient, and the recipient previously
+ * added with that cookie will be unlinked.
+ */
+ virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0,
+ wp<DeathRecipient>* outRecipient = NULL) = 0;
+
+ virtual bool checkSubclass(const void* subclassID) const;
+
+ typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
+
+ virtual void attachObject( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ object_cleanup_func func) = 0;
+ virtual void* findObject(const void* objectID) const = 0;
+ virtual void detachObject(const void* objectID) = 0;
+
+ virtual BBinder* localBinder();
+ virtual BpBinder* remoteBinder();
+
+protected:
+ inline virtual ~IBinder() { }
+
+private:
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IBINDER_H
diff --git a/include/utils/IInterface.h b/include/utils/IInterface.h
new file mode 100644
index 0000000..959722a
--- /dev/null
+++ b/include/utils/IInterface.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2005 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_IINTERFACE_H
+#define ANDROID_IINTERFACE_H
+
+#include <utils/Binder.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IInterface : public virtual RefBase
+{
+public:
+ sp<IBinder> asBinder();
+ sp<const IBinder> asBinder() const;
+
+protected:
+ virtual IBinder* onAsBinder() = 0;
+};
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
+{
+ return INTERFACE::asInterface(obj);
+}
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+class BnInterface : public INTERFACE, public BBinder
+{
+public:
+ virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
+ virtual String16 getInterfaceDescriptor() const;
+
+protected:
+ virtual IBinder* onAsBinder();
+};
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+class BpInterface : public INTERFACE, public BpRefBase
+{
+public:
+ BpInterface(const sp<IBinder>& remote);
+
+protected:
+ virtual IBinder* onAsBinder();
+};
+
+// ----------------------------------------------------------------------
+
+#define DECLARE_META_INTERFACE(INTERFACE) \
+ static const String16 descriptor; \
+ static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj); \
+ virtual String16 getInterfaceDescriptor() const; \
+
+#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
+ const String16 I##INTERFACE::descriptor(NAME); \
+ String16 I##INTERFACE::getInterfaceDescriptor() const { \
+ return I##INTERFACE::descriptor; \
+ } \
+ sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj) \
+ { \
+ sp<I##INTERFACE> intr; \
+ if (obj != NULL) { \
+ intr = static_cast<I##INTERFACE*>( \
+ obj->queryLocalInterface( \
+ I##INTERFACE::descriptor).get()); \
+ if (intr == NULL) { \
+ intr = new Bp##INTERFACE(obj); \
+ } \
+ } \
+ return intr; \
+ } \
+
+// ----------------------------------------------------------------------
+// No user-servicable parts after this...
+
+template<typename INTERFACE>
+inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
+ const String16& _descriptor)
+{
+ if (_descriptor == INTERFACE::descriptor) return this;
+ return NULL;
+}
+
+template<typename INTERFACE>
+inline String16 BnInterface<INTERFACE>::getInterfaceDescriptor() const
+{
+ return INTERFACE::getInterfaceDescriptor();
+}
+
+template<typename INTERFACE>
+IBinder* BnInterface<INTERFACE>::onAsBinder()
+{
+ return this;
+}
+
+template<typename INTERFACE>
+inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
+ : BpRefBase(remote)
+{
+}
+
+template<typename INTERFACE>
+inline IBinder* BpInterface<INTERFACE>::onAsBinder()
+{
+ return remote();
+}
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IINTERFACE_H
diff --git a/include/utils/IMemory.h b/include/utils/IMemory.h
new file mode 100644
index 0000000..35a3fd7
--- /dev/null
+++ b/include/utils/IMemory.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_IMEMORY_H
+#define ANDROID_IMEMORY_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IMemoryHeap : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MemoryHeap);
+
+ // flags returned by getFlags()
+ enum {
+ READ_ONLY = 0x00000001,
+ MAP_ONCE = 0x00000002
+ };
+
+ virtual int getHeapID() const = 0;
+ virtual void* getBase() const = 0;
+ virtual size_t getSize() const = 0;
+ virtual uint32_t getFlags() const = 0;
+
+ // these are there just for backward source compatibility
+ int32_t heapID() const { return getHeapID(); }
+ void* base() const { return getBase(); }
+ size_t virtualSize() const { return getSize(); }
+};
+
+class BnMemoryHeap : public BnInterface<IMemoryHeap>
+{
+public:
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+class IMemory : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(Memory);
+
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
+
+ // helpers
+ void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
+ void* pointer() const;
+ size_t size() const;
+ ssize_t offset() const;
+};
+
+class BnMemory : public BnInterface<IMemory>
+{
+public:
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IMEMORY_H
diff --git a/include/utils/IPCThreadState.h b/include/utils/IPCThreadState.h
new file mode 100644
index 0000000..47043b8
--- /dev/null
+++ b/include/utils/IPCThreadState.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2005 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_IPC_THREAD_STATE_H
+#define ANDROID_IPC_THREAD_STATE_H
+
+#include <utils/Errors.h>
+#include <utils/Parcel.h>
+#include <utils/ProcessState.h>
+
+#ifdef HAVE_WIN32_PROC
+typedef int uid_t;
+#endif
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IPCThreadState
+{
+public:
+ static IPCThreadState* self();
+
+ sp<ProcessState> process();
+
+ status_t clearLastError();
+
+ int getCallingPid();
+ int getCallingUid();
+
+ int64_t clearCallingIdentity();
+ void restoreCallingIdentity(int64_t token);
+
+ void flushCommands();
+
+ void joinThreadPool(bool isMain = true);
+
+ // Stop the local process.
+ void stopProcess(bool immediate = true);
+
+ status_t transact(int32_t handle,
+ uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+
+ void incStrongHandle(int32_t handle);
+ void decStrongHandle(int32_t handle);
+ void incWeakHandle(int32_t handle);
+ void decWeakHandle(int32_t handle);
+ status_t attemptIncStrongHandle(int32_t handle);
+ static void expungeHandle(int32_t handle, IBinder* binder);
+ status_t requestDeathNotification( int32_t handle,
+ BpBinder* proxy);
+ status_t clearDeathNotification( int32_t handle,
+ BpBinder* proxy);
+
+ static void shutdown();
+
+private:
+ IPCThreadState();
+ ~IPCThreadState();
+
+ status_t sendReply(const Parcel& reply, uint32_t flags);
+ status_t waitForResponse(Parcel *reply,
+ status_t *acquireResult=NULL);
+ status_t talkWithDriver(bool doReceive=true);
+ status_t writeTransactionData(int32_t cmd,
+ uint32_t binderFlags,
+ int32_t handle,
+ uint32_t code,
+ const Parcel& data,
+ status_t* statusBuffer);
+ status_t executeCommand(int32_t command);
+
+ void clearCaller();
+
+ static void threadDestructor(void *st);
+ static void freeBuffer(Parcel* parcel,
+ const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsSize,
+ void* cookie);
+
+ const sp<ProcessState> mProcess;
+
+ Parcel mIn;
+ Parcel mOut;
+ status_t mLastError;
+ pid_t mCallingPid;
+ uid_t mCallingUid;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IPC_THREAD_STATE_H
diff --git a/include/utils/IPermissionController.h b/include/utils/IPermissionController.h
new file mode 100644
index 0000000..cb1dd34
--- /dev/null
+++ b/include/utils/IPermissionController.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2005 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_IPERMISSION_CONTROLLER_H
+#define ANDROID_IPERMISSION_CONTROLLER_H
+
+#include <utils/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IPermissionController : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(PermissionController);
+
+ virtual bool checkPermission(const String16& permission,
+ int32_t pid, int32_t uid) = 0;
+
+ enum {
+ CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+ };
+};
+
+// ----------------------------------------------------------------------
+
+class BnPermissionController : public BnInterface<IPermissionController>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IPERMISSION_CONTROLLER_H
+
diff --git a/include/utils/IServiceManager.h b/include/utils/IServiceManager.h
new file mode 100644
index 0000000..e3d99fe
--- /dev/null
+++ b/include/utils/IServiceManager.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2005 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_ISERVICE_MANAGER_H
+#define ANDROID_ISERVICE_MANAGER_H
+
+#include <utils/IInterface.h>
+#include <utils/IPermissionController.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IServiceManager : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(ServiceManager);
+
+ /**
+ * Retrieve an existing service, blocking for a few seconds
+ * if it doesn't yet exist.
+ */
+ virtual sp<IBinder> getService( const String16& name) const = 0;
+
+ /**
+ * Retrieve an existing service, non-blocking.
+ */
+ virtual sp<IBinder> checkService( const String16& name) const = 0;
+
+ /**
+ * Register a service.
+ */
+ virtual status_t addService( const String16& name,
+ const sp<IBinder>& service) = 0;
+
+ /**
+ * Return list of all existing services.
+ */
+ virtual Vector<String16> listServices() = 0;
+
+ enum {
+ GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ CHECK_SERVICE_TRANSACTION,
+ ADD_SERVICE_TRANSACTION,
+ LIST_SERVICES_TRANSACTION,
+ };
+};
+
+sp<IServiceManager> defaultServiceManager();
+
+template<typename INTERFACE>
+status_t getService(const String16& name, sp<INTERFACE>* outService)
+{
+ const sp<IServiceManager> sm = defaultServiceManager();
+ if (sm != NULL) {
+ *outService = interface_cast<INTERFACE>(sm->getService(name));
+ if ((*outService) != NULL) return NO_ERROR;
+ }
+ return NAME_NOT_FOUND;
+}
+
+bool checkCallingPermission(const String16& permission);
+bool checkCallingPermission(const String16& permission,
+ int32_t* outPid, int32_t* outUid);
+
+// ----------------------------------------------------------------------
+
+class BnServiceManager : public BnInterface<IServiceManager>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISERVICE_MANAGER_H
+
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
new file mode 100644
index 0000000..f4513ee
--- /dev/null
+++ b/include/utils/KeyedVector.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2005 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_KEYED_VECTOR_H
+#define ANDROID_KEYED_VECTOR_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/SortedVector.h>
+#include <utils/TypeHelpers.h>
+#include <utils/Errors.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+template <typename KEY, typename VALUE>
+class KeyedVector
+{
+public:
+ typedef KEY key_type;
+ typedef VALUE value_type;
+
+ inline KeyedVector();
+
+ /*
+ * empty the vector
+ */
+
+ inline void clear() { mVector.clear(); }
+
+ /*!
+ * vector stats
+ */
+
+ //! returns number of items in the vector
+ inline size_t size() const { return mVector.size(); }
+ //! returns wether or not the vector is empty
+ inline bool isEmpty() const { return mVector.isEmpty(); }
+ //! returns how many items can be stored without reallocating the backing store
+ inline size_t capacity() const { return mVector.capacity(); }
+ //! setst the capacity. capacity can never be reduced less than size()
+ inline ssize_t setCapacity(size_t size) { return mVector.setCapacity(size); }
+
+ /*!
+ * accessors
+ */
+ const VALUE& valueFor(const KEY& key) const;
+ const VALUE& valueAt(size_t index) const;
+ const KEY& keyAt(size_t index) const;
+ ssize_t indexOfKey(const KEY& key) const;
+
+ /*!
+ * modifing the array
+ */
+
+ VALUE& editValueFor(const KEY& key);
+ VALUE& editValueAt(size_t index);
+
+ /*!
+ * add/insert/replace items
+ */
+
+ ssize_t add(const KEY& key, const VALUE& item);
+ ssize_t replaceValueFor(const KEY& key, const VALUE& item);
+ ssize_t replaceValueAt(size_t index, const VALUE& item);
+
+ /*!
+ * remove items
+ */
+
+ ssize_t removeItem(const KEY& key);
+ ssize_t removeItemsAt(size_t index, size_t count = 1);
+
+private:
+ SortedVector< key_value_pair_t<KEY, VALUE> > mVector;
+};
+
+// ---------------------------------------------------------------------------
+
+/**
+ * Variation of KeyedVector that holds a default value to return when
+ * valueFor() is called with a key that doesn't exist.
+ */
+template <typename KEY, typename VALUE>
+class DefaultKeyedVector : public KeyedVector<KEY, VALUE>
+{
+public:
+ inline DefaultKeyedVector(const VALUE& defValue = VALUE());
+ const VALUE& valueFor(const KEY& key) const;
+
+private:
+ VALUE mDefault;
+};
+
+// ---------------------------------------------------------------------------
+
+template<typename KEY, typename VALUE> inline
+KeyedVector<KEY,VALUE>::KeyedVector()
+{
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::indexOfKey(const KEY& key) const {
+ return mVector.indexOf( key_value_pair_t<KEY,VALUE>(key) );
+}
+
+template<typename KEY, typename VALUE> inline
+const VALUE& KeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
+ ssize_t i = indexOfKey(key);
+ assert(i>=0);
+ return mVector.itemAt(i).value;
+}
+
+template<typename KEY, typename VALUE> inline
+const VALUE& KeyedVector<KEY,VALUE>::valueAt(size_t index) const {
+ return mVector.itemAt(index).value;
+}
+
+template<typename KEY, typename VALUE> inline
+const KEY& KeyedVector<KEY,VALUE>::keyAt(size_t index) const {
+ return mVector.itemAt(index).key;
+}
+
+template<typename KEY, typename VALUE> inline
+VALUE& KeyedVector<KEY,VALUE>::editValueFor(const KEY& key) {
+ ssize_t i = indexOfKey(key);
+ assert(i>=0);
+ return mVector.editItemAt(i).value;
+}
+
+template<typename KEY, typename VALUE> inline
+VALUE& KeyedVector<KEY,VALUE>::editValueAt(size_t index) {
+ return mVector.editItemAt(index).value;
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::add(const KEY& key, const VALUE& value) {
+ return mVector.add( key_value_pair_t<KEY,VALUE>(key, value) );
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::replaceValueFor(const KEY& key, const VALUE& value) {
+ key_value_pair_t<KEY,VALUE> pair(key, value);
+ mVector.remove(pair);
+ return mVector.add(pair);
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::replaceValueAt(size_t index, const VALUE& item) {
+ if (index<size()) {
+ mVector.editValueAt(index).value = item;
+ return index;
+ }
+ return BAD_INDEX;
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::removeItem(const KEY& key) {
+ return mVector.remove(key_value_pair_t<KEY,VALUE>(key));
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY, VALUE>::removeItemsAt(size_t index, size_t count) {
+ return mVector.removeItemsAt(index, count);
+}
+
+// ---------------------------------------------------------------------------
+
+template<typename KEY, typename VALUE> inline
+DefaultKeyedVector<KEY,VALUE>::DefaultKeyedVector(const VALUE& defValue)
+ : mDefault(defValue)
+{
+}
+
+template<typename KEY, typename VALUE> inline
+const VALUE& DefaultKeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
+ ssize_t i = indexOfKey(key);
+ return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_KEYED_VECTOR_H
diff --git a/include/utils/List.h b/include/utils/List.h
new file mode 100644
index 0000000..1a6be9a
--- /dev/null
+++ b/include/utils/List.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Templated list class. Normally we'd use STL, but we don't have that.
+// This class mimics STL's interfaces.
+//
+// Objects are copied into the list with the '=' operator or with copy-
+// construction, so if the compiler's auto-generated versions won't work for
+// you, define your own.
+//
+// The only class you want to use from here is "List". Do not use classes
+// starting with "_" directly.
+//
+#ifndef _LIBS_UTILS_LIST_H
+#define _LIBS_UTILS_LIST_H
+
+namespace android {
+
+/*
+ * One element in the list.
+ */
+template<class T> class _ListNode {
+public:
+ typedef _ListNode<T> _Node;
+
+ _ListNode(const T& val) : mVal(val) {}
+ ~_ListNode(void) {}
+
+ T& getRef(void) { return mVal; }
+ void setVal(const T& val) { mVal = val; }
+
+ _Node* getPrev(void) const { return mpPrev; }
+ void setPrev(_Node* ptr) { mpPrev = ptr; }
+ _Node* getNext(void) const { return mpNext; }
+ void setNext(_Node* ptr) { mpNext = ptr; }
+
+private:
+ T mVal;
+ _Node* mpPrev;
+ _Node* mpNext;
+};
+
+/*
+ * Iterator for walking through the list.
+ */
+template<class T, class Tref> class _ListIterator {
+public:
+ typedef _ListIterator<T,Tref> _Iter;
+ typedef _ListNode<T> _Node;
+
+ _ListIterator(void) {}
+ _ListIterator(_Node* ptr) : mpNode(ptr) {}
+ ~_ListIterator(void) {}
+
+ /*
+ * Dereference operator. Used to get at the juicy insides.
+ */
+ Tref operator*() const { return mpNode->getRef(); }
+
+ /*
+ * Iterator comparison.
+ */
+ bool operator==(const _Iter& right) const { return mpNode == right.mpNode; }
+ bool operator!=(const _Iter& right) const { return mpNode != right.mpNode; }
+
+ /*
+ * Incr/decr, used to move through the list.
+ */
+ _Iter& operator++(void) { // pre-increment
+ mpNode = mpNode->getNext();
+ return *this;
+ }
+ _Iter operator++(int) { // post-increment
+ _Iter tmp = *this;
+ ++*this;
+ return tmp;
+ }
+ _Iter& operator--(void) { // pre-increment
+ mpNode = mpNode->getPrev();
+ return *this;
+ }
+ _Iter operator--(int) { // post-increment
+ _Iter tmp = *this;
+ --*this;
+ return tmp;
+ }
+
+ _Node* getNode(void) const { return mpNode; }
+
+private:
+ _Node* mpNode;
+};
+
+
+/*
+ * Doubly-linked list. Instantiate with "List<MyClass> myList".
+ *
+ * Objects added to the list are copied using the assignment operator,
+ * so this must be defined.
+ */
+template<class T> class List {
+public:
+ typedef _ListNode<T> _Node;
+
+ List(void) {
+ prep();
+ }
+ List(const List<T>& src) { // copy-constructor
+ prep();
+ insert(begin(), src.begin(), src.end());
+ }
+ virtual ~List(void) {
+ clear();
+ delete[] (unsigned char*) mpMiddle;
+ }
+
+ typedef _ListIterator<T,T&> iterator;
+ typedef _ListIterator<T, const T&> const_iterator;
+
+ List<T>& operator=(const List<T>& right);
+
+ /* returns true if the list is empty */
+ bool empty(void) const { return mpMiddle->getNext() == mpMiddle; }
+
+ /* return #of elements in list */
+ unsigned int size(void) const {
+ return distance(begin(), end());
+ }
+
+ /*
+ * Return the first element or one past the last element. The
+ * _ListNode* we're returning is converted to an "iterator" by a
+ * constructor in _ListIterator.
+ */
+ iterator begin() { return mpMiddle->getNext(); }
+ const_iterator begin() const { return mpMiddle->getNext(); }
+ iterator end() { return mpMiddle; }
+ const_iterator end() const { return mpMiddle; }
+
+ /* add the object to the head or tail of the list */
+ void push_front(const T& val) { insert(begin(), val); }
+ void push_back(const T& val) { insert(end(), val); }
+
+ /* insert before the current node; returns iterator at new node */
+ iterator insert(iterator posn, const T& val) {
+ _Node* newNode = new _Node(val); // alloc & copy-construct
+ newNode->setNext(posn.getNode());
+ newNode->setPrev(posn.getNode()->getPrev());
+ posn.getNode()->getPrev()->setNext(newNode);
+ posn.getNode()->setPrev(newNode);
+ return newNode;
+ }
+
+ /* insert a range of elements before the current node */
+ void insert(iterator posn, const_iterator first, const_iterator last) {
+ for ( ; first != last; ++first)
+ insert(posn, *first);
+ }
+
+ /* remove one entry; returns iterator at next node */
+ iterator erase(iterator posn) {
+ _Node* pNext = posn.getNode()->getNext();
+ _Node* pPrev = posn.getNode()->getPrev();
+ pPrev->setNext(pNext);
+ pNext->setPrev(pPrev);
+ delete posn.getNode();
+ return pNext;
+ }
+
+ /* remove a range of elements */
+ iterator erase(iterator first, iterator last) {
+ while (first != last)
+ erase(first++); // don't erase than incr later!
+ return last;
+ }
+
+ /* remove all contents of the list */
+ void clear(void) {
+ _Node* pCurrent = mpMiddle->getNext();
+ _Node* pNext;
+
+ while (pCurrent != mpMiddle) {
+ pNext = pCurrent->getNext();
+ delete pCurrent;
+ pCurrent = pNext;
+ }
+ mpMiddle->setPrev(mpMiddle);
+ mpMiddle->setNext(mpMiddle);
+ }
+
+ /*
+ * Measure the distance between two iterators. On exist, "first"
+ * will be equal to "last". The iterators must refer to the same
+ * list.
+ *
+ * (This is actually a generic iterator function. It should be part
+ * of some other class, possibly an iterator base class. It needs to
+ * know the difference between a list, which has to march through,
+ * and a vector, which can just do pointer math.)
+ */
+ unsigned int distance(iterator first, iterator last) {
+ unsigned int count = 0;
+ while (first != last) {
+ ++first;
+ ++count;
+ }
+ return count;
+ }
+ unsigned int distance(const_iterator first, const_iterator last) const {
+ unsigned int count = 0;
+ while (first != last) {
+ ++first;
+ ++count;
+ }
+ return count;
+ }
+
+private:
+ /*
+ * I want a _ListNode but don't need it to hold valid data. More
+ * to the point, I don't want T's constructor to fire, since it
+ * might have side-effects or require arguments. So, we do this
+ * slightly uncouth storage alloc.
+ */
+ void prep(void) {
+ mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
+ mpMiddle->setPrev(mpMiddle);
+ mpMiddle->setNext(mpMiddle);
+ }
+
+ /*
+ * This node plays the role of "pointer to head" and "pointer to tail".
+ * It sits in the middle of a circular list of nodes. The iterator
+ * runs around the circle until it encounters this one.
+ */
+ _Node* mpMiddle;
+};
+
+/*
+ * Assignment operator.
+ *
+ * The simplest way to do this would be to clear out the target list and
+ * fill it with the source. However, we can speed things along by
+ * re-using existing elements.
+ */
+template<class T>
+List<T>& List<T>::operator=(const List<T>& right)
+{
+ if (this == &right)
+ return *this; // self-assignment
+ iterator firstDst = begin();
+ iterator lastDst = end();
+ const_iterator firstSrc = right.begin();
+ const_iterator lastSrc = right.end();
+ while (firstSrc != lastSrc && firstDst != lastDst)
+ *firstDst++ = *firstSrc++;
+ if (firstSrc == lastSrc) // ran out of elements in source?
+ erase(firstDst, lastDst); // yes, erase any extras
+ else
+ insert(lastDst, firstSrc, lastSrc); // copy remaining over
+ return *this;
+}
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_LIST_H
diff --git a/include/utils/Log.h b/include/utils/Log.h
new file mode 100644
index 0000000..3c6cc8b
--- /dev/null
+++ b/include/utils/Log.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// C/C++ logging functions. See the logging documentation for API details.
+//
+// We'd like these to be available from C code (in case we import some from
+// somewhere), so this has a C interface.
+//
+// The output will be correct when the log file is shared between multiple
+// threads and/or multiple processes so long as the operating system
+// supports O_APPEND. These calls have mutex-protected data structures
+// and so are NOT reentrant. Do not use LOG in a signal handler.
+//
+#ifndef _LIBS_UTILS_LOG_H
+#define _LIBS_UTILS_LOG_H
+
+#include <cutils/log.h>
+
+#endif // _LIBS_UTILS_LOG_H
diff --git a/include/utils/LogSocket.h b/include/utils/LogSocket.h
new file mode 100644
index 0000000..01fbfb5
--- /dev/null
+++ b/include/utils/LogSocket.h
@@ -0,0 +1,20 @@
+/* utils/LogSocket.h
+**
+** Copyright 2008, The Android Open Source Project
+**
+** This file is dual licensed. It may be redistributed and/or modified
+** under the terms of the Apache 2.0 License OR version 2 of the GNU
+** General Public License.
+*/
+
+#ifndef _UTILS_LOGSOCKET_H
+#define _UTILS_LOGSOCKET_H
+
+#define SOCKET_CLOSE_LOCAL 0
+
+void add_send_stats(int fd, int send);
+void add_recv_stats(int fd, int recv);
+void log_socket_close(int fd, short reason);
+void log_socket_connect(int fd, unsigned int ip, unsigned short port);
+
+#endif /* _UTILS_LOGSOCKET_H */
diff --git a/include/utils/MemoryBase.h b/include/utils/MemoryBase.h
new file mode 100644
index 0000000..eb5a9d2
--- /dev/null
+++ b/include/utils/MemoryBase.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEMORY_BASE_H
+#define ANDROID_MEMORY_BASE_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <utils/IMemory.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryBase : public BnMemory
+{
+public:
+ MemoryBase(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
+ virtual ~MemoryBase();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+
+protected:
+ size_t getSize() const { return mSize; }
+ ssize_t getOffset() const { return mOffset; }
+ const sp<IMemoryHeap>& getHeap() const { return mHeap; }
+
+private:
+ size_t mSize;
+ ssize_t mOffset;
+ sp<IMemoryHeap> mHeap;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_BASE_H
diff --git a/include/utils/MemoryDealer.h b/include/utils/MemoryDealer.h
new file mode 100644
index 0000000..454b627
--- /dev/null
+++ b/include/utils/MemoryDealer.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_MEMORY_DEALER_H
+#define ANDROID_MEMORY_DEALER_H
+
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/IMemory.h>
+#include <utils/threads.h>
+#include <utils/MemoryHeapBase.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+class String8;
+
+/*
+ * interface for implementing a "heap". A heap basically provides
+ * the IMemoryHeap interface for cross-process sharing and the
+ * ability to map/unmap pages within the heap.
+ */
+class HeapInterface : public virtual BnMemoryHeap
+{
+public:
+ // all values must be page-aligned
+ virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * interface for implementing an allocator. An allocator provides
+ * methods for allocating and freeing memory blocks and dumping
+ * its state.
+ */
+class AllocatorInterface : public RefBase
+{
+public:
+ enum {
+ PAGE_ALIGNED = 0x00000001
+ };
+
+ virtual size_t allocate(size_t size, uint32_t flags = 0) = 0;
+ virtual status_t deallocate(size_t offset) = 0;
+ virtual size_t size() const = 0;
+ virtual void dump(const char* what, uint32_t flags = 0) const = 0;
+ virtual void dump(String8& res,
+ const char* what, uint32_t flags = 0) const = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * concrete implementation of HeapInterface on top of mmap()
+ */
+class SharedHeap : public HeapInterface, public MemoryHeapBase
+{
+public:
+ SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL);
+ virtual ~SharedHeap();
+ virtual sp<IMemory> mapMemory(size_t offset, size_t size);
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * A simple templatized doubly linked-list implementation
+ */
+
+template <typename NODE>
+class LinkedList
+{
+ NODE* mFirst;
+ NODE* mLast;
+
+public:
+ LinkedList() : mFirst(0), mLast(0) { }
+ bool isEmpty() const { return mFirst == 0; }
+ NODE const* head() const { return mFirst; }
+ NODE* head() { return mFirst; }
+ NODE const* tail() const { return mLast; }
+ NODE* tail() { return mLast; }
+
+ void insertAfter(NODE* node, NODE* newNode) {
+ newNode->prev = node;
+ newNode->next = node->next;
+ if (node->next == 0) mLast = newNode;
+ else node->next->prev = newNode;
+ node->next = newNode;
+ }
+
+ void insertBefore(NODE* node, NODE* newNode) {
+ newNode->prev = node->prev;
+ newNode->next = node;
+ if (node->prev == 0) mFirst = newNode;
+ else node->prev->next = newNode;
+ node->prev = newNode;
+ }
+
+ void insertHead(NODE* newNode) {
+ if (mFirst == 0) {
+ mFirst = mLast = newNode;
+ newNode->prev = newNode->next = 0;
+ } else {
+ insertBefore(mFirst, newNode);
+ }
+ }
+
+ void insertTail(NODE* newNode) {
+ if (mLast == 0) insertBeginning(newNode);
+ else insertAfter(mLast, newNode);
+ }
+
+ NODE* remove(NODE* node) {
+ if (node->prev == 0) mFirst = node->next;
+ else node->prev->next = node->next;
+ if (node->next == 0) mLast = node->prev;
+ else node->next->prev = node->prev;
+ return node;
+ }
+};
+
+
+/*
+ * concrete implementation of AllocatorInterface using a simple
+ * best-fit allocation scheme
+ */
+class SimpleBestFitAllocator : public AllocatorInterface
+{
+public:
+
+ SimpleBestFitAllocator(size_t size);
+ virtual ~SimpleBestFitAllocator();
+
+ virtual size_t allocate(size_t size, uint32_t flags = 0);
+ virtual status_t deallocate(size_t offset);
+ virtual size_t size() const;
+ virtual void dump(const char* what, uint32_t flags = 0) const;
+ virtual void dump(String8& res,
+ const char* what, uint32_t flags = 0) const;
+
+private:
+
+ struct chunk_t {
+ chunk_t(size_t start, size_t size)
+ : start(start), size(size), free(1), prev(0), next(0) {
+ }
+ size_t start;
+ size_t size : 28;
+ int free : 4;
+ mutable chunk_t* prev;
+ mutable chunk_t* next;
+ };
+
+ ssize_t alloc(size_t size, uint32_t flags);
+ chunk_t* dealloc(size_t start);
+ void dump_l(const char* what, uint32_t flags = 0) const;
+ void dump_l(String8& res, const char* what, uint32_t flags = 0) const;
+
+ static const int kMemoryAlign;
+ mutable Mutex mLock;
+ LinkedList<chunk_t> mList;
+ size_t mHeapSize;
+};
+
+// ----------------------------------------------------------------------------
+
+class MemoryDealer : public RefBase
+{
+public:
+
+ enum {
+ READ_ONLY = MemoryHeapBase::READ_ONLY,
+ PAGE_ALIGNED = AllocatorInterface::PAGE_ALIGNED
+ };
+
+ // creates a memory dealer with the SharedHeap and SimpleBestFitAllocator
+ MemoryDealer(size_t size, uint32_t flags = 0, const char* name = 0);
+
+ // provide a custom heap but use the SimpleBestFitAllocator
+ MemoryDealer(const sp<HeapInterface>& heap);
+
+ // provide both custom heap and allocotar
+ MemoryDealer(
+ const sp<HeapInterface>& heap,
+ const sp<AllocatorInterface>& allocator);
+
+ virtual ~MemoryDealer();
+
+ virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0);
+ virtual void deallocate(size_t offset);
+ virtual void dump(const char* what, uint32_t flags = 0) const;
+
+
+ sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
+ sp<AllocatorInterface> getAllocator() const { return allocator(); }
+
+private:
+ const sp<HeapInterface>& heap() const;
+ const sp<AllocatorInterface>& allocator() const;
+
+ class Allocation : public BnMemory {
+ public:
+ Allocation(const sp<MemoryDealer>& dealer,
+ ssize_t offset, size_t size, const sp<IMemory>& memory);
+ virtual ~Allocation();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+ private:
+ sp<MemoryDealer> mDealer;
+ ssize_t mOffset;
+ size_t mSize;
+ sp<IMemory> mMemory;
+ };
+
+ sp<HeapInterface> mHeap;
+ sp<AllocatorInterface> mAllocator;
+};
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_DEALER_H
diff --git a/include/utils/MemoryHeapBase.h b/include/utils/MemoryHeapBase.h
new file mode 100644
index 0000000..ff89738
--- /dev/null
+++ b/include/utils/MemoryHeapBase.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEMORY_HEAP_BASE_H
+#define ANDROID_MEMORY_HEAP_BASE_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <utils/IMemory.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryHeapBase : public virtual BnMemoryHeap
+{
+public:
+ enum {
+ READ_ONLY = IMemoryHeap::READ_ONLY,
+ MAP_ONCE = IMemoryHeap::MAP_ONCE
+ };
+
+ /*
+ * maps the memory referenced by fd. but DOESN'T take ownership
+ * of the filedescriptor (it makes a copy with dup()
+ */
+ MemoryHeapBase(int fd, size_t size, uint32_t flags = 0);
+
+ /*
+ * maps memory from the given device
+ */
+ MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0);
+
+ /*
+ * maps memory from ashmem, with the given name for debugging
+ */
+ MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL);
+
+ virtual ~MemoryHeapBase();
+
+ /* implement IMemoryHeap interface */
+ virtual int getHeapID() const;
+ virtual void* getBase() const;
+ virtual size_t getSize() const;
+ virtual uint32_t getFlags() const;
+
+ const char* getDevice() const;
+
+ /* this closes this heap -- use carefully */
+ void dispose();
+
+ /* this is only needed as a workaround, use only if you know
+ * what you are doing */
+ status_t setDevice(const char* device) {
+ if (mDevice == 0)
+ mDevice = device;
+ return mDevice ? NO_ERROR : ALREADY_EXISTS;
+ }
+
+protected:
+ MemoryHeapBase();
+ // init() takes ownership of fd
+ status_t init(int fd, void *base, int size,
+ int flags = 0, const char* device = NULL);
+
+private:
+ status_t mapfd(int fd, size_t size);
+
+ int mFD;
+ size_t mSize;
+ void* mBase;
+ uint32_t mFlags;
+ const char* mDevice;
+ bool mNeedUnmap;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_HEAP_BASE_H
diff --git a/include/utils/MemoryHeapPmem.h b/include/utils/MemoryHeapPmem.h
new file mode 100644
index 0000000..b694b20
--- /dev/null
+++ b/include/utils/MemoryHeapPmem.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEMORY_HEAP_PMEM_H
+#define ANDROID_MEMORY_HEAP_PMEM_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/IMemory.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class MemoryHeapBase;
+
+// ---------------------------------------------------------------------------
+
+class SubRegionMemory;
+
+class MemoryHeapPmem : public HeapInterface, public MemoryHeapBase
+{
+public:
+ MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
+ uint32_t flags = IMemoryHeap::MAP_ONCE);
+ ~MemoryHeapPmem();
+
+ /* HeapInterface additions */
+ virtual sp<IMemory> mapMemory(size_t offset, size_t size);
+
+ /* make the whole heap visible (you know who you are) */
+ virtual status_t slap();
+
+ /* hide (revoke) the whole heap (the client will see the garbage page) */
+ virtual status_t unslap();
+
+ /* revoke all allocations made by this heap */
+ virtual void revoke();
+
+private:
+ sp<MemoryHeapBase> mParentHeap;
+ mutable Mutex mLock;
+ Vector< wp<SubRegionMemory> > mAllocations;
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_HEAP_PMEM_H
diff --git a/include/utils/Parcel.h b/include/utils/Parcel.h
new file mode 100644
index 0000000..7c451ab
--- /dev/null
+++ b/include/utils/Parcel.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2005 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_PARCEL_H
+#define ANDROID_PARCEL_H
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IBinder;
+class ProcessState;
+class String8;
+class TextOutput;
+
+struct flat_binder_object; // defined in support_p/binder_module.h
+
+class Parcel
+{
+public:
+ Parcel();
+ ~Parcel();
+
+ const uint8_t* data() const;
+ size_t dataSize() const;
+ size_t dataAvail() const;
+ size_t dataPosition() const;
+ size_t dataCapacity() const;
+
+ status_t setDataSize(size_t size);
+ void setDataPosition(size_t pos) const;
+ status_t setDataCapacity(size_t size);
+
+ status_t setData(const uint8_t* buffer, size_t len);
+
+ status_t appendFrom(Parcel *parcel, size_t start, size_t len);
+
+ bool hasFileDescriptors() const;
+
+ status_t writeInterfaceToken(const String16& interface);
+ bool enforceInterface(const String16& interface) const;
+
+ void freeData();
+
+ const size_t* objects() const;
+ size_t objectsCount() const;
+
+ status_t errorCheck() const;
+ void setError(status_t err);
+
+ status_t write(const void* data, size_t len);
+ void* writeInplace(size_t len);
+ status_t writeUnpadded(const void* data, size_t len);
+ status_t writeInt32(int32_t val);
+ status_t writeInt64(int64_t val);
+ status_t writeFloat(float val);
+ status_t writeDouble(double val);
+ status_t writeCString(const char* str);
+ status_t writeString8(const String8& str);
+ status_t writeString16(const String16& str);
+ status_t writeString16(const char16_t* str, size_t len);
+ status_t writeStrongBinder(const sp<IBinder>& val);
+ status_t writeWeakBinder(const wp<IBinder>& val);
+
+ // Place a file descriptor into the parcel. The given fd must remain
+ // valid for the lifetime of the parcel.
+ status_t writeFileDescriptor(int fd);
+
+ // Place a file descriptor into the parcel. A dup of the fd is made, which
+ // will be closed once the parcel is destroyed.
+ status_t writeDupFileDescriptor(int fd);
+
+ status_t writeObject(const flat_binder_object& val, bool nullMetaData);
+
+ void remove(size_t start, size_t amt);
+
+ status_t read(void* outData, size_t len) const;
+ const void* readInplace(size_t len) const;
+ int32_t readInt32() const;
+ status_t readInt32(int32_t *pArg) const;
+ int64_t readInt64() const;
+ status_t readInt64(int64_t *pArg) const;
+ float readFloat() const;
+ status_t readFloat(float *pArg) const;
+ double readDouble() const;
+ status_t readDouble(double *pArg) const;
+
+ const char* readCString() const;
+ String8 readString8() const;
+ String16 readString16() const;
+ const char16_t* readString16Inplace(size_t* outLen) const;
+ sp<IBinder> readStrongBinder() const;
+ wp<IBinder> readWeakBinder() const;
+
+ // Retrieve a file descriptor from the parcel. This returns the raw fd
+ // in the parcel, which you do not own -- use dup() to get your own copy.
+ int readFileDescriptor() const;
+
+ const flat_binder_object* readObject(bool nullMetaData) const;
+
+ // Explicitly close all file descriptors in the parcel.
+ void closeFileDescriptors();
+
+ typedef void (*release_func)(Parcel* parcel,
+ const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsSize,
+ void* cookie);
+
+ const uint8_t* ipcData() const;
+ size_t ipcDataSize() const;
+ const size_t* ipcObjects() const;
+ size_t ipcObjectsCount() const;
+ void ipcSetDataReference(const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsCount,
+ release_func relFunc, void* relCookie);
+
+ void print(TextOutput& to, uint32_t flags = 0) const;
+
+private:
+ Parcel(const Parcel& o);
+ Parcel& operator=(const Parcel& o);
+
+ status_t finishWrite(size_t len);
+ void releaseObjects();
+ void acquireObjects();
+ status_t growData(size_t len);
+ status_t restartWrite(size_t desired);
+ status_t continueWrite(size_t desired);
+ void freeDataNoInit();
+ void initState();
+ void scanForFds() const;
+
+ status_t mError;
+ uint8_t* mData;
+ size_t mDataSize;
+ size_t mDataCapacity;
+ mutable size_t mDataPos;
+ size_t* mObjects;
+ size_t mObjectsSize;
+ size_t mObjectsCapacity;
+ mutable size_t mNextObjectHint;
+
+ mutable bool mFdsKnown;
+ mutable bool mHasFds;
+
+ release_func mOwner;
+ void* mOwnerCookie;
+};
+
+// ---------------------------------------------------------------------------
+
+inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
+{
+ parcel.print(to);
+ return to;
+}
+
+// ---------------------------------------------------------------------------
+
+// Generic acquire and release of objects.
+void acquire_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who);
+void release_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who);
+
+void flatten_binder(const sp<ProcessState>& proc,
+ const sp<IBinder>& binder, flat_binder_object* out);
+void flatten_binder(const sp<ProcessState>& proc,
+ const wp<IBinder>& binder, flat_binder_object* out);
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const flat_binder_object& flat, sp<IBinder>* out);
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const flat_binder_object& flat, wp<IBinder>* out);
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PARCEL_H
diff --git a/include/utils/Pipe.h b/include/utils/Pipe.h
new file mode 100644
index 0000000..6404168
--- /dev/null
+++ b/include/utils/Pipe.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// FIFO I/O.
+//
+#ifndef _LIBS_UTILS_PIPE_H
+#define _LIBS_UTILS_PIPE_H
+
+#ifdef HAVE_ANDROID_OS
+#error DO NOT USE THIS FILE IN THE DEVICE BUILD
+#endif
+
+namespace android {
+
+/*
+ * Simple anonymous unidirectional pipe.
+ *
+ * The primary goal is to create an implementation with minimal overhead
+ * under Linux. Making Windows, Mac OS X, and Linux all work the same way
+ * is a secondary goal. Part of this goal is to have something that can
+ * be fed to a select() call, so that the application can sleep in the
+ * kernel until something interesting happens.
+ */
+class Pipe {
+public:
+ Pipe(void);
+ virtual ~Pipe(void);
+
+ /* Create the pipe */
+ bool create(void);
+
+ /* Create a read-only pipe, using the supplied handle as read handle */
+ bool createReader(unsigned long handle);
+ /* Create a write-only pipe, using the supplied handle as write handle */
+ bool createWriter(unsigned long handle);
+
+ /* Is this object ready to go? */
+ bool isCreated(void);
+
+ /*
+ * Read "count" bytes from the pipe. Returns the amount of data read,
+ * or 0 if no data available and we're non-blocking.
+ * Returns -1 on error.
+ */
+ int read(void* buf, int count);
+
+ /*
+ * Write "count" bytes into the pipe. Returns number of bytes written,
+ * or 0 if there's no room for more data and we're non-blocking.
+ * Returns -1 on error.
+ */
+ int write(const void* buf, int count);
+
+ /* Returns "true" if data is available to read */
+ bool readReady(void);
+
+ /* Enable or disable non-blocking I/O for reads */
+ bool setReadNonBlocking(bool val);
+ /* Enable or disable non-blocking I/O for writes. Only works on Linux. */
+ bool setWriteNonBlocking(bool val);
+
+ /*
+ * Get the handle. Only useful in some platform-specific situations.
+ */
+ unsigned long getReadHandle(void);
+ unsigned long getWriteHandle(void);
+
+ /*
+ * Modify inheritance, i.e. whether or not a child process will get
+ * copies of the descriptors. Systems with fork+exec allow us to close
+ * the descriptors before launching the child process, but Win32
+ * doesn't allow it.
+ */
+ bool disallowReadInherit(void);
+ bool disallowWriteInherit(void);
+
+ /*
+ * Close one side or the other. Useful in the parent after launching
+ * a child process.
+ */
+ bool closeRead(void);
+ bool closeWrite(void);
+
+private:
+ bool mReadNonBlocking;
+ bool mWriteNonBlocking;
+
+ unsigned long mReadHandle;
+ unsigned long mWriteHandle;
+};
+
+}; // android
+
+#endif // _LIBS_UTILS_PIPE_H
diff --git a/include/utils/ProcessState.h b/include/utils/ProcessState.h
new file mode 100644
index 0000000..39584f4
--- /dev/null
+++ b/include/utils/ProcessState.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2005 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_PROCESS_STATE_H
+#define ANDROID_PROCESS_STATE_H
+
+#include <utils/IBinder.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+// Global variables
+extern int mArgC;
+extern const char* const* mArgV;
+extern int mArgLen;
+
+class IPCThreadState;
+
+class ProcessState : public virtual RefBase
+{
+public:
+ static sp<ProcessState> self();
+
+ static void setSingleProcess(bool singleProcess);
+
+ void setContextObject(const sp<IBinder>& object);
+ sp<IBinder> getContextObject(const sp<IBinder>& caller);
+
+ void setContextObject(const sp<IBinder>& object,
+ const String16& name);
+ sp<IBinder> getContextObject(const String16& name,
+ const sp<IBinder>& caller);
+
+ bool supportsProcesses() const;
+
+ void startThreadPool();
+
+ typedef bool (*context_check_func)(const String16& name,
+ const sp<IBinder>& caller,
+ void* userData);
+
+ bool isContextManager(void) const;
+ bool becomeContextManager(
+ context_check_func checkFunc,
+ void* userData);
+
+ sp<IBinder> getStrongProxyForHandle(int32_t handle);
+ wp<IBinder> getWeakProxyForHandle(int32_t handle);
+ void expungeHandle(int32_t handle, IBinder* binder);
+
+ void setArgs(int argc, const char* const argv[]);
+ int getArgC() const;
+ const char* const* getArgV() const;
+
+ void setArgV0(const char* txt);
+
+ void spawnPooledThread(bool isMain);
+
+private:
+ friend class IPCThreadState;
+
+ ProcessState();
+ ~ProcessState();
+
+ ProcessState(const ProcessState& o);
+ ProcessState& operator=(const ProcessState& o);
+
+ struct handle_entry {
+ IBinder* binder;
+ RefBase::weakref_type* refs;
+ };
+
+ handle_entry* lookupHandleLocked(int32_t handle);
+
+ int mDriverFD;
+ void* mVMStart;
+
+ mutable Mutex mLock; // protects everything below.
+
+ Vector<handle_entry>mHandleToObject;
+
+ bool mManagesContexts;
+ context_check_func mBinderContextCheckFunc;
+ void* mBinderContextUserData;
+
+ KeyedVector<String16, sp<IBinder> >
+ mContexts;
+
+
+ String8 mRootDir;
+ bool mThreadPoolStarted;
+ volatile int32_t mThreadPoolSeq;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PROCESS_STATE_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
new file mode 100644
index 0000000..e37b56f
--- /dev/null
+++ b/include/utils/RefBase.h
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2005 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_REF_BASE_H
+#define ANDROID_REF_BASE_H
+
+#include <utils/TextOutput.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+template<typename T> class wp;
+
+// ---------------------------------------------------------------------------
+
+#define COMPARE(_op_) \
+inline bool operator _op_ (const sp<T>& o) const { \
+ return m_ptr _op_ o.m_ptr; \
+} \
+inline bool operator _op_ (const wp<T>& o) const { \
+ return m_ptr _op_ o.m_ptr; \
+} \
+inline bool operator _op_ (const T* o) const { \
+ return m_ptr _op_ o; \
+} \
+template<typename U> \
+inline bool operator _op_ (const sp<U>& o) const { \
+ return m_ptr _op_ o.m_ptr; \
+} \
+template<typename U> \
+inline bool operator _op_ (const wp<U>& o) const { \
+ return m_ptr _op_ o.m_ptr; \
+} \
+template<typename U> \
+inline bool operator _op_ (const U* o) const { \
+ return m_ptr _op_ o; \
+}
+
+// ---------------------------------------------------------------------------
+
+class RefBase
+{
+public:
+ void incStrong(const void* id) const;
+ void decStrong(const void* id) const;
+
+ void forceIncStrong(const void* id) const;
+
+ //! DEBUGGING ONLY: Get current strong ref count.
+ int32_t getStrongCount() const;
+
+ class weakref_type
+ {
+ public:
+ RefBase* refBase() const;
+
+ void incWeak(const void* id);
+ void decWeak(const void* id);
+
+ bool attemptIncStrong(const void* id);
+
+ //! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
+ bool attemptIncWeak(const void* id);
+
+ //! DEBUGGING ONLY: Get current weak ref count.
+ int32_t getWeakCount() const;
+
+ //! DEBUGGING ONLY: Print references held on object.
+ void printRefs() const;
+
+ //! DEBUGGING ONLY: Enable tracking for this object.
+ // enable -- enable/disable tracking
+ // retain -- when tracking is enable, if true, then we save a stack trace
+ // for each reference and dereference; when retain == false, we
+ // match up references and dereferences and keep only the
+ // outstanding ones.
+
+ void trackMe(bool enable, bool retain);
+ };
+
+ weakref_type* createWeak(const void* id) const;
+
+ weakref_type* getWeakRefs() const;
+
+ //! DEBUGGING ONLY: Print references held on object.
+ inline void printRefs() const { getWeakRefs()->printRefs(); }
+
+ //! DEBUGGING ONLY: Enable tracking of object.
+ inline void trackMe(bool enable, bool retain)
+ {
+ getWeakRefs()->trackMe(enable, retain);
+ }
+
+protected:
+ RefBase();
+ virtual ~RefBase();
+
+ //! Flags for extendObjectLifetime()
+ enum {
+ OBJECT_LIFETIME_WEAK = 0x0001,
+ OBJECT_LIFETIME_FOREVER = 0x0003
+ };
+
+ void extendObjectLifetime(int32_t mode);
+
+ //! Flags for onIncStrongAttempted()
+ enum {
+ FIRST_INC_STRONG = 0x0001
+ };
+
+ virtual void onFirstRef();
+ virtual void onLastStrongRef(const void* id);
+ virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
+ virtual void onLastWeakRef(const void* id);
+
+private:
+ friend class weakref_type;
+ class weakref_impl;
+
+ RefBase(const RefBase& o);
+ RefBase& operator=(const RefBase& o);
+
+ weakref_impl* const mRefs;
+};
+
+// ---------------------------------------------------------------------------
+
+template <typename T>
+class sp
+{
+public:
+ typedef typename RefBase::weakref_type weakref_type;
+
+ inline sp() : m_ptr(0) { }
+
+ sp(T* other);
+ sp(const sp<T>& other);
+ template<typename U> sp(U* other);
+ template<typename U> sp(const sp<U>& other);
+
+ ~sp();
+
+ // Assignment
+
+ sp& operator = (T* other);
+ sp& operator = (const sp<T>& other);
+
+ template<typename U> sp& operator = (const sp<U>& other);
+ template<typename U> sp& operator = (U* other);
+
+ //! Special optimization for use by ProcessState (and nobody else).
+ void force_set(T* other);
+
+ // Reset
+
+ void clear();
+
+ // Accessors
+
+ inline T& operator* () const { return *m_ptr; }
+ inline T* operator-> () const { return m_ptr; }
+ inline T* get() const { return m_ptr; }
+
+ // Operators
+
+ COMPARE(==)
+ COMPARE(!=)
+ COMPARE(>)
+ COMPARE(<)
+ COMPARE(<=)
+ COMPARE(>=)
+
+private:
+ template<typename Y> friend class sp;
+ template<typename Y> friend class wp;
+
+ // Optimization for wp::promote().
+ sp(T* p, weakref_type* refs);
+
+ T* m_ptr;
+};
+
+template <typename T>
+TextOutput& operator<<(TextOutput& to, const sp<T>& val);
+
+// ---------------------------------------------------------------------------
+
+template <typename T>
+class wp
+{
+public:
+ typedef typename RefBase::weakref_type weakref_type;
+
+ inline wp() : m_ptr(0) { }
+
+ wp(T* other);
+ wp(const wp<T>& other);
+ wp(const sp<T>& other);
+ template<typename U> wp(U* other);
+ template<typename U> wp(const sp<U>& other);
+ template<typename U> wp(const wp<U>& other);
+
+ ~wp();
+
+ // Assignment
+
+ wp& operator = (T* other);
+ wp& operator = (const wp<T>& other);
+ wp& operator = (const sp<T>& other);
+
+ template<typename U> wp& operator = (U* other);
+ template<typename U> wp& operator = (const wp<U>& other);
+ template<typename U> wp& operator = (const sp<U>& other);
+
+ void set_object_and_refs(T* other, weakref_type* refs);
+
+ // promotion to sp
+
+ sp<T> promote() const;
+
+ // Reset
+
+ void clear();
+
+ // Accessors
+
+ inline weakref_type* get_refs() const { return m_refs; }
+
+ inline T* unsafe_get() const { return m_ptr; }
+
+ // Operators
+
+ COMPARE(==)
+ COMPARE(!=)
+ COMPARE(>)
+ COMPARE(<)
+ COMPARE(<=)
+ COMPARE(>=)
+
+private:
+ template<typename Y> friend class sp;
+ template<typename Y> friend class wp;
+
+ T* m_ptr;
+ weakref_type* m_refs;
+};
+
+template <typename T>
+TextOutput& operator<<(TextOutput& to, const wp<T>& val);
+
+#undef COMPARE
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts below here.
+
+template<typename T>
+sp<T>::sp(T* other)
+ : m_ptr(other)
+{
+ if (other) other->incStrong(this);
+}
+
+template<typename T>
+sp<T>::sp(const sp<T>& other)
+ : m_ptr(other.m_ptr)
+{
+ if (m_ptr) m_ptr->incStrong(this);
+}
+
+template<typename T> template<typename U>
+sp<T>::sp(U* other) : m_ptr(other)
+{
+ if (other) other->incStrong(this);
+}
+
+template<typename T> template<typename U>
+sp<T>::sp(const sp<U>& other)
+ : m_ptr(other.m_ptr)
+{
+ if (m_ptr) m_ptr->incStrong(this);
+}
+
+template<typename T>
+sp<T>::~sp()
+{
+ if (m_ptr) m_ptr->decStrong(this);
+}
+
+template<typename T>
+sp<T>& sp<T>::operator = (const sp<T>& other) {
+ if (other.m_ptr) other.m_ptr->incStrong(this);
+ if (m_ptr) m_ptr->decStrong(this);
+ m_ptr = other.m_ptr;
+ return *this;
+}
+
+template<typename T>
+sp<T>& sp<T>::operator = (T* other)
+{
+ if (other) other->incStrong(this);
+ if (m_ptr) m_ptr->decStrong(this);
+ m_ptr = other;
+ return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator = (const sp<U>& other)
+{
+ if (other.m_ptr) other.m_ptr->incStrong(this);
+ if (m_ptr) m_ptr->decStrong(this);
+ m_ptr = other.m_ptr;
+ return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator = (U* other)
+{
+ if (other) other->incStrong(this);
+ if (m_ptr) m_ptr->decStrong(this);
+ m_ptr = other;
+ return *this;
+}
+
+template<typename T>
+void sp<T>::force_set(T* other)
+{
+ other->forceIncStrong(this);
+ m_ptr = other;
+}
+
+template<typename T>
+void sp<T>::clear()
+{
+ if (m_ptr) {
+ m_ptr->decStrong(this);
+ m_ptr = 0;
+ }
+}
+
+template<typename T>
+sp<T>::sp(T* p, weakref_type* refs)
+ : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
+{
+}
+
+template <typename T>
+inline TextOutput& operator<<(TextOutput& to, const sp<T>& val)
+{
+ to << "sp<>(" << val.get() << ")";
+ return to;
+}
+
+// ---------------------------------------------------------------------------
+
+template<typename T>
+wp<T>::wp(T* other)
+ : m_ptr(other)
+{
+ if (other) m_refs = other->createWeak(this);
+}
+
+template<typename T>
+wp<T>::wp(const wp<T>& other)
+ : m_ptr(other.m_ptr), m_refs(other.m_refs)
+{
+ if (m_ptr) m_refs->incWeak(this);
+}
+
+template<typename T>
+wp<T>::wp(const sp<T>& other)
+ : m_ptr(other.m_ptr)
+{
+ if (m_ptr) {
+ m_refs = m_ptr->createWeak(this);
+ }
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(U* other)
+ : m_ptr(other)
+{
+ if (other) m_refs = other->createWeak(this);
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(const wp<U>& other)
+ : m_ptr(other.m_ptr)
+{
+ if (m_ptr) {
+ m_refs = other.m_refs;
+ m_refs->incWeak(this);
+ }
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(const sp<U>& other)
+ : m_ptr(other.m_ptr)
+{
+ if (m_ptr) {
+ m_refs = m_ptr->createWeak(this);
+ }
+}
+
+template<typename T>
+wp<T>::~wp()
+{
+ if (m_ptr) m_refs->decWeak(this);
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (T* other)
+{
+ weakref_type* newRefs =
+ other ? other->createWeak(this) : 0;
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other;
+ m_refs = newRefs;
+ return *this;
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (const wp<T>& other)
+{
+ if (other.m_ptr) other.m_refs->incWeak(this);
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other.m_ptr;
+ m_refs = other.m_refs;
+ return *this;
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (const sp<T>& other)
+{
+ weakref_type* newRefs =
+ other != NULL ? other->createWeak(this) : 0;
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other.get();
+ m_refs = newRefs;
+ return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (U* other)
+{
+ weakref_type* newRefs =
+ other ? other->createWeak(this) : 0;
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other;
+ m_refs = newRefs;
+ return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (const wp<U>& other)
+{
+ if (other.m_ptr) other.m_refs->incWeak(this);
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other.m_ptr;
+ m_refs = other.m_refs;
+ return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (const sp<U>& other)
+{
+ weakref_type* newRefs =
+ other != NULL ? other->createWeak(this) : 0;
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other.get();
+ m_refs = newRefs;
+ return *this;
+}
+
+template<typename T>
+void wp<T>::set_object_and_refs(T* other, weakref_type* refs)
+{
+ if (other) refs->incWeak(this);
+ if (m_ptr) m_refs->decWeak(this);
+ m_ptr = other;
+ m_refs = refs;
+}
+
+template<typename T>
+sp<T> wp<T>::promote() const
+{
+ return sp<T>(m_ptr, m_refs);
+}
+
+template<typename T>
+void wp<T>::clear()
+{
+ if (m_ptr) {
+ m_refs->decWeak(this);
+ m_ptr = 0;
+ }
+}
+
+template <typename T>
+inline TextOutput& operator<<(TextOutput& to, const wp<T>& val)
+{
+ to << "wp<>(" << val.unsafe_get() << ")";
+ return to;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_REF_BASE_H
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
new file mode 100644
index 0000000..31b9aa8
--- /dev/null
+++ b/include/utils/ResourceTypes.h
@@ -0,0 +1,1685 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Definitions of resource data structures.
+//
+#ifndef _LIBS_UTILS_RESOURCE_TYPES_H
+#define _LIBS_UTILS_RESOURCE_TYPES_H
+
+#include <utils/Asset.h>
+#include <utils/ByteOrder.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include <utils/threads.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+
+/** ********************************************************************
+ * PNG Extensions
+ *
+ * New private chunks that may be placed in PNG images.
+ *
+ *********************************************************************** */
+
+/**
+ * This chunk specifies how to split an image into segments for
+ * scaling.
+ *
+ * There are J horizontal and K vertical segments. These segments divide
+ * the image into J*K regions as follows (where J=4 and K=3):
+ *
+ * F0 S0 F1 S1
+ * +-----+----+------+-------+
+ * S2| 0 | 1 | 2 | 3 |
+ * +-----+----+------+-------+
+ * | | | | |
+ * | | | | |
+ * F2| 4 | 5 | 6 | 7 |
+ * | | | | |
+ * | | | | |
+ * +-----+----+------+-------+
+ * S3| 8 | 9 | 10 | 11 |
+ * +-----+----+------+-------+
+ *
+ * Each horizontal and vertical segment is considered to by either
+ * stretchable (marked by the Sx labels) or fixed (marked by the Fy
+ * labels), in the horizontal or vertical axis, respectively. In the
+ * above example, the first is horizontal segment (F0) is fixed, the
+ * next is stretchable and then they continue to alternate. Note that
+ * the segment list for each axis can begin or end with a stretchable
+ * or fixed segment.
+ *
+ * The relative sizes of the stretchy segments indicates the relative
+ * amount of stretchiness of the regions bordered by the segments. For
+ * example, regions 3, 7 and 11 above will take up more horizontal space
+ * than regions 1, 5 and 9 since the horizonal segment associated with
+ * the first set of regions is larger than the other set of regions. The
+ * ratios of the amount of horizontal (or vertical) space taken by any
+ * two stretchable slices is exactly the ratio of their corresponding
+ * segment lengths.
+ *
+ * xDivs and yDivs point to arrays of horizontal and vertical pixel
+ * indices. The first pair of Divs (in either array) indicate the
+ * starting and ending points of the first stretchable segment in that
+ * axis. The next pair specifies the next stretchable segment, etc. So
+ * in the above example xDiv[0] and xDiv[1] specify the horizontal
+ * coordinates for the regions labeled 1, 5 and 9. xDiv[2] and
+ * xDiv[3] specify the coordinates for regions 3, 7 and 11. Note that
+ * the leftmost slices always start at x=0 and the rightmost slices
+ * always end at the end of the image. So, for example, the regions 0,
+ * 4 and 8 (which are fixed along the X axis) start at x value 0 and
+ * go to xDiv[0] amd slices 2, 6 and 10 start at xDiv[1] and end at
+ * xDiv[2].
+ *
+ * The array pointed to by the colors field lists contains hints for
+ * each of the regions. They are ordered according left-to-right and
+ * top-to-bottom as indicated above. For each segment that is a solid
+ * color the array entry will contain that color value; otherwise it
+ * will contain NO_COLOR. Segments that are completely transparent
+ * will always have the value TRANSPARENT_COLOR.
+ *
+ * The PNG chunk type is "npTc".
+ */
+struct Res_png_9patch
+{
+ Res_png_9patch() : wasDeserialized(false), xDivs(NULL),
+ yDivs(NULL), colors(NULL) { }
+
+ int8_t wasDeserialized;
+ int8_t numXDivs;
+ int8_t numYDivs;
+ int8_t numColors;
+
+ // These tell where the next section of a patch starts.
+ // For example, the first patch includes the pixels from
+ // 0 to xDivs[0]-1 and the second patch includes the pixels
+ // from xDivs[0] to xDivs[1]-1.
+ // Note: allocation/free of these pointers is left to the caller.
+ int32_t* xDivs;
+ int32_t* yDivs;
+
+ int32_t paddingLeft, paddingRight;
+ int32_t paddingTop, paddingBottom;
+
+ enum {
+ // The 9 patch segment is not a solid color.
+ NO_COLOR = 0x00000001,
+
+ // The 9 patch segment is completely transparent.
+ TRANSPARENT_COLOR = 0x00000000
+ };
+ // Note: allocation/free of this pointer is left to the caller.
+ uint32_t* colors;
+
+ // Convert data from device representation to PNG file representation.
+ void deviceToFile();
+ // Convert data from PNG file representation to device representation.
+ void fileToDevice();
+ // Serialize/Marshall the patch data into a newly malloc-ed block
+ void* serialize();
+ // Serialize/Marshall the patch data
+ void serialize(void* outData);
+ // Deserialize/Unmarshall the patch data
+ static Res_png_9patch* deserialize(const void* data);
+ // Deserialize/Unmarshall the patch data into a newly malloc-ed block
+ static void deserialize(const void* data, Res_png_9patch* outData);
+ // Compute the size of the serialized data structure
+ size_t serializedSize();
+};
+
+/** ********************************************************************
+ * Base Types
+ *
+ * These are standard types that are shared between multiple specific
+ * resource types.
+ *
+ *********************************************************************** */
+
+/**
+ * Header that appears at the front of every data chunk in a resource.
+ */
+struct ResChunk_header
+{
+ // Type identifier for this chunk. The meaning of this value depends
+ // on the containing chunk.
+ uint16_t type;
+
+ // Size of the chunk header (in bytes). Adding this value to
+ // the address of the chunk allows you to find its associated data
+ // (if any).
+ uint16_t headerSize;
+
+ // Total size of this chunk (in bytes). This is the chunkSize plus
+ // the size of any data associated with the chunk. Adding this value
+ // to the chunk allows you to completely skip its contents (including
+ // any child chunks). If this value is the same as chunkSize, there is
+ // no data associated with the chunk.
+ uint32_t size;
+};
+
+enum {
+ RES_NULL_TYPE = 0x0000,
+ RES_STRING_POOL_TYPE = 0x0001,
+ RES_TABLE_TYPE = 0x0002,
+ RES_XML_TYPE = 0x0003,
+
+ // Chunk types in RES_XML_TYPE
+ RES_XML_FIRST_CHUNK_TYPE = 0x0100,
+ RES_XML_START_NAMESPACE_TYPE= 0x0100,
+ RES_XML_END_NAMESPACE_TYPE = 0x0101,
+ RES_XML_START_ELEMENT_TYPE = 0x0102,
+ RES_XML_END_ELEMENT_TYPE = 0x0103,
+ RES_XML_CDATA_TYPE = 0x0104,
+ RES_XML_LAST_CHUNK_TYPE = 0x017f,
+ // This contains a uint32_t array mapping strings in the string
+ // pool back to resource identifiers. It is optional.
+ RES_XML_RESOURCE_MAP_TYPE = 0x0180,
+
+ // Chunk types in RES_TABLE_TYPE
+ RES_TABLE_PACKAGE_TYPE = 0x0200,
+ RES_TABLE_TYPE_TYPE = 0x0201,
+ RES_TABLE_TYPE_SPEC_TYPE = 0x0202
+};
+
+/**
+ * Macros for building/splitting resource identifiers.
+ */
+#define Res_VALIDID(resid) (resid != 0)
+#define Res_CHECKID(resid) ((resid&0xFFFF0000) != 0)
+#define Res_MAKEID(package, type, entry) \
+ (((package+1)<<24) | (((type+1)&0xFF)<<16) | (entry&0xFFFF))
+#define Res_GETPACKAGE(id) ((id>>24)-1)
+#define Res_GETTYPE(id) (((id>>16)&0xFF)-1)
+#define Res_GETENTRY(id) (id&0xFFFF)
+
+#define Res_INTERNALID(resid) ((resid&0xFFFF0000) != 0 && (resid&0xFF0000) == 0)
+#define Res_MAKEINTERNAL(entry) (0x01000000 | (entry&0xFFFF))
+#define Res_MAKEARRAY(entry) (0x02000000 | (entry&0xFFFF))
+
+#define Res_MAXPACKAGE 255
+
+/**
+ * Representation of a value in a resource, supplying type
+ * information.
+ */
+struct Res_value
+{
+ // Number of bytes in this structure.
+ uint16_t size;
+
+ // Always set to 0.
+ uint8_t res0;
+
+ // Type of the data value.
+ enum {
+ // Contains no data.
+ TYPE_NULL = 0x00,
+ // The 'data' holds a ResTable_ref, a reference to another resource
+ // table entry.
+ TYPE_REFERENCE = 0x01,
+ // The 'data' holds an attribute resource identifier.
+ TYPE_ATTRIBUTE = 0x02,
+ // The 'data' holds an index into the containing resource table's
+ // global value string pool.
+ TYPE_STRING = 0x03,
+ // The 'data' holds a single-precision floating point number.
+ TYPE_FLOAT = 0x04,
+ // The 'data' holds a complex number encoding a dimension value,
+ // such as "100in".
+ TYPE_DIMENSION = 0x05,
+ // The 'data' holds a complex number encoding a fraction of a
+ // container.
+ TYPE_FRACTION = 0x06,
+
+ // Beginning of integer flavors...
+ TYPE_FIRST_INT = 0x10,
+
+ // The 'data' is a raw integer value of the form n..n.
+ TYPE_INT_DEC = 0x10,
+ // The 'data' is a raw integer value of the form 0xn..n.
+ TYPE_INT_HEX = 0x11,
+ // The 'data' is either 0 or 1, for input "false" or "true" respectively.
+ TYPE_INT_BOOLEAN = 0x12,
+
+ // Beginning of color integer flavors...
+ TYPE_FIRST_COLOR_INT = 0x1c,
+
+ // The 'data' is a raw integer value of the form #aarrggbb.
+ TYPE_INT_COLOR_ARGB8 = 0x1c,
+ // The 'data' is a raw integer value of the form #rrggbb.
+ TYPE_INT_COLOR_RGB8 = 0x1d,
+ // The 'data' is a raw integer value of the form #argb.
+ TYPE_INT_COLOR_ARGB4 = 0x1e,
+ // The 'data' is a raw integer value of the form #rgb.
+ TYPE_INT_COLOR_RGB4 = 0x1f,
+
+ // ...end of integer flavors.
+ TYPE_LAST_COLOR_INT = 0x1f,
+
+ // ...end of integer flavors.
+ TYPE_LAST_INT = 0x1f
+ };
+ uint8_t dataType;
+
+ // Structure of complex data values (TYPE_UNIT and TYPE_FRACTION)
+ enum {
+ // Where the unit type information is. This gives us 16 possible
+ // types, as defined below.
+ COMPLEX_UNIT_SHIFT = 0,
+ COMPLEX_UNIT_MASK = 0xf,
+
+ // TYPE_DIMENSION: Value is raw pixels.
+ COMPLEX_UNIT_PX = 0,
+ // TYPE_DIMENSION: Value is Device Independent Pixels.
+ COMPLEX_UNIT_DIP = 1,
+ // TYPE_DIMENSION: Value is a Scaled device independent Pixels.
+ COMPLEX_UNIT_SP = 2,
+ // TYPE_DIMENSION: Value is in points.
+ COMPLEX_UNIT_PT = 3,
+ // TYPE_DIMENSION: Value is in inches.
+ COMPLEX_UNIT_IN = 4,
+ // TYPE_DIMENSION: Value is in millimeters.
+ COMPLEX_UNIT_MM = 5,
+
+ // TYPE_FRACTION: A basic fraction of the overall size.
+ COMPLEX_UNIT_FRACTION = 0,
+ // TYPE_FRACTION: A fraction of the parent size.
+ COMPLEX_UNIT_FRACTION_PARENT = 1,
+
+ // Where the radix information is, telling where the decimal place
+ // appears in the mantissa. This give us 4 possible fixed point
+ // representations as defined below.
+ COMPLEX_RADIX_SHIFT = 4,
+ COMPLEX_RADIX_MASK = 0x3,
+
+ // The mantissa is an integral number -- i.e., 0xnnnnnn.0
+ COMPLEX_RADIX_23p0 = 0,
+ // The mantissa magnitude is 16 bits -- i.e, 0xnnnn.nn
+ COMPLEX_RADIX_16p7 = 1,
+ // The mantissa magnitude is 8 bits -- i.e, 0xnn.nnnn
+ COMPLEX_RADIX_8p15 = 2,
+ // The mantissa magnitude is 0 bits -- i.e, 0x0.nnnnnn
+ COMPLEX_RADIX_0p23 = 3,
+
+ // Where the actual value is. This gives us 23 bits of
+ // precision. The top bit is the sign.
+ COMPLEX_MANTISSA_SHIFT = 8,
+ COMPLEX_MANTISSA_MASK = 0xffffff
+ };
+
+ // The data for this item, as interpreted according to dataType.
+ uint32_t data;
+
+ void copyFrom_dtoh(const Res_value& src);
+};
+
+/**
+ * This is a reference to a unique entry (a ResTable_entry structure)
+ * in a resource table. The value is structured as: 0xpptteeee,
+ * where pp is the package index, tt is the type index in that
+ * package, and eeee is the entry index in that type. The package
+ * and type values start at 1 for the first item, to help catch cases
+ * where they have not been supplied.
+ */
+struct ResTable_ref
+{
+ uint32_t ident;
+};
+
+/**
+ * Reference to a string in a string pool.
+ */
+struct ResStringPool_ref
+{
+ // Index into the string pool table (uint32_t-offset from the indices
+ // immediately after ResStringPool_header) at which to find the location
+ // of the string data in the pool.
+ uint32_t index;
+};
+
+/** ********************************************************************
+ * String Pool
+ *
+ * A set of strings that can be references by others through a
+ * ResStringPool_ref.
+ *
+ *********************************************************************** */
+
+/**
+ * Definition for a pool of strings. The data of this chunk is an
+ * array of uint32_t providing indices into the pool, relative to
+ * stringsStart. At stringsStart are all of the UTF-16 strings
+ * concatenated together; each starts with a uint16_t of the string's
+ * length and each ends with a 0x0000 terminator. If a string is >
+ * 32767 characters, the high bit of the length is set meaning to take
+ * those 15 bits as a high word and it will be followed by another
+ * uint16_t containing the low word.
+ *
+ * If styleCount is not zero, then immediately following the array of
+ * uint32_t indices into the string table is another array of indices
+ * into a style table starting at stylesStart. Each entry in the
+ * style table is an array of ResStringPool_span structures.
+ */
+struct ResStringPool_header
+{
+ struct ResChunk_header header;
+
+ // Number of strings in this pool (number of uint32_t indices that follow
+ // in the data).
+ uint32_t stringCount;
+
+ // Number of style span arrays in the pool (number of uint32_t indices
+ // follow the string indices).
+ uint32_t styleCount;
+
+ // Flags.
+ enum {
+ // If set, the string index is sorted by the string values (based
+ // on strcmp16()).
+ SORTED_FLAG = 1<<0
+ };
+ uint32_t flags;
+
+ // Index from header of the string data.
+ uint32_t stringsStart;
+
+ // Index from header of the style data.
+ uint32_t stylesStart;
+};
+
+/**
+ * This structure defines a span of style information associated with
+ * a string in the pool.
+ */
+struct ResStringPool_span
+{
+ enum {
+ END = 0xFFFFFFFF
+ };
+
+ // This is the name of the span -- that is, the name of the XML
+ // tag that defined it. The special value END (0xFFFFFFFF) indicates
+ // the end of an array of spans.
+ ResStringPool_ref name;
+
+ // The range of characters in the string that this span applies to.
+ uint32_t firstChar, lastChar;
+};
+
+/**
+ * Convenience class for accessing data in a ResStringPool resource.
+ */
+class ResStringPool
+{
+public:
+ ResStringPool();
+ ResStringPool(const void* data, size_t size, bool copyData=false);
+ ~ResStringPool();
+
+ status_t setTo(const void* data, size_t size, bool copyData=false);
+
+ status_t getError() const;
+
+ void uninit();
+
+ inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const {
+ return stringAt(ref.index, outLen);
+ }
+ const char16_t* stringAt(size_t idx, size_t* outLen) const;
+
+ const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const;
+ const ResStringPool_span* styleAt(size_t idx) const;
+
+ ssize_t indexOfString(const char16_t* str, size_t strLen) const;
+
+ size_t size() const;
+
+private:
+ status_t mError;
+ void* mOwnedData;
+ const ResStringPool_header* mHeader;
+ size_t mSize;
+ const uint32_t* mEntries;
+ const uint32_t* mEntryStyles;
+ const char16_t* mStrings;
+ uint32_t mStringPoolSize; // number of uint16_t
+ const uint32_t* mStyles;
+ uint32_t mStylePoolSize; // number of uint32_t
+};
+
+/** ********************************************************************
+ * XML Tree
+ *
+ * Binary representation of an XML document. This is designed to
+ * express everything in an XML document, in a form that is much
+ * easier to parse on the device.
+ *
+ *********************************************************************** */
+
+/**
+ * XML tree header. This appears at the front of an XML tree,
+ * describing its content. It is followed by a flat array of
+ * ResXMLTree_node structures; the hierarchy of the XML document
+ * is described by the occurrance of RES_XML_START_ELEMENT_TYPE
+ * and corresponding RES_XML_END_ELEMENT_TYPE nodes in the array.
+ */
+struct ResXMLTree_header
+{
+ struct ResChunk_header header;
+};
+
+/**
+ * Basic XML tree node. A single item in the XML document. Extended info
+ * about the node can be found after header.headerSize.
+ */
+struct ResXMLTree_node
+{
+ struct ResChunk_header header;
+
+ // Line number in original source file at which this element appeared.
+ uint32_t lineNumber;
+
+ // Optional XML comment that was associated with this element; -1 if none.
+ struct ResStringPool_ref comment;
+};
+
+/**
+ * Extended XML tree node for CDATA tags -- includes the CDATA string.
+ * Appears header.headerSize bytes after a ResXMLTree_node.
+ */
+struct ResXMLTree_cdataExt
+{
+ // The raw CDATA character data.
+ struct ResStringPool_ref data;
+
+ // The typed value of the character data if this is a CDATA node.
+ struct Res_value typedData;
+};
+
+/**
+ * Extended XML tree node for namespace start/end nodes.
+ * Appears header.headerSize bytes after a ResXMLTree_node.
+ */
+struct ResXMLTree_namespaceExt
+{
+ // The prefix of the namespace.
+ struct ResStringPool_ref prefix;
+
+ // The URI of the namespace.
+ struct ResStringPool_ref uri;
+};
+
+/**
+ * Extended XML tree node for element start/end nodes.
+ * Appears header.headerSize bytes after a ResXMLTree_node.
+ */
+struct ResXMLTree_endElementExt
+{
+ // String of the full namespace of this element.
+ struct ResStringPool_ref ns;
+
+ // String name of this node if it is an ELEMENT; the raw
+ // character data if this is a CDATA node.
+ struct ResStringPool_ref name;
+};
+
+/**
+ * Extended XML tree node for start tags -- includes attribute
+ * information.
+ * Appears header.headerSize bytes after a ResXMLTree_node.
+ */
+struct ResXMLTree_attrExt
+{
+ // String of the full namespace of this element.
+ struct ResStringPool_ref ns;
+
+ // String name of this node if it is an ELEMENT; the raw
+ // character data if this is a CDATA node.
+ struct ResStringPool_ref name;
+
+ // Byte offset from the start of this structure where the attributes start.
+ uint16_t attributeStart;
+
+ // Size of the ResXMLTree_attribute structures that follow.
+ uint16_t attributeSize;
+
+ // Number of attributes associated with an ELEMENT. These are
+ // available as an array of ResXMLTree_attribute structures
+ // immediately following this node.
+ uint16_t attributeCount;
+
+ // Index (1-based) of the "id" attribute. 0 if none.
+ uint16_t idIndex;
+
+ // Index (1-based) of the "class" attribute. 0 if none.
+ uint16_t classIndex;
+
+ // Index (1-based) of the "style" attribute. 0 if none.
+ uint16_t styleIndex;
+};
+
+struct ResXMLTree_attribute
+{
+ // Namespace of this attribute.
+ struct ResStringPool_ref ns;
+
+ // Name of this attribute.
+ struct ResStringPool_ref name;
+
+ // The original raw string value of this attribute.
+ struct ResStringPool_ref rawValue;
+
+ // Processesd typed value of this attribute.
+ struct Res_value typedValue;
+};
+
+class ResXMLTree;
+
+class ResXMLParser
+{
+public:
+ ResXMLParser(const ResXMLTree& tree);
+
+ enum event_code_t {
+ BAD_DOCUMENT = -1,
+ START_DOCUMENT = 0,
+ END_DOCUMENT = 1,
+
+ FIRST_CHUNK_CODE = RES_XML_FIRST_CHUNK_TYPE,
+
+ START_NAMESPACE = RES_XML_START_NAMESPACE_TYPE,
+ END_NAMESPACE = RES_XML_END_NAMESPACE_TYPE,
+ START_TAG = RES_XML_START_ELEMENT_TYPE,
+ END_TAG = RES_XML_END_ELEMENT_TYPE,
+ TEXT = RES_XML_CDATA_TYPE
+ };
+
+ struct ResXMLPosition
+ {
+ event_code_t eventCode;
+ const ResXMLTree_node* curNode;
+ const void* curExt;
+ };
+
+ void restart();
+
+ event_code_t getEventType() const;
+ // Note, unlike XmlPullParser, the first call to next() will return
+ // START_TAG of the first element.
+ event_code_t next();
+
+ // These are available for all nodes:
+ const int32_t getCommentID() const;
+ const uint16_t* getComment(size_t* outLen) const;
+ const uint32_t getLineNumber() const;
+
+ // This is available for TEXT:
+ const int32_t getTextID() const;
+ const uint16_t* getText(size_t* outLen) const;
+ ssize_t getTextValue(Res_value* outValue) const;
+
+ // These are available for START_NAMESPACE and END_NAMESPACE:
+ const int32_t getNamespacePrefixID() const;
+ const uint16_t* getNamespacePrefix(size_t* outLen) const;
+ const int32_t getNamespaceUriID() const;
+ const uint16_t* getNamespaceUri(size_t* outLen) const;
+
+ // These are available for START_TAG and END_TAG:
+ const int32_t getElementNamespaceID() const;
+ const uint16_t* getElementNamespace(size_t* outLen) const;
+ const int32_t getElementNameID() const;
+ const uint16_t* getElementName(size_t* outLen) const;
+
+ // Remaining methods are for retrieving information about attributes
+ // associated with a START_TAG:
+
+ size_t getAttributeCount() const;
+
+ // Returns -1 if no namespace, -2 if idx out of range.
+ const int32_t getAttributeNamespaceID(size_t idx) const;
+ const uint16_t* getAttributeNamespace(size_t idx, size_t* outLen) const;
+
+ const int32_t getAttributeNameID(size_t idx) const;
+ const uint16_t* getAttributeName(size_t idx, size_t* outLen) const;
+ const uint32_t getAttributeNameResID(size_t idx) const;
+
+ const int32_t getAttributeValueStringID(size_t idx) const;
+ const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const;
+
+ int32_t getAttributeDataType(size_t idx) const;
+ int32_t getAttributeData(size_t idx) const;
+ ssize_t getAttributeValue(size_t idx, Res_value* outValue) const;
+
+ ssize_t indexOfAttribute(const char* ns, const char* attr) const;
+ ssize_t indexOfAttribute(const char16_t* ns, size_t nsLen,
+ const char16_t* attr, size_t attrLen) const;
+
+ ssize_t indexOfID() const;
+ ssize_t indexOfClass() const;
+ ssize_t indexOfStyle() const;
+
+ void getPosition(ResXMLPosition* pos) const;
+ void setPosition(const ResXMLPosition& pos);
+
+private:
+ friend class ResXMLTree;
+
+ event_code_t nextNode();
+
+ const ResXMLTree& mTree;
+ event_code_t mEventCode;
+ const ResXMLTree_node* mCurNode;
+ const void* mCurExt;
+};
+
+/**
+ * Convenience class for accessing data in a ResXMLTree resource.
+ */
+class ResXMLTree : public ResXMLParser
+{
+public:
+ ResXMLTree();
+ ResXMLTree(const void* data, size_t size, bool copyData=false);
+ ~ResXMLTree();
+
+ status_t setTo(const void* data, size_t size, bool copyData=false);
+
+ status_t getError() const;
+
+ void uninit();
+
+ const ResStringPool& getStrings() const;
+
+private:
+ friend class ResXMLParser;
+
+ status_t validateNode(const ResXMLTree_node* node) const;
+
+ status_t mError;
+ void* mOwnedData;
+ const ResXMLTree_header* mHeader;
+ size_t mSize;
+ const uint8_t* mDataEnd;
+ ResStringPool mStrings;
+ const uint32_t* mResIds;
+ size_t mNumResIds;
+ const ResXMLTree_node* mRootNode;
+ const void* mRootExt;
+ event_code_t mRootCode;
+};
+
+/** ********************************************************************
+ * RESOURCE TABLE
+ *
+ *********************************************************************** */
+
+/**
+ * Header for a resource table. Its data contains a series of
+ * additional chunks:
+ * * A ResStringPool_header containing all table values.
+ * * One or more ResTable_package chunks.
+ *
+ * Specific entries within a resource table can be uniquely identified
+ * with a single integer as defined by the ResTable_ref structure.
+ */
+struct ResTable_header
+{
+ struct ResChunk_header header;
+
+ // The number of ResTable_package structures.
+ uint32_t packageCount;
+};
+
+/**
+ * A collection of resource data types within a package. Followed by
+ * one or more ResTable_type and ResTable_typeSpec structures containing the
+ * entry values for each resource type.
+ */
+struct ResTable_package
+{
+ struct ResChunk_header header;
+
+ // If this is a base package, its ID. Package IDs start
+ // at 1 (corresponding to the value of the package bits in a
+ // resource identifier). 0 means this is not a base package.
+ uint32_t id;
+
+ // Actual name of this package, \0-terminated.
+ char16_t name[128];
+
+ // Offset to a ResStringPool_header defining the resource
+ // type symbol table. If zero, this package is inheriting from
+ // another base package (overriding specific values in it).
+ uint32_t typeStrings;
+
+ // Last index into typeStrings that is for public use by others.
+ uint32_t lastPublicType;
+
+ // Offset to a ResStringPool_header defining the resource
+ // key symbol table. If zero, this package is inheriting from
+ // another base package (overriding specific values in it).
+ uint32_t keyStrings;
+
+ // Last index into keyStrings that is for public use by others.
+ uint32_t lastPublicKey;
+};
+
+/**
+ * Describes a particular resource configuration.
+ */
+struct ResTable_config
+{
+ // Number of bytes in this structure.
+ uint32_t size;
+
+ union {
+ struct {
+ // Mobile country code (from SIM). 0 means "any".
+ uint16_t mcc;
+ // Mobile network code (from SIM). 0 means "any".
+ uint16_t mnc;
+ };
+ uint32_t imsi;
+ };
+
+ union {
+ struct {
+ // \0\0 means "any". Otherwise, en, fr, etc.
+ char language[2];
+
+ // \0\0 means "any". Otherwise, US, CA, etc.
+ char country[2];
+ };
+ uint32_t locale;
+ };
+
+ enum {
+ ORIENTATION_ANY = 0x0000,
+ ORIENTATION_PORT = 0x0001,
+ ORIENTATION_LAND = 0x0002,
+ ORIENTATION_SQUARE = 0x0002,
+ };
+
+ enum {
+ TOUCHSCREEN_ANY = 0x0000,
+ TOUCHSCREEN_NOTOUCH = 0x0001,
+ TOUCHSCREEN_STYLUS = 0x0002,
+ TOUCHSCREEN_FINGER = 0x0003,
+ };
+
+ enum {
+ DENSITY_ANY = 0
+ };
+
+ union {
+ struct {
+ uint8_t orientation;
+ uint8_t touchscreen;
+ uint16_t density;
+ };
+ uint32_t screenType;
+ };
+
+ enum {
+ KEYBOARD_ANY = 0x0000,
+ KEYBOARD_NOKEYS = 0x0001,
+ KEYBOARD_QWERTY = 0x0002,
+ KEYBOARD_12KEY = 0x0003,
+ };
+
+ enum {
+ NAVIGATION_ANY = 0x0000,
+ NAVIGATION_NONAV = 0x0001,
+ NAVIGATION_DPAD = 0x0002,
+ NAVIGATION_TRACKBALL = 0x0003,
+ NAVIGATION_WHEEL = 0x0004,
+ };
+
+ enum {
+ MASK_KEYSHIDDEN = 0x0003,
+ SHIFT_KEYSHIDDEN = 0,
+ KEYSHIDDEN_ANY = 0x0000,
+ KEYSHIDDEN_NO = 0x0001,
+ KEYSHIDDEN_YES = 0x0002,
+ };
+
+ union {
+ struct {
+ uint8_t keyboard;
+ uint8_t navigation;
+ uint8_t inputFlags;
+ uint8_t pad0;
+ };
+ uint32_t input;
+ };
+
+ enum {
+ SCREENWIDTH_ANY = 0
+ };
+
+ enum {
+ SCREENHEIGHT_ANY = 0
+ };
+
+ union {
+ struct {
+ uint16_t screenWidth;
+ uint16_t screenHeight;
+ };
+ uint32_t screenSize;
+ };
+
+ enum {
+ SDKVERSION_ANY = 0
+ };
+
+ enum {
+ MINORVERSION_ANY = 0
+ };
+
+ union {
+ struct {
+ uint16_t sdkVersion;
+ // For now minorVersion must always be 0!!! Its meaning
+ // is currently undefined.
+ uint16_t minorVersion;
+ };
+ uint32_t version;
+ };
+
+ inline void copyFromDeviceNoSwap(const ResTable_config& o) {
+ const size_t size = dtohl(o.size);
+ if (size >= sizeof(ResTable_config)) {
+ *this = o;
+ } else {
+ memcpy(this, &o, size);
+ memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
+ }
+ }
+
+ inline void copyFromDtoH(const ResTable_config& o) {
+ copyFromDeviceNoSwap(o);
+ size = sizeof(ResTable_config);
+ mcc = dtohs(mcc);
+ mnc = dtohs(mnc);
+ density = dtohs(density);
+ screenWidth = dtohs(screenWidth);
+ screenHeight = dtohs(screenHeight);
+ sdkVersion = dtohs(sdkVersion);
+ minorVersion = dtohs(minorVersion);
+ }
+
+ inline void swapHtoD() {
+ size = htodl(size);
+ mcc = htods(mcc);
+ mnc = htods(mnc);
+ density = htods(density);
+ screenWidth = htods(screenWidth);
+ screenHeight = htods(screenHeight);
+ sdkVersion = htods(sdkVersion);
+ minorVersion = htods(minorVersion);
+ }
+
+ inline int compare(const ResTable_config& o) const {
+ int32_t diff = (int32_t)(imsi - o.imsi);
+ if (diff != 0) return diff;
+ diff = (int32_t)(locale - o.locale);
+ if (diff != 0) return diff;
+ diff = (int32_t)(screenType - o.screenType);
+ if (diff != 0) return diff;
+ diff = (int32_t)(input - o.input);
+ if (diff != 0) return diff;
+ diff = (int32_t)(screenSize - o.screenSize);
+ if (diff != 0) return diff;
+ diff = (int32_t)(version - o.version);
+ return (int)diff;
+ }
+
+ // Flags indicating a set of config values. These flag constants must
+ // match the corresponding ones in android.content.pm.ActivityInfo and
+ // attrs_manifest.xml.
+ enum {
+ CONFIG_MCC = 0x0001,
+ CONFIG_MNC = 0x0002,
+ CONFIG_LOCALE = 0x0004,
+ CONFIG_TOUCHSCREEN = 0x0008,
+ CONFIG_KEYBOARD = 0x0010,
+ CONFIG_KEYBOARD_HIDDEN = 0x0020,
+ CONFIG_NAVIGATION = 0x0040,
+ CONFIG_ORIENTATION = 0x0080,
+ CONFIG_DENSITY = 0x0100,
+ CONFIG_SCREEN_SIZE = 0x0200,
+ CONFIG_VERSION = 0x0400
+ };
+
+ // Compare two configuration, returning CONFIG_* flags set for each value
+ // that is different.
+ inline int diff(const ResTable_config& o) const {
+ int diffs = 0;
+ if (mcc != o.mcc) diffs |= CONFIG_MCC;
+ if (mnc != o.mnc) diffs |= CONFIG_MNC;
+ if (locale != o.locale) diffs |= CONFIG_LOCALE;
+ if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
+ if (density != o.density) diffs |= CONFIG_DENSITY;
+ if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
+ if (((inputFlags^o.inputFlags)&MASK_KEYSHIDDEN) != 0) diffs |= CONFIG_KEYBOARD_HIDDEN;
+ if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
+ if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
+ if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
+ if (version != o.version) diffs |= CONFIG_VERSION;
+ return diffs;
+ }
+
+ // Return true if 'this' is more specific than 'o'.
+ inline bool
+ isBetterThan(const ResTable_config& o, const ResTable_config* requested = NULL) const {
+ if (imsi != 0 && (!requested || requested->imsi != 0)) {
+ if (mcc != 0 && (!requested || requested->mcc!= 0)) {
+ if (o.mcc == 0) {
+ return true;
+ }
+ }
+ if (mnc != 0 && (!requested || requested->mnc != 0)) {
+ if (o.mnc == 0) {
+ return true;
+ }
+ }
+ }
+ if (locale != 0 && (!requested || requested->locale != 0)) {
+ if (language[0] != 0 && (!requested || requested->language[0] != 0)) {
+ if (o.language[0] == 0) {
+ return true;
+ }
+ }
+ if (country[0] != 0 && (!requested || requested->country[0] != 0)) {
+ if (o.country[0] == 0) {
+ return true;
+ }
+ }
+ }
+ if (screenType != 0 && (!requested || requested->screenType != 0)) {
+ if (orientation != 0 && (!requested || requested->orientation != 0)) {
+ if (o.orientation == 0) {
+ return true;
+ }
+ }
+ if (density != 0 && (!requested || requested->density != 0)) {
+ if (o.density == 0) {
+ return true;
+ }
+ }
+ if (touchscreen != 0 && (!requested || requested->touchscreen != 0)) {
+ if (o.touchscreen == 0) {
+ return true;
+ }
+ }
+ }
+ if (input != 0 && (!requested || requested->input != 0)) {
+ if ((inputFlags&MASK_KEYSHIDDEN) != 0 && (!requested
+ || (requested->inputFlags&MASK_KEYSHIDDEN) != 0)) {
+ if ((o.inputFlags&MASK_KEYSHIDDEN) == 0) {
+ return true;
+ }
+ }
+ if (keyboard != 0 && (!requested || requested->keyboard != 0)) {
+ if (o.keyboard == 0) {
+ return true;
+ }
+ }
+ if (navigation != 0 && (!requested || requested->navigation != 0)) {
+ if (o.navigation == 0) {
+ return true;
+ }
+ }
+ }
+ if (screenSize != 0 && (!requested || requested->screenSize != 0)) {
+ if (screenWidth != 0 && (!requested || requested->screenWidth != 0)) {
+ if (o.screenWidth == 0) {
+ return true;
+ }
+ }
+ if (screenHeight != 0 && (!requested || requested->screenHeight != 0)) {
+ if (o.screenHeight == 0) {
+ return true;
+ }
+ }
+ }
+ if (version != 0 && (!requested || requested->version != 0)) {
+ if (sdkVersion != 0 && (!requested || requested->sdkVersion != 0)) {
+ if (o.sdkVersion == 0) {
+ return true;
+ }
+ }
+ if (minorVersion != 0 && (!requested || requested->minorVersion != 0)) {
+ if (o.minorVersion == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // Return true if 'this' matches the parameters in 'settings'.
+ inline bool match(const ResTable_config& settings) const {
+ if (imsi != 0) {
+ if (settings.mcc != 0 && mcc != 0
+ && mcc != settings.mcc) {
+ return false;
+ }
+ if (settings.mnc != 0 && mnc != 0
+ && mnc != settings.mnc) {
+ return false;
+ }
+ }
+ if (locale != 0) {
+ if (settings.language[0] != 0 && language[0] != 0
+ && (language[0] != settings.language[0]
+ || language[1] != settings.language[1])) {
+ return false;
+ }
+ if (settings.country[0] != 0 && country[0] != 0
+ && (country[0] != settings.country[0]
+ || country[1] != settings.country[1])) {
+ return false;
+ }
+ }
+ if (screenType != 0) {
+ if (settings.orientation != 0 && orientation != 0
+ && orientation != settings.orientation) {
+ return false;
+ }
+ if (settings.density != 0 && density != 0
+ && density != settings.density) {
+ return false;
+ }
+ if (settings.touchscreen != 0 && touchscreen != 0
+ && touchscreen != settings.touchscreen) {
+ return false;
+ }
+ }
+ if (input != 0) {
+ const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
+ const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
+ if (setKeysHidden != 0 && keysHidden != 0
+ && keysHidden != setKeysHidden) {
+ return false;
+ }
+ if (settings.keyboard != 0 && keyboard != 0
+ && keyboard != settings.keyboard) {
+ return false;
+ }
+ if (settings.navigation != 0 && navigation != 0
+ && navigation != settings.navigation) {
+ return false;
+ }
+ }
+ if (screenSize != 0) {
+ if (settings.screenWidth != 0 && screenWidth != 0
+ && screenWidth != settings.screenWidth) {
+ return false;
+ }
+ if (settings.screenHeight != 0 && screenHeight != 0
+ && screenHeight != settings.screenHeight) {
+ return false;
+ }
+ }
+ if (version != 0) {
+ if (settings.sdkVersion != 0 && sdkVersion != 0
+ && sdkVersion != settings.sdkVersion) {
+ return false;
+ }
+ if (settings.minorVersion != 0 && minorVersion != 0
+ && minorVersion != settings.minorVersion) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void getLocale(char str[6]) const {
+ memset(str, 0, 6);
+ if (language[0]) {
+ str[0] = language[0];
+ str[1] = language[1];
+ if (country[0]) {
+ str[2] = '_';
+ str[3] = country[0];
+ str[4] = country[1];
+ }
+ }
+ }
+
+ String8 toString() const {
+ char buf[200];
+ sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=0x%02x touch=0x%02x dens=0x%02x "
+ "kbd=0x%02x nav=0x%02x input=0x%02x screenW=0x%04x screenH=0x%04x vers=%d.%d",
+ mcc, mnc,
+ language[0] ? language[0] : '-', language[1] ? language[1] : '-',
+ country[0] ? country[0] : '-', country[1] ? country[1] : '-',
+ orientation, touchscreen, density, keyboard, navigation, inputFlags,
+ screenWidth, screenHeight, sdkVersion, minorVersion);
+ return String8(buf);
+ }
+};
+
+/**
+ * A specification of the resources defined by a particular type.
+ *
+ * There should be one of these chunks for each resource type.
+ *
+ * This structure is followed by an array of integers providing the set of
+ * configuation change flags (ResTable_config::CONFIG_*) that have multiple
+ * resources for that configuration. In addition, the high bit is set if that
+ * resource has been made public.
+ */
+struct ResTable_typeSpec
+{
+ struct ResChunk_header header;
+
+ // The type identifier this chunk is holding. Type IDs start
+ // at 1 (corresponding to the value of the type bits in a
+ // resource identifier). 0 is invalid.
+ uint8_t id;
+
+ // Must be 0.
+ uint8_t res0;
+ // Must be 0.
+ uint16_t res1;
+
+ // Number of uint32_t entry configuration masks that follow.
+ uint32_t entryCount;
+
+ enum {
+ // Additional flag indicating an entry is public.
+ SPEC_PUBLIC = 0x40000000
+ };
+};
+
+/**
+ * A collection of resource entries for a particular resource data
+ * type. Followed by an array of uint32_t defining the resource
+ * values, corresponding to the array of type strings in the
+ * ResTable_package::typeStrings string block. Each of these hold an
+ * index from entriesStart; a value of NO_ENTRY means that entry is
+ * not defined.
+ *
+ * There may be multiple of these chunks for a particular resource type,
+ * supply different configuration variations for the resource values of
+ * that type.
+ *
+ * It would be nice to have an additional ordered index of entries, so
+ * we can do a binary search if trying to find a resource by string name.
+ */
+struct ResTable_type
+{
+ struct ResChunk_header header;
+
+ enum {
+ NO_ENTRY = 0xFFFFFFFF
+ };
+
+ // The type identifier this chunk is holding. Type IDs start
+ // at 1 (corresponding to the value of the type bits in a
+ // resource identifier). 0 is invalid.
+ uint8_t id;
+
+ // Must be 0.
+ uint8_t res0;
+ // Must be 0.
+ uint16_t res1;
+
+ // Number of uint32_t entry indices that follow.
+ uint32_t entryCount;
+
+ // Offset from header where ResTable_entry data starts.
+ uint32_t entriesStart;
+
+ // Configuration this collection of entries is designed for.
+ ResTable_config config;
+};
+
+/**
+ * This is the beginning of information about an entry in the resource
+ * table. It holds the reference to the name of this entry, and is
+ * immediately followed by one of:
+ * * A Res_value structures, if FLAG_COMPLEX is -not- set.
+ * * An array of ResTable_map structures, if FLAG_COMPLEX is set.
+ * These supply a set of name/value mappings of data.
+ */
+struct ResTable_entry
+{
+ // Number of bytes in this structure.
+ uint16_t size;
+
+ enum {
+ // If set, this is a complex entry, holding a set of name/value
+ // mappings. It is followed by an array of ResTable_map structures.
+ FLAG_COMPLEX = 0x0001,
+ // If set, this resource has been declared public, so libraries
+ // are allowed to reference it.
+ FLAG_PUBLIC = 0x0002
+ };
+ uint16_t flags;
+
+ // Reference into ResTable_package::keyStrings identifying this entry.
+ struct ResStringPool_ref key;
+};
+
+/**
+ * Extended form of a ResTable_entry for map entries, defining a parent map
+ * resource from which to inherit values.
+ */
+struct ResTable_map_entry : public ResTable_entry
+{
+ // Resource identifier of the parent mapping, or 0 if there is none.
+ ResTable_ref parent;
+ // Number of name/value pairs that follow for FLAG_COMPLEX.
+ uint32_t count;
+};
+
+/**
+ * A single name/value mapping that is part of a complex resource
+ * entry.
+ */
+struct ResTable_map
+{
+ // The resource identifier defining this mapping's name. For attribute
+ // resources, 'name' can be one of the following special resource types
+ // to supply meta-data about the attribute; for all other resource types
+ // it must be an attribute resource.
+ ResTable_ref name;
+
+ // Special values for 'name' when defining attribute resources.
+ enum {
+ // This entry holds the attribute's type code.
+ ATTR_TYPE = Res_MAKEINTERNAL(0),
+
+ // For integral attributes, this is the minimum value it can hold.
+ ATTR_MIN = Res_MAKEINTERNAL(1),
+
+ // For integral attributes, this is the maximum value it can hold.
+ ATTR_MAX = Res_MAKEINTERNAL(2),
+
+ // Localization of this resource is can be encouraged or required with
+ // an aapt flag if this is set
+ ATTR_L10N = Res_MAKEINTERNAL(3),
+
+ // for plural support, see android.content.res.PluralRules#attrForQuantity(int)
+ ATTR_OTHER = Res_MAKEINTERNAL(4),
+ ATTR_ZERO = Res_MAKEINTERNAL(5),
+ ATTR_ONE = Res_MAKEINTERNAL(6),
+ ATTR_TWO = Res_MAKEINTERNAL(7),
+ ATTR_FEW = Res_MAKEINTERNAL(8),
+ ATTR_MANY = Res_MAKEINTERNAL(9)
+
+ };
+
+ // Bit mask of allowed types, for use with ATTR_TYPE.
+ enum {
+ // No type has been defined for this attribute, use generic
+ // type handling. The low 16 bits are for types that can be
+ // handled generically; the upper 16 require additional information
+ // in the bag so can not be handled generically for TYPE_ANY.
+ TYPE_ANY = 0x0000FFFF,
+
+ // Attribute holds a references to another resource.
+ TYPE_REFERENCE = 1<<0,
+
+ // Attribute holds a generic string.
+ TYPE_STRING = 1<<1,
+
+ // Attribute holds an integer value. ATTR_MIN and ATTR_MIN can
+ // optionally specify a constrained range of possible integer values.
+ TYPE_INTEGER = 1<<2,
+
+ // Attribute holds a boolean integer.
+ TYPE_BOOLEAN = 1<<3,
+
+ // Attribute holds a color value.
+ TYPE_COLOR = 1<<4,
+
+ // Attribute holds a floating point value.
+ TYPE_FLOAT = 1<<5,
+
+ // Attribute holds a dimension value, such as "20px".
+ TYPE_DIMENSION = 1<<6,
+
+ // Attribute holds a fraction value, such as "20%".
+ TYPE_FRACTION = 1<<7,
+
+ // Attribute holds an enumeration. The enumeration values are
+ // supplied as additional entries in the map.
+ TYPE_ENUM = 1<<16,
+
+ // Attribute holds a bitmaks of flags. The flag bit values are
+ // supplied as additional entries in the map.
+ TYPE_FLAGS = 1<<17
+ };
+
+ // Enum of localization modes, for use with ATTR_L10N.
+ enum {
+ L10N_NOT_REQUIRED = 0,
+ L10N_SUGGESTED = 1
+ };
+
+ // This mapping's value.
+ Res_value value;
+};
+
+/**
+ * Convenience class for accessing data in a ResTable resource.
+ */
+class ResTable
+{
+public:
+ ResTable();
+ ResTable(const void* data, size_t size, void* cookie,
+ bool copyData=false);
+ ~ResTable();
+
+ status_t add(const void* data, size_t size, void* cookie,
+ bool copyData=false);
+ status_t add(Asset* asset, void* cookie,
+ bool copyData=false);
+
+ status_t getError() const;
+
+ void uninit();
+
+ struct resource_name
+ {
+ const char16_t* package;
+ size_t packageLen;
+ const char16_t* type;
+ size_t typeLen;
+ const char16_t* name;
+ size_t nameLen;
+ };
+
+ bool getResourceName(uint32_t resID, resource_name* outName) const;
+
+ /**
+ * Retrieve the value of a resource. If the resource is found, returns a
+ * value >= 0 indicating the table it is in (for use with
+ * getTableStringBlock() and getTableCookie()) and fills in 'outValue'. If
+ * not found, returns a negative error code.
+ *
+ * Note that this function does not do reference traversal. If you want
+ * to follow references to other resources to get the "real" value to
+ * use, you need to call resolveReference() after this function.
+ *
+ * @param resID The desired resoruce identifier.
+ * @param outValue Filled in with the resource data that was found.
+ *
+ * @return ssize_t Either a >= 0 table index or a negative error code.
+ */
+ ssize_t getResource(uint32_t resID, Res_value* outValue, bool mayBeBag=false,
+ uint32_t* outSpecFlags=NULL) const;
+
+ inline ssize_t getResource(const ResTable_ref& res, Res_value* outValue,
+ uint32_t* outSpecFlags=NULL) const {
+ return getResource(res.ident, outValue, outSpecFlags);
+ }
+
+ ssize_t resolveReference(Res_value* inOutValue,
+ ssize_t blockIndex,
+ uint32_t* outLastRef = NULL,
+ uint32_t* inoutTypeSpecFlags = NULL) const;
+
+ enum {
+ TMP_BUFFER_SIZE = 16
+ };
+ const char16_t* valueToString(const Res_value* value, size_t stringBlock,
+ char16_t tmpBuffer[TMP_BUFFER_SIZE],
+ size_t* outLen);
+
+ struct bag_entry {
+ ssize_t stringBlock;
+ ResTable_map map;
+ };
+
+ /**
+ * Retrieve the bag of a resource. If the resoruce is found, returns the
+ * number of bags it contains and 'outBag' points to an array of their
+ * values. If not found, a negative error code is returned.
+ *
+ * Note that this function -does- do reference traversal of the bag data.
+ *
+ * @param resID The desired resource identifier.
+ * @param outBag Filled inm with a pointer to the bag mappings.
+ *
+ * @return ssize_t Either a >= 0 bag count of negative error code.
+ */
+ ssize_t lockBag(uint32_t resID, const bag_entry** outBag) const;
+
+ void unlockBag(const bag_entry* bag) const;
+
+ void lock() const;
+
+ ssize_t getBagLocked(uint32_t resID, const bag_entry** outBag,
+ uint32_t* outTypeSpecFlags=NULL) const;
+
+ void unlock() const;
+
+ class Theme {
+ public:
+ Theme(const ResTable& table);
+ ~Theme();
+
+ inline const ResTable& getResTable() const { return mTable; }
+
+ status_t applyStyle(uint32_t resID, bool force=false);
+ status_t setTo(const Theme& other);
+
+ /**
+ * Retrieve a value in the theme. If the theme defines this
+ * value, returns a value >= 0 indicating the table it is in
+ * (for use with getTableStringBlock() and getTableCookie) and
+ * fills in 'outValue'. If not found, returns a negative error
+ * code.
+ *
+ * Note that this function does not do reference traversal. If you want
+ * to follow references to other resources to get the "real" value to
+ * use, you need to call resolveReference() after this function.
+ *
+ * @param resID A resource identifier naming the desired theme
+ * attribute.
+ * @param outValue Filled in with the theme value that was
+ * found.
+ *
+ * @return ssize_t Either a >= 0 table index or a negative error code.
+ */
+ ssize_t getAttribute(uint32_t resID, Res_value* outValue,
+ uint32_t* outTypeSpecFlags = NULL) const;
+
+ /**
+ * This is like ResTable::resolveReference(), but also takes
+ * care of resolving attribute references to the theme.
+ */
+ ssize_t resolveAttributeReference(Res_value* inOutValue,
+ ssize_t blockIndex, uint32_t* outLastRef = NULL,
+ uint32_t* inoutTypeSpecFlags = NULL) const;
+
+ void dumpToLog() const;
+
+ private:
+ Theme(const Theme&);
+ Theme& operator=(const Theme&);
+
+ struct theme_entry {
+ ssize_t stringBlock;
+ uint32_t typeSpecFlags;
+ Res_value value;
+ };
+ struct type_info {
+ size_t numEntries;
+ theme_entry* entries;
+ };
+ struct package_info {
+ size_t numTypes;
+ type_info types[];
+ };
+
+ void free_package(package_info* pi);
+ package_info* copy_package(package_info* pi);
+
+ const ResTable& mTable;
+ package_info* mPackages[Res_MAXPACKAGE];
+ };
+
+ void setParameters(const ResTable_config* params);
+ void getParameters(ResTable_config* params) const;
+
+ // Retrieve an identifier (which can be passed to getResource)
+ // for a given resource name. The 'name' can be fully qualified
+ // (<package>:<type>.<basename>) or the package or type components
+ // can be dropped if default values are supplied here.
+ //
+ // Returns 0 if no such resource was found, else a valid resource ID.
+ uint32_t identifierForName(const char16_t* name, size_t nameLen,
+ const char16_t* type = 0, size_t typeLen = 0,
+ const char16_t* defPackage = 0,
+ size_t defPackageLen = 0,
+ uint32_t* outTypeSpecFlags = NULL) const;
+
+ static bool expandResourceRef(const uint16_t* refStr, size_t refLen,
+ String16* outPackage,
+ String16* outType,
+ String16* outName,
+ const String16* defType = NULL,
+ const String16* defPackage = NULL,
+ const char** outErrorMsg = NULL);
+
+ static bool stringToInt(const char16_t* s, size_t len, Res_value* outValue);
+ static bool stringToFloat(const char16_t* s, size_t len, Res_value* outValue);
+
+ // Used with stringToValue.
+ class Accessor
+ {
+ public:
+ inline virtual ~Accessor() { }
+
+ virtual uint32_t getCustomResource(const String16& package,
+ const String16& type,
+ const String16& name) const = 0;
+ virtual uint32_t getCustomResourceWithCreation(const String16& package,
+ const String16& type,
+ const String16& name,
+ const bool createIfNeeded = false) = 0;
+ virtual uint32_t getRemappedPackage(uint32_t origPackage) const = 0;
+ virtual bool getAttributeType(uint32_t attrID, uint32_t* outType) = 0;
+ virtual bool getAttributeMin(uint32_t attrID, uint32_t* outMin) = 0;
+ virtual bool getAttributeMax(uint32_t attrID, uint32_t* outMax) = 0;
+ virtual bool getAttributeEnum(uint32_t attrID,
+ const char16_t* name, size_t nameLen,
+ Res_value* outValue) = 0;
+ virtual bool getAttributeFlags(uint32_t attrID,
+ const char16_t* name, size_t nameLen,
+ Res_value* outValue) = 0;
+ virtual uint32_t getAttributeL10N(uint32_t attrID) = 0;
+ virtual bool getLocalizationSetting() = 0;
+ virtual void reportError(void* accessorCookie, const char* fmt, ...) = 0;
+ };
+
+ // Convert a string to a resource value. Handles standard "@res",
+ // "#color", "123", and "0x1bd" types; performs escaping of strings.
+ // The resulting value is placed in 'outValue'; if it is a string type,
+ // 'outString' receives the string. If 'attrID' is supplied, the value is
+ // type checked against this attribute and it is used to perform enum
+ // evaluation. If 'acccessor' is supplied, it will be used to attempt to
+ // resolve resources that do not exist in this ResTable. If 'attrType' is
+ // supplied, the value will be type checked for this format if 'attrID'
+ // is not supplied or found.
+ bool stringToValue(Res_value* outValue, String16* outString,
+ const char16_t* s, size_t len,
+ bool preserveSpaces, bool coerceType,
+ uint32_t attrID = 0,
+ const String16* defType = NULL,
+ const String16* defPackage = NULL,
+ Accessor* accessor = NULL,
+ void* accessorCookie = NULL,
+ uint32_t attrType = ResTable_map::TYPE_ANY,
+ bool enforcePrivate = true) const;
+
+ // Perform processing of escapes and quotes in a string.
+ static bool collectString(String16* outString,
+ const char16_t* s, size_t len,
+ bool preserveSpaces,
+ const char** outErrorMsg = NULL,
+ bool append = false);
+
+ size_t getBasePackageCount() const;
+ const char16_t* getBasePackageName(size_t idx) const;
+ uint32_t getBasePackageId(size_t idx) const;
+
+ size_t getTableCount() const;
+ const ResStringPool* getTableStringBlock(size_t index) const;
+ void* getTableCookie(size_t index) const;
+
+ // Return the configurations (ResTable_config) that we know about
+ void getConfigurations(Vector<ResTable_config>* configs) const;
+
+ void getLocales(Vector<String8>* locales) const;
+
+#ifndef HAVE_ANDROID_OS
+ void print() const;
+#endif
+
+private:
+ struct Header;
+ struct Type;
+ struct Package;
+ struct PackageGroup;
+ struct bag_set;
+
+ status_t add(const void* data, size_t size, void* cookie,
+ Asset* asset, bool copyData);
+
+ ssize_t getResourcePackageIndex(uint32_t resID) const;
+ ssize_t getEntry(
+ const Package* package, int typeIndex, int entryIndex,
+ const ResTable_config* config,
+ const ResTable_type** outType, const ResTable_entry** outEntry,
+ const Type** outTypeClass) const;
+ status_t parsePackage(
+ const ResTable_package* const pkg, const Header* const header);
+
+ mutable Mutex mLock;
+
+ status_t mError;
+
+ ResTable_config mParams;
+
+ // Array of all resource tables.
+ Vector<Header*> mHeaders;
+
+ // Array of packages in all resource tables.
+ Vector<PackageGroup*> mPackageGroups;
+
+ // Mapping from resource package IDs to indices into the internal
+ // package array.
+ uint8_t mPackageMap[256];
+};
+
+} // namespace android
+
+#endif // _LIBS_UTILS_RESOURCE_TYPES_H
diff --git a/include/utils/SharedBuffer.h b/include/utils/SharedBuffer.h
new file mode 100644
index 0000000..24508b0
--- /dev/null
+++ b/include/utils/SharedBuffer.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005 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_SHARED_BUFFER_H
+#define ANDROID_SHARED_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class SharedBuffer
+{
+public:
+
+ /* flags to use with release() */
+ enum {
+ eKeepStorage = 0x00000001
+ };
+
+ /*! allocate a buffer of size 'size' and acquire() it.
+ * call release() to free it.
+ */
+ static SharedBuffer* alloc(size_t size);
+
+ /*! free the memory associated with the SharedBuffer.
+ * Fails if there are any users associated with this SharedBuffer.
+ * In other words, the buffer must have been release by all its
+ * users.
+ */
+ static ssize_t dealloc(const SharedBuffer* released);
+
+ //! get the SharedBuffer from the data pointer
+ static inline const SharedBuffer* sharedBuffer(const void* data);
+
+ //! access the data for read
+ inline const void* data() const;
+
+ //! access the data for read/write
+ inline void* data();
+
+ //! get size of the buffer
+ inline size_t size() const;
+
+ //! get back a SharedBuffer object from its data
+ static inline SharedBuffer* bufferFromData(void* data);
+
+ //! get back a SharedBuffer object from its data
+ static inline const SharedBuffer* bufferFromData(const void* data);
+
+ //! get the size of a SharedBuffer object from its data
+ static inline size_t sizeFromData(const void* data);
+
+ //! edit the buffer (get a writtable, or non-const, version of it)
+ SharedBuffer* edit() const;
+
+ //! edit the buffer, resizing if needed
+ SharedBuffer* editResize(size_t size) const;
+
+ //! like edit() but fails if a copy is required
+ SharedBuffer* attemptEdit() const;
+
+ //! resize and edit the buffer, loose it's content.
+ SharedBuffer* reset(size_t size) const;
+
+ //! acquire/release a reference on this buffer
+ void acquire() const;
+
+ /*! release a reference on this buffer, with the option of not
+ * freeing the memory associated with it if it was the last reference
+ * returns the previous reference count
+ */
+ int32_t release(uint32_t flags = 0) const;
+
+ //! returns wether or not we're the only owner
+ inline bool onlyOwner() const;
+
+
+private:
+ inline SharedBuffer() { }
+ inline ~SharedBuffer() { }
+ inline SharedBuffer(const SharedBuffer&);
+
+ // 16 bytes. must be sized to preserve correct alingment.
+ mutable int32_t mRefs;
+ size_t mSize;
+ uint32_t mReserved[2];
+};
+
+// ---------------------------------------------------------------------------
+
+const SharedBuffer* SharedBuffer::sharedBuffer(const void* data) {
+ return data ? reinterpret_cast<const SharedBuffer *>(data)-1 : 0;
+}
+
+const void* SharedBuffer::data() const {
+ return this + 1;
+}
+
+void* SharedBuffer::data() {
+ return this + 1;
+}
+
+size_t SharedBuffer::size() const {
+ return mSize;
+}
+
+SharedBuffer* SharedBuffer::bufferFromData(void* data)
+{
+ return ((SharedBuffer*)data)-1;
+}
+
+const SharedBuffer* SharedBuffer::bufferFromData(const void* data)
+{
+ return ((const SharedBuffer*)data)-1;
+}
+
+size_t SharedBuffer::sizeFromData(const void* data)
+{
+ return (((const SharedBuffer*)data)-1)->mSize;
+}
+
+bool SharedBuffer::onlyOwner() const {
+ return (mRefs == 1);
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_H
diff --git a/include/utils/Socket.h b/include/utils/Socket.h
new file mode 100644
index 0000000..8b7f406
--- /dev/null
+++ b/include/utils/Socket.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Socket class. Modeled after Java classes.
+//
+#ifndef _RUNTIME_SOCKET_H
+#define _RUNTIME_SOCKET_H
+
+#include <utils/inet_address.h>
+#include <sys/types.h>
+
+namespace android {
+
+/*
+ * Basic socket class, needed to abstract away the differences between
+ * BSD sockets and WinSock. This establishes a streaming network
+ * connection (TCP/IP) to somebody.
+ */
+class Socket {
+public:
+ Socket(void);
+ ~Socket(void);
+
+ // Create a connection to somewhere.
+ // Return 0 on success.
+ int connect(const char* host, int port);
+ int connect(const InetAddress* addr, int port);
+
+
+ // Close the socket. Don't try to use this object again after
+ // calling this. Returns false on failure.
+ bool close(void);
+
+ // If we created the socket without an address, we can use these
+ // to finish the connection. Returns 0 on success.
+ int bind(const SocketAddress& bindPoint);
+ int connect(const SocketAddress& endPoint);
+
+ // Here we deviate from the traditional object-oriented fanciness
+ // and just provide read/write operators instead of getters for
+ // objects that abstract a stream.
+ //
+ // Standard read/write semantics.
+ int read(void* buf, ssize_t len) const;
+ int write(const void* buf, ssize_t len) const;
+
+ // This must be called once, at program startup.
+ static bool bootInit(void);
+ static void finalShutdown(void);
+
+private:
+ // Internal function that establishes a connection.
+ int doConnect(const InetSocketAddress& addr);
+
+ unsigned long mSock; // holds SOCKET or int
+
+ static bool mBootInitialized;
+};
+
+
+// debug -- unit tests
+void TestSockets(void);
+
+}; // namespace android
+
+#endif // _RUNTIME_SOCKET_H
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
new file mode 100644
index 0000000..c8a6153
--- /dev/null
+++ b/include/utils/SortedVector.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2005 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_SORTED_VECTOR_H
+#define ANDROID_SORTED_VECTOR_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Vector.h>
+#include <utils/VectorImpl.h>
+#include <utils/TypeHelpers.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+template <class TYPE>
+class SortedVector : private SortedVectorImpl
+{
+public:
+ typedef TYPE value_type;
+
+ /*!
+ * Constructors and destructors
+ */
+
+ SortedVector();
+ SortedVector(const SortedVector<TYPE>& rhs);
+ virtual ~SortedVector();
+
+ /*! copy operator */
+ const SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const;
+ SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs);
+
+ /*
+ * empty the vector
+ */
+
+ inline void clear() { VectorImpl::clear(); }
+
+ /*!
+ * vector stats
+ */
+
+ //! returns number of items in the vector
+ inline size_t size() const { return VectorImpl::size(); }
+ //! returns wether or not the vector is empty
+ inline bool isEmpty() const { return VectorImpl::isEmpty(); }
+ //! returns how many items can be stored without reallocating the backing store
+ inline size_t capacity() const { return VectorImpl::capacity(); }
+ //! setst the capacity. capacity can never be reduced less than size()
+ inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
+
+ /*!
+ * C-style array access
+ */
+
+ //! read-only C-style access
+ inline const TYPE* array() const;
+
+ //! read-write C-style access. BE VERY CAREFUL when modifying the array
+ //! you ust keep it sorted! You usually don't use this function.
+ TYPE* editArray();
+
+ //! finds the index of an item
+ ssize_t indexOf(const TYPE& item) const;
+
+ //! finds where this item should be inserted
+ size_t orderOf(const TYPE& item) const;
+
+
+ /*!
+ * accessors
+ */
+
+ //! read-only access to an item at a given index
+ inline const TYPE& operator [] (size_t index) const;
+ //! alternate name for operator []
+ inline const TYPE& itemAt(size_t index) const;
+ //! stack-usage of the vector. returns the top of the stack (last element)
+ const TYPE& top() const;
+ //! same as operator [], but allows to access the vector backward (from the end) with a negative index
+ const TYPE& mirrorItemAt(ssize_t index) const;
+
+ /*!
+ * modifing the array
+ */
+
+ //! add an item in the right place (and replace the one that is there)
+ ssize_t add(const TYPE& item);
+
+ //! editItemAt() MUST NOT change the order of this item
+ TYPE& editItemAt(size_t index) {
+ return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) );
+ }
+
+ //! merges a vector into this one
+ ssize_t merge(const Vector<TYPE>& vector);
+ ssize_t merge(const SortedVector<TYPE>& vector);
+
+ //! removes an item
+ ssize_t remove(const TYPE&);
+
+ //! remove several items
+ inline ssize_t removeItemsAt(size_t index, size_t count = 1);
+ //! remove one item
+ inline ssize_t removeAt(size_t index) { return removeItemsAt(index); }
+
+protected:
+ virtual void do_construct(void* storage, size_t num) const;
+ virtual void do_destroy(void* storage, size_t num) const;
+ virtual void do_copy(void* dest, const void* from, size_t num) const;
+ virtual void do_splat(void* dest, const void* item, size_t num) const;
+ virtual void do_move_forward(void* dest, const void* from, size_t num) const;
+ virtual void do_move_backward(void* dest, const void* from, size_t num) const;
+ virtual int do_compare(const void* lhs, const void* rhs) const;
+};
+
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts from here...
+// ---------------------------------------------------------------------------
+
+template<class TYPE> inline
+SortedVector<TYPE>::SortedVector()
+ : SortedVectorImpl(sizeof(TYPE),
+ ((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
+ |(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
+ |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
+ |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+ )
+{
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>::SortedVector(const SortedVector<TYPE>& rhs)
+ : SortedVectorImpl(rhs) {
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>::~SortedVector() {
+ finish_vector();
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
+ SortedVectorImpl::operator = (rhs);
+ return *this;
+}
+
+template<class TYPE> inline
+const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
+ SortedVectorImpl::operator = (rhs);
+ return *this;
+}
+
+template<class TYPE> inline
+const TYPE* SortedVector<TYPE>::array() const {
+ return static_cast<const TYPE *>(arrayImpl());
+}
+
+template<class TYPE> inline
+TYPE* SortedVector<TYPE>::editArray() {
+ return static_cast<TYPE *>(editArrayImpl());
+}
+
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::operator[](size_t index) const {
+ assert( index<size() );
+ return *(array() + index);
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::itemAt(size_t index) const {
+ return operator[](index);
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::mirrorItemAt(ssize_t index) const {
+ assert( (index>0 ? index : -index)<size() );
+ return *(array() + ((index<0) ? (size()-index) : index));
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::top() const {
+ return *(array() + size() - 1);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::add(const TYPE& item) {
+ return SortedVectorImpl::add(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::indexOf(const TYPE& item) const {
+ return SortedVectorImpl::indexOf(&item);
+}
+
+template<class TYPE> inline
+size_t SortedVector<TYPE>::orderOf(const TYPE& item) const {
+ return SortedVectorImpl::orderOf(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::merge(const Vector<TYPE>& vector) {
+ return SortedVectorImpl::merge(reinterpret_cast<const VectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::merge(const SortedVector<TYPE>& vector) {
+ return SortedVectorImpl::merge(reinterpret_cast<const SortedVectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::remove(const TYPE& item) {
+ return SortedVectorImpl::remove(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::removeItemsAt(size_t index, size_t count) {
+ return VectorImpl::removeItemsAt(index, count);
+}
+
+// ---------------------------------------------------------------------------
+
+template<class TYPE>
+void SortedVector<TYPE>::do_construct(void* storage, size_t num) const {
+ construct_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_destroy(void* storage, size_t num) const {
+ destroy_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
+ copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
+ splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
+ move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
+ move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+int SortedVector<TYPE>::do_compare(const void* lhs, const void* rhs) const {
+ return compare_type( *reinterpret_cast<const TYPE*>(lhs), *reinterpret_cast<const TYPE*>(rhs) );
+}
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SORTED_VECTOR_H
diff --git a/include/utils/StopWatch.h b/include/utils/StopWatch.h
new file mode 100644
index 0000000..cc0bebc
--- /dev/null
+++ b/include/utils/StopWatch.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005 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_STOPWATCH_H
+#define ANDROID_STOPWATCH_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Timers.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class StopWatch
+{
+public:
+ StopWatch( const char *name,
+ int clock = SYSTEM_TIME_MONOTONIC,
+ uint32_t flags = 0);
+ ~StopWatch();
+
+ const char* name() const;
+ nsecs_t lap();
+ nsecs_t elapsedTime() const;
+
+private:
+ const char* mName;
+ int mClock;
+ uint32_t mFlags;
+
+ struct lap_t {
+ nsecs_t soFar;
+ nsecs_t thisLap;
+ };
+
+ nsecs_t mStartTime;
+ lap_t mLaps[8];
+ int mNumLaps;
+};
+
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STOPWATCH_H
diff --git a/include/utils/String16.h b/include/utils/String16.h
new file mode 100644
index 0000000..a2d22ee
--- /dev/null
+++ b/include/utils/String16.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2005 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_STRING16_H
+#define ANDROID_STRING16_H
+
+#include <utils/Errors.h>
+#include <utils/SharedBuffer.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+extern "C" {
+
+typedef uint16_t char16_t;
+
+// Standard string functions on char16 strings.
+int strcmp16(const char16_t *, const char16_t *);
+int strncmp16(const char16_t *s1, const char16_t *s2, size_t n);
+size_t strlen16(const char16_t *);
+size_t strnlen16(const char16_t *, size_t);
+char16_t *strcpy16(char16_t *, const char16_t *);
+char16_t *strncpy16(char16_t *, const char16_t *, size_t);
+
+// Version of comparison that supports embedded nulls.
+// This is different than strncmp() because we don't stop
+// at a nul character and consider the strings to be different
+// if the lengths are different (thus we need to supply the
+// lengths of both strings). This can also be used when
+// your string is not nul-terminated as it will have the
+// equivalent result as strcmp16 (unlike strncmp16).
+int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2);
+
+// Version of strzcmp16 for comparing strings in different endianness.
+int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2);
+
+}
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class String8;
+class TextOutput;
+
+//! This is a string holding UTF-16 characters.
+class String16
+{
+public:
+ String16();
+ String16(const String16& o);
+ String16(const String16& o,
+ size_t len,
+ size_t begin=0);
+ explicit String16(const char16_t* o);
+ explicit String16(const char16_t* o, size_t len);
+ explicit String16(const String8& o);
+ explicit String16(const char* o);
+ explicit String16(const char* o, size_t len);
+
+ ~String16();
+
+ inline const char16_t* string() const;
+ inline size_t size() const;
+
+ inline const SharedBuffer* sharedBuffer() const;
+
+ void setTo(const String16& other);
+ status_t setTo(const char16_t* other);
+ status_t setTo(const char16_t* other, size_t len);
+ status_t setTo(const String16& other,
+ size_t len,
+ size_t begin=0);
+
+ status_t append(const String16& other);
+ status_t append(const char16_t* other, size_t len);
+
+ inline String16& operator=(const String16& other);
+
+ inline String16& operator+=(const String16& other);
+ inline String16 operator+(const String16& other) const;
+
+ status_t insert(size_t pos, const char16_t* chrs);
+ status_t insert(size_t pos,
+ const char16_t* chrs, size_t len);
+
+ ssize_t findFirst(char16_t c) const;
+ ssize_t findLast(char16_t c) const;
+
+ bool startsWith(const String16& prefix) const;
+ bool startsWith(const char16_t* prefix) const;
+
+ status_t makeLower();
+
+ status_t replaceAll(char16_t replaceThis,
+ char16_t withThis);
+
+ status_t remove(size_t len, size_t begin=0);
+
+ inline int compare(const String16& other) const;
+
+ inline bool operator<(const String16& other) const;
+ inline bool operator<=(const String16& other) const;
+ inline bool operator==(const String16& other) const;
+ inline bool operator!=(const String16& other) const;
+ inline bool operator>=(const String16& other) const;
+ inline bool operator>(const String16& other) const;
+
+ inline bool operator<(const char16_t* other) const;
+ inline bool operator<=(const char16_t* other) const;
+ inline bool operator==(const char16_t* other) const;
+ inline bool operator!=(const char16_t* other) const;
+ inline bool operator>=(const char16_t* other) const;
+ inline bool operator>(const char16_t* other) const;
+
+ inline operator const char16_t*() const;
+
+private:
+ const char16_t* mString;
+};
+
+TextOutput& operator<<(TextOutput& to, const String16& val);
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline int compare_type(const String16& lhs, const String16& rhs)
+{
+ return lhs.compare(rhs);
+}
+
+inline int strictly_order_type(const String16& lhs, const String16& rhs)
+{
+ return compare_type(lhs, rhs) < 0;
+}
+
+inline const char16_t* String16::string() const
+{
+ return mString;
+}
+
+inline size_t String16::size() const
+{
+ return SharedBuffer::sizeFromData(mString)/sizeof(char16_t)-1;
+}
+
+inline const SharedBuffer* String16::sharedBuffer() const
+{
+ return SharedBuffer::bufferFromData(mString);
+}
+
+inline String16& String16::operator=(const String16& other)
+{
+ setTo(other);
+ return *this;
+}
+
+inline String16& String16::operator+=(const String16& other)
+{
+ append(other);
+ return *this;
+}
+
+inline String16 String16::operator+(const String16& other) const
+{
+ String16 tmp;
+ tmp += other;
+ return tmp;
+}
+
+inline int String16::compare(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size());
+}
+
+inline bool String16::operator<(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) < 0;
+}
+
+inline bool String16::operator<=(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) <= 0;
+}
+
+inline bool String16::operator==(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) == 0;
+}
+
+inline bool String16::operator!=(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) != 0;
+}
+
+inline bool String16::operator>=(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) >= 0;
+}
+
+inline bool String16::operator>(const String16& other) const
+{
+ return strzcmp16(mString, size(), other.mString, other.size()) > 0;
+}
+
+inline bool String16::operator<(const char16_t* other) const
+{
+ return strcmp16(mString, other) < 0;
+}
+
+inline bool String16::operator<=(const char16_t* other) const
+{
+ return strcmp16(mString, other) <= 0;
+}
+
+inline bool String16::operator==(const char16_t* other) const
+{
+ return strcmp16(mString, other) == 0;
+}
+
+inline bool String16::operator!=(const char16_t* other) const
+{
+ return strcmp16(mString, other) != 0;
+}
+
+inline bool String16::operator>=(const char16_t* other) const
+{
+ return strcmp16(mString, other) >= 0;
+}
+
+inline bool String16::operator>(const char16_t* other) const
+{
+ return strcmp16(mString, other) > 0;
+}
+
+inline String16::operator const char16_t*() const
+{
+ return mString;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STRING16_H
diff --git a/include/utils/String8.h b/include/utils/String8.h
new file mode 100644
index 0000000..c49faf6
--- /dev/null
+++ b/include/utils/String8.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2005 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_STRING8_H
+#define ANDROID_STRING8_H
+
+#include <utils/Errors.h>
+
+// Need this for the char16_t type; String8.h should not
+// be depedent on the String16 class.
+#include <utils/String16.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class TextOutput;
+
+//! This is a string holding UTF-8 characters.
+class String8
+{
+public:
+ String8();
+ String8(const String8& o);
+ explicit String8(const char* o);
+ explicit String8(const char* o, size_t numChars);
+
+ explicit String8(const String16& o);
+ explicit String8(const char16_t* o);
+ explicit String8(const char16_t* o, size_t numChars);
+
+ ~String8();
+
+ inline const char* string() const;
+ inline size_t size() const;
+ inline size_t length() const;
+ inline size_t bytes() const;
+
+ inline const SharedBuffer* sharedBuffer() const;
+
+ void setTo(const String8& other);
+ status_t setTo(const char* other);
+ status_t setTo(const char* other, size_t numChars);
+ status_t setTo(const char16_t* other, size_t numChars);
+
+ status_t append(const String8& other);
+ status_t append(const char* other);
+ status_t append(const char* other, size_t numChars);
+
+ inline String8& operator=(const String8& other);
+ inline String8& operator=(const char* other);
+
+ inline String8& operator+=(const String8& other);
+ inline String8 operator+(const String8& other) const;
+
+ inline String8& operator+=(const char* other);
+ inline String8 operator+(const char* other) const;
+
+ inline int compare(const String8& other) const;
+
+ inline bool operator<(const String8& other) const;
+ inline bool operator<=(const String8& other) const;
+ inline bool operator==(const String8& other) const;
+ inline bool operator!=(const String8& other) const;
+ inline bool operator>=(const String8& other) const;
+ inline bool operator>(const String8& other) const;
+
+ inline bool operator<(const char* other) const;
+ inline bool operator<=(const char* other) const;
+ inline bool operator==(const char* other) const;
+ inline bool operator!=(const char* other) const;
+ inline bool operator>=(const char* other) const;
+ inline bool operator>(const char* other) const;
+
+ inline operator const char*() const;
+
+ char* lockBuffer(size_t size);
+ void unlockBuffer();
+ status_t unlockBuffer(size_t size);
+
+ // return the index of the first byte of other in this at or after
+ // start, or -1 if not found
+ ssize_t find(const char* other, size_t start = 0) const;
+
+ void toLower();
+ void toLower(size_t start, size_t numChars);
+ void toUpper();
+ void toUpper(size_t start, size_t numChars);
+
+ /*
+ * These methods operate on the string as if it were a path name.
+ */
+
+ /*
+ * Set the filename field to a specific value.
+ *
+ * Normalizes the filename, removing a trailing '/' if present.
+ */
+ void setPathName(const char* name);
+ void setPathName(const char* name, size_t numChars);
+
+ /*
+ * Get just the filename component.
+ *
+ * "/tmp/foo/bar.c" --> "bar.c"
+ */
+ String8 getPathLeaf(void) const;
+
+ /*
+ * Remove the last (file name) component, leaving just the directory
+ * name.
+ *
+ * "/tmp/foo/bar.c" --> "/tmp/foo"
+ * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX
+ * "bar.c" --> ""
+ */
+ String8 getPathDir(void) const;
+
+ /*
+ * Retrieve the front (root dir) component. Optionally also return the
+ * remaining components.
+ *
+ * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c")
+ * "/tmp" --> "tmp" (remain = "")
+ * "bar.c" --> "bar.c" (remain = "")
+ */
+ String8 walkPath(String8* outRemains = NULL) const;
+
+ /*
+ * Return the filename extension. This is the last '.' and up to
+ * four characters that follow it. The '.' is included in case we
+ * decide to expand our definition of what constitutes an extension.
+ *
+ * "/tmp/foo/bar.c" --> ".c"
+ * "/tmp" --> ""
+ * "/tmp/foo.bar/baz" --> ""
+ * "foo.jpeg" --> ".jpeg"
+ * "foo." --> ""
+ */
+ String8 getPathExtension(void) const;
+
+ /*
+ * Return the path without the extension. Rules for what constitutes
+ * an extension are described in the comment for getPathExtension().
+ *
+ * "/tmp/foo/bar.c" --> "/tmp/foo/bar"
+ */
+ String8 getBasePath(void) const;
+
+ /*
+ * Add a component to the pathname. We guarantee that there is
+ * exactly one path separator between the old path and the new.
+ * If there is no existing name, we just copy the new name in.
+ *
+ * If leaf is a fully qualified path (i.e. starts with '/', it
+ * replaces whatever was there before.
+ */
+ String8& appendPath(const char* leaf);
+ String8& appendPath(const String8& leaf) { return appendPath(leaf.string()); }
+
+ /*
+ * Like appendPath(), but does not affect this string. Returns a new one instead.
+ */
+ String8 appendPathCopy(const char* leaf) const
+ { String8 p(*this); p.appendPath(leaf); return p; }
+ String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.string()); }
+
+ /*
+ * Converts all separators in this string to /, the default path separator.
+ *
+ * If the default OS separator is backslash, this converts all
+ * backslashes to slashes, in-place. Otherwise it does nothing.
+ * Returns self.
+ */
+ String8& convertToResPath();
+
+private:
+ status_t real_append(const char* other, size_t numChars);
+ char* find_extension(void) const;
+
+ const char* mString;
+};
+
+TextOutput& operator<<(TextOutput& to, const String16& val);
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline int compare_type(const String8& lhs, const String8& rhs)
+{
+ return lhs.compare(rhs);
+}
+
+inline int strictly_order_type(const String8& lhs, const String8& rhs)
+{
+ return compare_type(lhs, rhs) < 0;
+}
+
+inline const char* String8::string() const
+{
+ return mString;
+}
+
+inline size_t String8::length() const
+{
+ return SharedBuffer::sizeFromData(mString)-1;
+}
+
+inline size_t String8::size() const
+{
+ return length();
+}
+
+inline size_t String8::bytes() const
+{
+ return SharedBuffer::sizeFromData(mString)-1;
+}
+
+inline const SharedBuffer* String8::sharedBuffer() const
+{
+ return SharedBuffer::bufferFromData(mString);
+}
+
+inline String8& String8::operator=(const String8& other)
+{
+ setTo(other);
+ return *this;
+}
+
+inline String8& String8::operator=(const char* other)
+{
+ setTo(other);
+ return *this;
+}
+
+inline String8& String8::operator+=(const String8& other)
+{
+ append(other);
+ return *this;
+}
+
+inline String8 String8::operator+(const String8& other) const
+{
+ String8 tmp;
+ tmp += other;
+ return tmp;
+}
+
+inline String8& String8::operator+=(const char* other)
+{
+ append(other);
+ return *this;
+}
+
+inline String8 String8::operator+(const char* other) const
+{
+ String8 tmp;
+ tmp += other;
+ return tmp;
+}
+
+inline int String8::compare(const String8& other) const
+{
+ return strcmp(mString, other.mString);
+}
+
+inline bool String8::operator<(const String8& other) const
+{
+ return strcmp(mString, other.mString) < 0;
+}
+
+inline bool String8::operator<=(const String8& other) const
+{
+ return strcmp(mString, other.mString) <= 0;
+}
+
+inline bool String8::operator==(const String8& other) const
+{
+ return strcmp(mString, other.mString) == 0;
+}
+
+inline bool String8::operator!=(const String8& other) const
+{
+ return strcmp(mString, other.mString) != 0;
+}
+
+inline bool String8::operator>=(const String8& other) const
+{
+ return strcmp(mString, other.mString) >= 0;
+}
+
+inline bool String8::operator>(const String8& other) const
+{
+ return strcmp(mString, other.mString) > 0;
+}
+
+inline bool String8::operator<(const char* other) const
+{
+ return strcmp(mString, other) < 0;
+}
+
+inline bool String8::operator<=(const char* other) const
+{
+ return strcmp(mString, other) <= 0;
+}
+
+inline bool String8::operator==(const char* other) const
+{
+ return strcmp(mString, other) == 0;
+}
+
+inline bool String8::operator!=(const char* other) const
+{
+ return strcmp(mString, other) != 0;
+}
+
+inline bool String8::operator>=(const char* other) const
+{
+ return strcmp(mString, other) >= 0;
+}
+
+inline bool String8::operator>(const char* other) const
+{
+ return strcmp(mString, other) > 0;
+}
+
+inline String8::operator const char*() const
+{
+ return mString;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STRING8_H
diff --git a/include/utils/SystemClock.h b/include/utils/SystemClock.h
new file mode 100644
index 0000000..7c319be
--- /dev/null
+++ b/include/utils/SystemClock.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UTILS_SYSTEMCLOCK_H
+#define ANDROID_UTILS_SYSTEMCLOCK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+
+int setCurrentTimeMillis(int64_t millis);
+int64_t uptimeMillis();
+int64_t elapsedRealtime();
+
+}; // namespace android
+
+#endif // ANDROID_UTILS_SYSTEMCLOCK_H
+
diff --git a/include/utils/TextOutput.h b/include/utils/TextOutput.h
new file mode 100644
index 0000000..d8d86ba
--- /dev/null
+++ b/include/utils/TextOutput.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2006 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_TEXTOUTPUT_H
+#define ANDROID_TEXTOUTPUT_H
+
+#include <utils/Errors.h>
+
+#include <stdint.h>
+#include <string.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class TextOutput
+{
+public:
+ TextOutput() { }
+ virtual ~TextOutput() { }
+
+ virtual status_t print(const char* txt, size_t len) = 0;
+ virtual void moveIndent(int delta) = 0;
+
+ class Bundle {
+ public:
+ inline Bundle(TextOutput& to) : mTO(to) { to.pushBundle(); }
+ inline ~Bundle() { mTO.popBundle(); }
+ private:
+ TextOutput& mTO;
+ };
+
+ virtual void pushBundle() = 0;
+ virtual void popBundle() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+// Text output stream for printing to the log (via utils/Log.h).
+extern TextOutput& alog;
+
+// Text output stream for printing to stdout.
+extern TextOutput& aout;
+
+// Text output stream for printing to stderr.
+extern TextOutput& aerr;
+
+typedef TextOutput& (*TextOutputManipFunc)(TextOutput&);
+
+TextOutput& endl(TextOutput& to);
+TextOutput& indent(TextOutput& to);
+TextOutput& dedent(TextOutput& to);
+
+TextOutput& operator<<(TextOutput& to, const char* str);
+TextOutput& operator<<(TextOutput& to, char); // writes raw character
+TextOutput& operator<<(TextOutput& to, bool);
+TextOutput& operator<<(TextOutput& to, int);
+TextOutput& operator<<(TextOutput& to, long);
+TextOutput& operator<<(TextOutput& to, unsigned int);
+TextOutput& operator<<(TextOutput& to, unsigned long);
+TextOutput& operator<<(TextOutput& to, long long);
+TextOutput& operator<<(TextOutput& to, unsigned long long);
+TextOutput& operator<<(TextOutput& to, float);
+TextOutput& operator<<(TextOutput& to, double);
+TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func);
+TextOutput& operator<<(TextOutput& to, const void*);
+
+class TypeCode
+{
+public:
+ inline TypeCode(uint32_t code);
+ inline ~TypeCode();
+
+ inline uint32_t typeCode() const;
+
+private:
+ uint32_t mCode;
+};
+
+TextOutput& operator<<(TextOutput& to, const TypeCode& val);
+
+class HexDump
+{
+public:
+ HexDump(const void *buf, size_t size, size_t bytesPerLine=16);
+ inline ~HexDump();
+
+ inline HexDump& setBytesPerLine(size_t bytesPerLine);
+ inline HexDump& setSingleLineCutoff(int32_t bytes);
+ inline HexDump& setAlignment(size_t alignment);
+ inline HexDump& setCArrayStyle(bool enabled);
+
+ inline const void* buffer() const;
+ inline size_t size() const;
+ inline size_t bytesPerLine() const;
+ inline int32_t singleLineCutoff() const;
+ inline size_t alignment() const;
+ inline bool carrayStyle() const;
+
+private:
+ const void* mBuffer;
+ size_t mSize;
+ size_t mBytesPerLine;
+ int32_t mSingleLineCutoff;
+ size_t mAlignment;
+ bool mCArrayStyle;
+};
+
+TextOutput& operator<<(TextOutput& to, const HexDump& val);
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline TextOutput& endl(TextOutput& to)
+{
+ to.print("\n", 1);
+ return to;
+}
+
+inline TextOutput& indent(TextOutput& to)
+{
+ to.moveIndent(1);
+ return to;
+}
+
+inline TextOutput& dedent(TextOutput& to)
+{
+ to.moveIndent(-1);
+ return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const char* str)
+{
+ to.print(str, strlen(str));
+ return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, char c)
+{
+ to.print(&c, 1);
+ return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func)
+{
+ return (*func)(to);
+}
+
+inline TypeCode::TypeCode(uint32_t code) : mCode(code) { }
+inline TypeCode::~TypeCode() { }
+inline uint32_t TypeCode::typeCode() const { return mCode; }
+
+inline HexDump::~HexDump() { }
+
+inline HexDump& HexDump::setBytesPerLine(size_t bytesPerLine) {
+ mBytesPerLine = bytesPerLine; return *this;
+}
+inline HexDump& HexDump::setSingleLineCutoff(int32_t bytes) {
+ mSingleLineCutoff = bytes; return *this;
+}
+inline HexDump& HexDump::setAlignment(size_t alignment) {
+ mAlignment = alignment; return *this;
+}
+inline HexDump& HexDump::setCArrayStyle(bool enabled) {
+ mCArrayStyle = enabled; return *this;
+}
+
+inline const void* HexDump::buffer() const { return mBuffer; }
+inline size_t HexDump::size() const { return mSize; }
+inline size_t HexDump::bytesPerLine() const { return mBytesPerLine; }
+inline int32_t HexDump::singleLineCutoff() const { return mSingleLineCutoff; }
+inline size_t HexDump::alignment() const { return mAlignment; }
+inline bool HexDump::carrayStyle() const { return mCArrayStyle; }
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_TEXTOUTPUT_H
diff --git a/include/utils/TimeUtils.h b/include/utils/TimeUtils.h
new file mode 100644
index 0000000..30e5330
--- /dev/null
+++ b/include/utils/TimeUtils.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2005 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_TIME_H
+#define ANDROID_TIME_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+namespace android {
+
+/*
+ * This class is the core implementation of the android.util.Time java
+ * class. It doesn't implement some of the methods that are implemented
+ * in Java. They could be done here, but it's not expected that this class
+ * will be used. If that assumption is incorrect, feel free to update this
+ * file. The reason to do it here is to not mix the implementation of this
+ * class and the jni glue code.
+ */
+class Time
+{
+public:
+ struct tm t;
+
+ // this object doesn't own this string
+ const char *timezone;
+
+ enum {
+ SEC = 1,
+ MIN = 2,
+ HOUR = 3,
+ MDAY = 4,
+ MON = 5,
+ YEAR = 6,
+ WDAY = 7,
+ YDAY = 8
+ };
+
+ static int compare(Time& a, Time& b);
+
+ Time();
+
+ void switchTimezone(const char *timezone);
+ String8 format(const char *format) const;
+ void format2445(short* buf, bool hasTime) const;
+ String8 toString() const;
+ void setToNow();
+ int64_t toMillis(bool ignoreDst);
+ void set(int64_t millis);
+
+ inline void set(int sec, int min, int hour, int mday, int mon, int year,
+ int isdst)
+ {
+ this->t.tm_sec = sec;
+ this->t.tm_min = min;
+ this->t.tm_hour = hour;
+ this->t.tm_mday = mday;
+ this->t.tm_mon = mon;
+ this->t.tm_year = year;
+ this->t.tm_isdst = isdst;
+#ifdef HAVE_TM_GMTOFF
+ this->t.tm_gmtoff = 0;
+#endif
+ this->t.tm_wday = 0;
+ this->t.tm_yday = 0;
+ }
+};
+
+}; // namespace android
+
+#endif // ANDROID_TIME_H
diff --git a/include/utils/TimerProbe.h b/include/utils/TimerProbe.h
new file mode 100644
index 0000000..f2e32b2
--- /dev/null
+++ b/include/utils/TimerProbe.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_TIMER_PROBE_H
+#define ANDROID_TIMER_PROBE_H
+
+#if 0 && defined(HAVE_POSIX_CLOCKS)
+#define ENABLE_TIMER_PROBE 1
+#else
+#define ENABLE_TIMER_PROBE 0
+#endif
+
+#if ENABLE_TIMER_PROBE
+
+#include <time.h>
+#include <sys/time.h>
+#include <utils/Vector.h>
+
+#define TIMER_PROBE(tag) \
+ static int _timer_slot_; \
+ android::TimerProbe probe(tag, &_timer_slot_)
+#define TIMER_PROBE_END() probe.end()
+#else
+#define TIMER_PROBE(tag)
+#define TIMER_PROBE_END()
+#endif
+
+#if ENABLE_TIMER_PROBE
+namespace android {
+
+class TimerProbe {
+public:
+ TimerProbe(const char tag[], int* slot);
+ void end();
+ ~TimerProbe();
+private:
+ struct Bucket {
+ int mStart, mReal, mProcess, mThread, mCount;
+ const char* mTag;
+ int* mSlotPtr;
+ int mIndent;
+ };
+ static Vector<Bucket> gBuckets;
+ static TimerProbe* gExecuteChain;
+ static int gIndent;
+ static timespec gRealBase;
+ TimerProbe* mNext;
+ static uint32_t ElapsedTime(const timespec& start, const timespec& end);
+ void print(const timespec& r, const timespec& p, const timespec& t) const;
+ timespec mRealStart, mPStart, mTStart;
+ const char* mTag;
+ int mIndent;
+ int mBucket;
+};
+
+}; // namespace android
+
+#endif
+#endif
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
new file mode 100644
index 0000000..9610399
--- /dev/null
+++ b/include/utils/Timers.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Timer functions.
+//
+#ifndef _LIBS_UTILS_TIMERS_H
+#define _LIBS_UTILS_TIMERS_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+// ------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int64_t nsecs_t; // nano-seconds
+
+static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
+{
+ return secs*1000000000;
+}
+
+static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
+{
+ return secs*1000000;
+}
+
+static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
+{
+ return secs*1000;
+}
+
+static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
+{
+ return secs/1000000000;
+}
+
+static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
+{
+ return secs/1000000;
+}
+
+static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
+{
+ return secs/1000;
+}
+
+static inline nsecs_t s2ns(nsecs_t v) {return seconds_to_nanoseconds(v);}
+static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
+static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
+static inline nsecs_t ns2s(nsecs_t v) {return nanoseconds_to_seconds(v);}
+static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
+static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
+
+static inline nsecs_t seconds(nsecs_t v) { return s2ns(v); }
+static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
+static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
+
+enum {
+ SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock
+ SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point
+ SYSTEM_TIME_PROCESS = 2, // high-resolution per-process clock
+ SYSTEM_TIME_THREAD = 3 // high-resolution per-thread clock
+};
+
+// return the system-time according to the specified clock
+#ifdef __cplusplus
+nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
+#else
+nsecs_t systemTime(int clock);
+#endif // def __cplusplus
+
+// return the system-time according to the specified clock
+int sleepForInterval(long interval, struct timeval* pNextTick);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+// ------------------------------------------------------------------
+// C++ API
+
+#ifdef __cplusplus
+
+namespace android {
+/*
+ * Time the duration of something.
+ *
+ * Includes some timeval manipulation functions.
+ */
+class DurationTimer {
+public:
+ DurationTimer(void) {}
+ ~DurationTimer(void) {}
+
+ // Start the timer.
+ void start(void);
+ // Stop the timer.
+ void stop(void);
+ // Get the duration in microseconds.
+ long long durationUsecs(void) const;
+
+ // Subtract two timevals. Returns the difference (ptv1-ptv2) in
+ // microseconds.
+ static long long subtractTimevals(const struct timeval* ptv1,
+ const struct timeval* ptv2);
+
+ // Add the specified amount of time to the timeval.
+ static void addToTimeval(struct timeval* ptv, long usec);
+
+private:
+ struct timeval mStartWhen;
+ struct timeval mStopWhen;
+};
+
+}; // android
+#endif // def __cplusplus
+
+#endif // _LIBS_UTILS_TIMERS_H
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
new file mode 100644
index 0000000..c04c37f
--- /dev/null
+++ b/include/utils/TypeHelpers.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2005 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_TYPE_HELPERS_H
+#define ANDROID_TYPE_HELPERS_H
+
+#include <new>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+/*
+ * Types traits
+ */
+
+template <typename T> struct trait_trivial_ctor { enum { value = false }; };
+template <typename T> struct trait_trivial_dtor { enum { value = false }; };
+template <typename T> struct trait_trivial_copy { enum { value = false }; };
+template <typename T> struct trait_trivial_assign{ enum { value = false }; };
+
+template <typename T> struct trait_pointer { enum { value = false }; };
+template <typename T> struct trait_pointer<T*> { enum { value = true }; };
+
+#define ANDROID_BASIC_TYPES_TRAITS( T ) \
+ template<> struct trait_trivial_ctor< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_dtor< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_copy< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_assign< T >{ enum { value = true }; };
+
+#define ANDROID_TYPE_TRAITS( T, ctor, dtor, copy, assign ) \
+ template<> struct trait_trivial_ctor< T > { enum { value = ctor }; }; \
+ template<> struct trait_trivial_dtor< T > { enum { value = dtor }; }; \
+ template<> struct trait_trivial_copy< T > { enum { value = copy }; }; \
+ template<> struct trait_trivial_assign< T >{ enum { value = assign }; };
+
+template <typename TYPE>
+struct traits {
+ enum {
+ is_pointer = trait_pointer<TYPE>::value,
+ has_trivial_ctor = is_pointer || trait_trivial_ctor<TYPE>::value,
+ has_trivial_dtor = is_pointer || trait_trivial_dtor<TYPE>::value,
+ has_trivial_copy = is_pointer || trait_trivial_copy<TYPE>::value,
+ has_trivial_assign = is_pointer || trait_trivial_assign<TYPE>::value
+ };
+};
+
+template <typename T, typename U>
+struct aggregate_traits {
+ enum {
+ is_pointer = false,
+ has_trivial_ctor = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
+ has_trivial_dtor = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
+ has_trivial_copy = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
+ has_trivial_assign = traits<T>::has_trivial_assign && traits<U>::has_trivial_assign
+ };
+};
+
+// ---------------------------------------------------------------------------
+
+/*
+ * basic types traits
+ */
+
+ANDROID_BASIC_TYPES_TRAITS( void );
+ANDROID_BASIC_TYPES_TRAITS( bool );
+ANDROID_BASIC_TYPES_TRAITS( char );
+ANDROID_BASIC_TYPES_TRAITS( unsigned char );
+ANDROID_BASIC_TYPES_TRAITS( short );
+ANDROID_BASIC_TYPES_TRAITS( unsigned short );
+ANDROID_BASIC_TYPES_TRAITS( int );
+ANDROID_BASIC_TYPES_TRAITS( unsigned int );
+ANDROID_BASIC_TYPES_TRAITS( long );
+ANDROID_BASIC_TYPES_TRAITS( unsigned long );
+ANDROID_BASIC_TYPES_TRAITS( long long );
+ANDROID_BASIC_TYPES_TRAITS( unsigned long long );
+ANDROID_BASIC_TYPES_TRAITS( float );
+ANDROID_BASIC_TYPES_TRAITS( double );
+
+// ---------------------------------------------------------------------------
+
+
+/*
+ * compare and order types
+ */
+
+template<typename TYPE> inline
+int strictly_order_type(const TYPE& lhs, const TYPE& rhs) {
+ return (lhs < rhs) ? 1 : 0;
+}
+
+template<typename TYPE> inline
+int compare_type(const TYPE& lhs, const TYPE& rhs) {
+ return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs);
+}
+
+/*
+ * create, destroy, copy and assign types...
+ */
+
+template<typename TYPE> inline
+void construct_type(TYPE* p, size_t n) {
+ if (!traits<TYPE>::has_trivial_ctor) {
+ while (n--) {
+ new(p++) TYPE;
+ }
+ }
+}
+
+template<typename TYPE> inline
+void destroy_type(TYPE* p, size_t n) {
+ if (!traits<TYPE>::has_trivial_dtor) {
+ while (n--) {
+ p->~TYPE();
+ p++;
+ }
+ }
+}
+
+template<typename TYPE> inline
+void copy_type(TYPE* d, const TYPE* s, size_t n) {
+ if (!traits<TYPE>::has_trivial_copy) {
+ while (n--) {
+ new(d) TYPE(*s);
+ d++, s++;
+ }
+ } else {
+ memcpy(d,s,n*sizeof(TYPE));
+ }
+}
+
+template<typename TYPE> inline
+void assign_type(TYPE* d, const TYPE* s, size_t n) {
+ if (!traits<TYPE>::has_trivial_assign) {
+ while (n--) {
+ *d++ = *s++;
+ }
+ } else {
+ memcpy(d,s,n*sizeof(TYPE));
+ }
+}
+
+template<typename TYPE> inline
+void splat_type(TYPE* where, const TYPE* what, size_t n) {
+ if (!traits<TYPE>::has_trivial_copy) {
+ while (n--) {
+ new(where) TYPE(*what);
+ where++;
+ }
+ } else {
+ while (n--) {
+ *where++ = *what;
+ }
+ }
+}
+
+template<typename TYPE> inline
+void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
+ if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
+ d += n;
+ s += n;
+ while (n--) {
+ --d, --s;
+ if (!traits<TYPE>::has_trivial_copy) {
+ new(d) TYPE(*s);
+ } else {
+ *d = *s;
+ }
+ if (!traits<TYPE>::has_trivial_dtor) {
+ s->~TYPE();
+ }
+ }
+ } else {
+ memmove(d,s,n*sizeof(TYPE));
+ }
+}
+
+template<typename TYPE> inline
+void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
+ if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
+ while (n--) {
+ if (!traits<TYPE>::has_trivial_copy) {
+ new(d) TYPE(*s);
+ } else {
+ *d = *s;
+ }
+ if (!traits<TYPE>::has_trivial_dtor) {
+ s->~TYPE();
+ }
+ d++, s++;
+ }
+ } else {
+ memmove(d,s,n*sizeof(TYPE));
+ }
+}
+// ---------------------------------------------------------------------------
+
+/*
+ * a key/value pair
+ */
+
+template <typename KEY, typename VALUE>
+struct key_value_pair_t {
+ KEY key;
+ VALUE value;
+ key_value_pair_t() { }
+ key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }
+ key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v) { }
+ key_value_pair_t(const KEY& k) : key(k) { }
+ inline bool operator < (const key_value_pair_t& o) const {
+ return strictly_order_type(key, o.key);
+ }
+};
+
+template<>
+template <typename K, typename V>
+struct trait_trivial_ctor< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };
+template<>
+template <typename K, typename V>
+struct trait_trivial_dtor< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };
+template<>
+template <typename K, typename V>
+struct trait_trivial_copy< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
+template<>
+template <typename K, typename V>
+struct trait_trivial_assign< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_assign};};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_TYPE_HELPERS_H
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
new file mode 100644
index 0000000..be365d8
--- /dev/null
+++ b/include/utils/Vector.h
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2005 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_VECTOR_H
+#define ANDROID_VECTOR_H
+
+#include <new>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Log.h>
+#include <utils/VectorImpl.h>
+#include <utils/TypeHelpers.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+/*!
+ * The main templated vector class ensuring type safety
+ * while making use of VectorImpl.
+ * This is the class users want to use.
+ */
+
+template <class TYPE>
+class Vector : private VectorImpl
+{
+public:
+ typedef TYPE value_type;
+
+ /*!
+ * Constructors and destructors
+ */
+
+ Vector();
+ Vector(const Vector<TYPE>& rhs);
+ virtual ~Vector();
+
+ /*! copy operator */
+ const Vector<TYPE>& operator = (const Vector<TYPE>& rhs) const;
+ Vector<TYPE>& operator = (const Vector<TYPE>& rhs);
+
+ /*
+ * empty the vector
+ */
+
+ inline void clear() { VectorImpl::clear(); }
+
+ /*!
+ * vector stats
+ */
+
+ //! returns number of items in the vector
+ inline size_t size() const { return VectorImpl::size(); }
+ //! returns wether or not the vector is empty
+ inline bool isEmpty() const { return VectorImpl::isEmpty(); }
+ //! returns how many items can be stored without reallocating the backing store
+ inline size_t capacity() const { return VectorImpl::capacity(); }
+ //! setst the capacity. capacity can never be reduced less than size()
+ inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
+
+ /*!
+ * C-style array access
+ */
+
+ //! read-only C-style access
+ inline const TYPE* array() const;
+ //! read-write C-style access
+ TYPE* editArray();
+
+ /*!
+ * accessors
+ */
+
+ //! read-only access to an item at a given index
+ inline const TYPE& operator [] (size_t index) const;
+ //! alternate name for operator []
+ inline const TYPE& itemAt(size_t index) const;
+ //! stack-usage of the vector. returns the top of the stack (last element)
+ const TYPE& top() const;
+ //! same as operator [], but allows to access the vector backward (from the end) with a negative index
+ const TYPE& mirrorItemAt(ssize_t index) const;
+
+ /*!
+ * modifing the array
+ */
+
+ //! copy-on write support, grants write access to an item
+ TYPE& editItemAt(size_t index);
+ //! grants right acces to the top of the stack (last element)
+ TYPE& editTop();
+
+ /*!
+ * append/insert another vector
+ */
+
+ //! insert another vector at a given index
+ ssize_t insertVectorAt(const Vector<TYPE>& vector, size_t index);
+
+ //! append another vector at the end of this one
+ ssize_t appendVector(const Vector<TYPE>& vector);
+
+
+ /*!
+ * add/insert/replace items
+ */
+
+ //! insert one or several items initialized with their default constructor
+ inline ssize_t insertAt(size_t index, size_t numItems = 1);
+ //! insert on onr several items initialized from a prototype item
+ ssize_t insertAt(const TYPE& prototype_item, size_t index, size_t numItems = 1);
+ //! pop the top of the stack (removes the last element). No-op if the stack's empty
+ inline void pop();
+ //! pushes an item initialized with its default constructor
+ inline void push();
+ //! pushes an item on the top of the stack
+ void push(const TYPE& item);
+ //! same as push() but returns the index the item was added at (or an error)
+ inline ssize_t add();
+ //! same as push() but returns the index the item was added at (or an error)
+ ssize_t add(const TYPE& item);
+ //! replace an item with a new one initialized with its default constructor
+ inline ssize_t replaceAt(size_t index);
+ //! replace an item with a new one
+ ssize_t replaceAt(const TYPE& item, size_t index);
+
+ /*!
+ * remove items
+ */
+
+ //! remove several items
+ inline ssize_t removeItemsAt(size_t index, size_t count = 1);
+ //! remove one item
+ inline ssize_t removeAt(size_t index) { return removeItemsAt(index); }
+
+ /*!
+ * sort (stable) the array
+ */
+
+ typedef int (*compar_t)(const TYPE* lhs, const TYPE* rhs);
+ typedef int (*compar_r_t)(const TYPE* lhs, const TYPE* rhs, void* state);
+
+ inline status_t sort(compar_t cmp);
+ inline status_t sort(compar_r_t cmp, void* state);
+
+protected:
+ virtual void do_construct(void* storage, size_t num) const;
+ virtual void do_destroy(void* storage, size_t num) const;
+ virtual void do_copy(void* dest, const void* from, size_t num) const;
+ virtual void do_splat(void* dest, const void* item, size_t num) const;
+ virtual void do_move_forward(void* dest, const void* from, size_t num) const;
+ virtual void do_move_backward(void* dest, const void* from, size_t num) const;
+};
+
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts from here...
+// ---------------------------------------------------------------------------
+
+template<class TYPE> inline
+Vector<TYPE>::Vector()
+ : VectorImpl(sizeof(TYPE),
+ ((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
+ |(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
+ |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
+ |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+ )
+{
+}
+
+template<class TYPE> inline
+Vector<TYPE>::Vector(const Vector<TYPE>& rhs)
+ : VectorImpl(rhs) {
+}
+
+template<class TYPE> inline
+Vector<TYPE>::~Vector() {
+ finish_vector();
+}
+
+template<class TYPE> inline
+Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) {
+ VectorImpl::operator = (rhs);
+ return *this;
+}
+
+template<class TYPE> inline
+const Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) const {
+ VectorImpl::operator = (rhs);
+ return *this;
+}
+
+template<class TYPE> inline
+const TYPE* Vector<TYPE>::array() const {
+ return static_cast<const TYPE *>(arrayImpl());
+}
+
+template<class TYPE> inline
+TYPE* Vector<TYPE>::editArray() {
+ return static_cast<TYPE *>(editArrayImpl());
+}
+
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::operator[](size_t index) const {
+ LOG_FATAL_IF( index>=size(),
+ "itemAt: index %d is past size %d", (int)index, (int)size() );
+ return *(array() + index);
+}
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::itemAt(size_t index) const {
+ return operator[](index);
+}
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::mirrorItemAt(ssize_t index) const {
+ LOG_FATAL_IF( (index>0 ? index : -index)>=size(),
+ "mirrorItemAt: index %d is past size %d",
+ (int)index, (int)size() );
+ return *(array() + ((index<0) ? (size()-index) : index));
+}
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::top() const {
+ return *(array() + size() - 1);
+}
+
+template<class TYPE> inline
+TYPE& Vector<TYPE>::editItemAt(size_t index) {
+ return *( static_cast<TYPE *>(editItemLocation(index)) );
+}
+
+template<class TYPE> inline
+TYPE& Vector<TYPE>::editTop() {
+ return *( static_cast<TYPE *>(editItemLocation(size()-1)) );
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertVectorAt(const Vector<TYPE>& vector, size_t index) {
+ return VectorImpl::insertVectorAt(reinterpret_cast<const VectorImpl&>(vector), index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::appendVector(const Vector<TYPE>& vector) {
+ return VectorImpl::appendVector(reinterpret_cast<const VectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertAt(const TYPE& item, size_t index, size_t numItems) {
+ return VectorImpl::insertAt(&item, index, numItems);
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::push(const TYPE& item) {
+ return VectorImpl::push(&item);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::add(const TYPE& item) {
+ return VectorImpl::add(&item);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::replaceAt(const TYPE& item, size_t index) {
+ return VectorImpl::replaceAt(&item, index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertAt(size_t index, size_t numItems) {
+ return VectorImpl::insertAt(index, numItems);
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::pop() {
+ VectorImpl::pop();
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::push() {
+ VectorImpl::push();
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::add() {
+ return VectorImpl::add();
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::replaceAt(size_t index) {
+ return VectorImpl::replaceAt(index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::removeItemsAt(size_t index, size_t count) {
+ return VectorImpl::removeItemsAt(index, count);
+}
+
+template<class TYPE> inline
+status_t Vector<TYPE>::sort(Vector<TYPE>::compar_t cmp) {
+ return VectorImpl::sort((VectorImpl::compar_t)cmp);
+}
+
+template<class TYPE> inline
+status_t Vector<TYPE>::sort(Vector<TYPE>::compar_r_t cmp, void* state) {
+ return VectorImpl::sort((VectorImpl::compar_r_t)cmp, state);
+}
+
+// ---------------------------------------------------------------------------
+
+template<class TYPE>
+void Vector<TYPE>::do_construct(void* storage, size_t num) const {
+ construct_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_destroy(void* storage, size_t num) const {
+ destroy_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
+ copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
+ splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
+ move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
+ move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_H
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
new file mode 100644
index 0000000..2525229
--- /dev/null
+++ b/include/utils/VectorImpl.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2005 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_VECTOR_IMPL_H
+#define ANDROID_VECTOR_IMPL_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts in here...
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+/*!
+ * Implementation of the guts of the vector<> class
+ * this ensures backward binary compatibility and
+ * reduces code size.
+ * For performance reasons, we expose mStorage and mCount
+ * so these fields are set in stone.
+ *
+ */
+
+class VectorImpl
+{
+public:
+ enum { // flags passed to the ctor
+ HAS_TRIVIAL_CTOR = 0x00000001,
+ HAS_TRIVIAL_DTOR = 0x00000002,
+ HAS_TRIVIAL_COPY = 0x00000004,
+ HAS_TRIVIAL_ASSIGN = 0x00000008
+ };
+
+ VectorImpl(size_t itemSize, uint32_t flags);
+ VectorImpl(const VectorImpl& rhs);
+ virtual ~VectorImpl();
+
+ /*! must be called from subclasses destructor */
+ void finish_vector();
+
+ VectorImpl& operator = (const VectorImpl& rhs);
+
+ /*! C-style array access */
+ inline const void* arrayImpl() const { return mStorage; }
+ void* editArrayImpl();
+
+ /*! vector stats */
+ inline size_t size() const { return mCount; }
+ inline bool isEmpty() const { return mCount == 0; }
+ size_t capacity() const;
+ ssize_t setCapacity(size_t size);
+
+ /*! append/insert another vector */
+ ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
+ ssize_t appendVector(const VectorImpl& vector);
+
+ /*! add/insert/replace items */
+ ssize_t insertAt(size_t where, size_t numItems = 1);
+ ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
+ void pop();
+ void push();
+ void push(const void* item);
+ ssize_t add();
+ ssize_t add(const void* item);
+ ssize_t replaceAt(size_t index);
+ ssize_t replaceAt(const void* item, size_t index);
+
+ /*! remove items */
+ ssize_t removeItemsAt(size_t index, size_t count = 1);
+ void clear();
+
+ const void* itemLocation(size_t index) const;
+ void* editItemLocation(size_t index);
+
+ typedef int (*compar_t)(const void* lhs, const void* rhs);
+ typedef int (*compar_r_t)(const void* lhs, const void* rhs, void* state);
+ status_t sort(compar_t cmp);
+ status_t sort(compar_r_t cmp, void* state);
+
+protected:
+ size_t itemSize() const;
+ void release_storage();
+
+ virtual void do_construct(void* storage, size_t num) const = 0;
+ virtual void do_destroy(void* storage, size_t num) const = 0;
+ virtual void do_copy(void* dest, const void* from, size_t num) const = 0;
+ virtual void do_splat(void* dest, const void* item, size_t num) const = 0;
+ virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0;
+ virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0;
+
+ // take care of FBC...
+ virtual void reservedVectorImpl1();
+ virtual void reservedVectorImpl2();
+ virtual void reservedVectorImpl3();
+ virtual void reservedVectorImpl4();
+ virtual void reservedVectorImpl5();
+ virtual void reservedVectorImpl6();
+ virtual void reservedVectorImpl7();
+ virtual void reservedVectorImpl8();
+
+private:
+ void* _grow(size_t where, size_t amount);
+ void _shrink(size_t where, size_t amount);
+
+ inline void _do_construct(void* storage, size_t num) const;
+ inline void _do_destroy(void* storage, size_t num) const;
+ inline void _do_copy(void* dest, const void* from, size_t num) const;
+ inline void _do_splat(void* dest, const void* item, size_t num) const;
+ inline void _do_move_forward(void* dest, const void* from, size_t num) const;
+ inline void _do_move_backward(void* dest, const void* from, size_t num) const;
+
+ // These 2 fields are exposed in the inlines below,
+ // so they're set in stone.
+ void * mStorage; // base address of the vector
+ size_t mCount; // number of items
+
+ const uint32_t mFlags;
+ const size_t mItemSize;
+};
+
+
+
+class SortedVectorImpl : public VectorImpl
+{
+public:
+ SortedVectorImpl(size_t itemSize, uint32_t flags);
+ SortedVectorImpl(const VectorImpl& rhs);
+ virtual ~SortedVectorImpl();
+
+ SortedVectorImpl& operator = (const SortedVectorImpl& rhs);
+
+ //! finds the index of an item
+ ssize_t indexOf(const void* item) const;
+
+ //! finds where this item should be inserted
+ size_t orderOf(const void* item) const;
+
+ //! add an item in the right place (or replaces it if there is one)
+ ssize_t add(const void* item);
+
+ //! merges a vector into this one
+ ssize_t merge(const VectorImpl& vector);
+ ssize_t merge(const SortedVectorImpl& vector);
+
+ //! removes an item
+ ssize_t remove(const void* item);
+
+protected:
+ virtual int do_compare(const void* lhs, const void* rhs) const = 0;
+
+ // take care of FBC...
+ virtual void reservedSortedVectorImpl1();
+ virtual void reservedSortedVectorImpl2();
+ virtual void reservedSortedVectorImpl3();
+ virtual void reservedSortedVectorImpl4();
+ virtual void reservedSortedVectorImpl5();
+ virtual void reservedSortedVectorImpl6();
+ virtual void reservedSortedVectorImpl7();
+ virtual void reservedSortedVectorImpl8();
+
+private:
+ ssize_t _indexOrderOf(const void* item, size_t* order = 0) const;
+
+ // these are made private, because they can't be used on a SortedVector
+ // (they don't have an implementation either)
+ ssize_t add();
+ void pop();
+ void push();
+ void push(const void* item);
+ ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
+ ssize_t appendVector(const VectorImpl& vector);
+ ssize_t insertAt(size_t where, size_t numItems = 1);
+ ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
+ ssize_t replaceAt(size_t index);
+ ssize_t replaceAt(const void* item, size_t index);
+};
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_IMPL_H
diff --git a/include/utils/ZipEntry.h b/include/utils/ZipEntry.h
new file mode 100644
index 0000000..e4698df
--- /dev/null
+++ b/include/utils/ZipEntry.h
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Zip archive entries.
+//
+// The ZipEntry class is tightly meshed with the ZipFile class.
+//
+#ifndef __LIBS_ZIPENTRY_H
+#define __LIBS_ZIPENTRY_H
+
+#include "Errors.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+namespace android {
+
+class ZipFile;
+
+/*
+ * ZipEntry objects represent a single entry in a Zip archive.
+ *
+ * You can use one of these to get or set information about an entry, but
+ * there are no functions here for accessing the data itself. (We could
+ * tuck a pointer to the ZipFile in here for convenience, but that raises
+ * the likelihood of using ZipEntry objects after discarding the ZipFile.)
+ *
+ * File information is stored in two places: next to the file data (the Local
+ * File Header, and possibly a Data Descriptor), and at the end of the file
+ * (the Central Directory Entry). The two must be kept in sync.
+ */
+class ZipEntry {
+public:
+ friend class ZipFile;
+
+ ZipEntry(void)
+ : mDeleted(false), mMarked(false)
+ {}
+ ~ZipEntry(void) {}
+
+ /*
+ * Returns "true" if the data is compressed.
+ */
+ bool isCompressed(void) const {
+ return mCDE.mCompressionMethod != kCompressStored;
+ }
+ int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
+
+ /*
+ * Return the uncompressed length.
+ */
+ off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
+
+ /*
+ * Return the compressed length. For uncompressed data, this returns
+ * the same thing as getUncompresesdLen().
+ */
+ off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
+
+ /*
+ * Return the absolute file offset of the start of the compressed or
+ * uncompressed data.
+ */
+ off_t getFileOffset(void) const {
+ return mCDE.mLocalHeaderRelOffset +
+ LocalFileHeader::kLFHLen +
+ mLFH.mFileNameLength +
+ mLFH.mExtraFieldLength;
+ }
+
+ /*
+ * Return the data CRC.
+ */
+ unsigned long getCRC32(void) const { return mCDE.mCRC32; }
+
+ /*
+ * Return file modification time in UNIX seconds-since-epoch.
+ */
+ time_t getModWhen(void) const;
+
+ /*
+ * Return the archived file name.
+ */
+ const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
+
+ /*
+ * Application-defined "mark". Can be useful when synchronizing the
+ * contents of an archive with contents on disk.
+ */
+ bool getMarked(void) const { return mMarked; }
+ void setMarked(bool val) { mMarked = val; }
+
+ /*
+ * Some basic functions for raw data manipulation. "LE" means
+ * Little Endian.
+ */
+ static inline unsigned short getShortLE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8);
+ }
+ static inline unsigned long getLongLE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+ }
+ static inline void putShortLE(unsigned char* buf, short val) {
+ buf[0] = (unsigned char) val;
+ buf[1] = (unsigned char) (val >> 8);
+ }
+ static inline void putLongLE(unsigned char* buf, long val) {
+ buf[0] = (unsigned char) val;
+ buf[1] = (unsigned char) (val >> 8);
+ buf[2] = (unsigned char) (val >> 16);
+ buf[3] = (unsigned char) (val >> 24);
+ }
+
+ /* defined for Zip archives */
+ enum {
+ kCompressStored = 0, // no compression
+ // shrunk = 1,
+ // reduced 1 = 2,
+ // reduced 2 = 3,
+ // reduced 3 = 4,
+ // reduced 4 = 5,
+ // imploded = 6,
+ // tokenized = 7,
+ kCompressDeflated = 8, // standard deflate
+ // Deflate64 = 9,
+ // lib imploded = 10,
+ // reserved = 11,
+ // bzip2 = 12,
+ };
+
+ /*
+ * Deletion flag. If set, the entry will be removed on the next
+ * call to "flush".
+ */
+ bool getDeleted(void) const { return mDeleted; }
+
+protected:
+ /*
+ * Initialize the structure from the file, which is pointing at
+ * our Central Directory entry.
+ */
+ status_t initFromCDE(FILE* fp);
+
+ /*
+ * Initialize the structure for a new file. We need the filename
+ * and comment so that we can properly size the LFH area. The
+ * filename is mandatory, the comment is optional.
+ */
+ void initNew(const char* fileName, const char* comment);
+
+ /*
+ * Initialize the structure with the contents of a ZipEntry from
+ * another file.
+ */
+ status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
+
+ /*
+ * Add some pad bytes to the LFH. We do this by adding or resizing
+ * the "extra" field.
+ */
+ status_t addPadding(int padding);
+
+ /*
+ * Set information about the data for this entry.
+ */
+ void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+ int compressionMethod);
+
+ /*
+ * Set the modification date.
+ */
+ void setModWhen(time_t when);
+
+ /*
+ * Return the offset of the local file header.
+ */
+ off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
+
+ /*
+ * Set the offset of the local file header, relative to the start of
+ * the current file.
+ */
+ void setLFHOffset(off_t offset) {
+ mCDE.mLocalHeaderRelOffset = (long) offset;
+ }
+
+ /* mark for deletion; used by ZipFile::remove() */
+ void setDeleted(void) { mDeleted = true; }
+
+private:
+ /* these are private and not defined */
+ ZipEntry(const ZipEntry& src);
+ ZipEntry& operator=(const ZipEntry& src);
+
+ /* returns "true" if the CDE and the LFH agree */
+ bool compareHeaders(void) const;
+ void copyCDEtoLFH(void);
+
+ bool mDeleted; // set if entry is pending deletion
+ bool mMarked; // app-defined marker
+
+ /*
+ * Every entry in the Zip archive starts off with one of these.
+ */
+ class LocalFileHeader {
+ public:
+ LocalFileHeader(void) :
+ mVersionToExtract(0),
+ mGPBitFlag(0),
+ mCompressionMethod(0),
+ mLastModFileTime(0),
+ mLastModFileDate(0),
+ mCRC32(0),
+ mCompressedSize(0),
+ mUncompressedSize(0),
+ mFileNameLength(0),
+ mExtraFieldLength(0),
+ mFileName(NULL),
+ mExtraField(NULL)
+ {}
+ virtual ~LocalFileHeader(void) {
+ delete[] mFileName;
+ delete[] mExtraField;
+ }
+
+ status_t read(FILE* fp);
+ status_t write(FILE* fp);
+
+ // unsigned long mSignature;
+ unsigned short mVersionToExtract;
+ unsigned short mGPBitFlag;
+ unsigned short mCompressionMethod;
+ unsigned short mLastModFileTime;
+ unsigned short mLastModFileDate;
+ unsigned long mCRC32;
+ unsigned long mCompressedSize;
+ unsigned long mUncompressedSize;
+ unsigned short mFileNameLength;
+ unsigned short mExtraFieldLength;
+ unsigned char* mFileName;
+ unsigned char* mExtraField;
+
+ enum {
+ kSignature = 0x04034b50,
+ kLFHLen = 30, // LocalFileHdr len, excl. var fields
+ };
+
+ void dump(void) const;
+ };
+
+ /*
+ * Every entry in the Zip archive has one of these in the "central
+ * directory" at the end of the file.
+ */
+ class CentralDirEntry {
+ public:
+ CentralDirEntry(void) :
+ mVersionMadeBy(0),
+ mVersionToExtract(0),
+ mGPBitFlag(0),
+ mCompressionMethod(0),
+ mLastModFileTime(0),
+ mLastModFileDate(0),
+ mCRC32(0),
+ mCompressedSize(0),
+ mUncompressedSize(0),
+ mFileNameLength(0),
+ mExtraFieldLength(0),
+ mFileCommentLength(0),
+ mDiskNumberStart(0),
+ mInternalAttrs(0),
+ mExternalAttrs(0),
+ mLocalHeaderRelOffset(0),
+ mFileName(NULL),
+ mExtraField(NULL),
+ mFileComment(NULL)
+ {}
+ virtual ~CentralDirEntry(void) {
+ delete[] mFileName;
+ delete[] mExtraField;
+ delete[] mFileComment;
+ }
+
+ status_t read(FILE* fp);
+ status_t write(FILE* fp);
+
+ // unsigned long mSignature;
+ unsigned short mVersionMadeBy;
+ unsigned short mVersionToExtract;
+ unsigned short mGPBitFlag;
+ unsigned short mCompressionMethod;
+ unsigned short mLastModFileTime;
+ unsigned short mLastModFileDate;
+ unsigned long mCRC32;
+ unsigned long mCompressedSize;
+ unsigned long mUncompressedSize;
+ unsigned short mFileNameLength;
+ unsigned short mExtraFieldLength;
+ unsigned short mFileCommentLength;
+ unsigned short mDiskNumberStart;
+ unsigned short mInternalAttrs;
+ unsigned long mExternalAttrs;
+ unsigned long mLocalHeaderRelOffset;
+ unsigned char* mFileName;
+ unsigned char* mExtraField;
+ unsigned char* mFileComment;
+
+ void dump(void) const;
+
+ enum {
+ kSignature = 0x02014b50,
+ kCDELen = 46, // CentralDirEnt len, excl. var fields
+ };
+ };
+
+ enum {
+ //kDataDescriptorSignature = 0x08074b50, // currently unused
+ kDataDescriptorLen = 16, // four 32-bit fields
+
+ kDefaultVersion = 20, // need deflate, nothing much else
+ kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
+ kUsesDataDescr = 0x0008, // GPBitFlag bit 3
+ };
+
+ LocalFileHeader mLFH;
+ CentralDirEntry mCDE;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPENTRY_H
diff --git a/include/utils/ZipFile.h b/include/utils/ZipFile.h
new file mode 100644
index 0000000..44df5bb
--- /dev/null
+++ b/include/utils/ZipFile.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// General-purpose Zip archive access. This class allows both reading and
+// writing to Zip archives, including deletion of existing entries.
+//
+#ifndef __LIBS_ZIPFILE_H
+#define __LIBS_ZIPFILE_H
+
+#include "ZipEntry.h"
+#include "Vector.h"
+#include "Errors.h"
+#include <stdio.h>
+
+namespace android {
+
+/*
+ * Manipulate a Zip archive.
+ *
+ * Some changes will not be visible in the until until "flush" is called.
+ *
+ * The correct way to update a file archive is to make all changes to a
+ * copy of the archive in a temporary file, and then unlink/rename over
+ * the original after everything completes. Because we're only interested
+ * in using this for packaging, we don't worry about such things. Crashing
+ * after making changes and before flush() completes could leave us with
+ * an unusable Zip archive.
+ */
+class ZipFile {
+public:
+ ZipFile(void)
+ : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
+ {}
+ ~ZipFile(void) {
+ if (!mReadOnly)
+ flush();
+ if (mZipFp != NULL)
+ fclose(mZipFp);
+ discardEntries();
+ }
+
+ /*
+ * Open a new or existing archive.
+ */
+ typedef enum {
+ kOpenReadOnly = 0x01,
+ kOpenReadWrite = 0x02,
+ kOpenCreate = 0x04, // create if it doesn't exist
+ kOpenTruncate = 0x08, // if it exists, empty it
+ };
+ status_t open(const char* zipFileName, int flags);
+
+ /*
+ * Add a file to the end of the archive. Specify whether you want the
+ * library to try to store it compressed.
+ *
+ * If "storageName" is specified, the archive will use that instead
+ * of "fileName".
+ *
+ * If there is already an entry with the same name, the call fails.
+ * Existing entries with the same name must be removed first.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const char* fileName, int compressionMethod,
+ ZipEntry** ppEntry)
+ {
+ return add(fileName, fileName, compressionMethod, ppEntry);
+ }
+ status_t add(const char* fileName, const char* storageName,
+ int compressionMethod, ZipEntry** ppEntry)
+ {
+ return addCommon(fileName, NULL, 0, storageName,
+ ZipEntry::kCompressStored,
+ compressionMethod, ppEntry);
+ }
+
+ /*
+ * Add a file that is already compressed with gzip.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t addGzip(const char* fileName, const char* storageName,
+ ZipEntry** ppEntry)
+ {
+ return addCommon(fileName, NULL, 0, storageName,
+ ZipEntry::kCompressDeflated,
+ ZipEntry::kCompressDeflated, ppEntry);
+ }
+
+ /*
+ * Add a file from an in-memory data buffer.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const void* data, size_t size, const char* storageName,
+ int compressionMethod, ZipEntry** ppEntry)
+ {
+ return addCommon(NULL, data, size, storageName,
+ ZipEntry::kCompressStored,
+ compressionMethod, ppEntry);
+ }
+
+ /*
+ * Add an entry by copying it from another zip file. If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+ int padding, ZipEntry** ppEntry);
+
+ /*
+ * Mark an entry as having been removed. It is not actually deleted
+ * from the archive or our internal data structures until flush() is
+ * called.
+ */
+ status_t remove(ZipEntry* pEntry);
+
+ /*
+ * Flush changes. If mNeedCDRewrite is set, this writes the central dir.
+ */
+ status_t flush(void);
+
+ /*
+ * Expand the data into the buffer provided. The buffer must hold
+ * at least <uncompressed len> bytes. Variation expands directly
+ * to a file.
+ *
+ * Returns "false" if an error was encountered in the compressed data.
+ */
+ //bool uncompress(const ZipEntry* pEntry, void* buf) const;
+ //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
+ void* uncompress(const ZipEntry* pEntry);
+
+ /*
+ * Get an entry, by name. Returns NULL if not found.
+ *
+ * Does not return entries pending deletion.
+ */
+ ZipEntry* getEntryByName(const char* fileName) const;
+
+ /*
+ * Get the Nth entry in the archive.
+ *
+ * This will return an entry that is pending deletion.
+ */
+ int getNumEntries(void) const { return mEntries.size(); }
+ ZipEntry* getEntryByIndex(int idx) const;
+
+private:
+ /* these are private and not defined */
+ ZipFile(const ZipFile& src);
+ ZipFile& operator=(const ZipFile& src);
+
+ class EndOfCentralDir {
+ public:
+ EndOfCentralDir(void) :
+ mDiskNumber(0),
+ mDiskWithCentralDir(0),
+ mNumEntries(0),
+ mTotalNumEntries(0),
+ mCentralDirSize(0),
+ mCentralDirOffset(0),
+ mCommentLen(0),
+ mComment(NULL)
+ {}
+ virtual ~EndOfCentralDir(void) {
+ delete[] mComment;
+ }
+
+ status_t readBuf(const unsigned char* buf, int len);
+ status_t write(FILE* fp);
+
+ //unsigned long mSignature;
+ unsigned short mDiskNumber;
+ unsigned short mDiskWithCentralDir;
+ unsigned short mNumEntries;
+ unsigned short mTotalNumEntries;
+ unsigned long mCentralDirSize;
+ unsigned long mCentralDirOffset; // offset from first disk
+ unsigned short mCommentLen;
+ unsigned char* mComment;
+
+ enum {
+ kSignature = 0x06054b50,
+ kEOCDLen = 22, // EndOfCentralDir len, excl. comment
+
+ kMaxCommentLen = 65535, // longest possible in ushort
+ kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
+
+ };
+
+ void dump(void) const;
+ };
+
+
+ /* read all entries in the central dir */
+ status_t readCentralDir(void);
+
+ /* crunch deleted entries out */
+ status_t crunchArchive(void);
+
+ /* clean up mEntries */
+ void discardEntries(void);
+
+ /* common handler for all "add" functions */
+ status_t addCommon(const char* fileName, const void* data, size_t size,
+ const char* storageName, int sourceType, int compressionMethod,
+ ZipEntry** ppEntry);
+
+ /* copy all of "srcFp" into "dstFp" */
+ status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
+ /* copy all of "data" into "dstFp" */
+ status_t copyDataToFp(FILE* dstFp,
+ const void* data, size_t size, unsigned long* pCRC32);
+ /* copy some of "srcFp" into "dstFp" */
+ status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+ unsigned long* pCRC32);
+ /* like memmove(), but on parts of a single file */
+ status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
+ /* compress all of "srcFp" into "dstFp", using Deflate */
+ status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
+ const void* data, size_t size, unsigned long* pCRC32);
+
+ /* get modification date from a file descriptor */
+ time_t getModTime(int fd);
+
+ /*
+ * We use stdio FILE*, which gives us buffering but makes dealing
+ * with files >2GB awkward. Until we support Zip64, we're fine.
+ */
+ FILE* mZipFp; // Zip file pointer
+
+ /* one of these per file */
+ EndOfCentralDir mEOCD;
+
+ /* did we open this read-only? */
+ bool mReadOnly;
+
+ /* set this when we trash the central dir */
+ bool mNeedCDRewrite;
+
+ /*
+ * One ZipEntry per entry in the zip file. I'm using pointers instead
+ * of objects because it's easier than making operator= work for the
+ * classes and sub-classes.
+ */
+ Vector<ZipEntry*> mEntries;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPFILE_H
diff --git a/include/utils/ZipFileCRO.h b/include/utils/ZipFileCRO.h
new file mode 100644
index 0000000..30e0036
--- /dev/null
+++ b/include/utils/ZipFileCRO.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+//
+// C API for ead-only access to Zip archives, with minimal heap allocation.
+//
+#ifndef __LIBS_ZIPFILECRO_H
+#define __LIBS_ZIPFILECRO_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Trivial typedef to ensure that ZipFileCRO is not treated as a simple integer.
+ */
+typedef void* ZipFileCRO;
+
+/*
+ * Trivial typedef to ensure that ZipEntryCRO is not treated as a simple
+ * integer. We use NULL to indicate an invalid value.
+ */
+typedef void* ZipEntryCRO;
+
+extern ZipFileCRO ZipFileXRO_open(const char* path);
+
+extern void ZipFileCRO_destroy(ZipFileCRO zip);
+
+extern ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zip,
+ const char* fileName);
+
+extern bool ZipFileCRO_getEntryInfo(ZipFileCRO zip, ZipEntryCRO entry,
+ int* pMethod, long* pUncompLen,
+ long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32);
+
+extern bool ZipFileCRO_uncompressEntry(ZipFileCRO zip, ZipEntryCRO entry, int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__LIBS_ZIPFILECRO_H*/
diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h
new file mode 100644
index 0000000..51c4f2f
--- /dev/null
+++ b/include/utils/ZipFileRO.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//
+// Read-only access to Zip archives, with minimal heap allocation.
+//
+// This is similar to the more-complete ZipFile class, but no attempt
+// has been made to make them interchangeable. This class operates under
+// a very different set of assumptions and constraints.
+//
+#ifndef __LIBS_ZIPFILERO_H
+#define __LIBS_ZIPFILERO_H
+
+#include "Errors.h"
+#include "FileMap.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+namespace android {
+
+/*
+ * Trivial typedef to ensure that ZipEntryRO is not treated as a simple
+ * integer. We use NULL to indicate an invalid value.
+ */
+typedef void* ZipEntryRO;
+
+/*
+ * Open a Zip archive for reading.
+ *
+ * We want "open" and "find entry by name" to be fast operations, and we
+ * want to use as little memory as possible. We memory-map the file,
+ * and load a hash table with pointers to the filenames (which aren't
+ * null-terminated). The other fields are at a fixed offset from the
+ * filename, so we don't need to extract those (but we do need to byte-read
+ * and endian-swap them every time we want them).
+ *
+ * To speed comparisons when doing a lookup by name, we could make the mapping
+ * "private" (copy-on-write) and null-terminate the filenames after verifying
+ * the record structure. However, this requires a private mapping of
+ * every page that the Central Directory touches. Easier to tuck a copy
+ * of the string length into the hash table entry.
+ */
+class ZipFileRO {
+public:
+ ZipFileRO()
+ : mFd(-1), mFileMap(NULL), mHashTableSize(-1), mHashTable(NULL)
+ {}
+ ~ZipFileRO() {
+ free(mHashTable);
+ if (mFileMap)
+ mFileMap->release();
+ if (mFd >= 0)
+ close(mFd);
+ }
+
+ /*
+ * Open an archive.
+ */
+ status_t open(const char* zipFileName);
+
+ /*
+ * Find an entry, by name. Returns the entry identifier, or NULL if
+ * not found.
+ *
+ * If two entries have the same name, one will be chosen at semi-random.
+ */
+ ZipEntryRO findEntryByName(const char* fileName) const;
+
+ /*
+ * Return the #of entries in the Zip archive.
+ */
+ int getNumEntries(void) const {
+ return mNumEntries;
+ }
+
+ /*
+ * Return the Nth entry. Zip file entries are not stored in sorted
+ * order, and updated entries may appear at the end, so anyone walking
+ * the archive needs to avoid making ordering assumptions. We take
+ * that further by returning the Nth non-empty entry in the hash table
+ * rather than the Nth entry in the archive.
+ *
+ * Valid values are [0..numEntries).
+ *
+ * [This is currently O(n). If it needs to be fast we can allocate an
+ * additional data structure or provide an iterator interface.]
+ */
+ ZipEntryRO findEntryByIndex(int idx) const;
+
+ /*
+ * Copy the filename into the supplied buffer. Returns 0 on success,
+ * -1 if "entry" is invalid, or the filename length if it didn't fit. The
+ * length, and the returned string, include the null-termination.
+ */
+ int getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) const;
+
+ /*
+ * Get the vital stats for an entry. Pass in NULL pointers for anything
+ * you don't need.
+ *
+ * "*pOffset" holds the Zip file offset of the entry's data.
+ *
+ * Returns "false" if "entry" is bogus or if the data in the Zip file
+ * appears to be bad.
+ */
+ bool getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen,
+ long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const;
+
+ /*
+ * Create a new FileMap object that maps a subset of the archive. For
+ * an uncompressed entry this effectively provides a pointer to the
+ * actual data, for a compressed entry this provides the input buffer
+ * for inflate().
+ */
+ FileMap* createEntryFileMap(ZipEntryRO entry) const;
+
+ /*
+ * Uncompress the data into a buffer. Depending on the compression
+ * format, this is either an "inflate" operation or a memcpy.
+ *
+ * Use "uncompLen" from getEntryInfo() to determine the required
+ * buffer size.
+ *
+ * Returns "true" on success.
+ */
+ bool uncompressEntry(ZipEntryRO entry, void* buffer) const;
+
+ /*
+ * Uncompress the data to an open file descriptor.
+ */
+ bool uncompressEntry(ZipEntryRO entry, int fd) const;
+
+ /* Zip compression methods we support */
+ enum {
+ kCompressStored = 0, // no compression
+ kCompressDeflated = 8, // standard deflate
+ };
+
+ /*
+ * Utility function: uncompress deflated data, buffer to buffer.
+ */
+ static bool inflateBuffer(void* outBuf, const void* inBuf,
+ long uncompLen, long compLen);
+
+ /*
+ * Utility function: uncompress deflated data, buffer to fd.
+ */
+ static bool inflateBuffer(int fd, const void* inBuf,
+ long uncompLen, long compLen);
+
+ /*
+ * Some basic functions for raw data manipulation. "LE" means
+ * Little Endian.
+ */
+ static inline unsigned short get2LE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8);
+ }
+ static inline unsigned long get4LE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+ }
+
+private:
+ /* these are private and not defined */
+ ZipFileRO(const ZipFileRO& src);
+ ZipFileRO& operator=(const ZipFileRO& src);
+
+ /* parse the archive, prepping internal structures */
+ bool parseZipArchive(void);
+
+ /* add a new entry to the hash table */
+ void addToHash(const char* str, int strLen, unsigned int hash);
+
+ /* compute string hash code */
+ static unsigned int computeHash(const char* str, int len);
+
+ /* convert a ZipEntryRO back to a hash table index */
+ int entryToIndex(const ZipEntryRO entry) const;
+
+ /*
+ * One entry in the hash table.
+ */
+ typedef struct HashEntry {
+ const char* name;
+ unsigned short nameLen;
+ //unsigned int hash;
+ } HashEntry;
+
+ /* open Zip archive */
+ int mFd;
+
+ /* mapped file */
+ FileMap* mFileMap;
+
+ /* number of entries in the Zip archive */
+ int mNumEntries;
+
+ /*
+ * We know how many entries are in the Zip archive, so we have a
+ * fixed-size hash table. We probe for an empty slot.
+ */
+ int mHashTableSize;
+ HashEntry* mHashTable;
+};
+
+}; // namespace android
+
+#endif /*__LIBS_ZIPFILERO_H*/
diff --git a/include/utils/ZipUtils.h b/include/utils/ZipUtils.h
new file mode 100644
index 0000000..42c42b6
--- /dev/null
+++ b/include/utils/ZipUtils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//
+// Miscellaneous zip/gzip utility functions.
+//
+#ifndef __LIBS_ZIPUTILS_H
+#define __LIBS_ZIPUTILS_H
+
+#include <stdio.h>
+
+namespace android {
+
+/*
+ * Container class for utility functions, primarily for namespace reasons.
+ */
+class ZipUtils {
+public:
+ /*
+ * General utility function for uncompressing "deflate" data from a file
+ * to a buffer.
+ */
+ static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
+ long compressedLen);
+ static bool inflateToBuffer(FILE* fp, void* buf, long uncompressedLen,
+ long compressedLen);
+
+ /*
+ * Someday we might want to make this generic and handle bzip2 ".bz2"
+ * files too.
+ *
+ * We could declare gzip to be a sub-class of zip that has exactly
+ * one always-compressed entry, but we currently want to treat Zip
+ * and gzip as distinct, so there's no value.
+ *
+ * The zlib library has some gzip utilities, but it has no interface
+ * for extracting the uncompressed length of the file (you do *not*
+ * want to gzseek to the end).
+ *
+ * Pass in a seeked file pointer for the gzip file. If this is a gzip
+ * file, we set our return values appropriately and return "true" with
+ * the file seeked to the start of the compressed data.
+ */
+ static bool examineGzip(FILE* fp, int* pCompressionMethod,
+ long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32);
+
+private:
+ ZipUtils() {}
+ ~ZipUtils() {}
+};
+
+}; // namespace android
+
+#endif /*__LIBS_ZIPUTILS_H*/
diff --git a/include/utils/ashmem.h b/include/utils/ashmem.h
new file mode 100644
index 0000000..0854775
--- /dev/null
+++ b/include/utils/ashmem.h
@@ -0,0 +1,41 @@
+/* utils/ashmem.h
+ **
+ ** Copyright 2008 The Android Open Source Project
+ **
+ ** This file is dual licensed. It may be redistributed and/or modified
+ ** under the terms of the Apache 2.0 License OR version 2 of the GNU
+ ** General Public License.
+ */
+
+#ifndef _UTILS_ASHMEM_H
+#define _UTILS_ASHMEM_H
+
+#include <linux/limits.h>
+#include <linux/ioctl.h>
+
+#define ASHMEM_NAME_LEN 256
+
+#define ASHMEM_NAME_DEF "dev/ashmem"
+
+/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
+#define ASHMEM_NOT_REAPED 0
+#define ASHMEM_WAS_REAPED 1
+
+/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
+#define ASHMEM_NOW_UNPINNED 0
+#define ASHMEM_NOW_PINNED 1
+
+#define __ASHMEMIOC 0x77
+
+#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
+#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
+#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
+#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
+#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long)
+#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6)
+#define ASHMEM_PIN _IO(__ASHMEMIOC, 7)
+#define ASHMEM_UNPIN _IO(__ASHMEMIOC, 8)
+#define ASHMEM_ISPINNED _IO(__ASHMEMIOC, 9)
+#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
+
+#endif /* _UTILS_ASHMEM_H */
diff --git a/include/utils/executablepath.h b/include/utils/executablepath.h
new file mode 100644
index 0000000..c979432
--- /dev/null
+++ b/include/utils/executablepath.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#ifndef _UTILS_EXECUTABLEPATH_H
+#define _UTILS_EXECUTABLEPATH_H
+
+#include <limits.h>
+
+// returns the path to this executable
+#if __cplusplus
+extern "C"
+#endif
+void executablepath(char s[PATH_MAX]);
+
+#endif // _UTILS_EXECUTABLEPATH_H
diff --git a/include/utils/inet_address.h b/include/utils/inet_address.h
new file mode 100644
index 0000000..dbd8672
--- /dev/null
+++ b/include/utils/inet_address.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Internet address classes. Modeled after Java classes.
+//
+#ifndef _RUNTIME_INET_ADDRESS_H
+#define _RUNTIME_INET_ADDRESS_H
+
+#ifdef HAVE_ANDROID_OS
+#error DO NOT USE THIS FILE IN THE DEVICE BUILD
+#endif
+
+
+namespace android {
+
+/*
+ * This class holds Internet addresses. Perhaps more useful is its
+ * ability to look up addresses by name.
+ *
+ * Invoke one of the static factory methods to create a new object.
+ */
+class InetAddress {
+public:
+ virtual ~InetAddress(void);
+
+ // create from w.x.y.z or foo.bar.com notation
+ static InetAddress* getByName(const char* host);
+
+ // copy-construction
+ InetAddress(const InetAddress& orig);
+
+ const void* getAddress(void) const { return mAddress; }
+ int getAddressLength(void) const { return mLength; }
+ const char* getHostName(void) const { return mName; }
+
+private:
+ InetAddress(void);
+ // assignment (private)
+ InetAddress& operator=(const InetAddress& addr);
+
+ // use a void* here so we don't have to expose actual socket headers
+ void* mAddress; // this is really a ptr to sockaddr_in
+ int mLength;
+ char* mName;
+};
+
+
+/*
+ * Base class for socket addresses.
+ */
+class SocketAddress {
+public:
+ SocketAddress() {}
+ virtual ~SocketAddress() {}
+};
+
+
+/*
+ * Internet address class. This combines an InetAddress with a port.
+ */
+class InetSocketAddress : public SocketAddress {
+public:
+ InetSocketAddress() :
+ mAddress(0), mPort(-1)
+ {}
+ ~InetSocketAddress(void) {
+ delete mAddress;
+ }
+
+ // Create an address with a host wildcard (useful for servers).
+ bool create(int port);
+ // Create an address with the specified host and port.
+ bool create(const InetAddress* addr, int port);
+ // Create an address with the specified host and port. Does the
+ // hostname lookup.
+ bool create(const char* host, int port);
+
+ const InetAddress* getAddress(void) const { return mAddress; }
+ const int getPort(void) const { return mPort; }
+ const char* getHostName(void) const { return mAddress->getHostName(); }
+
+private:
+ InetAddress* mAddress;
+ int mPort;
+};
+
+}; // namespace android
+
+#endif // _RUNTIME_INET_ADDRESS_H
diff --git a/include/utils/logger.h b/include/utils/logger.h
new file mode 100644
index 0000000..3a08019
--- /dev/null
+++ b/include/utils/logger.h
@@ -0,0 +1,46 @@
+/* utils/logger.h
+**
+** Copyright 2007, The Android Open Source Project
+**
+** This file is dual licensed. It may be redistributed and/or modified
+** under the terms of the Apache 2.0 License OR version 2 of the GNU
+** General Public License.
+*/
+
+#ifndef _UTILS_LOGGER_H
+#define _UTILS_LOGGER_H
+
+#include <stdint.h>
+
+struct logger_entry {
+ uint16_t len; /* length of the payload */
+ uint16_t __pad; /* no matter what, we get 2 bytes of padding */
+ int32_t pid; /* generating process's pid */
+ int32_t tid; /* generating process's tid */
+ int32_t sec; /* seconds since Epoch */
+ int32_t nsec; /* nanoseconds */
+ char msg[0]; /* the entry's payload */
+};
+
+#define LOGGER_LOG_MAIN "log/main"
+#define LOGGER_LOG_RADIO "log/radio"
+#define LOGGER_LOG_EVENTS "log/events"
+
+#define LOGGER_ENTRY_MAX_LEN (4*1024)
+#define LOGGER_ENTRY_MAX_PAYLOAD \
+ (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
+
+#ifdef HAVE_IOCTL
+
+#include <sys/ioctl.h>
+
+#define __LOGGERIO 0xAE
+
+#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
+#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
+#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
+#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
+
+#endif // HAVE_IOCTL
+
+#endif /* _UTILS_LOGGER_H */
diff --git a/include/utils/misc.h b/include/utils/misc.h
new file mode 100644
index 0000000..62e84b4
--- /dev/null
+++ b/include/utils/misc.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Handy utility functions and portability code.
+//
+#ifndef _LIBS_UTILS_MISC_H
+#define _LIBS_UTILS_MISC_H
+
+#include <sys/time.h>
+#include "utils/Endian.h"
+
+namespace android {
+
+/* get #of elements in a static array */
+#ifndef NELEM
+# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+#endif
+
+/*
+ * Make a copy of the string, using "new[]" instead of "malloc". Free the
+ * string with delete[].
+ *
+ * Returns NULL if "str" is NULL.
+ */
+char* strdupNew(const char* str);
+
+/*
+ * Concatenate an argument vector into a single string. If argc is >= 0
+ * it will be used; if it's < 0 then the last element in the arg vector
+ * must be NULL.
+ *
+ * This inserts a space between each argument.
+ *
+ * This does not automatically add double quotes around arguments with
+ * spaces in them. This practice is necessary for Win32, because Win32's
+ * CreateProcess call is stupid.
+ *
+ * The caller should delete[] the returned string.
+ */
+char* concatArgv(int argc, const char* const argv[]);
+
+/*
+ * Count up the number of arguments in "argv". The count does not include
+ * the final NULL entry.
+ */
+int countArgv(const char* const argv[]);
+
+/*
+ * Some utility functions for working with files. These could be made
+ * part of a "File" class.
+ */
+typedef enum FileType {
+ kFileTypeUnknown = 0,
+ kFileTypeNonexistent, // i.e. ENOENT
+ kFileTypeRegular,
+ kFileTypeDirectory,
+ kFileTypeCharDev,
+ kFileTypeBlockDev,
+ kFileTypeFifo,
+ kFileTypeSymlink,
+ kFileTypeSocket,
+} FileType;
+/* get the file's type; follows symlinks */
+FileType getFileType(const char* fileName);
+/* get the file's modification date; returns -1 w/errno set on failure */
+time_t getFileModDate(const char* fileName);
+
+/*
+ * Round up to the nearest power of 2. Handy for hash tables.
+ */
+unsigned int roundUpPower2(unsigned int val);
+
+void strreverse(char* begin, char* end);
+void k_itoa(int value, char* str, int base);
+char* itoa(int val, int base);
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_MISC_H
diff --git a/include/utils/ported.h b/include/utils/ported.h
new file mode 100644
index 0000000..eb3be01
--- /dev/null
+++ b/include/utils/ported.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Standard functions ported to the current platform. Note these are NOT
+// in the "android" namespace.
+//
+#ifndef _LIBS_UTILS_PORTED_H
+#define _LIBS_UTILS_PORTED_H
+
+#include <sys/time.h> // for timeval
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* library replacement functions */
+#if defined(NEED_GETTIMEOFDAY)
+int gettimeofday(struct timeval* tv, struct timezone* tz);
+#endif
+#if defined(NEED_USLEEP)
+void usleep(unsigned long usec);
+#endif
+#if defined(NEED_PIPE)
+int pipe(int filedes[2]);
+#endif
+#if defined(NEED_SETENV)
+int setenv(const char* name, const char* value, int overwrite);
+void unsetenv(const char* name);
+char* getenv(const char* name);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _LIBS_UTILS_PORTED_H
diff --git a/include/utils/string_array.h b/include/utils/string_array.h
new file mode 100644
index 0000000..ede0644
--- /dev/null
+++ b/include/utils/string_array.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Sortable array of strings. STL-ish, but STL-free.
+//
+#ifndef _LIBS_UTILS_STRING_ARRAY_H
+#define _LIBS_UTILS_STRING_ARRAY_H
+
+#include <stdlib.h>
+#include <string.h>
+
+namespace android {
+
+//
+// An expanding array of strings. Add, get, sort, delete.
+//
+class StringArray {
+public:
+ StringArray()
+ : mMax(0), mCurrent(0), mArray(NULL)
+ {}
+ virtual ~StringArray() {
+ for (int i = 0; i < mCurrent; i++)
+ delete[] mArray[i];
+ delete[] mArray;
+ }
+
+ //
+ // Add a string. A copy of the string is made.
+ //
+ bool push_back(const char* str) {
+ if (mCurrent >= mMax) {
+ char** tmp;
+
+ if (mMax == 0)
+ mMax = 16; // initial storage
+ else
+ mMax *= 2;
+
+ tmp = new char*[mMax];
+ if (tmp == NULL)
+ return false;
+
+ memcpy(tmp, mArray, mCurrent * sizeof(char*));
+ delete[] mArray;
+ mArray = tmp;
+ }
+
+ int len = strlen(str);
+ mArray[mCurrent] = new char[len+1];
+ memcpy(mArray[mCurrent], str, len+1);
+ mCurrent++;
+
+ return true;
+ }
+
+ //
+ // Delete an entry.
+ //
+ void erase(int idx) {
+ if (idx < 0 || idx >= mCurrent)
+ return;
+ delete[] mArray[idx];
+ if (idx < mCurrent-1) {
+ memmove(&mArray[idx], &mArray[idx+1],
+ (mCurrent-1 - idx) * sizeof(char*));
+ }
+ mCurrent--;
+ }
+
+ //
+ // Sort the array.
+ //
+ void sort(int (*compare)(const void*, const void*)) {
+ qsort(mArray, mCurrent, sizeof(char*), compare);
+ }
+
+ //
+ // Pass this to the sort routine to do an ascending alphabetical sort.
+ //
+ static int cmpAscendingAlpha(const void* pstr1, const void* pstr2) {
+ return strcmp(*(const char**)pstr1, *(const char**)pstr2);
+ }
+
+ //
+ // Get the #of items in the array.
+ //
+ inline int size(void) const { return mCurrent; }
+
+ //
+ // Return entry N.
+ // [should use operator[] here]
+ //
+ const char* getEntry(int idx) const {
+ if (idx < 0 || idx >= mCurrent)
+ return NULL;
+ return mArray[idx];
+ }
+
+private:
+ int mMax;
+ int mCurrent;
+ char** mArray;
+};
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_STRING_ARRAY_H
diff --git a/include/utils/threads.h b/include/utils/threads.h
new file mode 100644
index 0000000..7dca810
--- /dev/null
+++ b/include/utils/threads.h
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _LIBS_UTILS_THREADS_H
+#define _LIBS_UTILS_THREADS_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <time.h>
+
+// ------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* android_thread_id_t;
+
+typedef int (*android_thread_func_t)(void*);
+
+enum {
+ /*
+ * ***********************************************
+ * ** Keep in sync with android.os.Process.java **
+ * ***********************************************
+ *
+ * This maps directly to the "nice" priorites we use in Android.
+ * A thread priority should be chosen inverse-proportinally to
+ * the amount of work the thread is expected to do. The more work
+ * a thread will do, the less favorable priority it should get so that
+ * it doesn't starve the system. Threads not behaving properly might
+ * be "punished" by the kernel.
+ * Use the levels below when appropriate. Intermediate values are
+ * acceptable, preferably use the {MORE|LESS}_FAVORABLE constants below.
+ */
+ ANDROID_PRIORITY_LOWEST = 19,
+
+ /* use for background tasks */
+ ANDROID_PRIORITY_BACKGROUND = 10,
+
+ /* most threads run at normal priority */
+ ANDROID_PRIORITY_NORMAL = 0,
+
+ /* threads currently running a UI that the user is interacting with */
+ ANDROID_PRIORITY_FOREGROUND = -2,
+
+ /* the main UI thread has a slightly more favorable priority */
+ ANDROID_PRIORITY_DISPLAY = -4,
+
+ /* ui service treads might want to run at a urgent display (uncommon) */
+ ANDROID_PRIORITY_URGENT_DISPLAY = -8,
+
+ /* all normal audio threads */
+ ANDROID_PRIORITY_AUDIO = -16,
+
+ /* service audio threads (uncommon) */
+ ANDROID_PRIORITY_URGENT_AUDIO = -19,
+
+ /* should never be used in practice. regular process might not
+ * be allowed to use this level */
+ ANDROID_PRIORITY_HIGHEST = -20,
+
+ ANDROID_PRIORITY_DEFAULT = ANDROID_PRIORITY_NORMAL,
+ ANDROID_PRIORITY_MORE_FAVORABLE = -1,
+ ANDROID_PRIORITY_LESS_FAVORABLE = +1,
+};
+
+// Create and run a new thread.
+extern int androidCreateThread(android_thread_func_t, void *);
+
+// Create thread with lots of parameters
+extern int androidCreateThreadEtc(android_thread_func_t entryFunction,
+ void *userData,
+ const char* threadName,
+ int32_t threadPriority,
+ size_t threadStackSize,
+ android_thread_id_t *threadId);
+
+// Get some sort of unique identifier for the current thread.
+extern android_thread_id_t androidGetThreadId();
+
+// Low-level thread creation -- never creates threads that can
+// interact with the Java VM.
+extern int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
+ void *userData,
+ const char* threadName,
+ int32_t threadPriority,
+ size_t threadStackSize,
+ android_thread_id_t *threadId);
+
+// Used by the Java Runtime to control how threads are created, so that
+// they can be proper and lovely Java threads.
+typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction,
+ void *userData,
+ const char* threadName,
+ int32_t threadPriority,
+ size_t threadStackSize,
+ android_thread_id_t *threadId);
+
+extern void androidSetCreateThreadFunc(android_create_thread_fn func);
+
+#ifdef __cplusplus
+}
+#endif
+
+// ------------------------------------------------------------------
+// C++ API
+
+#ifdef __cplusplus
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+typedef android_thread_id_t thread_id_t;
+
+typedef android_thread_func_t thread_func_t;
+
+enum {
+ PRIORITY_LOWEST = ANDROID_PRIORITY_LOWEST,
+ PRIORITY_BACKGROUND = ANDROID_PRIORITY_BACKGROUND,
+ PRIORITY_NORMAL = ANDROID_PRIORITY_NORMAL,
+ PRIORITY_FOREGROUND = ANDROID_PRIORITY_FOREGROUND,
+ PRIORITY_DISPLAY = ANDROID_PRIORITY_DISPLAY,
+ PRIORITY_URGENT_DISPLAY = ANDROID_PRIORITY_URGENT_DISPLAY,
+ PRIORITY_AUDIO = ANDROID_PRIORITY_AUDIO,
+ PRIORITY_URGENT_AUDIO = ANDROID_PRIORITY_URGENT_AUDIO,
+ PRIORITY_HIGHEST = ANDROID_PRIORITY_HIGHEST,
+ PRIORITY_DEFAULT = ANDROID_PRIORITY_DEFAULT,
+ PRIORITY_MORE_FAVORABLE = ANDROID_PRIORITY_MORE_FAVORABLE,
+ PRIORITY_LESS_FAVORABLE = ANDROID_PRIORITY_LESS_FAVORABLE,
+};
+
+// Create and run a new thread.
+inline bool createThread(thread_func_t f, void *a) {
+ return androidCreateThread(f, a) ? true : false;
+}
+
+// Create thread with lots of parameters
+inline bool createThreadEtc(thread_func_t entryFunction,
+ void *userData,
+ const char* threadName = "android:unnamed_thread",
+ int32_t threadPriority = PRIORITY_DEFAULT,
+ size_t threadStackSize = 0,
+ thread_id_t *threadId = 0)
+{
+ return androidCreateThreadEtc(entryFunction, userData, threadName,
+ threadPriority, threadStackSize, threadId) ? true : false;
+}
+
+// Get some sort of unique identifier for the current thread.
+inline thread_id_t getThreadId() {
+ return androidGetThreadId();
+}
+
+/*
+ * Simple mutex class. The implementation is system-dependent.
+ *
+ * The mutex must be unlocked by the thread that locked it. They are not
+ * recursive, i.e. the same thread can't lock it multiple times.
+ */
+class Mutex {
+public:
+ Mutex();
+ Mutex(const char* name);
+ ~Mutex();
+
+ // lock or unlock the mutex
+ status_t lock();
+ void unlock();
+
+ // lock if possible; returns 0 on success, error otherwise
+ status_t tryLock();
+
+ // Manages the mutex automatically. It'll be locked when Autolock is
+ // constructed and released when Autolock goes out of scope.
+ class Autolock {
+ public:
+ inline Autolock(Mutex& mutex) : mpMutex(&mutex) { mutex.lock(); }
+ inline Autolock(Mutex* mutex) : mpMutex(mutex) { mutex->lock(); }
+ inline ~Autolock() { mpMutex->unlock(); }
+ private:
+ Mutex* mpMutex;
+ };
+
+private:
+ friend class Condition;
+
+ // A mutex cannot be copied
+ Mutex(const Mutex&);
+ Mutex& operator = (const Mutex&);
+ void _init();
+
+ void* mState;
+};
+
+/*
+ * Automatic mutex. Declare one of these at the top of a function.
+ * When the function returns, it will go out of scope, and release the
+ * mutex.
+ */
+
+typedef Mutex::Autolock AutoMutex;
+
+
+/*
+ * Condition variable class. The implementation is system-dependent.
+ *
+ * Condition variables are paired up with mutexes. Lock the mutex,
+ * call wait(), then either re-wait() if things aren't quite what you want,
+ * or unlock the mutex and continue. All threads calling wait() must
+ * use the same mutex for a given Condition.
+ */
+class Condition {
+public:
+ Condition();
+ ~Condition();
+ // Wait on the condition variable. Lock the mutex before calling.
+ status_t wait(Mutex& mutex);
+ // Wait on the condition variable until the given time. Lock the mutex
+ // before calling.
+ status_t wait(Mutex& mutex, nsecs_t abstime);
+ // same with relative timeout
+ status_t waitRelative(Mutex& mutex, nsecs_t reltime);
+ // Signal the condition variable, allowing one thread to continue.
+ void signal();
+ // Signal the condition variable, allowing all threads to continue.
+ void broadcast();
+
+private:
+ void* mState;
+};
+
+
+/*
+ * Read/write lock. The resource can have multiple readers or one writer,
+ * but can't be read and written at the same time.
+ *
+ * The same thread should not call a lock function while it already has
+ * a lock. (Should be okay for multiple readers.)
+ */
+class ReadWriteLock {
+public:
+ ReadWriteLock()
+ : mNumReaders(0), mNumWriters(0)
+ {}
+ ~ReadWriteLock() {}
+
+ void lockForRead();
+ bool tryLockForRead();
+ void unlockForRead();
+
+ void lockForWrite();
+ bool tryLockForWrite();
+ void unlockForWrite();
+
+private:
+ int mNumReaders;
+ int mNumWriters;
+
+ Mutex mLock;
+ Condition mReadWaiter;
+ Condition mWriteWaiter;
+#if defined(PRINT_RENDER_TIMES)
+ DurationTimer mDebugTimer;
+#endif
+};
+
+
+/*
+ * This is our spiffy thread object!
+ */
+
+class Thread : virtual public RefBase
+{
+public:
+ // Create a Thread object, but doesn't create or start the associated
+ // thread. See the run() method.
+ Thread(bool canCallJava = true);
+ virtual ~Thread();
+
+ // Start the thread in threadLoop() which needs to be implemented.
+ virtual status_t run( const char* name = 0,
+ int32_t priority = PRIORITY_DEFAULT,
+ size_t stack = 0);
+
+ // Ask this object's thread to exit. This function is asynchronous, when the
+ // function returns the thread might still be running. Of course, this
+ // function can be called from a different thread.
+ virtual void requestExit();
+
+ // Good place to do one-time initializations
+ virtual status_t readyToRun();
+
+ // Call requestExit() and wait until this object's thread exits.
+ // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call
+ // this function from this object's thread. Will return WOULD_BLOCK in
+ // that case.
+ status_t requestExitAndWait();
+
+protected:
+ // exitPending() returns true if requestExit() has been called.
+ bool exitPending() const;
+
+private:
+ // Derived class must implemtent threadLoop(). The thread starts its life
+ // here. There are two ways of using the Thread object:
+ // 1) loop: if threadLoop() returns true, it will be called again if
+ // requestExit() wasn't called.
+ // 2) once: if threadLoop() returns false, the thread will exit upon return.
+ virtual bool threadLoop() = 0;
+
+private:
+ Thread& operator=(const Thread&);
+ static int _threadLoop(void* user);
+ const bool mCanCallJava;
+ thread_id_t mThread;
+ Mutex mLock;
+ Condition mThreadExitedCondition;
+ status_t mStatus;
+ volatile bool mExitPending;
+ volatile bool mRunning;
+ sp<Thread> mHoldSelf;
+};
+
+
+}; // namespace android
+
+#endif // __cplusplus
+
+#endif // _LIBS_UTILS_THREADS_H
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
new file mode 100644
index 0000000..a9cb303
--- /dev/null
+++ b/libs/audioflinger/Android.mk
@@ -0,0 +1,53 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ AudioHardwareGeneric.cpp \
+ AudioHardwareStub.cpp \
+ AudioDumpInterface.cpp \
+ AudioHardwareInterface.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia \
+ libhardware
+
+ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
+ LOCAL_CFLAGS += -DGENERIC_AUDIO
+endif
+
+LOCAL_MODULE:= libaudiointerface
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ AudioFlinger.cpp \
+ AudioMixer.cpp.arm \
+ AudioResampler.cpp.arm \
+ AudioResamplerSinc.cpp.arm \
+ AudioResamplerCubic.cpp.arm
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia \
+ libhardware
+
+ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
+ LOCAL_STATIC_LIBRARIES += libaudiointerface
+else
+ LOCAL_SHARED_LIBRARIES += libaudio
+endif
+
+LOCAL_MODULE:= libaudioflinger
+
+ifeq ($(TARGET_ARCH),arm) # not simulator
+ LOCAL_CFLAGS += -DWITH_BLUETOOTH
+ LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/audioflinger/AudioBufferProvider.h b/libs/audioflinger/AudioBufferProvider.h
new file mode 100644
index 0000000..1a467c7
--- /dev/null
+++ b/libs/audioflinger/AudioBufferProvider.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_AUDIO_BUFFER_PROVIDER_H
+#define ANDROID_AUDIO_BUFFER_PROVIDER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioBufferProvider
+{
+public:
+
+ struct Buffer {
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ size_t frameCount;
+ };
+
+ virtual status_t getNextBuffer(Buffer* buffer) = 0;
+ virtual void releaseBuffer(Buffer* buffer) = 0;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_AUDIO_BUFFER_PROVIDER_H
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
new file mode 100644
index 0000000..5ff2f18
--- /dev/null
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -0,0 +1,94 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.cpp
+**
+** 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 "AudioFlingerDump"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "AudioDumpInterface.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
+{
+ if(hw == 0) {
+ LOGE("Dump construct hw = 0");
+ }
+ mFinalInterface = hw;
+ mStreamOut = 0;
+}
+
+
+status_t AudioDumpInterface::standby()
+{
+ if(mStreamOut) mStreamOut->Close();
+ return mFinalInterface->standby();
+}
+
+
+AudioStreamOut* AudioDumpInterface::openOutputStream(
+ int format, int channelCount, uint32_t sampleRate)
+{
+ AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate);
+
+ if(outFinal) {
+ mStreamOut = new AudioStreamOutDump(outFinal);
+ return mStreamOut;
+ } else {
+ LOGE("Dump outFinal=0");
+ return 0;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+AudioStreamOutDump::AudioStreamOutDump( AudioStreamOut* finalStream)
+{
+ mFinalStream = finalStream;
+ mOutFile = 0;
+}
+
+ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
+{
+ ssize_t ret;
+
+ ret = mFinalStream->write(buffer, bytes);
+ if(!mOutFile) {
+ mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+ }
+ if (mOutFile) {
+ fwrite(buffer, bytes, 1, mOutFile);
+ }
+ return ret;
+}
+
+void AudioStreamOutDump::Close(void)
+{
+ if(mOutFile) {
+ fclose(mOutFile);
+ mOutFile = 0;
+ }
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
new file mode 100644
index 0000000..732b97d
--- /dev/null
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -0,0 +1,101 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.h
+**
+** 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_AUDIO_DUMP_INTERFACE_H
+#define ANDROID_AUDIO_DUMP_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+namespace android {
+
+#define FLINGER_DUMP_NAME "/tmp/FlingerOut.pcm" // name of file used for dump
+
+class AudioStreamOutDump : public AudioStreamOut {
+public:
+ AudioStreamOutDump( AudioStreamOut* FinalStream);
+ virtual ssize_t write(const void* buffer, size_t bytes);
+
+ virtual uint32_t sampleRate() const { return mFinalStream->sampleRate(); }
+ virtual size_t bufferSize() const { return mFinalStream->bufferSize(); }
+ virtual int channelCount() const { return mFinalStream->channelCount(); }
+ virtual int format() const { return mFinalStream->format(); }
+ virtual status_t setVolume(float volume)
+ { return mFinalStream->setVolume(volume); }
+ virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalStream->dump(fd, args); }
+ void Close(void);
+
+private:
+ AudioStreamOut *mFinalStream;
+ FILE *mOutFile; // output file
+};
+
+
+class AudioDumpInterface : public AudioHardwareInterface
+{
+
+public:
+ AudioDumpInterface(AudioHardwareInterface* hw);
+ virtual status_t standby();
+ virtual AudioStreamOut* openOutputStream(
+ int format=0,
+ int channelCount=0,
+ uint32_t sampleRate=0);
+
+ virtual ~AudioDumpInterface()
+ {delete mFinalInterface;}
+ virtual status_t initCheck()
+ {return mFinalInterface->initCheck();}
+ virtual status_t setVoiceVolume(float volume)
+ {return mFinalInterface->setVoiceVolume(volume);}
+ virtual status_t setMasterVolume(float volume)
+ {return mFinalInterface->setMasterVolume(volume);}
+
+ virtual status_t setRouting(int mode, uint32_t routes)
+ {return mFinalInterface->setRouting(mode, routes);}
+ virtual status_t getRouting(int mode, uint32_t* routes)
+ {return mFinalInterface->getRouting(mode, routes);}
+ virtual status_t getMode(int* mode)
+ {return mFinalInterface->getMode(mode);}
+
+ // mic mute
+ virtual status_t setMicMute(bool state)
+ {return mFinalInterface->setMicMute(state);}
+ virtual status_t getMicMute(bool* state)
+ {return mFinalInterface->getMicMute(state);}
+
+ virtual status_t setParameter(const char* key, const char* value)
+ {return mFinalInterface->setParameter(key, value);}
+
+ virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate)
+ {return mFinalInterface->openInputStream( format, channelCount, sampleRate);}
+
+ virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
+
+protected:
+ virtual status_t doRouting() {return 0;}
+
+ AudioHardwareInterface *mFinalInterface;
+ AudioStreamOutDump *mStreamOut;
+
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_DUMP_INTERFACE_H
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
new file mode 100644
index 0000000..fb21629
--- /dev/null
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -0,0 +1,1450 @@
+/* //device/include/server/AudioFlinger/AudioFlinger.cpp
+**
+** 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.
+*/
+
+
+#define LOG_TAG "AudioFlinger"
+//#define LOG_NDEBUG 0
+
+#include <math.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+
+#include <media/AudioTrack.h>
+#include <media/AudioRecord.h>
+
+#include <private/media/AudioTrackShared.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+#include "AudioMixer.h"
+#include "AudioFlinger.h"
+
+namespace android {
+
+static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+static const unsigned long kBufferRecoveryInUsecs = 2000;
+static const unsigned long kMaxBufferRecoveryInUsecs = 20000;
+static const float MAX_GAIN = 4096.0f;
+
+// retry counts for buffer fill timeout
+// 50 * ~20msecs = 1 second
+static const int8_t kMaxTrackRetries = 50;
+static const int8_t kMaxTrackStartupRetries = 50;
+
+#define AUDIOFLINGER_SECURITY_ENABLED 1
+
+// ----------------------------------------------------------------------------
+
+static bool recordingAllowed() {
+#ifndef HAVE_ANDROID_OS
+ return true;
+#endif
+#if AUDIOFLINGER_SECURITY_ENABLED
+ if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+ bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO"));
+ if (!ok) LOGE("Request requires android.permission.RECORD_AUDIO");
+ return ok;
+#else
+ if (!checkCallingPermission(String16("android.permission.RECORD_AUDIO")))
+ LOGW("WARNING: Need to add android.permission.RECORD_AUDIO to manifest");
+ return true;
+#endif
+}
+
+static bool settingsAllowed() {
+#ifndef HAVE_ANDROID_OS
+ return true;
+#endif
+#if AUDIOFLINGER_SECURITY_ENABLED
+ if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+ bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
+ if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+ return ok;
+#else
+ if (!checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")))
+ LOGW("WARNING: Need to add android.permission.MODIFY_AUDIO_SETTINGS to manifest");
+ return true;
+#endif
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::AudioFlinger()
+ : BnAudioFlinger(), Thread(false),
+ mMasterVolume(0), mMasterMute(true),
+ mAudioMixer(0), mAudioHardware(0), mOutput(0), mAudioRecordThread(0),
+ mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0),
+ mMixBuffer(0), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0),
+ mStandby(false), mInWrite(false)
+{
+ mHardwareStatus = AUDIO_HW_IDLE;
+ mAudioHardware = AudioHardwareInterface::create();
+ mHardwareStatus = AUDIO_HW_INIT;
+ if (mAudioHardware->initCheck() == NO_ERROR) {
+ // open 16-bit output stream for s/w mixer
+ mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
+ mOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ if (mOutput) {
+ mSampleRate = mOutput->sampleRate();
+ mChannelCount = mOutput->channelCount();
+ mFormat = mOutput->format();
+ mMixBufferSize = mOutput->bufferSize();
+ mFrameCount = mMixBufferSize / mChannelCount / sizeof(int16_t);
+ mMixBuffer = new int16_t[mFrameCount * mChannelCount];
+ memset(mMixBuffer, 0, mMixBufferSize);
+ mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+ // FIXME - this should come from settings
+ setMasterVolume(1.0f);
+ setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+ setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+ setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+ setMode(AudioSystem::MODE_NORMAL);
+ mMasterMute = false;
+ } else {
+ LOGE("Failed to initialize output stream");
+ }
+ } else {
+ LOGE("Couldn't even initialize the stubbed audio hardware!");
+ }
+}
+
+AudioFlinger::~AudioFlinger()
+{
+ delete mOutput;
+ delete mAudioHardware;
+ delete [] mMixBuffer;
+ delete mAudioMixer;
+ mAudioRecordThread.clear();
+}
+
+status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ result.append("Clients:\n");
+ for (size_t i = 0; i < mClients.size(); ++i) {
+ wp<Client> wClient = mClients.valueAt(i);
+ if (wClient != 0) {
+ sp<Client> client = wClient.promote();
+ if (client != 0) {
+ snprintf(buffer, SIZE, " pid: %d\n", client->pid());
+ result.append(buffer);
+ }
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ result.append("Tracks:\n");
+ result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ wp<Track> wTrack = mTracks[i];
+ if (wTrack != 0) {
+ sp<Track> track = wTrack.promote();
+ if (track != 0) {
+ track->dump(buffer, SIZE);
+ result.append(buffer);
+ }
+ }
+ }
+
+ result.append("Active Tracks:\n");
+ result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+ for (size_t i = 0; i < mActiveTracks.size(); ++i) {
+ wp<Track> wTrack = mTracks[i];
+ if (wTrack != 0) {
+ sp<Track> track = wTrack.promote();
+ if (track != 0) {
+ track->dump(buffer, SIZE);
+ result.append(buffer);
+ }
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer().trackNames());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
+ result.append(buffer);
+ snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "standby: %d\n", mStandby);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump AudioFlinger from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
+{
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ dumpPermissionDenial(fd, args);
+ } else {
+ AutoMutex lock(&mLock);
+
+ dumpClients(fd, args);
+ dumpTracks(fd, args);
+ dumpInternals(fd, args);
+ if (mAudioHardware) {
+ mAudioHardware->dumpState(fd, args);
+ }
+ }
+ return NO_ERROR;
+}
+
+// Thread virtuals
+bool AudioFlinger::threadLoop()
+{
+ nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
+ unsigned long sleepTime = kBufferRecoveryInUsecs;
+ const size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
+ int16_t* curBuf = mMixBuffer;
+ Vector< sp<Track> > tracksToRemove;
+ size_t enabledTracks;
+ nsecs_t standbyTime = systemTime();
+
+ do {
+ enabledTracks = 0;
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
+
+ // put audio hardware into standby after short delay
+ if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
+ // wait until we have something to do...
+ LOGV("Audio hardware entering standby\n");
+ mHardwareStatus = AUDIO_HW_STANDBY;
+ if (!mStandby) {
+ mAudioHardware->standby();
+ mStandby = true;
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ mWaitWorkCV.wait(mLock);
+ LOGV("Audio hardware exiting standby\n");
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ continue;
+ }
+
+ // find out which tracks need to be processed
+ size_t count = activeTracks.size();
+ for (size_t i=0 ; i<count ; i++) {
+ sp<Track> t = activeTracks[i].promote();
+ if (t == 0) continue;
+
+ Track* const track = t.get();
+ audio_track_cblk_t* cblk = track->cblk();
+ uint32_t u = cblk->user;
+ uint32_t s = cblk->server;
+
+ // The first time a track is added we wait
+ // for all its buffers to be filled before processing it
+ audioMixer().setActiveTrack(track->name());
+ if ((u > s) && (track->isReady(u, s) || track->isStopped()) &&
+ !track->isPaused())
+ {
+ //LOGD("u=%08x, s=%08x [OK]", u, s);
+
+ // compute volume for this track
+ int16_t left, right;
+ if (track->isMuted() || mMasterMute || track->isPausing()) {
+ left = right = 0;
+ if (track->isPausing()) {
+ LOGV("paused(%d)", track->name());
+ track->setPaused();
+ }
+ } else {
+ float typeVolume = mStreamTypes[track->type()].volume;
+ float v = mMasterVolume * typeVolume;
+ float v_clamped = v * cblk->volume[0];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ left = int16_t(v_clamped);
+ v_clamped = v * cblk->volume[1];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ right = int16_t(v_clamped);
+ }
+
+ // XXX: these things DON'T need to be done each time
+ AudioMixer& mixer(audioMixer());
+ mixer.setBufferProvider(track);
+ mixer.enable(AudioMixer::MIXING);
+
+ int param;
+ if ( track->mFillingUpStatus == Track::FS_FILLED) {
+ // no ramp for the first volume setting
+ track->mFillingUpStatus = Track::FS_ACTIVE;
+ if (track->mState == TrackBase::RESUMING) {
+ track->mState = TrackBase::ACTIVE;
+ param = AudioMixer::RAMP_VOLUME;
+ } else {
+ param = AudioMixer::VOLUME;
+ }
+ } else {
+ param = AudioMixer::RAMP_VOLUME;
+ }
+ mixer.setParameter(param, AudioMixer::VOLUME0, left);
+ mixer.setParameter(param, AudioMixer::VOLUME1, right);
+ mixer.setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::FORMAT, track->format());
+ mixer.setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::CHANNEL_COUNT, track->channelCount());
+ mixer.setParameter(
+ AudioMixer::RESAMPLE,
+ AudioMixer::SAMPLE_RATE,
+ int(cblk->sampleRate));
+
+ // reset retry count
+ track->mRetryCount = kMaxTrackRetries;
+ enabledTracks++;
+ } else {
+ //LOGD("u=%08x, s=%08x [NOT READY]", u, s);
+ if (track->isStopped()) {
+ track->mFillingUpStatus = Track::FS_FILLING;
+ track->mFlags = 0;
+ }
+ if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+ // We have consumed all the buffers of this track.
+ // Remove it from the list of active tracks.
+ LOGV("remove(%d) from active list", track->name());
+ tracksToRemove.add(track);
+ } else {
+ // No buffers for this track. Give it a few chances to
+ // fill a buffer, then remove it from active list.
+ if (--(track->mRetryCount) <= 0) {
+ LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ tracksToRemove.add(track);
+ }
+ }
+ // LOGV("disable(%d)", track->name());
+ audioMixer().disable(AudioMixer::MIXING);
+ }
+ }
+
+ // remove all the tracks that need to be...
+ count = tracksToRemove.size();
+ if (UNLIKELY(count)) {
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Track>& track = tracksToRemove[i];
+ mActiveTracks.remove(track);
+ if (track->isTerminated()) {
+ mTracks.remove(track);
+ audioMixer().deleteTrackName(track->mName);
+ }
+ }
+ }
+ }
+
+ if (LIKELY(enabledTracks)) {
+ // mix buffers...
+ audioMixer().process(curBuf);
+
+ // output audio to hardware
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ mOutput->write(curBuf, mixBufferSize);
+ mNumWrites++;
+ mInWrite = false;
+ mStandby = false;
+ nsecs_t temp = systemTime();
+ standbyTime = temp + kStandbyTimeInNsecs;
+ nsecs_t delta = temp - mLastWriteTime;
+ if (delta > maxPeriod) {
+ LOGW("write blocked for %llu msecs", ns2ms(delta));
+ mNumDelayedWrites++;
+ }
+ sleepTime = kBufferRecoveryInUsecs;
+ } else {
+ // There was nothing to mix this round, which means all
+ // active tracks were late. Sleep a little bit to give
+ // them another chance. If we're too late, the audio
+ // hardware will zero-fill for us.
+ LOGV("no buffers - usleep(%lu)", sleepTime);
+ usleep(sleepTime);
+ if (sleepTime < kMaxBufferRecoveryInUsecs) {
+ sleepTime += kBufferRecoveryInUsecs;
+ }
+ }
+
+ // finally let go of all our tracks, without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+ tracksToRemove.clear();
+ } while (true);
+
+ return false;
+}
+
+status_t AudioFlinger::readyToRun()
+{
+ if (mSampleRate == 0) {
+ LOGE("No working audio driver found.");
+ return NO_INIT;
+ }
+ LOGI("AudioFlinger's main thread ready to run.");
+ return NO_ERROR;
+}
+
+void AudioFlinger::onFirstRef()
+{
+ run("AudioFlinger", ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+// IAudioFlinger interface
+sp<IAudioTrack> AudioFlinger::createTrack(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags)
+{
+ if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
+ LOGE("invalid stream type");
+ return NULL;
+ }
+
+ if (sampleRate > MAX_SAMPLE_RATE) {
+ LOGE("Sample rate out of range: %d", sampleRate);
+ return NULL;
+ }
+
+ sp<Track> track;
+ sp<TrackHandle> trackHandle;
+ Mutex::Autolock _l(mLock);
+
+ if (mSampleRate == 0) {
+ LOGE("Audio driver not initialized.");
+ return trackHandle;
+ }
+
+ sp<Client> client;
+ wp<Client> wclient = mClients.valueFor(pid);
+
+ if (wclient != NULL) {
+ client = wclient.promote();
+ } else {
+ client = new Client(this, pid);
+ mClients.add(pid, client);
+ }
+
+ // FIXME: Buffer size should be based on sample rate for consistent latency
+ track = new Track(this, client, streamType, sampleRate, format,
+ channelCount, bufferCount, channelCount == 1 ? mMixBufferSize>>1 : mMixBufferSize);
+ mTracks.add(track);
+ trackHandle = new TrackHandle(track);
+ return trackHandle;
+}
+
+uint32_t AudioFlinger::sampleRate() const
+{
+ return mSampleRate;
+}
+
+int AudioFlinger::channelCount() const
+{
+ return mChannelCount;
+}
+
+int AudioFlinger::format() const
+{
+ return mFormat;
+}
+
+size_t AudioFlinger::frameCount() const
+{
+ return mFrameCount;
+}
+
+status_t AudioFlinger::setMasterVolume(float value)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ // when hw supports master volume, don't scale in sw mixer
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
+ mMasterVolume = 1.0f;
+ }
+ else {
+ mMasterVolume = value;
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) {
+ LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask);
+ return BAD_VALUE;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_GET_ROUTING;
+ uint32_t r;
+ uint32_t err = mAudioHardware->getRouting(mode, &r);
+ if (err == NO_ERROR) {
+ r = (r & ~mask) | (routes & mask);
+ mHardwareStatus = AUDIO_HW_SET_ROUTING;
+ err = mAudioHardware->setRouting(mode, r);
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return err;
+}
+
+uint32_t AudioFlinger::getRouting(int mode) const
+{
+ uint32_t routes = 0;
+ if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
+ mHardwareStatus = AUDIO_HW_GET_ROUTING;
+ mAudioHardware->getRouting(mode, &routes);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ } else {
+ LOGW("Illegal value: getRouting(%d)", mode);
+ }
+ return routes;
+}
+
+status_t AudioFlinger::setMode(int mode)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) {
+ LOGW("Illegal value: setMode(%d)", mode);
+ return BAD_VALUE;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MODE;
+ status_t ret = mAudioHardware->setMode(mode);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return ret;
+}
+
+int AudioFlinger::getMode() const
+{
+ int mode = AudioSystem::MODE_INVALID;
+ mHardwareStatus = AUDIO_HW_SET_MODE;
+ mAudioHardware->getMode(&mode);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return mode;
+}
+
+status_t AudioFlinger::setMicMute(bool state)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
+ status_t ret = mAudioHardware->setMicMute(state);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return ret;
+}
+
+bool AudioFlinger::getMicMute() const
+{
+ bool state = AudioSystem::MODE_INVALID;
+ mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
+ mAudioHardware->getMicMute(&state);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return state;
+}
+
+status_t AudioFlinger::setMasterMute(bool muted)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ mMasterMute = muted;
+ return NO_ERROR;
+}
+
+float AudioFlinger::masterVolume() const
+{
+ return mMasterVolume;
+}
+
+bool AudioFlinger::masterMute() const
+{
+ return mMasterMute;
+}
+
+status_t AudioFlinger::setStreamVolume(int stream, float value)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+
+ mStreamTypes[stream].volume = value;
+ status_t ret = NO_ERROR;
+ if (stream == AudioTrack::VOICE_CALL) {
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
+ ret = mAudioHardware->setVoiceVolume(value);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ }
+ return ret;
+}
+
+status_t AudioFlinger::setStreamMute(int stream, bool muted)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+ mStreamTypes[stream].mute = muted;
+ return NO_ERROR;
+}
+
+float AudioFlinger::streamVolume(int stream) const
+{
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ return 0.0f;
+ }
+ return mStreamTypes[stream].volume;
+}
+
+bool AudioFlinger::streamMute(int stream) const
+{
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ return true;
+ }
+ return mStreamTypes[stream].mute;
+}
+
+bool AudioFlinger::isMusicActive() const
+{
+ size_t count = mActiveTracks.size();
+ for (size_t i = 0 ; i < count ; ++i) {
+ sp<Track> t = mActiveTracks[i].promote();
+ if (t == 0) continue;
+ Track* const track = t.get();
+ if (t->mStreamType == AudioTrack::MUSIC)
+ return true;
+ }
+ return false;
+}
+
+status_t AudioFlinger::setParameter(const char* key, const char* value)
+{
+ status_t result;
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_SET_PARAMETER;
+ result = mAudioHardware->setParameter(key, value);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return result;
+}
+
+void AudioFlinger::removeClient(pid_t pid)
+{
+ Mutex::Autolock _l(mLock);
+ mClients.removeItem(pid);
+}
+
+status_t AudioFlinger::addTrack(const sp<Track>& track)
+{
+ Mutex::Autolock _l(mLock);
+
+ // here the track could be either new, or restarted
+ // in both cases "unstop" the track
+ if (track->isPaused()) {
+ track->mState = TrackBase::RESUMING;
+ LOGV("PAUSED => RESUMING (%d)", track->name());
+ } else {
+ track->mState = TrackBase::ACTIVE;
+ LOGV("? => ACTIVE (%d)", track->name());
+ }
+ // set retry count for buffer fill
+ track->mRetryCount = kMaxTrackStartupRetries;
+ LOGV("mWaitWorkCV.broadcast");
+ mWaitWorkCV.broadcast();
+
+ if (mActiveTracks.indexOf(track) < 0) {
+ // the track is newly added, make sure it fills up all its
+ // buffers before playing. This is to ensure the client will
+ // effectively get the latency it requested.
+ track->mFillingUpStatus = Track::FS_FILLING;
+ mActiveTracks.add(track);
+ return NO_ERROR;
+ }
+ return ALREADY_EXISTS;
+}
+
+void AudioFlinger::removeTrack(wp<Track> track, int name)
+{
+ Mutex::Autolock _l(mLock);
+ sp<Track> t = track.promote();
+ if (t!=NULL && (t->mState <= TrackBase::STOPPED)) {
+ remove_track_l(track, name);
+ }
+}
+
+void AudioFlinger::remove_track_l(wp<Track> track, int name)
+{
+ sp<Track> t = track.promote();
+ if (t!=NULL) {
+ t->reset();
+ }
+ audioMixer().deleteTrackName(name);
+ mActiveTracks.remove(track);
+ mWaitWorkCV.broadcast();
+}
+
+void AudioFlinger::destroyTrack(const sp<Track>& track)
+{
+ // NOTE: We're acquiring a strong reference on the track before
+ // acquiring the lock, this is to make sure removing it from
+ // mTracks won't cause the destructor to be called while the lock is
+ // held (note that technically, 'track' could be a reference to an item
+ // in mTracks, which is why we need to do this).
+ sp<Track> keep(track);
+ Mutex::Autolock _l(mLock);
+ track->mState = TrackBase::TERMINATED;
+ if (mActiveTracks.indexOf(track) < 0) {
+ LOGV("remove track (%d) and delete from mixer", track->name());
+ mTracks.remove(track);
+ audioMixer().deleteTrackName(keep->name());
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
+ : RefBase(),
+ mAudioFlinger(audioFlinger),
+ mMemoryDealer(new MemoryDealer(1024*1024)),
+ mPid(pid)
+{
+ // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+}
+
+AudioFlinger::Client::~Client()
+{
+ mAudioFlinger->removeClient(mPid);
+}
+
+const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+{
+ return mMemoryDealer;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackBase::TrackBase(
+ const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize)
+ : RefBase(),
+ mAudioFlinger(audioFlinger),
+ mClient(client),
+ mStreamType(streamType),
+ mFormat(format),
+ mChannelCount(channelCount),
+ mBufferCount(bufferCount),
+ mFlags(0),
+ mBufferSize(bufferSize),
+ mState(IDLE),
+ mClientTid(-1)
+{
+ mName = audioFlinger->audioMixer().getTrackName();
+ if (mName < 0) {
+ LOGE("no more track names availlable");
+ return;
+ }
+
+ // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
+ size_t size = sizeof(audio_track_cblk_t) + bufferCount * bufferSize;
+ mCblkMemory = client->heap()->allocate(size);
+ if (mCblkMemory != 0) {
+ mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
+ if (mCblk) { // construct the shared structure in-place.
+ new(mCblk) audio_track_cblk_t();
+ // clear all buffers
+ mCblk->size = bufferSize;
+ mCblk->sampleRate = sampleRate;
+ mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ memset(mBuffers, 0, bufferCount * bufferSize);
+ }
+ } else {
+ LOGE("not enough memory for AudioTrack size=%u", size);
+ client->heap()->dump("AudioTrack");
+ return;
+ }
+}
+
+AudioFlinger::TrackBase::~TrackBase()
+{
+ mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ mCblkMemory.clear(); // and free the shared memory
+ mClient.clear();
+}
+
+void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ step();
+}
+
+bool AudioFlinger::TrackBase::step() {
+ bool result;
+ audio_track_cblk_t* cblk = this->cblk();
+
+ result = cblk->stepServer(bufferCount());
+ if (!result) {
+ LOGV("stepServer failed acquiring cblk mutex");
+ mFlags |= STEPSERVER_FAILED;
+ }
+ return result;
+}
+
+void AudioFlinger::TrackBase::reset() {
+ audio_track_cblk_t* cblk = this->cblk();
+
+ cblk->user = 0;
+ cblk->server = 0;
+ mFlags = 0;
+}
+
+sp<IMemory> AudioFlinger::TrackBase::getCblk() const
+{
+ return mCblkMemory;
+}
+
+int AudioFlinger::TrackBase::sampleRate() const {
+ return mCblk->sampleRate;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Track::Track(
+ const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize)
+ : TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, bufferCount, bufferSize)
+{
+ mVolume[0] = 1.0f;
+ mVolume[1] = 1.0f;
+ mMute = false;
+}
+
+AudioFlinger::Track::~Track()
+{
+ wp<Track> weak(this); // never create a strong ref from the dtor
+ mState = TERMINATED;
+ mAudioFlinger->removeTrack(weak, mName);
+}
+
+void AudioFlinger::Track::destroy()
+{
+ mAudioFlinger->destroyTrack(this);
+}
+
+void AudioFlinger::Track::dump(char* buffer, size_t size)
+{
+ snprintf(buffer, size, " %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
+ mName - AudioMixer::TRACK0,
+ mClient->pid(),
+ mStreamType,
+ mFormat,
+ mChannelCount,
+ mBufferCount,
+ mState,
+ mMute,
+ mFillingUpStatus,
+ mCblk->sampleRate,
+ mCblk->volume[0],
+ mCblk->volume[1],
+ mCblk->server,
+ mCblk->user);
+}
+
+status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ audio_track_cblk_t* cblk = this->cblk();
+ uint32_t u = cblk->user;
+ uint32_t s = cblk->server;
+
+ // Check if last stepServer failed, try to step now
+ if (mFlags & TrackBase::STEPSERVER_FAILED) {
+ if (!step()) goto getNextBuffer_exit;
+ LOGV("stepServer recovered");
+ mFlags &= ~TrackBase::STEPSERVER_FAILED;
+ }
+
+ if (LIKELY(u > s)) {
+ int index = s & audio_track_cblk_t::BUFFER_MASK;
+ buffer->raw = getBuffer(index);
+ buffer->frameCount = mAudioFlinger->frameCount();
+ return NO_ERROR;
+ }
+getNextBuffer_exit:
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
+}
+
+bool AudioFlinger::Track::isReady(uint32_t u, int32_t s) const {
+ if (mFillingUpStatus != FS_FILLING) return true;
+ const uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
+ const uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK;
+ const uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
+ const uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK;
+ if (u_seq > s_seq && u_buf == s_buf) {
+ mFillingUpStatus = FS_FILLED;
+ return true;
+ }
+ return false;
+}
+
+status_t AudioFlinger::Track::start()
+{
+ LOGV("start(%d)", mName);
+ mAudioFlinger->addTrack(this);
+ return NO_ERROR;
+}
+
+void AudioFlinger::Track::stop()
+{
+ LOGV("stop(%d)", mName);
+ Mutex::Autolock _l(mAudioFlinger->mLock);
+ if (mState > STOPPED) {
+ mState = STOPPED;
+ // If the track is not active (PAUSED and buffers full), flush buffers
+ if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
+ reset();
+ }
+ LOGV("(> STOPPED) => STOPPED (%d)", mName);
+ }
+}
+
+void AudioFlinger::Track::pause()
+{
+ LOGV("pause(%d)", mName);
+ Mutex::Autolock _l(mAudioFlinger->mLock);
+ if (mState == ACTIVE || mState == RESUMING) {
+ mState = PAUSING;
+ LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
+ }
+}
+
+void AudioFlinger::Track::flush()
+{
+ LOGV("flush(%d)", mName);
+ Mutex::Autolock _l(mAudioFlinger->mLock);
+ if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
+ return;
+ }
+ // No point remaining in PAUSED state after a flush => go to
+ // STOPPED state
+ mState = STOPPED;
+
+ // NOTE: reset() will reset cblk->user and cblk->server with
+ // the risk that at the same time, the AudioMixer is trying to read
+ // data. In this case, getNextBuffer() would return a NULL pointer
+ // as audio buffer => the AudioMixer code MUST always test that pointer
+ // returned by getNextBuffer() is not NULL!
+ reset();
+}
+
+void AudioFlinger::Track::reset()
+{
+ TrackBase::reset();
+ mFillingUpStatus = FS_FILLING;
+}
+
+void AudioFlinger::Track::mute(bool muted)
+{
+ mMute = muted;
+}
+
+void AudioFlinger::Track::setVolume(float left, float right)
+{
+ mVolume[0] = left;
+ mVolume[1] = right;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::Track>& track)
+ : BnAudioTrack(),
+ mTrack(track)
+{
+}
+
+AudioFlinger::TrackHandle::~TrackHandle() {
+ // just stop the track on deletion, associated resources
+ // will be freed from the main thread once all pending buffers have
+ // been played. Unless it's not in the active track list, in which
+ // case we free everything now...
+ mTrack->destroy();
+}
+
+status_t AudioFlinger::TrackHandle::start() {
+ return mTrack->start();
+}
+
+void AudioFlinger::TrackHandle::stop() {
+ mTrack->stop();
+}
+
+void AudioFlinger::TrackHandle::flush() {
+ mTrack->flush();
+}
+
+void AudioFlinger::TrackHandle::mute(bool e) {
+ mTrack->mute(e);
+}
+
+void AudioFlinger::TrackHandle::pause() {
+ mTrack->pause();
+}
+
+void AudioFlinger::TrackHandle::setVolume(float left, float right) {
+ mTrack->setVolume(left, right);
+}
+
+sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {
+ return mTrack->getCblk();
+}
+
+status_t AudioFlinger::TrackHandle::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ return BnAudioTrack::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+
+sp<AudioFlinger::AudioRecordThread> AudioFlinger::audioRecordThread()
+{
+ Mutex::Autolock _l(mLock);
+ return mAudioRecordThread;
+}
+
+void AudioFlinger::endRecord()
+{
+ Mutex::Autolock _l(mLock);
+ mAudioRecordThread.clear();
+}
+
+sp<IAudioRecord> AudioFlinger::openRecord(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags)
+{
+ sp<AudioRecordThread> thread;
+ sp<RecordTrack> recordTrack;
+ sp<RecordHandle> recordHandle;
+ sp<Client> client;
+ wp<Client> wclient;
+ AudioStreamIn* input = 0;
+
+ // check calling permissions
+ if (!recordingAllowed()) {
+ goto Exit;
+ }
+
+ if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
+ LOGE("invalid stream type");
+ goto Exit;
+ }
+
+ if (sampleRate > MAX_SAMPLE_RATE) {
+ LOGE("Sample rate out of range");
+ goto Exit;
+ }
+
+ if (mSampleRate == 0) {
+ LOGE("Audio driver not initialized");
+ goto Exit;
+ }
+
+ // Create audio thread - take mutex to prevent race condition
+ {
+ Mutex::Autolock _l(mLock);
+ if (mAudioRecordThread != 0) {
+ LOGE("Record channel already open");
+ goto Exit;
+ }
+ thread = new AudioRecordThread(this);
+ mAudioRecordThread = thread;
+ }
+ // It's safe to release the mutex here since the client doesn't get a
+ // handle until we return from this call
+
+ // open driver, initialize h/w
+ input = mAudioHardware->openInputStream(
+ AudioSystem::PCM_16_BIT, channelCount, sampleRate);
+ if (!input) {
+ LOGE("Error opening input stream");
+ mAudioRecordThread.clear();
+ goto Exit;
+ }
+
+ // add client to list
+ {
+ Mutex::Autolock _l(mLock);
+ wclient = mClients.valueFor(pid);
+ if (wclient != NULL) {
+ client = wclient.promote();
+ } else {
+ client = new Client(this, pid);
+ mClients.add(pid, client);
+ }
+ }
+
+ // create new record track and pass to record thread
+ recordTrack = new RecordTrack(this, client, streamType, sampleRate,
+ format, channelCount, bufferCount, input->bufferSize());
+
+ // spin up record thread
+ thread->open(recordTrack, input);
+ thread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
+
+ // return to handle to client
+ recordHandle = new RecordHandle(recordTrack);
+
+Exit:
+ return recordHandle;
+}
+
+status_t AudioFlinger::startRecord() {
+ sp<AudioRecordThread> t = audioRecordThread();
+ if (t == 0) return NO_INIT;
+ return t->start();
+}
+
+void AudioFlinger::stopRecord() {
+ sp<AudioRecordThread> t = audioRecordThread();
+ if (t != 0) t->stop();
+}
+
+void AudioFlinger::exitRecord()
+{
+ sp<AudioRecordThread> t = audioRecordThread();
+ if (t != 0) t->exit();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::RecordTrack::RecordTrack(
+ const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize)
+ : TrackBase(audioFlinger, client, streamType, sampleRate, format,
+ channelCount, bufferCount, bufferSize),
+ mOverflow(false)
+{
+}
+
+AudioFlinger::RecordTrack::~RecordTrack()
+{
+ mAudioFlinger->audioMixer().deleteTrackName(mName);
+ mAudioFlinger->exitRecord();
+}
+
+status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ audio_track_cblk_t* cblk = this->cblk();
+ const uint32_t u_seq = cblk->user & audio_track_cblk_t::SEQUENCE_MASK;
+ const uint32_t u_buf = cblk->user & audio_track_cblk_t::BUFFER_MASK;
+ const uint32_t s_seq = cblk->server & audio_track_cblk_t::SEQUENCE_MASK;
+ const uint32_t s_buf = cblk->server & audio_track_cblk_t::BUFFER_MASK;
+
+ // Check if last stepServer failed, try to step now
+ if (mFlags & TrackBase::STEPSERVER_FAILED) {
+ if (!step()) goto getNextBuffer_exit;
+ LOGV("stepServer recovered");
+ mFlags &= ~TrackBase::STEPSERVER_FAILED;
+ }
+
+ if (LIKELY(s_seq == u_seq || s_buf != u_buf)) {
+ buffer->raw = getBuffer(s_buf);
+ buffer->frameCount = mAudioFlinger->frameCount();
+ return NO_ERROR;
+ }
+
+getNextBuffer_exit:
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
+}
+
+status_t AudioFlinger::RecordTrack::start()
+{
+ return mAudioFlinger->startRecord();
+}
+
+void AudioFlinger::RecordTrack::stop()
+{
+ mAudioFlinger->stopRecord();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& recordTrack)
+ : BnAudioRecord(),
+ mRecordTrack(recordTrack)
+{
+}
+
+AudioFlinger::RecordHandle::~RecordHandle() {}
+
+status_t AudioFlinger::RecordHandle::start() {
+ LOGV("RecordHandle::start()");
+ return mRecordTrack->start();
+}
+
+void AudioFlinger::RecordHandle::stop() {
+ LOGV("RecordHandle::stop()");
+ mRecordTrack->stop();
+}
+
+sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
+ return mRecordTrack->getCblk();
+}
+
+status_t AudioFlinger::RecordHandle::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ return BnAudioRecord::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::AudioRecordThread::AudioRecordThread(const sp<AudioFlinger>& audioFlinger) :
+ mAudioFlinger(audioFlinger),
+ mRecordTrack(0),
+ mInput(0),
+ mActive(false)
+{
+}
+
+AudioFlinger::AudioRecordThread::~AudioRecordThread()
+{
+}
+
+bool AudioFlinger::AudioRecordThread::threadLoop()
+{
+ LOGV("AudioRecordThread: start record loop");
+
+ // start recording
+ while (!exitPending()) {
+ if (!mActive) {
+ mLock.lock();
+ if (!mActive && !exitPending()) {
+ LOGV("AudioRecordThread: loop stopping");
+ mWaitWorkCV.wait(mLock);
+ LOGV("AudioRecordThread: loop starting");
+ }
+ mLock.unlock();
+ } else {
+ // promote strong ref so track isn't deleted while we access it
+ sp<RecordTrack> t = mRecordTrack.promote();
+
+ // if we lose the weak reference, client is gone.
+ if (t == 0) {
+ LOGV("AudioRecordThread: client deleted track");
+ break;
+ }
+
+ if (LIKELY(t->getNextBuffer(&mBuffer) == NO_ERROR)) {
+ if (mInput->read(mBuffer.raw, t->mBufferSize) < 0) {
+ LOGE("Error reading audio input");
+ sleep(1);
+ }
+ t->releaseBuffer(&mBuffer);
+ }
+
+ // client isn't retrieving buffers fast enough
+ else {
+ if (!t->setOverflow())
+ LOGW("AudioRecordThread: buffer overflow");
+ }
+ }
+ };
+
+ // close hardware
+ close();
+
+ // delete this object - no more data references after this call
+ mAudioFlinger->endRecord();
+ return false;
+}
+
+status_t AudioFlinger::AudioRecordThread::open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input) {
+ LOGV("AudioRecordThread::open");
+ // check for record channel already open
+ AutoMutex lock(&mLock);
+ if (mRecordTrack != NULL) {
+ LOGE("Record channel already open");
+ return ALREADY_EXISTS;
+ }
+ mRecordTrack = recordTrack;
+ mInput = input;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::AudioRecordThread::start()
+{
+ LOGV("AudioRecordThread::start");
+ AutoMutex lock(&mLock);
+ if (mActive) return -EBUSY;
+
+ sp<RecordTrack> t = mRecordTrack.promote();
+ if (t == 0) return UNKNOWN_ERROR;
+
+ // signal thread to start
+ LOGV("Signal record thread");
+ mActive = true;
+ mWaitWorkCV.signal();
+ return NO_ERROR;
+}
+
+void AudioFlinger::AudioRecordThread::stop() {
+ LOGV("AudioRecordThread::stop");
+ AutoMutex lock(&mLock);
+ if (mActive) {
+ mActive = false;
+ mWaitWorkCV.signal();
+ }
+}
+
+void AudioFlinger::AudioRecordThread::exit()
+{
+ LOGV("AudioRecordThread::exit");
+ AutoMutex lock(&mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+}
+
+
+status_t AudioFlinger::AudioRecordThread::close()
+{
+ LOGV("AudioRecordThread::close");
+ AutoMutex lock(&mLock);
+ if (!mInput) return NO_INIT;
+ delete mInput;
+ mInput = 0;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ return BnAudioFlinger::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+void AudioFlinger::instantiate() {
+ defaultServiceManager()->addService(
+ String16("media.audio_flinger"), new AudioFlinger());
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
new file mode 100644
index 0000000..8c02617
--- /dev/null
+++ b/libs/audioflinger/AudioFlinger.h
@@ -0,0 +1,490 @@
+/* //device/include/server/AudioFlinger/AudioFlinger.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_AUDIO_FLINGER_H
+#define ANDROID_AUDIO_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <media/IAudioFlinger.h>
+#include <media/IAudioTrack.h>
+#include <media/IAudioRecord.h>
+#include <media/AudioTrack.h>
+
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/MemoryDealer.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+#include "AudioBufferProvider.h"
+
+namespace android {
+
+class audio_track_cblk_t;
+class AudioMixer;
+class AudioBuffer;
+
+// ----------------------------------------------------------------------------
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ----------------------------------------------------------------------------
+
+class AudioFlinger : public BnAudioFlinger, protected Thread
+{
+public:
+ static void instantiate();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ // Thread virtuals
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+ // IAudioFlinger interface
+ virtual sp<IAudioTrack> createTrack(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags);
+
+ virtual uint32_t sampleRate() const;
+ virtual int channelCount() const;
+ virtual int format() const;
+ virtual size_t frameCount() const;
+
+ virtual status_t setMasterVolume(float value);
+ virtual status_t setMasterMute(bool muted);
+
+ virtual float masterVolume() const;
+ virtual bool masterMute() const;
+
+ virtual status_t setStreamVolume(int stream, float value);
+ virtual status_t setStreamMute(int stream, bool muted);
+
+ virtual float streamVolume(int stream) const;
+ virtual bool streamMute(int stream) const;
+
+ virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask);
+ virtual uint32_t getRouting(int mode) const;
+
+ virtual status_t setMode(int mode);
+ virtual int getMode() const;
+
+ virtual status_t setMicMute(bool state);
+ virtual bool getMicMute() const;
+
+ virtual bool isMusicActive() const;
+
+ virtual status_t setParameter(const char* key, const char* value);
+
+ enum hardware_call_state {
+ AUDIO_HW_IDLE = 0,
+ AUDIO_HW_INIT,
+ AUDIO_HW_OUTPUT_OPEN,
+ AUDIO_HW_OUTPUT_CLOSE,
+ AUDIO_HW_INPUT_OPEN,
+ AUDIO_HW_INPUT_CLOSE,
+ AUDIO_HW_STANDBY,
+ AUDIO_HW_SET_MASTER_VOLUME,
+ AUDIO_HW_GET_ROUTING,
+ AUDIO_HW_SET_ROUTING,
+ AUDIO_HW_GET_MODE,
+ AUDIO_HW_SET_MODE,
+ AUDIO_HW_GET_MIC_MUTE,
+ AUDIO_HW_SET_MIC_MUTE,
+ AUDIO_SET_VOICE_VOLUME,
+ AUDIO_SET_PARAMETER,
+ };
+
+ // record interface
+ virtual sp<IAudioRecord> openRecord(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags);
+
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags);
+
+private:
+ AudioFlinger();
+ virtual ~AudioFlinger();
+
+ // Internal dump utilites.
+ status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
+ status_t dumpClients(int fd, const Vector<String16>& args);
+ status_t dumpTracks(int fd, const Vector<String16>& args);
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+
+ // --- Client ---
+ class Client : public RefBase {
+ public:
+ Client(const sp<AudioFlinger>& audioFlinger, pid_t pid);
+ virtual ~Client();
+ const sp<MemoryDealer>& heap() const;
+ pid_t pid() const { return mPid; }
+ private:
+ Client(const Client&);
+ Client& operator = (const Client&);
+ sp<AudioFlinger> mAudioFlinger;
+ sp<MemoryDealer> mMemoryDealer;
+ pid_t mPid;
+ };
+
+
+ // --- Track ---
+ class TrackHandle;
+ class RecordHandle;
+ class AudioRecordThread;
+
+ // base for record and playback
+ class TrackBase : public AudioBufferProvider, public RefBase {
+
+ public:
+ enum track_state {
+ IDLE,
+ TERMINATED,
+ STOPPED,
+ RESUMING,
+ ACTIVE,
+ PAUSING,
+ PAUSED
+ };
+
+ enum track_flags {
+ STEPSERVER_FAILED = 0x01 // StepServer could not acquire cblk->lock mutex
+ };
+
+ TrackBase( const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize);
+ ~TrackBase();
+
+ virtual status_t start() = 0;
+ virtual void stop() = 0;
+ sp<IMemory> getCblk() const;
+
+ protected:
+ friend class AudioFlinger;
+ friend class RecordHandle;
+
+ TrackBase(const TrackBase&);
+ TrackBase& operator = (const TrackBase&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
+ virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+
+ audio_track_cblk_t* cblk() const {
+ return mCblk;
+ }
+
+ int type() const {
+ return mStreamType;
+ }
+
+ int format() const {
+ return mFormat;
+ }
+
+ int channelCount() const {
+ return mChannelCount;
+ }
+
+ int bufferCount() const {
+ return mBufferCount;
+ }
+
+ int sampleRate() const;
+
+ void* getBuffer(int n) const {
+ return (char*)mBuffers + n * mBufferSize;
+ }
+
+ int name() const {
+ return mName;
+ }
+
+ bool isStopped() const {
+ return mState == STOPPED;
+ }
+
+ bool isTerminated() const {
+ return mState == TERMINATED;
+ }
+
+ bool step();
+ void reset();
+
+ sp<AudioFlinger> mAudioFlinger;
+ sp<Client> mClient;
+ sp<IMemory> mCblkMemory;
+ audio_track_cblk_t* mCblk;
+ int mStreamType;
+ uint8_t mFormat;
+ uint8_t mChannelCount;
+ uint8_t mBufferCount;
+ uint8_t mFlags;
+ void* mBuffers;
+ size_t mBufferSize;
+ int mName;
+ // we don't really need a lock for these
+ int mState;
+ int mClientTid;
+ };
+
+ // playback track
+ class Track : public TrackBase {
+ public:
+ Track( const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize);
+ ~Track();
+
+ void dump(char* buffer, size_t size);
+ virtual status_t start();
+ virtual void stop();
+ void pause();
+
+ void flush();
+ void destroy();
+ void mute(bool);
+ void setVolume(float left, float right);
+
+ private:
+ friend class AudioFlinger;
+ friend class TrackHandle;
+
+ Track(const Track&);
+ Track& operator = (const Track&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool isMuted() const {
+ return mMute;
+ }
+
+ bool isPausing() const {
+ return mState == PAUSING;
+ }
+
+ bool isPaused() const {
+ return mState == PAUSED;
+ }
+
+ bool isReady(uint32_t u, int32_t s) const;
+
+ void setPaused() { mState = PAUSED; }
+ void reset();
+
+ // we don't really need a lock for these
+ float mVolume[2];
+ volatile bool mMute;
+ // FILLED state is used for suppressing volume ramp at begin of playing
+ enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
+ mutable uint8_t mFillingUpStatus;
+ int8_t mRetryCount;
+ }; // end of Track
+
+ friend class AudioBuffer;
+
+ class TrackHandle : public android::BnAudioTrack {
+ public:
+ TrackHandle(const sp<Track>& track);
+ virtual ~TrackHandle();
+ virtual status_t start();
+ virtual void stop();
+ virtual void flush();
+ virtual void mute(bool);
+ virtual void pause();
+ virtual void setVolume(float left, float right);
+ virtual sp<IMemory> getCblk() const;
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ private:
+ sp<Track> mTrack;
+ };
+
+ struct stream_type_t {
+ stream_type_t()
+ : volume(1.0f),
+ mute(false)
+ {
+ }
+ float volume;
+ bool mute;
+ };
+
+ friend class Client;
+ friend class Track;
+
+
+ void removeClient(pid_t pid);
+
+ status_t addTrack(const sp<Track>& track);
+ void removeTrack(wp<Track> track, int name);
+ void remove_track_l(wp<Track> track, int name);
+ void destroyTrack(const sp<Track>& track);
+
+ AudioMixer& audioMixer() {
+ return *mAudioMixer;
+ }
+
+ // record track
+ class RecordTrack : public TrackBase {
+ public:
+ RecordTrack( const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize);
+ ~RecordTrack();
+
+ virtual status_t start();
+ virtual void stop();
+
+ bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+ bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+ private:
+ friend class AudioFlinger;
+ friend class RecordHandle;
+ friend class AudioRecordThread;
+
+ RecordTrack(const Track&);
+ RecordTrack& operator = (const Track&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool mOverflow;
+ };
+
+ class RecordHandle : public android::BnAudioRecord {
+ public:
+ RecordHandle(const sp<RecordTrack>& recordTrack);
+ virtual ~RecordHandle();
+ virtual status_t start();
+ virtual void stop();
+ virtual sp<IMemory> getCblk() const;
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ private:
+ sp<RecordTrack> mRecordTrack;
+ };
+
+ // record thread
+ class AudioRecordThread : public Thread
+ {
+ public:
+ AudioRecordThread(const sp<AudioFlinger>& audioFlinger);
+ virtual ~AudioRecordThread();
+ virtual bool threadLoop();
+ virtual status_t readyToRun() { return NO_ERROR; }
+ virtual void onFirstRef() {}
+
+ status_t open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input);
+ status_t start();
+ void stop();
+ status_t close();
+ void exit();
+
+ bool isOpen() { return bool(mRecordTrack != NULL); }
+
+ private:
+ AudioRecordThread();
+ sp<AudioFlinger> mAudioFlinger;
+ wp<RecordTrack> mRecordTrack;
+ AudioStreamIn* mInput;
+ Mutex mLock;
+ Condition mWaitWorkCV;
+ AudioBufferProvider::Buffer mBuffer;
+ volatile bool mActive;
+ };
+
+ friend class AudioRecordThread;
+
+ sp<AudioRecordThread> audioRecordThread();
+ void endRecord();
+ status_t startRecord();
+ void stopRecord();
+ void exitRecord();
+
+ AudioHardwareInterface* audioHardware() { return mAudioHardware; }
+
+ mutable Mutex mHardwareLock;
+ mutable Mutex mLock;
+ mutable Condition mWaitWorkCV;
+ DefaultKeyedVector< pid_t, wp<Client> > mClients;
+ SortedVector< wp<Track> > mActiveTracks;
+ SortedVector< sp<Track> > mTracks;
+ float mMasterVolume;
+ uint32_t mMasterRouting;
+ bool mMasterMute;
+ stream_type_t mStreamTypes[AudioTrack::NUM_STREAM_TYPES];
+
+ AudioMixer* mAudioMixer;
+ AudioHardwareInterface* mAudioHardware;
+ AudioStreamOut* mOutput;
+ sp<AudioRecordThread> mAudioRecordThread;
+ uint32_t mSampleRate;
+ size_t mFrameCount;
+ int mChannelCount;
+ int mFormat;
+ int mMixBufferSize;
+ int16_t* mMixBuffer;
+ mutable int mHardwareStatus;
+ nsecs_t mLastWriteTime;
+ int mNumWrites;
+ int mNumDelayedWrites;
+ bool mStandby;
+ bool mInWrite;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_FLINGER_H
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
new file mode 100644
index 0000000..b1e5b7f
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -0,0 +1,293 @@
+/*
+**
+** 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#define LOG_TAG "AudioHardware"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareGeneric.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static char const * const kAudioDeviceName = "/dev/eac";
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareGeneric::AudioHardwareGeneric()
+ : mOutput(0), mInput(0), mFd(-1), mMicMute(false)
+{
+ mFd = ::open(kAudioDeviceName, O_RDWR);
+}
+
+AudioHardwareGeneric::~AudioHardwareGeneric()
+{
+ if (mFd >= 0) ::close(mFd);
+ delete mOutput;
+ delete mInput;
+}
+
+status_t AudioHardwareGeneric::initCheck()
+{
+ if (mFd >= 0) {
+ if (::access(kAudioDeviceName, O_RDWR) == NO_ERROR)
+ return NO_ERROR;
+ }
+ return NO_INIT;
+}
+
+status_t AudioHardwareGeneric::standby()
+{
+ // Implement: audio hardware to standby mode
+ return NO_ERROR;
+}
+
+AudioStreamOut* AudioHardwareGeneric::openOutputStream(
+ int format, int channelCount, uint32_t sampleRate)
+{
+ AutoMutex lock(mLock);
+
+ // only one output stream allowed
+ if (mOutput) return 0;
+
+ // create new output stream
+ AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
+ if (out->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+ mOutput = out;
+ } else {
+ delete out;
+ }
+ return mOutput;
+}
+
+void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) {
+ if (out == mOutput) mOutput = 0;
+}
+
+AudioStreamIn* AudioHardwareGeneric::openInputStream(
+ int format, int channelCount, uint32_t sampleRate)
+{
+ AutoMutex lock(mLock);
+
+ // only one input stream allowed
+ if (mInput) return 0;
+
+ // create new output stream
+ AudioStreamInGeneric* in = new AudioStreamInGeneric();
+ if (in->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+ mInput = in;
+ } else {
+ delete in;
+ }
+ return mInput;
+}
+
+void AudioHardwareGeneric::closeInputStream(AudioStreamInGeneric* in) {
+ if (in == mInput) mInput = 0;
+}
+
+status_t AudioHardwareGeneric::setVoiceVolume(float v)
+{
+ // Implement: set voice volume
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::setMasterVolume(float v)
+{
+ // Implement: set master volume
+ // return error - software mixer will handle it
+ return INVALID_OPERATION;
+}
+
+status_t AudioHardwareGeneric::setMicMute(bool state)
+{
+ mMicMute = state;
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::getMicMute(bool* state)
+{
+ *state = mMicMute;
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioHardwareGeneric::dumpInternals\n");
+ snprintf(buffer, SIZE, "\tmFd: %d mMicMute: %s\n", mFd, mMicMute? "true": "false");
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dump(int fd, const Vector<String16>& args)
+{
+ dumpInternals(fd, args);
+ if (mInput) {
+ mInput->dump(fd, args);
+ }
+ if (mOutput) {
+ mOutput->dump(fd, args);
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutGeneric::set(
+ AudioHardwareGeneric *hw,
+ int fd,
+ int format,
+ int channels,
+ uint32_t rate)
+{
+ // fix up defaults
+ if (format == 0) format = AudioSystem::PCM_16_BIT;
+ if (channels == 0) channels = channelCount();
+ if (rate == 0) rate = sampleRate();
+
+ // check values
+ if ((format != AudioSystem::PCM_16_BIT) ||
+ (channels != channelCount()) ||
+ (rate != sampleRate()))
+ return BAD_VALUE;
+
+ mAudioHardware = hw;
+ mFd = fd;
+ return NO_ERROR;
+}
+
+AudioStreamOutGeneric::~AudioStreamOutGeneric()
+{
+ if (mAudioHardware)
+ mAudioHardware->closeOutputStream(this);
+}
+
+ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)
+{
+ Mutex::Autolock _l(mLock);
+ return ssize_t(::write(mFd, buffer, bytes));
+}
+
+status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamOutGeneric::dump\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+// record functions
+status_t AudioStreamInGeneric::set(
+ AudioHardwareGeneric *hw,
+ int fd,
+ int format,
+ int channels,
+ uint32_t rate)
+{
+ // FIXME: remove logging
+ LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, format, channels, rate);
+ // check values
+ if ((format != AudioSystem::PCM_16_BIT) ||
+ (channels != channelCount()) ||
+ (rate != sampleRate())) {
+ LOGE("Error opening input channel");
+ return BAD_VALUE;
+ }
+
+ mAudioHardware = hw;
+ mFd = fd;
+ return NO_ERROR;
+}
+
+AudioStreamInGeneric::~AudioStreamInGeneric()
+{
+ // FIXME: remove logging
+ LOGD("AudioStreamInGeneric destructor");
+ if (mAudioHardware)
+ mAudioHardware->closeInputStream(this);
+}
+
+ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
+{
+ // FIXME: remove logging
+ LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, bytes, mFd);
+ AutoMutex lock(mLock);
+ if (mFd < 0) {
+ LOGE("Attempt to read from unopened device");
+ return NO_INIT;
+ }
+ return ::read(mFd, buffer, bytes);
+}
+
+status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamInGeneric::dump\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
new file mode 100644
index 0000000..10cc45d
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -0,0 +1,135 @@
+/*
+**
+** 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.
+*/
+
+#ifndef ANDROID_AUDIO_HARDWARE_GENERIC_H
+#define ANDROID_AUDIO_HARDWARE_GENERIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class AudioHardwareGeneric;
+
+class AudioStreamOutGeneric : public AudioStreamOut {
+public:
+ AudioStreamOutGeneric() : mAudioHardware(0), mFd(-1) {}
+ virtual ~AudioStreamOutGeneric();
+
+ virtual status_t set(
+ AudioHardwareGeneric *hw,
+ int mFd,
+ int format,
+ int channelCount,
+ uint32_t sampleRate);
+
+ virtual uint32_t sampleRate() const { return 44100; }
+ virtual size_t bufferSize() const { return 4096; }
+ virtual int channelCount() const { return 2; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ AudioHardwareGeneric *mAudioHardware;
+ Mutex mLock;
+ int mFd;
+};
+
+class AudioStreamInGeneric : public AudioStreamIn {
+public:
+ AudioStreamInGeneric() : mAudioHardware(0), mFd(-1) {}
+ virtual ~AudioStreamInGeneric();
+
+ virtual status_t set(
+ AudioHardwareGeneric *hw,
+ int mFd,
+ int format,
+ int channelCount,
+ uint32_t sampleRate);
+
+ uint32_t sampleRate() const { return 8000; }
+ virtual size_t bufferSize() const { return 320; }
+ virtual int channelCount() const { return 1; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual status_t setGain(float gain) { return INVALID_OPERATION; }
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ AudioHardwareGeneric *mAudioHardware;
+ Mutex mLock;
+ int mFd;
+};
+
+
+class AudioHardwareGeneric : public AudioHardwareInterface
+{
+public:
+ AudioHardwareGeneric();
+ virtual ~AudioHardwareGeneric();
+ virtual status_t initCheck();
+ virtual status_t standby();
+ virtual status_t setVoiceVolume(float volume);
+ virtual status_t setMasterVolume(float volume);
+
+ // mic mute
+ virtual status_t setMicMute(bool state);
+ virtual status_t getMicMute(bool* state);
+
+ virtual status_t setParameter(const char* key, const char* value)
+ { return NO_ERROR; }
+
+ // create I/O streams
+ virtual AudioStreamOut* openOutputStream(
+ int format=0,
+ int channelCount=0,
+ uint32_t sampleRate=0);
+
+ virtual AudioStreamIn* openInputStream(
+ int format,
+ int channelCount,
+ uint32_t sampleRate);
+
+ void closeOutputStream(AudioStreamOutGeneric* out);
+ void closeInputStream(AudioStreamInGeneric* in);
+protected:
+ virtual status_t doRouting() { return NO_ERROR; }
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+
+ Mutex mLock;
+ AudioStreamOutGeneric *mOutput;
+ AudioStreamInGeneric *mInput;
+ int mFd;
+ bool mMicMute;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_GENERIC_H
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
new file mode 100644
index 0000000..7387b3d
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -0,0 +1,240 @@
+/*
+**
+** 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.
+*/
+
+#include <cutils/properties.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TAG "AudioHardwareInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+#include "AudioHardwareGeneric.h"
+
+// #define DUMP_FLINGER_OUT // if defined allows recording samples in a file
+#ifdef DUMP_FLINGER_OUT
+#include "AudioDumpInterface.h"
+#endif
+
+
+// change to 1 to log routing calls
+#define LOG_ROUTING_CALLS 0
+
+namespace android {
+
+#if LOG_ROUTING_CALLS
+static const char* routingModeStrings[] =
+{
+ "OUT OF RANGE",
+ "INVALID",
+ "CURRENT",
+ "NORMAL",
+ "RINGTONE",
+ "IN_CALL"
+};
+
+static const char* routeStrings[] =
+{
+ "EARPIECE ",
+ "SPEAKER ",
+ "BLUETOOTH ",
+ "HEADSET "
+};
+static const char* routeNone = "NONE";
+
+static const char* displayMode(int mode)
+{
+ if ((mode < -2) || (mode > 2))
+ return routingModeStrings[0];
+ return routingModeStrings[mode+3];
+}
+
+static const char* displayRoutes(uint32_t routes)
+{
+ static char routeStr[80];
+ if (routes == 0)
+ return routeNone;
+ routeStr[0] = 0;
+ int bitMask = 1;
+ for (int i = 0; i < 4; ++i, bitMask <<= 1) {
+ if (routes & bitMask) {
+ strcat(routeStr, routeStrings[i]);
+ }
+ }
+ routeStr[strlen(routeStr)-1] = 0;
+ return routeStr;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareInterface* AudioHardwareInterface::create()
+{
+ /*
+ * FIXME: This code needs to instantiate the correct audio device
+ * interface. For now - we use compile-time switches.
+ */
+ AudioHardwareInterface* hw = 0;
+ char value[PROPERTY_VALUE_MAX];
+
+#ifdef GENERIC_AUDIO
+ hw = new AudioHardwareGeneric();
+#else
+ // if running in emulation - use the emulator driver
+ if (property_get("ro.kernel.qemu", value, 0)) {
+ LOGD("Running in emulation - using generic audio driver");
+ hw = new AudioHardwareGeneric();
+ }
+ else {
+ LOGV("Creating Vendor Specific AudioHardware");
+ hw = createAudioHardware();
+ }
+#endif
+ if (hw->initCheck() != NO_ERROR) {
+ LOGW("Using stubbed audio hardware. No sound will be produced.");
+ delete hw;
+ hw = new AudioHardwareStub();
+ }
+
+#ifdef DUMP_FLINGER_OUT
+ // This code adds a record of buffers in a file to write calls made by AudioFlinger.
+ // It replaces the current AudioHardwareInterface object by an intermediate one which
+ // will record buffers in a file (after sending them to hardware) for testing purpose.
+ // This feature is enabled by defining symbol DUMP_FLINGER_OUT and setting environement
+ // "audioflinger.dump = 1". The output file is "tmp/FlingerOut.pcm". Pause are not recorded
+ // in the file.
+
+ // read dump mode
+ property_get("audioflinger.dump", value, "0");
+ switch(value[0]) {
+ case '1':
+ LOGV("Dump mode");
+ hw = new AudioDumpInterface(hw); // replace interface
+ return hw;
+ break;
+ case '0':
+ default:
+ LOGV("No Dump mode");
+ return hw;
+ break;
+ }
+#endif
+ return hw;
+}
+
+AudioStreamOut::~AudioStreamOut()
+{
+}
+
+AudioStreamIn::~AudioStreamIn() {}
+
+AudioHardwareInterface::AudioHardwareInterface()
+{
+ // force a routing update on initialization
+ memset(&mRoutes, 0, sizeof(mRoutes));
+ mMode = 0;
+}
+
+// generics for audio routing - the real work is done in doRouting
+status_t AudioHardwareInterface::setRouting(int mode, uint32_t routes)
+{
+#if LOG_ROUTING_CALLS
+ LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
+#endif
+ if (mode == AudioSystem::MODE_CURRENT)
+ mode = mMode;
+ if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+ return BAD_VALUE;
+ uint32_t old = mRoutes[mode];
+ mRoutes[mode] = routes;
+ if ((mode != mMode) || (old == routes))
+ return NO_ERROR;
+#if LOG_ROUTING_CALLS
+ const char* oldRouteStr = strdup(displayRoutes(old));
+ LOGD("doRouting: mode=%s, old route=[%s], new route=[%s]",
+ displayMode(mode), oldRouteStr, displayRoutes(routes));
+ delete oldRouteStr;
+#endif
+ return doRouting();
+}
+
+status_t AudioHardwareInterface::getRouting(int mode, uint32_t* routes)
+{
+ if (mode == AudioSystem::MODE_CURRENT)
+ mode = mMode;
+ if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+ return BAD_VALUE;
+ *routes = mRoutes[mode];
+#if LOG_ROUTING_CALLS
+ LOGD("getRouting: mode=%s, routes=[%s]",
+ displayMode(mode), displayRoutes(*routes));
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioHardwareInterface::setMode(int mode)
+{
+#if LOG_ROUTING_CALLS
+ LOGD("setMode(%s)", displayMode(mode));
+#endif
+ if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+ return BAD_VALUE;
+ if (mMode == mode)
+ return NO_ERROR;
+#if LOG_ROUTING_CALLS
+ LOGD("doRouting: old mode=%s, new mode=%s route=[%s]",
+ displayMode(mMode), displayMode(mode), displayRoutes(mRoutes[mode]));
+#endif
+ mMode = mode;
+ return doRouting();
+}
+
+status_t AudioHardwareInterface::getMode(int* mode)
+{
+ // Implement: set audio routing
+ *mode = mMode;
+ return NO_ERROR;
+}
+
+status_t AudioHardwareInterface::setParameter(const char* key, const char* value)
+{
+ // default implementation is to ignore
+ return NO_ERROR;
+}
+
+status_t AudioHardwareInterface::dumpState(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioHardwareInterface::dumpState\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
+ result.append(buffer);
+ for (int i = 0, n = AudioSystem::NUM_MODES; i < n; ++i) {
+ snprintf(buffer, SIZE, "\tmRoutes[%d]: %d\n", i, mRoutes[i]);
+ result.append(buffer);
+ }
+ ::write(fd, result.string(), result.size());
+ dump(fd, args); // Dump the state of the concrete child.
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
new file mode 100644
index 0000000..0046db8
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -0,0 +1,175 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.cpp
+**
+** 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareStub::AudioHardwareStub() : mMicMute(false)
+{
+}
+
+AudioHardwareStub::~AudioHardwareStub()
+{
+}
+
+status_t AudioHardwareStub::initCheck()
+{
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::standby()
+{
+ return NO_ERROR;
+}
+
+AudioStreamOut* AudioHardwareStub::openOutputStream(
+ int format, int channelCount, uint32_t sampleRate)
+{
+ AudioStreamOutStub* out = new AudioStreamOutStub();
+ if (out->set(format, channelCount, sampleRate) == NO_ERROR)
+ return out;
+ delete out;
+ return 0;
+}
+
+AudioStreamIn* AudioHardwareStub::openInputStream(
+ int format, int channelCount, uint32_t sampleRate)
+{
+ AudioStreamInStub* in = new AudioStreamInStub();
+ if (in->set(format, channelCount, sampleRate) == NO_ERROR)
+ return in;
+ delete in;
+ return 0;
+}
+
+status_t AudioHardwareStub::setVoiceVolume(float volume)
+{
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::setMasterVolume(float volume)
+{
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioHardwareStub::dumpInternals\n");
+ snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false");
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dump(int fd, const Vector<String16>& args)
+{
+ dumpInternals(fd, args);
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutStub::set(int format, int channels, uint32_t rate)
+{
+ // fix up defaults
+ if (format == 0) format = AudioSystem::PCM_16_BIT;
+ if (channels == 0) channels = channelCount();
+ if (rate == 0) rate = sampleRate();
+
+ if ((format == AudioSystem::PCM_16_BIT) &&
+ (channels == channelCount()) &&
+ (rate == sampleRate()))
+ return NO_ERROR;
+ return BAD_VALUE;
+}
+
+ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)
+{
+ // fake timing for audio output
+ usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+ return bytes;
+}
+
+status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n");
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamInStub::set(int format, int channels, uint32_t rate)
+{
+ if ((format == AudioSystem::PCM_16_BIT) &&
+ (channels == channelCount()) &&
+ (rate == sampleRate()))
+ return NO_ERROR;
+ return BAD_VALUE;
+}
+
+ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)
+{
+ // fake timing for audio input
+ usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+ memset(buffer, 0, bytes);
+ return bytes;
+}
+
+status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamInStub::dump\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
new file mode 100644
index 0000000..1a61552
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -0,0 +1,95 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_AUDIO_HARDWARE_STUB_H
+#define ANDROID_AUDIO_HARDWARE_STUB_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class AudioStreamOutStub : public AudioStreamOut {
+public:
+ virtual status_t set(int format, int channelCount, uint32_t sampleRate);
+ virtual uint32_t sampleRate() const { return 44100; }
+ virtual size_t bufferSize() const { return 4096; }
+ virtual int channelCount() const { return 2; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual status_t setVolume(float volume) { return NO_ERROR; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+};
+
+class AudioStreamInStub : public AudioStreamIn {
+public:
+ virtual status_t set(int format, int channelCount, uint32_t sampleRate);
+ virtual uint32_t sampleRate() const { return 8000; }
+ virtual size_t bufferSize() const { return 320; }
+ virtual int channelCount() const { return 1; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual status_t setGain(float gain) { return NO_ERROR; }
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+};
+
+class AudioHardwareStub : public AudioHardwareInterface
+{
+public:
+ AudioHardwareStub();
+ virtual ~AudioHardwareStub();
+ virtual status_t initCheck();
+ virtual status_t standby();
+ virtual status_t setVoiceVolume(float volume);
+ virtual status_t setMasterVolume(float volume);
+
+ // mic mute
+ virtual status_t setMicMute(bool state) { mMicMute = state; return NO_ERROR; }
+ virtual status_t getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
+
+ virtual status_t setParameter(const char* key, const char* value)
+ { return NO_ERROR; }
+
+ // create I/O streams
+ virtual AudioStreamOut* openOutputStream(
+ int format=0,
+ int channelCount=0,
+ uint32_t sampleRate=0);
+
+ virtual AudioStreamIn* openInputStream(
+ int format,
+ int channelCount,
+ uint32_t sampleRate);
+
+protected:
+ virtual status_t doRouting() { return NO_ERROR; }
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ bool mMicMute;
+private:
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_STUB_H
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
new file mode 100644
index 0000000..9f1b17f
--- /dev/null
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -0,0 +1,857 @@
+/* //device/include/server/AudioFlinger/AudioMixer.cpp
+**
+** 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.
+*/
+
+#define LOG_TAG "AudioMixer"
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "AudioMixer.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+static inline int16_t clamp16(int32_t sample)
+{
+ if ((sample>>15) ^ (sample>>31))
+ sample = 0x7FFF ^ (sample>>31);
+ return sample;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
+ : mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate)
+{
+ mState.enabledTracks= 0;
+ mState.needsChanged = 0;
+ mState.frameCount = frameCount;
+ mState.outputTemp = 0;
+ mState.resampleTemp = 0;
+ mState.hook = process__nop;
+ track_t* t = mState.tracks;
+ for (int i=0 ; i<32 ; i++) {
+ t->needs = 0;
+ t->volume[0] = UNITY_GAIN;
+ t->volume[1] = UNITY_GAIN;
+ t->volumeInc[0] = 0;
+ t->volumeInc[1] = 0;
+ t->channelCount = 2;
+ t->enabled = 0;
+ t->format = 16;
+ t->buffer.raw = 0;
+ t->bufferProvider = 0;
+ t->hook = 0;
+ t->resampler = 0;
+ t->sampleRate = mSampleRate;
+ t->in = 0;
+ t++;
+ }
+}
+
+ AudioMixer::~AudioMixer()
+ {
+ track_t* t = mState.tracks;
+ for (int i=0 ; i<32 ; i++) {
+ delete t->resampler;
+ t++;
+ }
+ delete [] mState.outputTemp;
+ delete [] mState.resampleTemp;
+ }
+
+ int AudioMixer::getTrackName()
+ {
+ uint32_t names = mTrackNames;
+ uint32_t mask = 1;
+ int n = 0;
+ while (names & mask) {
+ mask <<= 1;
+ n++;
+ }
+ if (mask) {
+ LOGV("add track (%d)", n);
+ mTrackNames |= mask;
+ return TRACK0 + n;
+ }
+ return -1;
+ }
+
+ void AudioMixer::invalidateState(uint32_t mask)
+ {
+ if (mask) {
+ mState.needsChanged |= mask;
+ mState.hook = process__validate;
+ }
+ }
+
+ void AudioMixer::deleteTrackName(int name)
+ {
+ name -= TRACK0;
+ if (uint32_t(name) < MAX_NUM_TRACKS) {
+ LOGV("deleteTrackName(%d)", name);
+ track_t& track(mState.tracks[ name ]);
+ if (track.enabled != 0) {
+ track.enabled = 0;
+ invalidateState(1<<name);
+ }
+ if (track.resampler) {
+ // delete the resampler
+ delete track.resampler;
+ track.resampler = 0;
+ track.sampleRate = mSampleRate;
+ invalidateState(1<<name);
+ }
+ track.volumeInc[0] = 0;
+ track.volumeInc[1] = 0;
+ mTrackNames &= ~(1<<name);
+ }
+ }
+
+status_t AudioMixer::enable(int name)
+{
+ switch (name) {
+ case MIXING: {
+ if (mState.tracks[ mActiveTrack ].enabled != 1) {
+ mState.tracks[ mActiveTrack ].enabled = 1;
+ LOGV("enable(%d)", mActiveTrack);
+ invalidateState(1<<mActiveTrack);
+ }
+ } break;
+ default:
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioMixer::disable(int name)
+{
+ switch (name) {
+ case MIXING: {
+ if (mState.tracks[ mActiveTrack ].enabled != 0) {
+ mState.tracks[ mActiveTrack ].enabled = 0;
+ LOGV("disable(%d)", mActiveTrack);
+ invalidateState(1<<mActiveTrack);
+ }
+ } break;
+ default:
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioMixer::setActiveTrack(int track)
+{
+ if (uint32_t(track-TRACK0) >= MAX_NUM_TRACKS) {
+ return BAD_VALUE;
+ }
+ mActiveTrack = track - TRACK0;
+ return NO_ERROR;
+}
+
+status_t AudioMixer::setParameter(int target, int name, int value)
+{
+ switch (target) {
+ case TRACK:
+ if (name == CHANNEL_COUNT) {
+ if ((uint32_t(value) <= MAX_NUM_CHANNELS) && (value)) {
+ if (mState.tracks[ mActiveTrack ].channelCount != value) {
+ mState.tracks[ mActiveTrack ].channelCount = value;
+ LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", value);
+ invalidateState(1<<mActiveTrack);
+ }
+ return NO_ERROR;
+ }
+ }
+ break;
+ case RESAMPLE:
+ if (name == SAMPLE_RATE) {
+ if (value > 0) {
+ track_t& track = mState.tracks[ mActiveTrack ];
+ if (track.setResampler(uint32_t(value), mSampleRate)) {
+ LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
+ uint32_t(value));
+ invalidateState(1<<mActiveTrack);
+ }
+ return NO_ERROR;
+ }
+ }
+ break;
+ case RAMP_VOLUME:
+ case VOLUME:
+ if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
+ track_t& track = mState.tracks[ mActiveTrack ];
+ if (track.volume[name-VOLUME0] != value) {
+ track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
+ track.volume[name-VOLUME0] = value;
+ if (target == VOLUME) {
+ track.prevVolume[name-VOLUME0] = value << 16;
+ track.volumeInc[name-VOLUME0] = 0;
+ } else {
+ int32_t d = (value<<16) - track.prevVolume[name-VOLUME0];
+ int32_t volInc = d / int32_t(mState.frameCount);
+ track.volumeInc[name-VOLUME0] = volInc;
+ if (volInc == 0) {
+ track.prevVolume[name-VOLUME0] = value << 16;
+ }
+ }
+ invalidateState(1<<mActiveTrack);
+ }
+ return NO_ERROR;
+ }
+ break;
+ }
+ return BAD_VALUE;
+}
+
+bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
+{
+ if (value!=devSampleRate || resampler) {
+ if (sampleRate != value) {
+ sampleRate = value;
+ if (resampler == 0) {
+ resampler = AudioResampler::create(
+ format, channelCount, devSampleRate);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioMixer::track_t::doesResample() const
+{
+ return resampler != 0;
+}
+
+inline
+void AudioMixer::track_t::adjustVolumeRamp()
+{
+ for (int i=0 ; i<2 ; i++) {
+ if (((volumeInc[i]>0) && ((prevVolume[i]>>16) >= volume[i])) ||
+ ((volumeInc[i]<0) && ((prevVolume[i]>>16) <= volume[i]))) {
+ volumeInc[i] = 0;
+ prevVolume[i] = volume[i]<<16;
+ }
+ }
+}
+
+
+status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
+{
+ mState.tracks[ mActiveTrack ].bufferProvider = buffer;
+ return NO_ERROR;
+}
+
+
+
+void AudioMixer::process(void* output)
+{
+ mState.hook(&mState, output);
+}
+
+
+void AudioMixer::process__validate(state_t* state, void* output)
+{
+ LOGW_IF(!state->needsChanged,
+ "in process__validate() but nothing's invalid");
+
+ uint32_t changed = state->needsChanged;
+ state->needsChanged = 0; // clear the validation flag
+
+ // recompute which tracks are enabled / disabled
+ uint32_t enabled = 0;
+ uint32_t disabled = 0;
+ while (changed) {
+ const int i = 31 - __builtin_clz(changed);
+ const uint32_t mask = 1<<i;
+ changed &= ~mask;
+ track_t& t = state->tracks[i];
+ (t.enabled ? enabled : disabled) |= mask;
+ }
+ state->enabledTracks &= ~disabled;
+ state->enabledTracks |= enabled;
+
+ // compute everything we need...
+ int countActiveTracks = 0;
+ int all16BitsStereoNoResample = 1;
+ int resampling = 0;
+ int volumeRamp = 0;
+ uint32_t en = state->enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+
+ countActiveTracks++;
+ track_t& t = state->tracks[i];
+ uint32_t n = 0;
+ n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
+ n |= NEEDS_FORMAT_16;
+ n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
+
+ if (t.volumeInc[0]|t.volumeInc[1]) {
+ volumeRamp = 1;
+ } else if (!t.doesResample() && t.volumeRL == 0) {
+ n |= NEEDS_MUTE_ENABLED;
+ }
+ t.needs = n;
+
+ if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
+ t.hook = track__nop;
+ } else {
+ if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
+ all16BitsStereoNoResample = 0;
+ resampling = 1;
+ t.hook = track__genericResample;
+ } else {
+ if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
+ t.hook = track__16BitsMono;
+ all16BitsStereoNoResample = 0;
+ }
+ if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_2){
+ t.hook = track__16BitsStereo;
+ }
+ }
+ }
+ }
+
+ // select the processing hooks
+ state->hook = process__nop;
+ if (countActiveTracks) {
+ if (resampling) {
+ if (!state->outputTemp) {
+ state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
+ }
+ if (!state->resampleTemp) {
+ state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
+ }
+ state->hook = process__genericResampling;
+ } else {
+ if (state->outputTemp) {
+ delete [] state->outputTemp;
+ state->outputTemp = 0;
+ }
+ if (state->resampleTemp) {
+ delete [] state->resampleTemp;
+ state->resampleTemp = 0;
+ }
+ state->hook = process__genericNoResampling;
+ if (all16BitsStereoNoResample && !volumeRamp) {
+ if (countActiveTracks == 1) {
+ state->hook = process__OneTrack16BitsStereoNoResampling;
+ }
+ }
+ }
+ }
+
+ LOGV("mixer configuration change: %d activeTracks (%08x) "
+ "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d",
+ countActiveTracks, state->enabledTracks,
+ all16BitsStereoNoResample, resampling, volumeRamp);
+
+ state->hook(state, output);
+
+ // Now that the volume ramp has been done, set optimal state and
+ // track hooks for subsequent mixer process
+ if (countActiveTracks) {
+ int allMuted = 1;
+ uint32_t en = state->enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+ if (!t.doesResample() && t.volumeRL == 0)
+ {
+ t.needs |= NEEDS_MUTE_ENABLED;
+ t.hook = track__nop;
+ } else {
+ allMuted = 0;
+ }
+ }
+ if (allMuted) {
+ state->hook = process__nop;
+ } else if (!resampling && all16BitsStereoNoResample) {
+ if (countActiveTracks == 1) {
+ state->hook = process__OneTrack16BitsStereoNoResampling;
+ }
+ }
+ }
+}
+
+static inline
+int32_t mulAdd(int16_t in, int16_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ asm( "smlabb %[out], %[in], %[v], %[a] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+ : );
+ return out;
+#else
+ return a + in * int32_t(v);
+#endif
+}
+
+static inline
+int32_t mul(int16_t in, int16_t v)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ asm( "smulbb %[out], %[in], %[v] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [v]"r"(v)
+ : );
+ return out;
+#else
+ return in * int32_t(v);
+#endif
+}
+
+static inline
+int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ if (left) {
+ asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
+ : );
+ } else {
+ asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
+ : );
+ }
+ return out;
+#else
+ if (left) {
+ return a + int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF);
+ } else {
+ return a + int16_t(inRL>>16) * int16_t(vRL>>16);
+ }
+#endif
+}
+
+static inline
+int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ if (left) {
+ asm( "smulbb %[out], %[inRL], %[vRL] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL)
+ : );
+ } else {
+ asm( "smultt %[out], %[inRL], %[vRL] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL)
+ : );
+ }
+ return out;
+#else
+ if (left) {
+ return int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF);
+ } else {
+ return int16_t(inRL>>16) * int16_t(vRL>>16);
+ }
+#endif
+}
+
+
+void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+{
+ t->resampler->setSampleRate(t->sampleRate);
+
+ // ramp gain - resample to temp buffer and scale/mix in 2nd step
+ if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+ t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
+ memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
+ t->resampler->resample(temp, outFrameCount, t->bufferProvider);
+ volumeRampStereo(t, out, outFrameCount, temp);
+ }
+
+ // constant gain
+ else {
+ t->resampler->setVolume(t->volume[0], t->volume[1]);
+ t->resampler->resample(out, outFrameCount, t->bufferProvider);
+ }
+}
+
+void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+{
+}
+
+void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+ int32_t vl = t->prevVolume[0];
+ int32_t vr = t->prevVolume[1];
+ const int32_t vlInc = t->volumeInc[0];
+ const int32_t vrInc = t->volumeInc[1];
+
+ //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+ // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+ // (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+ // ramp volume
+ do {
+ *out++ += (vl >> 16) * (*temp++ >> 12);
+ *out++ += (vr >> 16) * (*temp++ >> 12);
+ vl += vlInc;
+ vr += vrInc;
+ } while (--frameCount);
+
+ t->prevVolume[0] = vl;
+ t->prevVolume[1] = vr;
+ t->adjustVolumeRamp();
+}
+
+void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+ int16_t const *in = static_cast<int16_t const *>(t->in);
+
+ // ramp gain
+ if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+ int32_t vl = t->prevVolume[0];
+ int32_t vr = t->prevVolume[1];
+ const int32_t vlInc = t->volumeInc[0];
+ const int32_t vrInc = t->volumeInc[1];
+
+ // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+ // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+ // (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+ do {
+ *out++ += (vl >> 16) * (int32_t) *in++;
+ *out++ += (vr >> 16) * (int32_t) *in++;
+ vl += vlInc;
+ vr += vrInc;
+ } while (--frameCount);
+
+ t->prevVolume[0] = vl;
+ t->prevVolume[1] = vr;
+ t->adjustVolumeRamp();
+ }
+
+ // constant gain
+ else {
+ const uint32_t vrl = t->volumeRL;
+ do {
+ uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+ in += 2;
+ out[0] = mulAddRL(1, rl, vrl, out[0]);
+ out[1] = mulAddRL(0, rl, vrl, out[1]);
+ out += 2;
+ } while (--frameCount);
+ }
+ t->in = in;
+}
+
+void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+ int16_t const *in = static_cast<int16_t const *>(t->in);
+
+ // ramp gain
+ if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+ int32_t vl = t->prevVolume[0];
+ int32_t vr = t->prevVolume[1];
+ const int32_t vlInc = t->volumeInc[0];
+ const int32_t vrInc = t->volumeInc[1];
+
+ // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
+ // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
+ // (vl + vlInc*frameCount)/65536.0f, frameCount);
+
+ do {
+ int32_t l = *in++;
+ *out++ += (vl >> 16) * l;
+ *out++ += (vr >> 16) * l;
+ vl += vlInc;
+ vr += vrInc;
+ } while (--frameCount);
+
+ t->prevVolume[0] = vl;
+ t->prevVolume[1] = vr;
+ t->adjustVolumeRamp();
+ }
+ // constant gain
+ else {
+ const int16_t vl = t->volume[0];
+ const int16_t vr = t->volume[1];
+ do {
+ int16_t l = *in++;
+ out[0] = mulAdd(l, vl, out[0]);
+ out[1] = mulAdd(l, vr, out[1]);
+ out += 2;
+ } while (--frameCount);
+ }
+ t->in = in;
+}
+
+inline
+void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
+{
+ for (size_t i=0 ; i<c ; i++) {
+ int32_t l = *sums++;
+ int32_t r = *sums++;
+ int32_t nl = l >> 12;
+ int32_t nr = r >> 12;
+ l = clamp16(nl);
+ r = clamp16(nr);
+ *out++ = (r<<16) | (l & 0xFFFF);
+ }
+}
+
+// no-op case
+void AudioMixer::process__nop(state_t* state, void* output)
+{
+ // this assumes output 16 bits stereo, no resampling
+ memset(output, 0, state->frameCount*4);
+ uint32_t en = state->enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+ t.bufferProvider->getNextBuffer(&t.buffer);
+ if (t.buffer.raw) {
+ t.bufferProvider->releaseBuffer(&t.buffer);
+ }
+ }
+}
+
+// generic code without resampling
+void AudioMixer::process__genericNoResampling(state_t* state, void* output)
+{
+ int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
+
+ // acquire each track's buffer
+ uint32_t enabledTracks = state->enabledTracks;
+ uint32_t en = enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+ t.bufferProvider->getNextBuffer(&t.buffer);
+ t.in = t.buffer.raw;
+ // t.in == NULL can happen if the track was flushed just after having
+ // been enabled for mixing.
+ if (t.in == NULL)
+ enabledTracks &= ~(1<<i);
+ }
+
+ // this assumes output 16 bits stereo, no resampling
+ int32_t* out = static_cast<int32_t*>(output);
+ size_t numFrames = state->frameCount;
+ do {
+ memset(outTemp, 0, sizeof(outTemp));
+
+ en = enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+ (t.hook)(&t, outTemp, BLOCKSIZE, state->resampleTemp);
+ }
+
+ ditherAndClamp(out, outTemp, BLOCKSIZE);
+ out += BLOCKSIZE;
+
+ numFrames -= BLOCKSIZE;
+ } while (numFrames);
+
+
+ // release each track's buffer
+ en = enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+ t.bufferProvider->releaseBuffer(&t.buffer);
+ }
+}
+
+// generic code with resampling
+void AudioMixer::process__genericResampling(state_t* state, void* output)
+{
+ int32_t* const outTemp = state->outputTemp;
+ const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
+ memset(outTemp, 0, size);
+
+ int32_t* out = static_cast<int32_t*>(output);
+ size_t numFrames = state->frameCount;
+
+ uint32_t en = state->enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+
+ // this is a little goofy, on the resampling case we don't
+ // acquire/release the buffers because it's done by
+ // the resampler.
+ if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
+ (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
+ } else {
+ t.bufferProvider->getNextBuffer(&t.buffer);
+ t.in = t.buffer.raw;
+ // t.in == NULL can happen if the track was flushed just after having
+ // been enabled for mixing.
+ if (t.in) {
+ (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
+ t.bufferProvider->releaseBuffer(&t.buffer);
+ }
+ }
+ }
+
+ ditherAndClamp(out, outTemp, numFrames);
+}
+
+// one track, 16 bits stereo without resampling is the most common case
+void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output)
+{
+ const int i = 31 - __builtin_clz(state->enabledTracks);
+ const track_t& t = state->tracks[i];
+
+ AudioBufferProvider::Buffer& b(t.buffer);
+ t.bufferProvider->getNextBuffer(&b);
+ int16_t const *in = t.buffer.i16;
+
+ // in == NULL can happen if the track was flushed just after having
+ // been enabled for mixing.
+ if (in == NULL) {
+ memset(output, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
+ return;
+ }
+
+ int32_t* out = static_cast<int32_t*>(output);
+ size_t numFrames = state->frameCount;
+ const int16_t vl = t.volume[0];
+ const int16_t vr = t.volume[1];
+ const uint32_t vrl = t.volumeRL;
+ if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
+ // volume is boosted, so we might need to clamp even though
+ // we process only one track.
+ do {
+ uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+ in += 2;
+ int32_t l = mulRL(1, rl, vrl) >> 12;
+ int32_t r = mulRL(0, rl, vrl) >> 12;
+ // clamping...
+ l = clamp16(l);
+ r = clamp16(r);
+ *out++ = (r<<16) | (l & 0xFFFF);
+ } while (--numFrames);
+ } else {
+ do {
+ uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+ in += 2;
+ int32_t l = mulRL(1, rl, vrl) >> 12;
+ int32_t r = mulRL(0, rl, vrl) >> 12;
+ *out++ = (r<<16) | (l & 0xFFFF);
+ } while (--numFrames);
+ }
+
+ t.bufferProvider->releaseBuffer(&b);
+}
+
+// 2 tracks is also a common case
+void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output)
+{
+ int i;
+ uint32_t en = state->enabledTracks;
+
+ i = 31 - __builtin_clz(en);
+ const track_t& t0 = state->tracks[i];
+ AudioBufferProvider::Buffer& b0(t0.buffer);
+ t0.bufferProvider->getNextBuffer(&b0);
+
+ en &= ~(1<<i);
+ i = 31 - __builtin_clz(en);
+ const track_t& t1 = state->tracks[i];
+ AudioBufferProvider::Buffer& b1(t1.buffer);
+ t1.bufferProvider->getNextBuffer(&b1);
+
+ int16_t const *in0;
+ const int16_t vl0 = t0.volume[0];
+ const int16_t vr0 = t0.volume[1];
+ int16_t const *in1;
+ const int16_t vl1 = t1.volume[0];
+ const int16_t vr1 = t1.volume[1];
+ size_t numFrames = state->frameCount;
+ int32_t* out = static_cast<int32_t*>(output);
+
+ // t0/1.buffer.i16 == NULL can happen if the track was flushed just after having
+ // been enabled for mixing.
+ if (t0.buffer.i16 != NULL) {
+ in0 = t0.buffer.i16;
+ if (t1.buffer.i16 != NULL) {
+ in1 = t1.buffer.i16;
+ } else {
+ in1 = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
+ memset((void *)in1, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
+ }
+ } else {
+ in0 = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
+ memset((void *)in0, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
+ if (t1.buffer.i16 != NULL) {
+ in1 = t1.buffer.i16;
+ } else {
+ in1 = in0;
+ }
+ }
+
+ do {
+ int32_t l0 = *in0++;
+ int32_t r0 = *in0++;
+ l0 = mul(l0, vl0);
+ r0 = mul(r0, vr0);
+ int32_t l = *in1++;
+ int32_t r = *in1++;
+ l = mulAdd(l, vl1, l0) >> 12;
+ r = mulAdd(r, vr1, r0) >> 12;
+ // clamping...
+ l = clamp16(l);
+ r = clamp16(r);
+ *out++ = (r<<16) | (l & 0xFFFF);
+ } while (--numFrames);
+
+
+ if (t0.buffer.i16 != NULL) {
+ t0.bufferProvider->releaseBuffer(&b0);
+ if (t1.buffer.i16 != NULL) {
+ t1.bufferProvider->releaseBuffer(&b1);
+ } else {
+ delete [] in1;
+ }
+ } else {
+ delete [] in0;
+ if (t1.buffer.i16 != NULL) {
+ t1.bufferProvider->releaseBuffer(&b1);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
new file mode 100644
index 0000000..9ca109f
--- /dev/null
+++ b/libs/audioflinger/AudioMixer.h
@@ -0,0 +1,192 @@
+/* //device/include/server/AudioFlinger/AudioMixer.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_AUDIO_MIXER_H
+#define ANDROID_AUDIO_MIXER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "AudioBufferProvider.h"
+#include "AudioResampler.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ----------------------------------------------------------------------------
+
+class AudioMixer
+{
+public:
+ AudioMixer(size_t frameCount, uint32_t sampleRate);
+
+ ~AudioMixer();
+
+ static const uint32_t MAX_NUM_TRACKS = 32;
+ static const uint32_t MAX_NUM_CHANNELS = 2;
+
+ static const uint16_t UNITY_GAIN = 0x1000;
+
+ enum { // names
+
+ // track units (32 units)
+ TRACK0 = 0x1000,
+
+ // enable/disable
+ MIXING = 0x2000,
+
+ // setParameter targets
+ TRACK = 0x3000,
+ RESAMPLE = 0x3001,
+ RAMP_VOLUME = 0x3002, // ramp to new volume
+ VOLUME = 0x3003, // don't ramp
+
+ // set Parameter names
+ // for target TRACK
+ CHANNEL_COUNT = 0x4000,
+ FORMAT = 0x4001,
+ // for TARGET RESAMPLE
+ SAMPLE_RATE = 0x4100,
+ // for TARGET VOLUME (8 channels max)
+ VOLUME0 = 0x4200,
+ VOLUME1 = 0x4201,
+ };
+
+
+ int getTrackName();
+ void deleteTrackName(int name);
+
+ status_t enable(int name);
+ status_t disable(int name);
+
+ status_t setActiveTrack(int track);
+ status_t setParameter(int target, int name, int value);
+
+ status_t setBufferProvider(AudioBufferProvider* bufferProvider);
+ void process(void* output);
+
+ uint32_t trackNames() const { return mTrackNames; }
+
+private:
+
+ enum {
+ NEEDS_CHANNEL_COUNT__MASK = 0x00000003,
+ NEEDS_FORMAT__MASK = 0x000000F0,
+ NEEDS_MUTE__MASK = 0x00000100,
+ NEEDS_RESAMPLE__MASK = 0x00001000,
+ };
+
+ enum {
+ NEEDS_CHANNEL_1 = 0x00000000,
+ NEEDS_CHANNEL_2 = 0x00000001,
+
+ NEEDS_FORMAT_16 = 0x00000010,
+
+ NEEDS_MUTE_DISABLED = 0x00000000,
+ NEEDS_MUTE_ENABLED = 0x00000100,
+
+ NEEDS_RESAMPLE_DISABLED = 0x00000000,
+ NEEDS_RESAMPLE_ENABLED = 0x00001000,
+ };
+
+ static inline int32_t applyVolume(int32_t in, int32_t v) {
+ return in * v;
+ }
+
+
+ struct state_t;
+
+ typedef void (*mix_t)(state_t* state, void* output);
+
+ static const int BLOCKSIZE = 16; // 4 cache lines
+
+ struct track_t {
+ uint32_t needs;
+
+ union {
+ int16_t volume[2]; // [0]3.12 fixed point
+ int32_t volumeRL;
+ };
+
+ int32_t prevVolume[2];
+
+ int32_t volumeInc[2];
+
+ uint16_t reserved;
+
+ uint8_t channelCount : 4;
+ uint8_t enabled : 1;
+ uint8_t reserved0 : 3;
+ uint8_t format;
+
+ AudioBufferProvider* bufferProvider;
+ mutable AudioBufferProvider::Buffer buffer;
+
+ void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp);
+ void const* in; // current location in buffer
+
+ AudioResampler* resampler;
+ uint32_t sampleRate;
+
+ bool setResampler(uint32_t sampleRate, uint32_t devSampleRate);
+ bool doesResample() const;
+ void adjustVolumeRamp();
+ };
+
+ // pad to 32-bytes to fill cache line
+ struct state_t {
+ uint32_t enabledTracks;
+ uint32_t needsChanged;
+ size_t frameCount;
+ mix_t hook;
+ int32_t *outputTemp;
+ int32_t *resampleTemp;
+ int32_t reserved[2];
+ track_t tracks[32]; __attribute__((aligned(32)));
+ };
+
+ int mActiveTrack;
+ uint32_t mTrackNames;
+ const uint32_t mSampleRate;
+
+ state_t mState __attribute__((aligned(32)));
+
+ void invalidateState(uint32_t mask);
+
+ static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+ static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+ static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
+ static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+ static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+ static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
+
+ static void process__validate(state_t* state, void* output);
+ static void process__nop(state_t* state, void* output);
+ static void process__genericNoResampling(state_t* state, void* output);
+ static void process__genericResampling(state_t* state, void* output);
+ static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output);
+ static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_AUDIO_MIXER_H
diff --git a/libs/audioflinger/AudioResampler.cpp b/libs/audioflinger/AudioResampler.cpp
new file mode 100644
index 0000000..c93ead3
--- /dev/null
+++ b/libs/audioflinger/AudioResampler.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "AudioResampler.h"
+#include "AudioResamplerSinc.h"
+#include "AudioResamplerCubic.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerOrder1 : public AudioResampler {
+public:
+ AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
+ AudioResampler(bitDepth, inChannelCount, sampleRate), mX0L(0), mX0R(0) {
+ }
+ virtual void resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+private:
+ // number of bits used in interpolation multiply - 15 bits avoids overflow
+ static const int kNumInterpBits = 15;
+
+ // bits to shift the phase fraction down to avoid overflow
+ static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
+
+ void init() {}
+ void resampleMono16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+ void resampleStereo16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+ static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
+ return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
+ }
+ static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) {
+ *frac += inc;
+ *index += (size_t)(*frac >> kNumPhaseBits);
+ *frac &= kPhaseMask;
+ }
+ int mX0L;
+ int mX0R;
+};
+
+// ----------------------------------------------------------------------------
+AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
+ int32_t sampleRate, int quality) {
+
+ // can only create low quality resample now
+ AudioResampler* resampler;
+
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("af.resampler.quality", value, 0)) {
+ quality = atoi(value);
+ LOGD("forcing AudioResampler quality to %d", quality);
+ }
+
+ if (quality == DEFAULT)
+ quality = LOW_QUALITY;
+
+ switch (quality) {
+ default:
+ case LOW_QUALITY:
+ resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
+ break;
+ case MED_QUALITY:
+ resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
+ break;
+ case HIGH_QUALITY:
+ resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
+ break;
+ }
+
+ // initialize resampler
+ resampler->init();
+ return resampler;
+}
+
+AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
+ int32_t sampleRate) :
+ mBitDepth(bitDepth), mChannelCount(inChannelCount),
+ mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
+ mPhaseFraction(0) {
+ // sanity check on format
+ if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
+ LOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
+ inChannelCount);
+ // LOG_ASSERT(0);
+ }
+
+ // initialize common members
+ mVolume[0] = mVolume[1] = 0;
+ mBuffer.raw = NULL;
+
+ // save format for quick lookup
+ if (inChannelCount == 1) {
+ mFormat = MONO_16_BIT;
+ } else {
+ mFormat = STEREO_16_BIT;
+ }
+}
+
+AudioResampler::~AudioResampler() {
+}
+
+void AudioResampler::setSampleRate(int32_t inSampleRate) {
+ mInSampleRate = inSampleRate;
+ mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
+}
+
+void AudioResampler::setVolume(int16_t left, int16_t right) {
+ // TODO: Implement anti-zipper filter
+ mVolume[0] = left;
+ mVolume[1] = right;
+}
+
+// ----------------------------------------------------------------------------
+
+void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ // should never happen, but we overflow if it does
+ // LOG_ASSERT(outFrameCount < 32767);
+
+ // select the appropriate resampler
+ switch (mChannelCount) {
+ case 1:
+ resampleMono16(out, outFrameCount, provider);
+ break;
+ case 2:
+ resampleStereo16(out, outFrameCount, provider);
+ break;
+ }
+}
+
+void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ int32_t vl = mVolume[0];
+ int32_t vr = mVolume[1];
+
+ size_t inputIndex = mInputIndex;
+ uint32_t phaseFraction = mPhaseFraction;
+ uint32_t phaseIncrement = mPhaseIncrement;
+ size_t outputIndex = 0;
+ size_t outputSampleCount = outFrameCount * 2;
+
+ // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
+ // outFrameCount, inputIndex, phaseFraction, phaseIncrement);
+
+ while (outputIndex < outputSampleCount) {
+
+ // buffer is empty, fetch a new one
+ if (mBuffer.raw == NULL) {
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ break;
+ // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+ }
+ int16_t *in = mBuffer.i16;
+
+ // handle boundary case
+ while (inputIndex == 0) {
+ // LOGE("boundary case\n");
+ out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
+ out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
+ Advance(&inputIndex, &phaseFraction, phaseIncrement);
+ if (outputIndex == outputSampleCount)
+ break;
+ }
+
+ // process input samples
+ // LOGE("general case\n");
+ while (outputIndex < outputSampleCount) {
+ out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
+ in[inputIndex*2], phaseFraction);
+ out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
+ in[inputIndex*2+1], phaseFraction);
+ Advance(&inputIndex, &phaseFraction, phaseIncrement);
+ if (inputIndex >= mBuffer.frameCount)
+ break;
+ }
+ // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+ // if done with buffer, save samples
+ if (inputIndex >= mBuffer.frameCount) {
+ inputIndex -= mBuffer.frameCount;
+
+ // LOGE("buffer done, new input index", inputIndex);
+
+ mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
+ mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
+ provider->releaseBuffer(&mBuffer);
+
+ // verify that the releaseBuffer NULLS the buffer pointer
+ // LOG_ASSERT(mBuffer.raw == NULL);
+ }
+ }
+
+ // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+ // save state
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+}
+
+void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ int32_t vl = mVolume[0];
+ int32_t vr = mVolume[1];
+
+ size_t inputIndex = mInputIndex;
+ uint32_t phaseFraction = mPhaseFraction;
+ uint32_t phaseIncrement = mPhaseIncrement;
+ size_t outputIndex = 0;
+ size_t outputSampleCount = outFrameCount * 2;
+
+ // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
+ // outFrameCount, inputIndex, phaseFraction, phaseIncrement);
+
+ while (outputIndex < outputSampleCount) {
+
+ // buffer is empty, fetch a new one
+ if (mBuffer.raw == NULL) {
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ break;
+ // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+ }
+ int16_t *in = mBuffer.i16;
+
+ // handle boundary case
+ while (inputIndex == 0) {
+ // LOGE("boundary case\n");
+ int32_t sample = Interp(mX0L, in[0], phaseFraction);
+ out[outputIndex++] += vl * sample;
+ out[outputIndex++] += vr * sample;
+ Advance(&inputIndex, &phaseFraction, phaseIncrement);
+ if (outputIndex == outputSampleCount)
+ break;
+ }
+
+ // process input samples
+ // LOGE("general case\n");
+ while (outputIndex < outputSampleCount) {
+ int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
+ phaseFraction);
+ out[outputIndex++] += vl * sample;
+ out[outputIndex++] += vr * sample;
+ Advance(&inputIndex, &phaseFraction, phaseIncrement);
+ if (inputIndex >= mBuffer.frameCount)
+ break;
+ }
+ // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+ // if done with buffer, save samples
+ if (inputIndex >= mBuffer.frameCount) {
+ inputIndex -= mBuffer.frameCount;
+
+ // LOGE("buffer done, new input index", inputIndex);
+
+ mX0L = mBuffer.i16[mBuffer.frameCount-1];
+ provider->releaseBuffer(&mBuffer);
+
+ // verify that the releaseBuffer NULLS the buffer pointer
+ // LOG_ASSERT(mBuffer.raw == NULL);
+ }
+ }
+
+ // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+ // save state
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+}
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
diff --git a/libs/audioflinger/AudioResampler.h b/libs/audioflinger/AudioResampler.h
new file mode 100644
index 0000000..39656c0
--- /dev/null
+++ b/libs/audioflinger/AudioResampler.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_AUDIO_RESAMPLER_H
+#define ANDROID_AUDIO_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "AudioBufferProvider.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResampler {
+public:
+ // Determines quality of SRC.
+ // LOW_QUALITY: linear interpolator (1st order)
+ // MED_QUALITY: cubic interpolator (3rd order)
+ // HIGH_QUALITY: fixed multi-tap FIR (e.g. 48KHz->44.1KHz)
+ // NOTE: high quality SRC will only be supported for
+ // certain fixed rate conversions. Sample rate cannot be
+ // changed dynamically.
+ enum src_quality {
+ DEFAULT=0,
+ LOW_QUALITY=1,
+ MED_QUALITY=2,
+ HIGH_QUALITY=3
+ };
+
+ static AudioResampler* create(int bitDepth, int inChannelCount,
+ int32_t sampleRate, int quality=DEFAULT);
+
+ virtual ~AudioResampler();
+
+ virtual void init() = 0;
+ virtual void setSampleRate(int32_t inSampleRate);
+ virtual void setVolume(int16_t left, int16_t right);
+
+ virtual void resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) = 0;
+
+protected:
+ // number of bits for phase fraction - 30 bits allows nearly 2x downsampling
+ static const int kNumPhaseBits = 30;
+
+ // phase mask for fraction
+ static const uint32_t kPhaseMask = (1LU<<kNumPhaseBits)-1;
+
+ // multiplier to calculate fixed point phase increment
+ static const double kPhaseMultiplier = 1L << kNumPhaseBits;
+
+ enum format {MONO_16_BIT, STEREO_16_BIT};
+ AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate);
+
+ // prevent copying
+ AudioResampler(const AudioResampler&);
+ AudioResampler& operator=(const AudioResampler&);
+
+ int32_t mBitDepth;
+ int32_t mChannelCount;
+ int32_t mSampleRate;
+ int32_t mInSampleRate;
+ AudioBufferProvider::Buffer mBuffer;
+ union {
+ int16_t mVolume[2];
+ uint32_t mVolumeRL;
+ };
+ int16_t mTargetVolume[2];
+ format mFormat;
+ size_t mInputIndex;
+ int32_t mPhaseIncrement;
+ uint32_t mPhaseFraction;
+};
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
+#endif // ANDROID_AUDIO_RESAMPLER_H
diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/libs/audioflinger/AudioResamplerCubic.cpp
new file mode 100644
index 0000000..4f437bf
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerCubic.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+#include "AudioResamplerCubic.h"
+
+#define LOG_TAG "AudioSRC"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+void AudioResamplerCubic::init() {
+ memset(&left, 0, sizeof(state));
+ memset(&right, 0, sizeof(state));
+}
+
+void AudioResamplerCubic::resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ // should never happen, but we overflow if it does
+ // LOG_ASSERT(outFrameCount < 32767);
+
+ // select the appropriate resampler
+ switch (mChannelCount) {
+ case 1:
+ resampleMono16(out, outFrameCount, provider);
+ break;
+ case 2:
+ resampleStereo16(out, outFrameCount, provider);
+ break;
+ }
+}
+
+void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ int32_t vl = mVolume[0];
+ int32_t vr = mVolume[1];
+
+ size_t inputIndex = mInputIndex;
+ uint32_t phaseFraction = mPhaseFraction;
+ uint32_t phaseIncrement = mPhaseIncrement;
+ size_t outputIndex = 0;
+ size_t outputSampleCount = outFrameCount * 2;
+
+ // fetch first buffer
+ if (mBuffer.raw == NULL) {
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ return;
+ // LOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
+ }
+ int16_t *in = mBuffer.i16;
+
+ while (outputIndex < outputSampleCount) {
+ int32_t sample;
+ int32_t x;
+
+ // calculate output sample
+ x = phaseFraction >> kPreInterpShift;
+ out[outputIndex++] += vl * interp(&left, x);
+ out[outputIndex++] += vr * interp(&right, x);
+ // out[outputIndex++] += vr * in[inputIndex*2];
+
+ // increment phase
+ phaseFraction += phaseIncrement;
+ uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
+ phaseFraction &= kPhaseMask;
+
+ // time to fetch another sample
+ while (indexIncrement--) {
+
+ inputIndex++;
+ if (inputIndex == mBuffer.frameCount) {
+ inputIndex = 0;
+ provider->releaseBuffer(&mBuffer);
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ goto save_state; // ugly, but efficient
+ in = mBuffer.i16;
+ // LOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+ }
+
+ // advance sample state
+ advance(&left, in[inputIndex*2]);
+ advance(&right, in[inputIndex*2+1]);
+ }
+ }
+
+save_state:
+ // LOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction);
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+}
+
+void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ int32_t vl = mVolume[0];
+ int32_t vr = mVolume[1];
+
+ size_t inputIndex = mInputIndex;
+ uint32_t phaseFraction = mPhaseFraction;
+ uint32_t phaseIncrement = mPhaseIncrement;
+ size_t outputIndex = 0;
+ size_t outputSampleCount = outFrameCount * 2;
+
+ // fetch first buffer
+ if (mBuffer.raw == NULL) {
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ return;
+ // LOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+ }
+ int16_t *in = mBuffer.i16;
+
+ while (outputIndex < outputSampleCount) {
+ int32_t sample;
+ int32_t x;
+
+ // calculate output sample
+ x = phaseFraction >> kPreInterpShift;
+ sample = interp(&left, x);
+ out[outputIndex++] += vl * sample;
+ out[outputIndex++] += vr * sample;
+
+ // increment phase
+ phaseFraction += phaseIncrement;
+ uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
+ phaseFraction &= kPhaseMask;
+
+ // time to fetch another sample
+ while (indexIncrement--) {
+
+ inputIndex++;
+ if (inputIndex == mBuffer.frameCount) {
+ inputIndex = 0;
+ provider->releaseBuffer(&mBuffer);
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ goto save_state; // ugly, but efficient
+ // LOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
+ in = mBuffer.i16;
+ }
+
+ // advance sample state
+ advance(&left, in[inputIndex]);
+ }
+ }
+
+save_state:
+ // LOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction);
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+}
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
diff --git a/libs/audioflinger/AudioResamplerCubic.h b/libs/audioflinger/AudioResamplerCubic.h
new file mode 100644
index 0000000..b72b62a
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerCubic.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_AUDIO_RESAMPLER_CUBIC_H
+#define ANDROID_AUDIO_RESAMPLER_CUBIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerCubic : public AudioResampler {
+public:
+ AudioResamplerCubic(int bitDepth, int inChannelCount, int32_t sampleRate) :
+ AudioResampler(bitDepth, inChannelCount, sampleRate) {
+ }
+ virtual void resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+private:
+ // number of bits used in interpolation multiply - 14 bits avoids overflow
+ static const int kNumInterpBits = 14;
+
+ // bits to shift the phase fraction down to avoid overflow
+ static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
+ typedef struct {
+ int32_t a, b, c, y0, y1, y2, y3;
+ } state;
+ void init();
+ void resampleMono16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+ void resampleStereo16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+ static inline int32_t interp(state* p, int32_t x) {
+ return (((((p->a * x >> 14) + p->b) * x >> 14) + p->c) * x >> 14) + p->y1;
+ }
+ static inline void advance(state* p, int16_t in) {
+ p->y0 = p->y1;
+ p->y1 = p->y2;
+ p->y2 = p->y3;
+ p->y3 = in;
+ p->a = (3 * (p->y1 - p->y2) - p->y0 + p->y3) >> 1;
+ p->b = (p->y2 << 1) + p->y0 - (((5 * p->y1 + p->y3)) >> 1);
+ p->c = (p->y2 - p->y0) >> 1;
+ }
+ state left, right;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_CUBIC_H*/
diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/libs/audioflinger/AudioResamplerSinc.cpp
new file mode 100644
index 0000000..e710d16
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerSinc.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <string.h>
+#include "AudioResamplerSinc.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+
+/*
+ * These coeficients are computed with the "fir" utility found in
+ * tools/resampler_tools
+ * TODO: A good optimization would be to transpose this matrix, to take
+ * better advantage of the data-cache.
+ */
+const int32_t AudioResamplerSinc::mFirCoefsUp[] = {
+ 0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621,
+ 0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9,
+ 0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9,
+ 0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798,
+ 0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636,
+ 0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2,
+ 0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070,
+ 0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000 // this one is needed for lerping the last coefficient
+};
+
+/*
+ * These coefficients are optimized for 48KHz -> 44.1KHz (stop-band at 22.050KHz)
+ * It's possible to use the above coefficient for any down-sampling
+ * at the expense of a slower processing loop (we can interpolate
+ * these coefficient from the above by "Stretching" them in time).
+ */
+const int32_t AudioResamplerSinc::mFirCoefsDown[] = {
+ 0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540,
+ 0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4,
+ 0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa,
+ 0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066,
+ 0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf,
+ 0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d,
+ 0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a,
+ 0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000,
+ 0x00000000 // this one is needed for lerping the last coefficient
+};
+
+// ----------------------------------------------------------------------------
+
+static inline
+int32_t mulRL(int left, int32_t in, uint32_t vRL)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ if (left) {
+ asm( "smultb %[out], %[in], %[vRL] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [vRL]"r"(vRL)
+ : );
+ } else {
+ asm( "smultt %[out], %[in], %[vRL] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [vRL]"r"(vRL)
+ : );
+ }
+ return out;
+#else
+ if (left) {
+ return int16_t(in>>16) * int16_t(vRL&0xFFFF);
+ } else {
+ return int16_t(in>>16) * int16_t(vRL>>16);
+ }
+#endif
+}
+
+static inline
+int32_t mulAdd(int16_t in, int32_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ asm( "smlawb %[out], %[v], %[in], %[a] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+ : );
+ return out;
+#else
+ return a + ((in * int32_t(v))>>16);
+#endif
+}
+
+static inline
+int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ if (left) {
+ asm( "smlawb %[out], %[v], %[inRL], %[a] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+ : );
+ } else {
+ asm( "smlawt %[out], %[v], %[inRL], %[a] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+ : );
+ }
+ return out;
+#else
+ if (left) {
+ return a + ((int16_t(inRL&0xFFFF) * int32_t(v))>>16);
+ } else {
+ return a + ((int16_t(inRL>>16) * int32_t(v))>>16);
+ }
+#endif
+}
+
+// ----------------------------------------------------------------------------
+
+AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
+ int inChannelCount, int32_t sampleRate)
+ : AudioResampler(bitDepth, inChannelCount, sampleRate),
+ mState(0)
+{
+ /*
+ * Layout of the state buffer for 32 tap:
+ *
+ * "present" sample beginning of 2nd buffer
+ * v v
+ * 0 01 2 23 3
+ * 0 F0 0 F0 F
+ * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
+ * ^ ^ head
+ *
+ * p = past samples, convoluted with the (p)ositive side of sinc()
+ * n = future samples, convoluted with the (n)egative side of sinc()
+ * r = extra space for implementing the ring buffer
+ *
+ */
+
+ const size_t numCoefs = 2*halfNumCoefs;
+ const size_t stateSize = numCoefs * inChannelCount * 2;
+ mState = new int16_t[stateSize];
+ memset(mState, 0, sizeof(int16_t)*stateSize);
+ mImpulse = mState + (halfNumCoefs-1)*inChannelCount;
+ mRingFull = mImpulse + (numCoefs+1)*inChannelCount;
+}
+
+AudioResamplerSinc::~AudioResamplerSinc()
+{
+ delete [] mState;
+}
+
+void AudioResamplerSinc::init() {
+}
+
+void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider)
+{
+ mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
+
+ // select the appropriate resampler
+ switch (mChannelCount) {
+ case 1:
+ resample<1>(out, outFrameCount, provider);
+ break;
+ case 2:
+ resample<2>(out, outFrameCount, provider);
+ break;
+ }
+}
+
+
+template<int CHANNELS>
+void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider)
+{
+ int16_t* impulse = mImpulse;
+ uint32_t vRL = mVolumeRL;
+ size_t inputIndex = mInputIndex;
+ uint32_t phaseFraction = mPhaseFraction;
+ uint32_t phaseIncrement = mPhaseIncrement;
+ size_t outputIndex = 0;
+ size_t outputSampleCount = outFrameCount * 2;
+
+ AudioBufferProvider::Buffer& buffer(mBuffer);
+ while (outputIndex < outputSampleCount) {
+ // buffer is empty, fetch a new one
+ if (buffer.raw == NULL) {
+ provider->getNextBuffer(&buffer);
+ if (buffer.raw == NULL)
+ break;
+ const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+ if (phaseIndex) {
+ read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ }
+ }
+ int16_t *in = buffer.i16;
+ const size_t frameCount = buffer.frameCount;
+
+ // Always read-in the first samples from the input buffer
+ int16_t* head = impulse + halfNumCoefs*CHANNELS;
+ head[0] = in[inputIndex*CHANNELS + 0];
+ if (CHANNELS == 2)
+ head[1] = in[inputIndex*CHANNELS + 1];
+
+ // handle boundary case
+ int32_t l, r;
+ while (outputIndex < outputSampleCount) {
+ filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse);
+ out[outputIndex++] = mulRL(1, l, vRL);
+ out[outputIndex++] = mulRL(0, r, vRL);
+
+ phaseFraction += phaseIncrement;
+ const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+ if (phaseIndex) {
+ inputIndex += phaseIndex;
+ if (inputIndex >= frameCount)
+ break;
+ read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+ }
+ }
+
+ // if done with buffer, save samples
+ if (inputIndex >= frameCount) {
+ inputIndex -= frameCount;
+ provider->releaseBuffer(&buffer);
+ }
+ }
+
+ mImpulse = impulse;
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+}
+
+template<int CHANNELS>
+void AudioResamplerSinc::read(
+ int16_t*& impulse, uint32_t& phaseFraction,
+ int16_t const* in, size_t inputIndex)
+{
+ // read new samples into the ring buffer
+ while (phaseFraction >> kNumPhaseBits) {
+ const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+ impulse += CHANNELS;
+ phaseFraction -= 1LU<<kNumPhaseBits;
+ if (impulse >= mRingFull) {
+ const size_t stateSize = (halfNumCoefs*2)*CHANNELS;
+ memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
+ impulse -= stateSize;
+ }
+ int16_t* head = impulse + halfNumCoefs*CHANNELS;
+ head[0] = in[inputIndex*CHANNELS + 0];
+ if (CHANNELS == 2)
+ head[1] = in[inputIndex*CHANNELS + 1];
+ }
+}
+
+template<int CHANNELS>
+void AudioResamplerSinc::filterCoefficient(
+ int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples)
+{
+ // compute the index of the coefficient on the positive side and
+ // negative side
+ uint32_t indexP = (phase & cMask) >> cShift;
+ uint16_t lerpP = (phase & pMask) >> pShift;
+ uint32_t indexN = (-phase & cMask) >> cShift;
+ uint16_t lerpN = (-phase & pMask) >> pShift;
+
+ l = 0;
+ r = 0;
+ int32_t const* coefs = mFirCoefs;
+ int16_t const *sP = samples;
+ int16_t const *sN = samples+CHANNELS;
+ for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) {
+ interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+ interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+ interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+ interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+ interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ }
+}
+
+template<int CHANNELS>
+void AudioResamplerSinc::interpolate(
+ int32_t& l, int32_t& r,
+ int32_t const* coefs, int16_t lerp, int16_t const* samples)
+{
+ int32_t c0 = coefs[0];
+ int32_t c1 = coefs[1];
+ int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
+ if (CHANNELS == 2) {
+ uint32_t rl = *reinterpret_cast<uint32_t const*>(samples);
+ l = mulAddRL(1, rl, sinc, l);
+ r = mulAddRL(0, rl, sinc, r);
+ } else {
+ r = l = mulAdd(samples[0], sinc, l);
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/audioflinger/AudioResamplerSinc.h b/libs/audioflinger/AudioResamplerSinc.h
new file mode 100644
index 0000000..89b9577
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerSinc.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_AUDIO_RESAMPLER_SINC_H
+#define ANDROID_AUDIO_RESAMPLER_SINC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerSinc : public AudioResampler {
+public:
+ AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
+
+ ~AudioResamplerSinc();
+
+ virtual void resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+private:
+ void init();
+
+ template<int CHANNELS>
+ void resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+
+ template<int CHANNELS>
+ inline void filterCoefficient(
+ int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples);
+
+ template<int CHANNELS>
+ inline void interpolate(
+ int32_t& l, int32_t& r,
+ int32_t const* coefs, int16_t lerp, int16_t const* samples);
+
+ template<int CHANNELS>
+ inline void read(int16_t*& impulse, uint32_t& phaseFraction,
+ int16_t const* in, size_t inputIndex);
+
+ int16_t *mState;
+ int16_t *mImpulse;
+ int16_t *mRingFull;
+
+ int32_t const * mFirCoefs;
+ static const int32_t mFirCoefsDown[];
+ static const int32_t mFirCoefsUp[];
+
+ // ----------------------------------------------------------------------------
+ static const int32_t RESAMPLE_FIR_NUM_COEF = 8;
+ static const int32_t RESAMPLE_FIR_LERP_INT_BITS = 4;
+
+ // we have 16 coefs samples per zero-crossing
+ static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS;
+ static const int cShift = kNumPhaseBits - coefsBits;
+ static const uint32_t cMask = ((1<<coefsBits)-1) << cShift;
+
+ // and we use 15 bits to interpolate between these samples
+ // this cannot change because the mul below rely on it.
+ static const int pLerpBits = 15;
+ static const int pShift = kNumPhaseBits - coefsBits - pLerpBits;
+ static const uint32_t pMask = ((1<<pLerpBits)-1) << pShift;
+
+ // number of zero-crossing on each side
+ static const unsigned int halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_SINC_H*/
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
new file mode 100644
index 0000000..7741456
--- /dev/null
+++ b/libs/surfaceflinger/Android.mk
@@ -0,0 +1,47 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ clz.cpp.arm \
+ DisplayHardware/DisplayHardware.cpp \
+ DisplayHardware/DisplayHardwareBase.cpp \
+ GPUHardware/GPUHardware.cpp \
+ BootAnimation.cpp \
+ BlurFilter.cpp.arm \
+ CPUGauge.cpp \
+ Layer.cpp \
+ LayerBase.cpp \
+ LayerBuffer.cpp \
+ LayerBlur.cpp \
+ LayerBitmap.cpp \
+ LayerDim.cpp \
+ LayerScreenshot.cpp \
+ RFBServer.cpp \
+ SurfaceFlinger.cpp \
+ Tokenizer.cpp \
+ Transform.cpp \
+ VRamHeap.cpp
+
+
+# need "-lrt" on Linux simulator to pick up clock_gettime
+ifeq ($(TARGET_SIMULATOR),true)
+ ifeq ($(HOST_OS),linux)
+ LOCAL_LDLIBS += -lrt
+ endif
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libcutils \
+ libui \
+ libcorecg \
+ libsgl \
+ libpixelflinger \
+ libGLES_CM
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, corecg graphics)
+
+LOCAL_MODULE:= libsurfaceflinger
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/surfaceflinger/Barrier.h b/libs/surfaceflinger/Barrier.h
new file mode 100644
index 0000000..e2bcf6a
--- /dev/null
+++ b/libs/surfaceflinger/Barrier.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_BARRIER_H
+#define ANDROID_BARRIER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class Barrier
+{
+public:
+ inline Barrier() : state(CLOSED) { }
+ inline ~Barrier() { }
+ void open() {
+ // gcc memory barrier, this makes sure all memory writes
+ // have been issued by gcc. On an SMP system we'd need a real
+ // h/w barrier.
+ asm volatile ("":::"memory");
+ Mutex::Autolock _l(lock);
+ state = OPENED;
+ cv.broadcast();
+ }
+ void close() {
+ Mutex::Autolock _l(lock);
+ state = CLOSED;
+ }
+ void wait() const {
+ Mutex::Autolock _l(lock);
+ while (state == CLOSED) {
+ cv.wait(lock);
+ }
+ }
+private:
+ enum { OPENED, CLOSED };
+ mutable Mutex lock;
+ mutable Condition cv;
+ volatile int state;
+};
+
+}; // namespace android
+
+#endif // ANDROID_BARRIER_H
diff --git a/libs/surfaceflinger/BlurFilter.cpp b/libs/surfaceflinger/BlurFilter.cpp
new file mode 100644
index 0000000..5dc0ba0
--- /dev/null
+++ b/libs/surfaceflinger/BlurFilter.cpp
@@ -0,0 +1,326 @@
+/*
+**
+** Copyright 2006, 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.
+*/
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <utils/Errors.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "clz.h"
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) {
+ return v;
+}
+inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) {
+ return v;
+}
+#else
+inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) {
+ return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
+}
+inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) {
+ return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
+}
+#endif
+
+const int BLUR_DITHER_BITS = 6; // dither weights stored on 6 bits
+const int BLUR_DITHER_ORDER_SHIFT= 3;
+const int BLUR_DITHER_ORDER = (1<<BLUR_DITHER_ORDER_SHIFT);
+const int BLUR_DITHER_SIZE = BLUR_DITHER_ORDER * BLUR_DITHER_ORDER;
+const int BLUR_DITHER_MASK = BLUR_DITHER_ORDER-1;
+
+static const uint8_t gDitherMatrix[BLUR_DITHER_SIZE] = {
+ 0, 32, 8, 40, 2, 34, 10, 42,
+ 48, 16, 56, 24, 50, 18, 58, 26,
+ 12, 44, 4, 36, 14, 46, 6, 38,
+ 60, 28, 52, 20, 62, 30, 54, 22,
+ 3, 35, 11, 43, 1, 33, 9, 41,
+ 51, 19, 59, 27, 49, 17, 57, 25,
+ 15, 47, 7, 39, 13, 45, 5, 37,
+ 63, 31, 55, 23, 61, 29, 53, 21
+};
+
+
+template <int FACTOR = 0>
+struct BlurColor565
+{
+ typedef uint16_t type;
+ int r, g, b;
+ inline BlurColor565() { }
+ inline BlurColor565(uint16_t v) {
+ r = v >> 11;
+ g = (v >> 5) & 0x3E;
+ b = v & 0x1F;
+ }
+ inline void clear() { r=g=b=0; }
+ inline uint16_t to(int shift, int last, int dither) const {
+ int R = r;
+ int G = g;
+ int B = b;
+ if (UNLIKELY(last)) {
+ if (FACTOR>0) {
+ int L = (R+G+B)>>1;
+ R += (((L>>1) - R) * FACTOR) >> 8;
+ G += (((L ) - G) * FACTOR) >> 8;
+ B += (((L>>1) - B) * FACTOR) >> 8;
+ }
+ R += (dither << shift) >> BLUR_DITHER_BITS;
+ G += (dither << shift) >> BLUR_DITHER_BITS;
+ B += (dither << shift) >> BLUR_DITHER_BITS;
+ }
+ R >>= shift;
+ G >>= shift;
+ B >>= shift;
+ return (R<<11) | (G<<5) | B;
+ }
+ inline BlurColor565& operator += (const BlurColor565& rhs) {
+ r += rhs.r;
+ g += rhs.g;
+ b += rhs.b;
+ return *this;
+ }
+ inline BlurColor565& operator -= (const BlurColor565& rhs) {
+ r -= rhs.r;
+ g -= rhs.g;
+ b -= rhs.b;
+ return *this;
+ }
+};
+
+struct BlurGray565
+{
+ typedef uint16_t type;
+ int l;
+ inline BlurGray565() { }
+ inline BlurGray565(uint16_t v) {
+ int r = v >> 11;
+ int g = (v >> 5) & 0x3F;
+ int b = v & 0x1F;
+ l = (r + g + b + 1)>>1;
+ }
+ inline void clear() { l=0; }
+ inline uint16_t to(int shift, int last, int dither) const {
+ int L = l;
+ if (UNLIKELY(last)) {
+ L += (dither << shift) >> BLUR_DITHER_BITS;
+ }
+ L >>= shift;
+ return ((L>>1)<<11) | (L<<5) | (L>>1);
+ }
+ inline BlurGray565& operator += (const BlurGray565& rhs) {
+ l += rhs.l;
+ return *this;
+ }
+ inline BlurGray565& operator -= (const BlurGray565& rhs) {
+ l -= rhs.l;
+ return *this;
+ }
+};
+
+struct BlurGray8888
+{
+ typedef uint32_t type;
+ int l, a;
+ inline BlurGray8888() { }
+ inline BlurGray8888(uint32_t v) {
+ v = BLUR_RGBA_TO_HOST(v);
+ int r = v & 0xFF;
+ int g = (v >> 8) & 0xFF;
+ int b = (v >> 16) & 0xFF;
+ a = v >> 24;
+ l = r + g + g + b;
+ }
+ inline void clear() { l=a=0; }
+ inline uint32_t to(int shift, int last, int dither) const {
+ int L = l;
+ int A = a;
+ if (UNLIKELY(last)) {
+ L += (dither << (shift+2)) >> BLUR_DITHER_BITS;
+ A += (dither << shift) >> BLUR_DITHER_BITS;
+ }
+ L >>= (shift+2);
+ A >>= shift;
+ return BLUR_HOST_TO_RGBA((A<<24) | (L<<16) | (L<<8) | L);
+ }
+ inline BlurGray8888& operator += (const BlurGray8888& rhs) {
+ l += rhs.l;
+ a += rhs.a;
+ return *this;
+ }
+ inline BlurGray8888& operator -= (const BlurGray8888& rhs) {
+ l -= rhs.l;
+ a -= rhs.a;
+ return *this;
+ }
+};
+
+
+template<typename PIXEL>
+static status_t blurFilter(
+ GGLSurface const* dst,
+ GGLSurface const* src,
+ int kernelSizeUser,
+ int repeat)
+{
+ typedef typename PIXEL::type TYPE;
+
+ const int shift = 31 - clz(kernelSizeUser);
+ const int areaShift = shift*2;
+ const int kernelSize = 1<<shift;
+ const int kernelHalfSize = kernelSize/2;
+ const int mask = kernelSize-1;
+ const int w = src->width;
+ const int h = src->height;
+ const uint8_t* ditherMatrix = gDitherMatrix;
+
+ // we need a temporary buffer to store one line of blurred columns
+ // as well as kernelSize lines of source pixels organized as a ring buffer.
+ void* const temporary_buffer = malloc(
+ (w + kernelSize) * sizeof(PIXEL) +
+ (src->stride * kernelSize) * sizeof(TYPE));
+ if (!temporary_buffer)
+ return NO_MEMORY;
+
+ PIXEL* const sums = (PIXEL*)temporary_buffer;
+ TYPE* const scratch = (TYPE*)(sums + w + kernelSize);
+
+ // Apply the blur 'repeat' times, this is used to approximate
+ // gaussian blurs. 3 times gives good results.
+ for (int k=0 ; k<repeat ; k++) {
+
+ // Clear the columns sums for this round
+ memset(sums, 0, (w + kernelSize) * sizeof(PIXEL));
+ TYPE* head;
+ TYPE pixel;
+ PIXEL current;
+
+ // Since we're going to override the source data we need
+ // to copy it in a temporary buffer. Only kernelSize lines are
+ // required. But since we start in the center of the kernel,
+ // we only copy half of the data, and fill the rest with zeros
+ // (assuming black/transparent pixels).
+ memcpy( scratch + src->stride*kernelHalfSize,
+ src->data,
+ src->stride*kernelHalfSize*sizeof(TYPE));
+
+ // sum half of each column, because we assume the first half is
+ // zeros (black/transparent).
+ for (int y=0 ; y<kernelHalfSize ; y++) {
+ head = (TYPE*)src->data + y*src->stride;
+ for (int x=0 ; x<w ; x++)
+ sums[x] += PIXEL( *head++ );
+ }
+
+ for (int y=0 ; y<h ; y++) {
+ TYPE* fb = (TYPE*)dst->data + y*dst->stride;
+
+ // compute the dither matrix line
+ uint8_t const * ditherY = ditherMatrix
+ + (y & BLUR_DITHER_MASK)*BLUR_DITHER_ORDER;
+
+ // Horizontal blur pass on the columns sums
+ int count, dither, x=0;
+ PIXEL const * out= sums;
+ PIXEL const * in = sums;
+ current.clear();
+
+ count = kernelHalfSize;
+ do {
+ current += *in;
+ in++;
+ } while (--count);
+
+ count = kernelHalfSize;
+ do {
+ current += *in;
+ dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
+ *fb++ = current.to(areaShift, k==repeat-1, dither);
+ in++;
+ } while (--count);
+
+ count = w-kernelSize;
+ do {
+ current += *in;
+ current -= *out;
+ dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
+ *fb++ = current.to(areaShift, k==repeat-1, dither);
+ in++, out++;
+ } while (--count);
+
+ count = kernelHalfSize;
+ do {
+ current -= *out;
+ dither = *(ditherY + ((x++)&BLUR_DITHER_MASK));
+ *fb++ = current.to(areaShift, k==repeat-1, dither);
+ out++;
+ } while (--count);
+
+ // vertical blur pass, subtract the oldest line from each columns
+ // and add a new line. Subtract or add zeros at the top
+ // and bottom edges.
+ TYPE* const tail = scratch + (y & mask) * src->stride;
+ if (y >= kernelHalfSize) {
+ for (int x=0 ; x<w ; x++)
+ sums[x] -= PIXEL( tail[x] );
+ }
+ if (y < h-kernelSize) {
+ memcpy( tail,
+ (TYPE*)src->data + (y+kernelHalfSize)*src->stride,
+ src->stride*sizeof(TYPE));
+ for (int x=0 ; x<w ; x++)
+ sums[x] += PIXEL( tail[x] );
+ }
+ }
+
+ // The subsequent passes are always done in-place.
+ src = dst;
+ }
+
+ free(temporary_buffer);
+
+ return NO_ERROR;
+}
+
+template status_t blurFilter< BlurColor565<0x80> >(
+ GGLSurface const* dst,
+ GGLSurface const* src,
+ int kernelSizeUser,
+ int repeat);
+
+status_t blurFilter(
+ GGLSurface const* image,
+ int kernelSizeUser,
+ int repeat)
+{
+ return blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+}
+
+} // namespace android
+
+//err = blur< BlurColor565<0x80> >(dst, src, kernelSizeUser, repeat);
+//err = blur<BlurGray565>(dst, src, kernelSizeUser, repeat);
+//err = blur<BlurGray8888>(dst, src, kernelSizeUser, repeat);
diff --git a/libs/surfaceflinger/BlurFilter.h b/libs/surfaceflinger/BlurFilter.h
new file mode 100644
index 0000000..294db43
--- /dev/null
+++ b/libs/surfaceflinger/BlurFilter.h
@@ -0,0 +1,35 @@
+/*
+**
+** Copyright 2006, 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_BLUR_FILTER_H
+#define ANDROID_BLUR_FILTER_H
+
+#include <stdint.h>
+#include <utils/Errors.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+namespace android {
+
+status_t blurFilter(
+ GGLSurface const* image,
+ int kernelSizeUser,
+ int repeat);
+
+} // namespace android
+
+#endif // ANDROID_BLUR_FILTER_H
diff --git a/libs/surfaceflinger/BootAnimation.cpp b/libs/surfaceflinger/BootAnimation.cpp
new file mode 100644
index 0000000..e9e34c3
--- /dev/null
+++ b/libs/surfaceflinger/BootAnimation.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "BootAnimation"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <math.h>
+#include <fcntl.h>
+#include <utils/misc.h>
+
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/AssetManager.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/DisplayInfo.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+#include <ui/EGLNativeWindowSurface.h>
+
+#include <graphics/SkBitmap.h>
+#include <graphics/SkImageDecoder.h>
+
+#include <GLES/egl.h>
+
+#include "BootAnimation.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer)
+: Thread(false)
+{
+ mSession = SurfaceComposerClient::clientForConnection(
+ composer->createConnection()->asBinder());
+}
+
+BootAnimation::~BootAnimation()
+{
+}
+
+void BootAnimation::onFirstRef()
+{
+ run("BootAnimation", PRIORITY_DISPLAY);
+}
+
+const sp<SurfaceComposerClient>& BootAnimation::session() const
+{
+ return mSession;
+}
+
+status_t BootAnimation::initTexture(
+ Texture* texture, AssetManager& assets, const char* name)
+{
+ Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
+ if (!asset) return NO_INIT;
+ SkBitmap bitmap;
+ SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
+ &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
+ asset->close();
+ delete asset;
+
+ // ensure we can call getPixels(). No need to call unlock, since the
+ // bitmap will go out of scope when we return from this method.
+ bitmap.lockPixels();
+
+ const int w = bitmap.width();
+ const int h = bitmap.height();
+ const void* p = bitmap.getPixels();
+
+ GLint crop[4] = { 0, h, w, -h };
+ texture->w = w;
+ texture->h = h;
+
+ glGenTextures(1, &texture->name);
+ glBindTexture(GL_TEXTURE_2D, texture->name);
+
+ switch(bitmap.getConfig()) {
+ case SkBitmap::kA8_Config:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0,
+ GL_ALPHA, GL_UNSIGNED_BYTE, p);
+ break;
+ case SkBitmap::kARGB_4444_Config:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, p);
+ break;
+ case SkBitmap::kARGB_8888_Config:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, p);
+ break;
+ case SkBitmap::kRGB_565_Config:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
+ break;
+ default:
+ break;
+ }
+
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ return NO_ERROR;
+}
+
+status_t BootAnimation::readyToRun()
+{
+ mAssets.addDefaultAssets();
+
+ DisplayInfo dinfo;
+ status_t status = session()->getDisplayInfo(0, &dinfo);
+ if (status)
+ return -1;
+
+ // create the native surface
+ sp<Surface> s = session()->createSurface(getpid(), 0,
+ dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
+ session()->openTransaction();
+ s->setLayer(0x40000000);
+ session()->closeTransaction();
+
+ // initialize opengl and egl
+ const EGLint attribs[] = {
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+ EGLint w, h, dummy;
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLContext context;
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(display, NULL, NULL);
+ eglChooseConfig(display, attribs, &config, 1, &numConfigs);
+
+ surface = eglCreateWindowSurface(
+ display, config, new EGLNativeWindowSurface(s), NULL);
+
+ context = eglCreateContext(display, config, NULL, NULL);
+ eglQuerySurface(display, surface, EGL_WIDTH, &w);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+ eglMakeCurrent(display, surface, surface, context);
+ mDisplay = display;
+ mContext = context;
+ mSurface = surface;
+ mWidth = w;
+ mHeight= h;
+ mFlingerSurface = s;
+
+ // initialize GL
+ glShadeModel(GL_FLAT);
+ glEnable(GL_DITHER);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_SCISSOR_TEST);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ return NO_ERROR;
+}
+
+void BootAnimation::requestExit()
+{
+ mBarrier.open();
+ Thread::requestExit();
+}
+
+bool BootAnimation::threadLoop()
+{
+ bool r = android();
+ eglMakeCurrent(mDisplay, 0, 0, 0);
+ eglDestroyContext(mDisplay, mContext);
+ eglDestroySurface(mDisplay, mSurface);
+ eglTerminate(mDisplay);
+ return r;
+}
+
+
+bool BootAnimation::android()
+{
+ initTexture(&mAndroid[0], mAssets, "images/android_320x480.png");
+ initTexture(&mAndroid[1], mAssets, "images/boot_robot.png");
+ initTexture(&mAndroid[2], mAssets, "images/boot_robot_glow.png");
+
+ // erase screen
+ glDisable(GL_SCISSOR_TEST);
+ glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
+
+ // clear screen
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mDisplay, mSurface);
+
+ // wait ~1s
+ usleep(800000);
+
+ // fade in
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ const int steps = 8;
+ for (int i=1 ; i<steps ; i++) {
+ float fade = i / float(steps);
+ glColor4f(1, 1, 1, fade*fade);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
+ eglSwapBuffers(mDisplay, mSurface);
+ }
+
+ // draw last frame
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glDisable(GL_BLEND);
+ glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
+ eglSwapBuffers(mDisplay, mSurface);
+
+
+ // update rect for the robot
+ const int x = mWidth - mAndroid[1].w - 33;
+ const int y = (mHeight - mAndroid[1].h)/2 - 1;
+ const Rect updateRect(x, y, x+mAndroid[1].w, y+mAndroid[1].h);
+
+ // draw and update only what we need
+ eglSwapRectangleANDROID(mDisplay, mSurface,
+ updateRect.left, updateRect.top,
+ updateRect.width(), updateRect.height());
+
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(updateRect.left, mHeight-updateRect.bottom,
+ updateRect.width(), updateRect.height());
+
+ const nsecs_t startTime = systemTime();
+ do
+ {
+ // glow speed and shape
+ nsecs_t time = systemTime() - startTime;
+ float t = ((4.0f/(360.0f*us2ns(16667))) * time);
+ t = t - floorf(t);
+ const float fade = 0.5f + 0.5f*sinf(t * 2*M_PI);
+
+ // fade the glow in and out
+ glDisable(GL_BLEND);
+ glBindTexture(GL_TEXTURE_2D, mAndroid[2].name);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4f(fade, fade, fade, fade);
+ glDrawTexiOES(updateRect.left, mHeight-updateRect.bottom, 0,
+ updateRect.width(), updateRect.height());
+
+ // draw the robot
+ glEnable(GL_BLEND);
+ glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glDrawTexiOES(updateRect.left, mHeight-updateRect.bottom, 0,
+ updateRect.width(), updateRect.height());
+
+ // make sure sleep a lot to not take too much CPU away from
+ // the boot process. With this "glow" animation there is no
+ // visible difference.
+ usleep(16667*4);
+
+ eglSwapBuffers(mDisplay, mSurface);
+ } while (!exitPending());
+
+
+ glDeleteTextures(1, &mAndroid[0].name);
+ glDeleteTextures(1, &mAndroid[1].name);
+ glDeleteTextures(1, &mAndroid[2].name);
+ return false;
+}
+
+
+bool BootAnimation::cylon()
+{
+ // initialize the textures...
+ initTexture(&mLeftTrail, mAssets, "images/cylon_left.png");
+ initTexture(&mRightTrail, mAssets, "images/cylon_right.png");
+ initTexture(&mBrightSpot, mAssets, "images/cylon_dot.png");
+
+ int w = mWidth;
+ int h = mHeight;
+
+ const Point c(w/2 , h/2);
+ const GLint amplitude = 60;
+ const int scx = c.x - amplitude - mBrightSpot.w/2;
+ const int scy = c.y - mBrightSpot.h/2;
+ const int scw = amplitude*2 + mBrightSpot.w;
+ const int sch = mBrightSpot.h;
+ const Rect updateRect(scx, h-scy-sch, scx+scw, h-scy);
+
+ // erase screen
+ glDisable(GL_SCISSOR_TEST);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ eglSwapBuffers(mDisplay, mSurface);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ eglSwapRectangleANDROID(mDisplay, mSurface,
+ updateRect.left, updateRect.top,
+ updateRect.width(), updateRect.height());
+
+ glEnable(GL_SCISSOR_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+
+ // clear the screen to white
+ Point p;
+ float t = 0;
+ float alpha = 1.0f;
+ const nsecs_t startTime = systemTime();
+ nsecs_t fadeTime = 0;
+
+ do
+ {
+ // Set scissor in interesting area
+ glScissor(scx, scy, scw, sch);
+
+ // erase screen
+ glClear(GL_COLOR_BUFFER_BIT);
+
+
+ // compute wave
+ const float a = (t * 2*M_PI) - M_PI/2;
+ const float sn = sinf(a);
+ const float cs = cosf(a);
+ GLint x = GLint(amplitude * sn);
+ float derivative = cs;
+
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ if (derivative > 0) {
+ // vanishing trail...
+ p.x = (-amplitude + c.x) - mBrightSpot.w/2;
+ p.y = c.y-mLeftTrail.h/2;
+ float fade = 2.0f*(0.5f-t);
+ //fade *= fade;
+ glColor4f(fade, fade, fade, fade);
+ glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
+ glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
+
+ // trail...
+ p.x = (x + c.x) - (mRightTrail.w + mBrightSpot.w/2) + 16;
+ p.y = c.y-mRightTrail.h/2;
+ fade = t<0.25f ? t*4.0f : 1.0f;
+ fade *= fade;
+ glColor4f(fade, fade, fade, fade);
+ glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
+ glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
+ } else {
+ // vanishing trail..
+ p.x = (amplitude + c.x) - (mRightTrail.w + mBrightSpot.w/2) + 16;
+ p.y = c.y-mRightTrail.h/2;
+ float fade = 2.0f*(0.5f-(t-0.5f));
+ //fade *= fade;
+ glColor4f(fade, fade, fade, fade);
+ glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
+ glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
+
+ // trail...
+ p.x = (x + c.x) - mBrightSpot.w/2;
+ p.y = c.y-mLeftTrail.h/2;
+ fade = t<0.5f+0.25f ? (t-0.5f)*4.0f : 1.0f;
+ fade *= fade;
+ glColor4f(fade, fade, fade, fade);
+ glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
+ glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
+ }
+
+ const Point p( x + c.x-mBrightSpot.w/2, c.y-mBrightSpot.h/2 );
+ glBindTexture(GL_TEXTURE_2D, mBrightSpot.name);
+ glColor4f(1,0.5,0.5,1);
+ glDrawTexiOES(p.x, p.y, 0, mBrightSpot.w, mBrightSpot.h);
+
+ // update animation
+ nsecs_t time = systemTime() - startTime;
+ t = ((4.0f/(360.0f*us2ns(16667))) * time);
+ t = t - floorf(t);
+
+ eglSwapBuffers(mDisplay, mSurface);
+
+ if (exitPending()) {
+ if (fadeTime == 0) {
+ fadeTime = time;
+ }
+ time -= fadeTime;
+ alpha = 1.0f - ((float(time) * 6.0f) / float(s2ns(1)));
+
+ session()->openTransaction();
+ mFlingerSurface->setAlpha(alpha*alpha);
+ session()->closeTransaction();
+ }
+ } while (alpha > 0);
+
+ // cleanup
+ glFinish();
+ glDeleteTextures(1, &mLeftTrail.name);
+ glDeleteTextures(1, &mRightTrail.name);
+ glDeleteTextures(1, &mBrightSpot.name);
+ return false;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/BootAnimation.h b/libs/surfaceflinger/BootAnimation.h
new file mode 100644
index 0000000..a4a6d49
--- /dev/null
+++ b/libs/surfaceflinger/BootAnimation.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_BOOTANIMATION_H
+#define ANDROID_BOOTANIMATION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/AssetManager.h>
+
+#include <ui/ISurfaceComposer.h>
+#include <ui/SurfaceComposerClient.h>
+
+#include <GLES/egl.h>
+
+#include "Barrier.h"
+
+class SkBitmap;
+
+namespace android {
+
+class AssetManager;
+
+// ---------------------------------------------------------------------------
+
+class BootAnimation : public Thread
+{
+public:
+ BootAnimation(const sp<ISurfaceComposer>& composer);
+ virtual ~BootAnimation();
+
+ const sp<SurfaceComposerClient>& session() const;
+ virtual void requestExit();
+
+private:
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+ struct Texture {
+ GLint w;
+ GLint h;
+ GLuint name;
+ };
+
+ status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
+ bool android();
+ bool cylon();
+
+ sp<SurfaceComposerClient> mSession;
+ AssetManager mAssets;
+ Texture mLeftTrail;
+ Texture mRightTrail;
+ Texture mBrightSpot;
+ Texture mAndroid[3];
+ int mWidth;
+ int mHeight;
+ EGLDisplay mDisplay;
+ EGLDisplay mContext;
+ EGLDisplay mSurface;
+ sp<Surface> mFlingerSurface;
+ Barrier mBarrier;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_BOOTANIMATION_H
diff --git a/libs/surfaceflinger/CPUGauge.cpp b/libs/surfaceflinger/CPUGauge.cpp
new file mode 100644
index 0000000..74a9270
--- /dev/null
+++ b/libs/surfaceflinger/CPUGauge.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "CPUGauge"
+
+#include <stdint.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <math.h>
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/DisplayInfo.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "CPUGauge.h"
+
+namespace android {
+
+CPUGauge::CPUGauge( const sp<ISurfaceComposer>& composer,
+ nsecs_t interval,
+ int clock,
+ int refclock)
+ : Thread(false),
+ mInterval(interval), mClock(clock), mRefClock(refclock),
+ mReferenceTime(0),
+ mReferenceWorkingTime(0), mCpuUsage(0),
+ mRefIdleTime(0), mIdleTime(0)
+{
+ mFd = fopen("/proc/stat", "r");
+ setvbuf(mFd, NULL, _IONBF, 0);
+
+ mSession = SurfaceComposerClient::clientForConnection(
+ composer->createConnection()->asBinder());
+}
+
+CPUGauge::~CPUGauge()
+{
+ fclose(mFd);
+}
+
+const sp<SurfaceComposerClient>& CPUGauge::session() const
+{
+ return mSession;
+}
+
+void CPUGauge::onFirstRef()
+{
+ run("CPU Gauge");
+}
+
+status_t CPUGauge::readyToRun()
+{
+ LOGI("Starting CPU gauge...");
+ return NO_ERROR;
+}
+
+bool CPUGauge::threadLoop()
+{
+ DisplayInfo dinfo;
+ session()->getDisplayInfo(0, &dinfo);
+ sp<Surface> s(session()->createSurface(getpid(), 0, dinfo.w, 4, PIXEL_FORMAT_OPAQUE));
+ session()->openTransaction();
+ s->setLayer(INT_MAX);
+ session()->closeTransaction();
+
+ static const GGLfixed colors[4][4] = {
+ { 0x00000, 0x10000, 0x00000, 0x10000 },
+ { 0x10000, 0x10000, 0x00000, 0x10000 },
+ { 0x10000, 0x00000, 0x00000, 0x10000 },
+ { 0x00000, 0x00000, 0x00000, 0x10000 },
+ };
+
+ GGLContext* gl;
+ gglInit(&gl);
+ gl->activeTexture(gl, 0);
+ gl->disable(gl, GGL_TEXTURE_2D);
+ gl->disable(gl, GGL_BLEND);
+
+ const int w = dinfo.w;
+
+ while(!exitPending())
+ {
+ mLock.lock();
+ const float cpuUsage = this->cpuUsage();
+ const float totalCpuUsage = 1.0f - idle();
+ mLock.unlock();
+
+ Surface::SurfaceInfo info;
+ s->lock(&info);
+ GGLSurface fb;
+ fb.version = sizeof(GGLSurface);
+ fb.width = info.w;
+ fb.height = info.h;
+ fb.stride = info.w;
+ fb.format = info.format;
+ fb.data = (GGLubyte*)info.bits;
+
+ gl->colorBuffer(gl, &fb);
+ gl->color4xv(gl, colors[3]);
+ gl->recti(gl, 0, 0, w, 4);
+ gl->color4xv(gl, colors[2]); // red
+ gl->recti(gl, 0, 0, int(totalCpuUsage*w), 2);
+ gl->color4xv(gl, colors[0]); // green
+ gl->recti(gl, 0, 2, int(cpuUsage*w), 4);
+
+ s->unlockAndPost();
+
+ usleep(ns2us(mInterval));
+ }
+
+ gglUninit(gl);
+ return false;
+}
+
+void CPUGauge::sample()
+{
+ if (mLock.tryLock() == NO_ERROR) {
+ const nsecs_t now = systemTime(mRefClock);
+ const nsecs_t referenceTime = now-mReferenceTime;
+ if (referenceTime >= mInterval) {
+ const float reftime = 1.0f / referenceTime;
+ const nsecs_t nowWorkingTime = systemTime(mClock);
+
+ char buf[256];
+ fgets(buf, 256, mFd);
+ rewind(mFd);
+ char *str = buf+5;
+ char const * const usermode = strsep(&str, " "); (void)usermode;
+ char const * const usernice = strsep(&str, " "); (void)usernice;
+ char const * const systemmode = strsep(&str, " ");(void)systemmode;
+ char const * const idle = strsep(&str, " ");
+ const nsecs_t nowIdleTime = atoi(idle) * 10000000LL;
+ mIdleTime = float(nowIdleTime - mRefIdleTime) * reftime;
+ mRefIdleTime = nowIdleTime;
+
+ const nsecs_t workingTime = nowWorkingTime - mReferenceWorkingTime;
+ const float newCpuUsage = float(workingTime) * reftime;
+ if (mCpuUsage != newCpuUsage) {
+ mCpuUsage = newCpuUsage;
+ mReferenceWorkingTime = nowWorkingTime;
+ mReferenceTime = now;
+ }
+ }
+ mLock.unlock();
+ }
+}
+
+
+}; // namespace android
diff --git a/libs/surfaceflinger/CPUGauge.h b/libs/surfaceflinger/CPUGauge.h
new file mode 100644
index 0000000..5bb53c0
--- /dev/null
+++ b/libs/surfaceflinger/CPUGauge.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_CPUGAUGE_H
+#define ANDROID_CPUGAUGE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Timers.h>
+
+#include <ui/SurfaceComposerClient.h>
+
+namespace android {
+
+class CPUGauge : public Thread
+{
+public:
+ CPUGauge( const sp<ISurfaceComposer>& composer,
+ nsecs_t interval=s2ns(1),
+ int clock=SYSTEM_TIME_THREAD,
+ int refclock=SYSTEM_TIME_MONOTONIC);
+
+ ~CPUGauge();
+
+ const sp<SurfaceComposerClient>& session() const;
+
+ void sample();
+
+ inline float cpuUsage() const { return mCpuUsage; }
+ inline float idle() const { return mIdleTime; }
+
+private:
+ virtual void onFirstRef();
+ virtual status_t readyToRun();
+ virtual bool threadLoop();
+
+ Mutex mLock;
+
+ sp<SurfaceComposerClient> mSession;
+
+ const nsecs_t mInterval;
+ const int mClock;
+ const int mRefClock;
+
+ nsecs_t mReferenceTime;
+ nsecs_t mReferenceWorkingTime;
+ float mCpuUsage;
+ nsecs_t mRefIdleTime;
+ float mIdleTime;
+ FILE* mFd;
+};
+
+
+}; // namespace android
+
+#endif // ANDROID_CPUGAUGE_H
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
new file mode 100644
index 0000000..5dd9446
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <GLES/egl.h>
+
+#include <utils/Log.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "DisplayHardware/DisplayHardware.h"
+#include "ui/BlitHardware.h"
+
+using namespace android;
+
+static __attribute__((noinline))
+const char *egl_strerror(EGLint err)
+{
+ switch (err){
+ case EGL_SUCCESS: return "EGL_SUCCESS";
+ case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
+ case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
+ case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
+ case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
+ case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
+ case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
+ default: return "UNKNOWN";
+ }
+}
+
+static __attribute__((noinline))
+void checkGLErrors()
+{
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR)
+ LOGE("GL error 0x%04x", int(error));
+}
+
+static __attribute__((noinline))
+void checkEGLErrors(const char* token)
+{
+ EGLint error = eglGetError();
+ // GLESonGL seems to be returning 0 when there is no errors?
+ if (error && error != EGL_SUCCESS)
+ LOGE("%s error 0x%04x (%s)",
+ token, int(error), egl_strerror(error));
+}
+
+
+/*
+ * Initialize the display to the specified values.
+ *
+ */
+
+DisplayHardware::DisplayHardware(
+ const sp<SurfaceFlinger>& flinger,
+ uint32_t dpy)
+ : DisplayHardwareBase(flinger, dpy)
+{
+ init(dpy);
+}
+
+DisplayHardware::~DisplayHardware()
+{
+ fini();
+}
+
+float DisplayHardware::getDpiX() const { return mDpiX; }
+float DisplayHardware::getDpiY() const { return mDpiY; }
+float DisplayHardware::getRefreshRate() const { return mRefreshRate; }
+
+int DisplayHardware::getWidth() const {
+ return mWidth;
+}
+int DisplayHardware::getHeight() const {
+ return mHeight;
+}
+PixelFormat DisplayHardware::getFormat() const {
+ return mFormat;
+}
+
+void DisplayHardware::init(uint32_t dpy)
+{
+ // initialize EGL
+ const EGLint attribs[] = {
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+ EGLint w, h, dummy;
+ EGLint numConfigs, n;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLContext context;
+ mFlags = 0;
+
+ // TODO: all the extensions below should be queried through
+ // eglGetProcAddress().
+
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(display, NULL, NULL);
+ eglGetConfigs(display, NULL, 0, &numConfigs);
+ eglChooseConfig(display, attribs, &config, 1, &n);
+
+ /*
+ * Gather EGL extensions
+ */
+
+ const char* const egl_extensions = eglQueryString(
+ display, EGL_EXTENSIONS);
+
+ const char* egl_extensions_config = egl_extensions;
+
+ if (strstr(egl_extensions, "EGL_ANDROID_query_string_config")) {
+ egl_extensions_config = eglQueryStringConfigANDROID(
+ display, config, EGL_EXTENSIONS);
+ }
+
+ LOGI("EGL informations:");
+ LOGI("# of configs : %d", numConfigs);
+ LOGI("vendor : %s", eglQueryString(display, EGL_VENDOR));
+ LOGI("version : %s", eglQueryString(display, EGL_VERSION));
+ LOGI("extensions: %s", egl_extensions);
+ LOGI("ext/config: %s", egl_extensions_config);
+ LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+
+ if (strstr(egl_extensions_config, "EGL_ANDROID_swap_rectangle")) {
+ mFlags |= SWAP_RECTANGLE_EXTENSION;
+ // TODO: get the real "update_on_demand" behavior
+ mFlags |= UPDATE_ON_DEMAND;
+ }
+ if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
+ if (dummy == EGL_SLOW_CONFIG)
+ mFlags |= SLOW_CONFIG;
+ }
+
+ /*
+ * Create our main surface
+ */
+
+ mDisplaySurface = new EGLDisplaySurface();
+
+ surface = eglCreateWindowSurface(display, config, mDisplaySurface.get(), NULL);
+ //checkEGLErrors("eglCreateDisplaySurfaceANDROID");
+
+ if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
+ if (dummy == EGL_BUFFER_PRESERVED) {
+ mFlags |= BUFFER_PRESERVED;
+ if (strstr(egl_extensions_config, "EGL_ANDROID_copy_front_to_back")) {
+ mFlags |= COPY_BACK_EXTENSION;
+ }
+ }
+ }
+
+ GLint value = EGL_UNKNOWN;
+ eglQuerySurface(display, surface, EGL_HORIZONTAL_RESOLUTION, &value);
+ if (value == EGL_UNKNOWN) {
+ mDpiX = 160.0f;
+ } else {
+ mDpiX = 25.4f * float(value)/EGL_DISPLAY_SCALING;
+ }
+ value = EGL_UNKNOWN;
+ eglQuerySurface(display, surface, EGL_VERTICAL_RESOLUTION, &value);
+ if (value == EGL_UNKNOWN) {
+ mDpiY = 160.0f;
+ } else {
+ mDpiY = 25.4f * float(value)/EGL_DISPLAY_SCALING;
+ }
+ mRefreshRate = 60.f; // TODO: get the real refresh rate
+
+ /*
+ * Create our OpenGL ES context
+ */
+
+ context = eglCreateContext(display, config, NULL, NULL);
+ //checkEGLErrors("eglCreateContext");
+
+ eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
+
+
+ /*
+ * Gather OpenGL ES extensions
+ */
+
+ eglMakeCurrent(display, surface, surface, context);
+ const char* const gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
+ LOGI("OpenGL informations:");
+ LOGI("vendor : %s", glGetString(GL_VENDOR));
+ LOGI("renderer : %s", glGetString(GL_RENDERER));
+ LOGI("version : %s", glGetString(GL_VERSION));
+ LOGI("extensions: %s", gl_extensions);
+
+ if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) {
+ mFlags |= NPOT_EXTENSION;
+ }
+ if (strstr(gl_extensions, "GL_OES_draw_texture")) {
+ mFlags |= DRAW_TEXTURE_EXTENSION;
+ }
+ if (strstr(gl_extensions, "GL_ANDROID_direct_texture")) {
+ mFlags |= DIRECT_TEXTURE;
+ }
+
+ // Unbind the context from this thread
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ mDisplay = display;
+ mConfig = config;
+ mSurface = surface;
+ mContext = context;
+ mFormat = GGL_PIXEL_FORMAT_RGB_565;
+
+ mBlitEngine = copybit_init();
+}
+
+/*
+ * Clean up. Throw out our local state.
+ *
+ * (It's entirely possible we'll never get here, since this is meant
+ * for real hardware, which doesn't restart.)
+ */
+
+void DisplayHardware::fini()
+{
+ eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglTerminate(mDisplay);
+ copybit_term(mBlitEngine);
+}
+
+void DisplayHardware::releaseScreen() const
+{
+ DisplayHardwareBase::releaseScreen();
+}
+
+void DisplayHardware::acquireScreen() const
+{
+ DisplayHardwareBase::acquireScreen();
+}
+
+void DisplayHardware::getDisplaySurface(copybit_image_t* img) const
+{
+ img->w = mDisplaySurface->stride;
+ img->h = mDisplaySurface->height;
+ img->format = mDisplaySurface->format;
+ img->offset = mDisplaySurface->offset;
+ img->base = (void*)mDisplaySurface->base;
+ img->fd = mDisplaySurface->fd;
+}
+
+void DisplayHardware::getDisplaySurface(GGLSurface* fb) const
+{
+ fb->version= sizeof(GGLSurface);
+ fb->width = mDisplaySurface->width;
+ fb->height = mDisplaySurface->height;
+ fb->stride = mDisplaySurface->stride;
+ fb->format = mDisplaySurface->format;
+ fb->data = (GGLubyte*)mDisplaySurface->base + mDisplaySurface->offset;
+}
+
+uint32_t DisplayHardware::getPageFlipCount() const {
+ return mDisplaySurface->getPageFlipCount();
+}
+
+/*
+ * "Flip" the front and back buffers.
+ */
+
+void DisplayHardware::flip(const Region& dirty) const
+{
+ checkGLErrors();
+
+ EGLDisplay dpy = mDisplay;
+ EGLSurface surface = mSurface;
+
+ Region newDirty(dirty);
+ newDirty.andSelf(Rect(mWidth, mHeight));
+
+ if (mFlags & BUFFER_PRESERVED) {
+ const Region copyback(mDirty.subtract(newDirty));
+ mDirty = newDirty;
+ mDisplaySurface->copyFrontToBack(copyback);
+ }
+
+ if (mFlags & SWAP_RECTANGLE_EXTENSION) {
+ const Rect& b(newDirty.bounds());
+ eglSwapRectangleANDROID(
+ dpy, surface,
+ b.left, b.top, b.width(), b.height());
+ }
+
+ eglSwapBuffers(dpy, surface);
+ checkEGLErrors("eglSwapBuffers");
+
+ // for debugging
+ //glClearColor(1,0,0,0);
+ //glClear(GL_COLOR_BUFFER_BIT);
+}
+
+uint32_t DisplayHardware::getFlags() const
+{
+ return mFlags;
+}
+
+void DisplayHardware::makeCurrent() const
+{
+ eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
+}
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
new file mode 100644
index 0000000..299e236
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_DISPLAY_HARDWARE_H
+#define ANDROID_DISPLAY_HARDWARE_H
+
+#include <stdlib.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+
+#include <GLES/egl.h>
+
+#include "DisplayHardware/DisplayHardwareBase.h"
+
+struct copybit_image_t;
+struct copybit_t;
+
+namespace android {
+
+class EGLDisplaySurface;
+
+class DisplayHardware : public DisplayHardwareBase
+{
+public:
+ enum {
+ COPY_BACK_EXTENSION = 0x00000001,
+ DIRECT_TEXTURE = 0x00000002,
+ SWAP_RECTANGLE_EXTENSION= 0x00000004,
+ COPY_BITS_EXTENSION = 0x00000008,
+ NPOT_EXTENSION = 0x00000100,
+ DRAW_TEXTURE_EXTENSION = 0x00000200,
+ BUFFER_PRESERVED = 0x00010000,
+ UPDATE_ON_DEMAND = 0x00020000, // video driver feature
+ SLOW_CONFIG = 0x00040000, // software
+ };
+
+ DisplayHardware(
+ const sp<SurfaceFlinger>& flinger,
+ uint32_t displayIndex);
+
+ ~DisplayHardware();
+
+ void releaseScreen() const;
+ void acquireScreen() const;
+
+ // Flip the front and back buffers if the back buffer is "dirty". Might
+ // be instantaneous, might involve copying the frame buffer around.
+ void flip(const Region& dirty) const;
+
+ float getDpiX() const;
+ float getDpiY() const;
+ float getRefreshRate() const;
+ int getWidth() const;
+ int getHeight() const;
+ PixelFormat getFormat() const;
+ uint32_t getFlags() const;
+ void makeCurrent() const;
+
+ uint32_t getPageFlipCount() const;
+ void getDisplaySurface(copybit_image_t* img) const;
+ void getDisplaySurface(GGLSurface* fb) const;
+ EGLDisplay getEGLDisplay() const { return mDisplay; }
+ copybit_t* getBlitEngine() const { return mBlitEngine; }
+
+ Rect bounds() const {
+ return Rect(mWidth, mHeight);
+ }
+
+private:
+ void init(uint32_t displayIndex) __attribute__((noinline));
+ void fini() __attribute__((noinline));
+
+ EGLDisplay mDisplay;
+ EGLSurface mSurface;
+ EGLContext mContext;
+ EGLConfig mConfig;
+ float mDpiX;
+ float mDpiY;
+ float mRefreshRate;
+ int mWidth;
+ int mHeight;
+ PixelFormat mFormat;
+ uint32_t mFlags;
+ mutable Region mDirty;
+ sp<EGLDisplaySurface> mDisplaySurface;
+ copybit_t* mBlitEngine;
+};
+
+}; // namespace android
+
+#endif // ANDROID_DISPLAY_HARDWARE_H
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
new file mode 100644
index 0000000..90f6287
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+
+#include <linux/unistd.h>
+
+#include <utils/Log.h>
+
+#include "DisplayHardware/DisplayHardwareBase.h"
+#include "SurfaceFlinger.h"
+
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+namespace android {
+
+static char const * const kSleepFileName = "/sys/android_power/wait_for_fb_sleep";
+static char const * const kWakeFileName = "/sys/android_power/wait_for_fb_wake";
+
+// This dir exists if the framebuffer console is present, either built into
+// the kernel or loaded as a module.
+static char const * const kFbconSysDir = "/sys/class/graphics/fbcon";
+
+// ----------------------------------------------------------------------------
+
+DisplayHardwareBase::DisplayEventThreadBase::DisplayEventThreadBase(
+ const sp<SurfaceFlinger>& flinger)
+ : Thread(false), mFlinger(flinger) {
+}
+
+DisplayHardwareBase::DisplayEventThreadBase::~DisplayEventThreadBase() {
+}
+
+// ----------------------------------------------------------------------------
+
+DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
+ const sp<SurfaceFlinger>& flinger)
+ : DisplayEventThreadBase(flinger)
+{
+}
+
+DisplayHardwareBase::DisplayEventThread::~DisplayEventThread()
+{
+}
+
+bool DisplayHardwareBase::DisplayEventThread::threadLoop()
+{
+ int err = 0;
+ char buf;
+ int fd;
+
+ fd = open(kSleepFileName, O_RDONLY, 0);
+ do {
+ err = read(fd, &buf, 1);
+ } while (err < 0 && errno == EINTR);
+ close(fd);
+ LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
+ if (err >= 0) {
+ sp<SurfaceFlinger> flinger = mFlinger.promote();
+ LOGD("About to give-up screen, flinger = %p", flinger.get());
+ if (flinger != 0) {
+ mBarrier.close();
+ flinger->screenReleased(0);
+ mBarrier.wait();
+ }
+ }
+ fd = open(kWakeFileName, O_RDONLY, 0);
+ do {
+ err = read(fd, &buf, 1);
+ } while (err < 0 && errno == EINTR);
+ close(fd);
+ LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
+ if (err >= 0) {
+ sp<SurfaceFlinger> flinger = mFlinger.promote();
+ LOGD("Screen about to return, flinger = %p", flinger.get());
+ if (flinger != 0)
+ flinger->screenAcquired(0);
+ }
+ return true;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const
+{
+ mBarrier.open();
+ return NO_ERROR;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
+{
+ if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) {
+ LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
+{
+ return (access(kSleepFileName, R_OK) == 0 &&
+ access(kWakeFileName, R_OK) == 0 &&
+ access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT;
+}
+
+// ----------------------------------------------------------------------------
+
+pid_t DisplayHardwareBase::ConsoleManagerThread::sSignalCatcherPid = 0;
+
+DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread(
+ const sp<SurfaceFlinger>& flinger)
+ : DisplayEventThreadBase(flinger), consoleFd(-1)
+{
+ sSignalCatcherPid = 0;
+
+ // create a new console
+ char const * const ttydev = "/dev/tty0";
+ int fd = open(ttydev, O_RDWR | O_SYNC);
+ if (fd<0) {
+ LOGE("Can't open %s", ttydev);
+ this->consoleFd = -errno;
+ return;
+ }
+
+ // to make sure that we are in text mode
+ int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT);
+ if (res<0) {
+ LOGE("ioctl(%d, KDSETMODE, ...) failed, res %d (%s)",
+ fd, res, strerror(errno));
+ }
+
+ // get the current console
+ struct vt_stat vs;
+ res = ioctl(fd, VT_GETSTATE, &vs);
+ if (res<0) {
+ LOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)",
+ fd, res, strerror(errno));
+ this->consoleFd = -errno;
+ return;
+ }
+
+ // switch to console 7 (which is what X normaly uses)
+ int vtnum = 7;
+ do {
+ res = ioctl(fd, VT_ACTIVATE, (void*)vtnum);
+ } while(res < 0 && errno == EINTR);
+ if (res<0) {
+ LOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for %d",
+ fd, errno, strerror(errno), vtnum);
+ this->consoleFd = -errno;
+ return;
+ }
+
+ do {
+ res = ioctl(fd, VT_WAITACTIVE, (void*)vtnum);
+ } while(res < 0 && errno == EINTR);
+ if (res<0) {
+ LOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for %d",
+ fd, res, errno, strerror(errno), vtnum);
+ this->consoleFd = -errno;
+ return;
+ }
+
+ // open the new console
+ close(fd);
+ fd = open(ttydev, O_RDWR | O_SYNC);
+ if (fd<0) {
+ LOGE("Can't open new console %s", ttydev);
+ this->consoleFd = -errno;
+ return;
+ }
+
+ /* disable console line buffer, echo, ... */
+ struct termios ttyarg;
+ ioctl(fd, TCGETS , &ttyarg);
+ ttyarg.c_iflag = 0;
+ ttyarg.c_lflag = 0;
+ ioctl(fd, TCSETS , &ttyarg);
+
+ // set up signals so we're notified when the console changes
+ // we can't use SIGUSR1 because it's used by the java-vm
+ vm.mode = VT_PROCESS;
+ vm.waitv = 0;
+ vm.relsig = SIGUSR2;
+ vm.acqsig = SIGUNUSED;
+ vm.frsig = 0;
+
+ struct sigaction act;
+ sigemptyset(&act.sa_mask);
+ act.sa_handler = sigHandler;
+ act.sa_flags = 0;
+ sigaction(vm.relsig, &act, NULL);
+
+ sigemptyset(&act.sa_mask);
+ act.sa_handler = sigHandler;
+ act.sa_flags = 0;
+ sigaction(vm.acqsig, &act, NULL);
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, vm.relsig);
+ sigaddset(&mask, vm.acqsig);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ // switch to graphic mode
+ res = ioctl(fd, KDSETMODE, (void*)KD_GRAPHICS);
+ LOGW_IF(res<0,
+ "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res);
+
+ this->prev_vt_num = vs.v_active;
+ this->vt_num = vtnum;
+ this->consoleFd = fd;
+}
+
+DisplayHardwareBase::ConsoleManagerThread::~ConsoleManagerThread()
+{
+ if (this->consoleFd >= 0) {
+ int fd = this->consoleFd;
+ int prev_vt_num = this->prev_vt_num;
+ int res;
+ ioctl(fd, KDSETMODE, (void*)KD_TEXT);
+ do {
+ res = ioctl(fd, VT_ACTIVATE, (void*)prev_vt_num);
+ } while(res < 0 && errno == EINTR);
+ do {
+ res = ioctl(fd, VT_WAITACTIVE, (void*)prev_vt_num);
+ } while(res < 0 && errno == EINTR);
+ close(fd);
+ char const * const ttydev = "/dev/tty0";
+ fd = open(ttydev, O_RDWR | O_SYNC);
+ ioctl(fd, VT_DISALLOCATE, 0);
+ close(fd);
+ }
+}
+
+status_t DisplayHardwareBase::ConsoleManagerThread::readyToRun()
+{
+ if (this->consoleFd >= 0) {
+ sSignalCatcherPid = gettid();
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, vm.relsig);
+ sigaddset(&mask, vm.acqsig);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ int res = ioctl(this->consoleFd, VT_SETMODE, &vm);
+ if (res<0) {
+ LOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)",
+ this->consoleFd, errno, strerror(errno));
+ }
+ return NO_ERROR;
+ }
+ return this->consoleFd;
+}
+
+void DisplayHardwareBase::ConsoleManagerThread::requestExit()
+{
+ Thread::requestExit();
+ if (sSignalCatcherPid != 0) {
+ // wake the thread up
+ kill(sSignalCatcherPid, SIGINT);
+ // wait for it...
+ }
+}
+
+void DisplayHardwareBase::ConsoleManagerThread::sigHandler(int sig)
+{
+ // resend the signal to our signal catcher thread
+ LOGW("received signal %d in thread %d, resending to %d",
+ sig, gettid(), sSignalCatcherPid);
+
+ // we absolutely need the delays below because without them
+ // our main thread never gets a chance to handle the signal.
+ usleep(10000);
+ kill(sSignalCatcherPid, sig);
+ usleep(10000);
+}
+
+status_t DisplayHardwareBase::ConsoleManagerThread::releaseScreen() const
+{
+ int fd = this->consoleFd;
+ int err = ioctl(fd, VT_RELDISP, (void*)1);
+ LOGE_IF(err<0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)",
+ fd, errno, strerror(errno));
+ return (err<0) ? (-errno) : status_t(NO_ERROR);
+}
+
+bool DisplayHardwareBase::ConsoleManagerThread::threadLoop()
+{
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, vm.relsig);
+ sigaddset(&mask, vm.acqsig);
+
+ int sig = 0;
+ sigwait(&mask, &sig);
+
+ if (sig == vm.relsig) {
+ sp<SurfaceFlinger> flinger = mFlinger.promote();
+ //LOGD("About to give-up screen, flinger = %p", flinger.get());
+ if (flinger != 0)
+ flinger->screenReleased(0);
+ } else if (sig == vm.acqsig) {
+ sp<SurfaceFlinger> flinger = mFlinger.promote();
+ //LOGD("Screen about to return, flinger = %p", flinger.get());
+ if (flinger != 0)
+ flinger->screenAcquired(0);
+ }
+
+ return true;
+}
+
+status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const
+{
+ return consoleFd >= 0 ? NO_ERROR : NO_INIT;
+}
+
+// ----------------------------------------------------------------------------
+
+DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
+ uint32_t displayIndex)
+ : mCanDraw(true)
+{
+ mDisplayEventThread = new DisplayEventThread(flinger);
+ if (mDisplayEventThread->initCheck() != NO_ERROR) {
+ // fall-back on the console
+ mDisplayEventThread = new ConsoleManagerThread(flinger);
+ }
+}
+
+DisplayHardwareBase::~DisplayHardwareBase()
+{
+ // request exit
+ mDisplayEventThread->requestExitAndWait();
+}
+
+
+bool DisplayHardwareBase::canDraw() const
+{
+ return mCanDraw;
+}
+
+void DisplayHardwareBase::releaseScreen() const
+{
+ status_t err = mDisplayEventThread->releaseScreen();
+ if (err >= 0) {
+ //LOGD("screen given-up");
+ mCanDraw = false;
+ }
+}
+
+void DisplayHardwareBase::acquireScreen() const
+{
+ status_t err = mDisplayEventThread->acquireScreen();
+ if (err >= 0) {
+ //LOGD("screen returned");
+ mCanDraw = true;
+ }
+}
+
+}; // namespace android
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
new file mode 100644
index 0000000..8369bb8
--- /dev/null
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_DISPLAY_HARDWARE_BASE_H
+#define ANDROID_DISPLAY_HARDWARE_BASE_H
+
+#include <stdint.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include "Barrier.h"
+
+namespace android {
+
+class SurfaceFlinger;
+
+class DisplayHardwareBase
+{
+public:
+ DisplayHardwareBase(
+ const sp<SurfaceFlinger>& flinger,
+ uint32_t displayIndex);
+
+ ~DisplayHardwareBase();
+
+ // console managment
+ void releaseScreen() const;
+ void acquireScreen() const;
+ bool canDraw() const;
+
+private:
+ class DisplayEventThreadBase : public Thread {
+ protected:
+ wp<SurfaceFlinger> mFlinger;
+ public:
+ DisplayEventThreadBase(const sp<SurfaceFlinger>& flinger);
+ virtual ~DisplayEventThreadBase();
+ virtual void onFirstRef() {
+ run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
+ }
+ virtual status_t acquireScreen() const { return NO_ERROR; };
+ virtual status_t releaseScreen() const { return NO_ERROR; };
+ virtual status_t initCheck() const = 0;
+ };
+
+ class DisplayEventThread : public DisplayEventThreadBase
+ {
+ mutable Barrier mBarrier;
+ public:
+ DisplayEventThread(const sp<SurfaceFlinger>& flinger);
+ virtual ~DisplayEventThread();
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual status_t releaseScreen() const;
+ virtual status_t initCheck() const;
+ };
+
+ class ConsoleManagerThread : public DisplayEventThreadBase
+ {
+ int consoleFd;
+ int vt_num;
+ int prev_vt_num;
+ vt_mode vm;
+ static void sigHandler(int sig);
+ static pid_t sSignalCatcherPid;
+ public:
+ ConsoleManagerThread(const sp<SurfaceFlinger>& flinger);
+ virtual ~ConsoleManagerThread();
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void requestExit();
+ virtual status_t releaseScreen() const;
+ virtual status_t initCheck() const;
+ };
+
+ sp<DisplayEventThreadBase> mDisplayEventThread;
+ mutable int mCanDraw;
+};
+
+}; // namespace android
+
+#endif // ANDROID_DISPLAY_HARDWARE_BASE_H
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
new file mode 100644
index 0000000..b24a0f2
--- /dev/null
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
@@ -0,0 +1,557 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapPmem.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/IPCThreadState.h>
+#include <utils/StopWatch.h>
+
+#include <ui/ISurfaceComposer.h>
+
+#include "VRamHeap.h"
+#include "GPUHardware.h"
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+#include "GPUHardware/GPUHardware.h"
+
+/*
+ * This file manages the GPU if there is one. The intent is that this code
+ * needs to be different for every devce. Currently there is no abstraction,
+ * but in the long term, this code needs to be refactored so that API and
+ * implementation are separated.
+ *
+ * In this particular implementation, the GPU, its memory and register are
+ * managed here. Clients (such as OpenGL ES) request the GPU when then need
+ * it and are given a revokable heap containing the registers on memory.
+ *
+ */
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+// size reserved for GPU surfaces
+// 1200 KB fits exactly:
+// - two 320*480 16-bits double-buffered surfaces
+// - one 320*480 32-bits double-buffered surface
+// - one 320*240 16-bits double-bufferd, 4x anti-aliased surface
+static const int GPU_RESERVED_SIZE = 1200 * 1024;
+
+static const int GPUR_SIZE = 1 * 1024 * 1024;
+
+// ---------------------------------------------------------------------------
+
+/*
+ * GPUHandle is a special IMemory given to the client. It represents their
+ * handle to the GPU. Once they give it up, they loose GPU access, or if
+ * they explicitely revoke their acces through the binder code 1000.
+ * In both cases, this triggers a callback to revoke()
+ * first, and then actually powers down the chip.
+ *
+ * In the case of a misbehaving app, GPUHardware can ask for an immediate
+ * release of the GPU to the target process which should answer by calling
+ * code 1000 on GPUHandle. If it doesn't in a timely manner, the GPU will
+ * be revoked from under their feet.
+ *
+ * We should never hold a strong reference on GPUHandle. In practice this
+ * shouldn't be a big issue though because clients should use code 1000 and
+ * not rely on the dtor being called.
+ *
+ */
+
+class GPUHandle : public BnMemory
+{
+public:
+ GPUHandle(const sp<GPUHardware>& gpu, const sp<IMemoryHeap>& heap)
+ : mGPU(gpu), mClientHeap(heap) {
+ }
+ virtual ~GPUHandle();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ void setOwner(int owner) { mOwner = owner; }
+private:
+ void revokeNotification();
+ wp<GPUHardware> mGPU;
+ sp<IMemoryHeap> mClientHeap;
+ int mOwner;
+};
+
+GPUHandle::~GPUHandle() {
+ //LOGD("GPUHandle %p released, revoking GPU", this);
+ revokeNotification();
+}
+
+void GPUHandle::revokeNotification() {
+ sp<GPUHardware> hw(mGPU.promote());
+ if (hw != 0) {
+ hw->revoke(mOwner);
+ }
+}
+sp<IMemoryHeap> GPUHandle::getMemory(ssize_t* offset, size_t* size) const
+{
+ if (offset) *offset = 0;
+ if (size) *size = mClientHeap !=0 ? mClientHeap->virtualSize() : 0;
+ return mClientHeap;
+}
+status_t GPUHandle::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ status_t err = BnMemory::onTransact(code, data, reply, flags);
+ if (err == UNKNOWN_TRANSACTION && code == 1000) {
+ int callingPid = IPCThreadState::self()->getCallingPid();
+ //LOGD("pid %d voluntarily revoking gpu", callingPid);
+ if (callingPid == mOwner) {
+ revokeNotification();
+ // we've revoked the GPU, don't do it again later when we
+ // are destroyed.
+ mGPU.clear();
+ } else {
+ LOGW("%d revoking someone else's gpu? (owner=%d)",
+ callingPid, mOwner);
+ }
+ err = NO_ERROR;
+ }
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+
+class MemoryHeapRegs : public MemoryHeapPmem
+{
+public:
+ MemoryHeapRegs(const wp<GPUHardware>& gpu, const sp<MemoryHeapBase>& heap);
+ virtual ~MemoryHeapRegs();
+ sp<IMemory> mapMemory(size_t offset, size_t size);
+ virtual void revoke();
+private:
+ wp<GPUHardware> mGPU;
+};
+
+MemoryHeapRegs::MemoryHeapRegs(const wp<GPUHardware>& gpu, const sp<MemoryHeapBase>& heap)
+ : MemoryHeapPmem(heap), mGPU(gpu)
+{
+#if HAVE_ANDROID_OS
+ if (heapID()>0) {
+ /* this is where the GPU is powered on and the registers are mapped
+ * in the client */
+ //LOGD("ioctl(HW3D_GRANT_GPU)");
+ int err = ioctl(heapID(), HW3D_GRANT_GPU, base());
+ if (err) {
+ // it can happen if the master heap has been closed already
+ // in which case the GPU already is revoked (app crash for
+ // instance).
+ //LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
+ // strerror(errno), heapID(), base());
+ }
+ }
+#endif
+}
+
+MemoryHeapRegs::~MemoryHeapRegs()
+{
+}
+
+sp<IMemory> MemoryHeapRegs::mapMemory(size_t offset, size_t size)
+{
+ sp<GPUHandle> memory;
+ sp<GPUHardware> gpu = mGPU.promote();
+ if (heapID()>0 && gpu!=0)
+ memory = new GPUHandle(gpu, this);
+ return memory;
+}
+
+void MemoryHeapRegs::revoke()
+{
+ MemoryHeapPmem::revoke();
+#if HAVE_ANDROID_OS
+ if (heapID() > 0) {
+ //LOGD("ioctl(HW3D_REVOKE_GPU)");
+ int err = ioctl(heapID(), HW3D_REVOKE_GPU, base());
+ LOGE_IF(err, "HW3D_REVOKE_GPU failed (%s), mFD=%d, base=%p",
+ strerror(errno), heapID(), base());
+ }
+#endif
+}
+
+// ---------------------------------------------------------------------------
+
+class GPURegisterHeap : public PMemHeapInterface
+{
+public:
+ GPURegisterHeap(const sp<GPUHardware>& gpu)
+ : PMemHeapInterface("/dev/hw3d", GPUR_SIZE), mGPU(gpu)
+ {
+ }
+ virtual ~GPURegisterHeap() {
+ }
+ virtual sp<MemoryHeapPmem> createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new MemoryHeapRegs(mGPU, parentHeap);
+ }
+private:
+ wp<GPUHardware> mGPU;
+};
+
+/*****************************************************************************/
+
+GPUHardware::GPUHardware()
+ : mOwner(NO_OWNER)
+{
+}
+
+GPUHardware::~GPUHardware()
+{
+}
+
+sp<MemoryDealer> GPUHardware::request(int pid)
+{
+ sp<MemoryDealer> dealer;
+
+ LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
+
+ const int self_pid = getpid();
+ if (pid == self_pid) {
+ // can't use GPU from surfaceflinger's process
+ return dealer;
+ }
+
+ Mutex::Autolock _l(mLock);
+
+ if (mOwner != pid) {
+ // someone already has the gpu.
+ takeBackGPULocked();
+
+ // releaseLocked() should be a no-op most of the time
+ releaseLocked();
+
+ requestLocked();
+ }
+
+ dealer = mAllocator;
+ mOwner = pid;
+ if (dealer == 0) {
+ mOwner = SURFACE_FAILED;
+ }
+
+ LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
+ return dealer;
+}
+
+status_t GPUHardware::request(const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu)
+{
+ sp<IMemory> gpuHandle;
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int self_pid = getpid();
+
+ LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
+
+ if (pid == self_pid) {
+ // can't use GPU from surfaceflinger's process
+ return PERMISSION_DENIED;
+ }
+
+ Mutex::Autolock _l(mLock);
+ if (mOwner != pid) {
+ // someone already has the gpu.
+ takeBackGPULocked();
+
+ // releaseLocked() should be a no-op most of the time
+ releaseLocked();
+
+ requestLocked();
+ }
+
+ if (mHeapR.isValid()) {
+ gpu->count = 2;
+ gpu->regions[0].region = mHeap0.map(true);
+ gpu->regions[0].reserved = mHeap0.reserved;
+ gpu->regions[1].region = mHeap1.map(true);
+ gpu->regions[1].reserved = mHeap1.reserved;
+ gpu->regs = mHeapR.map();
+ if (gpu->regs != 0) {
+ static_cast< GPUHandle* >(gpu->regs.get())->setOwner(pid);
+ }
+ mCallback = callback;
+ mOwner = pid;
+ //LOGD("gpu core granted to pid %d, handle base=%p",
+ // mOwner, gpu->regs->pointer());
+ } else {
+ LOGW("couldn't grant gpu core to pid %d", pid);
+ }
+
+ return NO_ERROR;
+}
+
+void GPUHardware::revoke(int pid)
+{
+ Mutex::Autolock _l(mLock);
+ if (mOwner > 0) {
+ if (pid != mOwner) {
+ LOGW("GPU owned by %d, revoke from %d", mOwner, pid);
+ return;
+ }
+ //LOGD("revoke pid=%d, owner=%d", pid, mOwner);
+ // mOwner could be <0 if the same process acquired the GPU
+ // several times without releasing it first.
+ mCondition.signal();
+ releaseLocked(true);
+ }
+}
+
+status_t GPUHardware::friendlyRevoke()
+{
+ Mutex::Autolock _l(mLock);
+ takeBackGPULocked();
+ //LOGD("friendlyRevoke owner=%d", mOwner);
+ releaseLocked(true);
+ return NO_ERROR;
+}
+
+void GPUHardware::takeBackGPULocked()
+{
+ sp<IGPUCallback> callback = mCallback;
+ mCallback.clear();
+ if (callback != 0) {
+ callback->gpuLost(); // one-way
+ mCondition.waitRelative(mLock, ms2ns(250));
+ }
+}
+
+void GPUHardware::requestLocked()
+{
+ if (mAllocator == 0) {
+ GPUPart* part = 0;
+ sp<PMemHeap> surfaceHeap;
+ if (mHeap1.promote() == false) {
+ //LOGD("requestLocked: (1) creating new heap");
+ mHeap1.set(new PMemHeap("/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE));
+ }
+ if (mHeap1.isValid()) {
+ //LOGD("requestLocked: (1) heap is valid");
+ // NOTE: if GPU1 is available we use it for our surfaces
+ // this could be device specific, so we should do something more
+ // generic
+ surfaceHeap = static_cast< PMemHeap* >( mHeap1.getHeap().get() );
+ part = &mHeap1;
+ if (mHeap0.promote() == false) {
+ //LOGD("requestLocked: (0) creating new heap");
+ mHeap0.set(new PMemHeap("/dev/pmem_gpu0"));
+ }
+ } else {
+ //LOGD("requestLocked: (1) heap is not valid");
+ // No GPU1, use GPU0 only
+ if (mHeap0.promote() == false) {
+ //LOGD("requestLocked: (0) creating new heap");
+ mHeap0.set(new PMemHeap("/dev/pmem_gpu0", 0, GPU_RESERVED_SIZE));
+ }
+ if (mHeap0.isValid()) {
+ //LOGD("requestLocked: (0) heap is valid");
+ surfaceHeap = static_cast< PMemHeap* >( mHeap0.getHeap().get() );
+ part = &mHeap0;
+ }
+ }
+
+ if (mHeap0.isValid() || mHeap1.isValid()) {
+ if (mHeapR.promote() == false) {
+ //LOGD("requestLocked: (R) creating new register heap");
+ mHeapR.set(new GPURegisterHeap(this));
+ }
+ } else {
+ // we got nothing...
+ mHeap0.clear();
+ mHeap1.clear();
+ }
+
+ if (mHeapR.isValid() == false) {
+ //LOGD("requestLocked: (R) register heap not valid!!!");
+ // damn, couldn't get the gpu registers!
+ mHeap0.clear();
+ mHeap1.clear();
+ surfaceHeap.clear();
+ part = NULL;
+ }
+
+ if (surfaceHeap != 0 && part && part->getClientHeap()!=0) {
+ part->reserved = GPU_RESERVED_SIZE;
+ part->surface = true;
+ mAllocatorDebug = static_cast<SimpleBestFitAllocator*>(
+ surfaceHeap->getAllocator().get());
+ mAllocator = new MemoryDealer(
+ part->getClientHeap(),
+ surfaceHeap->getAllocator());
+ }
+ }
+}
+
+void GPUHardware::releaseLocked(bool dispose)
+{
+ /*
+ * if dispose is set, we will force the destruction of the heap,
+ * so it is given back to other systems, such as camera.
+ * Otherwise, we'll keep a weak pointer to it, this way we might be able
+ * to reuse it later if it's still around.
+ */
+ //LOGD("revoking gpu from pid %d", mOwner);
+ mOwner = NO_OWNER;
+ mAllocator.clear();
+ mCallback.clear();
+
+ /* if we're asked for a full revoke, dispose only of the heap
+ * we're not using for surface (as we might need it while drawing) */
+ mHeap0.release(mHeap0.surface ? false : dispose);
+ mHeap1.release(mHeap1.surface ? false : dispose);
+ mHeapR.release(false);
+}
+
+// ----------------------------------------------------------------------------
+// for debugging / testing ...
+
+sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
+ Mutex::Autolock _l(mLock);
+ sp<SimpleBestFitAllocator> allocator = mAllocatorDebug.promote();
+ return allocator;
+}
+
+void GPUHardware::unconditionalRevoke()
+{
+ Mutex::Autolock _l(mLock);
+ releaseLocked();
+}
+
+// ---------------------------------------------------------------------------
+
+
+GPUHardware::GPUPart::GPUPart()
+ : surface(false), reserved(0)
+{
+}
+
+GPUHardware::GPUPart::~GPUPart() {
+}
+
+const sp<PMemHeapInterface>& GPUHardware::GPUPart::getHeap() const {
+ return mHeap;
+}
+
+const sp<MemoryHeapPmem>& GPUHardware::GPUPart::getClientHeap() const {
+ return mClientHeap;
+}
+
+bool GPUHardware::GPUPart::isValid() const {
+ return ((mHeap!=0) && (mHeap->base() != MAP_FAILED));
+}
+
+void GPUHardware::GPUPart::clear()
+{
+ mHeap.clear();
+ mHeapWeak.clear();
+ mClientHeap.clear();
+ surface = false;
+}
+
+void GPUHardware::GPUPart::set(const sp<PMemHeapInterface>& heap)
+{
+ mHeapWeak.clear();
+ if (heap!=0 && heap->base() == MAP_FAILED) {
+ mHeap.clear();
+ mClientHeap.clear();
+ } else {
+ mHeap = heap;
+ mClientHeap = mHeap->createClientHeap();
+ }
+}
+
+bool GPUHardware::GPUPart::promote()
+{
+ //LOGD("mHeapWeak=%p, mHeap=%p", mHeapWeak.unsafe_get(), mHeap.get());
+ if (mHeap == 0) {
+ mHeap = mHeapWeak.promote();
+ }
+ if (mHeap != 0) {
+ if (mClientHeap != 0) {
+ mClientHeap->revoke();
+ }
+ mClientHeap = mHeap->createClientHeap();
+ } else {
+ surface = false;
+ }
+ return mHeap != 0;
+}
+
+sp<IMemory> GPUHardware::GPUPart::map(bool clear)
+{
+ sp<IMemory> memory;
+ if (mClientHeap != NULL) {
+ memory = mClientHeap->mapMemory(0, mHeap->virtualSize());
+ if (clear && memory!=0) {
+ //StopWatch sw("memset");
+ memset(memory->pointer(), 0, memory->size());
+ }
+ }
+ return memory;
+}
+
+void GPUHardware::GPUPart::release(bool dispose)
+{
+ if (mClientHeap != 0) {
+ mClientHeap->revoke();
+ mClientHeap.clear();
+ }
+ if (dispose) {
+ if (mHeapWeak!=0 && mHeap==0) {
+ mHeap = mHeapWeak.promote();
+ }
+ if (mHeap != 0) {
+ mHeap->dispose();
+ mHeapWeak.clear();
+ mHeap.clear();
+ } else {
+ surface = false;
+ }
+ } else {
+ if (mHeap != 0) {
+ mHeapWeak = mHeap;
+ mHeap.clear();
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.h b/libs/surfaceflinger/GPUHardware/GPUHardware.h
new file mode 100644
index 0000000..9a78b99
--- /dev/null
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GPU_HARDWARE_H
+#define ANDROID_GPU_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class GPUHardwareInterface : public RefBase
+{
+public:
+ virtual void revoke(int pid) = 0;
+ virtual sp<MemoryDealer> request(int pid) = 0;
+ virtual status_t request(const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu) = 0;
+
+ virtual status_t friendlyRevoke() = 0;
+ virtual void unconditionalRevoke() = 0;
+
+ // used for debugging only...
+ virtual sp<SimpleBestFitAllocator> getAllocator() const = 0;
+ virtual pid_t getOwner() const = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class IMemory;
+class MemoryHeapPmem;
+class PMemHeap;
+
+class GPUHardware : public GPUHardwareInterface
+{
+public:
+ GPUHardware();
+ virtual ~GPUHardware();
+
+ virtual void revoke(int pid);
+ virtual sp<MemoryDealer> request(int pid);
+ virtual status_t request(const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu);
+
+ virtual status_t friendlyRevoke();
+ virtual void unconditionalRevoke();
+
+ // used for debugging only...
+ virtual sp<SimpleBestFitAllocator> getAllocator() const;
+ virtual pid_t getOwner() const { return mOwner; }
+
+private:
+ enum {
+ NO_OWNER = -1,
+ SURFACE_FAILED = -2
+ };
+
+ void requestLocked();
+ void releaseLocked(bool dispose = false);
+ void takeBackGPULocked();
+
+ class GPUPart
+ {
+ public:
+ bool surface;
+ size_t reserved;
+ GPUPart();
+ ~GPUPart();
+ const sp<PMemHeapInterface>& getHeap() const;
+ const sp<MemoryHeapPmem>& getClientHeap() const;
+ bool isValid() const;
+ void clear();
+ void set(const sp<PMemHeapInterface>& heap);
+ bool promote();
+ sp<IMemory> map(bool clear = false);
+ void release(bool dispose);
+ private:
+ sp<PMemHeapInterface> mHeap;
+ wp<PMemHeapInterface> mHeapWeak;
+ sp<MemoryHeapPmem> mClientHeap;
+ };
+
+ mutable Mutex mLock;
+ GPUPart mHeap0; // SMI
+ GPUPart mHeap1; // EBI1
+ GPUPart mHeapR;
+ sp<MemoryDealer> mAllocator;
+ pid_t mOwner;
+ sp<IGPUCallback> mCallback;
+ wp<SimpleBestFitAllocator> mAllocatorDebug;
+
+ Condition mCondition;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GPU_HARDWARE_H
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
new file mode 100644
index 0000000..4f6bae1
--- /dev/null
+++ b/libs/surfaceflinger/Layer.cpp
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/properties.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/StopWatch.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/EGLDisplaySurface.h>
+
+#include "clz.h"
+#include "Layer.h"
+#include "LayerBitmap.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+#define DEBUG_RESIZE 0
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const uint32_t Layer::typeInfo = LayerBaseClient::typeInfo | 4;
+const char* const Layer::typeID = "Layer";
+
+// ---------------------------------------------------------------------------
+
+Layer::Layer(SurfaceFlinger* flinger, DisplayID display, Client* c, int32_t i)
+ : LayerBaseClient(flinger, display, c, i),
+ mSecure(false),
+ mFrontBufferIndex(1),
+ mNeedsBlending(true),
+ mResizeTransactionDone(false),
+ mTextureName(-1U), mTextureWidth(0), mTextureHeight(0)
+{
+ // no OpenGL operation is possible here, since we might not be
+ // in the OpenGL thread.
+}
+
+Layer::~Layer()
+{
+ client->free(clientIndex());
+ // this should always be called from the OpenGL thread
+ if (mTextureName != -1U) {
+ //glDeleteTextures(1, &mTextureName);
+ deletedTextures.add(mTextureName);
+ }
+}
+
+void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
+{
+ LayerBase::initStates(w,h,flags);
+
+ if (flags & ISurfaceComposer::eDestroyBackbuffer)
+ lcblk->flags |= eNoCopyBack;
+}
+
+sp<LayerBaseClient::Surface> Layer::getSurface() const
+{
+ return mSurface;
+}
+
+status_t Layer::setBuffers( Client* client,
+ uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags)
+{
+ PixelFormatInfo info;
+ status_t err = getPixelFormatInfo(format, &info);
+ if (err) return err;
+
+ // TODO: if eHardware is explicitely requested, we should fail
+ // on systems where we can't allocate memory that can be used with
+ // DMA engines for instance.
+
+ int memory_type = NATIVE_MEMORY_TYPE_PMEM;
+
+ // pixel-alignment. the final alignment may be bigger because
+ // we always force a 4-byte aligned bpr.
+ uint32_t alignment = 1;
+
+ const uint32_t mask = ISurfaceComposer::eGPU | ISurfaceComposer::eSecure;
+ if ((flags & mask) == ISurfaceComposer::eGPU) {
+ // don't grant GPU memory if GPU is disabled
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.hw", value, "1");
+ if (atoi(value) != 0) {
+ flags |= ISurfaceComposer::eHardware;
+ memory_type = NATIVE_MEMORY_TYPE_GPU;
+ // TODO: this value should come from the h/w
+ alignment = 8;
+ }
+ }
+
+ mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
+ mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
+ sp<MemoryDealer> allocators[2];
+ for (int i=0 ; i<2 ; i++) {
+ allocators[i] = client->createAllocator(memory_type);
+ if (allocators[i] == 0)
+ return NO_MEMORY;
+ mBuffers[i].init(allocators[i]);
+ int err = mBuffers[i].setBits(w, h, alignment, format, LayerBitmap::SECURE_BITS);
+ if (err != NO_ERROR)
+ return err;
+ mBuffers[i].clear(); // clear the bits for security
+ mBuffers[i].getInfo(lcblk->surface + i);
+ }
+
+ mSurface = new Surface(clientIndex(),
+ allocators[0]->getMemoryHeap(),
+ allocators[1]->getMemoryHeap(),
+ memory_type, mIdentity);
+
+ return NO_ERROR;
+}
+
+void Layer::reloadTexture(const Region& dirty)
+{
+ if (UNLIKELY(mTextureName == -1U)) {
+ // create the texture name the first time
+ // can't do that in the ctor, because it runs in another thread.
+ mTextureName = createTexture();
+ }
+ const GGLSurface& t(frontBuffer().surface());
+ loadTexture(dirty, mTextureName, t, mTextureWidth, mTextureHeight);
+}
+
+
+void Layer::onDraw(const Region& clip) const
+{
+ if (UNLIKELY(mTextureName == -1LU)) {
+ //LOGW("Layer %p doesn't have a texture", this);
+ // the texture has not been created yet, this Layer has
+ // in fact never been drawn into. this happens frequently with
+ // SurfaceView.
+ clearWithOpenGL(clip);
+ return;
+ }
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const LayerBitmap& front(frontBuffer());
+ const GGLSurface& t(front.surface());
+
+ status_t err = NO_ERROR;
+ const int can_use_copybit = canUseCopybit();
+ if (can_use_copybit) {
+ // StopWatch watch("copybit");
+ const State& s(drawingState());
+
+ copybit_image_t dst;
+ hw.getDisplaySurface(&dst);
+ const copybit_rect_t& drect
+ = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
+
+ copybit_image_t src;
+ front.getBitmapSurface(&src);
+ copybit_rect_t srect = { 0, 0, t.width, t.height };
+
+ copybit_t* copybit = mFlinger->getBlitEngine();
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ s.flags & ISurfaceComposer::eLayerDither ?
+ COPYBIT_ENABLE : COPYBIT_DISABLE);
+
+ region_iterator it(clip);
+ err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ }
+
+ if (!can_use_copybit || err) {
+ drawWithOpenGL(clip, mTextureName, t);
+ }
+}
+
+status_t Layer::reallocateBuffer(int32_t index, uint32_t w, uint32_t h)
+{
+ LOGD_IF(DEBUG_RESIZE,
+ "reallocateBuffer (layer=%p), "
+ "requested (%dx%d), "
+ "index=%d, (%dx%d), (%dx%d)",
+ this,
+ int(w), int(h),
+ int(index),
+ int(mBuffers[0].width()), int(mBuffers[0].height()),
+ int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+ status_t err = mBuffers[index].resize(w, h);
+ if (err == NO_ERROR) {
+ mBuffers[index].getInfo(lcblk->surface + index);
+ } else {
+ LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s",
+ index, w, h, err, strerror(err));
+ // XXX: what to do, what to do? We could try to free some
+ // hidden surfaces, instead of killing this one?
+ }
+ return err;
+}
+
+uint32_t Layer::doTransaction(uint32_t flags)
+{
+ const Layer::State& front(drawingState());
+ const Layer::State& temp(currentState());
+
+ // the test front.{w|h} != temp.{w|h} is not enough because it is possible
+ // that the size changed back to its previous value before the buffer
+ // was resized (in the eLocked case below), in which case, we still
+ // need to execute the code below so the clients have a chance to be
+ // release. resze() deals with the fact that the size can be the same.
+
+ /*
+ * Various states we could be in...
+
+ resize = state & eResizeRequested;
+ if (backbufferChanged) {
+ if (resize == 0) {
+ // ERROR, the resized buffer doesn't have its resize flag set
+ } else if (resize == mask) {
+ // ERROR one of the buffer has already been resized
+ } else if (resize == mask ^ eResizeRequested) {
+ // ERROR, the resized buffer doesn't have its resize flag set
+ } else if (resize == eResizeRequested) {
+ // OK, Normal case, proceed with resize
+ }
+ } else {
+ if (resize == 0) {
+ // OK, nothing special, do nothing
+ } else if (resize == mask) {
+ // restarted transaction, do nothing
+ } else if (resize == mask ^ eResizeRequested) {
+ // restarted transaction, do nothing
+ } else if (resize == eResizeRequested) {
+ // OK, size reset to previous value, proceed with resize
+ }
+ }
+ */
+
+ // Index of the back buffer
+ const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h);
+ const uint32_t state = lcblk->swapState;
+ const int32_t clientBackBufferIndex = layer_cblk_t::backBuffer(state);
+ const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
+ uint32_t resizeFlags = state & eResizeRequested;
+
+ if (UNLIKELY(backbufferChanged && (resizeFlags != eResizeRequested))) {
+ LOGE( "backbuffer size changed, but both resize flags are not set! "
+ "(layer=%p), state=%08x, requested (%dx%d), drawing (%d,%d), "
+ "index=%d, (%dx%d), (%dx%d)",
+ this, state,
+ int(temp.w), int(temp.h),
+ int(drawingState().w), int(drawingState().h),
+ int(clientBackBufferIndex),
+ int(mBuffers[0].width()), int(mBuffers[0].height()),
+ int(mBuffers[1].width()), int(mBuffers[1].height()));
+ // if we get there we're pretty screwed. the only reasonable
+ // thing to do is to pretend we should do the resize since
+ // backbufferChanged is set (this also will give a chance to
+ // client to get unblocked)
+ resizeFlags = eResizeRequested;
+ }
+
+ if (resizeFlags == eResizeRequested) {
+ // NOTE: asserting that clientBackBufferIndex!=mFrontBufferIndex
+ // here, would be wrong and misleading because by this point
+ // mFrontBufferIndex has not been updated yet.
+
+ LOGD_IF(DEBUG_RESIZE,
+ "resize (layer=%p), state=%08x, "
+ "requested (%dx%d), "
+ "drawing (%d,%d), "
+ "index=%d, (%dx%d), (%dx%d)",
+ this, state,
+ int(temp.w), int(temp.h),
+ int(drawingState().w), int(drawingState().h),
+ int(clientBackBufferIndex),
+ int(mBuffers[0].width()), int(mBuffers[0].height()),
+ int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+ if (state & eLocked) {
+ // if the buffer is locked, we can't resize anything because
+ // - the backbuffer is currently in use by the user
+ // - the front buffer is being shown
+ // We just act as if the transaction didn't happen and we
+ // reschedule it later...
+ flags |= eRestartTransaction;
+ } else {
+ // This buffer needs to be resized
+ status_t err =
+ resize(clientBackBufferIndex, temp.w, temp.h, "transaction");
+ if (err == NO_ERROR) {
+ const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
+ android_atomic_and(~mask, &(lcblk->swapState));
+ // since a buffer became availlable, we can let the client go...
+ mFlinger->scheduleBroadcast(client);
+ mResizeTransactionDone = true;
+
+ // we're being resized and there is a freeze display request,
+ // acquire a freeze lock, so that the screen stays put
+ // until we've redrawn at the new size; this is to avoid
+ // glitches upon orientation changes.
+ if (mFlinger->hasFreezeRequest()) {
+ // if the surface is hidden, don't try to acquire the
+ // freeze lock, since hidden surfaces may never redraw
+ if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
+ mFreezeLock = mFlinger->getFreezeLock();
+ }
+ }
+ }
+ }
+ }
+
+ if (temp.sequence != front.sequence) {
+ if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) {
+ // this surface is now hidden, so it shouldn't hold a freeze lock
+ // (it may never redraw, which is fine if it is hidden)
+ mFreezeLock.clear();
+ }
+ }
+
+ return LayerBase::doTransaction(flags);
+}
+
+status_t Layer::resize(
+ int32_t clientBackBufferIndex,
+ uint32_t width, uint32_t height,
+ const char* what)
+{
+ /*
+ * handle resize (backbuffer and frontbuffer reallocation)
+ */
+
+ const LayerBitmap& clientBackBuffer(mBuffers[clientBackBufferIndex]);
+
+ // if the new (transaction) size is != from the the backbuffer
+ // then we need to reallocate the backbuffer
+ bool backbufferChanged = (clientBackBuffer.width() != width) ||
+ (clientBackBuffer.height() != height);
+
+ LOGD_IF(!backbufferChanged,
+ "(%s) eResizeRequested (layer=%p), but size not changed: "
+ "requested (%dx%d), drawing (%d,%d), current (%d,%d),"
+ "state=%08lx, index=%d, (%dx%d), (%dx%d)",
+ what, this,
+ int(width), int(height),
+ int(drawingState().w), int(drawingState().h),
+ int(currentState().w), int(currentState().h),
+ long(lcblk->swapState),
+ int(clientBackBufferIndex),
+ int(mBuffers[0].width()), int(mBuffers[0].height()),
+ int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+ // this can happen when changing the size back and forth quickly
+ status_t err = NO_ERROR;
+ if (backbufferChanged) {
+ err = reallocateBuffer(clientBackBufferIndex, width, height);
+ }
+ if (UNLIKELY(err != NO_ERROR)) {
+ // couldn't reallocate the surface
+ android_atomic_write(eInvalidSurface, &lcblk->swapState);
+ memset(lcblk->surface+clientBackBufferIndex, 0, sizeof(surface_info_t));
+ }
+ return err;
+}
+
+void Layer::setSizeChanged(uint32_t w, uint32_t h)
+{
+ LOGD_IF(DEBUG_RESIZE,
+ "setSizeChanged w=%d, h=%d (old: w=%d, h=%d)",
+ w, h, mCurrentState.w, mCurrentState.h);
+ android_atomic_or(eResizeRequested, &(lcblk->swapState));
+}
+
+// ----------------------------------------------------------------------------
+// pageflip handling...
+// ----------------------------------------------------------------------------
+
+void Layer::lockPageFlip(bool& recomputeVisibleRegions)
+{
+ uint32_t state = android_atomic_or(eBusy, &(lcblk->swapState));
+ // preemptively block the client, because he might set
+ // eFlipRequested at any time and want to use this buffer
+ // for the next frame. This will be unset below if it
+ // turns out we didn't need it.
+
+ uint32_t mask = eInvalidSurface | eFlipRequested | eResizeRequested;
+ if (!(state & mask))
+ return;
+
+ if (UNLIKELY(state & eInvalidSurface)) {
+ // if eInvalidSurface is set, this means the surface
+ // became invalid during a transaction (NO_MEMORY for instance)
+ mFlinger->scheduleBroadcast(client);
+ return;
+ }
+
+ if (UNLIKELY(state & eFlipRequested)) {
+ uint32_t oldState;
+ mPostedDirtyRegion = post(&oldState, recomputeVisibleRegions);
+ if (oldState & eNextFlipPending) {
+ // Process another round (we know at least a buffer
+ // is ready for that client).
+ mFlinger->signalEvent();
+ }
+ }
+}
+
+Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
+{
+ // atomically swap buffers and (re)set eFlipRequested
+ int32_t oldValue, newValue;
+ layer_cblk_t * const lcblk = this->lcblk;
+ do {
+ oldValue = lcblk->swapState;
+ // get the current value
+
+ LOG_ASSERT(oldValue&eFlipRequested,
+ "eFlipRequested not set, yet we're flipping! (state=0x%08lx)",
+ long(oldValue));
+
+ newValue = (oldValue ^ eIndex);
+ // swap buffers
+
+ newValue &= ~(eFlipRequested | eNextFlipPending);
+ // clear eFlipRequested and eNextFlipPending
+
+ if (oldValue & eNextFlipPending)
+ newValue |= eFlipRequested;
+ // if eNextFlipPending is set (second buffer already has something
+ // in it) we need to reset eFlipRequested because the client
+ // might never do it
+
+ } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
+ *previousSate = oldValue;
+
+ const int32_t index = (newValue & eIndex) ^ 1;
+ mFrontBufferIndex = index;
+
+ // ... post the new front-buffer
+ Region dirty(lcblk->region + index);
+ dirty.andSelf(frontBuffer().bounds());
+
+ //LOGI("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
+ // oldValue, newValue, mFrontBufferIndex);
+ //dirty.dump("dirty");
+
+ if (UNLIKELY(oldValue & eResizeRequested)) {
+
+ LOGD_IF(DEBUG_RESIZE,
+ "post (layer=%p), state=%08x, "
+ "index=%d, (%dx%d), (%dx%d)",
+ this, newValue,
+ int(1-index),
+ int(mBuffers[0].width()), int(mBuffers[0].height()),
+ int(mBuffers[1].width()), int(mBuffers[1].height()));
+
+ // here, we just posted the surface and we have resolved
+ // the front/back buffer indices. The client is blocked, so
+ // it cannot start using the new backbuffer.
+
+ // If the backbuffer was resized in THIS round, we actually cannot
+ // resize the frontbuffer because it has *just* been drawn (and we
+ // would have nothing to draw). In this case we just skip the resize
+ // it'll happen after the next page flip or during the next
+ // transaction.
+
+ const uint32_t mask = (1-index) ? eResizeBuffer1 : eResizeBuffer0;
+ if (mResizeTransactionDone && (newValue & mask)) {
+ // Resize the layer's second buffer only if the transaction
+ // happened. It may not have happened yet if eResizeRequested
+ // was set immediately after the "transactionRequested" test,
+ // in which case the drawing state's size would be wrong.
+ mFreezeLock.clear();
+ const Layer::State& s(drawingState());
+ if (resize(1-index, s.w, s.h, "post") == NO_ERROR) {
+ do {
+ oldValue = lcblk->swapState;
+ if ((oldValue & eResizeRequested) == eResizeRequested) {
+ // ugh, another resize was requested since we processed
+ // the first buffer, don't free the client, and let
+ // the next transaction handle everything.
+ break;
+ }
+ newValue = oldValue & ~mask;
+ } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
+ }
+ mResizeTransactionDone = false;
+ recomputeVisibleRegions = true;
+ invalidate = true;
+ }
+ }
+
+ reloadTexture(dirty);
+
+ return dirty;
+}
+
+Point Layer::getPhysicalSize() const
+{
+ const LayerBitmap& front(frontBuffer());
+ return Point(front.width(), front.height());
+}
+
+void Layer::unlockPageFlip(
+ const Transform& planeTransform, Region& outDirtyRegion)
+{
+ Region dirtyRegion(mPostedDirtyRegion);
+ if (!dirtyRegion.isEmpty()) {
+ mPostedDirtyRegion.clear();
+ // The dirty region is given in the layer's coordinate space
+ // transform the dirty region by the surface's transformation
+ // and the global transformation.
+ const Layer::State& s(drawingState());
+ const Transform tr(planeTransform * s.transform);
+ dirtyRegion = tr.transform(dirtyRegion);
+
+ // At this point, the dirty region is in screen space.
+ // Make sure it's constrained by the visible region (which
+ // is in screen space as well).
+ dirtyRegion.andSelf(visibleRegionScreen);
+ outDirtyRegion.orSelf(dirtyRegion);
+
+ // client could be blocked, so signal them so they get a
+ // chance to reevaluate their condition.
+ mFlinger->scheduleBroadcast(client);
+ }
+}
+
+void Layer::finishPageFlip()
+{
+ if (LIKELY(!(lcblk->swapState & eInvalidSurface))) {
+ LOGE_IF(!(lcblk->swapState & eBusy),
+ "layer %p wasn't locked!", this);
+ android_atomic_and(~eBusy, &(lcblk->swapState));
+ }
+ mFlinger->scheduleBroadcast(client);
+}
+
+
+// ---------------------------------------------------------------------------
+
+
+}; // namespace android
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
new file mode 100644
index 0000000..2867f2b
--- /dev/null
+++ b/libs/surfaceflinger/Layer.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_LAYER_H
+#define ANDROID_LAYER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/PixelFormat.h>
+
+#include <private/ui/SharedState.h>
+#include <private/ui/LayerState.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "LayerBitmap.h"
+#include "LayerBase.h"
+#include "Transform.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Client;
+class LayerBitmap;
+class MemoryDealer;
+class FreezeLock;
+
+// ---------------------------------------------------------------------------
+
+class Layer : public LayerBaseClient
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ Layer(SurfaceFlinger* flinger, DisplayID display,
+ Client* c, int32_t i);
+
+ virtual ~Layer();
+
+ inline PixelFormat pixelFormat() const {
+ return frontBuffer().pixelFormat();
+ }
+
+ status_t setBuffers( Client* client,
+ uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags=0);
+
+ virtual void onDraw(const Region& clip) const;
+ virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
+ virtual void setSizeChanged(uint32_t w, uint32_t h);
+ virtual uint32_t doTransaction(uint32_t transactionFlags);
+ virtual Point getPhysicalSize() const;
+ virtual void lockPageFlip(bool& recomputeVisibleRegions);
+ virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+ virtual void finishPageFlip();
+ virtual bool needsBlending() const { return mNeedsBlending; }
+ virtual bool isSecure() const { return mSecure; }
+ virtual GLuint getTextureName() const { return mTextureName; }
+ virtual sp<Surface> getSurface() const;
+
+ const LayerBitmap& getBuffer(int i) const { return mBuffers[i]; }
+ LayerBitmap& getBuffer(int i) { return mBuffers[i]; }
+
+ // only for debugging
+ const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
+
+private:
+ inline const LayerBitmap&
+ frontBuffer() const { return getBuffer(mFrontBufferIndex); }
+ inline LayerBitmap&
+ frontBuffer() { return getBuffer(mFrontBufferIndex); }
+ inline const LayerBitmap&
+ backBuffer() const { return getBuffer(1-mFrontBufferIndex); }
+ inline LayerBitmap&
+ backBuffer() { return getBuffer(1-mFrontBufferIndex); }
+
+ void reloadTexture(const Region& dirty);
+
+ status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
+ Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
+ status_t reallocateBuffer(int32_t index, uint32_t w, uint32_t h);
+
+ sp<Surface> mSurface;
+
+ bool mSecure;
+ LayerBitmap mBuffers[2];
+ int32_t mFrontBufferIndex;
+ bool mNeedsBlending;
+ bool mResizeTransactionDone;
+ Region mPostedDirtyRegion;
+ sp<FreezeLock> mFreezeLock;
+
+ GLuint mTextureName;
+ GLuint mTextureWidth;
+ GLuint mTextureHeight;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_H
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
new file mode 100644
index 0000000..17c9f42
--- /dev/null
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -0,0 +1,700 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "clz.h"
+#include "LayerBase.h"
+#include "LayerBlur.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+// We don't honor the premultipliad alpha flags, which means that
+// premultiplied surface may be composed using a non-premultiplied
+// equation. We do this because it may be a lot faster on some hardware
+// The correct value is HONOR_PREMULTIPLIED_ALPHA = 1
+#define HONOR_PREMULTIPLIED_ALPHA 0
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerBase::typeInfo = 1;
+const char* const LayerBase::typeID = "LayerBase";
+
+const uint32_t LayerBaseClient::typeInfo = LayerBase::typeInfo | 2;
+const char* const LayerBaseClient::typeID = "LayerBaseClient";
+
+// ---------------------------------------------------------------------------
+
+Vector<GLuint> LayerBase::deletedTextures;
+
+int32_t LayerBase::sIdentity = 0;
+
+LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
+ : dpy(display), invalidate(false),
+ mFlinger(flinger),
+ mTransformed(false),
+ mOrientation(0),
+ mCanUseCopyBit(false),
+ mTransactionFlags(0),
+ mPremultipliedAlpha(true),
+ mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
+{
+ const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
+ mFlags = hw.getFlags();
+}
+
+LayerBase::~LayerBase()
+{
+}
+
+const GraphicPlane& LayerBase::graphicPlane(int dpy) const
+{
+ return mFlinger->graphicPlane(dpy);
+}
+
+GraphicPlane& LayerBase::graphicPlane(int dpy)
+{
+ return mFlinger->graphicPlane(dpy);
+}
+
+void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
+{
+ uint32_t layerFlags = 0;
+ if (flags & ISurfaceComposer::eHidden)
+ layerFlags = ISurfaceComposer::eLayerHidden;
+
+ if (flags & ISurfaceComposer::eNonPremultiplied)
+ mPremultipliedAlpha = false;
+
+ mCurrentState.z = 0;
+ mCurrentState.w = w;
+ mCurrentState.h = h;
+ mCurrentState.alpha = 0xFF;
+ mCurrentState.flags = layerFlags;
+ mCurrentState.sequence = 0;
+ mCurrentState.transform.set(0, 0);
+
+ // drawing state & current state are identical
+ mDrawingState = mCurrentState;
+}
+
+void LayerBase::commitTransaction(bool skipSize) {
+ const uint32_t w = mDrawingState.w;
+ const uint32_t h = mDrawingState.h;
+ mDrawingState = mCurrentState;
+ if (skipSize) {
+ mDrawingState.w = w;
+ mDrawingState.h = h;
+ }
+}
+bool LayerBase::requestTransaction() {
+ int32_t old = setTransactionFlags(eTransactionNeeded);
+ return ((old & eTransactionNeeded) == 0);
+}
+uint32_t LayerBase::getTransactionFlags(uint32_t flags) {
+ return android_atomic_and(~flags, &mTransactionFlags) & flags;
+}
+uint32_t LayerBase::setTransactionFlags(uint32_t flags) {
+ return android_atomic_or(flags, &mTransactionFlags);
+}
+
+void LayerBase::setSizeChanged(uint32_t w, uint32_t h) {
+}
+
+bool LayerBase::setPosition(int32_t x, int32_t y) {
+ if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.transform.set(x, y);
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setLayer(uint32_t z) {
+ if (mCurrentState.z == z)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.z = z;
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setSize(uint32_t w, uint32_t h) {
+ if (mCurrentState.w == w && mCurrentState.h == h)
+ return false;
+ setSizeChanged(w, h);
+ mCurrentState.w = w;
+ mCurrentState.h = h;
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setAlpha(uint8_t alpha) {
+ if (mCurrentState.alpha == alpha)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.alpha = alpha;
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) {
+ // TODO: check the matrix has changed
+ mCurrentState.sequence++;
+ mCurrentState.transform.set(
+ matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setTransparentRegionHint(const Region& transparent) {
+ // TODO: check the region has changed
+ mCurrentState.sequence++;
+ mCurrentState.transparentRegion = transparent;
+ requestTransaction();
+ return true;
+}
+bool LayerBase::setFlags(uint8_t flags, uint8_t mask) {
+ const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
+ if (mCurrentState.flags == newFlags)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.flags = newFlags;
+ requestTransaction();
+ return true;
+}
+
+Rect LayerBase::visibleBounds() const
+{
+ return mTransformedBounds;
+}
+
+void LayerBase::setVisibleRegion(const Region& visibleRegion) {
+ // always called from main thread
+ visibleRegionScreen = visibleRegion;
+}
+
+void LayerBase::setCoveredRegion(const Region& coveredRegion) {
+ // always called from main thread
+ coveredRegionScreen = coveredRegion;
+}
+
+uint32_t LayerBase::doTransaction(uint32_t flags)
+{
+ const Layer::State& front(drawingState());
+ const Layer::State& temp(currentState());
+
+ if (temp.sequence != front.sequence) {
+ // invalidate and recompute the visible regions if needed
+ flags |= eVisibleRegion;
+ this->invalidate = true;
+ }
+
+ // Commit the transaction
+ commitTransaction(flags & eRestartTransaction);
+ return flags;
+}
+
+Point LayerBase::getPhysicalSize() const
+{
+ const Layer::State& front(drawingState());
+ return Point(front.w, front.h);
+}
+
+void LayerBase::validateVisibility(const Transform& planeTransform)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(planeTransform * s.transform);
+ const bool transformed = tr.transformed();
+
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ tr.transform(mVertices[0], 0, 0);
+ tr.transform(mVertices[1], 0, h);
+ tr.transform(mVertices[2], w, h);
+ tr.transform(mVertices[3], w, 0);
+ if (UNLIKELY(transformed)) {
+ // NOTE: here we could also punt if we have too many rectangles
+ // in the transparent region
+ if (tr.preserveRects()) {
+ // transform the transparent region
+ transparentRegionScreen = tr.transform(s.transparentRegion);
+ } else {
+ // transformation too complex, can't do the transparent region
+ // optimization.
+ transparentRegionScreen.clear();
+ }
+ } else {
+ transparentRegionScreen = s.transparentRegion;
+ }
+
+ // cache a few things...
+ mOrientation = tr.getOrientation();
+ mTransformedBounds = tr.makeBounds(w, h);
+ mTransformed = transformed;
+ mLeft = tr.tx();
+ mTop = tr.ty();
+
+ // see if we can/should use 2D h/w with the new configuration
+ mCanUseCopyBit = false;
+ copybit_t* copybit = mFlinger->getBlitEngine();
+ if (copybit) {
+ const int step = copybit->get(copybit, COPYBIT_ROTATION_STEP_DEG);
+ const int scaleBits = copybit->get(copybit, COPYBIT_SCALING_FRAC_BITS);
+ mCanUseCopyBit = true;
+ if ((mOrientation < 0) && (step > 1)) {
+ // arbitrary orientations not supported
+ mCanUseCopyBit = false;
+ } else if ((mOrientation > 0) && (step > 90)) {
+ // 90 deg rotations not supported
+ mCanUseCopyBit = false;
+ } else if ((tr.getType() & SkMatrix::kScale_Mask) && (scaleBits < 12)) {
+ // arbitrary scaling not supported
+ mCanUseCopyBit = false;
+ }
+#if HONOR_PREMULTIPLIED_ALPHA
+ else if (needsBlending() && mPremultipliedAlpha) {
+ // pre-multiplied alpha not supported
+ mCanUseCopyBit = false;
+ }
+#endif
+ else {
+ // here, we determined we can use copybit
+ if (tr.getType() & SkMatrix::kScale_Mask) {
+ // and we have scaling
+ if (!transparentRegionScreen.isRect()) {
+ // we punt because blending is cheap (h/w) and the region is
+ // complex, which may causes artifacts when copying
+ // scaled content
+ transparentRegionScreen.clear();
+ }
+ }
+ }
+ }
+}
+
+void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
+{
+}
+
+void LayerBase::unlockPageFlip(
+ const Transform& planeTransform, Region& outDirtyRegion)
+{
+}
+
+void LayerBase::finishPageFlip()
+{
+}
+
+void LayerBase::drawRegion(const Region& reg) const
+{
+ Region::iterator iterator(reg);
+ if (iterator) {
+ Rect r;
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const int32_t fbWidth = hw.getWidth();
+ const int32_t fbHeight = hw.getHeight();
+ const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 },
+ { fbWidth, fbHeight }, { 0, fbHeight } };
+ glVertexPointer(2, GL_SHORT, 0, vertices);
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ }
+}
+
+void LayerBase::draw(const Region& inClip) const
+{
+ // invalidate the region we'll update
+ Region clip(inClip); // copy-on-write, so no-op most of the time
+
+ // Remove the transparent area from the clipping region
+ const State& s = drawingState();
+ if (LIKELY(!s.transparentRegion.isEmpty())) {
+ clip.subtract(transparentRegionScreen);
+ if (clip.isEmpty()) {
+ // usually this won't happen because this should be taken care of
+ // by SurfaceFlinger::computeVisibleRegions()
+ return;
+ }
+ }
+ onDraw(clip);
+
+ /*
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4x(0, 0x8000, 0, 0x10000);
+ drawRegion(transparentRegionScreen);
+ glDisable(GL_BLEND);
+ */
+}
+
+GLuint LayerBase::createTexture() const
+{
+ GLuint textureName = -1;
+ glGenTextures(1, &textureName);
+ glBindTexture(GL_TEXTURE_2D, textureName);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (mFlags & DisplayHardware::SLOW_CONFIG) {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ } else {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ return textureName;
+}
+
+void LayerBase::clearWithOpenGL(const Region& clip) const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t fbHeight = hw.getHeight();
+ glColor4x(0,0,0,0);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ Rect r;
+ Region::iterator iterator(clip);
+ if (iterator) {
+ glVertexPointer(2, GL_FIXED, 0, mVertices);
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ }
+}
+
+void LayerBase::drawWithOpenGL(const Region& clip,
+ GLint textureName, const GGLSurface& t) const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t fbHeight = hw.getHeight();
+ const State& s(drawingState());
+
+ // bind our texture
+ validateTexture(textureName);
+ glEnable(GL_TEXTURE_2D);
+
+ // Dithering...
+ if (s.flags & ISurfaceComposer::eLayerDither) {
+ glEnable(GL_DITHER);
+ } else {
+ glDisable(GL_DITHER);
+ }
+
+ if (UNLIKELY(s.alpha < 0xFF)) {
+ // We have an alpha-modulation. We need to modulate all
+ // texture components by alpha because we're always using
+ // premultiplied alpha.
+
+ // If the texture doesn't have an alpha channel we can
+ // use REPLACE and switch to non premultiplied-alpha
+ // blending (SRCA/ONE_MINUS_SRCA).
+
+ GLenum env, src;
+ if (needsBlending()) {
+ env = GL_MODULATE;
+ src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+ } else {
+ env = GL_REPLACE;
+ src = GL_SRC_ALPHA;
+ }
+ const GGLfixed alpha = (s.alpha << 16)/255;
+ glColor4x(alpha, alpha, alpha, alpha);
+ glEnable(GL_BLEND);
+ glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
+ } else {
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ if (needsBlending()) {
+ GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+ glEnable(GL_BLEND);
+ glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
+ } else {
+ glDisable(GL_BLEND);
+ }
+ }
+
+ if (UNLIKELY(transformed()
+ || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) ))
+ {
+ //StopWatch watch("GL transformed");
+ Region::iterator iterator(clip);
+ if (iterator) {
+ // always use high-quality filtering with fast configurations
+ bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG);
+ if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ const GLfixed texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 0x10000 },
+ { 0x10000, 0x10000 },
+ { 0x10000, 0 }
+ };
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
+ // find the smalest power-of-two that will accomodate our surface
+ GLuint tw = 1 << (31 - clz(t.width));
+ GLuint th = 1 << (31 - clz(t.height));
+ if (tw < t.width) tw <<= 1;
+ if (th < t.height) th <<= 1;
+ // this divide should be relatively fast because it's
+ // a power-of-two (optimized path in libgcc)
+ GLfloat ws = GLfloat(t.width) /tw;
+ GLfloat hs = GLfloat(t.height)/th;
+ glScalef(ws, hs, 1.0f);
+ }
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FIXED, 0, mVertices);
+ glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+
+ Rect r;
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+
+ if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+ } else {
+ Region::iterator iterator(clip);
+ if (iterator) {
+ Rect r;
+ GLint crop[4] = { 0, t.height, t.width, -t.height };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ int x = tx();
+ int y = ty();
+ y = fbHeight - (y + t.height);
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawTexiOES(x, y, 0, t.width, t.height);
+ }
+ }
+ }
+}
+
+void LayerBase::validateTexture(GLint textureName) const
+{
+ glBindTexture(GL_TEXTURE_2D, textureName);
+ // TODO: reload the texture if needed
+ // this is currently done in loadTexture() below
+}
+
+void LayerBase::loadTexture(const Region& dirty,
+ GLint textureName, const GGLSurface& t,
+ GLuint& textureWidth, GLuint& textureHeight) const
+{
+ // TODO: defer the actual texture reload until LayerBase::validateTexture
+ // is called.
+
+ uint32_t flags = mFlags;
+ glBindTexture(GL_TEXTURE_2D, textureName);
+
+ GLuint tw = t.width;
+ GLuint th = t.height;
+
+ /*
+ * In OpenGL ES we can't specify a stride with glTexImage2D (however,
+ * GL_UNPACK_ALIGNMENT is 4, which in essence allows a limited form of
+ * stride).
+ * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
+ * need to do something reasonable (here creating a bigger texture).
+ *
+ * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
+ *
+ * This situation doesn't happen often, but some h/w have a limitation
+ * for their framebuffer (eg: must be multiple of 8 pixels), and
+ * we need to take that into account when using these buffers as
+ * textures.
+ *
+ * This should never be a problem with POT textures
+ */
+
+ tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4);
+
+ /*
+ * round to POT if needed
+ */
+
+ GLuint texture_w = tw;
+ GLuint texture_h = th;
+ if (!(flags & DisplayHardware::NPOT_EXTENSION)) {
+ // find the smalest power-of-two that will accomodate our surface
+ texture_w = 1 << (31 - clz(t.width));
+ texture_h = 1 << (31 - clz(t.height));
+ if (texture_w < t.width) texture_w <<= 1;
+ if (texture_h < t.height) texture_h <<= 1;
+ if (texture_w != tw || texture_h != th) {
+ // we can't use DIRECT_TEXTURE since we changed the size
+ // of the texture
+ flags &= ~DisplayHardware::DIRECT_TEXTURE;
+ }
+ }
+
+ if (flags & DisplayHardware::DIRECT_TEXTURE) {
+ // here we're guaranteed that texture_{w|h} == t{w|h}
+ if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+ glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
+ GL_RGB, tw, th, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+ glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
+ GL_RGBA, tw, th, 0,
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
+ GL_RGBA, tw, th, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, t.data);
+ } else {
+ // oops, we don't handle this format, try the regular path
+ goto regular;
+ }
+ textureWidth = tw;
+ textureHeight = th;
+ } else {
+regular:
+ Rect bounds(dirty.bounds());
+ GLvoid* data = 0;
+ if (texture_w!=textureWidth || texture_w!=textureHeight) {
+ // texture size changed, we need to create a new one
+
+ if (!textureWidth || !textureHeight) {
+ // this is the first time, load the whole texture
+ if (texture_w==tw && texture_h==th) {
+ // we can do it one pass
+ data = t.data;
+ } else {
+ // we have to create the texture first because it
+ // doesn't match the size of the buffer
+ bounds.set(Rect(tw, th));
+ }
+ }
+
+ if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGB, tw, th, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, tw, th, 0,
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, tw, th, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+ } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
+ t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
+ // just show the Y plane of YUV buffers
+ data = t.data;
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_LUMINANCE, tw, th, 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+ }
+ textureWidth = tw;
+ textureHeight = th;
+ }
+ if (!data) {
+ if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
+ t.data + bounds.top*t.width*2);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
+ t.data + bounds.top*t.width*2);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGBA, GL_UNSIGNED_BYTE,
+ t.data + bounds.top*t.width*4);
+ }
+ }
+ }
+}
+
+bool LayerBase::canUseCopybit() const
+{
+ return mCanUseCopyBit;
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
+ Client* c, int32_t i)
+ : LayerBase(flinger, display), client(c),
+ lcblk( c ? &(c->ctrlblk->layers[i]) : 0 ),
+ mIndex(i)
+{
+ if (client) {
+ client->bindLayer(this, i);
+
+ // Initialize this layer's control block
+ memset(this->lcblk, 0, sizeof(layer_cblk_t));
+ this->lcblk->identity = mIdentity;
+ Region::writeEmpty(&(this->lcblk->region[0]), sizeof(flat_region_t));
+ Region::writeEmpty(&(this->lcblk->region[1]), sizeof(flat_region_t));
+ }
+}
+
+LayerBaseClient::~LayerBaseClient()
+{
+ if (client) {
+ client->free(mIndex);
+ }
+}
+
+int32_t LayerBaseClient::serverIndex() const {
+ if (client) {
+ return (client->cid<<16)|mIndex;
+ }
+ return 0xFFFF0000 | mIndex;
+}
+
+sp<LayerBaseClient::Surface> LayerBaseClient::getSurface() const
+{
+ return new Surface(clientIndex(), mIdentity);
+}
+
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
new file mode 100644
index 0000000..10c1bc1
--- /dev/null
+++ b/libs/surfaceflinger/LayerBase.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_LAYER_BASE_H
+#define ANDROID_LAYER_BASE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <private/ui/LayerState.h>
+
+#include <ui/Region.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include "Transform.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class SurfaceFlinger;
+class DisplayHardware;
+class GraphicPlane;
+class Client;
+
+// ---------------------------------------------------------------------------
+
+class LayerBase
+{
+ // poor man's dynamic_cast below
+ template<typename T>
+ struct getTypeInfoOfAnyType {
+ static uint32_t get() { return T::typeInfo; }
+ };
+
+ template<typename T>
+ struct getTypeInfoOfAnyType<T*> {
+ static uint32_t get() { return getTypeInfoOfAnyType<T>::get(); }
+ };
+
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ template<typename T>
+ static T dynamicCast(LayerBase* base) {
+ uint32_t mostDerivedInfo = base->getTypeInfo();
+ uint32_t castToInfo = getTypeInfoOfAnyType<T>::get();
+ if ((mostDerivedInfo & castToInfo) == castToInfo)
+ return static_cast<T>(base);
+ return 0;
+ }
+
+
+ static Vector<GLuint> deletedTextures;
+
+ LayerBase(SurfaceFlinger* flinger, DisplayID display);
+ virtual ~LayerBase();
+
+ DisplayID dpy;
+ mutable bool invalidate;
+ Region visibleRegionScreen;
+ Region transparentRegionScreen;
+ Region coveredRegionScreen;
+
+ struct State {
+ uint32_t w;
+ uint32_t h;
+ uint32_t z;
+ uint8_t alpha;
+ uint8_t flags;
+ uint8_t sequence; // changes when visible regions can change
+ uint8_t reserved;
+ uint32_t tint;
+ Transform transform;
+ Region transparentRegion;
+ };
+
+ // modify current state
+ bool setPosition(int32_t x, int32_t y);
+ bool setLayer(uint32_t z);
+ bool setSize(uint32_t w, uint32_t h);
+ bool setAlpha(uint8_t alpha);
+ bool setMatrix(const layer_state_t::matrix22_t& matrix);
+ bool setTransparentRegionHint(const Region& opaque);
+ bool setFlags(uint8_t flags, uint8_t mask);
+
+ void commitTransaction(bool skipSize);
+ bool requestTransaction();
+
+ uint32_t getTransactionFlags(uint32_t flags);
+ uint32_t setTransactionFlags(uint32_t flags);
+
+ void validateVisibility(const Transform& globalTransform);
+ Rect visibleBounds() const;
+ void drawRegion(const Region& reg) const;
+
+ virtual void draw(const Region& clip) const;
+ virtual void onDraw(const Region& clip) const = 0;
+ virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
+ virtual void setSizeChanged(uint32_t w, uint32_t h);
+ virtual uint32_t doTransaction(uint32_t transactionFlags);
+ virtual void setVisibleRegion(const Region& visibleRegion);
+ virtual void setCoveredRegion(const Region& coveredRegion);
+ virtual Point getPhysicalSize() const;
+ virtual void lockPageFlip(bool& recomputeVisibleRegions);
+ virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+ virtual void finishPageFlip();
+ virtual bool needsBlending() const { return false; }
+ virtual bool isSecure() const { return false; }
+
+ enum { // flags for doTransaction()
+ eVisibleRegion = 0x00000002,
+ eRestartTransaction = 0x00000008
+ };
+
+
+ inline const State& drawingState() const { return mDrawingState; }
+ inline const State& currentState() const { return mCurrentState; }
+ inline State& currentState() { return mCurrentState; }
+
+ static int compareCurrentStateZ(LayerBase*const* layerA, LayerBase*const* layerB) {
+ return layerA[0]->currentState().z - layerB[0]->currentState().z;
+ }
+
+ int32_t getOrientation() const { return mOrientation; }
+ bool transformed() const { return mTransformed; }
+ int tx() const { return mLeft; }
+ int ty() const { return mTop; }
+
+protected:
+ const GraphicPlane& graphicPlane(int dpy) const;
+ GraphicPlane& graphicPlane(int dpy);
+
+ GLuint createTexture() const;
+
+ void drawWithOpenGL(const Region& clip,
+ GLint textureName, const GGLSurface& surface) const;
+
+ void clearWithOpenGL(const Region& clip) const;
+
+ void loadTexture(const Region& dirty,
+ GLint textureName, const GGLSurface& t,
+ GLuint& textureWidth, GLuint& textureHeight) const;
+
+ bool canUseCopybit() const;
+
+
+ SurfaceFlinger* mFlinger;
+ uint32_t mFlags;
+
+ // cached during validateVisibility()
+ bool mTransformed;
+ int32_t mOrientation;
+ GLfixed mVertices[4][2];
+ Rect mTransformedBounds;
+ bool mCanUseCopyBit;
+ int mLeft;
+ int mTop;
+
+ // these are protected by an external lock
+ State mCurrentState;
+ State mDrawingState;
+ volatile int32_t mTransactionFlags;
+
+ // don't change, don't need a lock
+ bool mPremultipliedAlpha;
+
+ // only read
+ const uint32_t mIdentity;
+
+
+private:
+ void validateTexture(GLint textureName) const;
+ static int32_t sIdentity;
+};
+
+
+// ---------------------------------------------------------------------------
+
+class LayerBaseClient : public LayerBase
+{
+public:
+ class Surface;
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i);
+ virtual ~LayerBaseClient();
+
+
+ Client* const client;
+ layer_cblk_t* const lcblk;
+
+ inline int32_t clientIndex() const { return mIndex; }
+ int32_t serverIndex() const;
+
+ virtual sp<Surface> getSurface() const;
+
+ uint32_t getIdentity() const { return mIdentity; }
+
+ class Surface : public BnSurface
+ {
+ public:
+ Surface(SurfaceID id, int identity) {
+ mParams.token = id;
+ mParams.identity = identity;
+ mParams.type = 0;
+ }
+ Surface(SurfaceID id,
+ const sp<IMemoryHeap>& heap0,
+ const sp<IMemoryHeap>& heap1,
+ int memory_type, int identity)
+ {
+ mParams.token = id;
+ mParams.identity = identity;
+ mParams.type = memory_type;
+ mParams.heap[0] = heap0;
+ mParams.heap[1] = heap1;
+ }
+ virtual ~Surface() {
+ // TODO: We now have a point here were we can clean-up the
+ // client's mess.
+ // This is also where surface id should be recycled.
+ //LOGD("Surface %d, heaps={%p, %p}, type=%d destroyed",
+ // mId, mHeap[0].get(), mHeap[1].get(), mMemoryType);
+ }
+
+ virtual void getSurfaceData(
+ ISurfaceFlingerClient::surface_data_t* params) const {
+ *params = mParams;
+ }
+
+ virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
+ PixelFormat format, const sp<IMemoryHeap>& heap)
+ { return INVALID_OPERATION; }
+ virtual void postBuffer(ssize_t offset) { }
+ virtual void unregisterBuffers() { };
+
+ private:
+ ISurfaceFlingerClient::surface_data_t mParams;
+ };
+
+private:
+ int32_t mIndex;
+
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BASE_H
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
new file mode 100644
index 0000000..7c98857
--- /dev/null
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/memory.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/MemoryDealer.h>
+#include <utils/IMemory.h>
+#include <ui/PixelFormat.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include "LayerBitmap.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+LayerBitmap::LayerBitmap()
+ : mAllocFlags(0), mOffset(0), mSize(-1U), mAlignment(2)
+{
+ memset(&mSurface, 0, sizeof(mSurface));
+}
+
+LayerBitmap::~LayerBitmap()
+{
+ mSurface.data = 0;
+}
+
+status_t LayerBitmap::init(const sp<MemoryDealer>& allocator)
+{
+ if (mAllocator != NULL)
+ return BAD_VALUE;
+ mAllocator = allocator;
+ return NO_ERROR;
+}
+
+status_t LayerBitmap::setBits(uint32_t w, uint32_t h, uint32_t alignment,
+ PixelFormat format, uint32_t flags)
+{
+ const sp<MemoryDealer>& allocator(mAllocator);
+ if (allocator == NULL)
+ return NO_INIT;
+
+ if (UNLIKELY(w == mSurface.width && h == mSurface.height &&
+ format == mSurface.format))
+ { // same format and size, do nothing.
+ return NO_ERROR;
+ }
+
+ uint32_t allocFlags = MemoryDealer::PAGE_ALIGNED;
+ const uint32_t align = 4; // must match GL_UNPACK_ALIGNMENT
+ const uint32_t Bpp = bytesPerPixel(format);
+ uint32_t stride = (w + (alignment-1)) & ~(alignment-1);
+ stride = ((stride * Bpp + (align-1)) & ~(align-1)) / Bpp;
+ size_t size = stride * h * Bpp;
+ if (format == PIXEL_FORMAT_YCbCr_422_SP ||
+ format == PIXEL_FORMAT_YCbCr_420_SP) {
+ // in YUV planar, bitsPerPixel is for the Y plane
+ size = (size * bitsPerPixel(format)) / 8;
+ }
+
+ if (allocFlags & MemoryDealer::PAGE_ALIGNED) {
+ size_t pagesize = getpagesize();
+ size = (size + (pagesize-1)) & ~(pagesize-1);
+ }
+
+ /* FIXME: we should be able to have a h/v stride because the user of the
+ * surface might have stride limitation (for instance h/w codecs often do)
+ */
+ int32_t vstride = 0;
+
+ mAlignment = alignment;
+ mAllocFlags = allocFlags;
+ mOffset = 0;
+ if (mSize != size) {
+ // would be nice to have a reallocate() api
+ mBitsMemory.clear(); // free-memory
+ mBitsMemory = allocator->allocate(size, allocFlags);
+ mSize = size;
+ } else {
+ // don't erase memory if we didn't have to reallocate
+ flags &= ~SECURE_BITS;
+ }
+ if (mBitsMemory != 0) {
+ mOffset = mBitsMemory->offset();
+ mSurface.data = static_cast<GGLubyte*>(mBitsMemory->pointer());
+ mSurface.version = sizeof(GGLSurface);
+ mSurface.width = w;
+ mSurface.height = h;
+ mSurface.stride = stride;
+ mSurface.vstride = vstride;
+ mSurface.format = format;
+ if (flags & SECURE_BITS)
+ clear();
+ }
+
+ if (mBitsMemory==0 || mSurface.data==0) {
+ LOGE("not enough memory for layer bitmap size=%u", size);
+ allocator->dump("LayerBitmap");
+ mSurface.data = 0;
+ mSize = -1U;
+ return NO_MEMORY;
+ }
+ return NO_ERROR;
+}
+
+void LayerBitmap::clear()
+{
+ // NOTE: this memset should not be necessary, at least for
+ // opaque surface. However, for security reasons it's better to keep it
+ // (in the case of pmem, it's possible that the memory contains old
+ // data)
+ if (mSurface.data) {
+ memset(mSurface.data, 0, mSize);
+ //if (bytesPerPixel(mSurface.format) == 4) {
+ // android_memset32((uint32_t*)mSurface.data, 0xFF0000FF, mSize);
+ //} else {
+ // android_memset16((uint16_t*)mSurface.data, 0xF800, mSize);
+ //}
+ }
+}
+
+status_t LayerBitmap::getInfo(surface_info_t* info) const
+{
+ if (mSurface.data == 0) {
+ memset(info, 0, sizeof(surface_info_t));
+ info->bits_offset = NO_MEMORY;
+ return NO_MEMORY;
+ }
+ info->w = uint16_t(width());
+ info->h = uint16_t(height());
+ info->stride= uint16_t(stride());
+ info->bpr = uint16_t(stride() * bytesPerPixel(pixelFormat()));
+ info->format= uint8_t(pixelFormat());
+ info->flags = surface_info_t::eBufferDirty;
+ info->bits_offset = ssize_t(mOffset);
+ return NO_ERROR;
+}
+
+status_t LayerBitmap::resize(uint32_t w, uint32_t h)
+{
+ int err = setBits(w, h, mAlignment, pixelFormat(), SECURE_BITS);
+ return err;
+}
+
+size_t LayerBitmap::size() const
+{
+ return mSize;
+}
+
+void LayerBitmap::getBitmapSurface(copybit_image_t* img) const
+{
+ const sp<IMemoryHeap>& mh(getAllocator()->getMemoryHeap());
+ void* sbase = mh->base();
+ const GGLSurface& t(surface());
+ img->w = t.stride ?: t.width;
+ img->h = t.vstride ?: t.height;
+ img->format = t.format;
+ img->offset = intptr_t(t.data) - intptr_t(sbase);
+ img->base = sbase;
+ img->fd = mh->heapID();
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
new file mode 100644
index 0000000..4c2eb50
--- /dev/null
+++ b/libs/surfaceflinger/LayerBitmap.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_LAYER_BITMAP_H
+#define ANDROID_LAYER_BITMAP_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <private/ui/SharedState.h>
+#include <pixelflinger/pixelflinger.h>
+
+class copybit_image_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class IMemory;
+class MemoryDealer;
+class LayerBitmap;
+
+// ---------------------------------------------------------------------------
+
+class LayerBitmap
+{
+public:
+
+ enum {
+ // erase memory to ensure security when necessary
+ SECURE_BITS = 0x00000001
+ };
+
+ LayerBitmap();
+ ~LayerBitmap();
+ status_t init(const sp<MemoryDealer>& allocator);
+
+ status_t setBits(uint32_t w, uint32_t h, uint32_t alignment,
+ PixelFormat format, uint32_t flags = 0);
+ void clear();
+
+ status_t getInfo(surface_info_t* info) const;
+ status_t resize(uint32_t w, uint32_t h);
+
+ const GGLSurface& surface() const { return mSurface; }
+ Rect bounds() const { return Rect(width(), height()); }
+ uint32_t width() const { return surface().width; }
+ uint32_t height() const { return surface().height; }
+ uint32_t stride() const { return surface().stride; }
+ PixelFormat pixelFormat() const { return surface().format; }
+ void* serverBits() const { return surface().data; }
+ size_t size() const;
+ const sp<MemoryDealer>& getAllocator() const { return mAllocator; }
+ void getBitmapSurface(copybit_image_t* img) const;
+
+private:
+ LayerBitmap(const LayerBitmap& rhs);
+ LayerBitmap& operator = (const LayerBitmap& rhs);
+
+ sp<MemoryDealer> mAllocator;
+ sp<IMemory> mBitsMemory;
+ uint32_t mAllocFlags;
+ ssize_t mOffset;
+ GGLSurface mSurface;
+ size_t mSize;
+ uint32_t mAlignment;
+};
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BITMAP_H
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
new file mode 100644
index 0000000..192ceda
--- /dev/null
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "BlurFilter.h"
+#include "LayerBlur.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerBlur::typeInfo = LayerBaseClient::typeInfo | 8;
+const char* const LayerBlur::typeID = "LayerBlur";
+
+// ---------------------------------------------------------------------------
+
+LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i)
+ : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
+ mRefreshCache(true), mCacheAge(0), mTextureName(-1U)
+{
+}
+
+LayerBlur::~LayerBlur()
+{
+ if (mTextureName != -1U) {
+ //glDeleteTextures(1, &mTextureName);
+ deletedTextures.add(mTextureName);
+ }
+}
+
+void LayerBlur::setVisibleRegion(const Region& visibleRegion)
+{
+ LayerBaseClient::setVisibleRegion(visibleRegion);
+ if (visibleRegionScreen.isEmpty()) {
+ if (mTextureName != -1U) {
+ // We're not visible, free the texture up.
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures(1, &mTextureName);
+ mTextureName = -1U;
+ }
+ }
+}
+
+uint32_t LayerBlur::doTransaction(uint32_t flags)
+{
+ // we're doing a transaction, refresh the cache!
+ if (!mFlinger->isFrozen()) {
+ mRefreshCache = true;
+ mCacheDirty = true;
+ flags |= eVisibleRegion;
+ this->invalidate = true;
+ }
+ return LayerBase::doTransaction(flags);
+}
+
+void LayerBlur::unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion)
+{
+ // this code-path must be as tight as possible, it's called each time
+ // the screen is composited.
+ if (UNLIKELY(!visibleRegionScreen.isEmpty())) {
+ // if anything visible below us is invalidated, the cache becomes dirty
+ if (!mCacheDirty &&
+ !visibleRegionScreen.intersect(outDirtyRegion).isEmpty()) {
+ mCacheDirty = true;
+ }
+ if (mCacheDirty) {
+ if (!mFlinger->isFrozen()) {
+ // update everything below us that is visible
+ outDirtyRegion.orSelf(visibleRegionScreen);
+ nsecs_t now = systemTime();
+ if ((now - mCacheAge) >= ms2ns(500)) {
+ mCacheAge = now;
+ mRefreshCache = true;
+ mCacheDirty = false;
+ } else {
+ if (!mAutoRefreshPending) {
+ mFlinger->signalDelayedEvent(ms2ns(500));
+ mAutoRefreshPending = true;
+ }
+ }
+ }
+ }
+ }
+ LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);
+}
+
+void LayerBlur::onDraw(const Region& clip) const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t fbHeight = hw.getHeight();
+ int x = mTransformedBounds.left;
+ int y = mTransformedBounds.top;
+ int w = mTransformedBounds.width();
+ int h = mTransformedBounds.height();
+ GLint X = x;
+ GLint Y = fbHeight - (y + h);
+ if (X < 0) {
+ w += X;
+ X = 0;
+ }
+ if (Y < 0) {
+ h += Y;
+ Y = 0;
+ }
+ if (w<0 || h<0) {
+ // we're outside of the framebuffer
+ return;
+ }
+
+ if (mTextureName == -1U) {
+ // create the texture name the first time
+ // can't do that in the ctor, because it runs in another thread.
+ glGenTextures(1, &mTextureName);
+ }
+
+ Region::iterator iterator(clip);
+ if (iterator) {
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, mTextureName);
+
+ if (mRefreshCache) {
+ mRefreshCache = false;
+ mAutoRefreshPending = false;
+
+ uint16_t* const pixels = (uint16_t*)malloc(w*h*2);
+
+ // this reads the frame-buffer, so a h/w GL would have to
+ // finish() its rendering first. we don't want to do that
+ // too often.
+ glReadPixels(X, Y, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+
+ // blur that texture.
+ GGLSurface bl;
+ bl.version = sizeof(GGLSurface);
+ bl.width = w;
+ bl.height = h;
+ bl.stride = w;
+ bl.format = GGL_PIXEL_FORMAT_RGB_565;
+ bl.data = (GGLubyte*)pixels;
+ blurFilter(&bl, 8, 2);
+
+ // NOTE: this works only because we have POT. we'd have to round the
+ // texture size up, otherwise.
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+
+ free((void*)pixels);
+ }
+
+ const State& s = drawingState();
+ if (UNLIKELY(s.alpha < 0xFF)) {
+ const GGLfixed alpha = (s.alpha << 16)/255;
+ glColor4x(0, 0, 0, alpha);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ } else {
+ glDisable(GL_BLEND);
+ }
+
+ glDisable(GL_DITHER);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ if (UNLIKELY(transformed()
+ || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) )) {
+ // This is a very rare scenario.
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glScalef(1.0f/w, -1.0f/h, 1);
+ glTranslatef(-x, -y, 0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FIXED, 0, mVertices);
+ glTexCoordPointer(2, GL_FIXED, 0, mVertices);
+ Rect r;
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ } else {
+ Region::iterator iterator(clip);
+ if (iterator) {
+ // NOTE: this is marginally faster with the software gl, because
+ // glReadPixels() reads the fb bottom-to-top, however we'll
+ // skip all the jaccobian computations.
+ Rect r;
+ GLint crop[4] = { 0, 0, w, h };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ y = fbHeight - (y + h);
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawTexiOES(x, y, 0, w, h);
+ }
+ }
+ }
+ }
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
new file mode 100644
index 0000000..24b1156
--- /dev/null
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_LAYER_BLUR_H
+#define ANDROID_LAYER_BLUR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <private/ui/LayerState.h>
+
+#include <ui/Region.h>
+
+#include "LayerBase.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class LayerBlur : public LayerBaseClient
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerBlur(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i);
+ virtual ~LayerBlur();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual bool needsBlending() const { return true; }
+ virtual bool isSecure() const { return false; }
+
+ virtual uint32_t doTransaction(uint32_t flags);
+ virtual void setVisibleRegion(const Region& visibleRegion);
+ virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+
+private:
+ bool mCacheDirty;
+ mutable bool mRefreshCache;
+ mutable bool mAutoRefreshPending;
+ nsecs_t mCacheAge;
+ mutable GLuint mTextureName;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BLUR_H
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
new file mode 100644
index 0000000..d871fc3
--- /dev/null
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/StopWatch.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBuffer.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20;
+const char* const LayerBuffer::typeID = "LayerBuffer";
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i)
+ : LayerBaseClient(flinger, display, client, i),
+ mBuffer(0), mTextureName(-1U), mInvalidate(false), mNeedsBlending(false)
+{
+}
+
+LayerBuffer::~LayerBuffer()
+{
+ sp<SurfaceBuffer> s(getClientSurface());
+ if (s != 0) {
+ s->disown();
+ mClientSurface.clear();
+ }
+
+ // this should always be called from the OpenGL thread
+ if (mTextureName != -1U) {
+ //glDeleteTextures(1, &mTextureName);
+ deletedTextures.add(mTextureName);
+ }
+ // to help debugging we set those to zero
+ mWidth = mHeight = 0;
+}
+
+bool LayerBuffer::needsBlending() const
+{
+ Mutex::Autolock _l(mLock);
+ return mNeedsBlending;
+}
+
+void LayerBuffer::onDraw(const Region& clip) const
+{
+ sp<Buffer> buffer(getBuffer());
+ if (UNLIKELY(buffer == 0)) {
+ // nothing to do, we don't have a buffer
+ clearWithOpenGL(clip);
+ return;
+ }
+
+ status_t err = NO_ERROR;
+ NativeBuffer src(buffer->getBuffer());
+ const int can_use_copybit = canUseCopybit();
+
+ if (can_use_copybit) {
+ //StopWatch watch("MDP");
+
+ const int src_width = src.crop.r - src.crop.l;
+ const int src_height = src.crop.b - src.crop.t;
+ int W = mTransformedBounds.width();
+ int H = mTransformedBounds.height();
+ if (getOrientation() & Transform::ROT_90) {
+ int t(W); W=H; H=t;
+ }
+
+ /* With LayerBuffer, it is likely that we'll have to rescale the
+ * surface, because this is often used for video playback or
+ * camera-preview. Since we want these operation as fast as possible
+ * we make sure we can use the 2D H/W even if it doesn't support
+ * the requested scale factor, in which case we perform the scaling
+ * in several passes. */
+
+ copybit_t* copybit = mFlinger->getBlitEngine();
+ const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
+ const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
+
+ float xscale = 1.0f;
+ if (src_width > W*min) xscale = 1.0f / min;
+ else if (src_width*mag < W) xscale = mag;
+
+ float yscale = 1.0f;
+ if (src_height > H*min) yscale = 1.0f / min;
+ else if (src_height*mag < H) yscale = mag;
+
+ if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
+ //LOGD("MDP scaling hack w=%d, h=%d, ww=%d, wh=%d, xs=%f, ys=%f",
+ // src_width, src_height, W, H, xscale, yscale);
+
+ if (UNLIKELY(mTemporaryDealer == 0)) {
+ // allocate a memory-dealer for this the first time
+ mTemporaryDealer = mFlinger->getSurfaceHeapManager()
+ ->createHeap(NATIVE_MEMORY_TYPE_PMEM);
+ mTempBitmap.init(mTemporaryDealer);
+ }
+
+ const int tmp_w = floorf(src_width * xscale);
+ const int tmp_h = floorf(src_height * yscale);
+ err = mTempBitmap.setBits(tmp_w, tmp_h, 1, src.img.format);
+
+ if (LIKELY(err == NO_ERROR)) {
+ NativeBuffer tmp;
+ mTempBitmap.getBitmapSurface(&tmp.img);
+ tmp.crop.l = 0;
+ tmp.crop.t = 0;
+ tmp.crop.r = tmp.img.w;
+ tmp.crop.b = tmp.img.h;
+
+ region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+ err = copybit->stretch(copybit,
+ &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
+ src = tmp;
+ }
+ }
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ copybit_image_t dst;
+ hw.getDisplaySurface(&dst);
+ const copybit_rect_t& drect
+ = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
+ const State& s(drawingState());
+ region_iterator it(clip);
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ s.flags & ISurfaceComposer::eLayerDither ?
+ COPYBIT_ENABLE : COPYBIT_DISABLE);
+ err = copybit->stretch(copybit,
+ &dst, &src.img, &drect, &src.crop, &it);
+ }
+
+ if (!can_use_copybit || err) {
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ }
+ GLuint w = 0;
+ GLuint h = 0;
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.crop.r;
+ t.height = src.crop.b;
+ t.stride = src.img.w;
+ t.vstride= src.img.h;
+ t.format = src.img.format;
+ t.data = (GGLubyte*)(intptr_t(src.img.base) + src.img.offset);
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ drawWithOpenGL(clip, mTextureName, t);
+ }
+}
+
+void LayerBuffer::invalidateLocked()
+{
+ mInvalidate = true;
+ mFlinger->signalEvent();
+}
+
+void LayerBuffer::invalidate()
+{
+ Mutex::Autolock _l(mLock);
+ invalidateLocked();
+}
+
+void LayerBuffer::unlockPageFlip(const Transform& planeTransform,
+ Region& outDirtyRegion)
+{
+ Mutex::Autolock _l(mLock);
+ if (mInvalidate) {
+ mInvalidate = false;
+ outDirtyRegion.orSelf(visibleRegionScreen);
+ }
+}
+
+sp<LayerBuffer::SurfaceBuffer> LayerBuffer::getClientSurface() const
+{
+ Mutex::Autolock _l(mLock);
+ return mClientSurface.promote();
+}
+
+sp<LayerBaseClient::Surface> LayerBuffer::getSurface() const
+{
+ sp<SurfaceBuffer> s;
+ Mutex::Autolock _l(mLock);
+ s = mClientSurface.promote();
+ if (s == 0) {
+ s = new SurfaceBuffer(clientIndex(),
+ const_cast<LayerBuffer *>(this));
+ mClientSurface = s;
+ }
+ return s;
+}
+
+
+status_t LayerBuffer::registerBuffers(int w, int h, int hstride, int vstride,
+ PixelFormat format, const sp<IMemoryHeap>& memoryHeap)
+{
+ status_t err = (memoryHeap!=0 && memoryHeap->heapID() >= 0) ? NO_ERROR : NO_INIT;
+ if (err != NO_ERROR)
+ return err;
+
+ // TODO: validate format/parameters
+
+ Mutex::Autolock _l(mLock);
+ mHeap = memoryHeap;
+ mWidth = w;
+ mHeight = h;
+ mHStride = hstride;
+ mVStride = vstride;
+ mFormat = format;
+ PixelFormatInfo info;
+ getPixelFormatInfo(format, &info);
+ mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
+ return NO_ERROR;
+}
+
+void LayerBuffer::postBuffer(ssize_t offset)
+{
+ sp<IMemoryHeap> heap;
+ int w, h, hs, vs, f;
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ w = mWidth;
+ h = mHeight;
+ hs= mHStride;
+ vs= mVStride;
+ f = mFormat;
+ heap = mHeap;
+ }
+
+ sp<Buffer> buffer;
+ if (heap != 0) {
+ buffer = new Buffer(heap, offset, w, h, hs, vs, f);
+ if (buffer->getStatus() != NO_ERROR)
+ buffer.clear();
+ setBuffer(buffer);
+ invalidate();
+ }
+}
+
+void LayerBuffer::unregisterBuffers()
+{
+ Mutex::Autolock _l(mLock);
+ mHeap.clear();
+ mBuffer.clear();
+ invalidateLocked();
+}
+
+sp<LayerBuffer::Buffer> LayerBuffer::getBuffer() const
+{
+ Mutex::Autolock _l(mLock);
+ return mBuffer;
+}
+
+void LayerBuffer::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
+{
+ Mutex::Autolock _l(mLock);
+ mBuffer = buffer;
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::SurfaceBuffer::SurfaceBuffer(SurfaceID id, LayerBuffer* owner)
+ : LayerBaseClient::Surface(id, owner->getIdentity()), mOwner(owner)
+{
+}
+
+LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
+{
+ unregisterBuffers();
+ mOwner = 0;
+}
+
+status_t LayerBuffer::SurfaceBuffer::registerBuffers(
+ int w, int h, int hs, int vs,
+ PixelFormat format, const sp<IMemoryHeap>& heap)
+{
+ LayerBuffer* owner(getOwner());
+ if (owner)
+ return owner->registerBuffers(w, h, hs, vs, format, heap);
+ return NO_INIT;
+}
+
+void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset)
+{
+ LayerBuffer* owner(getOwner());
+ if (owner)
+ owner->postBuffer(offset);
+}
+
+void LayerBuffer::SurfaceBuffer::unregisterBuffers()
+{
+ LayerBuffer* owner(getOwner());
+ if (owner)
+ owner->unregisterBuffers();
+}
+
+void LayerBuffer::SurfaceBuffer::disown()
+{
+ Mutex::Autolock _l(mLock);
+ mOwner = 0;
+}
+
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::Buffer::Buffer(const sp<IMemoryHeap>& heap, ssize_t offset,
+ int w, int h, int hs, int vs, int f)
+ : mCount(0), mHeap(heap)
+{
+ NativeBuffer& src(mNativeBuffer);
+ src.crop.l = 0;
+ src.crop.t = 0;
+ src.crop.r = w;
+ src.crop.b = h;
+ src.img.w = hs ?: w;
+ src.img.h = vs ?: h;
+ src.img.format = f;
+ src.img.offset = offset;
+ src.img.base = heap->base();
+ src.img.fd = heap->heapID();
+ // FIXME: make sure this buffer lies within the heap, in which case, set
+ // mHeap to null
+}
+
+LayerBuffer::Buffer::~Buffer()
+{
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
new file mode 100644
index 0000000..ef473dd
--- /dev/null
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_LAYER_BUFFER_H
+#define ANDROID_LAYER_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/IMemory.h>
+#include <private/ui/LayerState.h>
+#include <GLES/eglnatives.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryDealer;
+class Region;
+
+class LayerBuffer : public LayerBaseClient
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i);
+ virtual ~LayerBuffer();
+
+ virtual bool needsBlending() const;
+
+ virtual sp<LayerBaseClient::Surface> getSurface() const;
+ virtual void onDraw(const Region& clip) const;
+ virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+
+ status_t registerBuffers(int w, int h, int hstride, int vstride,
+ PixelFormat format, const sp<IMemoryHeap>& heap);
+ void postBuffer(ssize_t offset);
+ void unregisterBuffers();
+ void invalidate();
+ void invalidateLocked();
+
+private:
+
+ struct NativeBuffer
+ {
+ copybit_image_t img;
+ copybit_rect_t crop;
+ };
+
+ class Buffer
+ {
+ public:
+ Buffer(const sp<IMemoryHeap>& heap, ssize_t offset,
+ int w, int h, int hs, int vs, int f);
+ inline void incStrong(void*) const {
+ android_atomic_inc(&mCount);
+ }
+ inline void decStrong(void*) const {
+ int32_t c = android_atomic_dec(&mCount);
+ //LOGE_IF(c<1, "Buffer::decStrong() called too many times");
+ if (c == 1) {
+ delete this;
+ }
+ }
+ inline status_t getStatus() const {
+ return mHeap!=0 ? NO_ERROR : NO_INIT;
+ }
+ inline const NativeBuffer& getBuffer() const {
+ return mNativeBuffer;
+ }
+ protected:
+ Buffer& operator = (const Buffer& rhs);
+ Buffer(const Buffer& rhs);
+ ~Buffer();
+ mutable volatile int32_t mCount;
+ private:
+ sp<IMemoryHeap> mHeap;
+ NativeBuffer mNativeBuffer;
+ };
+
+ class SurfaceBuffer : public LayerBaseClient::Surface
+ {
+ public:
+ SurfaceBuffer(SurfaceID id, LayerBuffer* owner);
+ virtual ~SurfaceBuffer();
+ virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
+ PixelFormat format, const sp<IMemoryHeap>& heap);
+ virtual void postBuffer(ssize_t offset);
+ virtual void unregisterBuffers();
+ void disown();
+ private:
+ LayerBuffer* getOwner() const {
+ Mutex::Autolock _l(mLock);
+ return mOwner;
+ }
+ mutable Mutex mLock;
+ LayerBuffer* mOwner;
+ };
+
+ friend class SurfaceFlinger;
+ sp<Buffer> getBuffer() const;
+ void setBuffer(const sp<Buffer>& buffer);
+ sp<SurfaceBuffer> getClientSurface() const;
+
+ mutable Mutex mLock;
+ sp<IMemoryHeap> mHeap;
+ sp<Buffer> mBuffer;
+ int mWidth;
+ int mHeight;
+ int mHStride;
+ int mVStride;
+ int mFormat;
+ mutable GLuint mTextureName;
+ bool mInvalidate;
+ bool mNeedsBlending;
+ mutable wp<SurfaceBuffer> mClientSurface;
+ mutable sp<MemoryDealer> mTemporaryDealer;
+ mutable LayerBitmap mTempBitmap;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BUFFER_H
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
new file mode 100644
index 0000000..fc23d53
--- /dev/null
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "LayerDim.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerDim::typeInfo = LayerBaseClient::typeInfo | 0x10;
+const char* const LayerDim::typeID = "LayerDim";
+sp<MemoryDealer> LayerDim::mDimmerDealer;
+LayerBitmap LayerDim::mDimmerBitmap;
+
+// ---------------------------------------------------------------------------
+
+LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i)
+ : LayerBaseClient(flinger, display, client, i)
+{
+}
+
+void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h)
+{
+ // must only be called once.
+ mDimmerDealer = flinger->getSurfaceHeapManager()
+ ->createHeap(NATIVE_MEMORY_TYPE_PMEM);
+ if (mDimmerDealer != 0) {
+ mDimmerBitmap.init(mDimmerDealer);
+ mDimmerBitmap.setBits(w, h, 1, PIXEL_FORMAT_RGB_565);
+ mDimmerBitmap.clear();
+ }
+}
+
+LayerDim::~LayerDim()
+{
+}
+
+void LayerDim::onDraw(const Region& clip) const
+{
+ const State& s(drawingState());
+
+ Region::iterator iterator(clip);
+ if (s.alpha>0 && iterator) {
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+
+ status_t err = NO_ERROR;
+ const int can_use_copybit = canUseCopybit();
+ if (can_use_copybit) {
+ // StopWatch watch("copybit");
+ copybit_image_t dst;
+ hw.getDisplaySurface(&dst);
+ const copybit_rect_t& drect
+ = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
+
+ copybit_image_t src;
+ mDimmerBitmap.getBitmapSurface(&src);
+ const copybit_rect_t& srect(drect);
+
+ copybit_t* copybit = mFlinger->getBlitEngine();
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+ region_iterator it(clip);
+ err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ }
+
+ if (!can_use_copybit || err) {
+ const GGLfixed alpha = (s.alpha << 16)/255;
+ const uint32_t fbHeight = hw.getHeight();
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4x(0, 0, 0, alpha);
+ glVertexPointer(2, GL_FIXED, 0, mVertices);
+ Rect r;
+ while (iterator.iterate(&r)) {
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h
new file mode 100644
index 0000000..3e37a47
--- /dev/null
+++ b/libs/surfaceflinger/LayerDim.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_LAYER_DIM_H
+#define ANDROID_LAYER_DIM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class LayerDim : public LayerBaseClient
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerDim(SurfaceFlinger* flinger, DisplayID display,
+ Client* client, int32_t i);
+ virtual ~LayerDim();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual bool needsBlending() const { return true; }
+ virtual bool isSecure() const { return false; }
+
+ static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h);
+
+private:
+ static sp<MemoryDealer> mDimmerDealer;
+ static LayerBitmap mDimmerBitmap;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_DIM_H
diff --git a/libs/surfaceflinger/LayerScreenshot.cpp b/libs/surfaceflinger/LayerScreenshot.cpp
new file mode 100644
index 0000000..9b82bad
--- /dev/null
+++ b/libs/surfaceflinger/LayerScreenshot.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <graphics/SkBitmap.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBase.h"
+#include "LayerScreenshot.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerScreenshot::typeInfo = LayerBase::typeInfo | 0x20;
+const char* const LayerScreenshot::typeID = "LayerScreenshot";
+
+// ---------------------------------------------------------------------------
+
+LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, DisplayID display)
+ : LayerBase(flinger, display), mReply(0)
+{
+}
+
+LayerScreenshot::~LayerScreenshot()
+{
+}
+
+void LayerScreenshot::onDraw(const Region& clip) const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ copybit_image_t dst;
+ hw.getDisplaySurface(&dst);
+ if (dst.base != 0) {
+ uint8_t const* src = (uint8_t const*)(intptr_t(dst.base) + dst.offset);
+ const int fbWidth = dst.w;
+ const int fbHeight = dst.h;
+ const int fbFormat = dst.format;
+
+ int x = mTransformedBounds.left;
+ int y = mTransformedBounds.top;
+ int w = mTransformedBounds.width();
+ int h = mTransformedBounds.height();
+ Parcel* const reply = mReply;
+ if (reply) {
+ const size_t Bpp = bytesPerPixel(fbFormat);
+ const size_t size = w * h * Bpp;
+ int32_t cfg = SkBitmap::kNo_Config;
+ switch (fbFormat) {
+ case PIXEL_FORMAT_RGBA_4444: cfg = SkBitmap::kARGB_4444_Config;
+ case PIXEL_FORMAT_RGBA_8888: cfg = SkBitmap::kARGB_8888_Config;
+ case PIXEL_FORMAT_RGB_565: cfg = SkBitmap::kRGB_565_Config;
+ case PIXEL_FORMAT_A_8: cfg = SkBitmap::kA8_Config;
+ }
+ reply->writeInt32(0);
+ reply->writeInt32(cfg);
+ reply->writeInt32(w);
+ reply->writeInt32(h);
+ reply->writeInt32(w * Bpp);
+ void* data = reply->writeInplace(size);
+ if (data) {
+ uint8_t* d = (uint8_t*)data;
+ uint8_t const* s = src + (x + y*fbWidth) * Bpp;
+ if (w == fbWidth) {
+ memcpy(d, s, w*h*Bpp);
+ } else {
+ for (int y=0 ; y<h ; y++) {
+ memcpy(d, s, w*Bpp);
+ d += w*Bpp;
+ s += fbWidth*Bpp;
+ }
+ }
+ }
+ }
+ }
+ mCV.broadcast();
+}
+
+void LayerScreenshot::takeScreenshot(Mutex& lock, Parcel* reply)
+{
+ mReply = reply;
+ mCV.wait(lock);
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerScreenshot.h b/libs/surfaceflinger/LayerScreenshot.h
new file mode 100644
index 0000000..2d9a8ec
--- /dev/null
+++ b/libs/surfaceflinger/LayerScreenshot.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_LAYER_SCREENSHOT_H
+#define ANDROID_LAYER_SCREENSHOT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <utils/Parcel.h>
+
+#include "LayerBase.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class LayerScreenshot : public LayerBase
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerScreenshot(SurfaceFlinger* flinger, DisplayID display);
+ virtual ~LayerScreenshot();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual bool needsBlending() const { return true; }
+ virtual bool isSecure() const { return false; }
+
+ void takeScreenshot(Mutex& lock, Parcel* reply);
+
+private:
+ mutable Condition mCV;
+ Parcel* mReply;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_SCREENSHOT_H
diff --git a/libs/surfaceflinger/MODULE_LICENSE_APACHE2 b/libs/surfaceflinger/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/surfaceflinger/MODULE_LICENSE_APACHE2
diff --git a/libs/surfaceflinger/RFBServer.cpp b/libs/surfaceflinger/RFBServer.cpp
new file mode 100644
index 0000000..c2c1989
--- /dev/null
+++ b/libs/surfaceflinger/RFBServer.cpp
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "RFBServer"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+
+#include <cutils/sockets.h>
+
+#include <utils/Log.h>
+#include <ui/Rect.h>
+
+#ifdef HAVE_ANDROID_OS
+#include <linux/input.h>
+#endif
+
+#include "RFBServer.h"
+#include "SurfaceFlinger.h"
+
+/* BUG=773511: this is a temporary hack required while developing the new
+ set of "clean kernel headers" for the Bionic C library. */
+#ifndef KEY_STAR
+#define KEY_STAR 227
+#endif
+#ifndef KEY_SHARP
+#define KEY_SHARP 228
+#endif
+#ifndef KEY_SOFT1
+#define KEY_SOFT1 229
+#endif
+#ifndef KEY_SOFT2
+#define KEY_SOFT2 230
+#endif
+#ifndef KEY_CENTER
+#define KEY_CENTER 232
+#endif
+
+// ----------------------------------------------------------------------------
+
+#define DEBUG_MSG 0
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+const int VNC_PORT = 5900;
+
+RFBServer::RFBServer(uint32_t w, uint32_t h, android::PixelFormat format)
+ : Thread(false), mFD(-1), mStatus(NO_INIT), mIoVec(0)
+{
+ mFrameBuffer.version = sizeof(mFrameBuffer);
+ mFrameBuffer.width = w;
+ mFrameBuffer.height = h;
+ mFrameBuffer.stride = w;
+ mFrameBuffer.format = format;
+ mFrameBuffer.data = 0;
+}
+
+RFBServer::~RFBServer()
+{
+ if (mRobinThread != 0) {
+ // ask the thread to exit first
+ mRobinThread->exitAndWait();
+ }
+
+ free(mFrameBuffer.data);
+
+ delete [] mIoVec;
+}
+
+void RFBServer::onFirstRef()
+{
+ run("Batman");
+}
+
+status_t RFBServer::readyToRun()
+{
+ LOGI("RFB server ready to run");
+ return NO_ERROR;
+}
+
+bool RFBServer::threadLoop()
+{
+ struct sockaddr addr;
+ socklen_t alen;
+ int serverfd = -1;
+ int port = VNC_PORT;
+
+ do {
+ retry:
+ if (serverfd < 0) {
+ serverfd = socket_loopback_server(port, SOCK_STREAM);
+ if (serverfd < 0) {
+ if ((errno == EADDRINUSE) && (port < (VNC_PORT+10))) {
+ LOGW("port %d already in use, trying %d", port, port+1);
+ port++;
+ goto retry;
+ }
+ LOGE("couldn't create socket, port=%d, error %d (%s)",
+ port, errno, strerror(errno));
+ sleep(1);
+ break;
+ }
+ fcntl(serverfd, F_SETFD, FD_CLOEXEC);
+ }
+
+ alen = sizeof(addr);
+ mFD = accept(serverfd, &addr, &alen);
+
+ if (mFD < 0) {
+ LOGE("couldn't accept(), error %d (%s)", errno, strerror(errno));
+ // we could have run out of file descriptors, wait a bit and
+ // try again.
+ sleep(1);
+ goto retry;
+ }
+ fcntl(mFD, F_SETFD, FD_CLOEXEC);
+
+ // send protocol version and Authentication method
+ mStatus = NO_ERROR;
+ handshake(3, 3, Authentication::None);
+
+ if (alive()) {
+ // create the thread we use to send data to the client
+ mRobinThread = new ServerThread(this);
+ }
+
+ while( alive() ) {
+ // client message must be destroyed at each iteration
+ // (most of the time this is a no-op)
+ ClientMessage msg;
+ waitForClientMessage(msg);
+ if (alive()) {
+ handleClientMessage(msg);
+ }
+ }
+
+ } while( alive() );
+
+ // free-up some resources
+ if (mRobinThread != 0) {
+ mRobinThread->exitAndWait();
+ mRobinThread.clear();
+ }
+
+ free(mFrameBuffer.data);
+ mFrameBuffer.data = 0;
+
+ close(mFD);
+ close(serverfd);
+ mFD = -1;
+
+ // we'll try again
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+
+RFBServer::ServerThread::ServerThread(const sp<RFBServer>& receiver)
+ : Thread(false), mReceiver(receiver)
+{
+ LOGD("RFB Server Thread created");
+}
+
+RFBServer::ServerThread::~ServerThread()
+{
+ LOGD("RFB Server Thread destroyed");
+}
+
+void RFBServer::ServerThread::onFirstRef()
+{
+ mUpdateBarrier.close();
+ run("Robin");
+}
+
+status_t RFBServer::ServerThread::readyToRun()
+{
+ return NO_ERROR;
+}
+
+void RFBServer::ServerThread::wake()
+{
+ mUpdateBarrier.open();
+}
+
+void RFBServer::ServerThread::exitAndWait()
+{
+ requestExit();
+ mUpdateBarrier.open();
+ requestExitAndWait();
+}
+
+bool RFBServer::ServerThread::threadLoop()
+{
+ sp<RFBServer> receiver(mReceiver.promote());
+ if (receiver == 0)
+ return false;
+
+ // wait for something to do
+ mUpdateBarrier.wait();
+
+ // we're asked to quit, abort everything
+ if (exitPending())
+ return false;
+
+ mUpdateBarrier.close();
+
+ // process updates
+ receiver->sendFrameBufferUpdates();
+ return !exitPending();
+}
+
+// ----------------------------------------------------------------------------
+
+void RFBServer::handshake(uint8_t major, uint8_t minor, uint32_t auth)
+{
+ ProtocolVersion protocolVersion(major, minor);
+ if( !write(protocolVersion) )
+ return;
+
+ if ( !read(protocolVersion) )
+ return;
+
+ int maj, min;
+ if ( protocolVersion.decode(maj, min) != NO_ERROR ) {
+ mStatus = -1;
+ return;
+ }
+
+#if DEBUG_MSG
+ LOGD("client protocol string: <%s>", (char*)protocolVersion.payload());
+ LOGD("client wants protocol version %d.%d\n", maj, min);
+#endif
+
+ Authentication authentication(auth);
+ if( !write(authentication) )
+ return;
+
+ ClientInitialization clientInit;
+ if ( !read(clientInit) )
+ return;
+
+#if DEBUG_MSG
+ LOGD("client initialization: sharedFlags = %d\n", clientInit.sharedFlags());
+#endif
+
+ ServerInitialization serverInit("Android RFB");
+ ServerInitialization::Payload& message(serverInit.message());
+ message.framebufferWidth = htons(mFrameBuffer.width);
+ message.framebufferHeight = htons(mFrameBuffer.height);
+ message.serverPixelFormat.bitsPerPixel = 16;
+ message.serverPixelFormat.depth = 16;
+ message.serverPixelFormat.bigEndianFlag = 0;
+ message.serverPixelFormat.trueColorFlag = 1;
+ message.serverPixelFormat.redMax = htons((1<<5)-1);
+ message.serverPixelFormat.greenMax = htons((1<<6)-1);
+ message.serverPixelFormat.blueMax = htons((1<<5)-1);
+ message.serverPixelFormat.redShift = 11;
+ message.serverPixelFormat.greenShift = 5;
+ message.serverPixelFormat.blueShift = 0;
+
+ mIoVec = new iovec[mFrameBuffer.height];
+
+ write(serverInit);
+}
+
+void RFBServer::handleClientMessage(const ClientMessage& msg)
+{
+ switch(msg.type()) {
+ case SET_PIXEL_FORMAT:
+ handleSetPixelFormat(msg.messages().setPixelFormat);
+ break;
+ case SET_ENCODINGS:
+ handleSetEncodings(msg.messages().setEncodings);
+ break;
+ case FRAME_BUFFER_UPDATE_REQ:
+ handleFrameBufferUpdateReq(msg.messages().frameBufferUpdateRequest);
+ break;
+ case KEY_EVENT:
+ handleKeyEvent(msg.messages().keyEvent);
+ break;
+ }
+}
+
+void RFBServer::handleSetPixelFormat(const SetPixelFormat& msg)
+{
+ if (!validatePixelFormat(msg.pixelFormat)) {
+ LOGE("The builtin VNC server only supports the RGB 565 pixel format");
+ LOGD("requested pixel format:");
+ LOGD("bitsPerPixel: %d", msg.pixelFormat.bitsPerPixel);
+ LOGD("depth: %d", msg.pixelFormat.depth);
+ LOGD("bigEndianFlag: %d", msg.pixelFormat.bigEndianFlag);
+ LOGD("trueColorFlag: %d", msg.pixelFormat.trueColorFlag);
+ LOGD("redmax: %d", ntohs(msg.pixelFormat.redMax));
+ LOGD("bluemax: %d", ntohs(msg.pixelFormat.greenMax));
+ LOGD("greenmax: %d", ntohs(msg.pixelFormat.blueMax));
+ LOGD("redshift: %d", msg.pixelFormat.redShift);
+ LOGD("greenshift: %d", msg.pixelFormat.greenShift);
+ LOGD("blueshift: %d", msg.pixelFormat.blueShift);
+ mStatus = -1;
+ }
+}
+
+bool RFBServer::validatePixelFormat(const PixelFormat& pf)
+{
+ if ((pf.bitsPerPixel != 16) || (pf.depth != 16))
+ return false;
+
+ if (pf.bigEndianFlag || !pf.trueColorFlag)
+ return false;
+
+ if (ntohs(pf.redMax)!=0x1F ||
+ ntohs(pf.greenMax)!=0x3F ||
+ ntohs(pf.blueMax)!=0x1F) {
+ return false;
+ }
+
+ if (pf.redShift!=11 || pf.greenShift!=5 || pf.blueShift!=0)
+ return false;
+
+ return true;
+}
+
+void RFBServer::handleSetEncodings(const SetEncodings& msg)
+{
+ /* From the RFB specification:
+ Sets the encoding types in which pixel data can be sent by the server.
+ The order of the encoding types given in this message is a hint by the
+ client as to its preference (the first encoding specified being most
+ preferred). The server may or may not choose to make use of this hint.
+ Pixel data may always be sent in raw encoding even if not specified
+ explicitly here.
+ */
+
+ LOGW("SetEncodings received. Only RAW is supported.");
+}
+
+void RFBServer::handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg)
+{
+#if DEBUG_MSG
+ LOGD("handle FrameBufferUpdateRequest");
+#endif
+
+ Rect r;
+ r.left = ntohs(msg.x);
+ r.top = ntohs(msg.y);
+ r.right = r.left + ntohs(msg.width);
+ r.bottom = r.top + ntohs(msg.height);
+
+ Mutex::Autolock _l(mRegionLock);
+ mClientRegionRequest.set(r);
+ if (!msg.incremental)
+ mDirtyRegion.orSelf(r);
+
+ mRobinThread->wake();
+}
+
+void RFBServer::handleKeyEvent(const KeyEvent& msg)
+{
+#ifdef HAVE_ANDROID_OS
+
+ int scancode = 0;
+ int code = ntohl(msg.key);
+
+ if (code>='0' && code<='9') {
+ scancode = (code & 0xF) - 1;
+ if (scancode<0) scancode += 10;
+ scancode += KEY_1;
+ } else if (code>=0xFF50 && code<=0xFF58) {
+ static const uint16_t map[] =
+ { KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,
+ KEY_SOFT1, KEY_SOFT2, KEY_END, 0 };
+ scancode = map[code & 0xF];
+ } else if (code>=0xFFE1 && code<=0xFFEE) {
+ static const uint16_t map[] =
+ { KEY_LEFTSHIFT, KEY_LEFTSHIFT,
+ KEY_COMPOSE, KEY_COMPOSE,
+ KEY_LEFTSHIFT, KEY_LEFTSHIFT,
+ 0,0,
+ KEY_LEFTALT, KEY_RIGHTALT,
+ 0, 0, 0, 0 };
+ scancode = map[code & 0xF];
+ } else if ((code>='A' && code<='Z') || (code>='a' && code<='z')) {
+ static const uint16_t map[] = {
+ KEY_A, KEY_B, KEY_C, KEY_D, KEY_E,
+ KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
+ KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
+ KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
+ KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z };
+ scancode = map[(code & 0x5F) - 'A'];
+ } else {
+ switch (code) {
+ case 0x0003: scancode = KEY_CENTER; break;
+ case 0x0020: scancode = KEY_SPACE; break;
+ case 0x0023: scancode = KEY_SHARP; break;
+ case 0x0033: scancode = KEY_SHARP; break;
+ case 0x002C: scancode = KEY_COMMA; break;
+ case 0x003C: scancode = KEY_COMMA; break;
+ case 0x002E: scancode = KEY_DOT; break;
+ case 0x003E: scancode = KEY_DOT; break;
+ case 0x002F: scancode = KEY_SLASH; break;
+ case 0x003F: scancode = KEY_SLASH; break;
+ case 0x0032: scancode = KEY_EMAIL; break;
+ case 0x0040: scancode = KEY_EMAIL; break;
+ case 0xFF08: scancode = KEY_BACKSPACE; break;
+ case 0xFF1B: scancode = KEY_BACK; break;
+ case 0xFF09: scancode = KEY_TAB; break;
+ case 0xFF0D: scancode = KEY_ENTER; break;
+ case 0x002A: scancode = KEY_STAR; break;
+ case 0xFFBE: scancode = KEY_SEND; break; // F1
+ case 0xFFBF: scancode = KEY_END; break; // F2
+ case 0xFFC0: scancode = KEY_HOME; break; // F3
+ case 0xFFC5: scancode = KEY_POWER; break; // F8
+ }
+ }
+
+#if DEBUG_MSG
+ LOGD("handle KeyEvent 0x%08x, %d, scancode=%d\n", code, msg.downFlag, scancode);
+#endif
+
+ if (scancode) {
+ mEventInjector.injectKey(uint16_t(scancode),
+ msg.downFlag ? EventInjector::DOWN : EventInjector::UP);
+ }
+#endif
+}
+
+void RFBServer::waitForClientMessage(ClientMessage& msg)
+{
+ if ( !read(msg.payload(), 1) )
+ return;
+
+ switch(msg.type()) {
+
+ case SET_PIXEL_FORMAT:
+ read(msg.payload(1), sizeof(SetPixelFormat)-1);
+ break;
+
+ case FIX_COLOUR_MAP_ENTRIES:
+ mStatus = UNKNOWN_ERROR;
+ return;
+
+ case SET_ENCODINGS:
+ {
+ if ( !read(msg.payload(1), sizeof(SetEncodings)-1) )
+ return;
+
+ size_t size = ntohs( msg.messages().setEncodings.numberOfEncodings ) * 4;
+ if (msg.resize(sizeof(SetEncodings) + size) != NO_ERROR) {
+ mStatus = NO_MEMORY;
+ return;
+ }
+
+ if ( !read(msg.payload(sizeof(SetEncodings)), size) )
+ return;
+
+ break;
+ }
+
+ case FRAME_BUFFER_UPDATE_REQ:
+ read(msg.payload(1), sizeof(FrameBufferUpdateRequest)-1);
+ break;
+
+ case KEY_EVENT:
+ read(msg.payload(1), sizeof(KeyEvent)-1);
+ break;
+
+ case POINTER_EVENT:
+ read(msg.payload(1), sizeof(PointerEvent)-1);
+ break;
+
+ case CLIENT_CUT_TEXT:
+ {
+ if ( !read(msg.payload(1), sizeof(ClientCutText)-1) )
+ return;
+
+ size_t size = ntohl( msg.messages().clientCutText.length );
+ if (msg.resize(sizeof(ClientCutText) + size) != NO_ERROR) {
+ mStatus = NO_MEMORY;
+ return;
+ }
+
+ if ( !read(msg.payload(sizeof(SetEncodings)), size) )
+ return;
+
+ break;
+ }
+
+ default:
+ LOGE("Unknown Message %d", msg.type());
+ mStatus = UNKNOWN_ERROR;
+ return;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+bool RFBServer::write(const Message& msg)
+{
+ write(msg.payload(), msg.size());
+ return alive();
+}
+
+bool RFBServer::read(Message& msg)
+{
+ read(msg.payload(), msg.size());
+ return alive();
+}
+
+bool RFBServer::write(const void* buffer, int size)
+{
+ int wr = ::write(mFD, buffer, size);
+ if (wr != size) {
+ //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
+ mStatus = (wr == -1) ? errno : -1;
+ }
+ return alive();
+}
+
+bool RFBServer::read(void* buffer, int size)
+{
+ int rd = ::read(mFD, buffer, size);
+ if (rd != size) {
+ //LOGE("read(%d) error %d (%s)", size, rd, strerror(errno));
+ mStatus = (rd == -1) ? errno : -1;
+ }
+ return alive();
+}
+
+bool RFBServer::alive() const
+{
+ return mStatus == 0;
+}
+
+bool RFBServer::isConnected() const
+{
+ return alive();
+}
+
+// ----------------------------------------------------------------------------
+
+void RFBServer::frameBufferUpdated(const GGLSurface& front, const Region& reg)
+{
+ Mutex::Autolock _l(mRegionLock);
+
+ // update dirty region
+ mDirtyRegion.orSelf(reg);
+
+ // remember the front-buffer
+ mFrontBuffer = front;
+
+ // The client has not requested anything, don't do anything more
+ if (mClientRegionRequest.isEmpty())
+ return;
+
+ // wake the sending thread up
+ mRobinThread->wake();
+}
+
+void RFBServer::sendFrameBufferUpdates()
+{
+ Vector<Rect> rects;
+ size_t countRects;
+ GGLSurface fb;
+
+ { // Scope for the lock
+ Mutex::Autolock _l(mRegionLock);
+ if (mFrontBuffer.data == 0)
+ return;
+
+ const Region reg( mDirtyRegion.intersect(mClientRegionRequest) );
+ if (reg.isEmpty())
+ return;
+
+ mDirtyRegion.subtractSelf(reg);
+ countRects = reg.rects(rects);
+
+ // copy the frame-buffer so we can stay responsive
+ size_t bytesPerPix = bytesPerPixel(mFrameBuffer.format);
+ size_t bpr = mFrameBuffer.stride * bytesPerPix;
+ if (mFrameBuffer.data == 0) {
+ mFrameBuffer.data = (GGLubyte*)malloc(bpr * mFrameBuffer.height);
+ if (mFrameBuffer.data == 0)
+ return;
+ }
+
+ memcpy(mFrameBuffer.data, mFrontBuffer.data, bpr*mFrameBuffer.height);
+ fb = mFrameBuffer;
+ }
+
+ FrameBufferUpdate msgHeader;
+ msgHeader.type = 0;
+ msgHeader.numberOfRectangles = htons(countRects);
+ write(&msgHeader, sizeof(msgHeader));
+
+ Rectangle rectangle;
+ for (size_t i=0 ; i<countRects ; i++) {
+ const Rect& r = rects[i];
+ rectangle.x = htons( r.left );
+ rectangle.y = htons( r.top );
+ rectangle.w = htons( r.width() );
+ rectangle.h = htons( r.height() );
+ rectangle.encoding = htons( SetEncodings::Raw );
+ write(&rectangle, sizeof(rectangle));
+ size_t h = r.height();
+ size_t w = r.width();
+ size_t bytesPerPix = bytesPerPixel(fb.format);
+ size_t bpr = fb.stride * bytesPerPix;
+ size_t bytes = w * bytesPerPix;
+ size_t offset = (r.top * bpr) + (r.left * bytesPerPix);
+ uint8_t* src = static_cast<uint8_t*>(fb.data) + offset;
+ iovec* iov = mIoVec;
+ while (h--) {
+ iov->iov_base = src;
+ iov->iov_len = bytes;
+ src += bpr;
+ iov++;
+ }
+ size_t iovcnt = iov - mIoVec;
+ int wr = ::writev(mFD, mIoVec, iovcnt);
+ if (wr < 0) {
+ //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
+ mStatus = errno;
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+RFBServer::Message::Message(size_t size)
+ : mSize(size), mAllocatedSize(size)
+{
+ mPayload = malloc(size);
+}
+
+RFBServer::Message::Message(void* payload, size_t size)
+ : mPayload(payload), mSize(size), mAllocatedSize(0)
+{
+}
+
+RFBServer::Message::~Message()
+{
+ if (mAllocatedSize)
+ free(mPayload);
+}
+
+status_t RFBServer::Message::resize(size_t size)
+{
+ if (size > mAllocatedSize) {
+ void* newp;
+ if (mAllocatedSize) {
+ newp = realloc(mPayload, size);
+ if (!newp) return NO_MEMORY;
+ } else {
+ newp = malloc(size);
+ if (!newp) return NO_MEMORY;
+ memcpy(newp, mPayload, mSize);
+ mAllocatedSize = size;
+ }
+ mPayload = newp;
+ }
+ mSize = size;
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+RFBServer::EventInjector::EventInjector()
+ : mFD(-1)
+{
+}
+
+RFBServer::EventInjector::~EventInjector()
+{
+}
+
+void RFBServer::EventInjector::injectKey(uint16_t code, uint16_t value)
+{
+#ifdef HAVE_ANDROID_OS
+ // XXX: we need to open the right event device
+ int version;
+ mFD = open("/dev/input/event0", O_RDWR);
+ ioctl(mFD, EVIOCGVERSION, &version);
+
+ input_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.type = EV_KEY;
+ ev.code = code;
+ ev.value = value;
+ ::write(mFD, &ev, sizeof(ev));
+
+ close(mFD);
+ mFD = -1;
+#endif
+}
+
+
+}; // namespace android
+
diff --git a/libs/surfaceflinger/RFBServer.h b/libs/surfaceflinger/RFBServer.h
new file mode 100644
index 0000000..420912e
--- /dev/null
+++ b/libs/surfaceflinger/RFBServer.h
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_RFB_SERVER_H
+#define ANDROID_RFB_SERVER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <ui/Region.h>
+#include <ui/PixelFormat.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include "Barrier.h"
+
+namespace android {
+
+class SurfaceFlinger;
+
+class RFBServer : public Thread
+{
+public:
+ RFBServer(uint32_t w, uint32_t h, android::PixelFormat format);
+ virtual ~RFBServer();
+
+ void frameBufferUpdated(const GGLSurface& front, const Region& reg);
+ bool isConnected() const;
+
+private:
+ typedef uint8_t card8;
+ typedef uint16_t card16;
+ typedef uint32_t card32;
+
+ struct Message {
+ Message(size_t size);
+ virtual ~Message();
+ void* payload(int offset=0) {
+ return static_cast<char*>(mPayload)+offset;
+ }
+ void const * payload(int offset=0) const {
+ return static_cast<char const *>(mPayload)+offset;
+ }
+ size_t size() const { return mSize; }
+ protected:
+ Message(void* payload, size_t size);
+ status_t resize(size_t size);
+ private:
+ void* mPayload;
+ size_t mSize;
+ size_t mAllocatedSize;
+ };
+
+ struct ProtocolVersion : public Message {
+ ProtocolVersion(uint8_t major, uint8_t minor)
+ : Message(&messageData, 12) {
+ char* p = static_cast<char*>(payload());
+ snprintf(p, 13, "RFB %03u.%03u%c", major, minor, 0xA);
+ }
+ status_t decode(int& maj, int& min) {
+ char* p = static_cast<char*>(payload());
+ int n = sscanf(p, "RFB %03u.%03u", &maj, &min);
+ return (n == 2) ? NO_ERROR : NOT_ENOUGH_DATA;
+ }
+ private:
+ char messageData[12+1];
+ };
+
+ struct Authentication : public Message {
+ enum { Failed=0, None=1, Vnc=2 };
+ Authentication(int auth) : Message(&messageData, 4) {
+ *static_cast<card32*>(payload()) = htonl(auth);
+ }
+ private:
+ card32 messageData;
+ };
+
+ struct ClientInitialization : public Message {
+ ClientInitialization() : Message(&messageData, 1) { }
+ int sharedFlags() {
+ return messageData;
+ }
+ private:
+ card8 messageData;
+ };
+
+ struct PixelFormat {
+ card8 bitsPerPixel;
+ card8 depth;
+ card8 bigEndianFlag;
+ card8 trueColorFlag;
+ card16 redMax;
+ card16 greenMax;
+ card16 blueMax;
+ card8 redShift;
+ card8 greenShift;
+ card8 blueShift;
+ uint8_t padding[3];
+ } __attribute__((packed));
+
+ struct ServerInitialization : public Message {
+ ServerInitialization(char const * name)
+ : Message(sizeof(Payload) + strlen(name))
+ {
+ const size_t nameLength = size() - sizeof(Payload);
+ message().nameLength = htonl(nameLength);
+ memcpy((char*)message().nameString, name,nameLength);
+ }
+ struct Payload {
+ card16 framebufferWidth;
+ card16 framebufferHeight;
+ PixelFormat serverPixelFormat;
+ card32 nameLength;
+ card8 nameString[0];
+ } __attribute__((packed));
+ Payload& message() {
+ return *static_cast<Payload*>(payload());
+ }
+ };
+
+ // client messages...
+
+ struct SetPixelFormat {
+ card8 type;
+ uint8_t padding[3];
+ PixelFormat pixelFormat;
+ } __attribute__((packed));
+
+ struct SetEncodings {
+ enum { Raw=0, CoR=1, RRE=2, CoRRE=4, Hextile=5 };
+ card8 type;
+ uint8_t padding;
+ card16 numberOfEncodings;
+ card32 encodings[0];
+ } __attribute__((packed));
+
+ struct FrameBufferUpdateRequest {
+ card8 type;
+ card8 incremental;
+ card16 x;
+ card16 y;
+ card16 width;
+ card16 height;
+ } __attribute__((packed));
+
+ struct KeyEvent {
+ card8 type;
+ card8 downFlag;
+ uint8_t padding[2];
+ card32 key;
+ } __attribute__((packed));
+
+ struct PointerEvent {
+ card8 type;
+ card8 buttonMask;
+ card16 x;
+ card16 y;
+ } __attribute__((packed));
+
+ struct ClientCutText {
+ card8 type;
+ uint8_t padding[3];
+ card32 length;
+ card8 text[0];
+ } __attribute__((packed));
+
+ union ClientMessages {
+ card8 type;
+ SetPixelFormat setPixelFormat;
+ SetEncodings setEncodings;
+ FrameBufferUpdateRequest frameBufferUpdateRequest;
+ KeyEvent keyEvent;
+ PointerEvent pointerEvent;
+ ClientCutText clientCutText;
+ };
+
+ struct Rectangle {
+ card16 x;
+ card16 y;
+ card16 w;
+ card16 h;
+ card32 encoding;
+ } __attribute__((packed));
+
+ struct FrameBufferUpdate {
+ card8 type;
+ uint8_t padding;
+ card16 numberOfRectangles;
+ Rectangle rectangles[0];
+ } __attribute__((packed));
+
+ enum {
+ SET_PIXEL_FORMAT = 0,
+ FIX_COLOUR_MAP_ENTRIES = 1,
+ SET_ENCODINGS = 2,
+ FRAME_BUFFER_UPDATE_REQ = 3,
+ KEY_EVENT = 4,
+ POINTER_EVENT = 5,
+ CLIENT_CUT_TEXT = 6,
+ };
+
+ struct ClientMessage : public Message {
+ ClientMessage()
+ : Message(&messageData, sizeof(messageData)) {
+ }
+ const ClientMessages& messages() const {
+ return *static_cast<ClientMessages const *>(payload());
+ }
+ const int type() const {
+ return messages().type;
+ }
+ status_t resize(size_t size) {
+ return Message::resize(size);
+ }
+
+ ClientMessages messageData;
+ };
+
+
+ class ServerThread : public Thread
+ {
+ friend class RFBServer;
+ public:
+ ServerThread(const sp<RFBServer>& receiver);
+ virtual ~ServerThread();
+ void wake();
+ void exitAndWait();
+ private:
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+ wp<RFBServer> mReceiver;
+ bool (RFBServer::*mAction)();
+ Barrier mUpdateBarrier;
+ };
+
+ class EventInjector {
+ public:
+ enum { UP=0, DOWN=1 };
+ EventInjector();
+ ~EventInjector();
+ void injectKey(uint16_t code, uint16_t value);
+ private:
+ struct input_event {
+ struct timeval time;
+ uint16_t type;
+ uint16_t code;
+ uint32_t value;
+ };
+ int mFD;
+ };
+
+ void handshake(uint8_t major, uint8_t minor, uint32_t auth);
+ void waitForClientMessage(ClientMessage& msg);
+ void handleClientMessage(const ClientMessage& msg);
+ void handleSetPixelFormat(const SetPixelFormat& msg);
+ void handleSetEncodings(const SetEncodings& msg);
+ void handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg);
+ void handleKeyEvent(const KeyEvent& msg);
+ void sendFrameBufferUpdates();
+
+ bool validatePixelFormat(const PixelFormat& pf);
+ bool alive() const;
+ bool write(const Message& msg);
+ bool read(Message& msg);
+
+ bool write(const void* buffer, int size);
+ bool read(void* buffer, int size);
+
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+ sp<ServerThread> mRobinThread;
+
+ int mFD;
+ int mStatus;
+ iovec* mIoVec;
+
+ EventInjector mEventInjector;
+
+ Mutex mRegionLock;
+ // This is the region requested by the client since the last
+ // time we updated it
+ Region mClientRegionRequest;
+ // This is the region of the screen that needs to be sent to the
+ // client since the last time we updated it.
+ // Typically this is the dirty region, but not necessarily, for
+ // instance if the client asked for a non incremental update.
+ Region mDirtyRegion;
+
+ GGLSurface mFrameBuffer;
+ GGLSurface mFrontBuffer;
+};
+
+}; // namespace android
+
+#endif // ANDROID_RFB_SERVER_H
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
new file mode 100644
index 0000000..45496b2
--- /dev/null
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -0,0 +1,1895 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryBase.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StopWatch.h>
+
+#include <ui/BlitHardware.h>
+#include <ui/PixelFormat.h>
+#include <ui/DisplayInfo.h>
+#include <ui/EGLDisplaySurface.h>
+
+#include <pixelflinger/pixelflinger.h>
+#include <GLES/gl.h>
+
+#include "clz.h"
+#include "CPUGauge.h"
+#include "Layer.h"
+#include "LayerBlur.h"
+#include "LayerBuffer.h"
+#include "LayerDim.h"
+#include "LayerBitmap.h"
+#include "LayerScreenshot.h"
+#include "SurfaceFlinger.h"
+#include "RFBServer.h"
+#include "VRamHeap.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+#include "GPUHardware/GPUHardware.h"
+
+
+// the VNC server even on local ports presents a significant
+// thread as it can allow an application to control and "see" other
+// applications, de-facto bypassing security permissions.
+#define ENABLE_VNC_SERVER 0
+
+#define DISPLAY_COUNT 1
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+void SurfaceFlinger::instantiate() {
+ defaultServiceManager()->addService(
+ String16("SurfaceFlinger"), new SurfaceFlinger());
+}
+
+void SurfaceFlinger::shutdown() {
+ // we should unregister here, but not really because
+ // when (if) the service manager goes away, all the services
+ // it has a reference to will leave too.
+}
+
+// ---------------------------------------------------------------------------
+
+SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs)
+ : lookup(rhs.lookup), layers(rhs.layers)
+{
+}
+
+ssize_t SurfaceFlinger::LayerVector::indexOf(
+ LayerBase* key, size_t guess) const
+{
+ if (guess<size() && lookup.keyAt(guess) == key)
+ return guess;
+ const ssize_t i = lookup.indexOfKey(key);
+ if (i>=0) {
+ const size_t idx = lookup.valueAt(i);
+ LOG_ASSERT(layers[idx]==key,
+ "LayerVector[%p]: layers[%d]=%p, key=%p",
+ this, int(idx), layers[idx], key);
+ return idx;
+ }
+ return i;
+}
+
+ssize_t SurfaceFlinger::LayerVector::add(
+ LayerBase* layer,
+ Vector<LayerBase*>::compar_t cmp)
+{
+ size_t count = layers.size();
+ ssize_t l = 0;
+ ssize_t h = count-1;
+ ssize_t mid;
+ LayerBase* const* a = layers.array();
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const int c = cmp(a+mid, &layer);
+ if (c == 0) { l = mid; break; }
+ else if (c<0) { l = mid+1; }
+ else { h = mid-1; }
+ }
+ size_t order = l;
+ while (order<count && !cmp(&layer, a+order)) {
+ order++;
+ }
+ count = lookup.size();
+ for (size_t i=0 ; i<count ; i++) {
+ if (lookup.valueAt(i) >= order) {
+ lookup.editValueAt(i)++;
+ }
+ }
+ layers.insertAt(layer, order);
+ lookup.add(layer, order);
+ return order;
+}
+
+ssize_t SurfaceFlinger::LayerVector::remove(LayerBase* layer)
+{
+ const ssize_t keyIndex = lookup.indexOfKey(layer);
+ if (keyIndex >= 0) {
+ const size_t index = lookup.valueAt(keyIndex);
+ LOG_ASSERT(layers[index]==layer,
+ "LayerVector[%p]: layers[%u]=%p, layer=%p",
+ this, int(index), layers[index], layer);
+ layers.removeItemsAt(index);
+ lookup.removeItemsAt(keyIndex);
+ const size_t count = lookup.size();
+ for (size_t i=0 ; i<count ; i++) {
+ if (lookup.valueAt(i) >= size_t(index)) {
+ lookup.editValueAt(i)--;
+ }
+ }
+ return index;
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t SurfaceFlinger::LayerVector::reorder(
+ LayerBase* layer,
+ Vector<LayerBase*>::compar_t cmp)
+{
+ // XXX: it's a little lame. but oh well...
+ ssize_t err = remove(layer);
+ if (err >=0)
+ err = add(layer, cmp);
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+SurfaceFlinger::SurfaceFlinger()
+ : BnSurfaceComposer(), Thread(false),
+ mTransactionFlags(0),
+ mTransactionCount(0),
+ mBootTime(systemTime()),
+ mLastScheduledBroadcast(NULL),
+ mVisibleRegionsDirty(false),
+ mDeferReleaseConsole(false),
+ mFreezeDisplay(false),
+ mFreezeCount(0),
+ mDebugRegion(0),
+ mDebugCpu(0),
+ mDebugFps(0),
+ mDebugBackground(0),
+ mDebugNoBootAnimation(0),
+ mSyncObject(),
+ mDeplayedTransactionPending(0),
+ mConsoleSignals(0),
+ mSecureFrameBuffer(0)
+{
+ init();
+}
+
+void SurfaceFlinger::init()
+{
+ LOGI("SurfaceFlinger is starting");
+
+ // create the shared control-block
+ mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
+ LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+
+ mServerCblkMemory = mServerHeap->allocate(4096);
+ LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
+
+ mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
+ LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+ new(mServerCblk) surface_flinger_cblk_t;
+
+ // create the surface Heap manager, which manages the heaps
+ // (be it in RAM or VRAM) where surfaces are allocated
+ // We give 8 MB per client.
+ mSurfaceHeapManager = new SurfaceHeapManager(8 << 20);
+ mGPU = new GPUHardware();
+
+ // debugging stuff...
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.showupdates", value, "0");
+ mDebugRegion = atoi(value);
+ property_get("debug.sf.showcpu", value, "0");
+ mDebugCpu = atoi(value);
+ property_get("debug.sf.showbackground", value, "0");
+ mDebugBackground = atoi(value);
+ property_get("debug.sf.showfps", value, "0");
+ mDebugFps = atoi(value);
+ property_get("debug.sf.nobootanimation", value, "0");
+ mDebugNoBootAnimation = atoi(value);
+
+ LOGI_IF(mDebugRegion, "showupdates enabled");
+ LOGI_IF(mDebugCpu, "showcpu enabled");
+ LOGI_IF(mDebugBackground, "showbackground enabled");
+ LOGI_IF(mDebugFps, "showfps enabled");
+ LOGI_IF(mDebugNoBootAnimation, "boot animation disabled");
+}
+
+SurfaceFlinger::~SurfaceFlinger()
+{
+ glDeleteTextures(1, &mWormholeTexName);
+}
+
+copybit_t* SurfaceFlinger::getBlitEngine() const
+{
+ return graphicPlane(0).displayHardware().getBlitEngine();
+}
+
+sp<IMemory> SurfaceFlinger::getCblk() const
+{
+ return mServerCblkMemory;
+}
+
+status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback,
+ gpu_info_t* gpu)
+{
+ status_t err = mGPU->request(callback, gpu);
+ return err;
+}
+
+status_t SurfaceFlinger::revokeGPU()
+{
+ return mGPU->friendlyRevoke();
+}
+
+sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
+{
+ Mutex::Autolock _l(mStateLock);
+ uint32_t token = mTokens.acquire();
+
+ Client* client = new Client(token, this);
+ if ((client == 0) || (client->ctrlblk == 0)) {
+ mTokens.release(token);
+ return 0;
+ }
+ status_t err = mClientsMap.add(token, client);
+ if (err < 0) {
+ delete client;
+ mTokens.release(token);
+ return 0;
+ }
+ sp<BClient> bclient =
+ new BClient(this, token, client->controlBlockMemory());
+ return bclient;
+}
+
+void SurfaceFlinger::destroyConnection(ClientID cid)
+{
+ Mutex::Autolock _l(mStateLock);
+ Client* const client = mClientsMap.valueFor(cid);
+ if (client) {
+ // free all the layers this client owns
+ const Vector<LayerBaseClient*>& layers = client->getLayers();
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ LayerBaseClient* const layer = layers[i];
+ removeLayer_l(layer);
+ }
+
+ // the resources associated with this client will be freed
+ // during the next transaction, after these surfaces have been
+ // properly removed from the screen
+
+ // remove this client from our ClientID->Client mapping.
+ mClientsMap.removeItem(cid);
+
+ // and add it to the list of disconnected clients
+ mDisconnectedClients.add(client);
+
+ // request a transaction
+ setTransactionFlags(eTransactionNeeded);
+ }
+}
+
+const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const
+{
+ LOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy);
+ const GraphicPlane& plane(mGraphicPlanes[dpy]);
+ return plane;
+}
+
+GraphicPlane& SurfaceFlinger::graphicPlane(int dpy)
+{
+ return const_cast<GraphicPlane&>(
+ const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy));
+}
+
+void SurfaceFlinger::bootFinished()
+{
+ const nsecs_t now = systemTime();
+ const nsecs_t duration = now - mBootTime;
+ LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
+ if (mBootAnimation != 0) {
+ mBootAnimation->requestExit();
+ mBootAnimation.clear();
+ }
+}
+
+void SurfaceFlinger::onFirstRef()
+{
+ run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
+
+ // Wait for the main thread to be done with its initialization
+ mReadyToRunBarrier.wait();
+}
+
+
+static inline uint16_t pack565(int r, int g, int b) {
+ return (r<<11)|(g<<5)|b;
+}
+
+// this is defined in libGLES_CM.so
+extern ISurfaceComposer* GLES_localSurfaceManager;
+
+status_t SurfaceFlinger::readyToRun()
+{
+ LOGI( "SurfaceFlinger's main thread ready to run. "
+ "Initializing graphics H/W...");
+
+ //
+ GLES_localSurfaceManager = static_cast<ISurfaceComposer*>(this);
+
+ // we only support one display currently
+ int dpy = 0;
+
+ {
+ // initialize the main display
+ GraphicPlane& plane(graphicPlane(dpy));
+ DisplayHardware* const hw = new DisplayHardware(this, dpy);
+ plane.setDisplayHardware(hw);
+ }
+
+ // initialize primary screen
+ // (other display should be initialized in the same manner, but
+ // asynchronously, as they could come and go. None of this is supported
+ // yet).
+ const GraphicPlane& plane(graphicPlane(dpy));
+ const DisplayHardware& hw = plane.displayHardware();
+ const uint32_t w = hw.getWidth();
+ const uint32_t h = hw.getHeight();
+ const uint32_t f = hw.getFormat();
+ hw.makeCurrent();
+
+ // initialize the shared control block
+ mServerCblk->connected |= 1<<dpy;
+ display_cblk_t* dcblk = mServerCblk->displays + dpy;
+ memset(dcblk, 0, sizeof(display_cblk_t));
+ dcblk->w = w;
+ dcblk->h = h;
+ dcblk->format = f;
+ dcblk->orientation = ISurfaceComposer::eOrientationDefault;
+ dcblk->xdpi = hw.getDpiX();
+ dcblk->ydpi = hw.getDpiY();
+ dcblk->fps = hw.getRefreshRate();
+ dcblk->density = 1.0f; // XXX: do someting more real here...
+ asm volatile ("":::"memory");
+
+ // Initialize OpenGL|ES
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnable(GL_SCISSOR_TEST);
+ glShadeModel(GL_FLAT);
+ glDisable(GL_DITHER);
+ glDisable(GL_CULL_FACE);
+
+ const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
+ const uint16_t g1 = pack565(0x17,0x2f,0x17);
+ const uint16_t textureData[4] = { g0, g1, g1, g0 };
+ glGenTextures(1, &mWormholeTexName);
+ glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData);
+
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, w, h, 0, 0, 1);
+
+ LayerDim::initDimmer(this, w, h);
+
+ mReadyToRunBarrier.open();
+
+ /*
+ * We're now ready to accept clients...
+ */
+
+ // start CPU gauge display
+ if (mDebugCpu)
+ mCpuGauge = new CPUGauge(this, ms2ns(500));
+
+ // the boot animation!
+ if (mDebugNoBootAnimation == false)
+ mBootAnimation = new BootAnimation(this);
+
+ if (ENABLE_VNC_SERVER)
+ mRFBServer = new RFBServer(w, h, f);
+
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Events Handler
+#endif
+
+void SurfaceFlinger::waitForEvent()
+{
+ // wait for something to do
+ if (UNLIKELY(isFrozen())) {
+ // wait 2 seconds
+ int err = mSyncObject.wait(ms2ns(3000));
+ if (err != NO_ERROR) {
+ if (isFrozen()) {
+ // we timed out and are still frozen
+ LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
+ mFreezeDisplay, mFreezeCount);
+ mFreezeCount = 0;
+ }
+ }
+ } else {
+ mSyncObject.wait();
+ }
+}
+
+void SurfaceFlinger::signalEvent() {
+ mSyncObject.open();
+}
+
+void SurfaceFlinger::signal() const {
+ mSyncObject.open();
+}
+
+void SurfaceFlinger::signalDelayedEvent(nsecs_t delay)
+{
+ if (android_atomic_or(1, &mDeplayedTransactionPending) == 0) {
+ sp<DelayedTransaction> delayedEvent(new DelayedTransaction(this, delay));
+ delayedEvent->run("DelayedeEvent", PRIORITY_URGENT_DISPLAY);
+ }
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Main loop
+#endif
+
+bool SurfaceFlinger::threadLoop()
+{
+ waitForEvent();
+
+ // check for transactions
+ if (UNLIKELY(mConsoleSignals)) {
+ handleConsoleEvents();
+ }
+
+ if (LIKELY(mTransactionCount == 0)) {
+ // if we're in a global transaction, don't do anything.
+ const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+ uint32_t transactionFlags = getTransactionFlags(mask);
+ if (LIKELY(transactionFlags)) {
+ handleTransaction(transactionFlags);
+ }
+ }
+
+ // post surfaces (if needed)
+ handlePageFlip();
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ if (LIKELY(hw.canDraw())) {
+ // repaint the framebuffer (if needed)
+ handleRepaint();
+
+ // release the clients before we flip ('cause flip might block)
+ unlockClients();
+ executeScheduledBroadcasts();
+
+ // sample the cpu gauge
+ if (UNLIKELY(mDebugCpu)) {
+ handleDebugCpu();
+ }
+
+ postFramebuffer();
+ } else {
+ // pretend we did the post
+ unlockClients();
+ executeScheduledBroadcasts();
+ usleep(16667); // 60 fps period
+ }
+ return true;
+}
+
+void SurfaceFlinger::postFramebuffer()
+{
+ if (UNLIKELY(isFrozen())) {
+ // we are not allowed to draw, but pause a bit to make sure
+ // apps don't end up using the whole CPU, if they depend on
+ // surfaceflinger for synchronization.
+ usleep(8333); // 8.3ms ~ 120fps
+ return;
+ }
+
+ if (!mInvalidRegion.isEmpty()) {
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+
+ if (UNLIKELY(mDebugFps)) {
+ debugShowFPS();
+ }
+
+ if (UNLIKELY(ENABLE_VNC_SERVER &&
+ mRFBServer!=0 && mRFBServer->isConnected())) {
+ if (!mSecureFrameBuffer) {
+ GGLSurface fb;
+ // backbufer, is going to become the front buffer really soon
+ hw.getDisplaySurface(&fb);
+ if (LIKELY(fb.data != 0)) {
+ mRFBServer->frameBufferUpdated(fb, mInvalidRegion);
+ }
+ }
+ }
+
+ hw.flip(mInvalidRegion);
+
+ mInvalidRegion.clear();
+
+ if (Layer::deletedTextures.size()) {
+ glDeleteTextures(
+ Layer::deletedTextures.size(),
+ Layer::deletedTextures.array());
+ Layer::deletedTextures.clear();
+ }
+ }
+}
+
+void SurfaceFlinger::handleConsoleEvents()
+{
+ // something to do with the console
+ const DisplayHardware& hw = graphicPlane(0).displayHardware();
+
+ int what = android_atomic_and(0, &mConsoleSignals);
+ if (what & eConsoleAcquired) {
+ hw.acquireScreen();
+ }
+
+ if (mDeferReleaseConsole && hw.canDraw()) {
+ // We got the release signal before the aquire signal
+ mDeferReleaseConsole = false;
+ revokeGPU();
+ hw.releaseScreen();
+ }
+
+ if (what & eConsoleReleased) {
+ if (hw.canDraw()) {
+ revokeGPU();
+ hw.releaseScreen();
+ } else {
+ mDeferReleaseConsole = true;
+ }
+ }
+
+ mDirtyRegion.set(hw.bounds());
+}
+
+void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
+{
+ Mutex::Autolock _l(mStateLock);
+
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+
+ /*
+ * Traversal of the children
+ * (perform the transaction for each of them if needed)
+ */
+
+ const bool layersNeedTransaction = transactionFlags & eTraversalNeeded;
+ if (layersNeedTransaction) {
+ for (size_t i=0 ; i<count ; i++) {
+ LayerBase* const layer = currentLayers[i];
+ uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
+ if (!trFlags) continue;
+
+ const uint32_t flags = layer->doTransaction(0);
+ if (flags & Layer::eVisibleRegion)
+ mVisibleRegionsDirty = true;
+
+ if (flags & Layer::eRestartTransaction) {
+ // restart the transaction, but back-off a little
+ layer->setTransactionFlags(eTransactionNeeded);
+ setTransactionFlags(eTraversalNeeded, ms2ns(8));
+ }
+ }
+ }
+
+ /*
+ * Perform our own transaction if needed
+ */
+
+ if (transactionFlags & eTransactionNeeded) {
+ if (mCurrentState.orientation != mDrawingState.orientation) {
+ // the orientation has changed, recompute all visible regions
+ // and invalidate everything.
+
+ const int dpy = 0;
+ const int orientation = mCurrentState.orientation;
+ GraphicPlane& plane(graphicPlane(dpy));
+ plane.setOrientation(orientation);
+
+ // update the shared control block
+ const DisplayHardware& hw(plane.displayHardware());
+ volatile display_cblk_t* dcblk = mServerCblk->displays + dpy;
+ dcblk->orientation = orientation;
+ if (orientation & eOrientationSwapMask) {
+ // 90 or 270 degrees orientation
+ dcblk->w = hw.getHeight();
+ dcblk->h = hw.getWidth();
+ } else {
+ dcblk->w = hw.getWidth();
+ dcblk->h = hw.getHeight();
+ }
+
+ mVisibleRegionsDirty = true;
+ mDirtyRegion.set(hw.bounds());
+ }
+
+ if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
+ // freezing or unfreezing the display -> trigger animation if needed
+ mFreezeDisplay = mCurrentState.freezeDisplay;
+ const nsecs_t now = systemTime();
+ if (mFreezeDisplay) {
+ mFreezeDisplayTime = now;
+ } else {
+ //LOGD("Screen was frozen for %llu us",
+ // ns2us(now-mFreezeDisplayTime));
+ }
+ }
+
+ // some layers might have been removed, so
+ // we need to update the regions they're exposing.
+ size_t c = mRemovedLayers.size();
+ if (c) {
+ mVisibleRegionsDirty = true;
+ }
+
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
+ // layers have been added
+ mVisibleRegionsDirty = true;
+ }
+
+ // get rid of all resources we don't need anymore
+ // (layers and clients)
+ free_resources_l();
+ }
+
+ commitTransaction();
+}
+
+sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
+{
+ return new FreezeLock(const_cast<SurfaceFlinger *>(this));
+}
+
+void SurfaceFlinger::computeVisibleRegions(
+ LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const Transform& planeTransform(plane.transform());
+
+ Region aboveOpaqueLayers;
+ Region aboveCoveredLayers;
+ Region dirty;
+
+ bool secureFrameBuffer = false;
+
+ size_t i = currentLayers.size();
+ while (i--) {
+ LayerBase* const layer = currentLayers[i];
+ layer->validateVisibility(planeTransform);
+
+ // start with the whole surface at its current location
+ const Layer::State& s = layer->drawingState();
+ const Rect bounds(layer->visibleBounds());
+
+ // handle hidden surfaces by setting the visible region to empty
+ Region opaqueRegion;
+ Region visibleRegion;
+ Region coveredRegion;
+ if (UNLIKELY((s.flags & ISurfaceComposer::eLayerHidden) || !s.alpha)) {
+ visibleRegion.clear();
+ } else {
+ const bool translucent = layer->needsBlending();
+ visibleRegion.set(bounds);
+ coveredRegion = visibleRegion;
+
+ // Remove the transparent area from the visible region
+ if (translucent) {
+ visibleRegion.subtractSelf(layer->transparentRegionScreen);
+ }
+
+ // compute the opaque region
+ if (s.alpha==255 && !translucent && layer->getOrientation()>=0) {
+ // the opaque region is the visible region
+ opaqueRegion = visibleRegion;
+ }
+ }
+
+ // subtract the opaque region covered by the layers above us
+ visibleRegion.subtractSelf(aboveOpaqueLayers);
+ coveredRegion.andSelf(aboveCoveredLayers);
+
+ // compute this layer's dirty region
+ if (layer->invalidate) {
+ // we need to invalidate the whole region
+ dirty = visibleRegion;
+ // as well, as the old visible region
+ dirty.orSelf(layer->visibleRegionScreen);
+ layer->invalidate = false;
+ } else {
+ // compute the exposed region
+ // dirty = what's visible now - what's wasn't covered before
+ // = what's visible now & what's was covered before
+ dirty = visibleRegion.intersect(layer->coveredRegionScreen);
+ }
+ dirty.subtractSelf(aboveOpaqueLayers);
+
+ // accumulate to the screen dirty region
+ dirtyRegion.orSelf(dirty);
+
+ // updade aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
+ aboveOpaqueLayers.orSelf(opaqueRegion);
+ aboveCoveredLayers.orSelf(bounds);
+
+ // Store the visible region is screen space
+ layer->setVisibleRegion(visibleRegion);
+ layer->setCoveredRegion(coveredRegion);
+
+ // If a secure layer is partially visible, lockdown the screen!
+ if (layer->isSecure() && !visibleRegion.isEmpty()) {
+ secureFrameBuffer = true;
+ }
+ }
+
+ mSecureFrameBuffer = secureFrameBuffer;
+ opaqueRegion = aboveOpaqueLayers;
+}
+
+
+void SurfaceFlinger::commitTransaction()
+{
+ mDrawingState = mCurrentState;
+ mTransactionCV.signal();
+}
+
+void SurfaceFlinger::handlePageFlip()
+{
+ bool visibleRegions = mVisibleRegionsDirty;
+ LayerVector& currentLayers = const_cast<LayerVector&>(mDrawingState.layersSortedByZ);
+ visibleRegions |= lockPageFlip(currentLayers);
+
+ const DisplayHardware& hw = graphicPlane(0).displayHardware();
+ const Region screenRegion(hw.bounds());
+ if (visibleRegions) {
+ Region opaqueRegion;
+ computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
+ mWormholeRegion = screenRegion.subtract(opaqueRegion);
+ mVisibleRegionsDirty = false;
+ }
+
+ unlockPageFlip(currentLayers);
+ mDirtyRegion.andSelf(screenRegion);
+}
+
+bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
+{
+ bool recomputeVisibleRegions = false;
+ size_t count = currentLayers.size();
+ LayerBase* const* layers = currentLayers.array();
+ for (size_t i=0 ; i<count ; i++) {
+ LayerBase* const layer = layers[i];
+ layer->lockPageFlip(recomputeVisibleRegions);
+ }
+ return recomputeVisibleRegions;
+}
+
+void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const Transform& planeTransform(plane.transform());
+ size_t count = currentLayers.size();
+ LayerBase* const* layers = currentLayers.array();
+ for (size_t i=0 ; i<count ; i++) {
+ LayerBase* const layer = layers[i];
+ layer->unlockPageFlip(planeTransform, mDirtyRegion);
+ }
+}
+
+void SurfaceFlinger::handleRepaint()
+{
+ // set the frame buffer
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ if (UNLIKELY(mDebugRegion)) {
+ debugFlashRegions();
+ }
+
+ // compute the invalid region
+ mInvalidRegion.orSelf(mDirtyRegion);
+
+ uint32_t flags = hw.getFlags();
+ if (flags & DisplayHardware::BUFFER_PRESERVED) {
+ if (flags & DisplayHardware::COPY_BACK_EXTENSION) {
+ // yay. nothing to do here.
+ } else {
+ if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
+ // we need to fully redraw the part that will be updated
+ mDirtyRegion.set(mInvalidRegion.bounds());
+ } else {
+ // TODO: we only need te redraw the part that had been drawn
+ // the round before and is not drawn now
+ }
+ }
+ } else {
+ // COPY_BACK_EXTENSION makes no sense here
+ if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
+ // we need to fully redraw the part that will be updated
+ mDirtyRegion.set(mInvalidRegion.bounds());
+ } else {
+ // we need to redraw everything
+ mDirtyRegion.set(hw.bounds());
+ mInvalidRegion = mDirtyRegion;
+ }
+ }
+
+ // compose all surfaces
+ composeSurfaces(mDirtyRegion);
+
+ // clear the dirty regions
+ mDirtyRegion.clear();
+}
+
+void SurfaceFlinger::composeSurfaces(const Region& dirty)
+{
+ if (UNLIKELY(!mWormholeRegion.isEmpty())) {
+ // should never happen unless the window manager has a bug
+ // draw something...
+ drawWormhole();
+ }
+ const SurfaceFlinger& flinger(*this);
+ const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
+ const size_t count = drawingLayers.size();
+ LayerBase const* const* const layers = drawingLayers.array();
+ for (size_t i=0 ; i<count ; ++i) {
+ LayerBase const * const layer = layers[i];
+ const Region& visibleRegion(layer->visibleRegionScreen);
+ if (!visibleRegion.isEmpty()) {
+ const Region clip(dirty.intersect(visibleRegion));
+ if (!clip.isEmpty()) {
+ layer->draw(clip);
+ }
+ }
+ }
+}
+
+void SurfaceFlinger::unlockClients()
+{
+ const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
+ const size_t count = drawingLayers.size();
+ LayerBase* const* const layers = drawingLayers.array();
+ for (size_t i=0 ; i<count ; ++i) {
+ LayerBase* const layer = layers[i];
+ layer->finishPageFlip();
+ }
+}
+
+void SurfaceFlinger::scheduleBroadcast(Client* client)
+{
+ if (mLastScheduledBroadcast != client) {
+ mLastScheduledBroadcast = client;
+ mScheduledBroadcasts.add(client);
+ }
+}
+
+void SurfaceFlinger::executeScheduledBroadcasts()
+{
+ SortedVector<Client*>& list = mScheduledBroadcasts;
+ size_t count = list.size();
+ while (count--) {
+ per_client_cblk_t* const cblk = list[count]->ctrlblk;
+ if (cblk->lock.tryLock() == NO_ERROR) {
+ cblk->cv.broadcast();
+ list.removeAt(count);
+ cblk->lock.unlock();
+ } else {
+ // schedule another round
+ LOGW("executeScheduledBroadcasts() skipped, "
+ "contention on the client. We'll try again later...");
+ signalDelayedEvent(ms2ns(4));
+ }
+ }
+ mLastScheduledBroadcast = 0;
+}
+
+void SurfaceFlinger::handleDebugCpu()
+{
+ Mutex::Autolock _l(mDebugLock);
+ if (mCpuGauge != 0)
+ mCpuGauge->sample();
+}
+
+void SurfaceFlinger::debugFlashRegions()
+{
+ if (UNLIKELY(!mDirtyRegion.isRect())) {
+ // TODO: do this only if we don't have preserving
+ // swapBuffer. If we don't have update-on-demand,
+ // redraw everything.
+ composeSurfaces(Region(mDirtyRegion.bounds()));
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+
+ glColor4x(0x10000, 0, 0x10000, 0x10000);
+
+ Rect r;
+ Region::iterator iterator(mDirtyRegion);
+ while (iterator.iterate(&r)) {
+ GLfloat vertices[][2] = {
+ { r.left, r.top },
+ { r.left, r.bottom },
+ { r.right, r.bottom },
+ { r.right, r.top }
+ };
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.flip(mDirtyRegion.merge(mInvalidRegion));
+ mInvalidRegion.clear();
+
+ if (mDebugRegion > 1)
+ usleep(mDebugRegion * 1000);
+
+ glEnable(GL_SCISSOR_TEST);
+ //mDirtyRegion.dump("mDirtyRegion");
+}
+
+void SurfaceFlinger::drawWormhole() const
+{
+ const Region region(mWormholeRegion.intersect(mDirtyRegion));
+ if (region.isEmpty())
+ return;
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const int32_t width = hw.getWidth();
+ const int32_t height = hw.getHeight();
+
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+
+ if (LIKELY(!mDebugBackground)) {
+ glClearColorx(0,0,0,0);
+ Rect r;
+ Region::iterator iterator(region);
+ while (iterator.iterate(&r)) {
+ const GLint sy = height - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ } else {
+ const GLshort vertices[][2] = { { 0, 0 }, { width, 0 },
+ { width, height }, { 0, height } };
+ const GLshort tcoords[][2] = { { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } };
+ glVertexPointer(2, GL_SHORT, 0, vertices);
+ glTexCoordPointer(2, GL_SHORT, 0, tcoords);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1);
+ Rect r;
+ Region::iterator iterator(region);
+ while (iterator.iterate(&r)) {
+ const GLint sy = height - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+}
+
+void SurfaceFlinger::debugShowFPS() const
+{
+ static int mFrameCount;
+ static int mLastFrameCount = 0;
+ static nsecs_t mLastFpsTime = 0;
+ static float mFps = 0;
+ mFrameCount++;
+ nsecs_t now = systemTime();
+ nsecs_t diff = now - mLastFpsTime;
+ if (diff > ms2ns(250)) {
+ mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
+ mLastFpsTime = now;
+ mLastFrameCount = mFrameCount;
+ }
+ // XXX: mFPS has the value we want
+ }
+
+status_t SurfaceFlinger::addLayer_l(LayerBase* layer)
+{
+ ssize_t i = mCurrentState.layersSortedByZ.add(
+ layer, &LayerBase::compareCurrentStateZ);
+ LayerBaseClient* lbc = LayerBase::dynamicCast<LayerBaseClient*>(layer);
+ if (lbc) {
+ mLayerMap.add(lbc->serverIndex(), lbc);
+ }
+ mRemovedLayers.remove(layer);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeLayer_l(LayerBase* layerBase)
+{
+ ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
+ if (index >= 0) {
+ mRemovedLayers.add(layerBase);
+ LayerBaseClient* layer = LayerBase::dynamicCast<LayerBaseClient*>(layerBase);
+ if (layer) {
+ mLayerMap.removeItem(layer->serverIndex());
+ }
+ return NO_ERROR;
+ }
+ // it's possible that we don't find a layer, because it might
+ // have been destroyed already -- this is not technically an error
+ // from the user because there is a race between destroySurface,
+ // destroyclient and destroySurface-from-a-transaction.
+ return (index == NAME_NOT_FOUND) ? status_t(NO_ERROR) : index;
+}
+
+void SurfaceFlinger::free_resources_l()
+{
+ // Destroy layers that were removed
+ destroy_all_removed_layers_l();
+
+ // free resources associated with disconnected clients
+ SortedVector<Client*>& scheduledBroadcasts(mScheduledBroadcasts);
+ Vector<Client*>& disconnectedClients(mDisconnectedClients);
+ const size_t count = disconnectedClients.size();
+ for (size_t i=0 ; i<count ; i++) {
+ Client* client = disconnectedClients[i];
+ // if this client is the scheduled broadcast list,
+ // remove it from there (and we don't need to signal it
+ // since it is dead).
+ int32_t index = scheduledBroadcasts.indexOf(client);
+ if (index >= 0) {
+ scheduledBroadcasts.removeItemsAt(index);
+ }
+ mTokens.release(client->cid);
+ delete client;
+ }
+ disconnectedClients.clear();
+}
+
+void SurfaceFlinger::destroy_all_removed_layers_l()
+{
+ size_t c = mRemovedLayers.size();
+ while (c--) {
+ LayerBase* const removed_layer = mRemovedLayers[c];
+
+ LOGE_IF(mCurrentState.layersSortedByZ.indexOf(removed_layer) >= 0,
+ "layer %p removed but still in the current state list",
+ removed_layer);
+
+ delete removed_layer;
+ }
+ mRemovedLayers.clear();
+}
+
+
+uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
+{
+ return android_atomic_and(~flags, &mTransactionFlags) & flags;
+}
+
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, nsecs_t delay)
+{
+ uint32_t old = android_atomic_or(flags, &mTransactionFlags);
+ if ((old & flags)==0) { // wake the server up
+ if (delay > 0) {
+ signalDelayedEvent(delay);
+ } else {
+ signalEvent();
+ }
+ }
+ return old;
+}
+
+void SurfaceFlinger::openGlobalTransaction()
+{
+ android_atomic_inc(&mTransactionCount);
+}
+
+void SurfaceFlinger::closeGlobalTransaction()
+{
+ if (android_atomic_dec(&mTransactionCount) == 1) {
+ signalEvent();
+ }
+}
+
+status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags)
+{
+ if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+ return BAD_VALUE;
+
+ Mutex::Autolock _l(mStateLock);
+ mCurrentState.freezeDisplay = 1;
+ setTransactionFlags(eTransactionNeeded);
+
+ // flags is intended to communicate some sort of animation behavior
+ // (for instance fadding)
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
+{
+ if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+ return BAD_VALUE;
+
+ Mutex::Autolock _l(mStateLock);
+ mCurrentState.freezeDisplay = 0;
+ setTransactionFlags(eTransactionNeeded);
+
+ // flags is intended to communicate some sort of animation behavior
+ // (for instance fadding)
+ return NO_ERROR;
+}
+
+int SurfaceFlinger::setOrientation(DisplayID dpy, int orientation)
+{
+ if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+ return BAD_VALUE;
+
+ Mutex::Autolock _l(mStateLock);
+ if (mCurrentState.orientation != orientation) {
+ if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
+ mCurrentState.orientation = orientation;
+ setTransactionFlags(eTransactionNeeded);
+ mTransactionCV.wait(mStateLock);
+ } else {
+ orientation = BAD_VALUE;
+ }
+ }
+ return orientation;
+}
+
+sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
+ ISurfaceFlingerClient::surface_data_t* params,
+ DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags)
+{
+ LayerBaseClient* layer = 0;
+ sp<LayerBaseClient::Surface> surfaceHandle;
+ Mutex::Autolock _l(mStateLock);
+ Client* const c = mClientsMap.valueFor(clientId);
+ if (UNLIKELY(!c)) {
+ LOGE("createSurface() failed, client not found (id=%d)", clientId);
+ return surfaceHandle;
+ }
+
+ //LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
+ int32_t id = c->generateId(pid);
+ if (uint32_t(id) >= NUM_LAYERS_MAX) {
+ LOGE("createSurface() failed, generateId = %d", id);
+ return surfaceHandle;
+ }
+
+ switch (flags & eFXSurfaceMask) {
+ case eFXSurfaceNormal:
+ if (UNLIKELY(flags & ePushBuffers)) {
+ layer = createPushBuffersSurfaceLocked(c, d, id, w, h, flags);
+ } else {
+ layer = createNormalSurfaceLocked(c, d, id, w, h, format, flags);
+ }
+ break;
+ case eFXSurfaceBlur:
+ layer = createBlurSurfaceLocked(c, d, id, w, h, flags);
+ break;
+ case eFXSurfaceDim:
+ layer = createDimSurfaceLocked(c, d, id, w, h, flags);
+ break;
+ }
+
+ if (layer) {
+ setTransactionFlags(eTransactionNeeded);
+ surfaceHandle = layer->getSurface();
+ if (surfaceHandle != 0)
+ surfaceHandle->getSurfaceData(params);
+ }
+
+ return surfaceHandle;
+}
+
+LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
+ Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+{
+ // initialize the surfaces
+ switch (format) { // TODO: take h/w into account
+ case PIXEL_FORMAT_TRANSPARENT:
+ case PIXEL_FORMAT_TRANSLUCENT:
+ format = PIXEL_FORMAT_RGBA_8888;
+ break;
+ case PIXEL_FORMAT_OPAQUE:
+ format = PIXEL_FORMAT_RGB_565;
+ break;
+ }
+
+ Layer* layer = new Layer(this, display, client, id);
+ status_t err = layer->setBuffers(client, w, h, format, flags);
+ if (LIKELY(err == NO_ERROR)) {
+ layer->initStates(w, h, flags);
+ addLayer_l(layer);
+ } else {
+ LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
+ delete layer;
+ return 0;
+ }
+ return layer;
+}
+
+LayerBaseClient* SurfaceFlinger::createBlurSurfaceLocked(
+ Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+{
+ LayerBlur* layer = new LayerBlur(this, display, client, id);
+ layer->initStates(w, h, flags);
+ addLayer_l(layer);
+ return layer;
+}
+
+LayerBaseClient* SurfaceFlinger::createDimSurfaceLocked(
+ Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+{
+ LayerDim* layer = new LayerDim(this, display, client, id);
+ layer->initStates(w, h, flags);
+ addLayer_l(layer);
+ return layer;
+}
+
+LayerBaseClient* SurfaceFlinger::createPushBuffersSurfaceLocked(
+ Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags)
+{
+ LayerBuffer* layer = new LayerBuffer(this, display, client, id);
+ layer->initStates(w, h, flags);
+ addLayer_l(layer);
+ return layer;
+}
+
+status_t SurfaceFlinger::destroySurface(SurfaceID index)
+{
+ Mutex::Autolock _l(mStateLock);
+ LayerBaseClient* const layer = getLayerUser_l(index);
+ status_t err = removeLayer_l(layer);
+ if (err < 0)
+ return err;
+ setTransactionFlags(eTransactionNeeded);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setClientState(
+ ClientID cid,
+ int32_t count,
+ const layer_state_t* states)
+{
+ Mutex::Autolock _l(mStateLock);
+ uint32_t flags = 0;
+ cid <<= 16;
+ for (int i=0 ; i<count ; i++) {
+ const layer_state_t& s = states[i];
+ LayerBaseClient* layer = getLayerUser_l(s.surface | cid);
+ if (layer) {
+ const uint32_t what = s.what;
+ // check if it has been destroyed first
+ if (what & eDestroyed) {
+ if (removeLayer_l(layer) == NO_ERROR) {
+ flags |= eTransactionNeeded;
+ // we skip everything else... well, no, not really
+ // we skip ONLY that transaction.
+ continue;
+ }
+ }
+ if (what & ePositionChanged) {
+ if (layer->setPosition(s.x, s.y))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eLayerChanged) {
+ if (layer->setLayer(s.z)) {
+ mCurrentState.layersSortedByZ.reorder(
+ layer, &Layer::compareCurrentStateZ);
+ // we need traversal (state changed)
+ // AND transaction (list changed)
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
+ if (what & eSizeChanged) {
+ if (layer->setSize(s.w, s.h))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eAlphaChanged) {
+ if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eMatrixChanged) {
+ if (layer->setMatrix(s.matrix))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eTransparentRegionChanged) {
+ if (layer->setTransparentRegionHint(s.transparentRegion))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eVisibilityChanged) {
+ if (layer->setFlags(s.flags, s.mask))
+ flags |= eTraversalNeeded;
+ }
+ }
+ }
+ if (flags) {
+ setTransactionFlags(flags);
+ }
+ return NO_ERROR;
+}
+
+LayerBaseClient* SurfaceFlinger::getLayerUser_l(SurfaceID s) const
+{
+ return mLayerMap.valueFor(s);
+}
+
+void SurfaceFlinger::screenReleased(int dpy)
+{
+ // this may be called by a signal handler, we can't do too much in here
+ android_atomic_or(eConsoleReleased, &mConsoleSignals);
+ signalEvent();
+}
+
+void SurfaceFlinger::screenAcquired(int dpy)
+{
+ // this may be called by a signal handler, we can't do too much in here
+ android_atomic_or(eConsoleAcquired, &mConsoleSignals);
+ signalEvent();
+}
+
+status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 1024;
+ char buffer[SIZE];
+ String8 result;
+ if (checkCallingPermission(
+ String16("android.permission.DUMP")) == false)
+ { // not allowed
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump SurfaceFlinger from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ result.append(buffer);
+ } else {
+ Mutex::Autolock _l(mStateLock);
+ size_t s = mClientsMap.size();
+ char name[64];
+ for (size_t i=0 ; i<s ; i++) {
+ Client* client = mClientsMap.valueAt(i);
+ sprintf(name, " Client (id=0x%08x)", client->cid);
+ client->dump(name);
+ }
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ /*** LayerBase ***/
+ LayerBase const * const layer = currentLayers[i];
+ const Layer::State& s = layer->drawingState();
+ snprintf(buffer, SIZE,
+ "+ %s %p\n"
+ " "
+ "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
+ "needsBlending=%1d, invalidate=%1d, "
+ "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
+ layer->getTypeID(), layer,
+ s.z, layer->tx(), layer->ty(), s.w, s.h,
+ layer->needsBlending(), layer->invalidate,
+ s.alpha, s.flags,
+ s.transform[0], s.transform[1],
+ s.transform[2], s.transform[3]);
+ result.append(buffer);
+ buffer[0] = 0;
+ /*** LayerBaseClient ***/
+ LayerBaseClient* const lbc =
+ LayerBase::dynamicCast<LayerBaseClient*>((LayerBase*)layer);
+ if (lbc) {
+ snprintf(buffer, SIZE,
+ " "
+ "id=0x%08x, client=0x%08x, identity=%u\n",
+ lbc->clientIndex(), lbc->client ? lbc->client->cid : 0,
+ lbc->getIdentity());
+ }
+ result.append(buffer);
+ buffer[0] = 0;
+ /*** LayerBuffer ***/
+ LayerBuffer* const lbuf =
+ LayerBase::dynamicCast<LayerBuffer*>((LayerBase*)layer);
+ if (lbuf) {
+ sp<LayerBuffer::Buffer> lbb(lbuf->getBuffer());
+ if (lbb != 0) {
+ const LayerBuffer::NativeBuffer& nbuf(lbb->getBuffer());
+ snprintf(buffer, SIZE,
+ " "
+ "mBuffer={w=%u, h=%u, f=%d, offset=%u, base=%p, fd=%d }\n",
+ nbuf.img.w, nbuf.img.h, nbuf.img.format, nbuf.img.offset,
+ nbuf.img.base, nbuf.img.fd);
+ }
+ }
+ result.append(buffer);
+ buffer[0] = 0;
+ /*** Layer ***/
+ Layer* const l = LayerBase::dynamicCast<Layer*>((LayerBase*)layer);
+ if (l) {
+ const LayerBitmap& buf0(l->getBuffer(0));
+ const LayerBitmap& buf1(l->getBuffer(1));
+ snprintf(buffer, SIZE,
+ " "
+ "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u], mTextureName=%d,"
+ " freezeLock=%p, swapState=0x%08x\n",
+ l->pixelFormat(),
+ buf0.width(), buf0.height(), buf0.stride(),
+ buf1.width(), buf1.height(), buf1.stride(),
+ l->getTextureName(), l->getFreezeLock().get(),
+ l->lcblk->swapState);
+ }
+ result.append(buffer);
+ buffer[0] = 0;
+ s.transparentRegion.dump(result, "transparentRegion");
+ layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
+ layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
+ }
+ mWormholeRegion.dump(result, "WormholeRegion");
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ snprintf(buffer, SIZE,
+ " display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
+ mFreezeDisplay?"yes":"no", mFreezeCount,
+ mCurrentState.orientation, hw.canDraw());
+ result.append(buffer);
+
+ sp<AllocatorInterface> allocator;
+ if (mGPU != 0) {
+ snprintf(buffer, SIZE, " GPU owner: %d\n", mGPU->getOwner());
+ result.append(buffer);
+ allocator = mGPU->getAllocator();
+ if (allocator != 0) {
+ allocator->dump(result, "GPU Allocator");
+ }
+ }
+ allocator = mSurfaceHeapManager->getAllocator(NATIVE_MEMORY_TYPE_PMEM);
+ if (allocator != 0) {
+ allocator->dump(result, "PMEM Allocator");
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case CREATE_CONNECTION:
+ case OPEN_GLOBAL_TRANSACTION:
+ case CLOSE_GLOBAL_TRANSACTION:
+ case SET_ORIENTATION:
+ case FREEZE_DISPLAY:
+ case UNFREEZE_DISPLAY:
+ case BOOT_FINISHED:
+ case REVOKE_GPU:
+ {
+ // codes that require permission check
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int self_pid = getpid();
+ if (UNLIKELY(pid != self_pid)) {
+ // we're called from a different process, do the real check
+ if (!checkCallingPermission(
+ String16("android.permission.ACCESS_SURFACE_FLINGER")))
+ {
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ }
+ }
+
+ status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
+ if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
+ if (code == 1012) {
+ // take screen-shot of the front buffer
+ if (UNLIKELY(checkCallingPermission(
+ String16("android.permission.READ_FRAME_BUFFER")) == false))
+ { // not allowed
+ LOGE("Permission Denial: "
+ "can't take screenshots from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+
+ if (UNLIKELY(mSecureFrameBuffer)) {
+ LOGE("A secure window is on screen: "
+ "can't take screenshots from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+
+ LOGI("Taking a screenshot...");
+
+ LayerScreenshot* l = new LayerScreenshot(this, 0);
+
+ Mutex::Autolock _l(mStateLock);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ l->initStates(hw.getWidth(), hw.getHeight(), 0);
+ l->setLayer(INT_MAX);
+
+ addLayer_l(l);
+ setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
+
+ l->takeScreenshot(mStateLock, reply);
+
+ removeLayer_l(l);
+ setTransactionFlags(eTransactionNeeded);
+ return NO_ERROR;
+ } else {
+ // HARDWARE_TEST stuff...
+ if (UNLIKELY(checkCallingPermission(
+ String16("android.permission.HARDWARE_TEST")) == false))
+ { // not allowed
+ LOGE("Permission Denial: pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+ int n;
+ switch (code) {
+ case 1000: // SHOW_CPU
+ n = data.readInt32();
+ mDebugCpu = n ? 1 : 0;
+ if (mDebugCpu) {
+ if (mCpuGauge == 0) {
+ mCpuGauge = new CPUGauge(this, ms2ns(500));
+ }
+ } else {
+ if (mCpuGauge != 0) {
+ mCpuGauge->requestExitAndWait();
+ Mutex::Autolock _l(mDebugLock);
+ mCpuGauge.clear();
+ }
+ }
+ return NO_ERROR;
+ case 1001: // SHOW_FPS
+ n = data.readInt32();
+ mDebugFps = n ? 1 : 0;
+ return NO_ERROR;
+ case 1002: // SHOW_UPDATES
+ n = data.readInt32();
+ mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
+ return NO_ERROR;
+ case 1003: // SHOW_BACKGROUND
+ n = data.readInt32();
+ mDebugBackground = n ? 1 : 0;
+ return NO_ERROR;
+ case 1004:{ // repaint everything
+ Mutex::Autolock _l(mStateLock);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
+ signalEvent();
+ }
+ return NO_ERROR;
+ case 1005: // ask GPU revoke
+ mGPU->friendlyRevoke();
+ return NO_ERROR;
+ case 1006: // revoke GPU
+ mGPU->unconditionalRevoke();
+ return NO_ERROR;
+ case 1007: // set mFreezeCount
+ mFreezeCount = data.readInt32();
+ return NO_ERROR;
+ case 1010: // interrogate.
+ reply->writeInt32(mDebugCpu);
+ reply->writeInt32(0);
+ reply->writeInt32(mDebugRegion);
+ reply->writeInt32(mDebugBackground);
+ return NO_ERROR;
+ case 1013: { // screenshot
+ Mutex::Autolock _l(mStateLock);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ reply->writeInt32(hw.getPageFlipCount());
+ }
+ return NO_ERROR;
+ }
+ }
+ }
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
+ : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
+{
+ mSharedHeapAllocator = getSurfaceHeapManager()->createHeap(NATIVE_MEMORY_TYPE_HEAP);
+ const int pgsize = getpagesize();
+ const int cblksize=((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
+ mCblkHeap = new MemoryDealer(cblksize);
+ mCblkMemory = mCblkHeap->allocate(cblksize);
+ if (mCblkMemory != 0) {
+ ctrlblk = static_cast<per_client_cblk_t *>(mCblkMemory->pointer());
+ if (ctrlblk) { // construct the shared structure in-place.
+ new(ctrlblk) per_client_cblk_t;
+ }
+ }
+}
+
+Client::~Client() {
+ if (ctrlblk) {
+ const int pgsize = getpagesize();
+ ctrlblk->~per_client_cblk_t(); // destroy our shared-structure.
+ }
+}
+
+const sp<SurfaceHeapManager>& Client::getSurfaceHeapManager() const {
+ return mFlinger->getSurfaceHeapManager();
+}
+
+const sp<GPUHardwareInterface>& Client::getGPU() const {
+ return mFlinger->getGPU();
+}
+
+int32_t Client::generateId(int pid)
+{
+ const uint32_t i = clz( ~mBitmap );
+ if (i >= NUM_LAYERS_MAX) {
+ return NO_MEMORY;
+ }
+ mPid = pid;
+ mInUse.add(uint8_t(i));
+ mBitmap |= 1<<(31-i);
+ return i;
+}
+status_t Client::bindLayer(LayerBaseClient* layer, int32_t id)
+{
+ ssize_t idx = mInUse.indexOf(id);
+ if (idx < 0)
+ return NAME_NOT_FOUND;
+ return mLayers.insertAt(layer, idx);
+}
+void Client::free(int32_t id)
+{
+ ssize_t idx = mInUse.remove(uint8_t(id));
+ if (idx >= 0) {
+ mBitmap &= ~(1<<(31-id));
+ mLayers.removeItemsAt(idx);
+ }
+}
+
+sp<MemoryDealer> Client::createAllocator(int memory_type)
+{
+ sp<MemoryDealer> allocator;
+ if (memory_type == NATIVE_MEMORY_TYPE_GPU) {
+ allocator = getGPU()->request(getClientPid());
+ if (allocator == 0)
+ memory_type = NATIVE_MEMORY_TYPE_PMEM;
+ }
+ if (memory_type == NATIVE_MEMORY_TYPE_PMEM) {
+ allocator = mPMemAllocator;
+ if (allocator == 0) {
+ allocator = getSurfaceHeapManager()->createHeap(
+ NATIVE_MEMORY_TYPE_PMEM);
+ mPMemAllocator = allocator;
+ }
+ }
+ if (allocator == 0)
+ allocator = mSharedHeapAllocator;
+
+ return allocator;
+}
+
+bool Client::isValid(int32_t i) const {
+ return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i)));
+}
+const uint8_t* Client::inUseArray() const {
+ return mInUse.array();
+}
+size_t Client::numActiveLayers() const {
+ return mInUse.size();
+}
+LayerBaseClient* Client::getLayerUser(int32_t i) const {
+ ssize_t idx = mInUse.indexOf(uint8_t(i));
+ if (idx<0) return 0;
+ return mLayers[idx];
+}
+
+void Client::dump(const char* what)
+{
+}
+
+// ---------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemory>& cblk)
+ : mId(cid), mFlinger(flinger), mCblk(cblk)
+{
+}
+
+BClient::~BClient() {
+ // destroy all resources attached to this client
+ mFlinger->destroyConnection(mId);
+}
+
+void BClient::getControlBlocks(sp<IMemory>* ctrl) const {
+ *ctrl = mCblk;
+}
+
+sp<ISurface> BClient::createSurface(
+ ISurfaceFlingerClient::surface_data_t* params, int pid,
+ DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags)
+{
+ return mFlinger->createSurface(mId, pid, params, display, w, h, format, flags);
+}
+
+status_t BClient::destroySurface(SurfaceID sid)
+{
+ sid |= (mId << 16); // add the client-part to id
+ return mFlinger->destroySurface(sid);
+}
+
+status_t BClient::setState(int32_t count, const layer_state_t* states)
+{
+ return mFlinger->setClientState(mId, count, states);
+}
+
+// ---------------------------------------------------------------------------
+
+GraphicPlane::GraphicPlane()
+ : mHw(0)
+{
+}
+
+GraphicPlane::~GraphicPlane() {
+ delete mHw;
+}
+
+bool GraphicPlane::initialized() const {
+ return mHw ? true : false;
+}
+
+void GraphicPlane::setDisplayHardware(DisplayHardware *hw) {
+ mHw = hw;
+}
+
+void GraphicPlane::setTransform(const Transform& tr) {
+ mTransform = tr;
+ mGlobalTransform = mOrientationTransform * mTransform;
+}
+
+status_t GraphicPlane::setOrientation(int orientation)
+{
+ float a, b, c, d, x, y;
+
+ const DisplayHardware& hw(displayHardware());
+ const float w = hw.getWidth();
+ const float h = hw.getHeight();
+
+ if (orientation == ISurfaceComposer::eOrientationDefault) {
+ // make sure the default orientation is optimal
+ mOrientationTransform.reset();
+ mGlobalTransform = mTransform;
+ return NO_ERROR;
+ }
+
+ // If the rotation can be handled in hardware, this is where
+ // the magic should happen.
+
+ switch (orientation) {
+ case ISurfaceComposer::eOrientation90:
+ a=0; b=-1; c=1; d=0; x=w; y=0;
+ break;
+ case ISurfaceComposer::eOrientation180:
+ a=-1; b=0; c=0; d=-1; x=w; y=h;
+ break;
+ case ISurfaceComposer::eOrientation270:
+ a=0; b=1; c=-1; d=0; x=0; y=h;
+ break;
+ case 42: {
+ const float r = (3.14159265f / 180.0f) * 42.0f;
+ const float si = sinf(r);
+ const float co = cosf(r);
+ a=co; b=-si; c=si; d=co;
+ x = si*(h*0.5f) + (1-co)*(w*0.5f);
+ y =-si*(w*0.5f) + (1-co)*(h*0.5f);
+ } break;
+ default:
+ return BAD_VALUE;
+ }
+ mOrientationTransform.set(a, b, c, d);
+ mOrientationTransform.set(x, y);
+ mGlobalTransform = mOrientationTransform * mTransform;
+ return NO_ERROR;
+}
+
+const DisplayHardware& GraphicPlane::displayHardware() const {
+ return *mHw;
+}
+
+const Transform& GraphicPlane::transform() const {
+ return mGlobalTransform;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
new file mode 100644
index 0000000..1581474
--- /dev/null
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_SURFACE_FLINGER_H
+#define ANDROID_SURFACE_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/MemoryDealer.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+
+#include <private/ui/SharedState.h>
+#include <private/ui/LayerState.h>
+#include <private/ui/SurfaceFlingerSynchro.h>
+
+#include "Layer.h"
+#include "Tokenizer.h"
+#include "CPUGauge.h"
+#include "BootAnimation.h"
+#include "Barrier.h"
+
+struct copybit_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class BClient;
+class Client;
+class DisplayHardware;
+class GPUHardwareInterface;
+class IGPUCallback;
+class Layer;
+class LayerBuffer;
+class RFBServer;
+class SurfaceHeapManager;
+class FreezeLock;
+
+typedef int32_t ClientID;
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+class Client
+{
+public:
+ Client(ClientID cid, const sp<SurfaceFlinger>& flinger);
+ ~Client();
+
+ int32_t generateId(int pid);
+ void free(int32_t id);
+ status_t bindLayer(LayerBaseClient* layer, int32_t id);
+ sp<MemoryDealer> createAllocator(int memory_type);
+
+ inline bool isValid(int32_t i) const;
+ inline const uint8_t* inUseArray() const;
+ inline size_t numActiveLayers() const;
+ LayerBaseClient* getLayerUser(int32_t i) const;
+ const Vector<LayerBaseClient*>& getLayers() const { return mLayers; }
+ const sp<IMemory>& controlBlockMemory() const { return mCblkMemory; }
+ void dump(const char* what);
+ const sp<SurfaceHeapManager>& getSurfaceHeapManager() const;
+
+ // pointer to this client's control block
+ per_client_cblk_t* ctrlblk;
+ ClientID cid;
+
+
+private:
+ int getClientPid() const { return mPid; }
+ const sp<GPUHardwareInterface>& getGPU() const;
+
+ int mPid;
+ uint32_t mBitmap;
+ SortedVector<uint8_t> mInUse;
+ Vector<LayerBaseClient*> mLayers;
+ sp<MemoryDealer> mCblkHeap;
+ sp<SurfaceFlinger> mFlinger;
+ sp<MemoryDealer> mSharedHeapAllocator;
+ sp<MemoryDealer> mPMemAllocator;
+ sp<IMemory> mCblkMemory;
+};
+
+// ---------------------------------------------------------------------------
+
+class GraphicPlane
+{
+public:
+
+ GraphicPlane();
+ ~GraphicPlane();
+
+ bool initialized() const;
+
+ void setDisplayHardware(DisplayHardware *);
+ void setTransform(const Transform& tr);
+ status_t setOrientation(int orientation);
+
+ const DisplayHardware& displayHardware() const;
+ const Transform& transform() const;
+private:
+ GraphicPlane(const GraphicPlane&);
+ GraphicPlane operator = (const GraphicPlane&);
+
+ DisplayHardware* mHw;
+ Transform mTransform;
+ Transform mOrientationTransform;
+ Transform mGlobalTransform;
+};
+
+// ---------------------------------------------------------------------------
+
+enum {
+ eTransactionNeeded = 0x01,
+ eTraversalNeeded = 0x02
+};
+
+class SurfaceFlinger : public BnSurfaceComposer, protected Thread
+{
+public:
+ static void instantiate();
+ static void shutdown();
+
+ SurfaceFlinger();
+ virtual ~SurfaceFlinger();
+ void init();
+
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ // ISurfaceComposer interface
+ virtual sp<ISurfaceFlingerClient> createConnection();
+ virtual sp<IMemory> getCblk() const;
+ virtual void bootFinished();
+ virtual void openGlobalTransaction();
+ virtual void closeGlobalTransaction();
+ virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags);
+ virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
+ virtual int setOrientation(DisplayID dpy, int orientation);
+ virtual void signal() const;
+ virtual status_t requestGPU(const sp<IGPUCallback>& callback,
+ gpu_info_t* gpu);
+ virtual status_t revokeGPU();
+
+ void screenReleased(DisplayID dpy);
+ void screenAcquired(DisplayID dpy);
+
+ const sp<SurfaceHeapManager>& getSurfaceHeapManager() const {
+ return mSurfaceHeapManager;
+ }
+
+ const sp<GPUHardwareInterface>& getGPU() const {
+ return mGPU;
+ }
+
+ copybit_t* getBlitEngine() const;
+
+private:
+ friend class BClient;
+ friend class LayerBase;
+ friend class LayerBuffer;
+ friend class LayerBaseClient;
+ friend class Layer;
+ friend class LayerBlur;
+
+ sp<ISurface> createSurface(ClientID client, int pid,
+ ISurfaceFlingerClient::surface_data_t* params,
+ DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags);
+
+ LayerBaseClient* createNormalSurfaceLocked(Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+
+ LayerBaseClient* createBlurSurfaceLocked(Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+
+ LayerBaseClient* createDimSurfaceLocked(Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+
+ LayerBaseClient* createPushBuffersSurfaceLocked(Client* client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags);
+
+ status_t destroySurface(SurfaceID surface_id);
+ status_t setClientState(ClientID cid, int32_t count, const layer_state_t* states);
+
+
+ class LayerVector {
+ public:
+ inline LayerVector() { }
+ LayerVector(const LayerVector&);
+ inline size_t size() const { return layers.size(); }
+ inline LayerBase*const* array() const { return layers.array(); }
+ ssize_t add(LayerBase*, Vector<LayerBase*>::compar_t);
+ ssize_t remove(LayerBase*);
+ ssize_t reorder(LayerBase*, Vector<LayerBase*>::compar_t);
+ ssize_t indexOf(LayerBase* key, size_t guess=0) const;
+ inline LayerBase* operator [] (size_t i) const { return layers[i]; }
+ private:
+ KeyedVector<LayerBase*, size_t> lookup;
+ Vector<LayerBase*> layers;
+ };
+
+ struct State {
+ State() {
+ orientation = ISurfaceComposer::eOrientationDefault;
+ freezeDisplay = 0;
+ }
+ LayerVector layersSortedByZ;
+ uint8_t orientation;
+ uint8_t freezeDisplay;
+ };
+
+ class DelayedTransaction : public Thread
+ {
+ friend class SurfaceFlinger;
+ sp<SurfaceFlinger> mFlinger;
+ nsecs_t mDelay;
+ public:
+ DelayedTransaction(const sp<SurfaceFlinger>& flinger, nsecs_t delay)
+ : Thread(false), mFlinger(flinger), mDelay(delay) {
+ }
+ virtual bool threadLoop() {
+ usleep(mDelay / 1000);
+ if (android_atomic_and(~1,
+ &mFlinger->mDeplayedTransactionPending) == 1) {
+ mFlinger->signalEvent();
+ }
+ return false;
+ }
+ };
+
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+ const GraphicPlane& graphicPlane(int dpy) const;
+ GraphicPlane& graphicPlane(int dpy);
+
+ void waitForEvent();
+ void signalEvent();
+ void signalDelayedEvent(nsecs_t delay);
+
+ void handleConsoleEvents();
+ void handleTransaction(uint32_t transactionFlags);
+
+ void computeVisibleRegions(
+ LayerVector& currentLayers,
+ Region& dirtyRegion,
+ Region& wormholeRegion);
+
+ void handlePageFlip();
+ bool lockPageFlip(const LayerVector& currentLayers);
+ void unlockPageFlip(const LayerVector& currentLayers);
+ void handleRepaint();
+ void handleDebugCpu();
+ void scheduleBroadcast(Client* client);
+ void executeScheduledBroadcasts();
+ void postFramebuffer();
+ void composeSurfaces(const Region& dirty);
+ void unlockClients();
+
+
+ void destroyConnection(ClientID cid);
+ LayerBaseClient* getLayerUser_l(SurfaceID index) const;
+ status_t addLayer_l(LayerBase* layer);
+ status_t removeLayer_l(LayerBase* layer);
+ void destroy_all_removed_layers_l();
+ void free_resources_l();
+
+ uint32_t getTransactionFlags(uint32_t flags);
+ uint32_t setTransactionFlags(uint32_t flags, nsecs_t delay = 0);
+ void commitTransaction();
+
+
+ friend class FreezeLock;
+ sp<FreezeLock> getFreezeLock() const;
+ inline void incFreezeCount() { mFreezeCount++; }
+ inline void decFreezeCount() { if (mFreezeCount > 0) mFreezeCount--; }
+ inline bool hasFreezeRequest() const { return mFreezeDisplay; }
+ inline bool isFrozen() const {
+ return mFreezeDisplay || mFreezeCount>0;
+ }
+
+
+ void debugFlashRegions();
+ void debugShowFPS() const;
+ void drawWormhole() const;
+
+ // access must be protected by mStateLock
+ mutable Mutex mStateLock;
+ State mCurrentState;
+ State mDrawingState;
+ volatile int32_t mTransactionFlags;
+ volatile int32_t mTransactionCount;
+ Condition mTransactionCV;
+
+ // protected by mStateLock (but we could use another lock)
+ Tokenizer mTokens;
+ DefaultKeyedVector<ClientID, Client*> mClientsMap;
+ DefaultKeyedVector<SurfaceID, LayerBaseClient*> mLayerMap;
+ GraphicPlane mGraphicPlanes[1];
+ SortedVector<LayerBase*> mRemovedLayers;
+ Vector<Client*> mDisconnectedClients;
+
+ // constant members (no synchronization needed for access)
+ sp<MemoryDealer> mServerHeap;
+ sp<IMemory> mServerCblkMemory;
+ surface_flinger_cblk_t* mServerCblk;
+ sp<SurfaceHeapManager> mSurfaceHeapManager;
+ sp<GPUHardwareInterface> mGPU;
+ GLuint mWormholeTexName;
+ sp<BootAnimation> mBootAnimation;
+ sp<RFBServer> mRFBServer;
+ nsecs_t mBootTime;
+
+ // Can only accessed from the main thread, these members
+ // don't need synchronization
+ Region mDirtyRegion;
+ Region mInvalidRegion;
+ Region mWormholeRegion;
+ Client* mLastScheduledBroadcast;
+ SortedVector<Client*> mScheduledBroadcasts;
+ bool mVisibleRegionsDirty;
+ bool mDeferReleaseConsole;
+ bool mFreezeDisplay;
+ int32_t mFreezeCount;
+ nsecs_t mFreezeDisplayTime;
+
+ // access protected by mDebugLock
+ mutable Mutex mDebugLock;
+ sp<CPUGauge> mCpuGauge;
+
+ // don't use a lock for these, we don't care
+ int mDebugRegion;
+ int mDebugCpu;
+ int mDebugFps;
+ int mDebugBackground;
+ int mDebugNoBootAnimation;
+
+ // these are thread safe
+ mutable Barrier mReadyToRunBarrier;
+ mutable SurfaceFlingerSynchro mSyncObject;
+ volatile int32_t mDeplayedTransactionPending;
+
+ // atomic variables
+ enum {
+ eConsoleReleased = 1,
+ eConsoleAcquired = 2
+ };
+ volatile int32_t mConsoleSignals;
+
+ // only written in the main thread, only read in other threads
+ volatile int32_t mSecureFrameBuffer;
+};
+
+// ---------------------------------------------------------------------------
+
+class FreezeLock {
+ SurfaceFlinger* mFlinger;
+ mutable volatile int32_t mCount;
+public:
+ FreezeLock(SurfaceFlinger* flinger)
+ : mFlinger(flinger), mCount(0) {
+ mFlinger->incFreezeCount();
+ }
+ ~FreezeLock() {
+ mFlinger->decFreezeCount();
+ }
+ inline void incStrong(void*) const {
+ android_atomic_inc(&mCount);
+ }
+ inline void decStrong(void*) const {
+ if (android_atomic_dec(&mCount) == 1)
+ delete this;
+ }
+};
+
+// ---------------------------------------------------------------------------
+
+class BClient : public BnSurfaceFlingerClient
+{
+public:
+ BClient(SurfaceFlinger *flinger, ClientID cid,
+ const sp<IMemory>& cblk);
+ ~BClient();
+
+ // ISurfaceFlingerClient interface
+ virtual void getControlBlocks(sp<IMemory>* ctrl) const;
+
+ virtual sp<ISurface> createSurface(
+ surface_data_t* params, int pid,
+ DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
+ uint32_t flags);
+
+ virtual status_t destroySurface(SurfaceID surfaceId);
+ virtual status_t setState(int32_t count, const layer_state_t* states);
+
+private:
+ ClientID mId;
+ SurfaceFlinger* mFlinger;
+ sp<IMemory> mCblk;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SURFACE_FLINGER_H
diff --git a/libs/surfaceflinger/Tokenizer.cpp b/libs/surfaceflinger/Tokenizer.cpp
new file mode 100644
index 0000000..ef51d6a
--- /dev/null
+++ b/libs/surfaceflinger/Tokenizer.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <stdio.h>
+
+#include "Tokenizer.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+ANDROID_BASIC_TYPES_TRAITS(Tokenizer::run_t)
+
+Tokenizer::Tokenizer()
+{
+}
+
+Tokenizer::Tokenizer(const Tokenizer& other)
+ : mRanges(other.mRanges)
+{
+}
+
+Tokenizer::~Tokenizer()
+{
+}
+
+uint32_t Tokenizer::acquire()
+{
+ if (!mRanges.size() || mRanges[0].first) {
+ _insertTokenAt(0,0);
+ return 0;
+ }
+
+ // just extend the first run
+ const run_t& run = mRanges[0];
+ uint32_t token = run.first + run.length;
+ _insertTokenAt(token, 1);
+ return token;
+}
+
+bool Tokenizer::isAcquired(uint32_t token) const
+{
+ return (_indexOrderOf(token) >= 0);
+}
+
+status_t Tokenizer::reserve(uint32_t token)
+{
+ size_t o;
+ const ssize_t i = _indexOrderOf(token, &o);
+ if (i >= 0) {
+ return BAD_VALUE; // this token is already taken
+ }
+ ssize_t err = _insertTokenAt(token, o);
+ return (err<0) ? err : status_t(NO_ERROR);
+}
+
+status_t Tokenizer::release(uint32_t token)
+{
+ const ssize_t i = _indexOrderOf(token);
+ if (i >= 0) {
+ const run_t& run = mRanges[i];
+ if ((token >= run.first) && (token < run.first+run.length)) {
+ // token in this range, we need to split
+ run_t& run = mRanges.editItemAt(i);
+ if ((token == run.first) || (token == run.first+run.length-1)) {
+ if (token == run.first) {
+ run.first += 1;
+ }
+ run.length -= 1;
+ if (run.length == 0) {
+ // XXX: should we systematically remove a run that's empty?
+ mRanges.removeItemsAt(i);
+ }
+ } else {
+ // split the run
+ run_t new_run;
+ new_run.first = token+1;
+ new_run.length = run.first+run.length - new_run.first;
+ run.length = token - run.first;
+ mRanges.insertAt(new_run, i+1);
+ }
+ return NO_ERROR;
+ }
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t Tokenizer::_indexOrderOf(uint32_t token, size_t* order) const
+{
+ // binary search
+ ssize_t err = NAME_NOT_FOUND;
+ ssize_t l = 0;
+ ssize_t h = mRanges.size()-1;
+ ssize_t mid;
+ const run_t* a = mRanges.array();
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const run_t* const curr = a + mid;
+ int c = 0;
+ if (token < curr->first) c = 1;
+ else if (token >= curr->first+curr->length) c = -1;
+ if (c == 0) {
+ err = l = mid;
+ break;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ if (order) *order = l;
+ return err;
+}
+
+ssize_t Tokenizer::_insertTokenAt(uint32_t token, size_t index)
+{
+ const size_t c = mRanges.size();
+
+ if (index >= 1) {
+ // do we need to merge with the previous run?
+ run_t& p = mRanges.editItemAt(index-1);
+ if (p.first+p.length == token) {
+ p.length += 1;
+ if (index < c) {
+ const run_t& n = mRanges[index];
+ if (token+1 == n.first) {
+ p.length += n.length;
+ mRanges.removeItemsAt(index);
+ }
+ }
+ return index;
+ }
+ }
+
+ if (index < c) {
+ // do we need to merge with the next run?
+ run_t& n = mRanges.editItemAt(index);
+ if (token+1 == n.first) {
+ n.first -= 1;
+ n.length += 1;
+ return index;
+ }
+ }
+
+ return mRanges.insertAt(run_t(token,1), index);
+}
+
+void Tokenizer::dump() const
+{
+ const run_t* ranges = mRanges.array();
+ const size_t c = mRanges.size();
+ printf("Tokenizer (%p, size = %lu)\n", this, c);
+ for (size_t i=0 ; i<c ; i++) {
+ printf("%lu: (%u, %u)\n", i, ranges[i].first, ranges[i].length);
+ }
+}
+
+}; // namespace android
+
diff --git a/libs/surfaceflinger/Tokenizer.h b/libs/surfaceflinger/Tokenizer.h
new file mode 100644
index 0000000..6b3057d
--- /dev/null
+++ b/libs/surfaceflinger/Tokenizer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_TOKENIZER_H
+#define ANDROID_TOKENIZER_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+class Tokenizer
+{
+public:
+ Tokenizer();
+ Tokenizer(const Tokenizer& other);
+ ~Tokenizer();
+
+ uint32_t acquire();
+ status_t reserve(uint32_t token);
+ status_t release(uint32_t token);
+ bool isAcquired(uint32_t token) const;
+
+ void dump() const;
+
+ struct run_t {
+ run_t() {};
+ run_t(uint32_t f, uint32_t l) : first(f), length(l) {}
+ uint32_t first;
+ uint32_t length;
+ };
+private:
+ ssize_t _indexOrderOf(uint32_t token, size_t* order=0) const;
+ ssize_t _insertTokenAt(uint32_t token, size_t index);
+ Vector<run_t> mRanges;
+};
+
+}; // namespace android
+
+// ----------------------------------------------------------------------------
+
+#endif // ANDROID_TOKENIZER_H
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
new file mode 100644
index 0000000..bec7a64
--- /dev/null
+++ b/libs/surfaceflinger/Transform.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <ui/Region.h>
+
+#include <private/pixelflinger/ggl_fixed.h>
+
+#include "Transform.h"
+
+// ---------------------------------------------------------------------------
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+Transform::Transform()
+ : mType(0)
+{
+ mTransform.reset();
+}
+
+Transform::Transform(const Transform& other)
+ : mTransform(other.mTransform), mType(other.mType)
+{
+}
+
+Transform::~Transform() {
+}
+
+Transform Transform::operator * (const Transform& rhs) const
+{
+ if (LIKELY(mType == 0))
+ return rhs;
+
+ Transform r(*this);
+ r.mTransform.preConcat(rhs.mTransform);
+ r.mType |= rhs.mType;
+ return r;
+}
+
+float Transform::operator [] (int i) const
+{
+ float r = 0;
+ switch(i) {
+ case 0: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleX] ); break;
+ case 1: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewX] ); break;
+ case 2: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewY] ); break;
+ case 3: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleY] ); break;
+ }
+ return r;
+}
+
+uint8_t Transform::type() const
+{
+ if (UNLIKELY(mType & 0x80000000)) {
+ mType = mTransform.getType();
+ }
+ return uint8_t(mType & 0xFF);
+}
+
+bool Transform::transformed() const {
+ return type() > SkMatrix::kTranslate_Mask;
+}
+
+int Transform::tx() const {
+ return SkScalarRound( mTransform[SkMatrix::kMTransX] );
+}
+
+int Transform::ty() const {
+ return SkScalarRound( mTransform[SkMatrix::kMTransY] );
+}
+
+void Transform::reset() {
+ mTransform.reset();
+ mType = 0;
+}
+
+void Transform::set( float xx, float xy,
+ float yx, float yy)
+{
+ mTransform.set(SkMatrix::kMScaleX, SkFloatToScalar(xx));
+ mTransform.set(SkMatrix::kMSkewX, SkFloatToScalar(xy));
+ mTransform.set(SkMatrix::kMSkewY, SkFloatToScalar(yx));
+ mTransform.set(SkMatrix::kMScaleY, SkFloatToScalar(yy));
+ mType |= 0x80000000;
+}
+
+void Transform::set(int tx, int ty)
+{
+ if (tx | ty) {
+ mTransform.set(SkMatrix::kMTransX, SkIntToScalar(tx));
+ mTransform.set(SkMatrix::kMTransY, SkIntToScalar(ty));
+ mType |= SkMatrix::kTranslate_Mask;
+ } else {
+ mTransform.set(SkMatrix::kMTransX, 0);
+ mTransform.set(SkMatrix::kMTransY, 0);
+ mType &= ~SkMatrix::kTranslate_Mask;
+ }
+}
+
+void Transform::transform(GLfixed* point, int x, int y) const
+{
+ SkPoint s;
+ mTransform.mapXY(SkIntToScalar(x), SkIntToScalar(y), &s);
+ point[0] = SkScalarToFixed(s.fX);
+ point[1] = SkScalarToFixed(s.fY);
+}
+
+Rect Transform::makeBounds(int w, int h) const
+{
+ Rect r;
+ SkRect d, s;
+ s.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
+ mTransform.mapRect(&d, s);
+ r.left = SkScalarRound( d.fLeft );
+ r.top = SkScalarRound( d.fTop );
+ r.right = SkScalarRound( d.fRight );
+ r.bottom = SkScalarRound( d.fBottom );
+ return r;
+}
+
+Rect Transform::transform(const Rect& bounds) const
+{
+ Rect r;
+ SkRect d, s;
+ s.set( SkIntToScalar( bounds.left ),
+ SkIntToScalar( bounds.top ),
+ SkIntToScalar( bounds.right ),
+ SkIntToScalar( bounds.bottom ));
+ mTransform.mapRect(&d, s);
+ r.left = SkScalarRound( d.fLeft );
+ r.top = SkScalarRound( d.fTop );
+ r.right = SkScalarRound( d.fRight );
+ r.bottom = SkScalarRound( d.fBottom );
+ return r;
+}
+
+Region Transform::transform(const Region& reg) const
+{
+ Region out;
+ if (UNLIKELY(transformed())) {
+ if (LIKELY(preserveRects())) {
+ Rect r;
+ Region::iterator iterator(reg);
+ while (iterator.iterate(&r)) {
+ out.orSelf(transform(r));
+ }
+ } else {
+ out.set(transform(reg.bounds()));
+ }
+ } else {
+ out = reg.translate(tx(), ty());
+ }
+ return out;
+}
+
+int32_t Transform::getOrientation() const
+{
+ uint32_t flags = 0;
+ if (UNLIKELY(transformed())) {
+ SkScalar a = mTransform[SkMatrix::kMScaleX];
+ SkScalar b = mTransform[SkMatrix::kMSkewX];
+ SkScalar c = mTransform[SkMatrix::kMSkewY];
+ SkScalar d = mTransform[SkMatrix::kMScaleY];
+ if (b==0 && c==0 && a && d) {
+ if (a<0) flags |= FLIP_H;
+ if (d<0) flags |= FLIP_V;
+ } else if (b && c && a==0 && d==0) {
+ flags |= ROT_90;
+ if (b>0) flags |= FLIP_H;
+ if (c<0) flags |= FLIP_V;
+ } else {
+ flags = 0x80000000;
+ }
+ }
+ return flags;
+}
+
+bool Transform::preserveRects() const
+{
+ return mTransform.rectStaysRect();
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h
new file mode 100644
index 0000000..2f617c4
--- /dev/null
+++ b/libs/surfaceflinger/Transform.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_TRANSFORM_H
+#define ANDROID_TRANSFORM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/Point.h>
+#include <ui/Rect.h>
+
+#include <GLES/gl.h>
+
+#include <corecg/SkMatrix.h>
+
+namespace android {
+
+class Region;
+
+// ---------------------------------------------------------------------------
+
+class Transform
+{
+public:
+ Transform();
+ Transform(const Transform& other);
+ ~Transform();
+
+ enum orientation_flags {
+ ROT_0 = 0x00000000,
+ FLIP_H = 0x00000001,
+ FLIP_V = 0x00000002,
+ ROT_90 = 0x00000004,
+ ROT_180 = FLIP_H|FLIP_V,
+ ROT_270 = ROT_180|ROT_90,
+ ROT_INVALID = 0x80000000
+ };
+
+ bool transformed() const;
+ int32_t getOrientation() const;
+ bool preserveRects() const;
+
+ int tx() const;
+ int ty() const;
+
+ void reset();
+ void set(float xx, float xy, float yx, float yy);
+ void set(int tx, int ty);
+
+ Rect makeBounds(int w, int h) const;
+ void transform(GLfixed* point, int x, int y) const;
+ Region transform(const Region& reg) const;
+ Rect transform(const Rect& bounds) const;
+
+ Transform operator * (const Transform& rhs) const;
+ float operator [] (int i) const;
+
+ inline uint32_t getType() const { return type(); }
+
+ inline Transform(bool) : mType(0xFF) { };
+
+private:
+ uint8_t type() const;
+
+private:
+ SkMatrix mTransform;
+ mutable uint32_t mType;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_TRANSFORM_H */
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
new file mode 100644
index 0000000..3852d51
--- /dev/null
+++ b/libs/surfaceflinger/VRamHeap.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapPmem.h>
+#include <utils/MemoryHeapBase.h>
+
+#include <GLES/eglnatives.h>
+
+#include "VRamHeap.h"
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+/*
+ * Amount of memory we reserve for surface, per client in PMEM
+ * (PMEM is used for 2D acceleration)
+ * 8 MB of address space per client should be enough.
+ */
+static const int PMEM_SIZE = int(8 * 1024 * 1024);
+
+int SurfaceHeapManager::global_pmem_heap = 0;
+
+// ---------------------------------------------------------------------------
+
+SurfaceHeapManager::SurfaceHeapManager(size_t clientHeapSize)
+ : mClientHeapSize(clientHeapSize)
+{
+ SurfaceHeapManager::global_pmem_heap = 1;
+}
+
+SurfaceHeapManager::~SurfaceHeapManager()
+{
+}
+
+void SurfaceHeapManager::onFirstRef()
+{
+ if (global_pmem_heap) {
+ const char* device = "/dev/pmem";
+ mPMemHeap = new PMemHeap(device, PMEM_SIZE);
+ if (mPMemHeap->base() == MAP_FAILED) {
+ mPMemHeap.clear();
+ global_pmem_heap = 0;
+ }
+ }
+}
+
+sp<MemoryDealer> SurfaceHeapManager::createHeap(int type)
+{
+ if (!global_pmem_heap && type==NATIVE_MEMORY_TYPE_PMEM)
+ type = NATIVE_MEMORY_TYPE_HEAP;
+
+ const sp<PMemHeap>& heap(mPMemHeap);
+ sp<MemoryDealer> dealer;
+ switch (type) {
+ case NATIVE_MEMORY_TYPE_HEAP:
+ dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
+ break;
+
+ case NATIVE_MEMORY_TYPE_PMEM:
+ if (heap != 0) {
+ dealer = new MemoryDealer(
+ heap->createClientHeap(),
+ heap->getAllocator());
+ }
+ break;
+ }
+ return dealer;
+}
+
+sp<SimpleBestFitAllocator> SurfaceHeapManager::getAllocator(int type) const
+{
+ Mutex::Autolock _l(mLock);
+ sp<SimpleBestFitAllocator> allocator;
+
+ // this is only used for debugging
+ switch (type) {
+ case NATIVE_MEMORY_TYPE_PMEM:
+ if (mPMemHeap != 0) {
+ allocator = mPMemHeap->getAllocator();
+ }
+ break;
+ }
+ return allocator;
+}
+
+// ---------------------------------------------------------------------------
+
+PMemHeapInterface::PMemHeapInterface(int fd, size_t size)
+ : MemoryHeapBase(fd, size) {
+}
+PMemHeapInterface::PMemHeapInterface(const char* device, size_t size)
+ : MemoryHeapBase(device, size) {
+}
+PMemHeapInterface::PMemHeapInterface(size_t size, uint32_t flags, char const * name)
+ : MemoryHeapBase(size, flags, name) {
+}
+PMemHeapInterface::~PMemHeapInterface() {
+}
+
+// ---------------------------------------------------------------------------
+
+PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
+ : PMemHeapInterface(device, size)
+{
+ //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
+ if (base() != MAP_FAILED) {
+ //LOGD("%s, %u bytes", device, virtualSize());
+ if (reserved == 0)
+ reserved = virtualSize();
+ mAllocator = new SimpleBestFitAllocator(reserved);
+ }
+}
+
+PMemHeap::~PMemHeap() {
+ //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
+}
+
+sp<MemoryHeapPmem> PMemHeap::createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new MemoryHeapPmem(parentHeap);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/VRamHeap.h b/libs/surfaceflinger/VRamHeap.h
new file mode 100644
index 0000000..03e0336
--- /dev/null
+++ b/libs/surfaceflinger/VRamHeap.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_VRAM_HEAP_H
+#define ANDROID_VRAM_HEAP_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/MemoryDealer.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class PMemHeap;
+class MemoryHeapPmem;
+
+// ---------------------------------------------------------------------------
+
+class SurfaceHeapManager : public RefBase
+{
+public:
+ SurfaceHeapManager(size_t clientHeapSize);
+ virtual ~SurfaceHeapManager();
+ virtual void onFirstRef();
+ sp<MemoryDealer> createHeap(int type);
+
+ // used for debugging only...
+ sp<SimpleBestFitAllocator> getAllocator(int type) const;
+
+private:
+ sp<PMemHeap> getHeap(int type) const;
+
+ mutable Mutex mLock;
+ size_t mClientHeapSize;
+ sp<PMemHeap> mPMemHeap;
+ static int global_pmem_heap;
+};
+
+// ---------------------------------------------------------------------------
+
+class PMemHeapInterface : public MemoryHeapBase
+{
+public:
+ PMemHeapInterface(int fd, size_t size);
+ PMemHeapInterface(const char* device, size_t size = 0);
+ PMemHeapInterface(size_t size, uint32_t flags = 0, char const * name = NULL);
+ virtual ~PMemHeapInterface();
+ virtual sp<MemoryHeapPmem> createClientHeap() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class PMemHeap : public PMemHeapInterface
+{
+public:
+ PMemHeap(const char* const vram,
+ size_t size=0, size_t reserved=0);
+ virtual ~PMemHeap();
+
+ virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
+ return mAllocator;
+ }
+ virtual sp<MemoryHeapPmem> createClientHeap();
+
+private:
+ sp<SimpleBestFitAllocator> mAllocator;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_VRAM_HEAP_H
diff --git a/libs/surfaceflinger/clz.cpp b/libs/surfaceflinger/clz.cpp
new file mode 100644
index 0000000..2456b86
--- /dev/null
+++ b/libs/surfaceflinger/clz.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "clz.h"
+
+namespace android {
+
+int clz_impl(int32_t x)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ return __builtin_clz(x);
+#else
+ if (!x) return 32;
+ int e = 31;
+ if (x&0xFFFF0000) { e -=16; x >>=16; }
+ if (x&0x0000FF00) { e -= 8; x >>= 8; }
+ if (x&0x000000F0) { e -= 4; x >>= 4; }
+ if (x&0x0000000C) { e -= 2; x >>= 2; }
+ if (x&0x00000002) { e -= 1; }
+ return e;
+#endif
+}
+
+}; // namespace android
diff --git a/libs/surfaceflinger/clz.h b/libs/surfaceflinger/clz.h
new file mode 100644
index 0000000..0ddf986
--- /dev/null
+++ b/libs/surfaceflinger/clz.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_SURFACE_FLINGER_CLZ_H
+
+#include <stdint.h>
+
+namespace android {
+
+int clz_impl(int32_t x);
+
+int inline clz(int32_t x)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ return __builtin_clz(x);
+#else
+ return clz_impl(x);
+#endif
+}
+
+
+}; // namespace android
+
+#endif /* ANDROID_SURFACE_FLINGER_CLZ_H */
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
new file mode 100644
index 0000000..71579c5
--- /dev/null
+++ b/libs/ui/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ BlitHardware.cpp \
+ Camera.cpp \
+ CameraParameters.cpp \
+ EGLDisplaySurface.cpp \
+ EGLNativeWindowSurface.cpp \
+ EventHub.cpp \
+ EventRecurrence.cpp \
+ KeyLayoutMap.cpp \
+ KeyCharacterMap.cpp \
+ ICamera.cpp \
+ ICameraClient.cpp \
+ ICameraService.cpp \
+ ISurfaceComposer.cpp \
+ ISurface.cpp \
+ ISurfaceFlingerClient.cpp \
+ LayerState.cpp \
+ PixelFormat.cpp \
+ Point.cpp \
+ Rect.cpp \
+ Region.cpp \
+ Surface.cpp \
+ SurfaceComposerClient.cpp \
+ SurfaceFlingerSynchro.cpp \
+ Time.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcorecg \
+ libcutils \
+ libutils \
+ libpixelflinger \
+ libhardware
+
+LOCAL_MODULE:= libui
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/ui/BlitHardware.cpp b/libs/ui/BlitHardware.cpp
new file mode 100644
index 0000000..90838b4
--- /dev/null
+++ b/libs/ui/BlitHardware.cpp
@@ -0,0 +1,446 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <cutils/log.h>
+
+#include <utils/Errors.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/fb.h>
+#include <linux/msm_mdp.h>
+#endif
+
+#include <ui/BlitHardware.h>
+
+/******************************************************************************/
+
+namespace android {
+class CopybitMSM7K : public copybit_t {
+public:
+ CopybitMSM7K();
+ ~CopybitMSM7K();
+
+ status_t getStatus() const {
+ if (mFD<0) return mFD;
+ return NO_ERROR;
+ }
+
+ status_t setParameter(int name, int value);
+
+ status_t get(int name);
+
+ status_t blit(
+ const copybit_image_t& dst,
+ const copybit_image_t& src,
+ copybit_region_t const* region);
+
+ status_t stretch(
+ const copybit_image_t& dst,
+ const copybit_image_t& src,
+ const copybit_rect_t& dst_rect,
+ const copybit_rect_t& src_rect,
+ copybit_region_t const* region);
+
+#if HAVE_ANDROID_OS
+private:
+ static int copybit_set_parameter(copybit_t* handle, int name, int value);
+ static int copybit_blit( copybit_t* handle,
+ copybit_image_t const* dst, copybit_image_t const* src,
+ copybit_region_t const* region);
+ static int copybit_stretch(copybit_t* handle,
+ copybit_image_t const* dst, copybit_image_t const* src,
+ copybit_rect_t const* dst_rect, copybit_rect_t const* src_rect,
+ copybit_region_t const* region);
+ static int copybit_get(copybit_t* handle, int name);
+
+ int getFormat(int format);
+ void setImage(mdp_img* img, const copybit_image_t& rhs);
+ void setRects(mdp_blit_req* req, const copybit_rect_t& dst,
+ const copybit_rect_t& src, const copybit_rect_t& scissor);
+ void setInfos(mdp_blit_req* req);
+ static void intersect(copybit_rect_t* out,
+ const copybit_rect_t& lhs, const copybit_rect_t& rhs);
+ status_t msm_copybit(void const* list);
+#endif
+ int mFD;
+ uint8_t mAlpha;
+ uint8_t mFlags;
+};
+}; // namespace android
+
+using namespace android;
+
+/******************************************************************************/
+
+struct copybit_t* copybit_init()
+{
+ CopybitMSM7K* engine = new CopybitMSM7K();
+ if (engine->getStatus() != NO_ERROR) {
+ delete engine;
+ engine = 0;
+ }
+ return (struct copybit_t*)engine;
+
+}
+
+int copybit_term(copybit_t* handle)
+{
+ delete static_cast<CopybitMSM7K*>(handle);
+ return NO_ERROR;
+}
+
+namespace android {
+/******************************************************************************/
+
+static inline
+int min(int a, int b) {
+ return (a<b) ? a : b;
+}
+
+static inline
+int max(int a, int b) {
+ return (a>b) ? a : b;
+}
+
+static inline
+void MULDIV(uint32_t& a, uint32_t& b, int mul, int div)
+{
+ if (mul != div) {
+ a = (mul * a) / div;
+ b = (mul * b) / div;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+#if HAVE_ANDROID_OS
+
+int CopybitMSM7K::copybit_set_parameter(copybit_t* handle, int name, int value)
+{
+ return static_cast<CopybitMSM7K*>(handle)->setParameter(name, value);
+}
+
+int CopybitMSM7K::copybit_get(copybit_t* handle, int name)
+{
+ return static_cast<CopybitMSM7K*>(handle)->get(name);
+}
+
+int CopybitMSM7K::copybit_blit(
+ copybit_t* handle,
+ copybit_image_t const* dst,
+ copybit_image_t const* src,
+ struct copybit_region_t const* region)
+{
+ return static_cast<CopybitMSM7K*>(handle)->blit(*dst, *src, region);
+}
+
+int CopybitMSM7K::copybit_stretch(
+ copybit_t* handle,
+ copybit_image_t const* dst,
+ copybit_image_t const* src,
+ copybit_rect_t const* dst_rect,
+ copybit_rect_t const* src_rect,
+ struct copybit_region_t const* region)
+{
+ return static_cast<CopybitMSM7K*>(handle)->stretch(
+ *dst, *src, *dst_rect, *src_rect, region);
+}
+
+//-----------------------------------------------------------------------------
+
+CopybitMSM7K::CopybitMSM7K()
+ : mFD(-1), mAlpha(MDP_ALPHA_NOP), mFlags(0)
+{
+ int fd = open("/dev/graphics/fb0", O_RDWR, 0);
+ if (fd > 0) {
+ struct fb_fix_screeninfo finfo;
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == 0) {
+ if (!strcmp(finfo.id, "msmfb")) {
+ mFD = fd;
+ copybit_t::set_parameter = copybit_set_parameter;
+ copybit_t::get = copybit_get;
+ copybit_t::blit = copybit_blit;
+ copybit_t::stretch = copybit_stretch;
+ }
+ }
+ }
+ if (fd<0 || mFD<0) {
+ if (fd>0) { close(fd); }
+ mFD = -errno;
+ }
+}
+
+CopybitMSM7K::~CopybitMSM7K()
+{
+ if (mFD > 0){
+ close(mFD);
+ }
+}
+
+status_t CopybitMSM7K::setParameter(int name, int value)
+{
+ switch(name) {
+ case COPYBIT_ROTATION_DEG:
+ switch (value) {
+ case 0:
+ mFlags &= ~0x7;
+ break;
+ case 90:
+ mFlags &= ~0x7;
+ mFlags |= MDP_ROT_90;
+ break;
+ case 180:
+ mFlags &= ~0x7;
+ mFlags |= MDP_ROT_180;
+ break;
+ case 270:
+ mFlags &= ~0x7;
+ mFlags |= MDP_ROT_270;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ break;
+ case COPYBIT_PLANE_ALPHA:
+ if (value < 0) value = 0;
+ if (value >= 256) value = 255;
+ mAlpha = value;
+ break;
+ case COPYBIT_DITHER:
+ if (value == COPYBIT_ENABLE) {
+ mFlags |= MDP_DITHER;
+ } else if (value == COPYBIT_DISABLE) {
+ mFlags &= ~MDP_DITHER;
+ }
+ break;
+ case COPYBIT_TRANSFORM:
+ mFlags &= ~0x7;
+ mFlags |= value & 0x7;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
+status_t CopybitMSM7K::get(int name)
+{
+ switch(name) {
+ case COPYBIT_MINIFICATION_LIMIT:
+ return 4;
+ case COPYBIT_MAGNIFICATION_LIMIT:
+ return 4;
+ case COPYBIT_SCALING_FRAC_BITS:
+ return 32;
+ case COPYBIT_ROTATION_STEP_DEG:
+ return 90;
+ }
+ return BAD_VALUE;
+}
+
+status_t CopybitMSM7K::blit(
+ const copybit_image_t& dst,
+ const copybit_image_t& src,
+ copybit_region_t const* region)
+{
+
+ copybit_rect_t dr = { 0, 0, dst.w, dst.h };
+ copybit_rect_t sr = { 0, 0, src.w, src.h };
+ return CopybitMSM7K::stretch(dst, src, dr, sr, region);
+}
+
+status_t CopybitMSM7K::stretch(
+ const copybit_image_t& dst,
+ const copybit_image_t& src,
+ const copybit_rect_t& dst_rect,
+ const copybit_rect_t& src_rect,
+ copybit_region_t const* region)
+{
+ struct {
+ uint32_t count;
+ struct mdp_blit_req req[12];
+ } list;
+
+ if (mAlpha<255) {
+ switch (src.format) {
+ // we dont' support plane alpha with RGBA formats
+ case COPYBIT_RGBA_8888:
+ case COPYBIT_RGBA_5551:
+ case COPYBIT_RGBA_4444:
+ return INVALID_OPERATION;
+ }
+ }
+
+ const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]);
+ const copybit_rect_t bounds = { 0, 0, dst.w, dst.h };
+ copybit_rect_t clip;
+ list.count = 0;
+ int err = 0;
+ while (!err && region->next(region, &clip)) {
+ intersect(&clip, bounds, clip);
+ setInfos(&list.req[list.count]);
+ setImage(&list.req[list.count].dst, dst);
+ setImage(&list.req[list.count].src, src);
+ setRects(&list.req[list.count], dst_rect, src_rect, clip);
+ if (++list.count == maxCount) {
+ err = msm_copybit(&list);
+ list.count = 0;
+ }
+ }
+ if (!err && list.count) {
+ err = msm_copybit(&list);
+ }
+ return err;
+}
+
+status_t CopybitMSM7K::msm_copybit(void const* list)
+{
+ int err = ioctl(mFD, MSMFB_BLIT, static_cast<mdp_blit_req_list const*>(list));
+ LOGE_IF(err<0, "copyBits failed (%s)", strerror(errno));
+ if (err == 0)
+ return NO_ERROR;
+ return -errno;
+}
+
+int CopybitMSM7K::getFormat(int format)
+{
+ switch (format) {
+ case COPYBIT_RGBA_8888: return MDP_RGBA_8888;
+ case COPYBIT_RGB_565: return MDP_RGB_565;
+ case COPYBIT_YCbCr_422_SP: return MDP_Y_CBCR_H2V1;
+ case COPYBIT_YCbCr_420_SP: return MDP_Y_CBCR_H2V2;
+ }
+ return -1;
+}
+
+void CopybitMSM7K::setInfos(mdp_blit_req* req)
+{
+ req->alpha = mAlpha;
+ req->transp_mask = MDP_TRANSP_NOP;
+ req->flags = mFlags;
+}
+
+void CopybitMSM7K::setImage(mdp_img* img, const copybit_image_t& rhs)
+{
+ img->width = rhs.w;
+ img->height = rhs.h;
+ img->format = getFormat(rhs.format);
+ img->offset = rhs.offset;
+ img->memory_id = rhs.fd;
+}
+
+void CopybitMSM7K::setRects(mdp_blit_req* e,
+ const copybit_rect_t& dst, const copybit_rect_t& src,
+ const copybit_rect_t& scissor)
+{
+ copybit_rect_t clip;
+ intersect(&clip, scissor, dst);
+
+ e->dst_rect.x = clip.l;
+ e->dst_rect.y = clip.t;
+ e->dst_rect.w = clip.r - clip.l;
+ e->dst_rect.h = clip.b - clip.t;
+
+ uint32_t W, H;
+ if (mFlags & COPYBIT_TRANSFORM_ROT_90) {
+ e->src_rect.x = (clip.t - dst.t) + src.t;
+ e->src_rect.y = (dst.r - clip.r) + src.l;
+ e->src_rect.w = (clip.b - clip.t);
+ e->src_rect.h = (clip.r - clip.l);
+ W = dst.b - dst.t;
+ H = dst.r - dst.l;
+ } else {
+ e->src_rect.x = (clip.l - dst.l) + src.l;
+ e->src_rect.y = (clip.t - dst.t) + src.t;
+ e->src_rect.w = (clip.r - clip.l);
+ e->src_rect.h = (clip.b - clip.t);
+ W = dst.r - dst.l;
+ H = dst.b - dst.t;
+ }
+ MULDIV(e->src_rect.x, e->src_rect.w, src.r - src.l, W);
+ MULDIV(e->src_rect.y, e->src_rect.h, src.b - src.t, H);
+ if (mFlags & COPYBIT_TRANSFORM_FLIP_V) {
+ e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h);
+ }
+ if (mFlags & COPYBIT_TRANSFORM_FLIP_H) {
+ e->src_rect.x = e->src.width - (e->src_rect.x + e->src_rect.w);
+ }
+}
+
+void CopybitMSM7K::intersect(copybit_rect_t* out,
+ const copybit_rect_t& lhs, const copybit_rect_t& rhs)
+{
+ out->l = max(lhs.l, rhs.l);
+ out->t = max(lhs.t, rhs.t);
+ out->r = min(lhs.r, rhs.r);
+ out->b = min(lhs.b, rhs.b);
+}
+
+/******************************************************************************/
+#else // HAVE_ANDROID_OS
+
+CopybitMSM7K::CopybitMSM7K()
+ : mFD(-1)
+{
+}
+
+CopybitMSM7K::~CopybitMSM7K()
+{
+}
+
+status_t CopybitMSM7K::setParameter(int name, int value)
+{
+ return NO_INIT;
+}
+
+status_t CopybitMSM7K::get(int name)
+{
+ return BAD_VALUE;
+}
+
+status_t CopybitMSM7K::blit(
+ const copybit_image_t& dst,
+ const copybit_image_t& src,
+ copybit_region_t const* region)
+{
+ return NO_INIT;
+}
+
+status_t CopybitMSM7K::stretch(
+ const copybit_image_t& dst,
+ const copybit_image_t& src,
+ const copybit_rect_t& dst_rect,
+ const copybit_rect_t& src_rect,
+ copybit_region_t const* region)
+{
+ return NO_INIT;
+}
+
+#endif // HAVE_ANDROID_OS
+
+/******************************************************************************/
+}; // namespace android
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
new file mode 100644
index 0000000..1528e6e
--- /dev/null
+++ b/libs/ui/Camera.cpp
@@ -0,0 +1,249 @@
+/*
+**
+** 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 "Camera"
+#include <utils/Log.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/threads.h>
+#include <utils/IMemory.h>
+#include <ui/Surface.h>
+
+#include <ui/Camera.h>
+#include <ui/ICameraService.h>
+
+namespace android {
+
+// client singleton for camera service binder interface
+Mutex Camera::mLock;
+sp<ICameraService> Camera::mCameraService;
+sp<Camera::DeathNotifier> Camera::mDeathNotifier;
+
+// establish binder interface to camera service
+const sp<ICameraService>& Camera::getCameraService()
+{
+ Mutex::Autolock _l(mLock);
+ if (mCameraService.get() == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.camera"));
+ if (binder != 0)
+ break;
+ LOGW("CameraService not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while(true);
+ if (mDeathNotifier == NULL) {
+ mDeathNotifier = new DeathNotifier();
+ }
+ binder->linkToDeath(mDeathNotifier);
+ mCameraService = interface_cast<ICameraService>(binder);
+ }
+ LOGE_IF(mCameraService==0, "no CameraService!?");
+ return mCameraService;
+}
+
+// ---------------------------------------------------------------------------
+
+Camera::Camera()
+ : mStatus(UNKNOWN_ERROR),
+ mShutterCallback(0),
+ mShutterCallbackCookie(0),
+ mRawCallback(0),
+ mRawCallbackCookie(0),
+ mJpegCallback(0),
+ mJpegCallbackCookie(0),
+ mFrameCallback(0),
+ mFrameCallbackCookie(0),
+ mErrorCallback(0),
+ mErrorCallbackCookie(0),
+ mAutoFocusCallback(0),
+ mAutoFocusCallbackCookie(0)
+{
+}
+
+Camera::~Camera()
+{
+ disconnect();
+}
+
+sp<Camera> Camera::connect()
+{
+ sp<Camera> c = new Camera();
+ const sp<ICameraService>& cs = getCameraService();
+ if (cs != 0) {
+ c->mCamera = cs->connect(c);
+ }
+ if (c->mCamera != 0) {
+ c->mCamera->asBinder()->linkToDeath(c);
+ c->mStatus = NO_ERROR;
+ }
+ return c;
+}
+
+void Camera::disconnect()
+{
+ if (mCamera != 0) {
+ mErrorCallback = 0;
+ mCamera->disconnect();
+ mCamera = 0;
+ }
+}
+
+// pass the buffered ISurface to the camera service
+status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
+{
+ if (surface == 0) {
+ LOGE("app passed NULL surface");
+ return NO_INIT;
+ }
+ return mCamera->setPreviewDisplay(surface->getISurface());
+}
+
+// start preview mode, must call setPreviewDisplay first
+status_t Camera::startPreview()
+{
+ return mCamera->startPreview();
+}
+
+// stop preview mode
+void Camera::stopPreview()
+{
+ mCamera->stopPreview();
+}
+
+status_t Camera::autoFocus()
+{
+ return mCamera->autoFocus();
+}
+
+// take a picture
+status_t Camera::takePicture()
+{
+ return mCamera->takePicture();
+}
+
+// set preview/capture parameters - key/value pairs
+status_t Camera::setParameters(const String8& params)
+{
+ return mCamera->setParameters(params);
+}
+
+// get preview/capture parameters - key/value pairs
+String8 Camera::getParameters() const
+{
+ String8 params = mCamera->getParameters();
+ return params;
+}
+
+void Camera::setAutoFocusCallback(autofocus_callback cb, void *cookie)
+{
+ mAutoFocusCallback = cb;
+ mAutoFocusCallbackCookie = cookie;
+}
+
+void Camera::setShutterCallback(shutter_callback cb, void *cookie)
+{
+ mShutterCallback = cb;
+ mShutterCallbackCookie = cookie;
+}
+
+void Camera::setRawCallback(frame_callback cb, void *cookie)
+{
+ mRawCallback = cb;
+ mRawCallbackCookie = cookie;
+}
+
+void Camera::setJpegCallback(frame_callback cb, void *cookie)
+{
+ mJpegCallback = cb;
+ mJpegCallbackCookie = cookie;
+}
+
+void Camera::setFrameCallback(frame_callback cb, void *cookie)
+{
+ mFrameCallback = cb;
+ mFrameCallbackCookie = cookie;
+ mCamera->setHasFrameCallback(cb != NULL);
+}
+
+void Camera::setErrorCallback(error_callback cb, void *cookie)
+{
+ mErrorCallback = cb;
+ mErrorCallbackCookie = cookie;
+}
+
+void Camera::autoFocusCallback(bool focused)
+{
+ if (mAutoFocusCallback) {
+ mAutoFocusCallback(focused, mAutoFocusCallbackCookie);
+ }
+}
+
+void Camera::shutterCallback()
+{
+ if (mShutterCallback) {
+ mShutterCallback(mShutterCallbackCookie);
+ }
+}
+
+void Camera::rawCallback(const sp<IMemory>& picture)
+{
+ if (mRawCallback) {
+ mRawCallback(picture, mRawCallbackCookie);
+ }
+}
+
+// callback from camera service when image is ready
+void Camera::jpegCallback(const sp<IMemory>& picture)
+{
+ if (mJpegCallback) {
+ mJpegCallback(picture, mJpegCallbackCookie);
+ }
+}
+
+// callback from camera service when video frame is ready
+void Camera::frameCallback(const sp<IMemory>& frame)
+{
+ if (mFrameCallback) {
+ mFrameCallback(frame, mFrameCallbackCookie);
+ }
+}
+
+// callback from camera service when an error occurs in preview or takePicture
+void Camera::errorCallback(status_t error)
+{
+ if (mErrorCallback) {
+ mErrorCallback(error, mErrorCallbackCookie);
+ }
+}
+
+void Camera::binderDied(const wp<IBinder>& who) {
+ LOGW("ICamera died");
+ if (mErrorCallback) {
+ mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
+ }
+}
+
+void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
+ Mutex::Autolock _l(Camera::mLock);
+ Camera::mCameraService.clear();
+ LOGW("Camera server died!");
+}
+
+}; // namespace android
+
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
new file mode 100644
index 0000000..7ca77bb
--- /dev/null
+++ b/libs/ui/CameraParameters.cpp
@@ -0,0 +1,253 @@
+/*
+**
+** 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 "CameraParams"
+#include <utils/Log.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <ui/CameraParameters.h>
+
+namespace android {
+
+CameraParameters::CameraParameters()
+ : mMap()
+{
+}
+
+CameraParameters::~CameraParameters()
+{
+}
+
+String8 CameraParameters::flatten() const
+{
+ String8 flattened("");
+ size_t size = mMap.size();
+
+ for (size_t i = 0; i < size; i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+
+ flattened += k;
+ flattened += "=";
+ flattened += v;
+ if (i != size-1)
+ flattened += ";";
+ }
+
+ return flattened;
+}
+
+void CameraParameters::unflatten(const String8 &params)
+{
+ const char *a = params.string();
+ const char *b;
+
+ mMap.clear();
+
+ for (;;) {
+ // Find the bounds of the key name.
+ b = strchr(a, '=');
+ if (b == 0)
+ break;
+
+ // Create the key string.
+ String8 k(a, (size_t)(b-a));
+
+ // Find the value.
+ a = b+1;
+ b = strchr(a, ';');
+ if (b == 0) {
+ // If there's no semicolon, this is the last item.
+ String8 v(a);
+ mMap.add(k, v);
+ break;
+ }
+
+ String8 v(a, (size_t)(b-a));
+ mMap.add(k, v);
+ a = b+1;
+ }
+}
+
+
+void CameraParameters::set(const char *key, const char *value)
+{
+ // XXX i think i can do this with strspn()
+ if (strchr(key, '=') || strchr(key, ';')) {
+ //XXX LOGE("Key \"%s\"contains invalid character (= or ;)", key);
+ return;
+ }
+
+ if (strchr(value, '=') || strchr(key, ';')) {
+ //XXX LOGE("Value \"%s\"contains invalid character (= or ;)", value);
+ return;
+ }
+
+ mMap.replaceValueFor(String8(key), String8(value));
+}
+
+void CameraParameters::set(const char *key, int value)
+{
+ char str[16];
+ sprintf(str, "%d", value);
+ set(key, str);
+}
+
+const char *CameraParameters::get(const char *key) const
+{
+ String8 v = mMap.valueFor(String8(key));
+ if (v.length() == 0)
+ return 0;
+ return v.string();
+}
+
+int CameraParameters::getInt(const char *key) const
+{
+ const char *v = get(key);
+ if (v == 0)
+ return -1;
+ return strtol(v, 0, 0);
+}
+
+static int parse_size(const char *str, int &width, int &height)
+{
+ // Find the width.
+ char *end;
+ int w = (int)strtol(str, &end, 10);
+ // If an 'x' does not immediately follow, give up.
+ if (*end != 'x')
+ return -1;
+
+ // Find the height, immediately after the 'x'.
+ int h = (int)strtol(end+1, 0, 10);
+
+ width = w;
+ height = h;
+
+ return 0;
+}
+
+void CameraParameters::setPreviewSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set("preview-size", str);
+}
+
+void CameraParameters::getPreviewSize(int *width, int *height) const
+{
+ *width = -1;
+ *height = -1;
+
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get("preview-size");
+ if (p == 0)
+ return;
+
+ int w, h;
+ if (parse_size(p, w, h) == 0) {
+ *width = w;
+ *height = h;
+ }
+}
+
+void CameraParameters::setPreviewFrameRate(int fps)
+{
+ set("preview-frame-rate", fps);
+}
+
+int CameraParameters::getPreviewFrameRate() const
+{
+ return getInt("preview-frame-rate");
+}
+
+void CameraParameters::setPreviewFormat(const char *format)
+{
+ set("preview-format", format);
+}
+
+const char *CameraParameters::getPreviewFormat() const
+{
+ return get("preview-format");
+}
+
+void CameraParameters::setPictureSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set("picture-size", str);
+}
+
+void CameraParameters::getPictureSize(int *width, int *height) const
+{
+ *width = -1;
+ *height = -1;
+
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get("picture-size");
+ if (p == 0)
+ return;
+
+ int w, h;
+ if (parse_size(p, w, h) == 0) {
+ *width = w;
+ *height = h;
+ }
+}
+
+void CameraParameters::setPictureFormat(const char *format)
+{
+ set("picture-format", format);
+}
+
+const char *CameraParameters::getPictureFormat() const
+{
+ return get("picture-format");
+}
+
+void CameraParameters::dump() const
+{
+ LOGD("dump: mMap.size = %d", mMap.size());
+ for (size_t i = 0; i < mMap.size(); i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+ LOGD("%s: %s\n", k.string(), v.string());
+ }
+}
+
+status_t CameraParameters::dump(int fd, const Vector<String16>& args) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %d\n", mMap.size());
+ result.append(buffer);
+ for (size_t i = 0; i < mMap.size(); i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+ snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string());
+ result.append(buffer);
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
new file mode 100644
index 0000000..ea245f5
--- /dev/null
+++ b/libs/ui/EGLDisplaySurface.cpp
@@ -0,0 +1,471 @@
+/*
+ **
+ ** 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.
+ */
+
+#define LOG_TAG "EGLDisplaySurface"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/msm_mdp.h>
+#endif
+
+#include <GLES/egl.h>
+
+#include <pixelflinger/format.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+// ----------------------------------------------------------------------------
+
+egl_native_window_t* android_createDisplaySurface()
+{
+ egl_native_window_t* s = new android::EGLDisplaySurface();
+ s->memory_type = NATIVE_MEMORY_TYPE_GPU;
+ return s;
+}
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+EGLDisplaySurface::EGLDisplaySurface()
+ : EGLNativeSurface<EGLDisplaySurface>()
+{
+ egl_native_window_t::version = sizeof(egl_native_window_t);
+ egl_native_window_t::ident = 0;
+ egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
+ egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
+ egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
+ egl_native_window_t::setSwapRectangle = &EGLDisplaySurface::hook_setSwapRectangle;
+ egl_native_window_t::nextBuffer = &EGLDisplaySurface::hook_nextBuffer;
+ egl_native_window_t::connect = 0;
+ egl_native_window_t::disconnect = 0;
+
+ mFb[0].data = 0;
+ mFb[1].data = 0;
+ mBlitEngine = 0;
+ egl_native_window_t::fd = mapFrameBuffer();
+ if (egl_native_window_t::fd >= 0) {
+ mBlitEngine = copybit_init();
+ const float in2mm = 25.4f;
+ float refreshRate = 1000000000000000LLU / (
+ float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
+ * ( mInfo.left_margin + mInfo.right_margin + mInfo.xres )
+ * mInfo.pixclock);
+
+ const GGLSurface& buffer = mFb[1 - mIndex];
+ egl_native_window_t::width = buffer.width;
+ egl_native_window_t::height = buffer.height;
+ egl_native_window_t::stride = buffer.stride;
+ egl_native_window_t::format = buffer.format;
+ egl_native_window_t::base = intptr_t(mFb[0].data);
+ egl_native_window_t::offset =
+ intptr_t(buffer.data) - egl_native_window_t::base;
+ egl_native_window_t::flags = 0;
+ egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width;
+ egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height;
+ egl_native_window_t::fps = refreshRate;
+ egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB;
+ // no error, set the magic word
+ egl_native_window_t::magic = 0x600913;
+ }
+ mSwapCount = -1;
+ mPageFlipCount = 0;
+}
+
+EGLDisplaySurface::~EGLDisplaySurface()
+{
+ magic = 0;
+ copybit_term(mBlitEngine);
+ mBlitEngine = 0;
+ close(egl_native_window_t::fd);
+ munmap(mFb[0].data, mSize);
+ if (!(mFlags & PAGE_FLIP))
+ free((void*)mFb[1].data);
+}
+
+void EGLDisplaySurface::hook_incRef(NativeWindowType window) {
+ EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
+ that->incStrong(that);
+}
+void EGLDisplaySurface::hook_decRef(NativeWindowType window) {
+ EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
+ that->decStrong(that);
+}
+uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) {
+ EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
+ return that->swapBuffers();
+}
+uint32_t EGLDisplaySurface::hook_nextBuffer(NativeWindowType window) {
+ EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
+ return that->nextBuffer();
+}
+void EGLDisplaySurface::hook_setSwapRectangle(NativeWindowType window,
+ int l, int t, int w, int h) {
+ EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
+ that->setSwapRectangle(l, t, w, h);
+}
+
+void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
+{
+ mInfo.reserved[0] = 0x54445055; // "UPDT";
+ mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
+ mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
+}
+
+uint32_t EGLDisplaySurface::swapBuffers()
+{
+ if (!(mFlags & PAGE_FLIP))
+ return 0;
+
+#define SHOW_FPS 0
+#if SHOW_FPS
+ nsecs_t now = systemTime();
+ if (mSwapCount == -1) {
+ mTime = now;
+ mSwapCount = 0;
+ mSleep = 0;
+ } else {
+ nsecs_t d = now-mTime;
+ if (d >= seconds(1)) {
+ double fps = (mSwapCount * double(seconds(1))) / double(d);
+ LOGD("%f fps, sleep=%d / frame",
+ fps, (int)ns2us(mSleep / mSwapCount));
+ mSwapCount = 0;
+ mTime = now;
+ mSleep = 0;
+ } else {
+ mSwapCount++;
+ }
+ }
+#endif
+
+ // do the actual flip
+ mIndex = 1 - mIndex;
+ mInfo.activate = FB_ACTIVATE_VBL;
+ mInfo.yoffset = mIndex ? mInfo.yres : 0;
+ if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) {
+ LOGE("FBIOPUT_VSCREENINFO failed");
+ return 0;
+ }
+
+ /*
+ * this is a monstrous hack: Because the h/w accelerator is not able
+ * to render directly into the framebuffer, we need to copy its
+ * internal framebuffer out to the fb.
+ * oem[0] is used to access the fd of internal fb.
+ * All this is needed only in standalone mode, in SurfaceFlinger mode
+ * we control where the GPU renders.
+ * We do this only if we have copybit, since this hack is needed only
+ * with msm7k.
+ */
+ if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0] && mBlitEngine) {
+ copybit_t *copybit = mBlitEngine;
+ copybit_rect_t sdrect = { 0, 0,
+ egl_native_window_t::width, egl_native_window_t::height };
+ copybit_image_t dst = {
+ egl_native_window_t::width,
+ egl_native_window_t::height,
+ egl_native_window_t::format,
+ egl_native_window_t::offset,
+ (void*)egl_native_window_t::base,
+ egl_native_window_t::fd
+ };
+ copybit_image_t src = {
+ egl_native_window_t::width,
+ egl_native_window_t::height,
+ egl_native_window_t::format, // XXX: use proper format
+ egl_native_window_t::offset,
+ (void*)egl_native_window_t::base, // XXX: use proper base
+ egl_native_window_t::oem[0]
+ };
+ region_iterator it(Region(Rect(
+ egl_native_window_t::width, egl_native_window_t::height)));
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+ copybit->stretch(copybit, &dst, &src, &sdrect, &sdrect, &it);
+ }
+
+ // update the address of the buffer to draw to next
+ const GGLSurface& buffer = mFb[1 - mIndex];
+ egl_native_window_t::offset =
+ intptr_t(buffer.data) - egl_native_window_t::base;
+
+#if SHOW_FPS
+ mSleep += systemTime()-now;
+#endif
+
+ mPageFlipCount++;
+
+ // We don't support screen-size changes for now
+ return 0;
+}
+
+int32_t EGLDisplaySurface::getPageFlipCount() const
+{
+ return mPageFlipCount;
+}
+
+uint32_t EGLDisplaySurface::nextBuffer()
+{
+ // update the address of the buffer to draw to next
+ const GGLSurface& buffer = mFb[mIndex];
+ egl_native_window_t::offset =
+ intptr_t(buffer.data) - egl_native_window_t::base;
+ return 0;
+}
+
+void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
+{
+#if HAVE_ANDROID_OS
+ if (mBlitEngine) {
+ copybit_image_t dst = {
+ w: egl_native_window_t::stride,
+ h: egl_native_window_t::height,
+ format: egl_native_window_t::format,
+ offset: mFb[1-mIndex].data - mFb[0].data,
+ base: (void*)egl_native_window_t::base,
+ fd: egl_native_window_t::fd
+ };
+ copybit_image_t src = {
+ w: egl_native_window_t::stride,
+ h: egl_native_window_t::height,
+ format: egl_native_window_t::format,
+ offset: mFb[mIndex].data - mFb[0].data,
+ base: (void*)egl_native_window_t::base,
+ fd: egl_native_window_t::fd
+ };
+ region_iterator it(copyback);
+ mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
+ } else
+#endif
+ {
+ Region::iterator iterator(copyback);
+ if (iterator) {
+ Rect r;
+ uint8_t* const screen_src = mFb[ mIndex].data;
+ uint8_t* const screen_dst = mFb[1-mIndex].data;
+ const size_t bpp = bytesPerPixel(egl_native_window_t::format);
+ const size_t bpr = egl_native_window_t::stride * bpp;
+ while (iterator.iterate(&r)) {
+ ssize_t h = r.bottom - r.top;
+ if (h) {
+ size_t size = (r.right - r.left) * bpp;
+ size_t o = (r.left + egl_native_window_t::stride * r.top) * bpp;
+ uint8_t* s = screen_src + o;
+ uint8_t* d = screen_dst + o;
+ if (size == bpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += bpr;
+ s += bpr;
+ } while (--h > 0);
+ }
+ }
+ }
+ }
+}
+
+status_t EGLDisplaySurface::mapFrameBuffer()
+{
+ char const * const device_template[] = {
+ "/dev/graphics/fb%u",
+ "/dev/fb%u",
+ 0 };
+ int fd = -1;
+ int i=0;
+ char name[64];
+ while ((fd==-1) && device_template[i]) {
+ snprintf(name, 64, device_template[i], 0);
+ fd = open(name, O_RDWR, 0);
+ i++;
+ }
+ if (fd < 0)
+ return -errno;
+
+ struct fb_fix_screeninfo finfo;
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
+ return -errno;
+
+ struct fb_var_screeninfo info;
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
+ return -errno;
+
+ info.reserved[0] = 0;
+ info.reserved[1] = 0;
+ info.reserved[2] = 0;
+ info.xoffset = 0;
+ info.yoffset = 0;
+ info.yres_virtual = info.yres * 2;
+ info.bits_per_pixel = 16;
+ /* Explicitly request 5/6/5 */
+ info.red.offset = 11;
+ info.red.length = 5;
+ info.green.offset = 5;
+ info.green.length = 6;
+ info.blue.offset = 0;
+ info.blue.length = 5;
+ info.transp.offset = 0;
+ info.transp.length = 0;
+ info.activate = FB_ACTIVATE_NOW;
+
+ uint32_t flags = PAGE_FLIP;
+ if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
+ info.yres_virtual = info.yres;
+ flags &= ~PAGE_FLIP;
+ LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
+ }
+
+ if (info.yres_virtual < info.yres * 2) {
+ info.yres_virtual = info.yres;
+ flags &= ~PAGE_FLIP;
+ LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
+ info.yres_virtual, info.yres*2);
+ }
+
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
+ return -errno;
+
+ int refreshRate = 1000000000000000LLU /
+ (
+ uint64_t( info.upper_margin + info.lower_margin + info.yres )
+ * ( info.left_margin + info.right_margin + info.xres )
+ * info.pixclock
+ );
+
+ if (refreshRate == 0) {
+ // bleagh, bad info from the driver
+ refreshRate = 60*1000; // 60 Hz
+ }
+
+ if (int(info.width) <= 0 || int(info.height) <= 0) {
+ // the driver doesn't return that information
+ // default to 160 dpi
+ info.width = 51;
+ info.height = 38;
+ }
+
+ float xdpi = (info.xres * 25.4f) / info.width;
+ float ydpi = (info.yres * 25.4f) / info.height;
+ float fps = refreshRate / 1000.0f;
+
+ LOGI( "using (fd=%d)\n"
+ "id = %s\n"
+ "xres = %d px\n"
+ "yres = %d px\n"
+ "xres_virtual = %d px\n"
+ "yres_virtual = %d px\n"
+ "bpp = %d\n"
+ "r = %2u:%u\n"
+ "g = %2u:%u\n"
+ "b = %2u:%u\n",
+ fd,
+ finfo.id,
+ info.xres,
+ info.yres,
+ info.xres_virtual,
+ info.yres_virtual,
+ info.bits_per_pixel,
+ info.red.offset, info.red.length,
+ info.green.offset, info.green.length,
+ info.blue.offset, info.blue.length
+ );
+
+ LOGI( "width = %d mm (%f dpi)\n"
+ "height = %d mm (%f dpi)\n"
+ "refresh rate = %.2f Hz\n",
+ info.width, xdpi,
+ info.height, ydpi,
+ fps
+ );
+
+
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
+ return -errno;
+
+ if (finfo.smem_len <= 0)
+ return -errno;
+
+ /*
+ * Open and map the display.
+ */
+
+ void* buffer = (uint16_t*) mmap(
+ 0, finfo.smem_len,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd, 0);
+
+ if (buffer == MAP_FAILED)
+ return -errno;
+
+ // at least for now, always clear the fb
+ memset(buffer, 0, finfo.smem_len);
+
+ uint8_t* offscreen[2];
+ offscreen[0] = (uint8_t*)buffer;
+ if (flags & PAGE_FLIP) {
+ offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres;
+ } else {
+ offscreen[1] = (uint8_t*)malloc(finfo.smem_len);
+ if (offscreen[1] == 0) {
+ munmap(buffer, finfo.smem_len);
+ return NO_MEMORY;
+ }
+ }
+
+ mFlags = flags;
+ mInfo = info;
+ mFinfo = finfo;
+ mSize = finfo.smem_len;
+ mIndex = 0;
+ for (int i=0 ; i<2 ; i++) {
+ mFb[i].version = sizeof(GGLSurface);
+ mFb[i].width = info.xres;
+ mFb[i].height = info.yres;
+ mFb[i].stride = finfo.line_length / (info.bits_per_pixel >> 3);
+ mFb[i].data = (GGLubyte*)(offscreen[i]);
+ mFb[i].format = GGL_PIXEL_FORMAT_RGB_565;
+ }
+ return fd;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
new file mode 100644
index 0000000..0b6afc0
--- /dev/null
+++ b/libs/ui/EGLNativeWindowSurface.cpp
@@ -0,0 +1,181 @@
+/*
+**
+** 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.
+*/
+
+#define LOG_TAG "EGLNativeWindowSurface"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+#include <ui/Rect.h>
+
+#include <GLES/egl.h>
+
+#include <pixelflinger/format.h>
+
+#include <ui/EGLNativeWindowSurface.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+EGLNativeWindowSurface::EGLNativeWindowSurface(const sp<Surface>& surface)
+ : EGLNativeSurface<EGLNativeWindowSurface>(),
+ mSurface(surface), mConnected(false)
+{
+ egl_native_window_t::magic = 0x600913;
+ egl_native_window_t::version = sizeof(egl_native_window_t);
+ egl_native_window_t::ident = 0;
+ egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef;
+ egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef;
+ egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers;
+ egl_native_window_t::nextBuffer = &EGLNativeWindowSurface::hook_nextBuffer;
+ egl_native_window_t::setSwapRectangle = &EGLNativeWindowSurface::hook_setSwapRectangle;
+ egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect;
+ egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect;
+
+ DisplayInfo dinfo;
+ SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+ egl_native_window_t::xdpi = dinfo.xdpi;
+ egl_native_window_t::ydpi = dinfo.ydpi;
+ egl_native_window_t::fps = dinfo.fps;
+ egl_native_window_t::flags= EGL_NATIVES_FLAG_DESTROY_BACKBUFFER;
+}
+
+EGLNativeWindowSurface::~EGLNativeWindowSurface()
+{
+ disconnect();
+ mSurface.clear();
+ magic = 0;
+}
+
+void EGLNativeWindowSurface::hook_incRef(NativeWindowType window)
+{
+ EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+ that->incStrong(that);
+}
+
+void EGLNativeWindowSurface::hook_decRef(NativeWindowType window)
+{
+ EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+ that->decStrong(that);
+}
+
+void EGLNativeWindowSurface::hook_connect(NativeWindowType window)
+{
+ EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+ that->connect();
+}
+
+void EGLNativeWindowSurface::hook_disconnect(NativeWindowType window)
+{
+ EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+ that->disconnect();
+}
+
+uint32_t EGLNativeWindowSurface::hook_swapBuffers(NativeWindowType window)
+{
+ EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+ return that->swapBuffers();
+}
+
+uint32_t EGLNativeWindowSurface::hook_nextBuffer(NativeWindowType window)
+{
+ EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+ return that->nextBuffer();
+}
+
+void EGLNativeWindowSurface::hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h)
+{
+ EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
+ that->setSwapRectangle(l, t, w, h);
+}
+
+void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h)
+{
+ mSurface->setSwapRectangle(Rect(l, t, l+w, t+h));
+}
+
+uint32_t EGLNativeWindowSurface::swapBuffers()
+{
+ const int w = egl_native_window_t::width;
+ const int h = egl_native_window_t::height;
+ const sp<Surface>& surface(mSurface);
+ Surface::SurfaceInfo info;
+ surface->unlockAndPost();
+ surface->lock(&info);
+ // update the address of the buffer to draw to next
+ egl_native_window_t::base = intptr_t(info.base);
+ egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
+
+ // update size if it changed
+ if (w != int(info.w) || h != int(info.h)) {
+ egl_native_window_t::width = info.w;
+ egl_native_window_t::height = info.h;
+ egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
+ egl_native_window_t::format = info.format;
+ return EGL_NATIVES_FLAG_SIZE_CHANGED;
+ }
+ return 0;
+}
+
+uint32_t EGLNativeWindowSurface::nextBuffer()
+{
+ const sp<Surface>& surface(mSurface);
+ Surface::SurfaceInfo info;
+ surface->nextBuffer(&info);
+ // update the address of the buffer to draw to next
+ egl_native_window_t::base = intptr_t(info.base);
+ egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
+ return 0;
+}
+
+void EGLNativeWindowSurface::connect()
+{
+ if (!mConnected) {
+ Surface::SurfaceInfo info;
+ mSurface->lock(&info);
+ mSurface->setSwapRectangle(Rect(info.w, info.h));
+ mConnected = true;
+
+ egl_native_window_t::width = info.w;
+ egl_native_window_t::height = info.h;
+ egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
+ egl_native_window_t::format = info.format;
+ egl_native_window_t::base = intptr_t(info.base);
+ egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
+ egl_native_window_t::memory_type = mSurface->getMemoryType();
+ egl_native_window_t::fd = 0;
+ }
+}
+
+void EGLNativeWindowSurface::disconnect()
+{
+ if (mConnected) {
+ mSurface->unlock();
+ mConnected = false;
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
new file mode 100644
index 0000000..f0c77ba
--- /dev/null
+++ b/libs/ui/EventHub.cpp
@@ -0,0 +1,743 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+// Handle events, like key input and vsync.
+//
+// The goal is to provide an optimized solution for Linux, not an
+// implementation that works well across all platforms. We expect
+// events to arrive on file descriptors, so that we can use a select()
+// select() call to sleep.
+//
+// We can't select() on anything but network sockets in Windows, so we
+// provide an alternative implementation of waitEvent for that platform.
+//
+#define LOG_TAG "EventHub"
+
+//#define LOG_NDEBUG 0
+
+#include <ui/EventHub.h>
+#include <hardware/power.h>
+
+#include <cutils/properties.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <utils.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "KeyLayoutMap.h"
+
+#include <string.h>
+#include <stdint.h>
+#include <dirent.h>
+#ifdef HAVE_INOTIFY
+# include <sys/inotify.h>
+#endif
+#ifdef HAVE_ANDROID_OS
+# include <sys/limits.h> /* not part of Linux */
+#endif
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+
+/* this macro is used to tell if "bit" is set in "array"
+ * it selects a byte from the array, and does a boolean AND
+ * operation with a byte that only has the relevant bit set.
+ * eg. to check for the 12th bit, we do (array[1] & 1<<4)
+ */
+#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
+
+#define ID_MASK 0x0000ffff
+#define SEQ_MASK 0x7fff0000
+#define SEQ_SHIFT 16
+#define id_to_index(id) ((id&ID_MASK)+1)
+
+namespace android {
+
+static const char *WAKE_LOCK_ID = "KeyEvents";
+static const char *device_path = "/dev/input";
+
+/* return the larger integer */
+static inline int max(int v1, int v2)
+{
+ return (v1 > v2) ? v1 : v2;
+}
+
+EventHub::device_t::device_t(int32_t _id, const char* _path)
+ : id(_id), path(_path), classes(0)
+ , layoutMap(new KeyLayoutMap()), next(NULL) {
+}
+
+EventHub::device_t::~device_t() {
+ delete layoutMap;
+}
+
+EventHub::EventHub(void)
+ : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
+ , mDevicesById(0), mNumDevicesById(0)
+ , mOpeningDevices(0), mClosingDevices(0)
+ , mDevices(0), mFDs(0), mFDCount(0)
+{
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+#ifdef EV_SW
+ memset(mSwitches, 0, sizeof(mSwitches));
+#endif
+}
+
+/*
+ * Clean up.
+ */
+EventHub::~EventHub(void)
+{
+ release_wake_lock(WAKE_LOCK_ID);
+ // we should free stuff here...
+}
+
+void EventHub::onFirstRef()
+{
+ mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
+}
+
+status_t EventHub::errorCheck() const
+{
+ return mError;
+}
+
+String8 EventHub::getDeviceName(int32_t deviceId) const
+{
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+ if (device == NULL) return String8();
+ return device->name;
+}
+
+uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
+{
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+ if (device == NULL) return 0;
+ return device->classes;
+}
+
+int EventHub::getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
+ int* outMaxValue, int* outFlat, int* outFuzz) const
+{
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+ if (device == NULL) return -1;
+
+ struct input_absinfo info;
+
+ if(ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGABS(axis), &info)) {
+ LOGE("Error reading absolute controller %d for device %s fd %d\n",
+ axis, device->name.string(), mFDs[id_to_index(device->id)].fd);
+ return -1;
+ }
+ *outMinValue = info.minimum;
+ *outMaxValue = info.maximum;
+ *outFlat = info.flat;
+ *outFuzz = info.fuzz;
+ return 0;
+}
+
+int EventHub::getSwitchState(int sw) const
+{
+#ifdef EV_SW
+ if (sw >= 0 && sw <= SW_MAX) {
+ int32_t devid = mSwitches[sw];
+ if (devid != 0) {
+ return getSwitchState(devid, sw);
+ }
+ }
+#endif
+ return -1;
+}
+
+int EventHub::getSwitchState(int32_t deviceId, int sw) const
+{
+#ifdef EV_SW
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+ if (device == NULL) return -1;
+
+ if (sw >= 0 && sw <= SW_MAX) {
+ uint8_t sw_bitmask[(SW_MAX+1)/8];
+ memset(sw_bitmask, 0, sizeof(sw_bitmask));
+ if (ioctl(mFDs[id_to_index(device->id)].fd,
+ EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
+ return test_bit(sw, sw_bitmask) ? 1 : 0;
+ }
+ }
+#endif
+
+ return -1;
+}
+
+int EventHub::getScancodeState(int code) const
+{
+ return getScancodeState(mFirstKeyboardId, code);
+}
+
+int EventHub::getScancodeState(int32_t deviceId, int code) const
+{
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+ if (device == NULL) return -1;
+
+ if (code >= 0 && code <= KEY_MAX) {
+ uint8_t key_bitmask[(KEY_MAX+1)/8];
+ memset(key_bitmask, 0, sizeof(key_bitmask));
+ if (ioctl(mFDs[id_to_index(device->id)].fd,
+ EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
+ return test_bit(code, key_bitmask) ? 1 : 0;
+ }
+ }
+
+ return -1;
+}
+
+int EventHub::getKeycodeState(int code) const
+{
+ return getKeycodeState(mFirstKeyboardId, code);
+}
+
+int EventHub::getKeycodeState(int32_t deviceId, int code) const
+{
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+ if (device == NULL || device->layoutMap == NULL) return -1;
+
+ Vector<int32_t> scanCodes;
+ device->layoutMap->findScancodes(code, &scanCodes);
+
+ uint8_t key_bitmask[(KEY_MAX+1)/8];
+ memset(key_bitmask, 0, sizeof(key_bitmask));
+ if (ioctl(mFDs[id_to_index(device->id)].fd,
+ EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
+ #if 0
+ for (size_t i=0; i<=KEY_MAX; i++) {
+ LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask));
+ }
+ #endif
+ const size_t N = scanCodes.size();
+ for (size_t i=0; i<N && i<=KEY_MAX; i++) {
+ int32_t sc = scanCodes.itemAt(i);
+ //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask));
+ if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
+{
+ if (deviceId == 0) deviceId = mFirstKeyboardId;
+ int32_t id = deviceId & ID_MASK;
+ if (id >= mNumDevicesById || id < 0) return NULL;
+ device_t* dev = mDevicesById[id].device;
+ if (dev->id == deviceId) {
+ return dev;
+ }
+ return NULL;
+}
+
+bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
+ int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
+ int32_t* outValue, nsecs_t* outWhen)
+{
+ *outDeviceId = 0;
+ *outType = 0;
+ *outScancode = 0;
+ *outKeycode = 0;
+ *outFlags = 0;
+ *outValue = 0;
+ *outWhen = 0;
+
+ status_t err;
+
+ fd_set readfds;
+ int maxFd = -1;
+ int cc;
+ int i;
+ int res;
+ int pollres;
+ struct input_event iev;
+
+ // Note that we only allow one caller to getEvent(), so don't need
+ // to do locking here... only when adding/removing devices.
+
+ while(1) {
+
+ // First, report any devices that had last been added/removed.
+ if (mClosingDevices != NULL) {
+ device_t* device = mClosingDevices;
+ LOGV("Reporting device closed: id=0x%x, name=%s\n",
+ device->id, device->path.string());
+ mClosingDevices = device->next;
+ *outDeviceId = device->id;
+ if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
+ *outType = DEVICE_REMOVED;
+ delete device;
+ return true;
+ }
+ if (mOpeningDevices != NULL) {
+ device_t* device = mOpeningDevices;
+ LOGV("Reporting device opened: id=0x%x, name=%s\n",
+ device->id, device->path.string());
+ mOpeningDevices = device->next;
+ *outDeviceId = device->id;
+ if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
+ *outType = DEVICE_ADDED;
+ return true;
+ }
+
+ release_wake_lock(WAKE_LOCK_ID);
+
+ pollres = poll(mFDs, mFDCount, -1);
+
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+
+ if (pollres <= 0) {
+ if (errno != EINTR) {
+ LOGW("select failed (errno=%d)\n", errno);
+ usleep(100000);
+ }
+ continue;
+ }
+
+ //printf("poll %d, returned %d\n", mFDCount, pollres);
+ if(mFDs[0].revents & POLLIN) {
+ read_notify(mFDs[0].fd);
+ }
+ for(i = 1; i < mFDCount; i++) {
+ if(mFDs[i].revents) {
+ LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
+ if(mFDs[i].revents & POLLIN) {
+ res = read(mFDs[i].fd, &iev, sizeof(iev));
+ if (res == sizeof(iev)) {
+ LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
+ mDevices[i]->path.string(),
+ (int) iev.time.tv_sec, (int) iev.time.tv_usec,
+ iev.type, iev.code, iev.value);
+ *outDeviceId = mDevices[i]->id;
+ if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
+ *outType = iev.type;
+ *outScancode = iev.code;
+ if (iev.type == EV_KEY) {
+ err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags);
+ LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n",
+ iev.code, *outKeycode, *outFlags, err);
+ if (err != 0) {
+ *outKeycode = 0;
+ *outFlags = 0;
+ }
+ } else {
+ *outKeycode = iev.code;
+ }
+ *outValue = iev.value;
+ *outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec);
+ return true;
+ } else {
+ if (res<0) {
+ LOGW("could not get event (errno=%d)", errno);
+ } else {
+ LOGE("could not get event (wrong size: %d)", res);
+ }
+ continue;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Open the platform-specific input device.
+ */
+bool EventHub::openPlatformInput(void)
+{
+ /*
+ * Open platform-specific input device(s).
+ */
+ int res;
+
+ mFDCount = 1;
+ mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
+ mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
+ mFDs[0].events = POLLIN;
+ mDevices[0] = NULL;
+#ifdef HAVE_INOTIFY
+ mFDs[0].fd = inotify_init();
+ res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
+ if(res < 0) {
+ LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
+ }
+#else
+ /*
+ * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
+ * We allocate space for it and set it to something invalid.
+ */
+ mFDs[0].fd = -1;
+#endif
+
+ res = scan_dir(device_path);
+ if(res < 0) {
+ LOGE("scan dir failed for %s\n", device_path);
+ //open_device("/dev/input/event0");
+ }
+
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+
+int EventHub::open_device(const char *deviceName)
+{
+ int version;
+ int fd;
+ struct pollfd *new_mFDs;
+ device_t **new_devices;
+ char **new_device_names;
+ char name[80];
+ char location[80];
+ char idstr[80];
+ struct input_id id;
+
+ LOGV("Opening device: %s", deviceName);
+
+ AutoMutex _l(mLock);
+
+ fd = open(deviceName, O_RDWR);
+ if(fd < 0) {
+ LOGE("could not open %s, %s\n", deviceName, strerror(errno));
+ return -1;
+ }
+
+ if(ioctl(fd, EVIOCGVERSION, &version)) {
+ LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
+ return -1;
+ }
+ if(ioctl(fd, EVIOCGID, &id)) {
+ LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno));
+ return -1;
+ }
+ name[sizeof(name) - 1] = '\0';
+ location[sizeof(location) - 1] = '\0';
+ idstr[sizeof(idstr) - 1] = '\0';
+ if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
+ //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
+ name[0] = '\0';
+ }
+ if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
+ //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
+ location[0] = '\0';
+ }
+ if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
+ //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno));
+ idstr[0] = '\0';
+ }
+
+ int devid = 0;
+ while (devid < mNumDevicesById) {
+ if (mDevicesById[devid].device == NULL) {
+ break;
+ }
+ devid++;
+ }
+ if (devid >= mNumDevicesById) {
+ device_ent* new_devids = (device_ent*)realloc(mDevicesById,
+ sizeof(mDevicesById[0]) * (devid + 1));
+ if (new_devids == NULL) {
+ LOGE("out of memory");
+ return -1;
+ }
+ mDevicesById = new_devids;
+ mNumDevicesById = devid+1;
+ mDevicesById[devid].device = NULL;
+ mDevicesById[devid].seq = 0;
+ }
+
+ mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
+ if (mDevicesById[devid].seq == 0) {
+ mDevicesById[devid].seq = 1<<SEQ_SHIFT;
+ }
+
+ new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
+ new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
+ if (new_mFDs == NULL || new_devices == NULL) {
+ LOGE("out of memory");
+ return -1;
+ }
+ mFDs = new_mFDs;
+ mDevices = new_devices;
+
+#if 0
+ LOGI("add device %d: %s\n", mFDCount, deviceName);
+ LOGI(" bus: %04x\n"
+ " vendor %04x\n"
+ " product %04x\n"
+ " version %04x\n",
+ id.bustype, id.vendor, id.product, id.version);
+ LOGI(" name: \"%s\"\n", name);
+ LOGI(" location: \"%s\"\n"
+ " id: \"%s\"\n", location, idstr);
+ LOGI(" version: %d.%d.%d\n",
+ version >> 16, (version >> 8) & 0xff, version & 0xff);
+#endif
+
+ device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName);
+ if (device == NULL) {
+ LOGE("out of memory");
+ return -1;
+ }
+
+ mFDs[mFDCount].fd = fd;
+ mFDs[mFDCount].events = POLLIN;
+
+ // figure out the kinds of events the device reports
+ uint8_t key_bitmask[(KEY_MAX+1)/8];
+ memset(key_bitmask, 0, sizeof(key_bitmask));
+ LOGV("Getting keys...");
+ if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
+ //LOGI("MAP\n");
+ //for (int i=0; i<((KEY_MAX+1)/8); i++) {
+ // LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
+ //}
+ for (int i=0; i<((BTN_MISC+7)/8); i++) {
+ if (key_bitmask[i] != 0) {
+ device->classes |= CLASS_KEYBOARD;
+ break;
+ }
+ }
+ }
+ if (test_bit(BTN_MOUSE, key_bitmask)) {
+ uint8_t rel_bitmask[(REL_MAX+1)/8];
+ memset(rel_bitmask, 0, sizeof(rel_bitmask));
+ LOGV("Getting relative controllers...");
+ if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0)
+ {
+ if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
+ device->classes |= CLASS_TRACKBALL;
+ }
+ }
+ }
+ if (test_bit(BTN_TOUCH, key_bitmask)) {
+ uint8_t abs_bitmask[(ABS_MAX+1)/8];
+ memset(abs_bitmask, 0, sizeof(abs_bitmask));
+ LOGV("Getting absolute controllers...");
+ if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0)
+ {
+ if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
+ device->classes |= CLASS_TOUCHSCREEN;
+ }
+ }
+ }
+
+#ifdef EV_SW
+ // figure out the switches this device reports
+ uint8_t sw_bitmask[(SW_MAX+1)/8];
+ memset(sw_bitmask, 0, sizeof(sw_bitmask));
+ if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
+ for (int i=0; i<EV_SW; i++) {
+ //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
+ if (test_bit(i, sw_bitmask)) {
+ if (mSwitches[i] == 0) {
+ mSwitches[i] = device->id;
+ }
+ }
+ }
+ }
+#endif
+
+ LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
+ deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
+
+ if ((device->classes&CLASS_KEYBOARD) != 0) {
+ char devname[101];
+ char tmpfn[101];
+ char keylayoutFilename[300];
+
+ // a more descriptive name
+ ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
+ devname[sizeof(devname)-1] = 0;
+ device->name = devname;
+
+ // replace all the spaces with underscores
+ strcpy(tmpfn, devname);
+ for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
+ *p = '_';
+
+ // find the .kl file we need for this device
+ const char* root = getenv("ANDROID_ROOT");
+ snprintf(keylayoutFilename, sizeof(keylayoutFilename),
+ "%s/usr/keylayout/%s.kl", root, tmpfn);
+ bool defaultKeymap = false;
+ if (access(keylayoutFilename, R_OK)) {
+ snprintf(keylayoutFilename, sizeof(keylayoutFilename),
+ "%s/usr/keylayout/%s", root, "qwerty.kl");
+ defaultKeymap = true;
+ }
+ device->layoutMap->load(keylayoutFilename);
+
+ // tell the world about the devname (the descriptive name)
+ int32_t publicID;
+ if (!mHaveFirstKeyboard && !defaultKeymap) {
+ publicID = 0;
+ // the built-in keyboard has a well-known device ID of 0,
+ // this device better not go away.
+ mHaveFirstKeyboard = true;
+ mFirstKeyboardId = device->id;
+ } else {
+ publicID = device->id;
+ // ensure mFirstKeyboardId is set to -something-.
+ if (mFirstKeyboardId == 0) {
+ mFirstKeyboardId = device->id;
+ }
+ }
+ char propName[100];
+ sprintf(propName, "hw.keyboards.%u.devname", publicID);
+ property_set(propName, devname);
+
+ LOGI("New keyboard: publicID=%d device->id=%d devname='%s propName='%s' keylayout='%s'\n",
+ publicID, device->id, devname, propName, keylayoutFilename);
+ }
+
+ LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
+ deviceName, device, mFDCount, devid, device->classes);
+
+ mDevicesById[devid].device = device;
+ device->next = mOpeningDevices;
+ mOpeningDevices = device;
+ mDevices[mFDCount] = device;
+
+ mFDCount++;
+ return 0;
+}
+
+int EventHub::close_device(const char *deviceName)
+{
+ AutoMutex _l(mLock);
+
+ int i;
+ for(i = 1; i < mFDCount; i++) {
+ if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
+ //LOGD("remove device %d: %s\n", i, deviceName);
+ device_t* device = mDevices[i];
+ int count = mFDCount - i - 1;
+ int index = (device->id&ID_MASK);
+ mDevicesById[index].device = NULL;
+ memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
+ memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
+
+#ifdef EV_SW
+ for (int j=0; j<EV_SW; j++) {
+ if (mSwitches[j] == device->id) {
+ mSwitches[j] = 0;
+ }
+ }
+#endif
+
+ device->next = mClosingDevices;
+ mClosingDevices = device;
+
+ mFDCount--;
+
+ uint32_t publicID;
+ if (device->id == mFirstKeyboardId) {
+ LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
+ device->path.string(), mFirstKeyboardId);
+ mFirstKeyboardId = 0;
+ publicID = 0;
+ } else {
+ publicID = device->id;
+ }
+ // clear the property
+ char propName[100];
+ sprintf(propName, "hw.keyboards.%u.devname", publicID);
+ property_set(propName, NULL);
+ return 0;
+ }
+ }
+ LOGE("remote device: %s not found\n", deviceName);
+ return -1;
+}
+
+int EventHub::read_notify(int nfd)
+{
+#ifdef HAVE_INOTIFY
+ int res;
+ char devname[PATH_MAX];
+ char *filename;
+ char event_buf[512];
+ int event_size;
+ int event_pos = 0;
+ struct inotify_event *event;
+
+ res = read(nfd, event_buf, sizeof(event_buf));
+ if(res < (int)sizeof(*event)) {
+ if(errno == EINTR)
+ return 0;
+ LOGW("could not get event, %s\n", strerror(errno));
+ return 1;
+ }
+ //printf("got %d bytes of event information\n", res);
+
+ strcpy(devname, device_path);
+ filename = devname + strlen(devname);
+ *filename++ = '/';
+
+ while(res >= (int)sizeof(*event)) {
+ event = (struct inotify_event *)(event_buf + event_pos);
+ //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
+ if(event->len) {
+ strcpy(filename, event->name);
+ if(event->mask & IN_CREATE) {
+ open_device(devname);
+ }
+ else {
+ close_device(devname);
+ }
+ }
+ event_size = sizeof(*event) + event->len;
+ res -= event_size;
+ event_pos += event_size;
+ }
+#endif
+ return 0;
+}
+
+
+int EventHub::scan_dir(const char *dirname)
+{
+ char devname[PATH_MAX];
+ char *filename;
+ DIR *dir;
+ struct dirent *de;
+ dir = opendir(dirname);
+ if(dir == NULL)
+ return -1;
+ strcpy(devname, dirname);
+ filename = devname + strlen(devname);
+ *filename++ = '/';
+ while((de = readdir(dir))) {
+ if(de->d_name[0] == '.' &&
+ (de->d_name[1] == '\0' ||
+ (de->d_name[1] == '.' && de->d_name[2] == '\0')))
+ continue;
+ strcpy(filename, de->d_name);
+ open_device(devname);
+ }
+ closedir(dir);
+ return 0;
+}
+
+}; // namespace android
diff --git a/libs/ui/EventRecurrence.cpp b/libs/ui/EventRecurrence.cpp
new file mode 100644
index 0000000..b436b50
--- /dev/null
+++ b/libs/ui/EventRecurrence.cpp
@@ -0,0 +1,484 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ */
+
+#include <pim/EventRecurrence.h>
+#include <utils/String8.h>
+#include <stdio.h>
+#include <limits.h>
+
+namespace android {
+
+#define FAIL_HERE() do { \
+ printf("Parsing failed at line %d\n", __LINE__); \
+ return UNKNOWN_ERROR; \
+ } while(0)
+
+EventRecurrence::EventRecurrence()
+ :freq((freq_t)0),
+ until(),
+ count(0),
+ interval(0),
+ bysecond(0),
+ bysecondCount(0),
+ byminute(0),
+ byminuteCount(0),
+ byhour(0),
+ byhourCount(0),
+ byday(0),
+ bydayNum(0),
+ bydayCount(0),
+ bymonthday(0),
+ bymonthdayCount(0),
+ byyearday(0),
+ byyeardayCount(0),
+ byweekno(0),
+ byweeknoCount(0),
+ bymonth(0),
+ bymonthCount(0),
+ bysetpos(0),
+ bysetposCount(0),
+ wkst(0)
+{
+}
+
+EventRecurrence::~EventRecurrence()
+{
+ delete[] bysecond;
+ delete[] byminute;
+ delete[] byhour;
+ delete[] byday;
+ delete[] bydayNum;
+ delete[] byyearday;
+ delete[] bymonthday;
+ delete[] byweekno;
+ delete[] bymonth;
+ delete[] bysetpos;
+}
+
+enum LHS {
+ NONE_LHS = 0,
+ FREQ,
+ UNTIL,
+ COUNT,
+ INTERVAL,
+ BYSECOND,
+ BYMINUTE,
+ BYHOUR,
+ BYDAY,
+ BYMONTHDAY,
+ BYYEARDAY,
+ BYWEEKNO,
+ BYMONTH,
+ BYSETPOS,
+ WKST
+};
+
+struct LHSProc
+{
+ const char16_t* text;
+ size_t textSize;
+ uint32_t value;
+};
+
+const char16_t FREQ_text[] = { 'F', 'R', 'E', 'Q' };
+const char16_t UNTIL_text[] = { 'U', 'N', 'T', 'I', 'L' };
+const char16_t COUNT_text[] = { 'C', 'O', 'U', 'N', 'T' };
+const char16_t INTERVAL_text[] = { 'I', 'N', 'T', 'E', 'R', 'V', 'A', 'L'};
+const char16_t BYSECOND_text[] = { 'B', 'Y', 'S', 'E', 'C', 'O', 'N', 'D' };
+const char16_t BYMINUTE_text[] = { 'B', 'Y', 'M', 'I', 'N', 'U', 'T', 'E' };
+const char16_t BYHOUR_text[] = { 'B', 'Y', 'H', 'O', 'U', 'R' };
+const char16_t BYDAY_text[] = { 'B', 'Y', 'D', 'A', 'Y' };
+const char16_t BYMONTHDAY_text[] = { 'B','Y','M','O','N','T','H','D','A','Y' };
+const char16_t BYYEARDAY_text[] = { 'B','Y','Y','E','A','R','D','A','Y' };
+const char16_t BYWEEKNO_text[] = { 'B', 'Y', 'W', 'E', 'E', 'K', 'N', 'O' };
+const char16_t BYMONTH_text[] = { 'B', 'Y', 'M', 'O', 'N', 'T', 'H' };
+const char16_t BYSETPOS_text[] = { 'B', 'Y', 'S', 'E', 'T', 'P', 'O', 'S' };
+const char16_t WKST_text[] = { 'W', 'K', 'S', 'T' };
+
+#define SIZ(x) (sizeof(x)/sizeof(x[0]))
+
+const LHSProc LHSPROC[] = {
+ { FREQ_text, SIZ(FREQ_text), FREQ },
+ { UNTIL_text, SIZ(UNTIL_text), UNTIL },
+ { COUNT_text, SIZ(COUNT_text), COUNT },
+ { INTERVAL_text, SIZ(INTERVAL_text), INTERVAL },
+ { BYSECOND_text, SIZ(BYSECOND_text), BYSECOND },
+ { BYMINUTE_text, SIZ(BYMINUTE_text), BYMINUTE },
+ { BYHOUR_text, SIZ(BYHOUR_text), BYHOUR },
+ { BYDAY_text, SIZ(BYDAY_text), BYDAY },
+ { BYMONTHDAY_text, SIZ(BYMONTHDAY_text), BYMONTHDAY },
+ { BYYEARDAY_text, SIZ(BYYEARDAY_text), BYYEARDAY },
+ { BYWEEKNO_text, SIZ(BYWEEKNO_text), BYWEEKNO },
+ { BYMONTH_text, SIZ(BYMONTH_text), BYMONTH },
+ { BYSETPOS_text, SIZ(BYSETPOS_text), BYSETPOS },
+ { WKST_text, SIZ(WKST_text), WKST },
+ { NULL, 0, NONE_LHS },
+};
+
+const char16_t SECONDLY_text[] = { 'S','E','C','O','N','D','L','Y' };
+const char16_t MINUTELY_text[] = { 'M','I','N','U','T','E','L','Y' };
+const char16_t HOURLY_text[] = { 'H','O','U','R','L','Y' };
+const char16_t DAILY_text[] = { 'D','A','I','L','Y' };
+const char16_t WEEKLY_text[] = { 'W','E','E','K','L','Y' };
+const char16_t MONTHLY_text[] = { 'M','O','N','T','H','L','Y' };
+const char16_t YEARLY_text[] = { 'Y','E','A','R','L','Y' };
+
+typedef LHSProc FreqProc;
+
+const FreqProc FREQPROC[] = {
+ { SECONDLY_text, SIZ(SECONDLY_text), EventRecurrence::SECONDLY },
+ { MINUTELY_text, SIZ(MINUTELY_text), EventRecurrence::MINUTELY },
+ { HOURLY_text, SIZ(HOURLY_text), EventRecurrence::HOURLY },
+ { DAILY_text, SIZ(DAILY_text), EventRecurrence::DAILY },
+ { WEEKLY_text, SIZ(WEEKLY_text), EventRecurrence::WEEKLY },
+ { MONTHLY_text, SIZ(MONTHLY_text), EventRecurrence::MONTHLY },
+ { YEARLY_text, SIZ(YEARLY_text), EventRecurrence::YEARLY },
+ { NULL, 0, NONE_LHS },
+};
+
+const char16_t SU_text[] = { 'S','U' };
+const char16_t MO_text[] = { 'M','O' };
+const char16_t TU_text[] = { 'T','U' };
+const char16_t WE_text[] = { 'W','E' };
+const char16_t TH_text[] = { 'T','H' };
+const char16_t FR_text[] = { 'F','R' };
+const char16_t SA_text[] = { 'S','A' };
+
+const FreqProc WEEKDAYPROC[] = {
+ { SU_text, SIZ(SU_text), EventRecurrence::SU },
+ { MO_text, SIZ(MO_text), EventRecurrence::MO },
+ { TU_text, SIZ(TU_text), EventRecurrence::TU },
+ { WE_text, SIZ(WE_text), EventRecurrence::WE },
+ { TH_text, SIZ(TH_text), EventRecurrence::TH },
+ { FR_text, SIZ(FR_text), EventRecurrence::FR },
+ { SA_text, SIZ(SA_text), EventRecurrence::SA },
+ { NULL, 0, NONE_LHS },
+};
+
+// returns the index into LHSPROC for the match or -1 if not found
+inline static int
+match_proc(const LHSProc* p, const char16_t* str, size_t len)
+{
+ int i = 0;
+ while (p->text != NULL) {
+ if (p->textSize == len) {
+ if (0 == memcmp(p->text, str, len*sizeof(char16_t))) {
+ return i;
+ }
+ }
+ p++;
+ i++;
+ }
+ return -1;
+}
+
+// rangeMin and rangeMax are inclusive
+static status_t
+parse_int(const char16_t* str, size_t len, int* out,
+ int rangeMin, int rangeMax, bool zeroOK)
+{
+ char16_t c;
+ size_t i=0;
+
+ if (len == 0) {
+ FAIL_HERE();
+ }
+ bool negative = false;
+ c = str[0];
+ if (c == '-' ) {
+ negative = true;
+ i++;
+ }
+ else if (c == '+') {
+ i++;
+ }
+ int n = 0;
+ for (; i<len; i++) {
+ c = str[i];
+ if (c < '0' || c > '9') {
+ FAIL_HERE();
+ }
+ int prev = n;
+ n *= 10;
+ // the spec doesn't address how big these numbers can be,
+ // so we're not going to worry about not being able to represent
+ // INT_MIN, and if we're going to wrap, we'll just clamp to
+ // INT_MAX instead
+ if (n < prev) {
+ n = INT_MAX;
+ } else {
+ n += c - '0';
+ }
+ }
+ if (negative) {
+ n = -n;
+ }
+ if (n < rangeMin || n > rangeMax) {
+ FAIL_HERE();
+ }
+ if (!zeroOK && n == 0) {
+ FAIL_HERE();
+ }
+ *out = n;
+ return NO_ERROR;
+}
+
+static status_t
+parse_int_list(const char16_t* str, size_t len, int* countOut, int** listOut,
+ int rangeMin, int rangeMax, bool zeroOK,
+ status_t (*func)(const char16_t*,size_t,int*,int,int,bool)=parse_int)
+{
+ status_t err;
+
+ if (len == 0) {
+ *countOut = 0;
+ *listOut = NULL;
+ return NO_ERROR;
+ }
+
+ // make one pass through looking for commas so we know how big to make our
+ // out array.
+ int count = 1;
+ for (size_t i=0; i<len; i++) {
+ if (str[i] == ',') {
+ count++;
+ }
+ }
+
+ int* list = new int[count];
+ const char16_t* p = str;
+ int commaIndex = 0;
+ size_t i;
+
+ for (i=0; i<len; i++) {
+ if (str[i] == ',') {
+ err = func(p, (str+i-p), list+commaIndex, rangeMin,
+ rangeMax, zeroOK);
+ if (err != NO_ERROR) {
+ goto bail;
+ }
+ commaIndex++;
+ p = str+i+1;
+ }
+ }
+
+ err = func(p, (str+i-p), list+commaIndex, rangeMin, rangeMax, zeroOK);
+ if (err != NO_ERROR) {
+ goto bail;
+ }
+ commaIndex++;
+
+ *countOut = count;
+ *listOut = list;
+
+ return NO_ERROR;
+
+bail:
+ delete[] list;
+ FAIL_HERE();
+}
+
+// the numbers here are small, so we pack them both into one value, and then
+// split it out later. it lets us reuse all the comma separated list code.
+static status_t
+parse_byday(const char16_t* s, size_t len, int* out,
+ int rangeMin, int rangeMax, bool zeroOK)
+{
+ status_t err;
+ int n = 0;
+ const char16_t* p = s;
+ size_t plen = len;
+
+ if (len > 0) {
+ char16_t c = s[0];
+ if (c == '-' || c == '+' || (c >= '0' && c <= '9')) {
+ if (len > 1) {
+ size_t nlen = 0;
+ c = s[nlen];
+ while (nlen < len
+ && (c == '-' || c == '+' || (c >= '0' && c <= '9'))) {
+ c = s[nlen];
+ nlen++;
+ }
+ if (nlen > 0) {
+ nlen--;
+ err = parse_int(s, nlen, &n, rangeMin, rangeMax, zeroOK);
+ if (err != NO_ERROR) {
+ FAIL_HERE();
+ }
+ p += nlen;
+ plen -= nlen;
+ }
+ }
+ }
+
+ int index = match_proc(WEEKDAYPROC, p, plen);
+ if (index >= 0) {
+ *out = (0xffff0000 & WEEKDAYPROC[index].value)
+ | (0x0000ffff & n);
+ return NO_ERROR;
+ }
+ }
+ return UNKNOWN_ERROR;
+}
+
+static void
+postprocess_byday(int count, int* byday, int** bydayNum)
+{
+ int* bdn = new int[count];
+ *bydayNum = bdn;
+ for (int i=0; i<count; i++) {
+ uint32_t v = byday[i];
+ int16_t num = v & 0x0000ffff;
+ byday[i] = v & 0xffff0000;
+ // will sign extend:
+ bdn[i] = num;
+ }
+}
+
+#define PARSE_INT_LIST_CHECKED(name, rangeMin, rangeMax, zeroOK) \
+ if (name##Count != 0 || NO_ERROR != parse_int_list(s, slen, \
+ &name##Count, &name, rangeMin, rangeMax, zeroOK)) { \
+ FAIL_HERE(); \
+ }
+status_t
+EventRecurrence::parse(const String16& str)
+{
+ char16_t const* work = str.string();
+ size_t len = str.size();
+
+ int lhsIndex = NONE_LHS;
+ int index;
+
+ size_t start = 0;
+ for (size_t i=0; i<len; i++) {
+ char16_t c = work[i];
+ if (c != ';' && i == len-1) {
+ c = ';';
+ i++;
+ }
+ if (c == ';' || c == '=') {
+ if (i != start) {
+ const char16_t* s = work+start;
+ const size_t slen = i-start;
+
+ String8 thestring(String16(s, slen));
+
+ switch (c)
+ {
+ case '=':
+ if (lhsIndex == NONE_LHS) {
+ lhsIndex = match_proc(LHSPROC, s, slen);
+ if (lhsIndex >= 0) {
+ break;
+ }
+ }
+ FAIL_HERE();
+ case ';':
+ {
+ switch (LHSPROC[lhsIndex].value)
+ {
+ case FREQ:
+ if (this->freq != 0) {
+ FAIL_HERE();
+ }
+ index = match_proc(FREQPROC, s, slen);
+ if (index >= 0) {
+ this->freq = (freq_t)FREQPROC[index].value;
+ }
+ break;
+ case UNTIL:
+ // XXX should check that this is a valid time
+ until.setTo(String16(s, slen));
+ break;
+ case COUNT:
+ if (count != 0
+ || NO_ERROR != parse_int(s, slen,
+ &count, INT_MIN, INT_MAX, true)) {
+ FAIL_HERE();
+ }
+ break;
+ case INTERVAL:
+ if (interval != 0
+ || NO_ERROR != parse_int(s, slen,
+ &interval, INT_MIN, INT_MAX, false)) {
+ FAIL_HERE();
+ }
+ break;
+ case BYSECOND:
+ PARSE_INT_LIST_CHECKED(bysecond, 0, 59, true)
+ break;
+ case BYMINUTE:
+ PARSE_INT_LIST_CHECKED(byminute, 0, 59, true)
+ break;
+ case BYHOUR:
+ PARSE_INT_LIST_CHECKED(byhour, 0, 23, true)
+ break;
+ case BYDAY:
+ if (bydayCount != 0 || NO_ERROR !=
+ parse_int_list(s, slen, &bydayCount,
+ &byday, -53, 53, false,
+ parse_byday)) {
+ FAIL_HERE();
+ }
+ postprocess_byday(bydayCount, byday, &bydayNum);
+ break;
+ case BYMONTHDAY:
+ PARSE_INT_LIST_CHECKED(bymonthday, -31, 31,
+ false)
+ break;
+ case BYYEARDAY:
+ PARSE_INT_LIST_CHECKED(byyearday, -366, 366,
+ false)
+ break;
+ case BYWEEKNO:
+ PARSE_INT_LIST_CHECKED(byweekno, -53, 53,
+ false)
+ break;
+ case BYMONTH:
+ PARSE_INT_LIST_CHECKED(bymonth, 1, 12, false)
+ break;
+ case BYSETPOS:
+ PARSE_INT_LIST_CHECKED(bysetpos,
+ INT_MIN, INT_MAX, true)
+ break;
+ case WKST:
+ if (this->wkst != 0) {
+ FAIL_HERE();
+ }
+ index = match_proc(WEEKDAYPROC, s, slen);
+ if (index >= 0) {
+ this->wkst = (int)WEEKDAYPROC[index].value;
+ }
+ break;
+ default:
+ FAIL_HERE();
+ }
+ lhsIndex = NONE_LHS;
+ break;
+ }
+ }
+
+ start = i+1;
+ }
+ }
+ }
+
+ // enforce that there was a FREQ
+ if (freq == 0) {
+ FAIL_HERE();
+ }
+
+ // default wkst to MO if it wasn't specified
+ if (wkst == 0) {
+ wkst = MO;
+ }
+
+ return NO_ERROR;
+}
+
+
+}; // namespace android
+
+
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
new file mode 100644
index 0000000..420bb49
--- /dev/null
+++ b/libs/ui/ICamera.cpp
@@ -0,0 +1,204 @@
+/*
+**
+** 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <ui/ICamera.h>
+
+#define LOG_TAG "@@@@@@@@@@@ CAMERA @@@@@@@@@@@"
+#include <utils/Log.h>
+
+namespace android {
+
+enum {
+ DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ SET_PREVIEW_DISPLAY,
+ SET_HAS_FRAME_CALLBACK,
+ START_PREVIEW,
+ STOP_PREVIEW,
+ AUTO_FOCUS,
+ TAKE_PICTURE,
+ SET_PARAMETERS,
+ GET_PARAMETERS
+};
+
+class BpCamera: public BpInterface<ICamera>
+{
+public:
+ BpCamera(const sp<IBinder>& impl)
+ : BpInterface<ICamera>(impl)
+ {
+ }
+
+ // disconnect from camera service
+ void disconnect()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(DISCONNECT, data, &reply);
+ }
+
+ // pass the buffered ISurface to the camera service
+ status_t setPreviewDisplay(const sp<ISurface>& surface)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ data.writeStrongBinder(surface->asBinder());
+ remote()->transact(SET_PREVIEW_DISPLAY, data, &reply);
+ return reply.readInt32();
+ }
+
+ // tell the service whether to callback with each preview frame
+ void setHasFrameCallback(bool installed)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ data.writeInt32((int32_t)installed);
+ remote()->transact(SET_HAS_FRAME_CALLBACK, data, &reply);
+ }
+
+ // start preview mode, must call setPreviewDisplay first
+ status_t startPreview()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(START_PREVIEW, data, &reply);
+ return reply.readInt32();
+ }
+
+ // stop preview mode
+ void stopPreview()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(STOP_PREVIEW, data, &reply);
+ }
+
+ // auto focus
+ status_t autoFocus()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(AUTO_FOCUS, data, &reply);
+ status_t ret = reply.readInt32();
+ return ret;
+ }
+
+ // take a picture - returns an IMemory (ref-counted mmap)
+ status_t takePicture()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(TAKE_PICTURE, data, &reply);
+ status_t ret = reply.readInt32();
+ return ret;
+ }
+
+ // set preview/capture parameters - key/value pairs
+ status_t setParameters(const String8& params)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ data.writeString8(params);
+ remote()->transact(SET_PARAMETERS, data, &reply);
+ return reply.readInt32();
+ }
+
+ // get preview/capture parameters - key/value pairs
+ String8 getParameters() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(GET_PARAMETERS, data, &reply);
+ return reply.readString8();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnCamera::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case DISCONNECT: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ disconnect();
+ return NO_ERROR;
+ } break;
+ case SET_PREVIEW_DISPLAY: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+ reply->writeInt32(setPreviewDisplay(surface));
+ return NO_ERROR;
+ } break;
+ case SET_HAS_FRAME_CALLBACK: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ bool installed = (bool)data.readInt32();
+ setHasFrameCallback(installed);
+ return NO_ERROR;
+ } break;
+ case START_PREVIEW: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ reply->writeInt32(startPreview());
+ return NO_ERROR;
+ } break;
+ case STOP_PREVIEW: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ stopPreview();
+ return NO_ERROR;
+ } break;
+ case AUTO_FOCUS: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ reply->writeInt32(autoFocus());
+ return NO_ERROR;
+ } break;
+ case TAKE_PICTURE: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ reply->writeInt32(takePicture());
+ return NO_ERROR;
+ } break;
+ case SET_PARAMETERS: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ String8 params(data.readString8());
+ reply->writeInt32(setParameters(params));
+ return NO_ERROR;
+ } break;
+ case GET_PARAMETERS: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ reply->writeString8(getParameters());
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
new file mode 100644
index 0000000..3737034
--- /dev/null
+++ b/libs/ui/ICameraClient.cpp
@@ -0,0 +1,153 @@
+/*
+**
+** 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/ICameraClient.h>
+
+namespace android {
+
+enum {
+ SHUTTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
+ RAW_CALLBACK,
+ JPEG_CALLBACK,
+ FRAME_CALLBACK,
+ ERROR_CALLBACK,
+ AUTOFOCUS_CALLBACK
+};
+
+class BpCameraClient: public BpInterface<ICameraClient>
+{
+public:
+ BpCameraClient(const sp<IBinder>& impl)
+ : BpInterface<ICameraClient>(impl)
+ {
+ }
+
+ // callback to let the app know the shutter has closed, ideal for playing the shutter sound
+ void shutterCallback()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+ remote()->transact(SHUTTER_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ // callback from camera service to app with picture data
+ void rawCallback(const sp<IMemory>& picture)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+ data.writeStrongBinder(picture->asBinder());
+ remote()->transact(RAW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ // callback from camera service to app with picture data
+ void jpegCallback(const sp<IMemory>& picture)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+ data.writeStrongBinder(picture->asBinder());
+ remote()->transact(JPEG_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ // callback from camera service to app with video frame data
+ void frameCallback(const sp<IMemory>& frame)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+ data.writeStrongBinder(frame->asBinder());
+ remote()->transact(FRAME_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ // callback from camera service to app to report error
+ void errorCallback(status_t error)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+ data.writeInt32(error);
+ remote()->transact(ERROR_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ // callback from camera service to app to report autofocus completion
+ void autoFocusCallback(bool focused)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+ data.writeInt32(focused);
+ remote()->transact(AUTOFOCUS_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnCameraClient::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case SHUTTER_CALLBACK: {
+ CHECK_INTERFACE(ICameraClient, data, reply);
+ shutterCallback();
+ return NO_ERROR;
+ } break;
+ case RAW_CALLBACK: {
+ CHECK_INTERFACE(ICameraClient, data, reply);
+ sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder());
+ rawCallback(picture);
+ return NO_ERROR;
+ } break;
+ case JPEG_CALLBACK: {
+ CHECK_INTERFACE(ICameraClient, data, reply);
+ sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder());
+ jpegCallback(picture);
+ return NO_ERROR;
+ } break;
+ case FRAME_CALLBACK: {
+ CHECK_INTERFACE(ICameraClient, data, reply);
+ sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
+ frameCallback(frame);
+ return NO_ERROR;
+ } break;
+ case ERROR_CALLBACK: {
+ CHECK_INTERFACE(ICameraClient, data, reply);
+ status_t error = data.readInt32();
+ errorCallback(error);
+ return NO_ERROR;
+ } break;
+ case AUTOFOCUS_CALLBACK: {
+ CHECK_INTERFACE(ICameraClient, data, reply);
+ bool focused = (bool)data.readInt32();
+ autoFocusCallback(focused);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libs/ui/ICameraService.cpp b/libs/ui/ICameraService.cpp
new file mode 100644
index 0000000..e5687fe
--- /dev/null
+++ b/libs/ui/ICameraService.cpp
@@ -0,0 +1,77 @@
+/*
+**
+** 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
+#include <ui/ICameraService.h>
+
+namespace android {
+
+class BpCameraService: public BpInterface<ICameraService>
+{
+public:
+ BpCameraService(const sp<IBinder>& impl)
+ : BpInterface<ICameraService>(impl)
+ {
+ }
+
+ // connect to camera service
+ virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+ data.writeStrongBinder(cameraClient->asBinder());
+ remote()->transact(BnCameraService::CONNECT, data, &reply);
+ return interface_cast<ICamera>(reply.readStrongBinder());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnCameraService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case CONNECT: {
+ CHECK_INTERFACE(ICameraService, data, reply);
+ sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
+ sp<ICamera> camera = connect(cameraClient);
+ reply->writeStrongBinder(camera->asBinder());
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
new file mode 100644
index 0000000..817f4d9
--- /dev/null
+++ b/libs/ui/ISurface.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IMemory.h>
+
+#include <ui/ISurface.h>
+
+
+namespace android {
+
+enum {
+ REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION,
+ UNREGISTER_BUFFERS,
+ POST_BUFFER, // one-way transaction
+};
+
+class BpSurface : public BpInterface<ISurface>
+{
+public:
+ BpSurface(const sp<IBinder>& impl)
+ : BpInterface<ISurface>(impl)
+ {
+ }
+
+ virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
+ PixelFormat format, const sp<IMemoryHeap>& heap)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ data.writeInt32(w);
+ data.writeInt32(h);
+ data.writeInt32(hstride);
+ data.writeInt32(vstride);
+ data.writeInt32(format);
+ data.writeStrongBinder(heap->asBinder());
+ remote()->transact(REGISTER_BUFFERS, data, &reply);
+ status_t result = reply.readInt32();
+ return result;
+ }
+
+ virtual void postBuffer(ssize_t offset)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ data.writeInt32(offset);
+ remote()->transact(POST_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual void unregisterBuffers()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ remote()->transact(UNREGISTER_BUFFERS, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnSurface::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case REGISTER_BUFFERS: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ int w = data.readInt32();
+ int h = data.readInt32();
+ int hs= data.readInt32();
+ int vs= data.readInt32();
+ PixelFormat f = data.readInt32();
+ sp<IMemoryHeap> heap(interface_cast<IMemoryHeap>(data.readStrongBinder()));
+ status_t err = registerBuffers(w,h,hs,vs,f,heap);
+ reply->writeInt32(err);
+ return NO_ERROR;
+ } break;
+ case UNREGISTER_BUFFERS: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ unregisterBuffers();
+ return NO_ERROR;
+ } break;
+ case POST_BUFFER: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ ssize_t offset = data.readInt32();
+ postBuffer(offset);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
diff --git a/libs/ui/ISurfaceComposer.cpp b/libs/ui/ISurfaceComposer.cpp
new file mode 100644
index 0000000..0fea6f9
--- /dev/null
+++ b/libs/ui/ISurfaceComposer.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// tag as surfaceflinger
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IMemory.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
+#include <ui/ISurfaceComposer.h>
+#include <ui/DisplayInfo.h>
+
+// ---------------------------------------------------------------------------
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
+{
+public:
+ BpSurfaceComposer(const sp<IBinder>& impl)
+ : BpInterface<ISurfaceComposer>(impl)
+ {
+ }
+
+ virtual sp<ISurfaceFlingerClient> createConnection()
+ {
+ uint32_t n;
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
+ return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder());
+ }
+
+ virtual sp<IMemory> getCblk() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::GET_CBLK, data, &reply);
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+
+ virtual void openGlobalTransaction()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::OPEN_GLOBAL_TRANSACTION, data, &reply);
+ }
+
+ virtual void closeGlobalTransaction()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::CLOSE_GLOBAL_TRANSACTION, data, &reply);
+ }
+
+ virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(dpy);
+ data.writeInt32(flags);
+ remote()->transact(BnSurfaceComposer::FREEZE_DISPLAY, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(dpy);
+ data.writeInt32(flags);
+ remote()->transact(BnSurfaceComposer::UNFREEZE_DISPLAY, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual int setOrientation(DisplayID dpy, int orientation)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(dpy);
+ data.writeInt32(orientation);
+ remote()->transact(BnSurfaceComposer::SET_ORIENTATION, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual void bootFinished()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
+ }
+
+ virtual status_t requestGPU(
+ const sp<IGPUCallback>& callback, gpu_info_t* gpu)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(callback->asBinder());
+ remote()->transact(BnSurfaceComposer::REQUEST_GPU, data, &reply);
+ gpu->regs = interface_cast<IMemory>(reply.readStrongBinder());
+ gpu->count = reply.readInt32();
+
+ // FIXME: for now, we don't dynamically allocate the regions array
+ size_t maxCount = sizeof(gpu->regions)/sizeof(*gpu->regions);
+ if (gpu->count > maxCount)
+ return BAD_VALUE;
+
+ for (size_t i=0 ; i<gpu->count ; i++) {
+ gpu->regions[i].region = interface_cast<IMemory>(reply.readStrongBinder());
+ gpu->regions[i].reserved = reply.readInt32();
+ }
+ return reply.readInt32();
+ }
+
+ virtual status_t revokeGPU()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::REVOKE_GPU, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual void signal() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnSurfaceComposer::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ status_t err = BnInterface<ISurfaceComposer>::onTransact(code, data, reply, flags);
+ if (err == NO_ERROR)
+ return err;
+
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+
+ switch(code) {
+ case CREATE_CONNECTION: {
+ sp<IBinder> b = createConnection()->asBinder();
+ reply->writeStrongBinder(b);
+ } break;
+ case OPEN_GLOBAL_TRANSACTION: {
+ openGlobalTransaction();
+ } break;
+ case CLOSE_GLOBAL_TRANSACTION: {
+ closeGlobalTransaction();
+ } break;
+ case SET_ORIENTATION: {
+ DisplayID dpy = data.readInt32();
+ int orientation = data.readInt32();
+ reply->writeInt32( setOrientation(dpy, orientation) );
+ } break;
+ case FREEZE_DISPLAY: {
+ DisplayID dpy = data.readInt32();
+ uint32_t flags = data.readInt32();
+ reply->writeInt32( freezeDisplay(dpy, flags) );
+ } break;
+ case UNFREEZE_DISPLAY: {
+ DisplayID dpy = data.readInt32();
+ uint32_t flags = data.readInt32();
+ reply->writeInt32( unfreezeDisplay(dpy, flags) );
+ } break;
+ case BOOT_FINISHED: {
+ bootFinished();
+ } break;
+ case REVOKE_GPU: {
+ reply->writeInt32( revokeGPU() );
+ } break;
+ case SIGNAL: {
+ signal();
+ } break;
+ case GET_CBLK: {
+ sp<IBinder> b = getCblk()->asBinder();
+ reply->writeStrongBinder(b);
+ } break;
+ case REQUEST_GPU: {
+ // TODO: this should be protected by a permission
+ gpu_info_t info;
+ sp<IGPUCallback> callback
+ = interface_cast<IGPUCallback>(data.readStrongBinder());
+ status_t res = requestGPU(callback, &info);
+
+ // FIXME: for now, we don't dynamically allocate the regions array
+ size_t maxCount = sizeof(info.regions)/sizeof(*info.regions);
+ if (info.count > maxCount)
+ return BAD_VALUE;
+
+ reply->writeStrongBinder(info.regs->asBinder());
+ reply->writeInt32(info.count);
+ for (size_t i=0 ; i<info.count ; i++) {
+ reply->writeStrongBinder(info.regions[i].region->asBinder());
+ reply->writeInt32(info.regions[i].reserved);
+ }
+ reply->writeInt32(res);
+ } break;
+ default:
+ return UNKNOWN_TRANSACTION;
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+enum {
+ // Note: BOOT_FINISHED must remain this value, it is called by ActivityManagerService.
+ GPU_LOST = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpGPUCallback : public BpInterface<IGPUCallback>
+{
+public:
+ BpGPUCallback(const sp<IBinder>& impl)
+ : BpInterface<IGPUCallback>(impl)
+ {
+ }
+
+ virtual void gpuLost()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGPUCallback::getInterfaceDescriptor());
+ remote()->transact(GPU_LOST, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(GPUCallback, "android.ui.IGPUCallback");
+
+status_t BnGPUCallback::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case GPU_LOST: {
+ CHECK_INTERFACE(IGPUCallback, data, reply);
+ gpuLost();
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+};
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
new file mode 100644
index 0000000..9444af7
--- /dev/null
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// tag as surfaceflinger
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IMemory.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
+#include <ui/ISurface.h>
+#include <ui/ISurfaceFlingerClient.h>
+#include <ui/Point.h>
+#include <ui/Rect.h>
+
+#include <private/ui/LayerState.h>
+
+// ---------------------------------------------------------------------------
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+enum {
+ GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+ CREATE_SURFACE,
+ DESTROY_SURFACE,
+ SET_STATE
+};
+
+class BpSurfaceFlingerClient : public BpInterface<ISurfaceFlingerClient>
+{
+public:
+ BpSurfaceFlingerClient(const sp<IBinder>& impl)
+ : BpInterface<ISurfaceFlingerClient>(impl)
+ {
+ }
+
+ virtual void getControlBlocks(sp<IMemory>* ctl) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+ remote()->transact(GET_CBLK, data, &reply);
+ *ctl = interface_cast<IMemory>(reply.readStrongBinder());
+ }
+
+ virtual sp<ISurface> createSurface( surface_data_t* params,
+ int pid,
+ DisplayID display,
+ uint32_t w,
+ uint32_t h,
+ PixelFormat format,
+ uint32_t flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeInt32(display);
+ data.writeInt32(w);
+ data.writeInt32(h);
+ data.writeInt32(format);
+ data.writeInt32(flags);
+ remote()->transact(CREATE_SURFACE, data, &reply);
+ params->readFromParcel(data);
+ return interface_cast<ISurface>(reply.readStrongBinder());
+ }
+
+ virtual status_t destroySurface(SurfaceID sid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+ data.writeInt32(sid);
+ remote()->transact(DESTROY_SURFACE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setState(int32_t count, const layer_state_t* states)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
+ data.writeInt32(count);
+ for (int i=0 ; i<count ; i++)
+ states[i].write(data);
+ remote()->transact(SET_STATE, data, &reply);
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(SurfaceFlingerClient, "android.ui.ISurfaceFlingerClient");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnSurfaceFlingerClient::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ // codes that don't require permission check
+
+ switch(code) {
+ case GET_CBLK: {
+ CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+ sp<IMemory> ctl;
+ getControlBlocks(&ctl);
+ reply->writeStrongBinder(ctl->asBinder());
+ return NO_ERROR;
+ } break;
+ }
+
+ // these must be checked
+
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int self_pid = getpid();
+ if (UNLIKELY(pid != self_pid)) {
+ // we're called from a different process, do the real check
+ if (!checkCallingPermission(
+ String16("android.permission.ACCESS_SURFACE_FLINGER")))
+ {
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+
+ switch(code) {
+ case CREATE_SURFACE: {
+ CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+ surface_data_t params;
+ int32_t pid = data.readInt32();
+ DisplayID display = data.readInt32();
+ uint32_t w = data.readInt32();
+ uint32_t h = data.readInt32();
+ PixelFormat format = data.readInt32();
+ uint32_t flags = data.readInt32();
+ sp<ISurface> s = createSurface(&params, pid, display, w, h, format, flags);
+ params.writeToParcel(reply);
+ reply->writeStrongBinder(s->asBinder());
+ return NO_ERROR;
+ } break;
+ case DESTROY_SURFACE: {
+ CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+ reply->writeInt32( destroySurface( data.readInt32() ) );
+ return NO_ERROR;
+ } break;
+ case SET_STATE: {
+ CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
+ int32_t count = data.readInt32();
+ layer_state_t* states = new layer_state_t[count];
+ for (int i=0 ; i<count ; i++)
+ states[i].read(data);
+ status_t err = setState(count, states);
+ delete [] states;
+ reply->writeInt32(err);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------
+
+status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel)
+{
+ token = parcel.readInt32();
+ identity = parcel.readInt32();
+ type = parcel.readInt32();
+ heap[0] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
+ heap[1] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
+ return NO_ERROR;
+}
+
+status_t ISurfaceFlingerClient::surface_data_t::writeToParcel(Parcel* parcel) const
+{
+ parcel->writeInt32(token);
+ parcel->writeInt32(identity);
+ parcel->writeInt32(type);
+ parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
+ parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp
new file mode 100644
index 0000000..e891181
--- /dev/null
+++ b/libs/ui/KeyCharacterMap.cpp
@@ -0,0 +1,263 @@
+#define LOG_TAG "KeyCharacterMap"
+
+#include <ui/KeyCharacterMap.h>
+#include <cutils/properties.h>
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <string.h>
+
+struct Header
+{
+ char magic[8];
+ unsigned int endian;
+ unsigned int version;
+ unsigned int keycount;
+ unsigned char kbdtype;
+ char padding[11];
+};
+
+KeyCharacterMap::KeyCharacterMap()
+{
+}
+
+KeyCharacterMap::~KeyCharacterMap()
+{
+ free(m_keys);
+}
+
+unsigned short
+KeyCharacterMap::get(int keycode, int meta)
+{
+ Key* k = find_key(keycode);
+ if (k != NULL) {
+ return k->data[meta & META_MASK];
+ }
+ return 0;
+}
+
+unsigned short
+KeyCharacterMap::getNumber(int keycode)
+{
+ Key* k = find_key(keycode);
+ if (k != NULL) {
+ return k->number;
+ }
+ return 0;
+}
+
+unsigned short
+KeyCharacterMap::getMatch(int keycode, const unsigned short* chars,
+ int charsize, uint32_t modifiers)
+{
+ Key* k = find_key(keycode);
+ modifiers &= 3; // ignore the SYM key because we don't have keymap entries for it
+ if (k != NULL) {
+ const uint16_t* data = k->data;
+ for (int j=0; j<charsize; j++) {
+ uint16_t c = chars[j];
+ for (int i=0; i<(META_MASK + 1); i++) {
+ if ((modifiers == 0) || ((modifiers & i) != 0)) {
+ if (c == data[i]) {
+ return c;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+unsigned short
+KeyCharacterMap::getDisplayLabel(int keycode)
+{
+ Key* k = find_key(keycode);
+ if (k != NULL) {
+ return k->display_label;
+ }
+ return 0;
+}
+
+bool
+KeyCharacterMap::getKeyData(int keycode, unsigned short *displayLabel,
+ unsigned short *number, unsigned short* results)
+{
+ Key* k = find_key(keycode);
+ if (k != NULL) {
+ memcpy(results, k->data, sizeof(short)*(META_MASK + 1));
+ *number = k->number;
+ *displayLabel = k->display_label;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool
+KeyCharacterMap::find_char(uint16_t c, uint32_t* key, uint32_t* mods)
+{
+ uint32_t N = m_keyCount;
+ for (int j=0; j<(META_MASK + 1); j++) {
+ Key const* keys = m_keys;
+ for (uint32_t i=0; i<N; i++) {
+ if (keys->data[j] == c) {
+ *key = keys->keycode;
+ *mods = j;
+ return true;
+ }
+ keys++;
+ }
+ }
+ return false;
+}
+
+bool
+KeyCharacterMap::getEvents(uint16_t* chars, size_t len,
+ Vector<int32_t>* keys, Vector<uint32_t>* modifiers)
+{
+ for (size_t i=0; i<len; i++) {
+ uint32_t k, mods;
+ if (find_char(chars[i], &k, &mods)) {
+ keys->add(k);
+ modifiers->add(mods);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+KeyCharacterMap::Key*
+KeyCharacterMap::find_key(int keycode)
+{
+ Key* keys = m_keys;
+ int low = 0;
+ int high = m_keyCount - 1;
+ int mid;
+ int n;
+ while (low <= high) {
+ mid = (low + high) / 2;
+ n = keys[mid].keycode;
+ if (keycode < n) {
+ high = mid - 1;
+ } else if (keycode > n) {
+ low = mid + 1;
+ } else {
+ return keys + mid;
+ }
+ }
+ return NULL;
+}
+
+KeyCharacterMap*
+KeyCharacterMap::load(int id)
+{
+ KeyCharacterMap* rv = NULL;
+ char path[PATH_MAX];
+ char propName[100];
+ char dev[PROPERTY_VALUE_MAX];
+ char tmpfn[PROPERTY_VALUE_MAX];
+ int err;
+ const char* root = getenv("ANDROID_ROOT");
+
+ sprintf(propName, "hw.keyboards.%u.devname", id);
+ err = property_get(propName, dev, "");
+ if (err > 0) {
+ // replace all the spaces with underscores
+ strcpy(tmpfn, dev);
+ for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
+ *p = '_';
+ snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn);
+ //LOGD("load: dev='%s' path='%s'\n", dev, path);
+ rv = try_file(path);
+ if (rv != NULL) {
+ return rv;
+ }
+ LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev);
+ } else {
+ LOGW("No keyboard for id %d", id);
+ }
+
+ snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root);
+ rv = try_file(path);
+ if (rv == NULL) {
+ LOGE("Can't find any keycharmaps (also tried %s)", path);
+ return NULL;
+ }
+ LOGW("Using default keymap: %s", path);
+
+ return rv;
+}
+
+KeyCharacterMap*
+KeyCharacterMap::try_file(const char* filename)
+{
+ KeyCharacterMap* rv = NULL;
+ Key* keys;
+ int fd;
+ off_t filesize;
+ Header header;
+ int err;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ LOGW("Can't open keycharmap file");
+ return NULL;
+ }
+
+ filesize = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+
+ // validate the header
+ if (filesize <= (off_t)sizeof(header)) {
+ LOGW("Bad keycharmap - filesize=%d\n", (int)filesize);
+ goto cleanup1;
+ }
+
+ err = read(fd, &header, sizeof(header));
+ if (err == -1) {
+ LOGW("Error reading keycharmap file");
+ goto cleanup1;
+ }
+
+ if (0 != memcmp(header.magic, "keychar", 8)) {
+ LOGW("Bad keycharmap magic token");
+ goto cleanup1;
+ }
+ if (header.endian != 0x12345678) {
+ LOGW("Bad keycharmap endians");
+ goto cleanup1;
+ }
+ if ((header.version & 0xff) != 2) {
+ LOGW("Only support keycharmap version 2 (got 0x%08x)", header.version);
+ goto cleanup1;
+ }
+ if (filesize < (off_t)(sizeof(Header)+(sizeof(Key)*header.keycount))) {
+ LOGW("Bad keycharmap file size\n");
+ goto cleanup1;
+ }
+
+ // read the key data
+ keys = (Key*)malloc(sizeof(Key)*header.keycount);
+ err = read(fd, keys, sizeof(Key)*header.keycount);
+ if (err == -1) {
+ LOGW("Error reading keycharmap file");
+ free(keys);
+ goto cleanup1;
+ }
+
+ // return the object
+ rv = new KeyCharacterMap;
+ rv->m_keyCount = header.keycount;
+ rv->m_keys = keys;
+ rv->m_type = header.kbdtype;
+
+cleanup1:
+ close(fd);
+
+ return rv;
+}
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp
new file mode 100644
index 0000000..15ae54c
--- /dev/null
+++ b/libs/ui/KeyLayoutMap.cpp
@@ -0,0 +1,235 @@
+#define LOG_TAG "KeyLayoutMap"
+
+#include "KeyLayoutMap.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <utils/String8.h>
+#include <stdlib.h>
+#include <ui/KeycodeLabels.h>
+#include <utils/Log.h>
+
+namespace android {
+
+KeyLayoutMap::KeyLayoutMap()
+ :m_status(NO_INIT),
+ m_keys()
+{
+}
+
+KeyLayoutMap::~KeyLayoutMap()
+{
+}
+
+static String8
+next_token(char const** p, int *line)
+{
+ bool begun = false;
+ const char* begin = *p;
+ const char* end = *p;
+ while (true) {
+ if (*end == '\n') {
+ (*line)++;
+ }
+ switch (*end)
+ {
+ case '#':
+ if (begun) {
+ *p = end;
+ return String8(begin, end-begin);
+ } else {
+ do {
+ begin++;
+ end++;
+ } while (*begin != '\0' && *begin != '\n');
+ }
+ case '\0':
+ case ' ':
+ case '\n':
+ case '\r':
+ case '\t':
+ if (begun || (*end == '\0')) {
+ *p = end;
+ return String8(begin, end-begin);
+ } else {
+ begin++;
+ end++;
+ break;
+ }
+ default:
+ end++;
+ begun = true;
+ }
+ }
+}
+
+static int32_t
+token_to_value(const char *literal, const KeycodeLabel *list)
+{
+ while (list->literal) {
+ if (0 == strcmp(literal, list->literal)) {
+ return list->value;
+ }
+ list++;
+ }
+ return list->value;
+}
+
+status_t
+KeyLayoutMap::load(const char* filename)
+{
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ LOGE("error opening file=%s err=%s\n", filename, strerror(errno));
+ m_status = errno;
+ return errno;
+ }
+
+ off_t len = lseek(fd, 0, SEEK_END);
+ off_t errlen = lseek(fd, 0, SEEK_SET);
+ if (len < 0 || errlen < 0) {
+ close(fd);
+ LOGE("error seeking file=%s err=%s\n", filename, strerror(errno));
+ m_status = errno;
+ return errno;
+ }
+
+ char* buf = (char*)malloc(len+1);
+ if (read(fd, buf, len) != len) {
+ LOGE("error reading file=%s err=%s\n", filename, strerror(errno));
+ m_status = errno != 0 ? errno : ((int)NOT_ENOUGH_DATA);
+ return errno != 0 ? errno : ((int)NOT_ENOUGH_DATA);
+ }
+ errno = 0;
+ buf[len] = '\0';
+
+ int32_t scancode = -1;
+ int32_t keycode = -1;
+ uint32_t flags = 0;
+ uint32_t tmp;
+ char* end;
+ status_t err = NO_ERROR;
+ int line = 1;
+ char const* p = buf;
+ enum { BEGIN, SCANCODE, KEYCODE, FLAG } state = BEGIN;
+ while (true) {
+ String8 token = next_token(&p, &line);
+ if (*p == '\0') {
+ break;
+ }
+ switch (state)
+ {
+ case BEGIN:
+ if (token == "key") {
+ state = SCANCODE;
+ } else {
+ LOGE("%s:%d: expected key, got '%s'\n", filename, line,
+ token.string());
+ err = BAD_VALUE;
+ goto done;
+ }
+ break;
+ case SCANCODE:
+ scancode = strtol(token.string(), &end, 0);
+ if (*end != '\0') {
+ LOGE("%s:%d: expected scancode (a number), got '%s'\n",
+ filename, line, token.string());
+ goto done;
+ }
+ //LOGI("%s:%d: got scancode %d\n", filename, line, scancode );
+ state = KEYCODE;
+ break;
+ case KEYCODE:
+ keycode = token_to_value(token.string(), KEYCODES);
+ //LOGI("%s:%d: got keycode %d for %s\n", filename, line, keycode, token.string() );
+ if (keycode == 0) {
+ LOGE("%s:%d: expected keycode, got '%s'\n",
+ filename, line, token.string());
+ goto done;
+ }
+ state = FLAG;
+ break;
+ case FLAG:
+ if (token == "key") {
+ if (scancode != -1) {
+ //LOGI("got key decl scancode=%d keycode=%d"
+ // " flags=0x%08x\n", scancode, keycode, flags);
+ Key k = { keycode, flags };
+ m_keys.add(scancode, k);
+ state = SCANCODE;
+ scancode = -1;
+ keycode = -1;
+ flags = 0;
+ break;
+ }
+ }
+ tmp = token_to_value(token.string(), FLAGS);
+ //LOGI("%s:%d: got flags %x for %s\n", filename, line, tmp, token.string() );
+ if (tmp == 0) {
+ LOGE("%s:%d: expected flag, got '%s'\n",
+ filename, line, token.string());
+ goto done;
+ }
+ flags |= tmp;
+ break;
+ }
+ }
+ if (state == FLAG && scancode != -1 ) {
+ //LOGI("got key decl scancode=%d keycode=%d"
+ // " flags=0x%08x\n", scancode, keycode, flags);
+ Key k = { keycode, flags };
+ m_keys.add(scancode, k);
+ }
+
+done:
+ free(buf);
+ close(fd);
+
+ m_status = err;
+ return err;
+}
+
+status_t
+KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags) const
+{
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+
+ ssize_t index = m_keys.indexOfKey(scancode);
+ if (index < 0) {
+ //LOGW("couldn't map scancode=%d\n", scancode);
+ return NAME_NOT_FOUND;
+ }
+
+ const Key& k = m_keys.valueAt(index);
+
+ *keycode = k.keycode;
+ *flags = k.flags;
+
+ //LOGD("mapped scancode=%d to keycode=%d flags=0x%08x\n", scancode,
+ // keycode, flags);
+
+ return NO_ERROR;
+}
+
+status_t
+KeyLayoutMap::findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const
+{
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+
+ const size_t N = m_keys.size();
+ for (size_t i=0; i<N; i++) {
+ if (m_keys.valueAt(i).keycode == keycode) {
+ outScancodes->add(m_keys.keyAt(i));
+ }
+ }
+
+ return NO_ERROR;
+}
+
+};
diff --git a/libs/ui/KeyLayoutMap.h b/libs/ui/KeyLayoutMap.h
new file mode 100644
index 0000000..43f84ce
--- /dev/null
+++ b/libs/ui/KeyLayoutMap.h
@@ -0,0 +1,31 @@
+#ifndef KEYLAYOUTMAP_H
+#define KEYLAYOUTMAP_H
+
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+class KeyLayoutMap
+{
+public:
+ KeyLayoutMap();
+ ~KeyLayoutMap();
+
+ status_t load(const char* filename);
+
+ status_t map(int32_t scancode, int32_t *keycode, uint32_t *flags) const;
+ status_t findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const;
+
+private:
+ struct Key {
+ int32_t keycode;
+ uint32_t flags;
+ };
+
+ status_t m_status;
+ KeyedVector<int32_t,Key> m_keys;
+};
+
+};
+
+#endif // KEYLAYOUTMAP_H
diff --git a/libs/ui/LayerState.cpp b/libs/ui/LayerState.cpp
new file mode 100644
index 0000000..0b6374b
--- /dev/null
+++ b/libs/ui/LayerState.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include <utils/Errors.h>
+#include <utils/Parcel.h>
+#include <private/ui/LayerState.h>
+
+namespace android {
+
+status_t layer_state_t::write(Parcel& output) const
+{
+ size_t size = sizeof(layer_state_t);
+
+ //output.writeStrongBinder(surface->asBinder());
+ //size -= sizeof(surface);
+
+ transparentRegion.write(output);
+ size -= sizeof(transparentRegion);
+
+ output.write(this, size);
+
+ return NO_ERROR;
+}
+
+status_t layer_state_t::read(const Parcel& input)
+{
+ size_t size = sizeof(layer_state_t);
+
+ //surface = interface_cast<ISurface>(input.readStrongBinder());
+ //size -= sizeof(surface);
+
+ transparentRegion.read(input);
+ size -= sizeof(transparentRegion);
+
+ input.read(this, size);
+
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/libs/ui/MODULE_LICENSE_APACHE2 b/libs/ui/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/ui/MODULE_LICENSE_APACHE2
diff --git a/libs/ui/NOTICE b/libs/ui/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/ui/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the 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/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
new file mode 100644
index 0000000..605c8ae
--- /dev/null
+++ b/libs/ui/PixelFormat.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <ui/PixelFormat.h>
+#include <pixelflinger/format.h>
+
+namespace android {
+
+ssize_t bytesPerPixel(PixelFormat format)
+{
+ PixelFormatInfo info;
+ status_t err = getPixelFormatInfo(format, &info);
+ return (err < 0) ? err : info.bytesPerPixel;
+}
+
+ssize_t bitsPerPixel(PixelFormat format)
+{
+ PixelFormatInfo info;
+ status_t err = getPixelFormatInfo(format, &info);
+ return (err < 0) ? err : info.bitsPerPixel;
+}
+
+status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info)
+{
+ if (format < 0)
+ return BAD_VALUE;
+
+ if (info->version != sizeof(PixelFormatInfo))
+ return INVALID_OPERATION;
+
+ size_t numEntries;
+ const GGLFormat *i = gglGetPixelFormatTable(&numEntries) + format;
+ bool valid = uint32_t(format) < numEntries;
+ if (!valid) {
+ return BAD_INDEX;
+ }
+
+ info->format = format;
+ info->bytesPerPixel = i->size;
+ info->bitsPerPixel = i->bitsPerPixel;
+ info->h_alpha = i->ah;
+ info->l_alpha = i->al;
+ info->h_red = i->rh;
+ info->l_red = i->rl;
+ info->h_green = i->gh;
+ info->l_green = i->gl;
+ info->h_blue = i->bh;
+ info->l_blue = i->bl;
+ return NO_ERROR;
+}
+
+}; // namespace android
+
diff --git a/libs/ui/Point.cpp b/libs/ui/Point.cpp
new file mode 100644
index 0000000..438d49f
--- /dev/null
+++ b/libs/ui/Point.cpp
@@ -0,0 +1,11 @@
+/*
+ * Point.cpp
+ * Android
+ *
+ * Created on 11/16/2006.
+ * Copyright 2005 The Android Open Source Project
+ *
+ */
+
+#include <ui/Point.h>
+
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
new file mode 100644
index 0000000..99e68bb
--- /dev/null
+++ b/libs/ui/Rect.cpp
@@ -0,0 +1,86 @@
+/*
+ * Rect.cpp
+ * Android
+ *
+ * Created on 10/14/05.
+ * Copyright 2005 The Android Open Source Project
+ *
+ */
+
+#include <ui/Rect.h>
+
+namespace android {
+
+inline int min(int a, int b) {
+ return (a<b) ? a : b;
+}
+
+inline int max(int a, int b) {
+ return (a>b) ? a : b;
+}
+
+void Rect::makeInvalid() {
+ left = 0;
+ top = 0;
+ right = -1;
+ bottom = -1;
+}
+
+bool Rect::operator < (const Rect& rhs) const
+{
+ if (top<rhs.top) {
+ return true;
+ } else if (top == rhs.top) {
+ if (left < rhs.left) {
+ return true;
+ } else if (left == rhs.left) {
+ if (bottom<rhs.bottom) {
+ return true;
+ } else if (bottom == rhs.bottom) {
+ if (right<rhs.right) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+Rect& Rect::offsetTo(int x, int y)
+{
+ right -= left - x;
+ bottom -= top - y;
+ left = x;
+ top = y;
+ return *this;
+}
+
+Rect& Rect::offsetBy(int x, int y)
+{
+ left += x;
+ top += y;
+ right+= x;
+ bottom+=y;
+ return *this;
+}
+
+Rect Rect::operator + (const Point& rhs) const
+{
+ return Rect(left+rhs.x, top+rhs.y, right+rhs.x, bottom+rhs.y);
+}
+
+Rect Rect::operator - (const Point& rhs) const
+{
+ return Rect(left-rhs.x, top-rhs.y, right-rhs.x, bottom-rhs.y);
+}
+
+bool Rect::intersect(const Rect& with, Rect* result) const
+{
+ result->left = max(left, with.left);
+ result->top = max(top, with.top);
+ result->right = min(right, with.right);
+ result->bottom = min(bottom, with.bottom);
+ return !(result->isEmpty());
+}
+
+}; // namespace android
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
new file mode 100644
index 0000000..3e07f2b
--- /dev/null
+++ b/libs/ui/Region.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "Region"
+
+#include <stdio.h>
+#include <utils/Atomic.h>
+#include <utils/Debug.h>
+#include <utils/String8.h>
+#include <ui/Region.h>
+#include <corecg/SkRegion.h>
+#include <corecg/SkRect.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+Region::Region()
+{
+}
+
+Region::Region(const Region& rhs)
+ : mRegion(rhs.mRegion)
+{
+}
+
+Region::Region(const SkRegion& rhs)
+ : mRegion(rhs)
+{
+}
+
+Region::~Region()
+{
+}
+
+Region::Region(const Rect& rhs)
+{
+ set(rhs);
+}
+
+Region::Region(const Parcel& parcel)
+{
+ read(parcel);
+}
+
+Region::Region(const void* buffer)
+{
+ read(buffer);
+}
+
+Region& Region::operator = (const Region& rhs)
+{
+ mRegion = rhs.mRegion;
+ return *this;
+}
+
+const SkRegion& Region::toSkRegion() const
+{
+ return mRegion;
+}
+
+Rect Region::bounds() const
+{
+ const SkIRect& b(mRegion.getBounds());
+ return Rect(b.fLeft, b.fTop, b.fRight, b.fBottom);
+}
+
+void Region::clear()
+{
+ mRegion.setEmpty();
+}
+
+void Region::set(const Rect& r)
+{
+ SkIRect ir;
+ ir.set(r.left, r.top, r.right, r.bottom);
+ mRegion.setRect(ir);
+}
+
+// ----------------------------------------------------------------------------
+
+Region& Region::orSelf(const Rect& r)
+{
+ SkIRect ir;
+ ir.set(r.left, r.top, r.right, r.bottom);
+ mRegion.op(ir, SkRegion::kUnion_Op);
+ return *this;
+}
+
+Region& Region::andSelf(const Rect& r)
+{
+ SkIRect ir;
+ ir.set(r.left, r.top, r.right, r.bottom);
+ mRegion.op(ir, SkRegion::kIntersect_Op);
+ return *this;
+}
+
+// ----------------------------------------------------------------------------
+
+Region& Region::orSelf(const Region& rhs) {
+ mRegion.op(rhs.mRegion, SkRegion::kUnion_Op);
+ return *this;
+}
+
+Region& Region::andSelf(const Region& rhs) {
+ mRegion.op(rhs.mRegion, SkRegion::kIntersect_Op);
+ return *this;
+}
+
+Region& Region::subtractSelf(const Region& rhs) {
+ mRegion.op(rhs.mRegion, SkRegion::kDifference_Op);
+ return *this;
+}
+
+Region& Region::translateSelf(int x, int y) {
+ if (x|y) mRegion.translate(x, y);
+ return *this;
+}
+
+Region Region::merge(const Region& rhs) const {
+ Region result;
+ result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kUnion_Op);
+ return result;
+}
+
+Region Region::intersect(const Region& rhs) const {
+ Region result;
+ result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kIntersect_Op);
+ return result;
+}
+
+Region Region::subtract(const Region& rhs) const {
+ Region result;
+ result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kDifference_Op);
+ return result;
+}
+
+Region Region::translate(int x, int y) const {
+ Region result;
+ mRegion.translate(x, y, &result.mRegion);
+ return result;
+}
+
+// ----------------------------------------------------------------------------
+
+Region& Region::orSelf(const Region& rhs, int dx, int dy) {
+ SkRegion r(rhs.mRegion);
+ r.translate(dx, dy);
+ mRegion.op(r, SkRegion::kUnion_Op);
+ return *this;
+}
+
+Region& Region::andSelf(const Region& rhs, int dx, int dy) {
+ SkRegion r(rhs.mRegion);
+ r.translate(dx, dy);
+ mRegion.op(r, SkRegion::kIntersect_Op);
+ return *this;
+}
+
+Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
+ SkRegion r(rhs.mRegion);
+ r.translate(dx, dy);
+ mRegion.op(r, SkRegion::kDifference_Op);
+ return *this;
+}
+
+Region Region::merge(const Region& rhs, int dx, int dy) const {
+ Region result;
+ SkRegion r(rhs.mRegion);
+ r.translate(dx, dy);
+ result.mRegion.op(mRegion, r, SkRegion::kUnion_Op);
+ return result;
+}
+
+Region Region::intersect(const Region& rhs, int dx, int dy) const {
+ Region result;
+ SkRegion r(rhs.mRegion);
+ r.translate(dx, dy);
+ result.mRegion.op(mRegion, r, SkRegion::kIntersect_Op);
+ return result;
+}
+
+Region Region::subtract(const Region& rhs, int dx, int dy) const {
+ Region result;
+ SkRegion r(rhs.mRegion);
+ r.translate(dx, dy);
+ result.mRegion.op(mRegion, r, SkRegion::kDifference_Op);
+ return result;
+}
+
+// ----------------------------------------------------------------------------
+
+Region::iterator::iterator(const Region& r)
+ : mIt(r.mRegion)
+{
+}
+
+int Region::iterator::iterate(Rect* rect)
+{
+ if (mIt.done())
+ return 0;
+ const SkIRect& r(mIt.rect());
+ rect->left = r.fLeft;
+ rect->top = r.fTop;
+ rect->right = r.fRight;
+ rect->bottom= r.fBottom;
+ mIt.next();
+ return 1;
+}
+
+// ----------------------------------------------------------------------------
+
+// we write a 4byte size ahead of the actual region, so we know how much we'll need for reading
+
+status_t Region::write(Parcel& parcel) const
+{
+ int32_t size = mRegion.flatten(NULL);
+ parcel.writeInt32(size);
+ mRegion.flatten(parcel.writeInplace(size));
+ return NO_ERROR;
+}
+
+status_t Region::read(const Parcel& parcel)
+{
+ size_t size = parcel.readInt32();
+ mRegion.unflatten(parcel.readInplace(size));
+ return NO_ERROR;
+}
+
+ssize_t Region::write(void* buffer, size_t size) const
+{
+ size_t sizeNeeded = mRegion.flatten(NULL);
+ if (sizeNeeded > size) return NO_MEMORY;
+ return mRegion.flatten(buffer);
+}
+
+ssize_t Region::read(const void* buffer)
+{
+ return mRegion.unflatten(buffer);
+}
+
+ssize_t Region::writeEmpty(void* buffer, size_t size)
+{
+ if (size < 4) return NO_MEMORY;
+ // this needs to stay in sync with SkRegion
+ *static_cast<int32_t*>(buffer) = -1;
+ return 4;
+}
+
+bool Region::isEmpty(void* buffer)
+{
+ // this needs to stay in sync with SkRegion
+ return *static_cast<int32_t*>(buffer) == -1;
+}
+
+size_t Region::rects(Vector<Rect>& rectList) const
+{
+ rectList.clear();
+ if (!isEmpty()) {
+ SkRegion::Iterator iterator(mRegion);
+ while( !iterator.done() ) {
+ const SkIRect& ir(iterator.rect());
+ rectList.push(Rect(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom));
+ iterator.next();
+ }
+ }
+ return rectList.size();
+}
+
+void Region::dump(String8& out, const char* what, uint32_t flags) const
+{
+ (void)flags;
+ Vector<Rect> r;
+ rects(r);
+
+ size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n", what, this, r.size());
+ out.append(buffer);
+ for (size_t i=0 ; i<r.size() ; i++) {
+ snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n",
+ r[i].left, r[i].top,r[i].right,r[i].bottom);
+ out.append(buffer);
+ }
+}
+
+void Region::dump(const char* what, uint32_t flags) const
+{
+ (void)flags;
+ Vector<Rect> r;
+ rects(r);
+ LOGD(" Region %s (this=%p, count=%d)\n", what, this, r.size());
+ for (size_t i=0 ; i<r.size() ; i++) {
+ LOGD(" [%3d, %3d, %3d, %3d]\n",
+ r[i].left, r[i].top,r[i].right,r[i].bottom);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
new file mode 100644
index 0000000..0a9aaad
--- /dev/null
+++ b/libs/ui/Surface.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "Surface"
+
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IMemory.h>
+#include <utils/Log.h>
+
+#include <ui/ISurface.h>
+#include <ui/Surface.h>
+#include <ui/SurfaceComposerClient.h>
+#include <ui/Rect.h>
+
+#include <private/ui/SharedState.h>
+#include <private/ui/LayerState.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+Surface::Surface(const sp<SurfaceComposerClient>& client,
+ const sp<ISurface>& surface,
+ const ISurfaceFlingerClient::surface_data_t& data,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
+ bool owner)
+ : mClient(client), mSurface(surface), mMemoryType(data.type),
+ mToken(data.token), mIdentity(data.identity),
+ mFormat(format), mFlags(flags), mOwner(owner)
+{
+ mSwapRectangle.makeInvalid();
+ mSurfaceHeapBase[0] = 0;
+ mSurfaceHeapBase[1] = 0;
+ mHeap[0] = data.heap[0];
+ mHeap[1] = data.heap[1];
+}
+
+Surface::Surface(Surface const* rhs)
+ : mOwner(false)
+{
+ mToken = rhs->mToken;
+ mIdentity= rhs->mIdentity;
+ mClient = rhs->mClient;
+ mSurface = rhs->mSurface;
+ mHeap[0] = rhs->mHeap[0];
+ mHeap[1] = rhs->mHeap[1];
+ mMemoryType = rhs->mMemoryType;
+ mFormat = rhs->mFormat;
+ mFlags = rhs->mFlags;
+ mSurfaceHeapBase[0] = rhs->mSurfaceHeapBase[0];
+ mSurfaceHeapBase[1] = rhs->mSurfaceHeapBase[1];
+ mSwapRectangle.makeInvalid();
+}
+
+Surface::~Surface()
+{
+ if (mOwner && mToken>=0 && mClient!=0) {
+ mClient->destroySurface(mToken);
+ }
+ mClient.clear();
+ mSurface.clear();
+ mHeap[0].clear();
+ mHeap[1].clear();
+ IPCThreadState::self()->flushCommands();
+}
+
+sp<Surface> Surface::dup() const
+{
+ Surface const * r = this;
+ if (this && mOwner) {
+ // the only reason we need to do this is because of Java's garbage
+ // collector: because we're creating a copy of the Surface
+ // instead of a reference, we can garantee that when our last
+ // reference goes away, the real surface will be deleted.
+ // Without this hack (the code is correct too), we'd have to
+ // wait for a GC for the surface to go away.
+ r = new Surface(this);
+ }
+ return const_cast<Surface*>(r);
+}
+
+status_t Surface::nextBuffer(SurfaceInfo* info) {
+ return mClient->nextBuffer(this, info);
+}
+
+status_t Surface::lock(SurfaceInfo* info, bool blocking) {
+ return Surface::lock(info, NULL, blocking);
+}
+
+status_t Surface::lock(SurfaceInfo* info, Region* dirty, bool blocking) {
+ if (heapBase(0) == 0) return INVALID_OPERATION;
+ if (heapBase(1) == 0) return INVALID_OPERATION;
+ return mClient->lockSurface(this, info, dirty, blocking);
+}
+
+status_t Surface::unlockAndPost() {
+ if (heapBase(0) == 0) return INVALID_OPERATION;
+ if (heapBase(1) == 0) return INVALID_OPERATION;
+ return mClient->unlockAndPostSurface(this);
+}
+
+status_t Surface::unlock() {
+ if (heapBase(0) == 0) return INVALID_OPERATION;
+ if (heapBase(1) == 0) return INVALID_OPERATION;
+ return mClient->unlockSurface(this);
+}
+
+status_t Surface::setLayer(int32_t layer) {
+ return mClient->setLayer(this, layer);
+}
+status_t Surface::setPosition(int32_t x, int32_t y) {
+ return mClient->setPosition(this, x, y);
+}
+status_t Surface::setSize(uint32_t w, uint32_t h) {
+ return mClient->setSize(this, w, h);
+}
+status_t Surface::hide() {
+ return mClient->hide(this);
+}
+status_t Surface::show(int32_t layer) {
+ return mClient->show(this, layer);
+}
+status_t Surface::freeze() {
+ return mClient->freeze(this);
+}
+status_t Surface::unfreeze() {
+ return mClient->unfreeze(this);
+}
+status_t Surface::setFlags(uint32_t flags, uint32_t mask) {
+ return mClient->setFlags(this, flags, mask);
+}
+status_t Surface::setTransparentRegionHint(const Region& transparent) {
+ return mClient->setTransparentRegionHint(this, transparent);
+}
+status_t Surface::setAlpha(float alpha) {
+ return mClient->setAlpha(this, alpha);
+}
+status_t Surface::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ return mClient->setMatrix(this, dsdx, dtdx, dsdy, dtdy);
+}
+status_t Surface::setFreezeTint(uint32_t tint) {
+ return mClient->setFreezeTint(this, tint);
+}
+
+Region Surface::dirtyRegion() const {
+ return mDirtyRegion;
+}
+void Surface::setDirtyRegion(const Region& region) const {
+ mDirtyRegion = region;
+}
+const Rect& Surface::swapRectangle() const {
+ return mSwapRectangle;
+}
+void Surface::setSwapRectangle(const Rect& r) {
+ mSwapRectangle = r;
+}
+
+sp<Surface> Surface::readFromParcel(Parcel* parcel)
+{
+ sp<SurfaceComposerClient> client;
+ ISurfaceFlingerClient::surface_data_t data;
+ sp<IBinder> clientBinder= parcel->readStrongBinder();
+ sp<ISurface> surface = interface_cast<ISurface>(parcel->readStrongBinder());
+ data.heap[0] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
+ data.heap[1] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
+ data.type = parcel->readInt32();
+ data.token = parcel->readInt32();
+ data.identity = parcel->readInt32();
+ PixelFormat format = parcel->readInt32();
+ uint32_t flags = parcel->readInt32();
+
+ if (clientBinder != NULL)
+ client = SurfaceComposerClient::clientForConnection(clientBinder);
+
+ return new Surface(client, surface, data, 0, 0, format, flags, false);
+}
+
+status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
+{
+ uint32_t flags=0;
+ uint32_t format=0;
+ SurfaceID token = -1;
+ uint32_t identity = 0;
+ sp<SurfaceComposerClient> client;
+ sp<ISurface> sur;
+ sp<IMemoryHeap> heap[2];
+ int type = 0;
+ if (surface->isValid()) {
+ token = surface->mToken;
+ identity = surface->mIdentity;
+ client = surface->mClient;
+ sur = surface->mSurface;
+ heap[0] = surface->mHeap[0];
+ heap[1] = surface->mHeap[1];
+ type = surface->mMemoryType;
+ format = surface->mFormat;
+ flags = surface->mFlags;
+ }
+ parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);
+ parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+ parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
+ parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
+ parcel->writeInt32(type);
+ parcel->writeInt32(token);
+ parcel->writeInt32(identity);
+ parcel->writeInt32(format);
+ parcel->writeInt32(flags);
+ return NO_ERROR;
+}
+
+bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs)
+{
+ if (lhs == 0 || rhs == 0)
+ return false;
+ return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
+}
+
+void* Surface::heapBase(int i) const
+{
+ void* heapBase = mSurfaceHeapBase[i];
+ // map lazily so it doesn't get mapped in clients that don't need it
+ if (heapBase == 0) {
+ const sp<IMemoryHeap>& heap(mHeap[i]);
+ if (heap != 0) {
+ heapBase = static_cast<uint8_t*>(heap->base());
+ if (heapBase == MAP_FAILED) {
+ heapBase = NULL;
+ LOGE("Couldn't map Surface's heap (binder=%p, heap=%p)",
+ heap->asBinder().get(), heap.get());
+ }
+ mSurfaceHeapBase[i] = heapBase;
+ }
+ }
+ return heapBase;
+}
+
+}; // namespace android
+
diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp
new file mode 100644
index 0000000..9354a7a
--- /dev/null
+++ b/libs/ui/SurfaceComposerClient.cpp
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceComposerClient"
+
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <cutils/memory.h>
+
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+#include <utils/IMemory.h>
+#include <utils/Log.h>
+
+#include <ui/ISurfaceComposer.h>
+#include <ui/ISurfaceFlingerClient.h>
+#include <ui/ISurface.h>
+#include <ui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+#include <ui/Rect.h>
+#include <ui/Point.h>
+
+#include <private/ui/SharedState.h>
+#include <private/ui/LayerState.h>
+#include <private/ui/SurfaceFlingerSynchro.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include <utils/BpBinder.h>
+
+#define VERBOSE(...) ((void)0)
+//#define VERBOSE LOGD
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+// Must not be holding SurfaceComposerClient::mLock when acquiring gLock here.
+static Mutex gLock;
+static sp<ISurfaceComposer> gSurfaceManager;
+static DefaultKeyedVector< sp<IBinder>, sp<SurfaceComposerClient> > gActiveConnections;
+static SortedVector<sp<SurfaceComposerClient> > gOpenTransactions;
+static sp<IMemory> gServerCblkMemory;
+static volatile surface_flinger_cblk_t* gServerCblk;
+
+const sp<ISurfaceComposer>& _get_surface_manager()
+{
+ if (gSurfaceManager != 0) {
+ return gSurfaceManager;
+ }
+
+ sp<IBinder> binder;
+ sp<IServiceManager> sm = defaultServiceManager();
+ do {
+ binder = sm->getService(String16("SurfaceFlinger"));
+ if (binder == 0) {
+ LOGW("SurfaceFlinger not published, waiting...");
+ usleep(500000); // 0.5 s
+ }
+ } while(binder == 0);
+ sp<ISurfaceComposer> sc(interface_cast<ISurfaceComposer>(binder));
+
+ Mutex::Autolock _l(gLock);
+ if (gSurfaceManager == 0) {
+ gSurfaceManager = sc;
+ }
+ return gSurfaceManager;
+}
+
+static volatile surface_flinger_cblk_t const * get_cblk()
+{
+ if (gServerCblk == 0) {
+ const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ Mutex::Autolock _l(gLock);
+ if (gServerCblk == 0) {
+ gServerCblkMemory = sm->getCblk();
+ LOGE_IF(gServerCblkMemory==0, "Can't get server control block");
+ gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->pointer();
+ LOGE_IF(gServerCblk==0, "Can't get server control block address");
+ }
+ }
+ return gServerCblk;
+}
+
+// ---------------------------------------------------------------------------
+
+static void copyBlt(const GGLSurface& dst,
+ const GGLSurface& src, const Region& reg)
+{
+ Region::iterator iterator(reg);
+ if (iterator) {
+ // NOTE: dst and src must be the same format
+ Rect r;
+ const size_t bpp = bytesPerPixel(src.format);
+ const size_t dbpr = dst.stride * bpp;
+ const size_t sbpr = src.stride * bpp;
+ while (iterator.iterate(&r)) {
+ ssize_t h = r.bottom - r.top;
+ if (h) {
+ size_t size = (r.right - r.left) * bpp;
+ uint8_t* s = src.data + (r.left + src.stride * r.top) * bpp;
+ uint8_t* d = dst.data + (r.left + dst.stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+surface_flinger_cblk_t::surface_flinger_cblk_t()
+{
+}
+
+// ---------------------------------------------------------------------------
+
+per_client_cblk_t::per_client_cblk_t()
+{
+}
+
+// these functions are used by the clients
+inline status_t per_client_cblk_t::validate(size_t i) const {
+ if (uint32_t(i) >= NUM_LAYERS_MAX)
+ return BAD_INDEX;
+ if (layers[i].swapState & eInvalidSurface)
+ return NO_MEMORY;
+ return NO_ERROR;
+}
+
+int32_t per_client_cblk_t::lock_layer(size_t i, uint32_t flags)
+{
+ int32_t index;
+ uint32_t state;
+ int timeout = 0;
+ status_t result;
+ layer_cblk_t * const layer = layers + i;
+ const bool blocking = flags & BLOCKING;
+ const bool inspect = flags & INSPECT;
+
+ do {
+ state = layer->swapState;
+
+ if (UNLIKELY((state&(eFlipRequested|eNextFlipPending)) == eNextFlipPending)) {
+ LOGE("eNextFlipPending set but eFlipRequested not set, "
+ "layer=%d (lcblk=%p), state=%08x",
+ int(i), layer, int(state));
+ return INVALID_OPERATION;
+ }
+
+ if (UNLIKELY(state&eLocked)) {
+ LOGE("eLocked set when entering lock_layer(), "
+ "layer=%d (lcblk=%p), state=%08x",
+ int(i), layer, int(state));
+ return WOULD_BLOCK;
+ }
+
+
+ if (state & (eFlipRequested | eNextFlipPending | eResizeRequested
+ | eInvalidSurface))
+ {
+ int32_t resizeIndex;
+ Mutex::Autolock _l(lock);
+ // might block for a very short amount of time
+ // will never cause the server to block (trylock())
+
+ goto start_loop_here;
+
+ // We block the client if:
+ // eNextFlipPending: we've used both buffers already, so we need to
+ // wait for one to become availlable.
+ // eResizeRequested: the buffer we're going to acquire is being
+ // resized. Block until it is done.
+ // eFlipRequested && eBusy: the buffer we're going to acquire is
+ // currently in use by the server.
+ // eInvalidSurface: this is a special case, we don't block in this
+ // case, we just return an error.
+
+ while((state & (eNextFlipPending|eInvalidSurface)) ||
+ (state & ((resizeIndex) ? eResizeBuffer1 : eResizeBuffer0)) ||
+ ((state & (eFlipRequested|eBusy)) == (eFlipRequested|eBusy)) )
+ {
+ if (state & eInvalidSurface)
+ return NO_MEMORY;
+
+ if (!blocking)
+ return WOULD_BLOCK;
+
+ timeout = 0;
+ result = cv.waitRelative(lock, seconds(1));
+ if (__builtin_expect(result!=NO_ERROR, false)) {
+ const int newState = layer->swapState;
+ LOGW( "lock_layer timed out (is the CPU pegged?) "
+ "layer=%d, lcblk=%p, state=%08x (was %08x)",
+ int(i), layer, newState, int(state));
+ timeout = newState != int(state);
+ }
+
+ start_loop_here:
+ state = layer->swapState;
+ resizeIndex = (state&eIndex) ^ ((state&eFlipRequested)>>1);
+ }
+
+ LOGW_IF(timeout,
+ "lock_layer() timed out but didn't appear to need "
+ "to be locked and we recovered "
+ "(layer=%d, lcblk=%p, state=%08x)",
+ int(i), layer, int(state));
+ }
+
+ // eFlipRequested is not set and cannot be set by another thread: it's
+ // safe to use the first buffer without synchronization.
+
+ // Choose the index depending on eFlipRequested.
+ // When it's set, choose the 'other' buffer.
+ index = (state&eIndex) ^ ((state&eFlipRequested)>>1);
+
+ // make sure this buffer is valid
+ if (layer->surface[index].bits_offset < 0) {
+ return status_t(layer->surface[index].bits_offset);
+ }
+
+ if (inspect) {
+ // we just want to inspect this layer. don't lock it.
+ goto done;
+ }
+
+ // last thing before we're done, we need to atomically lock the state
+ } while (android_atomic_cmpxchg(state, state|eLocked, &(layer->swapState)));
+
+ VERBOSE("locked layer=%d (lcblk=%p), buffer=%d, state=0x%08x",
+ int(i), layer, int(index), int(state));
+
+ // store the index of the locked buffer (for client use only)
+ layer->flags &= ~eBufferIndex;
+ layer->flags |= ((index << eBufferIndexShift) & eBufferIndex);
+
+done:
+ return index;
+}
+
+uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
+{
+ // atomically set eFlipRequested and clear eLocked and optionnaly
+ // set eNextFlipPending if eFlipRequested was already set
+
+ layer_cblk_t * const layer = layers + i;
+ int32_t oldvalue, newvalue;
+ do {
+ oldvalue = layer->swapState;
+ // get current value
+
+ newvalue = oldvalue & ~eLocked;
+ // clear eLocked
+
+ newvalue |= eFlipRequested;
+ // set eFlipRequested
+
+ if (oldvalue & eFlipRequested)
+ newvalue |= eNextFlipPending;
+ // if eFlipRequested was alread set, set eNextFlipPending
+
+ } while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState)));
+
+ VERBOSE("request pageflip for layer=%d, buffer=%d, state=0x%08x",
+ int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift),
+ int(newvalue));
+
+ // from this point, the server can kick in at anytime and use the first
+ // buffer, so we cannot use it anymore, and we must use the 'other'
+ // buffer instead (or wait if it is not availlable yet, see lock_layer).
+
+ return newvalue;
+}
+
+void per_client_cblk_t::unlock_layer(size_t i)
+{
+ layer_cblk_t * const layer = layers + i;
+ android_atomic_and(~eLocked, &layer->swapState);
+}
+
+// ---------------------------------------------------------------------------
+
+static inline int compare_type( const layer_state_t& lhs,
+ const layer_state_t& rhs) {
+ if (lhs.surface < rhs.surface) return -1;
+ if (lhs.surface > rhs.surface) return 1;
+ return 0;
+}
+
+SurfaceComposerClient::SurfaceComposerClient()
+{
+ const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ if (sm == 0) {
+ _init(0, 0);
+ return;
+ }
+
+ _init(sm, sm->createConnection());
+
+ if (mClient != 0) {
+ Mutex::Autolock _l(gLock);
+ VERBOSE("Adding client %p to map", this);
+ gActiveConnections.add(mClient->asBinder(), this);
+ }
+}
+
+SurfaceComposerClient::SurfaceComposerClient(
+ const sp<ISurfaceComposer>& sm, const sp<IBinder>& conn)
+{
+ _init(sm, interface_cast<ISurfaceFlingerClient>(conn));
+}
+
+void SurfaceComposerClient::_init(
+ const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn)
+{
+ VERBOSE("Creating client %p, conn %p", this, conn.get());
+
+ mSignalServer = 0;
+ mPrebuiltLayerState = 0;
+ mTransactionOpen = 0;
+ mStatus = NO_ERROR;
+ mControl = 0;
+
+ mClient = conn;
+ if (mClient == 0) {
+ mStatus = NO_INIT;
+ return;
+ }
+
+ mClient->getControlBlocks(&mControlMemory);
+ mSignalServer = new SurfaceFlingerSynchro(sm);
+ mControl = static_cast<per_client_cblk_t *>(mControlMemory->pointer());
+}
+
+SurfaceComposerClient::~SurfaceComposerClient()
+{
+ VERBOSE("Destroying client %p, conn %p", this, mClient.get());
+ dispose();
+}
+
+status_t SurfaceComposerClient::initCheck() const
+{
+ return mStatus;
+}
+
+status_t SurfaceComposerClient::validateSurface(
+ per_client_cblk_t const* cblk, Surface const * surface)
+{
+ SurfaceID index = surface->ID();
+ if (cblk == 0) {
+ LOGE("cblk is null (surface id=%d, identity=%u)",
+ index, surface->getIdentity());
+ return NO_INIT;
+ }
+
+ status_t err = cblk->validate(index);
+ if (err != NO_ERROR) {
+ LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
+ index, surface->getIdentity(), err, strerror(-err));
+ return err;
+ }
+
+ if (surface->getIdentity() != uint32_t(cblk->layers[index].identity)) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ index, surface->getIdentity(), cblk->layers[index].identity);
+ return NO_INIT;
+ }
+
+ return NO_ERROR;
+}
+
+sp<IBinder> SurfaceComposerClient::connection() const
+{
+ return (mClient != 0) ? mClient->asBinder() : 0;
+}
+
+sp<SurfaceComposerClient>
+SurfaceComposerClient::clientForConnection(const sp<IBinder>& conn)
+{
+ sp<SurfaceComposerClient> client;
+
+ { // scope for lock
+ Mutex::Autolock _l(gLock);
+ client = gActiveConnections.valueFor(conn);
+ }
+
+ if (client == 0) {
+ // Need to make a new client.
+ const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ client = new SurfaceComposerClient(sm, conn);
+ if (client != 0 && client->initCheck() == NO_ERROR) {
+ Mutex::Autolock _l(gLock);
+ gActiveConnections.add(conn, client);
+ //LOGD("we have %d connections", gActiveConnections.size());
+ } else {
+ client.clear();
+ }
+ }
+
+ return client;
+}
+
+void SurfaceComposerClient::dispose()
+{
+ // this can be called more than once.
+
+ sp<IMemory> controlMemory;
+ sp<ISurfaceFlingerClient> client;
+ sp<IMemoryHeap> surfaceHeap;
+
+ {
+ Mutex::Autolock _lg(gLock);
+ Mutex::Autolock _lm(mLock);
+
+ delete mSignalServer;
+ mSignalServer = 0;
+
+ if (mClient != 0) {
+ client = mClient;
+ mClient.clear();
+
+ ssize_t i = gActiveConnections.indexOfKey(client->asBinder());
+ if (i >= 0 && gActiveConnections.valueAt(i) == this) {
+ VERBOSE("Removing client %p from map at %d", this, int(i));
+ gActiveConnections.removeItemsAt(i);
+ }
+ }
+
+ delete mPrebuiltLayerState;
+ mPrebuiltLayerState = 0;
+ controlMemory = mControlMemory;
+ surfaceHeap = mSurfaceHeap;
+ mControlMemory.clear();
+ mSurfaceHeap.clear();
+ mControl = 0;
+ mStatus = NO_INIT;
+ }
+}
+
+status_t SurfaceComposerClient::getDisplayInfo(
+ DisplayID dpy, DisplayInfo* info)
+{
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+
+ info->w = dcblk->w;
+ info->h = dcblk->h;
+ info->orientation = dcblk->orientation;
+ info->xdpi = dcblk->xdpi;
+ info->ydpi = dcblk->ydpi;
+ info->fps = dcblk->fps;
+ info->density = dcblk->density;
+ return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo));
+}
+
+ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
+{
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+ return dcblk->w;
+}
+
+ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
+{
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+ return dcblk->h;
+}
+
+ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
+{
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+ return dcblk->orientation;
+}
+
+ssize_t SurfaceComposerClient::getNumberOfDisplays()
+{
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ uint32_t connected = cblk->connected;
+ int n = 0;
+ while (connected) {
+ if (connected&1) n++;
+ connected >>= 1;
+ }
+ return n;
+}
+
+sp<Surface> SurfaceComposerClient::createSurface(
+ int pid,
+ DisplayID display,
+ uint32_t w,
+ uint32_t h,
+ PixelFormat format,
+ uint32_t flags)
+{
+ sp<Surface> result;
+ if (mStatus == NO_ERROR) {
+ ISurfaceFlingerClient::surface_data_t data;
+ sp<ISurface> surface = mClient->createSurface(&data, pid,
+ display, w, h, format, flags);
+ if (surface != 0) {
+ if (uint32_t(data.token) < NUM_LAYERS_MAX) {
+ result = new Surface(this, surface, data, w, h, format, flags);
+ }
+ }
+ }
+ return result;
+}
+
+status_t SurfaceComposerClient::destroySurface(SurfaceID sid)
+{
+ if (mStatus != NO_ERROR)
+ return mStatus;
+
+ // it's okay to destroy a surface while a transaction is open,
+ // (transactions really are a client-side concept)
+ // however, this indicates probably a misuse of the API or a bug
+ // in the client code.
+ LOGW_IF(mTransactionOpen,
+ "Destroying surface while a transaction is open. "
+ "Client %p: destroying surface %d, mTransactionOpen=%d",
+ this, sid, mTransactionOpen);
+
+ status_t err = mClient->destroySurface(sid);
+ return err;
+}
+
+status_t SurfaceComposerClient::nextBuffer(Surface* surface,
+ Surface::SurfaceInfo* info)
+{
+ SurfaceID index = surface->ID();
+ per_client_cblk_t* const cblk = mControl;
+ status_t err = validateSurface(cblk, surface);
+ if (err != NO_ERROR)
+ return err;
+
+ int32_t backIdx = surface->mBackbufferIndex;
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+ const surface_info_t* const front = lcblk->surface + (1-backIdx);
+ info->w = front->w;
+ info->h = front->h;
+ info->format = front->format;
+ info->base = surface->heapBase(1-backIdx);
+ info->bits = reinterpret_cast<void*>(intptr_t(info->base) + front->bits_offset);
+ info->bpr = front->bpr;
+
+ return 0;
+}
+
+status_t SurfaceComposerClient::lockSurface(
+ Surface* surface,
+ Surface::SurfaceInfo* other,
+ Region* dirty,
+ bool blocking)
+{
+ Mutex::Autolock _l(surface->getLock());
+
+ SurfaceID index = surface->ID();
+ per_client_cblk_t* const cblk = mControl;
+ status_t err = validateSurface(cblk, surface);
+ if (err != NO_ERROR)
+ return err;
+
+ int32_t backIdx = cblk->lock_layer(size_t(index),
+ per_client_cblk_t::BLOCKING);
+ if (backIdx >= 0) {
+ surface->mBackbufferIndex = backIdx;
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+ const surface_info_t* const back = lcblk->surface + backIdx;
+ const surface_info_t* const front = lcblk->surface + (1-backIdx);
+ other->w = back->w;
+ other->h = back->h;
+ other->format = back->format;
+ other->base = surface->heapBase(backIdx);
+ other->bits = reinterpret_cast<void*>(intptr_t(other->base) + back->bits_offset);
+ other->bpr = back->bpr;
+
+ const Rect bounds(other->w, other->h);
+ Region newDirtyRegion;
+
+ if (back->flags & surface_info_t::eBufferDirty) {
+ /* it is safe to write *back here, because we're guaranteed
+ * SurfaceFlinger is not touching it (since it just granted
+ * access to us) */
+ const_cast<surface_info_t*>(back)->flags &=
+ ~surface_info_t::eBufferDirty;
+
+ // content is meaningless in this case and the whole surface
+ // needs to be redrawn.
+
+ newDirtyRegion.set(bounds);
+ if (dirty) {
+ *dirty = newDirtyRegion;
+ }
+
+ //if (bytesPerPixel(other->format) == 4) {
+ // android_memset32(
+ // (uint32_t*)other->bits, 0xFF00FF00, other->h * other->bpr);
+ //} else {
+ // android_memset16( // fill with green
+ // (uint16_t*)other->bits, 0x7E0, other->h * other->bpr);
+ //}
+ }
+ else
+ {
+ if (dirty) {
+ dirty->andSelf(Region(bounds));
+ newDirtyRegion = *dirty;
+ } else {
+ newDirtyRegion.set(bounds);
+ }
+
+ Region copyback;
+ if (!(lcblk->flags & eNoCopyBack)) {
+ const Region previousDirtyRegion(surface->dirtyRegion());
+ copyback = previousDirtyRegion.subtract(newDirtyRegion);
+ }
+
+ if (!copyback.isEmpty()) {
+ // copy front to back
+ GGLSurface cb;
+ cb.version = sizeof(GGLSurface);
+ cb.width = back->w;
+ cb.height = back->h;
+ cb.stride = back->stride;
+ cb.data = (GGLubyte*)surface->heapBase(backIdx);
+ cb.data += back->bits_offset;
+ cb.format = back->format;
+
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = front->w;
+ t.height = front->h;
+ t.stride = front->stride;
+ t.data = (GGLubyte*)surface->heapBase(1-backIdx);
+ t.data += front->bits_offset;
+ t.format = front->format;
+
+ //const Region copyback(lcblk->region + 1-backIdx);
+ copyBlt(cb, t, copyback);
+ }
+ }
+
+ // update dirty region
+ surface->setDirtyRegion(newDirtyRegion);
+ }
+ return (backIdx < 0) ? status_t(backIdx) : status_t(NO_ERROR);
+}
+
+void SurfaceComposerClient::_signal_server()
+{
+ mSignalServer->signal();
+}
+
+void SurfaceComposerClient::_send_dirty_region(
+ layer_cblk_t* lcblk, const Region& dirty)
+{
+ const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
+ flat_region_t* flat_region = lcblk->region + index;
+ status_t err = dirty.write(flat_region, sizeof(flat_region_t));
+ if (err < NO_ERROR) {
+ // region doesn't fit, use the bounds
+ const Region reg(dirty.bounds());
+ reg.write(flat_region, sizeof(flat_region_t));
+ }
+}
+
+status_t SurfaceComposerClient::unlockAndPostSurface(Surface* surface)
+{
+ Mutex::Autolock _l(surface->getLock());
+
+ SurfaceID index = surface->ID();
+ per_client_cblk_t* const cblk = mControl;
+ status_t err = validateSurface(cblk, surface);
+ if (err != NO_ERROR)
+ return err;
+
+ Region dirty(surface->dirtyRegion());
+ const Rect& swapRect(surface->swapRectangle());
+ if (swapRect.isValid()) {
+ dirty.set(swapRect);
+ }
+
+ // transmit the dirty region
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+ _send_dirty_region(lcblk, dirty);
+ uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
+ if (!(newstate & eNextFlipPending))
+ _signal_server();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::unlockSurface(Surface* surface)
+{
+ Mutex::Autolock _l(surface->getLock());
+
+ SurfaceID index = surface->ID();
+ per_client_cblk_t* const cblk = mControl;
+ status_t err = validateSurface(cblk, surface);
+ if (err != NO_ERROR)
+ return err;
+
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+ cblk->unlock_layer(size_t(index));
+ return NO_ERROR;
+}
+
+void SurfaceComposerClient::openGlobalTransaction()
+{
+ Mutex::Autolock _l(gLock);
+
+ if (gOpenTransactions.size()) {
+ LOGE("openGlobalTransaction() called more than once. skipping.");
+ return;
+ }
+
+ const size_t N = gActiveConnections.size();
+ VERBOSE("openGlobalTransaction (%ld clients)", N);
+ for (size_t i=0; i<N; i++) {
+ sp<SurfaceComposerClient> client(gActiveConnections.valueAt(i));
+ if (gOpenTransactions.indexOf(client) < 0) {
+ if (client->openTransaction() == NO_ERROR) {
+ if (gOpenTransactions.add(client) < 0) {
+ // Ooops!
+ LOGE( "Unable to add a SurfaceComposerClient "
+ "to the global transaction set (out of memory?)");
+ client->closeTransaction();
+ // let it go, it'll fail later when the user
+ // tries to do something with the transaction
+ }
+ } else {
+ LOGE("openTransaction on client %p failed", client.get());
+ // let it go, it'll fail later when the user
+ // tries to do something with the transaction
+ }
+ }
+ }
+}
+
+void SurfaceComposerClient::closeGlobalTransaction()
+{
+ gLock.lock();
+ SortedVector< sp<SurfaceComposerClient> > clients(gOpenTransactions);
+ gOpenTransactions.clear();
+ gLock.unlock();
+
+ const size_t N = clients.size();
+ VERBOSE("closeGlobalTransaction (%ld clients)", N);
+ if (N == 1) {
+ clients[0]->closeTransaction();
+ } else {
+ const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ sm->openGlobalTransaction();
+ for (size_t i=0; i<N; i++) {
+ clients[i]->closeTransaction();
+ }
+ sm->closeGlobalTransaction();
+ }
+}
+
+status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
+{
+ const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ return sm->freezeDisplay(dpy, flags);
+}
+
+status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags)
+{
+ const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ return sm->unfreezeDisplay(dpy, flags);
+}
+
+int SurfaceComposerClient::setOrientation(DisplayID dpy, int orientation)
+{
+ const sp<ISurfaceComposer>& sm(_get_surface_manager());
+ return sm->setOrientation(dpy, orientation);
+}
+
+status_t SurfaceComposerClient::openTransaction()
+{
+ if (mStatus != NO_ERROR)
+ return mStatus;
+ Mutex::Autolock _l(mLock);
+ VERBOSE( "openTransaction (client %p, mTransactionOpen=%d)",
+ this, mTransactionOpen);
+ mTransactionOpen++;
+ if (mPrebuiltLayerState == 0) {
+ mPrebuiltLayerState = new layer_state_t;
+ }
+ return NO_ERROR;
+}
+
+
+status_t SurfaceComposerClient::closeTransaction()
+{
+ if (mStatus != NO_ERROR)
+ return mStatus;
+
+ Mutex::Autolock _l(mLock);
+
+ VERBOSE( "closeTransaction (client %p, mTransactionOpen=%d)",
+ this, mTransactionOpen);
+
+ if (mTransactionOpen <= 0) {
+ LOGE( "closeTransaction (client %p, mTransactionOpen=%d) "
+ "called more times than openTransaction()",
+ this, mTransactionOpen);
+ return INVALID_OPERATION;
+ }
+
+ if (mTransactionOpen >= 2) {
+ mTransactionOpen--;
+ return NO_ERROR;
+ }
+
+ mTransactionOpen = 0;
+ const ssize_t count = mStates.size();
+ if (count) {
+ mClient->setState(count, mStates.array());
+ mStates.clear();
+ }
+ return NO_ERROR;
+}
+
+layer_state_t* SurfaceComposerClient::_get_state_l(const sp<Surface>& surface)
+{
+ SurfaceID index = surface->ID();
+ per_client_cblk_t* const cblk = mControl;
+ status_t err = validateSurface(cblk, surface.get());
+ if (err != NO_ERROR)
+ return 0;
+
+ // API usage error, do nothing.
+ if (mTransactionOpen<=0) {
+ LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d",
+ this, int(index), mTransactionOpen);
+ return 0;
+ }
+
+ // use mPrebuiltLayerState just to find out if we already have it
+ layer_state_t& dummy = *mPrebuiltLayerState;
+ dummy.surface = index;
+ ssize_t i = mStates.indexOf(dummy);
+ if (i < 0) {
+ // we don't have it, add an initialized layer_state to our list
+ i = mStates.add(dummy);
+ }
+ return mStates.editArray() + i;
+}
+
+layer_state_t* SurfaceComposerClient::_lockLayerState(const sp<Surface>& surface)
+{
+ layer_state_t* s;
+ mLock.lock();
+ s = _get_state_l(surface);
+ if (!s) mLock.unlock();
+ return s;
+}
+
+void SurfaceComposerClient::_unlockLayerState()
+{
+ mLock.unlock();
+}
+
+status_t SurfaceComposerClient::setPosition(Surface* surface, int32_t x, int32_t y)
+{
+ layer_state_t* s = _lockLayerState(surface);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::ePositionChanged;
+ s->x = x;
+ s->y = y;
+ _unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setSize(Surface* surface, uint32_t w, uint32_t h)
+{
+ layer_state_t* s = _lockLayerState(surface);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eSizeChanged;
+ s->w = w;
+ s->h = h;
+ _unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setLayer(Surface* surface, int32_t z)
+{
+ layer_state_t* s = _lockLayerState(surface);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eLayerChanged;
+ s->z = z;
+ _unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::hide(Surface* surface)
+{
+ return setFlags(surface, ISurfaceComposer::eLayerHidden,
+ ISurfaceComposer::eLayerHidden);
+}
+
+status_t SurfaceComposerClient::show(Surface* surface, int32_t)
+{
+ return setFlags(surface, 0, ISurfaceComposer::eLayerHidden);
+}
+
+status_t SurfaceComposerClient::freeze(Surface* surface)
+{
+ return setFlags(surface, ISurfaceComposer::eLayerFrozen,
+ ISurfaceComposer::eLayerFrozen);
+}
+
+status_t SurfaceComposerClient::unfreeze(Surface* surface)
+{
+ return setFlags(surface, 0, ISurfaceComposer::eLayerFrozen);
+}
+
+status_t SurfaceComposerClient::setFlags(Surface* surface,
+ uint32_t flags, uint32_t mask)
+{
+ layer_state_t* s = _lockLayerState(surface);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eVisibilityChanged;
+ s->flags &= ~mask;
+ s->flags |= (flags & mask);
+ s->mask |= mask;
+ _unlockLayerState();
+ return NO_ERROR;
+}
+
+
+status_t SurfaceComposerClient::setTransparentRegionHint(
+ Surface* surface, const Region& transparentRegion)
+{
+ layer_state_t* s = _lockLayerState(surface);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eTransparentRegionChanged;
+ s->transparentRegion = transparentRegion;
+ _unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setAlpha(Surface* surface, float alpha)
+{
+ layer_state_t* s = _lockLayerState(surface);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eAlphaChanged;
+ s->alpha = alpha;
+ _unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setMatrix(
+ Surface* surface,
+ float dsdx, float dtdx,
+ float dsdy, float dtdy )
+{
+ layer_state_t* s = _lockLayerState(surface);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eMatrixChanged;
+ layer_state_t::matrix22_t matrix;
+ matrix.dsdx = dsdx;
+ matrix.dtdx = dtdx;
+ matrix.dsdy = dsdy;
+ matrix.dtdy = dtdy;
+ s->matrix = matrix;
+ _unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setFreezeTint(Surface* surface, uint32_t tint)
+{
+ layer_state_t* s = _lockLayerState(surface);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eFreezeTintChanged;
+ s->tint = tint;
+ _unlockLayerState();
+ return NO_ERROR;
+}
+
+}; // namespace android
+
diff --git a/libs/ui/SurfaceFlingerSynchro.cpp b/libs/ui/SurfaceFlingerSynchro.cpp
new file mode 100644
index 0000000..5cd9755
--- /dev/null
+++ b/libs/ui/SurfaceFlingerSynchro.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlingerSynchro"
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+
+#include <private/ui/SurfaceFlingerSynchro.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+SurfaceFlingerSynchro::Barrier::Barrier()
+ : state(CLOSED) {
+}
+
+SurfaceFlingerSynchro::Barrier::~Barrier() {
+}
+
+void SurfaceFlingerSynchro::Barrier::open() {
+ asm volatile ("":::"memory");
+ Mutex::Autolock _l(lock);
+ state = OPENED;
+ cv.broadcast();
+}
+
+void SurfaceFlingerSynchro::Barrier::close() {
+ Mutex::Autolock _l(lock);
+ state = CLOSED;
+}
+
+void SurfaceFlingerSynchro::Barrier::waitAndClose()
+{
+ Mutex::Autolock _l(lock);
+ while (state == CLOSED) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ cv.wait(lock);
+ }
+ state = CLOSED;
+}
+
+status_t SurfaceFlingerSynchro::Barrier::waitAndClose(nsecs_t timeout)
+{
+ Mutex::Autolock _l(lock);
+ while (state == CLOSED) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ int err = cv.waitRelative(lock, timeout);
+ if (err != 0)
+ return err;
+ }
+ state = CLOSED;
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+SurfaceFlingerSynchro::SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger)
+ : mSurfaceComposer(flinger)
+{
+}
+
+SurfaceFlingerSynchro::SurfaceFlingerSynchro()
+{
+}
+
+SurfaceFlingerSynchro::~SurfaceFlingerSynchro()
+{
+}
+
+status_t SurfaceFlingerSynchro::signal()
+{
+ mSurfaceComposer->signal();
+ return NO_ERROR;
+}
+
+status_t SurfaceFlingerSynchro::wait()
+{
+ mBarrier.waitAndClose();
+ return NO_ERROR;
+}
+
+status_t SurfaceFlingerSynchro::wait(nsecs_t timeout)
+{
+ if (timeout == 0)
+ return SurfaceFlingerSynchro::wait();
+ return mBarrier.waitAndClose(timeout);
+}
+
+void SurfaceFlingerSynchro::open()
+{
+ mBarrier.open();
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libs/ui/Time.cpp b/libs/ui/Time.cpp
new file mode 100644
index 0000000..c98667f
--- /dev/null
+++ b/libs/ui/Time.cpp
@@ -0,0 +1,199 @@
+#include <utils/TimeUtils.h>
+#include <stdio.h>
+#include <cutils/tztime.h>
+
+namespace android {
+
+static void
+dump(const Time& t)
+{
+ #ifdef HAVE_TM_GMTOFF
+ long tm_gmtoff = t.t.tm_gmtoff;
+ #else
+ long tm_gmtoff = 0;
+ #endif
+ printf("%04d-%02d-%02d %02d:%02d:%02d (%d,%ld,%d,%d)\n",
+ t.t.tm_year+1900, t.t.tm_mon+1, t.t.tm_mday,
+ t.t.tm_hour, t.t.tm_min, t.t.tm_sec,
+ t.t.tm_isdst, tm_gmtoff, t.t.tm_wday, t.t.tm_yday);
+}
+
+Time::Time()
+{
+ t.tm_sec = 0;
+ t.tm_min = 0;
+ t.tm_hour = 0;
+ t.tm_mday = 0;
+ t.tm_mon = 0;
+ t.tm_year = 0;
+ t.tm_wday = 0;
+ t.tm_yday = 0;
+ t.tm_isdst = -1; // we don't know, so let the C library determine
+ #ifdef HAVE_TM_GMTOFF
+ t.tm_gmtoff = 0;
+ #endif
+}
+
+
+#define COMPARE_FIELD(field) do { \
+ int diff = a.t.field - b.t.field; \
+ if (diff != 0) return diff; \
+ } while(0)
+
+int
+Time::compare(Time& a, Time& b)
+{
+ if (0 == strcmp(a.timezone, b.timezone)) {
+ // if the timezones are the same, we can easily compare the two
+ // times. Otherwise, convert to milliseconds and compare that.
+ // This requires that object be normalized.
+ COMPARE_FIELD(tm_year);
+ COMPARE_FIELD(tm_mon);
+ COMPARE_FIELD(tm_mday);
+ COMPARE_FIELD(tm_hour);
+ COMPARE_FIELD(tm_min);
+ COMPARE_FIELD(tm_sec);
+ return 0;
+ } else {
+ int64_t am = a.toMillis(false /* use isDst */);
+ int64_t bm = b.toMillis(false /* use isDst */);
+ int64_t diff = am-bm;
+ return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0);
+ }
+}
+
+static const int DAYS_PER_MONTH[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+
+static inline int days_this_month(int year, int month)
+{
+ int n = DAYS_PER_MONTH[month];
+ if (n != 28) {
+ return n;
+ } else {
+ int y = year;
+ return ((y%4)==0&&((y%100)!=0||(y%400)==0)) ? 29 : 28;
+ }
+}
+
+void
+Time::switchTimezone(const char* timezone)
+{
+ time_t seconds = mktime_tz(&(this->t), this->timezone);
+ localtime_tz(&seconds, &(this->t), timezone);
+}
+
+String8
+Time::format(const char *format) const
+{
+ char buf[257];
+ int n = strftime(buf, 257, format, &(this->t));
+ if (n > 0) {
+ return String8(buf);
+ } else {
+ return String8();
+ }
+}
+
+static inline short
+tochar(int n)
+{
+ return (n >= 0 && n <= 9) ? ('0'+n) : ' ';
+}
+
+static inline short
+next_char(int *m, int k)
+{
+ int n = *m / k;
+ *m = *m % k;
+ return tochar(n);
+}
+
+void
+Time::format2445(short* buf, bool hasTime) const
+{
+ int n;
+
+ n = t.tm_year+1900;
+ buf[0] = next_char(&n, 1000);
+ buf[1] = next_char(&n, 100);
+ buf[2] = next_char(&n, 10);
+ buf[3] = tochar(n);
+
+ n = t.tm_mon+1;
+ buf[4] = next_char(&n, 10);
+ buf[5] = tochar(n);
+
+ n = t.tm_mday;
+ buf[6] = next_char(&n, 10);
+ buf[7] = tochar(n);
+
+ if (hasTime) {
+ buf[8] = 'T';
+
+ n = t.tm_hour;
+ buf[9] = next_char(&n, 10);
+ buf[10] = tochar(n);
+
+ n = t.tm_min;
+ buf[11] = next_char(&n, 10);
+ buf[12] = tochar(n);
+
+ n = t.tm_sec;
+ buf[13] = next_char(&n, 10);
+ buf[14] = tochar(n);
+ bool inUtc = strcmp("UTC", timezone) == 0;
+ if (inUtc) {
+ buf[15] = 'Z';
+ }
+ }
+}
+
+String8
+Time::toString() const
+{
+ String8 str;
+ char* s = str.lockBuffer(150);
+ #ifdef HAVE_TM_GMTOFF
+ long tm_gmtoff = t.tm_gmtoff;
+ #else
+ long tm_gmtoff = 0;
+ #endif
+ sprintf(s, "%04d%02d%02dT%02d%02d%02d%s(%d,%d,%ld,%d,%d)",
+ t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min,
+ t.tm_sec, timezone, t.tm_wday, t.tm_yday, tm_gmtoff, t.tm_isdst,
+ (int)(((Time*)this)->toMillis(false /* use isDst */)/1000));
+ str.unlockBuffer();
+ return str;
+}
+
+void
+Time::setToNow()
+{
+ time_t seconds;
+ time(&seconds);
+ localtime_tz(&seconds, &(this->t), this->timezone);
+}
+
+int64_t
+Time::toMillis(bool ignoreDst)
+{
+ if (ignoreDst) {
+ this->t.tm_isdst = -1;
+ }
+ int64_t r = mktime_tz(&(this->t), this->timezone);
+ if (r == -1)
+ return -1;
+ return r * 1000;
+}
+
+void
+Time::set(int64_t millis)
+{
+ time_t seconds = millis / 1000;
+ localtime_tz(&seconds, &(this->t), this->timezone);
+}
+
+}; // namespace android
+
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
new file mode 100644
index 0000000..4a68dc1
--- /dev/null
+++ b/libs/utils/Android.mk
@@ -0,0 +1,148 @@
+# 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)
+
+# libutils is a little unique: It's built twice, once for the host
+# and once for the device.
+
+commonSources:= \
+ Asset.cpp \
+ AssetDir.cpp \
+ AssetManager.cpp \
+ BufferedTextOutput.cpp \
+ CallStack.cpp \
+ Debug.cpp \
+ FileMap.cpp \
+ RefBase.cpp \
+ ResourceTypes.cpp \
+ SharedBuffer.cpp \
+ Static.cpp \
+ StopWatch.cpp \
+ String8.cpp \
+ String16.cpp \
+ SystemClock.cpp \
+ TextOutput.cpp \
+ Threads.cpp \
+ TimerProbe.cpp \
+ Timers.cpp \
+ VectorImpl.cpp \
+ ZipFileCRO.cpp \
+ ZipFileRO.cpp \
+ ZipUtils.cpp \
+ misc.cpp \
+ ported.cpp \
+ LogSocket.cpp
+
+#
+# The cpp files listed here do not belong in the device
+# build. Consult with the swetland before even thinking about
+# putting them in commonSources.
+#
+# They're used by the simulator runtime and by host-side tools like
+# aapt and the simulator front-end.
+#
+hostSources:= \
+ InetAddress.cpp \
+ Pipe.cpp \
+ Socket.cpp \
+ ZipEntry.cpp \
+ ZipFile.cpp
+
+# For the host
+# =====================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= $(commonSources) $(hostSources)
+
+ifeq ($(HOST_OS),linux)
+# Use the futex based mutex and condition variable
+# implementation from android-arm because it's shared mem safe
+ LOCAL_SRC_FILES += \
+ futex_synchro.c \
+ executablepath_linux.cpp
+endif
+ifeq ($(HOST_OS),darwin)
+ LOCAL_SRC_FILES += \
+ executablepath_darwin.cpp
+endif
+
+LOCAL_MODULE:= libutils
+
+LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)
+LOCAL_C_INCLUDES += external/zlib
+
+ifeq ($(HOST_OS),windows)
+ifeq ($(strip $(USE_CYGWIN),),)
+# Under MinGW, ctype.h doesn't need multi-byte support
+LOCAL_CFLAGS += -DMB_CUR_MAX=1
+endif
+endif
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+
+# we have the common sources, plus some device-specific stuff
+LOCAL_SRC_FILES:= \
+ $(commonSources) \
+ Binder.cpp \
+ BpBinder.cpp \
+ IInterface.cpp \
+ IMemory.cpp \
+ IPCThreadState.cpp \
+ MemoryDealer.cpp \
+ MemoryBase.cpp \
+ MemoryHeapBase.cpp \
+ MemoryHeapPmem.cpp \
+ Parcel.cpp \
+ ProcessState.cpp \
+ IPermissionController.cpp \
+ IServiceManager.cpp \
+ Unicode.cpp
+
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_SRC_FILES += $(hostSources)
+endif
+
+ifeq ($(TARGET_OS),linux)
+# Use the futex based mutex and condition variable
+# implementation from android-arm because it's shared mem safe
+LOCAL_SRC_FILES += futex_synchro.c
+LOCAL_LDLIBS += -lrt -ldl
+endif
+
+LOCAL_C_INCLUDES += \
+ external/zlib \
+ external/icu4c/common
+LOCAL_LDLIBS += -lpthread
+
+LOCAL_SHARED_LIBRARIES := \
+ libz \
+ liblog \
+ libcutils
+
+LOCAL_MODULE:= libutils
+
+#LOCAL_CFLAGS+=
+#LOCAL_LDFLAGS:=
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/libs/utils/Asset.cpp b/libs/utils/Asset.cpp
new file mode 100644
index 0000000..91203dd
--- /dev/null
+++ b/libs/utils/Asset.cpp
@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Provide access to a read-only asset.
+//
+
+#define LOG_TAG "asset"
+//#define NDEBUG 0
+
+#include <utils/Asset.h>
+#include <utils/Atomic.h>
+#include <utils/FileMap.h>
+#include <utils/ZipUtils.h>
+#include <utils/ZipFileRO.h>
+#include <utils/Log.h>
+
+#include <string.h>
+#include <memory.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+static volatile int32_t gCount = 0;
+
+int32_t Asset::getGlobalCount()
+{
+ return gCount;
+}
+
+Asset::Asset(void)
+ : mAccessMode(ACCESS_UNKNOWN)
+{
+ int count = android_atomic_inc(&gCount)+1;
+ //LOGI("Creating Asset %p #%d\n", this, count);
+}
+
+Asset::~Asset(void)
+{
+ int count = android_atomic_dec(&gCount);
+ //LOGI("Destroying Asset in %p #%d\n", this, count);
+}
+
+/*
+ * Create a new Asset from a file on disk. There is a fair chance that
+ * the file doesn't actually exist.
+ *
+ * We can use "mode" to decide how we want to go about it.
+ */
+/*static*/ Asset* Asset::createFromFile(const char* fileName, AccessMode mode)
+{
+ _FileAsset* pAsset;
+ status_t result;
+ off_t length;
+ int fd;
+
+ fd = open(fileName, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ return NULL;
+
+ /*
+ * Under Linux, the lseek fails if we actually opened a directory. To
+ * be correct we should test the file type explicitly, but since we
+ * always open things read-only it doesn't really matter, so there's
+ * no value in incurring the extra overhead of an fstat() call.
+ */
+ length = lseek(fd, 0, SEEK_END);
+ if (length < 0) {
+ ::close(fd);
+ return NULL;
+ }
+ (void) lseek(fd, 0, SEEK_SET);
+
+ pAsset = new _FileAsset;
+ result = pAsset->openChunk(fileName, fd, 0, length);
+ if (result != NO_ERROR) {
+ delete pAsset;
+ return NULL;
+ }
+
+ pAsset->mAccessMode = mode;
+ return pAsset;
+}
+
+
+/*
+ * Create a new Asset from a compressed file on disk. There is a fair chance
+ * that the file doesn't actually exist.
+ *
+ * We currently support gzip files. We might want to handle .bz2 someday.
+ */
+/*static*/ Asset* Asset::createFromCompressedFile(const char* fileName,
+ AccessMode mode)
+{
+ _CompressedAsset* pAsset;
+ status_t result;
+ off_t fileLen;
+ bool scanResult;
+ long offset;
+ int method;
+ long uncompressedLen, compressedLen;
+ int fd;
+
+ fd = open(fileName, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ return NULL;
+
+ fileLen = lseek(fd, 0, SEEK_END);
+ if (fileLen < 0) {
+ ::close(fd);
+ return NULL;
+ }
+ (void) lseek(fd, 0, SEEK_SET);
+
+ /* want buffered I/O for the file scan; must dup so fclose() is safe */
+ FILE* fp = fdopen(dup(fd), "rb");
+ if (fp == NULL) {
+ ::close(fd);
+ return NULL;
+ }
+
+ unsigned long crc32;
+ scanResult = ZipUtils::examineGzip(fp, &method, &uncompressedLen,
+ &compressedLen, &crc32);
+ offset = ftell(fp);
+ fclose(fp);
+ if (!scanResult) {
+ LOGD("File '%s' is not in gzip format\n", fileName);
+ ::close(fd);
+ return NULL;
+ }
+
+ pAsset = new _CompressedAsset;
+ result = pAsset->openChunk(fd, offset, method, uncompressedLen,
+ compressedLen);
+ if (result != NO_ERROR) {
+ delete pAsset;
+ return NULL;
+ }
+
+ pAsset->mAccessMode = mode;
+ return pAsset;
+}
+
+
+#if 0
+/*
+ * Create a new Asset from part of an open file.
+ */
+/*static*/ Asset* Asset::createFromFileSegment(int fd, off_t offset,
+ size_t length, AccessMode mode)
+{
+ _FileAsset* pAsset;
+ status_t result;
+
+ pAsset = new _FileAsset;
+ result = pAsset->openChunk(NULL, fd, offset, length);
+ if (result != NO_ERROR)
+ return NULL;
+
+ pAsset->mAccessMode = mode;
+ return pAsset;
+}
+
+/*
+ * Create a new Asset from compressed data in an open file.
+ */
+/*static*/ Asset* Asset::createFromCompressedData(int fd, off_t offset,
+ int compressionMethod, size_t uncompressedLen, size_t compressedLen,
+ AccessMode mode)
+{
+ _CompressedAsset* pAsset;
+ status_t result;
+
+ pAsset = new _CompressedAsset;
+ result = pAsset->openChunk(fd, offset, compressionMethod,
+ uncompressedLen, compressedLen);
+ if (result != NO_ERROR)
+ return NULL;
+
+ pAsset->mAccessMode = mode;
+ return pAsset;
+}
+#endif
+
+/*
+ * Create a new Asset from a memory mapping.
+ */
+/*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap,
+ AccessMode mode)
+{
+ _FileAsset* pAsset;
+ status_t result;
+
+ pAsset = new _FileAsset;
+ result = pAsset->openChunk(dataMap);
+ if (result != NO_ERROR)
+ return NULL;
+
+ pAsset->mAccessMode = mode;
+ return pAsset;
+}
+
+/*
+ * Create a new Asset from compressed data in a memory mapping.
+ */
+/*static*/ Asset* Asset::createFromCompressedMap(FileMap* dataMap,
+ int method, size_t uncompressedLen, AccessMode mode)
+{
+ _CompressedAsset* pAsset;
+ status_t result;
+
+ pAsset = new _CompressedAsset;
+ result = pAsset->openChunk(dataMap, method, uncompressedLen);
+ if (result != NO_ERROR)
+ return NULL;
+
+ pAsset->mAccessMode = mode;
+ return pAsset;
+}
+
+
+/*
+ * Do generic seek() housekeeping. Pass in the offset/whence values from
+ * the seek request, along with the current chunk offset and the chunk
+ * length.
+ *
+ * Returns the new chunk offset, or -1 if the seek is illegal.
+ */
+off_t Asset::handleSeek(off_t offset, int whence, off_t curPosn, off_t maxPosn)
+{
+ off_t newOffset;
+
+ switch (whence) {
+ case SEEK_SET:
+ newOffset = offset;
+ break;
+ case SEEK_CUR:
+ newOffset = curPosn + offset;
+ break;
+ case SEEK_END:
+ newOffset = maxPosn + offset;
+ break;
+ default:
+ LOGW("unexpected whence %d\n", whence);
+ // this was happening due to an off_t size mismatch
+ assert(false);
+ return (off_t) -1;
+ }
+
+ if (newOffset < 0 || newOffset > maxPosn) {
+ LOGW("seek out of range: want %ld, end=%ld\n",
+ (long) newOffset, (long) maxPosn);
+ return (off_t) -1;
+ }
+
+ return newOffset;
+}
+
+
+/*
+ * ===========================================================================
+ * _FileAsset
+ * ===========================================================================
+ */
+
+/*
+ * Constructor.
+ */
+_FileAsset::_FileAsset(void)
+ : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL)
+{
+}
+
+/*
+ * Destructor. Release resources.
+ */
+_FileAsset::~_FileAsset(void)
+{
+ close();
+}
+
+/*
+ * Operate on a chunk of an uncompressed file.
+ *
+ * Zero-length chunks are allowed.
+ */
+status_t _FileAsset::openChunk(const char* fileName, int fd, off_t offset, size_t length)
+{
+ assert(mFp == NULL); // no reopen
+ assert(mMap == NULL);
+ assert(fd >= 0);
+ assert(offset >= 0);
+
+ /*
+ * Seek to end to get file length.
+ */
+ off_t fileLength;
+ fileLength = lseek(fd, 0, SEEK_END);
+ if (fileLength == (off_t) -1) {
+ // probably a bad file descriptor
+ LOGD("failed lseek (errno=%d)\n", errno);
+ return UNKNOWN_ERROR;
+ }
+
+ if ((off_t) (offset + length) > fileLength) {
+ LOGD("start (%ld) + len (%ld) > end (%ld)\n",
+ (long) offset, (long) length, (long) fileLength);
+ return BAD_INDEX;
+ }
+
+ /* after fdopen, the fd will be closed on fclose() */
+ mFp = fdopen(fd, "rb");
+ if (mFp == NULL)
+ return UNKNOWN_ERROR;
+
+ mStart = offset;
+ mLength = length;
+ assert(mOffset == 0);
+
+ /* seek the FILE* to the start of chunk */
+ if (fseek(mFp, mStart, SEEK_SET) != 0) {
+ assert(false);
+ }
+
+ mFileName = fileName != NULL ? strdup(fileName) : NULL;
+
+ return NO_ERROR;
+}
+
+/*
+ * Create the chunk from the map.
+ */
+status_t _FileAsset::openChunk(FileMap* dataMap)
+{
+ assert(mFp == NULL); // no reopen
+ assert(mMap == NULL);
+ assert(dataMap != NULL);
+
+ mMap = dataMap;
+ mStart = -1; // not used
+ mLength = dataMap->getDataLength();
+ assert(mOffset == 0);
+
+ return NO_ERROR;
+}
+
+/*
+ * Read a chunk of data.
+ */
+ssize_t _FileAsset::read(void* buf, size_t count)
+{
+ size_t maxLen;
+ size_t actual;
+
+ assert(mOffset >= 0 && mOffset <= mLength);
+
+ if (getAccessMode() == ACCESS_BUFFER) {
+ /*
+ * On first access, read or map the entire file. The caller has
+ * requested buffer access, either because they're going to be
+ * using the buffer or because what they're doing has appropriate
+ * performance needs and access patterns.
+ */
+ if (mBuf == NULL)
+ getBuffer(false);
+ }
+
+ /* adjust count if we're near EOF */
+ maxLen = mLength - mOffset;
+ if (count > maxLen)
+ count = maxLen;
+
+ if (!count)
+ return 0;
+
+ if (mMap != NULL) {
+ /* copy from mapped area */
+ //printf("map read\n");
+ memcpy(buf, (char*)mMap->getDataPtr() + mOffset, count);
+ actual = count;
+ } else if (mBuf != NULL) {
+ /* copy from buffer */
+ //printf("buf read\n");
+ memcpy(buf, (char*)mBuf + mOffset, count);
+ actual = count;
+ } else {
+ /* read from the file */
+ //printf("file read\n");
+ if (ftell(mFp) != mStart + mOffset) {
+ LOGE("Hosed: %ld != %ld+%ld\n",
+ ftell(mFp), (long) mStart, (long) mOffset);
+ assert(false);
+ }
+
+ /*
+ * This returns 0 on error or eof. We need to use ferror() or feof()
+ * to tell the difference, but we don't currently have those on the
+ * device. However, we know how much data is *supposed* to be in the
+ * file, so if we don't read the full amount we know something is
+ * hosed.
+ */
+ actual = fread(buf, 1, count, mFp);
+ if (actual == 0) // something failed -- I/O error?
+ return -1;
+
+ assert(actual == count);
+ }
+
+ mOffset += actual;
+ return actual;
+}
+
+/*
+ * Seek to a new position.
+ */
+off_t _FileAsset::seek(off_t offset, int whence)
+{
+ off_t newPosn;
+ long actualOffset;
+
+ // compute new position within chunk
+ newPosn = handleSeek(offset, whence, mOffset, mLength);
+ if (newPosn == (off_t) -1)
+ return newPosn;
+
+ actualOffset = (long) (mStart + newPosn);
+
+ if (mFp != NULL) {
+ if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0)
+ return (off_t) -1;
+ }
+
+ mOffset = actualOffset - mStart;
+ return mOffset;
+}
+
+/*
+ * Close the asset.
+ */
+void _FileAsset::close(void)
+{
+ if (mMap != NULL) {
+ mMap->release();
+ mMap = NULL;
+ }
+ if (mBuf != NULL) {
+ delete[] mBuf;
+ mBuf = NULL;
+ }
+
+ if (mFileName != NULL) {
+ free(mFileName);
+ mFileName = NULL;
+ }
+
+ if (mFp != NULL) {
+ // can only be NULL when called from destructor
+ // (otherwise we would never return this object)
+ fclose(mFp);
+ mFp = NULL;
+ }
+}
+
+/*
+ * Return a read-only pointer to a buffer.
+ *
+ * We can either read the whole thing in or map the relevant piece of
+ * the source file. Ideally a map would be established at a higher
+ * level and we'd be using a different object, but we didn't, so we
+ * deal with it here.
+ */
+const void* _FileAsset::getBuffer(bool wordAligned)
+{
+ /* subsequent requests just use what we did previously */
+ if (mBuf != NULL)
+ return mBuf;
+ if (mMap != NULL) {
+ if (!wordAligned) {
+ return mMap->getDataPtr();
+ }
+ return ensureAlignment(mMap);
+ }
+
+ assert(mFp != NULL);
+
+ if (mLength < kReadVsMapThreshold) {
+ unsigned char* buf;
+ long allocLen;
+
+ /* zero-length files are allowed; not sure about zero-len allocs */
+ /* (works fine with gcc + x86linux) */
+ allocLen = mLength;
+ if (mLength == 0)
+ allocLen = 1;
+
+ buf = new unsigned char[allocLen];
+ if (buf == NULL) {
+ LOGE("alloc of %ld bytes failed\n", (long) allocLen);
+ return NULL;
+ }
+
+ LOGV("Asset %p allocating buffer size %d (smaller than threshold)", this, (int)allocLen);
+ if (mLength > 0) {
+ long oldPosn = ftell(mFp);
+ fseek(mFp, mStart, SEEK_SET);
+ if (fread(buf, 1, mLength, mFp) != (size_t) mLength) {
+ LOGE("failed reading %ld bytes\n", (long) mLength);
+ delete[] buf;
+ return NULL;
+ }
+ fseek(mFp, oldPosn, SEEK_SET);
+ }
+
+ LOGV(" getBuffer: loaded into buffer\n");
+
+ mBuf = buf;
+ return mBuf;
+ } else {
+ FileMap* map;
+
+ map = new FileMap;
+ if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
+ map->release();
+ return NULL;
+ }
+
+ LOGV(" getBuffer: mapped\n");
+
+ mMap = map;
+ if (!wordAligned) {
+ return mMap->getDataPtr();
+ }
+ return ensureAlignment(mMap);
+ }
+}
+
+int _FileAsset::openFileDescriptor(off_t* outStart, off_t* outLength) const
+{
+ if (mMap != NULL) {
+ const char* fname = mMap->getFileName();
+ if (fname == NULL) {
+ fname = mFileName;
+ }
+ if (fname == NULL) {
+ return -1;
+ }
+ *outStart = mMap->getDataOffset();
+ *outLength = mMap->getDataLength();
+ return open(fname, O_RDONLY | O_BINARY);
+ }
+ if (mFileName == NULL) {
+ return -1;
+ }
+ *outStart = mStart;
+ *outLength = mLength;
+ return open(mFileName, O_RDONLY | O_BINARY);
+}
+
+const void* _FileAsset::ensureAlignment(FileMap* map)
+{
+ void* data = map->getDataPtr();
+ if ((((size_t)data)&0x3) == 0) {
+ // We can return this directly if it is aligned on a word
+ // boundary.
+ return data;
+ }
+ // If not aligned on a word boundary, then we need to copy it into
+ // our own buffer.
+ LOGV("Copying FileAsset %p to buffer size %d to make it aligned.", this, (int)mLength);
+ unsigned char* buf = new unsigned char[mLength];
+ if (buf == NULL) {
+ LOGE("alloc of %ld bytes failed\n", (long) mLength);
+ return NULL;
+ }
+ memcpy(buf, data, mLength);
+ mBuf = buf;
+ return buf;
+}
+
+/*
+ * ===========================================================================
+ * _CompressedAsset
+ * ===========================================================================
+ */
+
+/*
+ * Constructor.
+ */
+_CompressedAsset::_CompressedAsset(void)
+ : mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
+ mMap(NULL), mFd(-1), mBuf(NULL)
+{
+}
+
+/*
+ * Destructor. Release resources.
+ */
+_CompressedAsset::~_CompressedAsset(void)
+{
+ close();
+}
+
+/*
+ * Open a chunk of compressed data inside a file.
+ *
+ * This currently just sets up some values and returns. On the first
+ * read, we expand the entire file into a buffer and return data from it.
+ */
+status_t _CompressedAsset::openChunk(int fd, off_t offset,
+ int compressionMethod, size_t uncompressedLen, size_t compressedLen)
+{
+ assert(mFd < 0); // no re-open
+ assert(mMap == NULL);
+ assert(fd >= 0);
+ assert(offset >= 0);
+ assert(compressedLen > 0);
+
+ if (compressionMethod != ZipFileRO::kCompressDeflated) {
+ assert(false);
+ return UNKNOWN_ERROR;
+ }
+
+ mStart = offset;
+ mCompressedLen = compressedLen;
+ mUncompressedLen = uncompressedLen;
+ assert(mOffset == 0);
+ mFd = fd;
+ assert(mBuf == NULL);
+
+ return NO_ERROR;
+}
+
+/*
+ * Open a chunk of compressed data in a mapped region.
+ *
+ * Nothing is expanded until the first read call.
+ */
+status_t _CompressedAsset::openChunk(FileMap* dataMap, int compressionMethod,
+ size_t uncompressedLen)
+{
+ assert(mFd < 0); // no re-open
+ assert(mMap == NULL);
+ assert(dataMap != NULL);
+
+ if (compressionMethod != ZipFileRO::kCompressDeflated) {
+ assert(false);
+ return UNKNOWN_ERROR;
+ }
+
+ mMap = dataMap;
+ mStart = -1; // not used
+ mCompressedLen = dataMap->getDataLength();
+ mUncompressedLen = uncompressedLen;
+ assert(mOffset == 0);
+
+ return NO_ERROR;
+}
+
+/*
+ * Read data from a chunk of compressed data.
+ *
+ * [For now, that's just copying data out of a buffer.]
+ */
+ssize_t _CompressedAsset::read(void* buf, size_t count)
+{
+ size_t maxLen;
+ size_t actual;
+
+ assert(mOffset >= 0 && mOffset <= mUncompressedLen);
+
+ // TODO: if mAccessMode == ACCESS_STREAMING, use zlib more cleverly
+
+ if (mBuf == NULL) {
+ if (getBuffer(false) == NULL)
+ return -1;
+ }
+ assert(mBuf != NULL);
+
+ /* adjust count if we're near EOF */
+ maxLen = mUncompressedLen - mOffset;
+ if (count > maxLen)
+ count = maxLen;
+
+ if (!count)
+ return 0;
+
+ /* copy from buffer */
+ //printf("comp buf read\n");
+ memcpy(buf, (char*)mBuf + mOffset, count);
+ actual = count;
+
+ mOffset += actual;
+ return actual;
+}
+
+/*
+ * Handle a seek request.
+ *
+ * If we're working in a streaming mode, this is going to be fairly
+ * expensive, because it requires plowing through a bunch of compressed
+ * data.
+ */
+off_t _CompressedAsset::seek(off_t offset, int whence)
+{
+ off_t newPosn;
+
+ // compute new position within chunk
+ newPosn = handleSeek(offset, whence, mOffset, mUncompressedLen);
+ if (newPosn == (off_t) -1)
+ return newPosn;
+
+ mOffset = newPosn;
+ return mOffset;
+}
+
+/*
+ * Close the asset.
+ */
+void _CompressedAsset::close(void)
+{
+ if (mMap != NULL) {
+ mMap->release();
+ mMap = NULL;
+ }
+ if (mBuf != NULL) {
+ delete[] mBuf;
+ mBuf = NULL;
+ }
+
+ if (mFd > 0) {
+ ::close(mFd);
+ mFd = -1;
+ }
+}
+
+/*
+ * Get a pointer to a read-only buffer of data.
+ *
+ * The first time this is called, we expand the compressed data into a
+ * buffer.
+ */
+const void* _CompressedAsset::getBuffer(bool wordAligned)
+{
+ unsigned char* buf = NULL;
+
+ if (mBuf != NULL)
+ return mBuf;
+
+ if (mUncompressedLen > UNCOMPRESS_DATA_MAX) {
+ LOGD("Data exceeds UNCOMPRESS_DATA_MAX (%ld vs %d)\n",
+ (long) mUncompressedLen, UNCOMPRESS_DATA_MAX);
+ goto bail;
+ }
+
+ /*
+ * Allocate a buffer and read the file into it.
+ */
+ buf = new unsigned char[mUncompressedLen];
+ if (buf == NULL) {
+ LOGW("alloc %ld bytes failed\n", (long) mUncompressedLen);
+ goto bail;
+ }
+
+ if (mMap != NULL) {
+ if (!ZipFileRO::inflateBuffer(buf, mMap->getDataPtr(),
+ mUncompressedLen, mCompressedLen))
+ goto bail;
+ } else {
+ assert(mFd >= 0);
+
+ /*
+ * Seek to the start of the compressed data.
+ */
+ if (lseek(mFd, mStart, SEEK_SET) != mStart)
+ goto bail;
+
+ /*
+ * Expand the data into it.
+ */
+ if (!ZipUtils::inflateToBuffer(mFd, buf, mUncompressedLen,
+ mCompressedLen))
+ goto bail;
+ }
+
+ /* success! */
+ mBuf = buf;
+ buf = NULL;
+
+bail:
+ delete[] buf;
+ return mBuf;
+}
+
diff --git a/libs/utils/AssetDir.cpp b/libs/utils/AssetDir.cpp
new file mode 100644
index 0000000..c5f664e
--- /dev/null
+++ b/libs/utils/AssetDir.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Provide access to a virtual directory in "asset space". Most of the
+// implementation is in the header file or in friend functions in
+// AssetManager.
+//
+#include <utils/AssetDir.h>
+
+using namespace android;
+
+
+/*
+ * Find a matching entry in a vector of FileInfo. Because it's sorted, we
+ * can use a binary search.
+ *
+ * Assumes the vector is sorted in ascending order.
+ */
+/*static*/ int AssetDir::FileInfo::findEntry(const SortedVector<FileInfo>* pVector,
+ const String8& fileName)
+{
+ FileInfo tmpInfo;
+
+ tmpInfo.setFileName(fileName);
+ return pVector->indexOf(tmpInfo);
+
+#if 0 // don't need this after all (uses 1/2 compares of SortedVector though)
+ int lo, hi, cur;
+
+ lo = 0;
+ hi = pVector->size() -1;
+ while (lo <= hi) {
+ int cmp;
+
+ cur = (hi + lo) / 2;
+ cmp = strcmp(pVector->itemAt(cur).getFileName(), fileName);
+ if (cmp == 0) {
+ /* match, bail */
+ return cur;
+ } else if (cmp < 0) {
+ /* too low */
+ lo = cur + 1;
+ } else {
+ /* too high */
+ hi = cur -1;
+ }
+ }
+
+ return -1;
+#endif
+}
+
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
new file mode 100644
index 0000000..447b801
--- /dev/null
+++ b/libs/utils/AssetManager.cpp
@@ -0,0 +1,1637 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Provide access to read-only assets.
+//
+
+#define LOG_TAG "asset"
+//#define LOG_NDEBUG 0
+
+#include <utils/AssetManager.h>
+#include <utils/AssetDir.h>
+#include <utils/Asset.h>
+#include <utils/Atomic.h>
+#include <utils/String8.h>
+#include <utils/ResourceTypes.h>
+#include <utils/String8.h>
+#include <utils/ZipFileRO.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Names for default app, locale, and vendor. We might want to change
+ * these to be an actual locale, e.g. always use en-US as the default.
+ */
+static const char* kDefaultLocale = "default";
+static const char* kDefaultVendor = "default";
+static const char* kAssetsRoot = "assets";
+static const char* kAppZipName = NULL; //"classes.jar";
+static const char* kSystemAssets = "framework/framework-res.apk";
+
+static const char* kExcludeExtension = ".EXCLUDE";
+
+static Asset* const kExcludedAsset = (Asset*) 0xd000000d;
+
+static volatile int32_t gCount = 0;
+
+
+/*
+ * ===========================================================================
+ * AssetManager
+ * ===========================================================================
+ */
+
+int32_t AssetManager::getGlobalCount()
+{
+ return gCount;
+}
+
+AssetManager::AssetManager(CacheMode cacheMode)
+ : mLocale(NULL), mVendor(NULL),
+ mResources(NULL), mConfig(new ResTable_config),
+ mCacheMode(cacheMode), mCacheValid(false)
+{
+ int count = android_atomic_inc(&gCount)+1;
+ //LOGI("Creating AssetManager %p #%d\n", this, count);
+ memset(mConfig, 0, sizeof(ResTable_config));
+}
+
+AssetManager::~AssetManager(void)
+{
+ int count = android_atomic_dec(&gCount);
+ //LOGI("Destroying AssetManager in %p #%d\n", this, count);
+
+ delete mConfig;
+ delete mResources;
+
+ // don't have a String class yet, so make sure we clean up
+ delete[] mLocale;
+ delete[] mVendor;
+}
+
+bool AssetManager::addAssetPath(const String8& path, void** cookie)
+{
+ AutoMutex _l(mLock);
+
+ asset_path ap;
+
+ String8 realPath(path);
+ if (kAppZipName) {
+ realPath.appendPath(kAppZipName);
+ }
+ ap.type = ::getFileType(realPath.string());
+ if (ap.type == kFileTypeRegular) {
+ ap.path = realPath;
+ } else {
+ ap.path = path;
+ ap.type = ::getFileType(path.string());
+ if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) {
+ LOGW("Asset path %s is neither a directory nor file (type=%d).",
+ path.string(), (int)ap.type);
+ return false;
+ }
+ }
+
+ // Skip if we have it already.
+ for (size_t i=0; i<mAssetPaths.size(); i++) {
+ if (mAssetPaths[i].path == ap.path) {
+ if (cookie) {
+ *cookie = (void*)(i+1);
+ }
+ return true;
+ }
+ }
+
+ LOGV("In %p Asset %s path: %s", this,
+ ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
+
+ mAssetPaths.add(ap);
+
+ // new paths are always added at the end
+ if (cookie) {
+ *cookie = (void*)mAssetPaths.size();
+ }
+
+ return true;
+}
+
+bool AssetManager::addDefaultAssets()
+{
+ const char* root = getenv("ANDROID_ROOT");
+ LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");
+
+ String8 path(root);
+ path.appendPath(kSystemAssets);
+
+ return addAssetPath(path, NULL);
+}
+
+void* AssetManager::nextAssetPath(void* cookie) const
+{
+ AutoMutex _l(mLock);
+ size_t next = ((size_t)cookie)+1;
+ return next > mAssetPaths.size() ? NULL : (void*)next;
+}
+
+String8 AssetManager::getAssetPath(void* cookie) const
+{
+ AutoMutex _l(mLock);
+ const size_t which = ((size_t)cookie)-1;
+ if (which < mAssetPaths.size()) {
+ return mAssetPaths[which].path;
+ }
+ return String8();
+}
+
+/*
+ * Set the current locale. Use NULL to indicate no locale.
+ *
+ * Close and reopen Zip archives as appropriate, and reset cached
+ * information in the locale-specific sections of the tree.
+ */
+void AssetManager::setLocale(const char* locale)
+{
+ AutoMutex _l(mLock);
+ setLocaleLocked(locale);
+}
+
+void AssetManager::setLocaleLocked(const char* locale)
+{
+ if (mLocale != NULL) {
+ /* previously set, purge cached data */
+ purgeFileNameCacheLocked();
+ //mZipSet.purgeLocale();
+ delete[] mLocale;
+ }
+ mLocale = strdupNew(locale);
+
+ updateResourceParamsLocked();
+}
+
+/*
+ * Set the current vendor. Use NULL to indicate no vendor.
+ *
+ * Close and reopen Zip archives as appropriate, and reset cached
+ * information in the vendor-specific sections of the tree.
+ */
+void AssetManager::setVendor(const char* vendor)
+{
+ AutoMutex _l(mLock);
+
+ if (mVendor != NULL) {
+ /* previously set, purge cached data */
+ purgeFileNameCacheLocked();
+ //mZipSet.purgeVendor();
+ delete[] mVendor;
+ }
+ mVendor = strdupNew(vendor);
+}
+
+void AssetManager::setConfiguration(const ResTable_config& config, const char* locale)
+{
+ AutoMutex _l(mLock);
+ *mConfig = config;
+ if (locale) {
+ setLocaleLocked(locale);
+ } else if (config.language[0] != 0) {
+ char spec[9];
+ spec[0] = config.language[0];
+ spec[1] = config.language[1];
+ if (config.country[0] != 0) {
+ spec[2] = '_';
+ spec[3] = config.country[0];
+ spec[4] = config.country[1];
+ spec[5] = 0;
+ } else {
+ spec[3] = 0;
+ }
+ setLocaleLocked(spec);
+ } else {
+ updateResourceParamsLocked();
+ }
+}
+
+/*
+ * Open an asset.
+ *
+ * The data could be;
+ * - In a file on disk (assetBase + fileName).
+ * - In a compressed file on disk (assetBase + fileName.gz).
+ * - In a Zip archive, uncompressed or compressed.
+ *
+ * It can be in a number of different directories and Zip archives.
+ * The search order is:
+ * - [appname]
+ * - locale + vendor
+ * - "default" + vendor
+ * - locale + "default"
+ * - "default + "default"
+ * - "common"
+ * - (same as above)
+ *
+ * To find a particular file, we have to try up to eight paths with
+ * all three forms of data.
+ *
+ * We should probably reject requests for "illegal" filenames, e.g. those
+ * with illegal characters or "../" backward relative paths.
+ */
+Asset* AssetManager::open(const char* fileName, AccessMode mode)
+{
+ AutoMutex _l(mLock);
+
+ LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+
+
+ if (mCacheMode != CACHE_OFF && !mCacheValid)
+ loadFileNameCacheLocked();
+
+ String8 assetName(kAssetsRoot);
+ assetName.appendPath(fileName);
+
+ /*
+ * For each top-level asset path, search for the asset.
+ */
+
+ size_t i = mAssetPaths.size();
+ while (i > 0) {
+ i--;
+ LOGV("Looking for asset '%s' in '%s'\n",
+ assetName.string(), mAssetPaths.itemAt(i).path.string());
+ Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i));
+ if (pAsset != NULL) {
+ return pAsset != kExcludedAsset ? pAsset : NULL;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Open a non-asset file as if it were an asset.
+ *
+ * The "fileName" is the partial path starting from the application
+ * name.
+ */
+Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode)
+{
+ AutoMutex _l(mLock);
+
+ LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+
+
+ if (mCacheMode != CACHE_OFF && !mCacheValid)
+ loadFileNameCacheLocked();
+
+ /*
+ * For each top-level asset path, search for the asset.
+ */
+
+ size_t i = mAssetPaths.size();
+ while (i > 0) {
+ i--;
+ LOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string());
+ Asset* pAsset = openNonAssetInPathLocked(
+ fileName, mode, mAssetPaths.itemAt(i));
+ if (pAsset != NULL) {
+ return pAsset != kExcludedAsset ? pAsset : NULL;
+ }
+ }
+
+ return NULL;
+}
+
+Asset* AssetManager::openNonAsset(void* cookie, const char* fileName, AccessMode mode)
+{
+ const size_t which = ((size_t)cookie)-1;
+
+ AutoMutex _l(mLock);
+
+ LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+
+
+ if (mCacheMode != CACHE_OFF && !mCacheValid)
+ loadFileNameCacheLocked();
+
+ if (which < mAssetPaths.size()) {
+ LOGV("Looking for non-asset '%s' in '%s'\n", fileName,
+ mAssetPaths.itemAt(which).path.string());
+ Asset* pAsset = openNonAssetInPathLocked(
+ fileName, mode, mAssetPaths.itemAt(which));
+ if (pAsset != NULL) {
+ return pAsset != kExcludedAsset ? pAsset : NULL;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Get the type of a file in the asset namespace.
+ *
+ * This currently only works for regular files. All others (including
+ * directories) will return kFileTypeNonexistent.
+ */
+FileType AssetManager::getFileType(const char* fileName)
+{
+ Asset* pAsset = NULL;
+
+ /*
+ * Open the asset. This is less efficient than simply finding the
+ * file, but it's not too bad (we don't uncompress or mmap data until
+ * the first read() call).
+ */
+ pAsset = open(fileName, Asset::ACCESS_STREAMING);
+ delete pAsset;
+
+ if (pAsset == NULL)
+ return kFileTypeNonexistent;
+ else
+ return kFileTypeRegular;
+}
+
+const ResTable* AssetManager::getResTable(bool required) const
+{
+ ResTable* rt = mResources;
+ if (rt) {
+ return rt;
+ }
+
+ // Iterate through all asset packages, collecting resources from each.
+
+ AutoMutex _l(mLock);
+
+ if (mResources != NULL) {
+ return mResources;
+ }
+
+ if (required) {
+ LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+ }
+
+ if (mCacheMode != CACHE_OFF && !mCacheValid)
+ const_cast<AssetManager*>(this)->loadFileNameCacheLocked();
+
+ const size_t N = mAssetPaths.size();
+ for (size_t i=0; i<N; i++) {
+ Asset* ass = NULL;
+ bool shared = true;
+ const asset_path& ap = mAssetPaths.itemAt(i);
+ LOGV("Looking for resource asset in '%s'\n", ap.path.string());
+ if (ap.type != kFileTypeDirectory) {
+ ass = const_cast<AssetManager*>(this)->
+ mZipSet.getZipResourceTable(ap.path);
+ if (ass == NULL) {
+ LOGV("loading resource table %s\n", ap.path.string());
+ ass = const_cast<AssetManager*>(this)->
+ openNonAssetInPathLocked("resources.arsc",
+ Asset::ACCESS_BUFFER,
+ ap);
+ if (ass != NULL && ass != kExcludedAsset) {
+ ass = const_cast<AssetManager*>(this)->
+ mZipSet.setZipResourceTable(ap.path, ass);
+ }
+ }
+ } else {
+ LOGV("loading resource table %s\n", ap.path.string());
+ Asset* ass = const_cast<AssetManager*>(this)->
+ openNonAssetInPathLocked("resources.arsc",
+ Asset::ACCESS_BUFFER,
+ ap);
+ shared = false;
+ }
+ if (ass != NULL && ass != kExcludedAsset) {
+ if (rt == NULL) {
+ mResources = rt = new ResTable();
+ updateResourceParamsLocked();
+ }
+ LOGV("Installing resource asset %p in to table %p\n", ass, mResources);
+ rt->add(ass, (void*)(i+1), !shared);
+
+ if (!shared) {
+ delete ass;
+ }
+ }
+ }
+
+ if (required && !rt) LOGW("Unable to find resources file resources.arsc");
+ if (!rt) {
+ mResources = rt = new ResTable();
+ }
+ return rt;
+}
+
+void AssetManager::updateResourceParamsLocked() const
+{
+ ResTable* res = mResources;
+ if (!res) {
+ return;
+ }
+
+ size_t llen = mLocale ? strlen(mLocale) : 0;
+ mConfig->language[0] = 0;
+ mConfig->language[1] = 0;
+ mConfig->country[0] = 0;
+ mConfig->country[1] = 0;
+ if (llen >= 2) {
+ mConfig->language[0] = mLocale[0];
+ mConfig->language[1] = mLocale[1];
+ }
+ if (llen >= 5) {
+ mConfig->country[0] = mLocale[3];
+ mConfig->country[1] = mLocale[4];
+ }
+ mConfig->size = sizeof(*mConfig);
+
+ res->setParameters(mConfig);
+}
+
+const ResTable& AssetManager::getResources(bool required) const
+{
+ const ResTable* rt = getResTable(required);
+ return *rt;
+}
+
+bool AssetManager::isUpToDate()
+{
+ AutoMutex _l(mLock);
+ return mZipSet.isUpToDate();
+}
+
+void AssetManager::getLocales(Vector<String8>* locales) const
+{
+ ResTable* res = mResources;
+ if (res != NULL) {
+ res->getLocales(locales);
+ }
+}
+
+/*
+ * Open a non-asset file as if it were an asset, searching for it in the
+ * specified app.
+ *
+ * Pass in a NULL values for "appName" if the common app directory should
+ * be used.
+ */
+Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode mode,
+ const asset_path& ap)
+{
+ Asset* pAsset = NULL;
+
+ /* look at the filesystem on disk */
+ if (ap.type == kFileTypeDirectory) {
+ String8 path(ap.path);
+ path.appendPath(fileName);
+
+ pAsset = openAssetFromFileLocked(path, mode);
+
+ if (pAsset == NULL) {
+ /* try again, this time with ".gz" */
+ path.append(".gz");
+ pAsset = openAssetFromFileLocked(path, mode);
+ }
+
+ if (pAsset != NULL) {
+ //printf("FOUND NA '%s' on disk\n", fileName);
+ pAsset->setAssetSource(path);
+ }
+
+ /* look inside the zip file */
+ } else {
+ String8 path(fileName);
+
+ /* check the appropriate Zip file */
+ ZipFileRO* pZip;
+ ZipEntryRO entry;
+
+ pZip = getZipFileLocked(ap);
+ if (pZip != NULL) {
+ //printf("GOT zip, checking NA '%s'\n", (const char*) path);
+ entry = pZip->findEntryByName(path.string());
+ if (entry != NULL) {
+ //printf("FOUND NA in Zip file for %s\n", appName ? appName : kAppCommon);
+ pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
+ }
+ }
+
+ if (pAsset != NULL) {
+ /* create a "source" name, for debug/display */
+ pAsset->setAssetSource(
+ createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()), String8(""),
+ String8(fileName)));
+ }
+ }
+
+ return pAsset;
+}
+
+/*
+ * Open an asset, searching for it in the directory hierarchy for the
+ * specified app.
+ *
+ * Pass in a NULL values for "appName" if the common app directory should
+ * be used.
+ */
+Asset* AssetManager::openInPathLocked(const char* fileName, AccessMode mode,
+ const asset_path& ap)
+{
+ Asset* pAsset = NULL;
+
+ /*
+ * Try various combinations of locale and vendor.
+ */
+ if (mLocale != NULL && mVendor != NULL)
+ pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, mVendor);
+ if (pAsset == NULL && mVendor != NULL)
+ pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, mVendor);
+ if (pAsset == NULL && mLocale != NULL)
+ pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, NULL);
+ if (pAsset == NULL)
+ pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, NULL);
+
+ return pAsset;
+}
+
+/*
+ * Open an asset, searching for it in the directory hierarchy for the
+ * specified locale and vendor.
+ *
+ * We also search in "app.jar".
+ *
+ * Pass in NULL values for "appName", "locale", and "vendor" if the
+ * defaults should be used.
+ */
+Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode mode,
+ const asset_path& ap, const char* locale, const char* vendor)
+{
+ Asset* pAsset = NULL;
+
+ if (ap.type == kFileTypeDirectory) {
+ if (mCacheMode == CACHE_OFF) {
+ /* look at the filesystem on disk */
+ String8 path(createPathNameLocked(ap, locale, vendor));
+ path.appendPath(fileName);
+
+ String8 excludeName(path);
+ excludeName.append(kExcludeExtension);
+ if (::getFileType(excludeName.string()) != kFileTypeNonexistent) {
+ /* say no more */
+ //printf("+++ excluding '%s'\n", (const char*) excludeName);
+ return kExcludedAsset;
+ }
+
+ pAsset = openAssetFromFileLocked(path, mode);
+
+ if (pAsset == NULL) {
+ /* try again, this time with ".gz" */
+ path.append(".gz");
+ pAsset = openAssetFromFileLocked(path, mode);
+ }
+
+ if (pAsset != NULL)
+ pAsset->setAssetSource(path);
+ } else {
+ /* find in cache */
+ String8 path(createPathNameLocked(ap, locale, vendor));
+ path.appendPath(fileName);
+
+ AssetDir::FileInfo tmpInfo;
+ bool found = false;
+
+ String8 excludeName(path);
+ excludeName.append(kExcludeExtension);
+
+ if (mCache.indexOf(excludeName) != NAME_NOT_FOUND) {
+ /* go no farther */
+ //printf("+++ Excluding '%s'\n", (const char*) excludeName);
+ return kExcludedAsset;
+ }
+
+ /*
+ * File compression extensions (".gz") don't get stored in the
+ * name cache, so we have to try both here.
+ */
+ if (mCache.indexOf(path) != NAME_NOT_FOUND) {
+ found = true;
+ pAsset = openAssetFromFileLocked(path, mode);
+ if (pAsset == NULL) {
+ /* try again, this time with ".gz" */
+ path.append(".gz");
+ pAsset = openAssetFromFileLocked(path, mode);
+ }
+ }
+
+ if (pAsset != NULL)
+ pAsset->setAssetSource(path);
+
+ /*
+ * Don't continue the search into the Zip files. Our cached info
+ * said it was a file on disk; to be consistent with openDir()
+ * we want to return the loose asset. If the cached file gets
+ * removed, we fail.
+ *
+ * The alternative is to update our cache when files get deleted,
+ * or make some sort of "best effort" promise, but for now I'm
+ * taking the hard line.
+ */
+ if (found) {
+ if (pAsset == NULL)
+ LOGD("Expected file not found: '%s'\n", path.string());
+ return pAsset;
+ }
+ }
+ }
+
+ /*
+ * Either it wasn't found on disk or on the cached view of the disk.
+ * Dig through the currently-opened set of Zip files. If caching
+ * is disabled, the Zip file may get reopened.
+ */
+ if (pAsset == NULL && ap.type == kFileTypeRegular) {
+ String8 path;
+
+ path.appendPath((locale != NULL) ? locale : kDefaultLocale);
+ path.appendPath((vendor != NULL) ? vendor : kDefaultVendor);
+ path.appendPath(fileName);
+
+ /* check the appropriate Zip file */
+ ZipFileRO* pZip;
+ ZipEntryRO entry;
+
+ pZip = getZipFileLocked(ap);
+ if (pZip != NULL) {
+ //printf("GOT zip, checking '%s'\n", (const char*) path);
+ entry = pZip->findEntryByName(path.string());
+ if (entry != NULL) {
+ //printf("FOUND in Zip file for %s/%s-%s\n",
+ // appName, locale, vendor);
+ pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
+ }
+ }
+
+ if (pAsset != NULL) {
+ /* create a "source" name, for debug/display */
+ pAsset->setAssetSource(createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()),
+ String8(""), String8(fileName)));
+ }
+ }
+
+ return pAsset;
+}
+
+/*
+ * Create a "source name" for a file from a Zip archive.
+ */
+String8 AssetManager::createZipSourceNameLocked(const String8& zipFileName,
+ const String8& dirName, const String8& fileName)
+{
+ String8 sourceName("zip:");
+ sourceName.append(zipFileName);
+ sourceName.append(":");
+ if (dirName.length() > 0) {
+ sourceName.appendPath(dirName);
+ }
+ sourceName.appendPath(fileName);
+ return sourceName;
+}
+
+/*
+ * Create a path to a loose asset (asset-base/app/locale/vendor).
+ */
+String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* locale,
+ const char* vendor)
+{
+ String8 path(ap.path);
+ path.appendPath((locale != NULL) ? locale : kDefaultLocale);
+ path.appendPath((vendor != NULL) ? vendor : kDefaultVendor);
+ return path;
+}
+
+/*
+ * Create a path to a loose asset (asset-base/app/rootDir).
+ */
+String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir)
+{
+ String8 path(ap.path);
+ if (rootDir != NULL) path.appendPath(rootDir);
+ return path;
+}
+
+/*
+ * Return a pointer to one of our open Zip archives. Returns NULL if no
+ * matching Zip file exists.
+ *
+ * Right now we have 2 possible Zip files (1 each in app/"common").
+ *
+ * If caching is set to CACHE_OFF, to get the expected behavior we
+ * need to reopen the Zip file on every request. That would be silly
+ * and expensive, so instead we just check the file modification date.
+ *
+ * Pass in NULL values for "appName", "locale", and "vendor" if the
+ * generics should be used.
+ */
+ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap)
+{
+ LOGV("getZipFileLocked() in %p\n", this);
+
+ return mZipSet.getZip(ap.path);
+}
+
+/*
+ * Try to open an asset from a file on disk.
+ *
+ * If the file is compressed with gzip, we seek to the start of the
+ * deflated data and pass that in (just like we would for a Zip archive).
+ *
+ * For uncompressed data, we may already have an mmap()ed version sitting
+ * around. If so, we want to hand that to the Asset instead.
+ *
+ * This returns NULL if the file doesn't exist, couldn't be opened, or
+ * claims to be a ".gz" but isn't.
+ */
+Asset* AssetManager::openAssetFromFileLocked(const String8& pathName,
+ AccessMode mode)
+{
+ Asset* pAsset = NULL;
+
+ if (strcasecmp(pathName.getPathExtension().string(), ".gz") == 0) {
+ //printf("TRYING '%s'\n", (const char*) pathName);
+ pAsset = Asset::createFromCompressedFile(pathName.string(), mode);
+ } else {
+ //printf("TRYING '%s'\n", (const char*) pathName);
+ pAsset = Asset::createFromFile(pathName.string(), mode);
+ }
+
+ return pAsset;
+}
+
+/*
+ * Given an entry in a Zip archive, create a new Asset object.
+ *
+ * If the entry is uncompressed, we may want to create or share a
+ * slice of shared memory.
+ */
+Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile,
+ const ZipEntryRO entry, AccessMode mode, const String8& entryName)
+{
+ Asset* pAsset = NULL;
+
+ // TODO: look for previously-created shared memory slice?
+ int method;
+ long uncompressedLen;
+
+ //printf("USING Zip '%s'\n", pEntry->getFileName());
+
+ //pZipFile->getEntryInfo(entry, &method, &uncompressedLen, &compressedLen,
+ // &offset);
+ if (!pZipFile->getEntryInfo(entry, &method, &uncompressedLen, NULL, NULL,
+ NULL, NULL))
+ {
+ LOGW("getEntryInfo failed\n");
+ return NULL;
+ }
+
+ FileMap* dataMap = pZipFile->createEntryFileMap(entry);
+ if (dataMap == NULL) {
+ LOGW("create map from entry failed\n");
+ return NULL;
+ }
+
+ if (method == ZipFileRO::kCompressStored) {
+ pAsset = Asset::createFromUncompressedMap(dataMap, mode);
+ LOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(),
+ dataMap->getFileName(), mode, pAsset);
+ } else {
+ pAsset = Asset::createFromCompressedMap(dataMap, method,
+ uncompressedLen, mode);
+ LOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(),
+ dataMap->getFileName(), mode, pAsset);
+ }
+ if (pAsset == NULL) {
+ /* unexpected */
+ LOGW("create from segment failed\n");
+ }
+
+ return pAsset;
+}
+
+
+
+/*
+ * Open a directory in the asset namespace.
+ *
+ * An "asset directory" is simply the combination of all files in all
+ * locations, with ".gz" stripped for loose files. With app, locale, and
+ * vendor defined, we have 8 directories and 2 Zip archives to scan.
+ *
+ * Pass in "" for the root dir.
+ */
+AssetDir* AssetManager::openDir(const char* dirName)
+{
+ AutoMutex _l(mLock);
+
+ AssetDir* pDir = NULL;
+ SortedVector<AssetDir::FileInfo>* pMergedInfo = NULL;
+
+ LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+ assert(dirName != NULL);
+
+ //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
+
+ if (mCacheMode != CACHE_OFF && !mCacheValid)
+ loadFileNameCacheLocked();
+
+ pDir = new AssetDir;
+
+ /*
+ * Scan the various directories, merging what we find into a single
+ * vector. We want to scan them in reverse priority order so that
+ * the ".EXCLUDE" processing works correctly. Also, if we decide we
+ * want to remember where the file is coming from, we'll get the right
+ * version.
+ *
+ * We start with Zip archives, then do loose files.
+ */
+ pMergedInfo = new SortedVector<AssetDir::FileInfo>;
+
+ size_t i = mAssetPaths.size();
+ while (i > 0) {
+ i--;
+ const asset_path& ap = mAssetPaths.itemAt(i);
+ if (ap.type == kFileTypeRegular) {
+ LOGV("Adding directory %s from zip %s", dirName, ap.path.string());
+ scanAndMergeZipLocked(pMergedInfo, ap, kAssetsRoot, dirName);
+ } else {
+ LOGV("Adding directory %s from dir %s", dirName, ap.path.string());
+ scanAndMergeDirLocked(pMergedInfo, ap, kAssetsRoot, dirName);
+ }
+ }
+
+#if 0
+ printf("FILE LIST:\n");
+ for (i = 0; i < (size_t) pMergedInfo->size(); i++) {
+ printf(" %d: (%d) '%s'\n", i,
+ pMergedInfo->itemAt(i).getFileType(),
+ (const char*) pMergedInfo->itemAt(i).getFileName());
+ }
+#endif
+
+ pDir->setFileList(pMergedInfo);
+ return pDir;
+}
+
+/*
+ * Scan the contents of the specified directory and merge them into the
+ * "pMergedInfo" vector, removing previous entries if we find "exclude"
+ * directives.
+ *
+ * Returns "false" if we found nothing to contribute.
+ */
+bool AssetManager::scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+ const asset_path& ap, const char* rootDir, const char* dirName)
+{
+ SortedVector<AssetDir::FileInfo>* pContents;
+ String8 path;
+
+ assert(pMergedInfo != NULL);
+
+ //printf("scanAndMergeDir: %s %s %s %s\n", appName, locale, vendor,dirName);
+
+ if (mCacheValid) {
+ int i, start, count;
+
+ pContents = new SortedVector<AssetDir::FileInfo>;
+
+ /*
+ * Get the basic partial path and find it in the cache. That's
+ * the start point for the search.
+ */
+ path = createPathNameLocked(ap, rootDir);
+ if (dirName[0] != '\0')
+ path.appendPath(dirName);
+
+ start = mCache.indexOf(path);
+ if (start == NAME_NOT_FOUND) {
+ //printf("+++ not found in cache: dir '%s'\n", (const char*) path);
+ delete pContents;
+ return false;
+ }
+
+ /*
+ * The match string looks like "common/default/default/foo/bar/".
+ * The '/' on the end ensures that we don't match on the directory
+ * itself or on ".../foo/barfy/".
+ */
+ path.append("/");
+
+ count = mCache.size();
+
+ /*
+ * Pick out the stuff in the current dir by examining the pathname.
+ * It needs to match the partial pathname prefix, and not have a '/'
+ * (fssep) anywhere after the prefix.
+ */
+ for (i = start+1; i < count; i++) {
+ if (mCache[i].getFileName().length() > path.length() &&
+ strncmp(mCache[i].getFileName().string(), path.string(), path.length()) == 0)
+ {
+ const char* name = mCache[i].getFileName().string();
+ // XXX THIS IS BROKEN! Looks like we need to store the full
+ // path prefix separately from the file path.
+ if (strchr(name + path.length(), '/') == NULL) {
+ /* grab it, reducing path to just the filename component */
+ AssetDir::FileInfo tmp = mCache[i];
+ tmp.setFileName(tmp.getFileName().getPathLeaf());
+ pContents->add(tmp);
+ }
+ } else {
+ /* no longer in the dir or its subdirs */
+ break;
+ }
+
+ }
+ } else {
+ path = createPathNameLocked(ap, rootDir);
+ if (dirName[0] != '\0')
+ path.appendPath(dirName);
+ pContents = scanDirLocked(path);
+ if (pContents == NULL)
+ return false;
+ }
+
+ // if we wanted to do an incremental cache fill, we would do it here
+
+ /*
+ * Process "exclude" directives. If we find a filename that ends with
+ * ".EXCLUDE", we look for a matching entry in the "merged" set, and
+ * remove it if we find it. We also delete the "exclude" entry.
+ */
+ int i, count, exclExtLen;
+
+ count = pContents->size();
+ exclExtLen = strlen(kExcludeExtension);
+ for (i = 0; i < count; i++) {
+ const char* name;
+ int nameLen;
+
+ name = pContents->itemAt(i).getFileName().string();
+ nameLen = strlen(name);
+ if (nameLen > exclExtLen &&
+ strcmp(name + (nameLen - exclExtLen), kExcludeExtension) == 0)
+ {
+ String8 match(name, nameLen - exclExtLen);
+ int matchIdx;
+
+ matchIdx = AssetDir::FileInfo::findEntry(pMergedInfo, match);
+ if (matchIdx > 0) {
+ LOGV("Excluding '%s' [%s]\n",
+ pMergedInfo->itemAt(matchIdx).getFileName().string(),
+ pMergedInfo->itemAt(matchIdx).getSourceName().string());
+ pMergedInfo->removeAt(matchIdx);
+ } else {
+ //printf("+++ no match on '%s'\n", (const char*) match);
+ }
+
+ LOGD("HEY: size=%d removing %d\n", (int)pContents->size(), i);
+ pContents->removeAt(i);
+ i--; // adjust "for" loop
+ count--; // and loop limit
+ }
+ }
+
+ mergeInfoLocked(pMergedInfo, pContents);
+
+ delete pContents;
+
+ return true;
+}
+
+/*
+ * Scan the contents of the specified directory, and stuff what we find
+ * into a newly-allocated vector.
+ *
+ * Files ending in ".gz" will have their extensions removed.
+ *
+ * We should probably think about skipping files with "illegal" names,
+ * e.g. illegal characters (/\:) or excessive length.
+ *
+ * Returns NULL if the specified directory doesn't exist.
+ */
+SortedVector<AssetDir::FileInfo>* AssetManager::scanDirLocked(const String8& path)
+{
+ SortedVector<AssetDir::FileInfo>* pContents = NULL;
+ DIR* dir;
+ struct dirent* entry;
+ FileType fileType;
+
+ LOGV("Scanning dir '%s'\n", path.string());
+
+ dir = opendir(path.string());
+ if (dir == NULL)
+ return NULL;
+
+ pContents = new SortedVector<AssetDir::FileInfo>;
+
+ while (1) {
+ entry = readdir(dir);
+ if (entry == NULL)
+ break;
+
+ if (strcmp(entry->d_name, ".") == 0 ||
+ strcmp(entry->d_name, "..") == 0)
+ continue;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (entry->d_type == DT_REG)
+ fileType = kFileTypeRegular;
+ else if (entry->d_type == DT_DIR)
+ fileType = kFileTypeDirectory;
+ else
+ fileType = kFileTypeUnknown;
+#else
+ // stat the file
+ fileType = ::getFileType(path.appendPathCopy(entry->d_name).string());
+#endif
+
+ if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory)
+ continue;
+
+ AssetDir::FileInfo info;
+ info.set(String8(entry->d_name), fileType);
+ if (strcasecmp(info.getFileName().getPathExtension().string(), ".gz") == 0)
+ info.setFileName(info.getFileName().getBasePath());
+ info.setSourceName(path.appendPathCopy(info.getFileName()));
+ pContents->add(info);
+ }
+
+ closedir(dir);
+ return pContents;
+}
+
+/*
+ * Scan the contents out of the specified Zip archive, and merge what we
+ * find into "pMergedInfo". If the Zip archive in question doesn't exist,
+ * we return immediately.
+ *
+ * Returns "false" if we found nothing to contribute.
+ */
+bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+ const asset_path& ap, const char* rootDir, const char* baseDirName)
+{
+ ZipFileRO* pZip;
+ Vector<String8> dirs;
+ AssetDir::FileInfo info;
+ SortedVector<AssetDir::FileInfo> contents;
+ String8 sourceName, zipName, dirName;
+
+ pZip = mZipSet.getZip(ap.path);
+ if (pZip == NULL) {
+ LOGW("Failure opening zip %s\n", ap.path.string());
+ return false;
+ }
+
+ zipName = ZipSet::getPathName(ap.path.string());
+
+ /* convert "sounds" to "rootDir/sounds" */
+ if (rootDir != NULL) dirName = rootDir;
+ dirName.appendPath(baseDirName);
+
+ /*
+ * Scan through the list of files, looking for a match. The files in
+ * the Zip table of contents are not in sorted order, so we have to
+ * process the entire list. We're looking for a string that begins
+ * with the characters in "dirName", is followed by a '/', and has no
+ * subsequent '/' in the stuff that follows.
+ *
+ * What makes this especially fun is that directories are not stored
+ * explicitly in Zip archives, so we have to infer them from context.
+ * When we see "sounds/foo.wav" we have to leave a note to ourselves
+ * to insert a directory called "sounds" into the list. We store
+ * these in temporary vector so that we only return each one once.
+ *
+ * Name comparisons are case-sensitive to match UNIX filesystem
+ * semantics.
+ */
+ int dirNameLen = dirName.length();
+ for (int i = 0; i < pZip->getNumEntries(); i++) {
+ ZipEntryRO entry;
+ char nameBuf[256];
+
+ entry = pZip->findEntryByIndex(i);
+ if (pZip->getEntryFileName(entry, nameBuf, sizeof(nameBuf)) != 0) {
+ // TODO: fix this if we expect to have long names
+ LOGE("ARGH: name too long?\n");
+ continue;
+ }
+ if (dirNameLen == 0 ||
+ (strncmp(nameBuf, dirName.string(), dirNameLen) == 0 &&
+ nameBuf[dirNameLen] == '/'))
+ {
+ const char* cp;
+ const char* nextSlash;
+
+ cp = nameBuf + dirNameLen;
+ if (dirNameLen != 0)
+ cp++; // advance past the '/'
+
+ nextSlash = strchr(cp, '/');
+//xxx this may break if there are bare directory entries
+ if (nextSlash == NULL) {
+ /* this is a file in the requested directory */
+
+ info.set(String8(nameBuf).getPathLeaf(), kFileTypeRegular);
+
+ info.setSourceName(
+ createZipSourceNameLocked(zipName, dirName, info.getFileName()));
+
+ contents.add(info);
+ //printf("FOUND: file '%s'\n", (const char*) info.mFileName);
+ } else {
+ /* this is a subdir; add it if we don't already have it*/
+ String8 subdirName(cp, nextSlash - cp);
+ size_t j;
+ size_t N = dirs.size();
+
+ for (j = 0; j < N; j++) {
+ if (subdirName == dirs[j]) {
+ break;
+ }
+ }
+ if (j == N) {
+ dirs.add(subdirName);
+ }
+
+ //printf("FOUND: dir '%s'\n", (const char*) subdirName);
+ }
+ }
+ }
+
+ /*
+ * Add the set of unique directories.
+ */
+ for (int i = 0; i < (int) dirs.size(); i++) {
+ info.set(dirs[i], kFileTypeDirectory);
+ info.setSourceName(
+ createZipSourceNameLocked(zipName, dirName, info.getFileName()));
+ contents.add(info);
+ }
+
+ mergeInfoLocked(pMergedInfo, &contents);
+
+ return true;
+}
+
+
+/*
+ * Merge two vectors of FileInfo.
+ *
+ * The merged contents will be stuffed into *pMergedInfo.
+ *
+ * If an entry for a file exists in both "pMergedInfo" and "pContents",
+ * we use the newer "pContents" entry.
+ */
+void AssetManager::mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+ const SortedVector<AssetDir::FileInfo>* pContents)
+{
+ /*
+ * Merge what we found in this directory with what we found in
+ * other places.
+ *
+ * Two basic approaches:
+ * (1) Create a new array that holds the unique values of the two
+ * arrays.
+ * (2) Take the elements from pContents and shove them into pMergedInfo.
+ *
+ * Because these are vectors of complex objects, moving elements around
+ * inside the vector requires constructing new objects and allocating
+ * storage for members. With approach #1, we're always adding to the
+ * end, whereas with #2 we could be inserting multiple elements at the
+ * front of the vector. Approach #1 requires a full copy of the
+ * contents of pMergedInfo, but approach #2 requires the same copy for
+ * every insertion at the front of pMergedInfo.
+ *
+ * (We should probably use a SortedVector interface that allows us to
+ * just stuff items in, trusting us to maintain the sort order.)
+ */
+ SortedVector<AssetDir::FileInfo>* pNewSorted;
+ int mergeMax, contMax;
+ int mergeIdx, contIdx;
+
+ pNewSorted = new SortedVector<AssetDir::FileInfo>;
+ mergeMax = pMergedInfo->size();
+ contMax = pContents->size();
+ mergeIdx = contIdx = 0;
+
+ while (mergeIdx < mergeMax || contIdx < contMax) {
+ if (mergeIdx == mergeMax) {
+ /* hit end of "merge" list, copy rest of "contents" */
+ pNewSorted->add(pContents->itemAt(contIdx));
+ contIdx++;
+ } else if (contIdx == contMax) {
+ /* hit end of "cont" list, copy rest of "merge" */
+ pNewSorted->add(pMergedInfo->itemAt(mergeIdx));
+ mergeIdx++;
+ } else if (pMergedInfo->itemAt(mergeIdx) == pContents->itemAt(contIdx))
+ {
+ /* items are identical, add newer and advance both indices */
+ pNewSorted->add(pContents->itemAt(contIdx));
+ mergeIdx++;
+ contIdx++;
+ } else if (pMergedInfo->itemAt(mergeIdx) < pContents->itemAt(contIdx))
+ {
+ /* "merge" is lower, add that one */
+ pNewSorted->add(pMergedInfo->itemAt(mergeIdx));
+ mergeIdx++;
+ } else {
+ /* "cont" is lower, add that one */
+ assert(pContents->itemAt(contIdx) < pMergedInfo->itemAt(mergeIdx));
+ pNewSorted->add(pContents->itemAt(contIdx));
+ contIdx++;
+ }
+ }
+
+ /*
+ * Overwrite the "merged" list with the new stuff.
+ */
+ *pMergedInfo = *pNewSorted;
+ delete pNewSorted;
+
+#if 0 // for Vector, rather than SortedVector
+ int i, j;
+ for (i = pContents->size() -1; i >= 0; i--) {
+ bool add = true;
+
+ for (j = pMergedInfo->size() -1; j >= 0; j--) {
+ /* case-sensitive comparisons, to behave like UNIX fs */
+ if (strcmp(pContents->itemAt(i).mFileName,
+ pMergedInfo->itemAt(j).mFileName) == 0)
+ {
+ /* match, don't add this entry */
+ add = false;
+ break;
+ }
+ }
+
+ if (add)
+ pMergedInfo->add(pContents->itemAt(i));
+ }
+#endif
+}
+
+
+/*
+ * Load all files into the file name cache. We want to do this across
+ * all combinations of { appname, locale, vendor }, performing a recursive
+ * directory traversal.
+ *
+ * This is not the most efficient data structure. Also, gathering the
+ * information as we needed it (file-by-file or directory-by-directory)
+ * would be faster. However, on the actual device, 99% of the files will
+ * live in Zip archives, so this list will be very small. The trouble
+ * is that we have to check the "loose" files first, so it's important
+ * that we don't beat the filesystem silly looking for files that aren't
+ * there.
+ *
+ * Note on thread safety: this is the only function that causes updates
+ * to mCache, and anybody who tries to use it will call here if !mCacheValid,
+ * so we need to employ a mutex here.
+ */
+void AssetManager::loadFileNameCacheLocked(void)
+{
+ assert(!mCacheValid);
+ assert(mCache.size() == 0);
+
+#ifdef DO_TIMINGS // need to link against -lrt for this now
+ DurationTimer timer;
+ timer.start();
+#endif
+
+ fncScanLocked(&mCache, "");
+
+#ifdef DO_TIMINGS
+ timer.stop();
+ LOGD("Cache scan took %.3fms\n",
+ timer.durationUsecs() / 1000.0);
+#endif
+
+#if 0
+ int i;
+ printf("CACHED FILE LIST (%d entries):\n", mCache.size());
+ for (i = 0; i < (int) mCache.size(); i++) {
+ printf(" %d: (%d) '%s'\n", i,
+ mCache.itemAt(i).getFileType(),
+ (const char*) mCache.itemAt(i).getFileName());
+ }
+#endif
+
+ mCacheValid = true;
+}
+
+/*
+ * Scan up to 8 versions of the specified directory.
+ */
+void AssetManager::fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
+ const char* dirName)
+{
+ size_t i = mAssetPaths.size();
+ while (i > 0) {
+ i--;
+ const asset_path& ap = mAssetPaths.itemAt(i);
+ fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, NULL, dirName);
+ if (mLocale != NULL)
+ fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, NULL, dirName);
+ if (mVendor != NULL)
+ fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, mVendor, dirName);
+ if (mLocale != NULL && mVendor != NULL)
+ fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, mVendor, dirName);
+ }
+}
+
+/*
+ * Recursively scan this directory and all subdirs.
+ *
+ * This is similar to scanAndMergeDir, but we don't remove the .EXCLUDE
+ * files, and we prepend the extended partial path to the filenames.
+ */
+bool AssetManager::fncScanAndMergeDirLocked(
+ SortedVector<AssetDir::FileInfo>* pMergedInfo,
+ const asset_path& ap, const char* locale, const char* vendor,
+ const char* dirName)
+{
+ SortedVector<AssetDir::FileInfo>* pContents;
+ String8 partialPath;
+ String8 fullPath;
+
+ // XXX This is broken -- the filename cache needs to hold the base
+ // asset path separately from its filename.
+
+ partialPath = createPathNameLocked(ap, locale, vendor);
+ if (dirName[0] != '\0') {
+ partialPath.appendPath(dirName);
+ }
+
+ fullPath = partialPath;
+ pContents = scanDirLocked(fullPath);
+ if (pContents == NULL) {
+ return false; // directory did not exist
+ }
+
+ /*
+ * Scan all subdirectories of the current dir, merging what we find
+ * into "pMergedInfo".
+ */
+ for (int i = 0; i < (int) pContents->size(); i++) {
+ if (pContents->itemAt(i).getFileType() == kFileTypeDirectory) {
+ String8 subdir(dirName);
+ subdir.appendPath(pContents->itemAt(i).getFileName());
+
+ fncScanAndMergeDirLocked(pMergedInfo, ap, locale, vendor, subdir.string());
+ }
+ }
+
+ /*
+ * To be consistent, we want entries for the root directory. If
+ * we're the root, add one now.
+ */
+ if (dirName[0] == '\0') {
+ AssetDir::FileInfo tmpInfo;
+
+ tmpInfo.set(String8(""), kFileTypeDirectory);
+ tmpInfo.setSourceName(createPathNameLocked(ap, locale, vendor));
+ pContents->add(tmpInfo);
+ }
+
+ /*
+ * We want to prepend the extended partial path to every entry in
+ * "pContents". It's the same value for each entry, so this will
+ * not change the sorting order of the vector contents.
+ */
+ for (int i = 0; i < (int) pContents->size(); i++) {
+ const AssetDir::FileInfo& info = pContents->itemAt(i);
+ pContents->editItemAt(i).setFileName(partialPath.appendPathCopy(info.getFileName()));
+ }
+
+ mergeInfoLocked(pMergedInfo, pContents);
+ return true;
+}
+
+/*
+ * Trash the cache.
+ */
+void AssetManager::purgeFileNameCacheLocked(void)
+{
+ mCacheValid = false;
+ mCache.clear();
+}
+
+/*
+ * ===========================================================================
+ * AssetManager::SharedZip
+ * ===========================================================================
+ */
+
+
+Mutex AssetManager::SharedZip::gLock;
+DefaultKeyedVector<String8, wp<AssetManager::SharedZip> > AssetManager::SharedZip::gOpen;
+
+AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen)
+ : mPath(path), mZipFile(NULL), mModWhen(modWhen), mResourceTableAsset(NULL)
+{
+ //LOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
+ mZipFile = new ZipFileRO;
+ LOGV("+++ opening zip '%s'\n", mPath.string());
+ if (mZipFile->open(mPath.string()) != NO_ERROR) {
+ LOGD("failed to open Zip archive '%s'\n", mPath.string());
+ delete mZipFile;
+ mZipFile = NULL;
+ }
+}
+
+sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path)
+{
+ AutoMutex _l(gLock);
+ time_t modWhen = getFileModDate(path);
+ sp<SharedZip> zip = gOpen.valueFor(path).promote();
+ if (zip != NULL && zip->mModWhen == modWhen) {
+ return zip;
+ }
+ zip = new SharedZip(path, modWhen);
+ gOpen.add(path, zip);
+ return zip;
+
+}
+
+ZipFileRO* AssetManager::SharedZip::getZip()
+{
+ return mZipFile;
+}
+
+Asset* AssetManager::SharedZip::getResourceTableAsset()
+{
+ LOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset);
+ return mResourceTableAsset;
+}
+
+Asset* AssetManager::SharedZip::setResourceTableAsset(Asset* asset)
+{
+ {
+ AutoMutex _l(gLock);
+ if (mResourceTableAsset == NULL) {
+ mResourceTableAsset = asset;
+ // This is not thread safe the first time it is called, so
+ // do it here with the global lock held.
+ asset->getBuffer(true);
+ return asset;
+ }
+ }
+ delete asset;
+ return mResourceTableAsset;
+}
+
+bool AssetManager::SharedZip::isUpToDate()
+{
+ time_t modWhen = getFileModDate(mPath.string());
+ return mModWhen == modWhen;
+}
+
+AssetManager::SharedZip::~SharedZip()
+{
+ //LOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
+ if (mResourceTableAsset != NULL) {
+ delete mResourceTableAsset;
+ }
+ if (mZipFile != NULL) {
+ delete mZipFile;
+ LOGV("Closed '%s'\n", mPath.string());
+ }
+}
+
+/*
+ * ===========================================================================
+ * AssetManager::ZipSet
+ * ===========================================================================
+ */
+
+/*
+ * Constructor.
+ */
+AssetManager::ZipSet::ZipSet(void)
+{
+}
+
+/*
+ * Destructor. Close any open archives.
+ */
+AssetManager::ZipSet::~ZipSet(void)
+{
+ size_t N = mZipFile.size();
+ for (size_t i = 0; i < N; i++)
+ closeZip(i);
+}
+
+/*
+ * Close a Zip file and reset the entry.
+ */
+void AssetManager::ZipSet::closeZip(int idx)
+{
+ mZipFile.editItemAt(idx) = NULL;
+}
+
+
+/*
+ * Retrieve the appropriate Zip file from the set.
+ */
+ZipFileRO* AssetManager::ZipSet::getZip(const String8& path)
+{
+ int idx = getIndex(path);
+ sp<SharedZip> zip = mZipFile[idx];
+ if (zip == NULL) {
+ zip = SharedZip::get(path);
+ mZipFile.editItemAt(idx) = zip;
+ }
+ return zip->getZip();
+}
+
+Asset* AssetManager::ZipSet::getZipResourceTable(const String8& path)
+{
+ int idx = getIndex(path);
+ sp<SharedZip> zip = mZipFile[idx];
+ if (zip == NULL) {
+ zip = SharedZip::get(path);
+ mZipFile.editItemAt(idx) = zip;
+ }
+ return zip->getResourceTableAsset();
+}
+
+Asset* AssetManager::ZipSet::setZipResourceTable(const String8& path,
+ Asset* asset)
+{
+ int idx = getIndex(path);
+ sp<SharedZip> zip = mZipFile[idx];
+ // doesn't make sense to call before previously accessing.
+ return zip->setResourceTableAsset(asset);
+}
+
+/*
+ * Generate the partial pathname for the specified archive. The caller
+ * gets to prepend the asset root directory.
+ *
+ * Returns something like "common/en-US-noogle.jar".
+ */
+/*static*/ String8 AssetManager::ZipSet::getPathName(const char* zipPath)
+{
+ return String8(zipPath);
+}
+
+bool AssetManager::ZipSet::isUpToDate()
+{
+ const size_t N = mZipFile.size();
+ for (size_t i=0; i<N; i++) {
+ if (mZipFile[i] != NULL && !mZipFile[i]->isUpToDate()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * Compute the zip file's index.
+ *
+ * "appName", "locale", and "vendor" should be set to NULL to indicate the
+ * default directory.
+ */
+int AssetManager::ZipSet::getIndex(const String8& zip) const
+{
+ const size_t N = mZipPath.size();
+ for (size_t i=0; i<N; i++) {
+ if (mZipPath[i] == zip) {
+ return i;
+ }
+ }
+
+ mZipPath.add(zip);
+ mZipFile.add(NULL);
+
+ return mZipPath.size()-1;
+}
+
diff --git a/libs/utils/Binder.cpp b/libs/utils/Binder.cpp
new file mode 100644
index 0000000..37e4685
--- /dev/null
+++ b/libs/utils/Binder.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#include <utils/Binder.h>
+
+#include <utils/Atomic.h>
+#include <utils/BpBinder.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor)
+{
+ return NULL;
+}
+
+BBinder* IBinder::localBinder()
+{
+ return NULL;
+}
+
+BpBinder* IBinder::remoteBinder()
+{
+ return NULL;
+}
+
+bool IBinder::checkSubclass(const void* /*subclassID*/) const
+{
+ return false;
+}
+
+// ---------------------------------------------------------------------------
+
+class BBinder::Extras
+{
+public:
+ Mutex mLock;
+ BpBinder::ObjectManager mObjects;
+};
+
+// ---------------------------------------------------------------------------
+
+BBinder::BBinder()
+ : mExtras(NULL)
+{
+}
+
+bool BBinder::isBinderAlive() const
+{
+ return true;
+}
+
+status_t BBinder::pingBinder()
+{
+ return NO_ERROR;
+}
+
+String16 BBinder::getInterfaceDescriptor() const
+{
+ LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
+ return String16();
+}
+
+status_t BBinder::transact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ data.setDataPosition(0);
+
+ status_t err = NO_ERROR;
+ switch (code) {
+ case PING_TRANSACTION:
+ reply->writeInt32(pingBinder());
+ break;
+ default:
+ err = onTransact(code, data, reply, flags);
+ break;
+ }
+
+ if (reply != NULL) {
+ reply->setDataPosition(0);
+ }
+
+ return err;
+}
+
+status_t BBinder::linkToDeath(
+ const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
+{
+ return INVALID_OPERATION;
+}
+
+status_t BBinder::unlinkToDeath(
+ const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+ wp<DeathRecipient>* outRecipient)
+{
+ return INVALID_OPERATION;
+}
+
+status_t BBinder::dump(int fd, const Vector<String16>& args)
+{
+ return NO_ERROR;
+}
+
+void BBinder::attachObject(
+ const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func)
+{
+ Extras* e = mExtras;
+
+ if (!e) {
+ e = new Extras;
+ if (android_atomic_cmpxchg(0, reinterpret_cast<int32_t>(e),
+ reinterpret_cast<volatile int32_t*>(&mExtras)) != 0) {
+ delete e;
+ e = mExtras;
+ }
+ if (e == 0) return; // out of memory
+ }
+
+ AutoMutex _l(e->mLock);
+ e->mObjects.attach(objectID, object, cleanupCookie, func);
+}
+
+void* BBinder::findObject(const void* objectID) const
+{
+ Extras* e = mExtras;
+ if (!e) return NULL;
+
+ AutoMutex _l(e->mLock);
+ return e->mObjects.find(objectID);
+}
+
+void BBinder::detachObject(const void* objectID)
+{
+ Extras* e = mExtras;
+ if (!e) return;
+
+ AutoMutex _l(e->mLock);
+ e->mObjects.detach(objectID);
+}
+
+BBinder* BBinder::localBinder()
+{
+ return this;
+}
+
+BBinder::~BBinder()
+{
+ if (mExtras) delete mExtras;
+}
+
+
+status_t BBinder::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case INTERFACE_TRANSACTION:
+ reply->writeString16(getInterfaceDescriptor());
+ return NO_ERROR;
+
+ case DUMP_TRANSACTION: {
+ int fd = data.readFileDescriptor();
+ int argc = data.readInt32();
+ Vector<String16> args;
+ for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+ args.add(data.readString16());
+ }
+ return dump(fd, args);
+ }
+ default:
+ return UNKNOWN_TRANSACTION;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+enum {
+ // This is used to transfer ownership of the remote binder from
+ // the BpRefBase object holding it (when it is constructed), to the
+ // owner of the BpRefBase object when it first acquires that BpRefBase.
+ kRemoteAcquired = 0x00000001
+};
+
+BpRefBase::BpRefBase(const sp<IBinder>& o)
+ : mRemote(o.get()), mRefs(NULL), mState(0)
+{
+ extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+
+ if (mRemote) {
+ mRemote->incStrong(this); // Removed on first IncStrong().
+ mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
+ }
+}
+
+BpRefBase::~BpRefBase()
+{
+ if (mRemote) {
+ if (!(mState&kRemoteAcquired)) {
+ mRemote->decStrong(this);
+ }
+ mRefs->decWeak(this);
+ }
+}
+
+void BpRefBase::onFirstRef()
+{
+ android_atomic_or(kRemoteAcquired, &mState);
+}
+
+void BpRefBase::onLastStrongRef(const void* id)
+{
+ if (mRemote) {
+ mRemote->decStrong(this);
+ }
+}
+
+bool BpRefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+ return mRemote ? mRefs->attemptIncStrong(this) : false;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/utils/BpBinder.cpp b/libs/utils/BpBinder.cpp
new file mode 100644
index 0000000..69ab195
--- /dev/null
+++ b/libs/utils/BpBinder.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2005 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 "BpBinder"
+//#define LOG_NDEBUG 0
+
+#include <utils/BpBinder.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+
+//#undef LOGV
+//#define LOGV(...) fprintf(stderr, __VA_ARGS__)
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+BpBinder::ObjectManager::ObjectManager()
+{
+}
+
+BpBinder::ObjectManager::~ObjectManager()
+{
+ kill();
+}
+
+void BpBinder::ObjectManager::attach(
+ const void* objectID, void* object, void* cleanupCookie,
+ IBinder::object_cleanup_func func)
+{
+ entry_t e;
+ e.object = object;
+ e.cleanupCookie = cleanupCookie;
+ e.func = func;
+
+ if (mObjects.indexOfKey(objectID) >= 0) {
+ LOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",
+ objectID, this, object);
+ return;
+ }
+
+ mObjects.add(objectID, e);
+}
+
+void* BpBinder::ObjectManager::find(const void* objectID) const
+{
+ const ssize_t i = mObjects.indexOfKey(objectID);
+ if (i < 0) return NULL;
+ return mObjects.valueAt(i).object;
+}
+
+void BpBinder::ObjectManager::detach(const void* objectID)
+{
+ mObjects.removeItem(objectID);
+}
+
+void BpBinder::ObjectManager::kill()
+{
+ const size_t N = mObjects.size();
+ LOGV("Killing %d objects in manager %p", N, this);
+ for (size_t i=0; i<N; i++) {
+ const entry_t& e = mObjects.valueAt(i);
+ if (e.func != NULL) {
+ e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
+ }
+ }
+
+ mObjects.clear();
+}
+
+// ---------------------------------------------------------------------------
+
+BpBinder::BpBinder(int32_t handle)
+ : mHandle(handle)
+ , mAlive(1)
+ , mObitsSent(0)
+ , mObituaries(NULL)
+{
+ LOGV("Creating BpBinder %p handle %d\n", this, mHandle);
+
+ extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+ IPCThreadState::self()->incWeakHandle(handle);
+}
+
+String16 BpBinder::getInterfaceDescriptor() const
+{
+ String16 res;
+ Parcel send, reply;
+ status_t err = const_cast<BpBinder*>(this)->transact(
+ INTERFACE_TRANSACTION, send, &reply);
+ if (err == NO_ERROR) {
+ res = reply.readString16();
+ }
+ return res;
+}
+
+bool BpBinder::isBinderAlive() const
+{
+ return mAlive != 0;
+}
+
+status_t BpBinder::pingBinder()
+{
+ Parcel send;
+ Parcel reply;
+ status_t err = transact(PING_TRANSACTION, send, &reply);
+ if (err != NO_ERROR) return err;
+ if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA;
+ return (status_t)reply.readInt32();
+}
+
+status_t BpBinder::dump(int fd, const Vector<String16>& args)
+{
+ Parcel send;
+ Parcel reply;
+ send.writeFileDescriptor(fd);
+ const size_t numArgs = args.size();
+ send.writeInt32(numArgs);
+ for (size_t i = 0; i < numArgs; i++) {
+ send.writeString16(args[i]);
+ }
+ status_t err = transact(DUMP_TRANSACTION, send, &reply);
+ return err;
+}
+
+status_t BpBinder::transact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ // Once a binder has died, it will never come back to life.
+ if (mAlive) {
+ status_t status = IPCThreadState::self()->transact(
+ mHandle, code, data, reply, flags);
+ if (status == DEAD_OBJECT) mAlive = 0;
+ return status;
+ }
+
+ return DEAD_OBJECT;
+}
+
+status_t BpBinder::linkToDeath(
+ const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
+{
+ Obituary ob;
+ ob.recipient = recipient;
+ ob.cookie = cookie;
+ ob.flags = flags;
+
+ LOG_ALWAYS_FATAL_IF(recipient == NULL,
+ "linkToDeath(): recipient must be non-NULL");
+
+ {
+ AutoMutex _l(mLock);
+
+ if (!mObitsSent) {
+ if (!mObituaries) {
+ mObituaries = new Vector<Obituary>;
+ if (!mObituaries) {
+ return NO_MEMORY;
+ }
+ LOGV("Requesting death notification: %p handle %d\n", this, mHandle);
+ getWeakRefs()->incWeak(this);
+ IPCThreadState* self = IPCThreadState::self();
+ self->requestDeathNotification(mHandle, this);
+ self->flushCommands();
+ }
+ ssize_t res = mObituaries->add(ob);
+ return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
+ }
+ }
+
+ return DEAD_OBJECT;
+}
+
+status_t BpBinder::unlinkToDeath(
+ const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+ wp<DeathRecipient>* outRecipient)
+{
+ AutoMutex _l(mLock);
+
+ if (mObitsSent) {
+ return DEAD_OBJECT;
+ }
+
+ const size_t N = mObituaries ? mObituaries->size() : 0;
+ for (size_t i=0; i<N; i++) {
+ const Obituary& obit = mObituaries->itemAt(i);
+ if ((obit.recipient == recipient
+ || (recipient == NULL && obit.cookie == cookie))
+ && obit.flags == flags) {
+ const uint32_t allFlags = obit.flags|flags;
+ if (outRecipient != NULL) {
+ *outRecipient = mObituaries->itemAt(i).recipient;
+ }
+ mObituaries->removeAt(i);
+ if (mObituaries->size() == 0) {
+ LOGV("Clearing death notification: %p handle %d\n", this, mHandle);
+ IPCThreadState* self = IPCThreadState::self();
+ self->clearDeathNotification(mHandle, this);
+ self->flushCommands();
+ delete mObituaries;
+ mObituaries = NULL;
+ }
+ return NO_ERROR;
+ }
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+void BpBinder::sendObituary()
+{
+ LOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
+ this, mHandle, mObitsSent ? "true" : "false");
+
+ mAlive = 0;
+ if (mObitsSent) return;
+
+ mLock.lock();
+ Vector<Obituary>* obits = mObituaries;
+ if(obits != NULL) {
+ LOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
+ IPCThreadState* self = IPCThreadState::self();
+ self->clearDeathNotification(mHandle, this);
+ self->flushCommands();
+ mObituaries = NULL;
+ }
+ mObitsSent = 1;
+ mLock.unlock();
+
+ LOGV("Reporting death of proxy %p for %d recipients\n",
+ this, obits ? obits->size() : 0);
+
+ if (obits != NULL) {
+ const size_t N = obits->size();
+ for (size_t i=0; i<N; i++) {
+ reportOneDeath(obits->itemAt(i));
+ }
+
+ delete obits;
+ }
+}
+
+void BpBinder::reportOneDeath(const Obituary& obit)
+{
+ sp<DeathRecipient> recipient = obit.recipient.promote();
+ LOGV("Reporting death to recipient: %p\n", recipient.get());
+ if (recipient == NULL) return;
+
+ recipient->binderDied(this);
+}
+
+
+void BpBinder::attachObject(
+ const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func)
+{
+ AutoMutex _l(mLock);
+ LOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
+ mObjects.attach(objectID, object, cleanupCookie, func);
+}
+
+void* BpBinder::findObject(const void* objectID) const
+{
+ AutoMutex _l(mLock);
+ return mObjects.find(objectID);
+}
+
+void BpBinder::detachObject(const void* objectID)
+{
+ AutoMutex _l(mLock);
+ mObjects.detach(objectID);
+}
+
+BpBinder* BpBinder::remoteBinder()
+{
+ return this;
+}
+
+BpBinder::~BpBinder()
+{
+ LOGV("Destroying BpBinder %p handle %d\n", this, mHandle);
+
+ IPCThreadState* ipc = IPCThreadState::self();
+
+ mLock.lock();
+ Vector<Obituary>* obits = mObituaries;
+ if(obits != NULL) {
+ if (ipc) ipc->clearDeathNotification(mHandle, this);
+ mObituaries = NULL;
+ }
+ mLock.unlock();
+
+ if (obits != NULL) {
+ // XXX Should we tell any remaining DeathRecipient
+ // objects that the last strong ref has gone away, so they
+ // are no longer linked?
+ delete obits;
+ }
+
+ if (ipc) {
+ ipc->expungeHandle(mHandle, this);
+ ipc->decWeakHandle(mHandle);
+ }
+}
+
+void BpBinder::onFirstRef()
+{
+ LOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (ipc) ipc->incStrongHandle(mHandle);
+}
+
+void BpBinder::onLastStrongRef(const void* id)
+{
+ LOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle);
+ IF_LOGV() {
+ printRefs();
+ }
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (ipc) ipc->decStrongHandle(mHandle);
+}
+
+bool BpBinder::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+ LOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle);
+ IPCThreadState* ipc = IPCThreadState::self();
+ return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/utils/BufferedTextOutput.cpp b/libs/utils/BufferedTextOutput.cpp
new file mode 100644
index 0000000..989662e
--- /dev/null
+++ b/libs/utils/BufferedTextOutput.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#include <utils/BufferedTextOutput.h>
+
+#include <utils/Atomic.h>
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <cutils/threads.h>
+
+#include <private/utils/Static.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+struct BufferedTextOutput::BufferState : public RefBase
+{
+ BufferState(int32_t _seq)
+ : seq(_seq)
+ , buffer(NULL)
+ , bufferPos(0)
+ , bufferSize(0)
+ , atFront(true)
+ , indent(0)
+ , bundle(0) {
+ }
+ ~BufferState() {
+ free(buffer);
+ }
+
+ status_t append(const char* txt, size_t len) {
+ if ((len+bufferPos) > bufferSize) {
+ void* b = realloc(buffer, ((len+bufferPos)*3)/2);
+ if (!b) return NO_MEMORY;
+ buffer = (char*)b;
+ }
+ memcpy(buffer+bufferPos, txt, len);
+ bufferPos += len;
+ return NO_ERROR;
+ }
+
+ void restart() {
+ bufferPos = 0;
+ atFront = true;
+ if (bufferSize > 256) {
+ void* b = realloc(buffer, 256);
+ if (b) {
+ buffer = (char*)b;
+ bufferSize = 256;
+ }
+ }
+ }
+
+ const int32_t seq;
+ char* buffer;
+ size_t bufferPos;
+ size_t bufferSize;
+ bool atFront;
+ int32_t indent;
+ int32_t bundle;
+};
+
+struct BufferedTextOutput::ThreadState
+{
+ Vector<sp<BufferedTextOutput::BufferState> > states;
+};
+
+static mutex_t gMutex;
+
+static thread_store_t tls;
+
+BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState()
+{
+ ThreadState* ts = (ThreadState*) thread_store_get( &tls );
+ if (ts) return ts;
+ ts = new ThreadState;
+ thread_store_set( &tls, ts, threadDestructor );
+ return ts;
+}
+
+void BufferedTextOutput::threadDestructor(void *st)
+{
+ delete ((ThreadState*)st);
+}
+
+static volatile int32_t gSequence = 0;
+
+static volatile int32_t gFreeBufferIndex = -1;
+
+static int32_t allocBufferIndex()
+{
+ int32_t res = -1;
+
+ mutex_lock(&gMutex);
+
+ if (gFreeBufferIndex >= 0) {
+ res = gFreeBufferIndex;
+ gFreeBufferIndex = gTextBuffers[res];
+ gTextBuffers.editItemAt(res) = -1;
+
+ } else {
+ res = gTextBuffers.size();
+ gTextBuffers.add(-1);
+ }
+
+ mutex_unlock(&gMutex);
+
+ return res;
+}
+
+static void freeBufferIndex(int32_t idx)
+{
+ mutex_lock(&gMutex);
+ gTextBuffers.editItemAt(idx) = gFreeBufferIndex;
+ gFreeBufferIndex = idx;
+ mutex_unlock(&gMutex);
+}
+
+// ---------------------------------------------------------------------------
+
+BufferedTextOutput::BufferedTextOutput(uint32_t flags)
+ : mFlags(flags)
+ , mSeq(android_atomic_inc(&gSequence))
+ , mIndex(allocBufferIndex())
+{
+ mGlobalState = new BufferState(mSeq);
+ if (mGlobalState) mGlobalState->incStrong(this);
+}
+
+BufferedTextOutput::~BufferedTextOutput()
+{
+ if (mGlobalState) mGlobalState->decStrong(this);
+ freeBufferIndex(mIndex);
+}
+
+status_t BufferedTextOutput::print(const char* txt, size_t len)
+{
+ //printf("BufferedTextOutput: printing %d\n", len);
+
+ AutoMutex _l(mLock);
+ BufferState* b = getBuffer();
+
+ const char* const end = txt+len;
+
+ status_t err;
+
+ while (txt < end) {
+ // Find the next line.
+ const char* first = txt;
+ while (txt < end && *txt != '\n') txt++;
+
+ // Include this and all following empty lines.
+ while (txt < end && *txt == '\n') txt++;
+
+ // Special cases for first data on a line.
+ if (b->atFront) {
+ if (b->indent > 0) {
+ // If this is the start of a line, add the indent.
+ const char* prefix = stringForIndent(b->indent);
+ err = b->append(prefix, strlen(prefix));
+ if (err != NO_ERROR) return err;
+
+ } else if (*(txt-1) == '\n' && !b->bundle) {
+ // Fast path: if we are not indenting or bundling, and
+ // have been given one or more complete lines, just write
+ // them out without going through the buffer.
+
+ // Slurp up all of the lines.
+ const char* lastLine = txt+1;
+ while (txt < end) {
+ if (*txt++ == '\n') lastLine = txt;
+ }
+ struct iovec vec;
+ vec.iov_base = (void*)first;
+ vec.iov_len = lastLine-first;
+ //printf("Writing %d bytes of data!\n", vec.iov_len);
+ writeLines(vec, 1);
+ txt = lastLine;
+ continue;
+ }
+ }
+
+ // Append the new text to the buffer.
+ err = b->append(first, txt-first);
+ if (err != NO_ERROR) return err;
+ b->atFront = *(txt-1) == '\n';
+
+ // If we have finished a line and are not bundling, write
+ // it out.
+ //printf("Buffer is now %d bytes\n", b->bufferPos);
+ if (b->atFront && !b->bundle) {
+ struct iovec vec;
+ vec.iov_base = b->buffer;
+ vec.iov_len = b->bufferPos;
+ //printf("Writing %d bytes of data!\n", vec.iov_len);
+ writeLines(vec, 1);
+ b->restart();
+ }
+ }
+
+ return NO_ERROR;
+}
+
+void BufferedTextOutput::moveIndent(int delta)
+{
+ AutoMutex _l(mLock);
+ BufferState* b = getBuffer();
+ b->indent += delta;
+ if (b->indent < 0) b->indent = 0;
+}
+
+void BufferedTextOutput::pushBundle()
+{
+ AutoMutex _l(mLock);
+ BufferState* b = getBuffer();
+ b->bundle++;
+}
+
+void BufferedTextOutput::popBundle()
+{
+ AutoMutex _l(mLock);
+ BufferState* b = getBuffer();
+ b->bundle--;
+ LOG_FATAL_IF(b->bundle < 0,
+ "TextOutput::popBundle() called more times than pushBundle()");
+ if (b->bundle < 0) b->bundle = 0;
+
+ if (b->bundle == 0) {
+ // Last bundle, write out data if it is complete. If it is not
+ // complete, don't write until the last line is done... this may
+ // or may not be the write thing to do, but it's the easiest.
+ if (b->bufferPos > 0 && b->atFront) {
+ struct iovec vec;
+ vec.iov_base = b->buffer;
+ vec.iov_len = b->bufferPos;
+ writeLines(vec, 1);
+ b->restart();
+ }
+ }
+}
+
+BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
+{
+ if ((mFlags&MULTITHREADED) != 0) {
+ ThreadState* ts = getThreadState();
+ if (ts) {
+ while (ts->states.size() <= (size_t)mIndex) ts->states.add(NULL);
+ BufferState* bs = ts->states[mIndex].get();
+ if (bs != NULL && bs->seq == mSeq) return bs;
+
+ ts->states.editItemAt(mIndex) = new BufferState(mIndex);
+ bs = ts->states[mIndex].get();
+ if (bs != NULL) return bs;
+ }
+ }
+
+ return mGlobalState;
+}
+
+}; // namespace android
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
new file mode 100644
index 0000000..4968666
--- /dev/null
+++ b/libs/utils/CallStack.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "CallStack"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if HAVE_DLADDR
+#include <dlfcn.h>
+#endif
+
+#if HAVE_CXXABI
+#include <cxxabi.h>
+#endif
+
+#include <unwind.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/CallStack.h>
+#include <utils/threads.h>
+
+
+/*****************************************************************************/
+namespace android {
+
+
+typedef struct {
+ size_t count;
+ size_t ignore;
+ const void** addrs;
+} stack_crawl_state_t;
+
+static
+_Unwind_Reason_Code trace_function(_Unwind_Context *context, void *arg)
+{
+ stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
+ if (state->count) {
+ void* ip = (void*)_Unwind_GetIP(context);
+ if (ip) {
+ if (state->ignore) {
+ state->ignore--;
+ } else {
+ state->addrs[0] = ip;
+ state->addrs++;
+ state->count--;
+ }
+ }
+ }
+ return _URC_NO_REASON;
+}
+
+static
+int backtrace(const void** addrs, size_t ignore, size_t size)
+{
+ stack_crawl_state_t state;
+ state.count = size;
+ state.ignore = ignore;
+ state.addrs = addrs;
+ _Unwind_Backtrace(trace_function, (void*)&state);
+ return size - state.count;
+}
+
+/*****************************************************************************/
+
+static
+const char *lookup_symbol(const void* addr, uint32_t *offset, char* name, size_t bufSize)
+{
+#if HAVE_DLADDR
+ Dl_info info;
+ if (dladdr(addr, &info)) {
+ *offset = (uint32_t)info.dli_saddr;
+ return info.dli_sname;
+ }
+#endif
+ return NULL;
+}
+
+static
+int32_t linux_gcc_demangler(const char *mangled_name, char *unmangled_name, size_t buffersize)
+{
+ size_t out_len = 0;
+#if HAVE_CXXABI
+ int status = 0;
+ char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status);
+ if (status == 0) {
+ // OK
+ if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len);
+ else out_len = 0;
+ free(demangled);
+ } else {
+ out_len = 0;
+ }
+#endif
+ return out_len;
+}
+
+/*****************************************************************************/
+
+class MapInfo {
+ struct mapinfo {
+ struct mapinfo *next;
+ unsigned start;
+ unsigned end;
+ char name[];
+ };
+
+ const char *map_to_name(unsigned pc, const char* def) {
+ mapinfo* mi = getMapInfoList();
+ while(mi) {
+ if ((pc >= mi->start) && (pc < mi->end))
+ return mi->name;
+ mi = mi->next;
+ }
+ return def;
+ }
+
+ mapinfo *parse_maps_line(char *line) {
+ mapinfo *mi;
+ int len = strlen(line);
+ if (len < 1) return 0;
+ line[--len] = 0;
+ if (len < 50) return 0;
+ if (line[20] != 'x') return 0;
+ mi = (mapinfo*)malloc(sizeof(mapinfo) + (len - 47));
+ if (mi == 0) return 0;
+ mi->start = strtoul(line, 0, 16);
+ mi->end = strtoul(line + 9, 0, 16);
+ mi->next = 0;
+ strcpy(mi->name, line + 49);
+ return mi;
+ }
+
+ mapinfo* getMapInfoList() {
+ Mutex::Autolock _l(mLock);
+ if (milist == 0) {
+ char data[1024];
+ FILE *fp;
+ sprintf(data, "/proc/%d/maps", getpid());
+ fp = fopen(data, "r");
+ if (fp) {
+ while(fgets(data, 1024, fp)) {
+ mapinfo *mi = parse_maps_line(data);
+ if(mi) {
+ mi->next = milist;
+ milist = mi;
+ }
+ }
+ fclose(fp);
+ }
+ }
+ return milist;
+ }
+ mapinfo* milist;
+ Mutex mLock;
+ static MapInfo sMapInfo;
+
+public:
+ MapInfo()
+ : milist(0) {
+ }
+
+ ~MapInfo() {
+ while (milist) {
+ mapinfo *next = milist->next;
+ free(milist);
+ milist = next;
+ }
+ }
+
+ static const char *mapAddressToName(const void* pc, const char* def) {
+ return sMapInfo.map_to_name((unsigned)pc, def);
+ }
+
+};
+
+/*****************************************************************************/
+
+MapInfo MapInfo::sMapInfo;
+
+/*****************************************************************************/
+
+CallStack::CallStack()
+ : mCount(0)
+{
+}
+
+CallStack::CallStack(const CallStack& rhs)
+ : mCount(rhs.mCount)
+{
+ if (mCount) {
+ memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
+ }
+}
+
+CallStack::~CallStack()
+{
+}
+
+CallStack& CallStack::operator = (const CallStack& rhs)
+{
+ mCount = rhs.mCount;
+ if (mCount) {
+ memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
+ }
+ return *this;
+}
+
+bool CallStack::operator == (const CallStack& rhs) const {
+ if (mCount != rhs.mCount)
+ return false;
+ return !mCount || (memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) == 0);
+}
+
+bool CallStack::operator != (const CallStack& rhs) const {
+ return !operator == (rhs);
+}
+
+bool CallStack::operator < (const CallStack& rhs) const {
+ if (mCount != rhs.mCount)
+ return mCount < rhs.mCount;
+ return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) < 0;
+}
+
+bool CallStack::operator >= (const CallStack& rhs) const {
+ return !operator < (rhs);
+}
+
+bool CallStack::operator > (const CallStack& rhs) const {
+ if (mCount != rhs.mCount)
+ return mCount > rhs.mCount;
+ return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) > 0;
+}
+
+bool CallStack::operator <= (const CallStack& rhs) const {
+ return !operator > (rhs);
+}
+
+const void* CallStack::operator [] (int index) const {
+ if (index >= int(mCount))
+ return 0;
+ return mStack[index];
+}
+
+
+void CallStack::clear()
+{
+ mCount = 0;
+}
+
+void CallStack::update(int32_t ignoreDepth, int32_t maxDepth)
+{
+ if (maxDepth > MAX_DEPTH)
+ maxDepth = MAX_DEPTH;
+ mCount = backtrace(mStack, ignoreDepth, maxDepth);
+}
+
+// Return the stack frame name on the designated level
+String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const
+{
+ String8 res;
+ char namebuf[1024];
+ char tmp[256];
+ char tmp1[32];
+ char tmp2[32];
+ uint32_t offs;
+
+ const void* ip = mStack[level];
+ if (!ip) return res;
+
+ if (prefix) res.append(prefix);
+ snprintf(tmp1, 32, "#%02d ", level);
+ res.append(tmp1);
+
+ const char* name = lookup_symbol(ip, &offs, namebuf, sizeof(namebuf));
+ if (name) {
+ if (linux_gcc_demangler(name, tmp, 256) != 0)
+ name = tmp;
+ snprintf(tmp1, 32, "0x%08x: <", (size_t)ip);
+ snprintf(tmp2, 32, ">+0x%08x", offs);
+ res.append(tmp1);
+ res.append(name);
+ res.append(tmp2);
+ } else {
+ name = MapInfo::mapAddressToName(ip, "<unknown>");
+ snprintf(tmp, 256, "pc %08x %s", (size_t)ip, name);
+ res.append(tmp);
+ }
+ res.append("\n");
+
+ return res;
+}
+
+// Dump a stack trace to the log
+void CallStack::dump(const char* prefix) const
+{
+ /*
+ * Sending a single long log may be truncated since the stack levels can
+ * get very deep. So we request function names of each frame individually.
+ */
+ for (int i=0; i<int(mCount); i++) {
+ LOGD("%s", toStringSingleLevel(prefix, i).string());
+ }
+}
+
+// Return a string (possibly very long) containing the complete stack trace
+String8 CallStack::toString(const char* prefix) const
+{
+ String8 res;
+
+ for (int i=0; i<int(mCount); i++) {
+ res.append(toStringSingleLevel(prefix, i).string());
+ }
+
+ return res;
+}
+
+/*****************************************************************************/
+
+}; // namespace android
diff --git a/libs/utils/Debug.cpp b/libs/utils/Debug.cpp
new file mode 100644
index 0000000..f7988ec
--- /dev/null
+++ b/libs/utils/Debug.cpp
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#include <utils/Debug.h>
+
+#include <utils/misc.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------
+
+static const char indentStr[] =
+" "
+" ";
+
+const char* stringForIndent(int32_t indentLevel)
+{
+ ssize_t off = sizeof(indentStr)-1-(indentLevel*2);
+ return indentStr + (off < 0 ? 0 : off);
+}
+
+// ---------------------------------------------------------------------
+
+static void defaultPrintFunc(void* cookie, const char* txt)
+{
+ printf("%s", txt);
+}
+
+// ---------------------------------------------------------------------
+
+static inline int isident(int c)
+{
+ return isalnum(c) || c == '_';
+}
+
+static inline bool isasciitype(char c)
+{
+ if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true;
+ return false;
+}
+
+static inline char makehexdigit(uint32_t val)
+{
+ return "0123456789abcdef"[val&0xF];
+}
+
+static char* appendhexnum(uint32_t val, char* out)
+{
+ for( int32_t i=28; i>=0; i-=4 ) {
+ *out++ = makehexdigit( val>>i );
+ }
+ *out = 0;
+ return out;
+}
+
+static inline char makeupperhexdigit(uint32_t val)
+{
+ return "0123456789ABCDEF"[val&0xF];
+}
+
+static char* appendupperhexnum(uint32_t val, char* out)
+{
+ for( int32_t i=28; i>=0; i-=4 ) {
+ *out++ = makeupperhexdigit( val>>i );
+ }
+ *out = 0;
+ return out;
+}
+
+static char* appendcharornum(char c, char* out, bool skipzero = true)
+{
+ if (skipzero && c == 0) return out;
+
+ if (isasciitype(c)) {
+ *out++ = c;
+ return out;
+ }
+
+ *out++ = '\\';
+ *out++ = 'x';
+ *out++ = makehexdigit(c>>4);
+ *out++ = makehexdigit(c);
+ return out;
+}
+
+static char* typetostring(uint32_t type, char* out,
+ bool fullContext = true,
+ bool strict = false)
+{
+ char* pos = out;
+ char c[4];
+ c[0] = (char)((type>>24)&0xFF);
+ c[1] = (char)((type>>16)&0xFF);
+ c[2] = (char)((type>>8)&0xFF);
+ c[3] = (char)(type&0xFF);
+ bool valid;
+ if( !strict ) {
+ // now even less strict!
+ // valid = isasciitype(c[3]);
+ valid = true;
+ int32_t i = 0;
+ bool zero = true;
+ while (valid && i<3) {
+ if (c[i] == 0) {
+ if (!zero) valid = false;
+ } else {
+ zero = false;
+ //if (!isasciitype(c[i])) valid = false;
+ }
+ i++;
+ }
+ // if all zeros, not a valid type code.
+ if (zero) valid = false;
+ } else {
+ valid = isident(c[3]) ? true : false;
+ int32_t i = 0;
+ bool zero = true;
+ while (valid && i<3) {
+ if (c[i] == 0) {
+ if (!zero) valid = false;
+ } else {
+ zero = false;
+ if (!isident(c[i])) valid = false;
+ }
+ i++;
+ }
+ }
+ if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) {
+ if( fullContext ) *pos++ = '\'';
+ pos = appendcharornum(c[0], pos);
+ pos = appendcharornum(c[1], pos);
+ pos = appendcharornum(c[2], pos);
+ pos = appendcharornum(c[3], pos);
+ if( fullContext ) *pos++ = '\'';
+ *pos = 0;
+ return pos;
+ }
+
+ if( fullContext ) {
+ *pos++ = '0';
+ *pos++ = 'x';
+ }
+ return appendhexnum(type, pos);
+}
+
+void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie)
+{
+ char buffer[32];
+ char* end = typetostring(typeCode, buffer);
+ *end = 0;
+ func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer);
+}
+
+void printHexData(int32_t indent, const void *buf, size_t length,
+ size_t bytesPerLine, int32_t singleLineBytesCutoff,
+ size_t alignment, bool cStyle,
+ debugPrintFunc func, void* cookie)
+{
+ if (alignment == 0) {
+ if (bytesPerLine >= 16) alignment = 4;
+ else if (bytesPerLine >= 8) alignment = 2;
+ else alignment = 1;
+ }
+ if (func == NULL) func = defaultPrintFunc;
+
+ size_t offset;
+
+ unsigned char *pos = (unsigned char *)buf;
+
+ if (pos == NULL) {
+ if (singleLineBytesCutoff < 0) func(cookie, "\n");
+ func(cookie, "(NULL)");
+ return;
+ }
+
+ if (length == 0) {
+ if (singleLineBytesCutoff < 0) func(cookie, "\n");
+ func(cookie, "(empty)");
+ return;
+ }
+
+ if ((int32_t)length < 0) {
+ if (singleLineBytesCutoff < 0) func(cookie, "\n");
+ char buf[64];
+ sprintf(buf, "(bad length: %d)", length);
+ func(cookie, buf);
+ return;
+ }
+
+ char buffer[256];
+ static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1);
+
+ if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine;
+
+ const bool oneLine = (int32_t)length <= singleLineBytesCutoff;
+ bool newLine = false;
+ if (cStyle) {
+ indent++;
+ func(cookie, "{\n");
+ newLine = true;
+ } else if (!oneLine) {
+ func(cookie, "\n");
+ newLine = true;
+ }
+
+ for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
+ long remain = length;
+
+ char* c = buffer;
+ if (!oneLine && !cStyle) {
+ sprintf(c, "0x%08x: ", (int)offset);
+ c += 12;
+ }
+
+ size_t index;
+ size_t word;
+
+ for (word = 0; word < bytesPerLine; ) {
+
+#ifdef HAVE_LITTLE_ENDIAN
+ const size_t startIndex = word+(alignment-(alignment?1:0));
+ const ssize_t dir = -1;
+#else
+ const size_t startIndex = word;
+ const ssize_t dir = 1;
+#endif
+
+ for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) {
+
+ if (!cStyle) {
+ if (index == 0 && word > 0 && alignment > 0) {
+ *c++ = ' ';
+ }
+
+ if (remain-- > 0) {
+ const unsigned char val = *(pos+startIndex+(index*dir));
+ *c++ = makehexdigit(val>>4);
+ *c++ = makehexdigit(val);
+ } else if (!oneLine) {
+ *c++ = ' ';
+ *c++ = ' ';
+ }
+ } else {
+ if (remain > 0) {
+ if (index == 0 && word > 0) {
+ *c++ = ',';
+ *c++ = ' ';
+ }
+ if (index == 0) {
+ *c++ = '0';
+ *c++ = 'x';
+ }
+ const unsigned char val = *(pos+startIndex+(index*dir));
+ *c++ = makehexdigit(val>>4);
+ *c++ = makehexdigit(val);
+ remain--;
+ }
+ }
+ }
+
+ word += index;
+ }
+
+ if (!cStyle) {
+ remain = length;
+ *c++ = ' ';
+ *c++ = '\'';
+ for (index = 0; index < bytesPerLine; index++) {
+
+ if (remain-- > 0) {
+ const unsigned char val = pos[index];
+ *c++ = (val >= ' ' && val < 127) ? val : '.';
+ } else if (!oneLine) {
+ *c++ = ' ';
+ }
+ }
+
+ *c++ = '\'';
+ if (length > bytesPerLine) *c++ = '\n';
+ } else {
+ if (remain > 0) *c++ = ',';
+ *c++ = '\n';
+ }
+
+ if (newLine && indent) func(cookie, stringForIndent(indent));
+ *c = 0;
+ func(cookie, buffer);
+ newLine = true;
+
+ if (length <= bytesPerLine) break;
+ length -= bytesPerLine;
+ }
+
+ if (cStyle) {
+ if (indent > 0) func(cookie, stringForIndent(indent-1));
+ func(cookie, "};");
+ }
+}
+
+}; // namespace android
+
diff --git a/libs/utils/FileMap.cpp b/libs/utils/FileMap.cpp
new file mode 100644
index 0000000..e1ba9b2
--- /dev/null
+++ b/libs/utils/FileMap.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Shared file mapping class.
+//
+
+#define LOG_TAG "filemap"
+
+#include <utils/FileMap.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_POSIX_FILEMAP
+#include <sys/mman.h>
+#endif
+
+#include <string.h>
+#include <memory.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*static*/ long FileMap::mPageSize = -1;
+
+
+/*
+ * Constructor. Create an empty object.
+ */
+FileMap::FileMap(void)
+ : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
+ mDataPtr(NULL), mDataLength(0)
+{
+}
+
+/*
+ * Destructor.
+ */
+FileMap::~FileMap(void)
+{
+ assert(mRefCount == 0);
+
+ //printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength);
+
+ mRefCount = -100; // help catch double-free
+ if (mFileName != NULL) {
+ free(mFileName);
+ }
+#ifdef HAVE_POSIX_FILEMAP
+ if (munmap(mBasePtr, mBaseLength) != 0) {
+ LOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength);
+ }
+#endif
+#ifdef HAVE_WIN32_FILEMAP
+ if ( UnmapViewOfFile(mBasePtr) == 0) {
+ LOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr,
+ GetLastError() );
+ }
+ CloseHandle(mFileMapping);
+ CloseHandle(mFileHandle);
+#endif
+}
+
+
+/*
+ * Create a new mapping on an open file.
+ *
+ * Closing the file descriptor does not unmap the pages, so we don't
+ * claim ownership of the fd.
+ *
+ * Returns "false" on failure.
+ */
+bool FileMap::create(const char* origFileName, int fd, off_t offset, size_t length, bool readOnly)
+{
+#ifdef HAVE_WIN32_FILEMAP
+ int adjust;
+ off_t adjOffset;
+ size_t adjLength;
+
+ if (mPageSize == -1) {
+ SYSTEM_INFO si;
+
+ GetSystemInfo( &si );
+ mPageSize = si.dwAllocationGranularity;
+ }
+
+ DWORD protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
+
+ mFileHandle = (HANDLE) _get_osfhandle(fd);
+ mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
+ if (mFileMapping == NULL) {
+ LOGE("CreateFileMapping(%p, %lx) failed with error %ld\n",
+ mFileHandle, protect, GetLastError() );
+ return false;
+ }
+
+ adjust = offset % mPageSize;
+ adjOffset = offset - adjust;
+ adjLength = length + adjust;
+
+ mBasePtr = MapViewOfFile( mFileMapping,
+ readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
+ 0,
+ (DWORD)(adjOffset),
+ adjLength );
+ if (mBasePtr == NULL) {
+ LOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n",
+ adjOffset, adjLength, GetLastError() );
+ CloseHandle(mFileMapping);
+ mFileMapping = INVALID_HANDLE_VALUE;
+ return false;
+ }
+#endif
+#ifdef HAVE_POSIX_FILEMAP
+ int prot, flags, adjust;
+ off_t adjOffset;
+ size_t adjLength;
+
+ void* ptr;
+
+ assert(mRefCount == 1);
+ assert(fd >= 0);
+ assert(offset >= 0);
+ assert(length > 0);
+
+ /* init on first use */
+ if (mPageSize == -1) {
+#if NOT_USING_KLIBC
+ mPageSize = sysconf(_SC_PAGESIZE);
+ if (mPageSize == -1) {
+ LOGE("could not get _SC_PAGESIZE\n");
+ return false;
+ }
+#else
+ /* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */
+ mPageSize = 4096;
+#endif
+ }
+
+ adjust = offset % mPageSize;
+try_again:
+ adjOffset = offset - adjust;
+ adjLength = length + adjust;
+
+ flags = MAP_SHARED;
+ prot = PROT_READ;
+ if (!readOnly)
+ prot |= PROT_WRITE;
+
+ ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
+ if (ptr == MAP_FAILED) {
+ // Cygwin does not seem to like file mapping files from an offset.
+ // So if we fail, try again with offset zero
+ if (adjOffset > 0) {
+ adjust = offset;
+ goto try_again;
+ }
+
+ LOGE("mmap(%ld,%ld) failed: %s\n",
+ (long) adjOffset, (long) adjLength, strerror(errno));
+ return false;
+ }
+ mBasePtr = ptr;
+#endif /* HAVE_POSIX_FILEMAP */
+
+ mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
+ mBaseLength = adjLength;
+ mDataOffset = offset;
+ mDataPtr = (char*) mBasePtr + adjust;
+ mDataLength = length;
+
+ assert(mBasePtr != NULL);
+
+ LOGV("MAP: base %p/%d data %p/%d\n",
+ mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength);
+
+ return true;
+}
+
+/*
+ * Provide guidance to the system.
+ */
+int FileMap::advise(MapAdvice advice)
+{
+#if HAVE_MADVISE
+ int cc, sysAdvice;
+
+ switch (advice) {
+ case NORMAL: sysAdvice = MADV_NORMAL; break;
+ case RANDOM: sysAdvice = MADV_RANDOM; break;
+ case SEQUENTIAL: sysAdvice = MADV_SEQUENTIAL; break;
+ case WILLNEED: sysAdvice = MADV_WILLNEED; break;
+ case DONTNEED: sysAdvice = MADV_DONTNEED; break;
+ default:
+ assert(false);
+ return -1;
+ }
+
+ cc = madvise(mBasePtr, mBaseLength, sysAdvice);
+ if (cc != 0)
+ LOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
+ return cc;
+#else
+ return -1;
+#endif // HAVE_MADVISE
+}
diff --git a/libs/utils/IDataConnection.cpp b/libs/utils/IDataConnection.cpp
new file mode 100644
index 0000000..c6d49aa
--- /dev/null
+++ b/libs/utils/IDataConnection.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <utils/IDataConnection.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+enum
+{
+ CONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ DISCONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1
+};
+
+class BpDataConnection : public BpInterface<IDataConnection>
+{
+public:
+ BpDataConnection::BpDataConnection(const sp<IBinder>& impl)
+ : BpInterface<IDataConnection>(impl)
+ {
+ }
+
+ virtual void connect()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDataConnection::descriptor());
+ remote()->transact(CONNECT_TRANSACTION, data, &reply);
+ }
+
+ virtual void disconnect()
+ {
+ Parcel data, reply;
+ remote()->transact(DISCONNECT_TRANSACTION, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(DataConnection, "android.utils.IDataConnection");
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnDataConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code)
+ {
+ case CONNECT_TRANSACTION:
+ {
+ CHECK_INTERFACE(IDataConnection, data, reply);
+ connect();
+ return NO_ERROR;
+ }
+
+ case DISCONNECT_TRANSACTION:
+ {
+ CHECK_INTERFACE(IDataConnection, data, reply);
+ disconnect();
+ return NO_ERROR;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/utils/IInterface.cpp b/libs/utils/IInterface.cpp
new file mode 100644
index 0000000..6ea8178
--- /dev/null
+++ b/libs/utils/IInterface.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#include <utils/IInterface.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+sp<IBinder> IInterface::asBinder()
+{
+ return this ? onAsBinder() : NULL;
+}
+
+sp<const IBinder> IInterface::asBinder() const
+{
+ return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/utils/IMemory.cpp b/libs/utils/IMemory.cpp
new file mode 100644
index 0000000..429bc2b
--- /dev/null
+++ b/libs/utils/IMemory.cpp
@@ -0,0 +1,486 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IMemory"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <utils/IMemory.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <utils/Parcel.h>
+#include <utils/CallStack.h>
+
+#define VERBOSE 0
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class HeapCache : public IBinder::DeathRecipient
+{
+public:
+ HeapCache();
+ virtual ~HeapCache();
+
+ virtual void binderDied(const wp<IBinder>& who);
+
+ sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);
+ void pin_heap(const sp<IBinder>& binder);
+ void free_heap(const sp<IBinder>& binder);
+ sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
+ void dump_heaps();
+
+private:
+ // For IMemory.cpp
+ struct heap_info_t {
+ sp<IMemoryHeap> heap;
+ int32_t count;
+ };
+
+ void free_heap(const wp<IBinder>& binder);
+
+ Mutex mHeapCacheLock;
+ KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
+};
+
+static sp<HeapCache> gHeapCache = new HeapCache();
+
+/******************************************************************************/
+
+enum {
+ HEAP_ID = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMemoryHeap : public BpInterface<IMemoryHeap>
+{
+public:
+ BpMemoryHeap(const sp<IBinder>& impl);
+ virtual ~BpMemoryHeap();
+
+ virtual int getHeapID() const;
+ virtual void* getBase() const;
+ virtual size_t getSize() const;
+ virtual uint32_t getFlags() const;
+
+private:
+ friend class IMemory;
+ friend class HeapCache;
+
+ // for debugging in this module
+ static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
+ return gHeapCache->find_heap(binder);
+ }
+ static inline void free_heap(const sp<IBinder>& binder) {
+ gHeapCache->free_heap(binder);
+ }
+ static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) {
+ return gHeapCache->get_heap(binder);
+ }
+ static inline void dump_heaps() {
+ gHeapCache->dump_heaps();
+ }
+ void inline pin_heap() const {
+ gHeapCache->pin_heap(const_cast<BpMemoryHeap*>(this)->asBinder());
+ }
+
+ void assertMapped() const;
+ void assertReallyMapped() const;
+ void pinHeap() const;
+
+ mutable volatile int32_t mHeapId;
+ mutable void* mBase;
+ mutable size_t mSize;
+ mutable uint32_t mFlags;
+ mutable bool mRealHeap;
+ mutable Mutex mLock;
+};
+
+// ----------------------------------------------------------------------------
+
+enum {
+ GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMemory : public BpInterface<IMemory>
+{
+public:
+ BpMemory(const sp<IBinder>& impl);
+ virtual ~BpMemory();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
+
+private:
+ mutable sp<IMemoryHeap> mHeap;
+ mutable ssize_t mOffset;
+ mutable size_t mSize;
+};
+
+/******************************************************************************/
+
+void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const
+{
+ sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder);
+ void* const base = realHeap->base();
+ if (base == MAP_FAILED)
+ return 0;
+ return static_cast<char*>(base) + offset;
+}
+
+void* IMemory::pointer() const {
+ ssize_t offset;
+ sp<IMemoryHeap> heap = getMemory(&offset);
+ void* const base = heap!=0 ? heap->base() : MAP_FAILED;
+ if (base == MAP_FAILED)
+ return 0;
+ return static_cast<char*>(base) + offset;
+}
+
+size_t IMemory::size() const {
+ size_t size;
+ getMemory(NULL, &size);
+ return size;
+}
+
+ssize_t IMemory::offset() const {
+ ssize_t offset;
+ getMemory(&offset);
+ return offset;
+}
+
+/******************************************************************************/
+
+BpMemory::BpMemory(const sp<IBinder>& impl)
+ : BpInterface<IMemory>(impl), mOffset(0), mSize(0)
+{
+}
+
+BpMemory::~BpMemory()
+{
+}
+
+sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
+{
+ if (mHeap == 0) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
+ if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
+ sp<IBinder> heap = reply.readStrongBinder();
+ ssize_t o = reply.readInt32();
+ size_t s = reply.readInt32();
+ if (heap != 0) {
+ mHeap = interface_cast<IMemoryHeap>(heap);
+ if (mHeap != 0) {
+ mOffset = o;
+ mSize = s;
+ }
+ }
+ }
+ }
+ if (offset) *offset = mOffset;
+ if (size) *size = mSize;
+ return mHeap;
+}
+
+// ---------------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnMemory::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case GET_MEMORY: {
+ CHECK_INTERFACE(IMemory, data, reply);
+ ssize_t offset;
+ size_t size;
+ reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );
+ reply->writeInt32(offset);
+ reply->writeInt32(size);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+
+/******************************************************************************/
+
+BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
+ : BpInterface<IMemoryHeap>(impl),
+ mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
+{
+}
+
+BpMemoryHeap::~BpMemoryHeap() {
+ if (mHeapId != -1) {
+ close(mHeapId);
+ if (mRealHeap) {
+ // by construction we're the last one
+ if (mBase != MAP_FAILED) {
+ sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
+
+ if (VERBOSE) {
+ LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d",
+ binder.get(), this, mSize, mHeapId);
+ CallStack stack;
+ stack.update();
+ stack.dump("callstack");
+ }
+
+ munmap(mBase, mSize);
+ }
+ } else {
+ // remove from list only if it was mapped before
+ sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
+ free_heap(binder);
+ }
+ }
+}
+
+void BpMemoryHeap::assertMapped() const
+{
+ if (mHeapId == -1) {
+ sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());
+ sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
+ heap->assertReallyMapped();
+ if (heap->mBase != MAP_FAILED) {
+ Mutex::Autolock _l(mLock);
+ if (mHeapId == -1) {
+ mBase = heap->mBase;
+ mSize = heap->mSize;
+ android_atomic_write( dup( heap->mHeapId ), &mHeapId );
+ }
+ } else {
+ // something went wrong
+ free_heap(binder);
+ }
+ }
+}
+
+void BpMemoryHeap::assertReallyMapped() const
+{
+ if (mHeapId == -1) {
+
+ // remote call without mLock held, worse case scenario, we end up
+ // calling transact() from multiple threads, but that's not a problem,
+ // only mmap below must be in the critical section.
+
+ Parcel data, reply;
+ data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
+ status_t err = remote()->transact(HEAP_ID, data, &reply);
+ int parcel_fd = reply.readFileDescriptor();
+ ssize_t size = reply.readInt32();
+ uint32_t flags = reply.readInt32();
+
+ LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%d, err=%d (%s)",
+ asBinder().get(), parcel_fd, size, err, strerror(-err));
+
+ int fd = dup( parcel_fd );
+ LOGE_IF(fd==-1, "cannot dup fd=%d, size=%d, err=%d (%s)",
+ parcel_fd, size, err, strerror(errno));
+
+ int access = PROT_READ;
+ if (!(flags & READ_ONLY)) {
+ access |= PROT_WRITE;
+ }
+
+ Mutex::Autolock _l(mLock);
+ if (mHeapId == -1) {
+ mRealHeap = true;
+ mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
+ if (mBase == MAP_FAILED) {
+ LOGE("cannot map BpMemoryHeap (binder=%p), size=%d, fd=%d (%s)",
+ asBinder().get(), size, fd, strerror(errno));
+ close(fd);
+ } else {
+ if (flags & MAP_ONCE) {
+ //LOGD("pinning heap (binder=%p, size=%d, fd=%d",
+ // asBinder().get(), size, fd);
+ pin_heap();
+ }
+ mSize = size;
+ mFlags = flags;
+ android_atomic_write(fd, &mHeapId);
+ }
+ }
+ }
+}
+
+int BpMemoryHeap::getHeapID() const {
+ assertMapped();
+ return mHeapId;
+}
+
+void* BpMemoryHeap::getBase() const {
+ assertMapped();
+ return mBase;
+}
+
+size_t BpMemoryHeap::getSize() const {
+ assertMapped();
+ return mSize;
+}
+
+uint32_t BpMemoryHeap::getFlags() const {
+ assertMapped();
+ return mFlags;
+}
+
+// ---------------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
+
+status_t BnMemoryHeap::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case HEAP_ID: {
+ CHECK_INTERFACE(IMemoryHeap, data, reply);
+ reply->writeFileDescriptor(getHeapID());
+ reply->writeInt32(getSize());
+ reply->writeInt32(getFlags());
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+/*****************************************************************************/
+
+HeapCache::HeapCache()
+ : DeathRecipient()
+{
+}
+
+HeapCache::~HeapCache()
+{
+}
+
+void HeapCache::binderDied(const wp<IBinder>& binder)
+{
+ //LOGD("binderDied binder=%p", binder.unsafe_get());
+ free_heap(binder);
+}
+
+sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
+{
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) {
+ heap_info_t& info = mHeapCache.editValueAt(i);
+ LOGD_IF(VERBOSE,
+ "found binder=%p, heap=%p, size=%d, fd=%d, count=%d",
+ binder.get(), info.heap.get(),
+ static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
+ static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+ info.count);
+ android_atomic_inc(&info.count);
+ return info.heap;
+ } else {
+ heap_info_t info;
+ info.heap = interface_cast<IMemoryHeap>(binder);
+ info.count = 1;
+ //LOGD("adding binder=%p, heap=%p, count=%d",
+ // binder.get(), info.heap.get(), info.count);
+ mHeapCache.add(binder, info);
+ return info.heap;
+ }
+}
+
+void HeapCache::pin_heap(const sp<IBinder>& binder)
+{
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) {
+ heap_info_t& info(mHeapCache.editValueAt(i));
+ android_atomic_inc(&info.count);
+ binder->linkToDeath(this);
+ } else {
+ LOGE("pin_heap binder=%p not found!!!", binder.get());
+ }
+}
+
+void HeapCache::free_heap(const sp<IBinder>& binder) {
+ free_heap( wp<IBinder>(binder) );
+}
+
+void HeapCache::free_heap(const wp<IBinder>& binder)
+{
+ sp<IMemoryHeap> rel;
+ {
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) {
+ heap_info_t& info(mHeapCache.editValueAt(i));
+ int32_t c = android_atomic_dec(&info.count);
+ if (c == 1) {
+ LOGD_IF(VERBOSE,
+ "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d",
+ binder.unsafe_get(), info.heap.get(),
+ static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
+ static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+ info.count);
+ rel = mHeapCache.valueAt(i).heap;
+ mHeapCache.removeItemsAt(i);
+ }
+ } else {
+ LOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
+ }
+ }
+}
+
+sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder)
+{
+ sp<IMemoryHeap> realHeap;
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) realHeap = mHeapCache.valueAt(i).heap;
+ else realHeap = interface_cast<IMemoryHeap>(binder);
+ return realHeap;
+}
+
+void HeapCache::dump_heaps()
+{
+ Mutex::Autolock _l(mHeapCacheLock);
+ int c = mHeapCache.size();
+ for (int i=0 ; i<c ; i++) {
+ const heap_info_t& info = mHeapCache.valueAt(i);
+ BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
+ LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)",
+ mHeapCache.keyAt(i).unsafe_get(),
+ info.heap.get(), info.count,
+ h->mHeapId, h->mBase, h->mSize);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/utils/IPCThreadState.cpp b/libs/utils/IPCThreadState.cpp
new file mode 100644
index 0000000..ca49d9a
--- /dev/null
+++ b/libs/utils/IPCThreadState.cpp
@@ -0,0 +1,1007 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#include <utils/IPCThreadState.h>
+
+#include <utils/Binder.h>
+#include <utils/BpBinder.h>
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/TextOutput.h>
+#include <utils/threads.h>
+
+#include <private/utils/binder_module.h>
+#include <private/utils/Static.h>
+
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_WIN32_THREADS
+#include <windows.h>
+#endif
+
+
+#if LOG_NDEBUG
+
+#define IF_LOG_TRANSACTIONS() if (false)
+#define IF_LOG_COMMANDS() if (false)
+#define LOG_REMOTEREFS(...)
+#define IF_LOG_REMOTEREFS() if (false)
+#define LOG_THREADPOOL(...)
+#define LOG_ONEWAY(...)
+
+#else
+
+#define IF_LOG_TRANSACTIONS() IF_LOG(LOG_VERBOSE, "transact")
+#define IF_LOG_COMMANDS() IF_LOG(LOG_VERBOSE, "ipc")
+#define LOG_REMOTEREFS(...) LOG(LOG_DEBUG, "remoterefs", __VA_ARGS__)
+#define IF_LOG_REMOTEREFS() IF_LOG(LOG_DEBUG, "remoterefs")
+#define LOG_THREADPOOL(...) LOG(LOG_DEBUG, "threadpool", __VA_ARGS__)
+#define LOG_ONEWAY(...) LOG(LOG_DEBUG, "ipc", __VA_ARGS__)
+
+#endif
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+static const char* getReturnString(size_t idx);
+static const char* getCommandString(size_t idx);
+static const void* printReturnCommand(TextOutput& out, const void* _cmd);
+static const void* printCommand(TextOutput& out, const void* _cmd);
+
+// This will result in a missing symbol failure if the IF_LOG_COMMANDS()
+// conditionals don't get stripped... but that is probably what we want.
+#if !LOG_NDEBUG
+static const char *kReturnStrings[] = {
+#if 1 /* TODO: error update strings */
+ "unknown",
+#else
+ "BR_OK",
+ "BR_TIMEOUT",
+ "BR_WAKEUP",
+ "BR_TRANSACTION",
+ "BR_REPLY",
+ "BR_ACQUIRE_RESULT",
+ "BR_DEAD_REPLY",
+ "BR_TRANSACTION_COMPLETE",
+ "BR_INCREFS",
+ "BR_ACQUIRE",
+ "BR_RELEASE",
+ "BR_DECREFS",
+ "BR_ATTEMPT_ACQUIRE",
+ "BR_EVENT_OCCURRED",
+ "BR_NOOP",
+ "BR_SPAWN_LOOPER",
+ "BR_FINISHED",
+ "BR_DEAD_BINDER",
+ "BR_CLEAR_DEATH_NOTIFICATION_DONE"
+#endif
+};
+
+static const char *kCommandStrings[] = {
+#if 1 /* TODO: error update strings */
+ "unknown",
+#else
+ "BC_NOOP",
+ "BC_TRANSACTION",
+ "BC_REPLY",
+ "BC_ACQUIRE_RESULT",
+ "BC_FREE_BUFFER",
+ "BC_TRANSACTION_COMPLETE",
+ "BC_INCREFS",
+ "BC_ACQUIRE",
+ "BC_RELEASE",
+ "BC_DECREFS",
+ "BC_INCREFS_DONE",
+ "BC_ACQUIRE_DONE",
+ "BC_ATTEMPT_ACQUIRE",
+ "BC_RETRIEVE_ROOT_OBJECT",
+ "BC_SET_THREAD_ENTRY",
+ "BC_REGISTER_LOOPER",
+ "BC_ENTER_LOOPER",
+ "BC_EXIT_LOOPER",
+ "BC_SYNC",
+ "BC_STOP_PROCESS",
+ "BC_STOP_SELF",
+ "BC_REQUEST_DEATH_NOTIFICATION",
+ "BC_CLEAR_DEATH_NOTIFICATION",
+ "BC_DEAD_BINDER_DONE"
+#endif
+};
+
+static const char* getReturnString(size_t idx)
+{
+ if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0]))
+ return kReturnStrings[idx];
+ else
+ return "unknown";
+}
+
+static const char* getCommandString(size_t idx)
+{
+ if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[0]))
+ return kCommandStrings[idx];
+ else
+ return "unknown";
+}
+
+static const void* printBinderTransactionData(TextOutput& out, const void* data)
+{
+ const binder_transaction_data* btd =
+ (const binder_transaction_data*)data;
+ out << "target=" << btd->target.ptr << " (cookie " << btd->cookie << ")" << endl
+ << "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl
+ << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
+ << " bytes)" << endl
+ << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
+ << " bytes)" << endl;
+ return btd+1;
+}
+
+static const void* printReturnCommand(TextOutput& out, const void* _cmd)
+{
+ static const int32_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
+
+ const int32_t* cmd = (const int32_t*)_cmd;
+ int32_t code = *cmd++;
+ if (code == BR_ERROR) {
+ out << "BR_ERROR: " << (void*)(*cmd++) << endl;
+ return cmd;
+ } else if (code < 0 || code >= N) {
+ out << "Unknown reply: " << code << endl;
+ return cmd;
+ }
+
+ out << kReturnStrings[code];
+ switch (code) {
+ case BR_TRANSACTION:
+ case BR_REPLY: {
+ out << ": " << indent;
+ cmd = (const int32_t *)printBinderTransactionData(out, cmd);
+ out << dedent;
+ } break;
+
+ case BR_ACQUIRE_RESULT: {
+ const int32_t res = *cmd++;
+ out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
+ } break;
+
+ case BR_INCREFS:
+ case BR_ACQUIRE:
+ case BR_RELEASE:
+ case BR_DECREFS: {
+ const int32_t b = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
+ } break;
+
+ case BR_ATTEMPT_ACQUIRE: {
+ const int32_t p = *cmd++;
+ const int32_t b = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": target=" << (void*)b << " (cookie " << (void*)c
+ << "), pri=" << p;
+ } break;
+
+ case BR_DEAD_BINDER:
+ case BR_CLEAR_DEATH_NOTIFICATION_DONE: {
+ const int32_t c = *cmd++;
+ out << ": death cookie " << (void*)c;
+ } break;
+ }
+
+ out << endl;
+ return cmd;
+}
+
+static const void* printCommand(TextOutput& out, const void* _cmd)
+{
+ static const int32_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
+
+ const int32_t* cmd = (const int32_t*)_cmd;
+ int32_t code = *cmd++;
+ if (code < 0 || code >= N) {
+ out << "Unknown command: " << code << endl;
+ return cmd;
+ }
+
+ out << kCommandStrings[code];
+ switch (code) {
+ case BC_TRANSACTION:
+ case BC_REPLY: {
+ out << ": " << indent;
+ cmd = (const int32_t *)printBinderTransactionData(out, cmd);
+ out << dedent;
+ } break;
+
+ case BC_ACQUIRE_RESULT: {
+ const int32_t res = *cmd++;
+ out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
+ } break;
+
+ case BC_FREE_BUFFER: {
+ const int32_t buf = *cmd++;
+ out << ": buffer=" << (void*)buf;
+ } break;
+
+ case BC_INCREFS:
+ case BC_ACQUIRE:
+ case BC_RELEASE:
+ case BC_DECREFS: {
+ const int32_t d = *cmd++;
+ out << ": descriptor=" << (void*)d;
+ } break;
+
+ case BC_INCREFS_DONE:
+ case BC_ACQUIRE_DONE: {
+ const int32_t b = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
+ } break;
+
+ case BC_ATTEMPT_ACQUIRE: {
+ const int32_t p = *cmd++;
+ const int32_t d = *cmd++;
+ out << ": decriptor=" << (void*)d << ", pri=" << p;
+ } break;
+
+ case BC_REQUEST_DEATH_NOTIFICATION:
+ case BC_CLEAR_DEATH_NOTIFICATION: {
+ const int32_t h = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": handle=" << h << " (death cookie " << (void*)c << ")";
+ } break;
+
+ case BC_DEAD_BINDER_DONE: {
+ const int32_t c = *cmd++;
+ out << ": death cookie " << (void*)c;
+ } break;
+ }
+
+ out << endl;
+ return cmd;
+}
+#endif
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+static bool gShutdown = false;
+
+IPCThreadState* IPCThreadState::self()
+{
+ if (gHaveTLS) {
+restart:
+ const pthread_key_t k = gTLS;
+ IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
+ if (st) return st;
+ return new IPCThreadState;
+ }
+
+ if (gShutdown) return NULL;
+
+ pthread_mutex_lock(&gTLSMutex);
+ if (!gHaveTLS) {
+ if (pthread_key_create(&gTLS, threadDestructor) != 0) {
+ pthread_mutex_unlock(&gTLSMutex);
+ return NULL;
+ }
+ gHaveTLS = true;
+ }
+ pthread_mutex_unlock(&gTLSMutex);
+ goto restart;
+}
+
+void IPCThreadState::shutdown()
+{
+ gShutdown = true;
+
+ if (gHaveTLS) {
+ // XXX Need to wait for all thread pool threads to exit!
+ IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
+ if (st) {
+ delete st;
+ pthread_setspecific(gTLS, NULL);
+ }
+ gHaveTLS = false;
+ }
+}
+
+sp<ProcessState> IPCThreadState::process()
+{
+ return mProcess;
+}
+
+status_t IPCThreadState::clearLastError()
+{
+ const status_t err = mLastError;
+ mLastError = NO_ERROR;
+ return err;
+}
+
+int IPCThreadState::getCallingPid()
+{
+ return mCallingPid;
+}
+
+int IPCThreadState::getCallingUid()
+{
+ return mCallingUid;
+}
+
+int64_t IPCThreadState::clearCallingIdentity()
+{
+ int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
+ clearCaller();
+ return token;
+}
+
+void IPCThreadState::restoreCallingIdentity(int64_t token)
+{
+ mCallingUid = (int)(token>>32);
+ mCallingPid = (int)token;
+}
+
+void IPCThreadState::clearCaller()
+{
+ if (mProcess->supportsProcesses()) {
+ mCallingPid = getpid();
+ mCallingUid = getuid();
+ } else {
+ mCallingPid = -1;
+ mCallingUid = -1;
+ }
+}
+
+void IPCThreadState::flushCommands()
+{
+ if (mProcess->mDriverFD <= 0)
+ return;
+ talkWithDriver(false);
+}
+
+void IPCThreadState::joinThreadPool(bool isMain)
+{
+ LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
+
+ mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
+
+ status_t result;
+ do {
+ int32_t cmd;
+ result = talkWithDriver();
+ if (result >= NO_ERROR) {
+ size_t IN = mIn.dataAvail();
+ if (IN < sizeof(int32_t)) continue;
+ cmd = mIn.readInt32();
+ IF_LOG_COMMANDS() {
+ alog << "Processing top-level Command: "
+ << getReturnString(cmd) << endl;
+ }
+ result = executeCommand(cmd);
+ }
+
+ // Let this thread exit the thread pool if it is no longer
+ // needed and it is not the main process thread.
+ if(result == TIMED_OUT && !isMain) {
+ break;
+ }
+ } while (result != -ECONNREFUSED && result != -EBADF);
+
+ LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
+ (void*)pthread_self(), getpid(), (void*)result);
+
+ mOut.writeInt32(BC_EXIT_LOOPER);
+ talkWithDriver(false);
+}
+
+void IPCThreadState::stopProcess(bool immediate)
+{
+ //LOGI("**** STOPPING PROCESS");
+ flushCommands();
+ int fd = mProcess->mDriverFD;
+ mProcess->mDriverFD = -1;
+ close(fd);
+ //kill(getpid(), SIGKILL);
+}
+
+status_t IPCThreadState::transact(int32_t handle,
+ uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags)
+{
+ status_t err = data.errorCheck();
+
+ flags |= TF_ACCEPT_FDS;
+
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
+ << handle << " / code " << TypeCode(code) << ": "
+ << indent << data << dedent << endl;
+ }
+
+ if (err == NO_ERROR) {
+ LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
+ (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
+ err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
+ }
+
+ if (err != NO_ERROR) {
+ if (reply) reply->setError(err);
+ return (mLastError = err);
+ }
+
+ if ((flags & TF_ONE_WAY) == 0) {
+ if (reply) {
+ err = waitForResponse(reply);
+ } else {
+ Parcel fakeReply;
+ err = waitForResponse(&fakeReply);
+ }
+
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
+ << handle << ": ";
+ if (reply) alog << indent << *reply << dedent << endl;
+ else alog << "(none requested)" << endl;
+ }
+ } else {
+ err = waitForResponse(NULL, NULL);
+ }
+
+ return err;
+}
+
+void IPCThreadState::incStrongHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
+ mOut.writeInt32(BC_ACQUIRE);
+ mOut.writeInt32(handle);
+}
+
+void IPCThreadState::decStrongHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle);
+ mOut.writeInt32(BC_RELEASE);
+ mOut.writeInt32(handle);
+}
+
+void IPCThreadState::incWeakHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
+ mOut.writeInt32(BC_INCREFS);
+ mOut.writeInt32(handle);
+}
+
+void IPCThreadState::decWeakHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
+ mOut.writeInt32(BC_DECREFS);
+ mOut.writeInt32(handle);
+}
+
+status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
+{
+ mOut.writeInt32(BC_ATTEMPT_ACQUIRE);
+ mOut.writeInt32(0); // xxx was thread priority
+ mOut.writeInt32(handle);
+ status_t result = UNKNOWN_ERROR;
+
+ waitForResponse(NULL, &result);
+
+#if LOG_REFCOUNTS
+ printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
+ handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
+#endif
+
+ return result;
+}
+
+void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder)
+{
+#if LOG_REFCOUNTS
+ printf("IPCThreadState::expungeHandle(%ld)\n", handle);
+#endif
+ self()->mProcess->expungeHandle(handle, binder);
+}
+
+status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
+{
+ mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
+ mOut.writeInt32((int32_t)handle);
+ mOut.writeInt32((int32_t)proxy);
+ return NO_ERROR;
+}
+
+status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
+{
+ mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION);
+ mOut.writeInt32((int32_t)handle);
+ mOut.writeInt32((int32_t)proxy);
+ return NO_ERROR;
+}
+
+IPCThreadState::IPCThreadState()
+ : mProcess(ProcessState::self())
+{
+ pthread_setspecific(gTLS, this);
+ clearCaller();
+ mIn.setDataCapacity(256);
+ mOut.setDataCapacity(256);
+}
+
+IPCThreadState::~IPCThreadState()
+{
+}
+
+status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
+{
+ status_t err;
+ status_t statusBuffer;
+ err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
+ if (err < NO_ERROR) return err;
+
+ return waitForResponse(NULL, NULL);
+}
+
+status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
+{
+ int32_t cmd;
+ int32_t err;
+
+ while (1) {
+ if ((err=talkWithDriver()) < NO_ERROR) break;
+ err = mIn.errorCheck();
+ if (err < NO_ERROR) break;
+ if (mIn.dataAvail() == 0) continue;
+
+ cmd = mIn.readInt32();
+
+ IF_LOG_COMMANDS() {
+ alog << "Processing waitForResponse Command: "
+ << getReturnString(cmd) << endl;
+ }
+
+ switch (cmd) {
+ case BR_TRANSACTION_COMPLETE:
+ if (!reply && !acquireResult) goto finish;
+ break;
+
+ case BR_DEAD_REPLY:
+ err = DEAD_OBJECT;
+ goto finish;
+
+ case BR_FAILED_REPLY:
+ err = FAILED_TRANSACTION;
+ goto finish;
+
+ case BR_ACQUIRE_RESULT:
+ {
+ LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
+ const int32_t result = mIn.readInt32();
+ if (!acquireResult) continue;
+ *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
+ }
+ goto finish;
+
+ case BR_REPLY:
+ {
+ binder_transaction_data tr;
+ err = mIn.read(&tr, sizeof(tr));
+ LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
+ if (err != NO_ERROR) goto finish;
+
+ if (reply) {
+ if ((tr.flags & TF_STATUS_CODE) == 0) {
+ reply->ipcSetDataReference(
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t),
+ freeBuffer, this);
+ } else {
+ err = *static_cast<const status_t*>(tr.data.ptr.buffer);
+ freeBuffer(NULL,
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t), this);
+ }
+ } else {
+ freeBuffer(NULL,
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t), this);
+ continue;
+ }
+ }
+ goto finish;
+
+ default:
+ err = executeCommand(cmd);
+ if (err != NO_ERROR) goto finish;
+ break;
+ }
+ }
+
+finish:
+ if (err != NO_ERROR) {
+ if (acquireResult) *acquireResult = err;
+ if (reply) reply->setError(err);
+ mLastError = err;
+ }
+
+ return err;
+}
+
+status_t IPCThreadState::talkWithDriver(bool doReceive)
+{
+ LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
+
+ binder_write_read bwr;
+
+ // Is the read buffer empty?
+ const bool needRead = mIn.dataPosition() >= mIn.dataSize();
+
+ // We don't want to write anything if we are still reading
+ // from data left in the input buffer and the caller
+ // has requested to read the next data.
+ const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
+
+ bwr.write_size = outAvail;
+ bwr.write_buffer = (long unsigned int)mOut.data();
+
+ // This is what we'll read.
+ if (doReceive && needRead) {
+ bwr.read_size = mIn.dataCapacity();
+ bwr.read_buffer = (long unsigned int)mIn.data();
+ } else {
+ bwr.read_size = 0;
+ }
+
+ IF_LOG_COMMANDS() {
+ TextOutput::Bundle _b(alog);
+ if (outAvail != 0) {
+ alog << "Sending commands to driver: " << indent;
+ const void* cmds = (const void*)bwr.write_buffer;
+ const void* end = ((const uint8_t*)cmds)+bwr.write_size;
+ alog << HexDump(cmds, bwr.write_size) << endl;
+ while (cmds < end) cmds = printCommand(alog, cmds);
+ alog << dedent;
+ }
+ alog << "Size of receive buffer: " << bwr.read_size
+ << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
+ }
+
+ // Return immediately if there is nothing to do.
+ if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
+
+ bwr.write_consumed = 0;
+ bwr.read_consumed = 0;
+ status_t err;
+ do {
+ IF_LOG_COMMANDS() {
+ alog << "About to read/write, write size = " << mOut.dataSize() << endl;
+ }
+#if defined(HAVE_ANDROID_OS)
+ if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
+ err = NO_ERROR;
+ else
+ err = -errno;
+#else
+ err = INVALID_OPERATION;
+#endif
+ IF_LOG_COMMANDS() {
+ alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
+ }
+ } while (err == -EINTR);
+
+ IF_LOG_COMMANDS() {
+ alog << "Our err: " << (void*)err << ", write consumed: "
+ << bwr.write_consumed << " (of " << mOut.dataSize()
+ << "), read consumed: " << bwr.read_consumed << endl;
+ }
+
+ if (err >= NO_ERROR) {
+ if (bwr.write_consumed > 0) {
+ if (bwr.write_consumed < (ssize_t)mOut.dataSize())
+ mOut.remove(0, bwr.write_consumed);
+ else
+ mOut.setDataSize(0);
+ }
+ if (bwr.read_consumed > 0) {
+ mIn.setDataSize(bwr.read_consumed);
+ mIn.setDataPosition(0);
+ }
+ IF_LOG_COMMANDS() {
+ TextOutput::Bundle _b(alog);
+ alog << "Remaining data size: " << mOut.dataSize() << endl;
+ alog << "Received commands from driver: " << indent;
+ const void* cmds = mIn.data();
+ const void* end = mIn.data() + mIn.dataSize();
+ alog << HexDump(cmds, mIn.dataSize()) << endl;
+ while (cmds < end) cmds = printReturnCommand(alog, cmds);
+ alog << dedent;
+ }
+ return NO_ERROR;
+ }
+
+ return err;
+}
+
+status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
+ int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
+{
+ binder_transaction_data tr;
+
+ tr.target.handle = handle;
+ tr.code = code;
+ tr.flags = binderFlags;
+
+ const status_t err = data.errorCheck();
+ if (err == NO_ERROR) {
+ tr.data_size = data.ipcDataSize();
+ tr.data.ptr.buffer = data.ipcData();
+ tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
+ tr.data.ptr.offsets = data.ipcObjects();
+ } else if (statusBuffer) {
+ tr.flags |= TF_STATUS_CODE;
+ *statusBuffer = err;
+ tr.data_size = sizeof(status_t);
+ tr.data.ptr.buffer = statusBuffer;
+ tr.offsets_size = 0;
+ tr.data.ptr.offsets = NULL;
+ } else {
+ return (mLastError = err);
+ }
+
+ mOut.writeInt32(cmd);
+ mOut.write(&tr, sizeof(tr));
+
+ return NO_ERROR;
+}
+
+sp<BBinder> the_context_object;
+
+void setTheContextObject(sp<BBinder> obj)
+{
+ the_context_object = obj;
+}
+
+status_t IPCThreadState::executeCommand(int32_t cmd)
+{
+ BBinder* obj;
+ RefBase::weakref_type* refs;
+ status_t result = NO_ERROR;
+
+ switch (cmd) {
+ case BR_ERROR:
+ result = mIn.readInt32();
+ break;
+
+ case BR_OK:
+ break;
+
+ case BR_ACQUIRE:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ LOG_ASSERT(refs->refBase() == obj,
+ "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
+ refs, obj, refs->refBase());
+ obj->incStrong(mProcess.get());
+ IF_LOG_REMOTEREFS() {
+ LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
+ obj->printRefs();
+ }
+ mOut.writeInt32(BC_ACQUIRE_DONE);
+ mOut.writeInt32((int32_t)refs);
+ mOut.writeInt32((int32_t)obj);
+ break;
+
+ case BR_RELEASE:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ LOG_ASSERT(refs->refBase() == obj,
+ "BR_RELEASE: object %p does not match cookie %p (expected %p)",
+ refs, obj, refs->refBase());
+ IF_LOG_REMOTEREFS() {
+ LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
+ obj->printRefs();
+ }
+ obj->decStrong(mProcess.get());
+ break;
+
+ case BR_INCREFS:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ refs->incWeak(mProcess.get());
+ mOut.writeInt32(BC_INCREFS_DONE);
+ mOut.writeInt32((int32_t)refs);
+ mOut.writeInt32((int32_t)obj);
+ break;
+
+ case BR_DECREFS:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ // NOTE: This assertion is not valid, because the object may no
+ // longer exist (thus the (BBinder*)cast above resulting in a different
+ // memory address).
+ //LOG_ASSERT(refs->refBase() == obj,
+ // "BR_DECREFS: object %p does not match cookie %p (expected %p)",
+ // refs, obj, refs->refBase());
+ refs->decWeak(mProcess.get());
+ break;
+
+ case BR_ATTEMPT_ACQUIRE:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+
+ {
+ const bool success = refs->attemptIncStrong(mProcess.get());
+ LOG_ASSERT(success && refs->refBase() == obj,
+ "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
+ refs, obj, refs->refBase());
+
+ mOut.writeInt32(BC_ACQUIRE_RESULT);
+ mOut.writeInt32((int32_t)success);
+ }
+ break;
+
+ case BR_TRANSACTION:
+ {
+ binder_transaction_data tr;
+ result = mIn.read(&tr, sizeof(tr));
+ LOG_ASSERT(result == NO_ERROR,
+ "Not enough command data for brTRANSACTION");
+ if (result != NO_ERROR) break;
+
+ Parcel buffer;
+ buffer.ipcSetDataReference(
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t), freeBuffer, this);
+
+ const pid_t origPid = mCallingPid;
+ const uid_t origUid = mCallingUid;
+
+ mCallingPid = tr.sender_pid;
+ mCallingUid = tr.sender_euid;
+
+ //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
+
+ Parcel reply;
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BR_TRANSACTION thr " << (void*)pthread_self()
+ << " / obj " << tr.target.ptr << " / code "
+ << TypeCode(tr.code) << ": " << indent << buffer
+ << dedent << endl
+ << "Data addr = "
+ << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
+ << ", offsets addr="
+ << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
+ }
+ if (tr.target.ptr) {
+ sp<BBinder> b((BBinder*)tr.cookie);
+ const status_t error = b->transact(tr.code, buffer, &reply, 0);
+ if (error < NO_ERROR) reply.setError(error);
+
+ } else {
+ const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);
+ if (error < NO_ERROR) reply.setError(error);
+ }
+
+ //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
+ // mCallingPid, origPid, origUid);
+
+ if ((tr.flags & TF_ONE_WAY) == 0) {
+ LOG_ONEWAY("Sending reply to %d!", mCallingPid);
+ sendReply(reply, 0);
+ } else {
+ LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
+ }
+
+ mCallingPid = origPid;
+ mCallingUid = origUid;
+
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
+ << tr.target.ptr << ": " << indent << reply << dedent << endl;
+ }
+
+ }
+ break;
+
+ case BR_DEAD_BINDER:
+ {
+ BpBinder *proxy = (BpBinder*)mIn.readInt32();
+ proxy->sendObituary();
+ mOut.writeInt32(BC_DEAD_BINDER_DONE);
+ mOut.writeInt32((int32_t)proxy);
+ } break;
+
+ case BR_CLEAR_DEATH_NOTIFICATION_DONE:
+ {
+ BpBinder *proxy = (BpBinder*)mIn.readInt32();
+ proxy->getWeakRefs()->decWeak(proxy);
+ } break;
+
+ case BR_FINISHED:
+ result = TIMED_OUT;
+ break;
+
+ case BR_NOOP:
+ break;
+
+ case BR_SPAWN_LOOPER:
+ mProcess->spawnPooledThread(false);
+ break;
+
+ default:
+ printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
+ result = UNKNOWN_ERROR;
+ break;
+ }
+
+ if (result != NO_ERROR) {
+ mLastError = result;
+ }
+
+ return result;
+}
+
+void IPCThreadState::threadDestructor(void *st)
+{
+ IPCThreadState* const self = static_cast<IPCThreadState*>(st);
+ if (self) {
+ self->flushCommands();
+#if defined(HAVE_ANDROID_OS)
+ ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
+#endif
+ delete self;
+ }
+}
+
+
+void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsSize,
+ void* cookie)
+{
+ //LOGI("Freeing parcel %p", &parcel);
+ IF_LOG_COMMANDS() {
+ alog << "Writing BC_FREE_BUFFER for " << data << endl;
+ }
+ LOG_ASSERT(data != NULL, "Called with NULL data");
+ if (parcel != NULL) parcel->closeFileDescriptors();
+ IPCThreadState* state = self();
+ state->mOut.writeInt32(BC_FREE_BUFFER);
+ state->mOut.writeInt32((int32_t)data);
+}
+
+}; // namespace android
diff --git a/libs/utils/IPermissionController.cpp b/libs/utils/IPermissionController.cpp
new file mode 100644
index 0000000..f01d38f
--- /dev/null
+++ b/libs/utils/IPermissionController.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2005 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 "PermissionController"
+
+#include <utils/IPermissionController.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/String8.h>
+
+#include <private/utils/Static.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BpPermissionController : public BpInterface<IPermissionController>
+{
+public:
+ BpPermissionController(const sp<IBinder>& impl)
+ : BpInterface<IPermissionController>(impl)
+ {
+ }
+
+ virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+ data.writeString16(permission);
+ data.writeInt32(pid);
+ data.writeInt32(uid);
+ remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readInt32() != 0) return 0;
+ return reply.readInt32() != 0;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnPermissionController::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ //printf("PermissionController received: "); data.print();
+ switch(code) {
+ case CHECK_PERMISSION_TRANSACTION: {
+ CHECK_INTERFACE(IPermissionController, data, reply);
+ String16 permission = data.readString16();
+ int32_t pid = data.readInt32();
+ int32_t uid = data.readInt32();
+ bool res = checkPermission(permission, pid, uid);
+ // write exception
+ reply->writeInt32(0);
+ reply->writeInt32(res ? 1 : 0);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/libs/utils/IServiceManager.cpp b/libs/utils/IServiceManager.cpp
new file mode 100644
index 0000000..9beeadd
--- /dev/null
+++ b/libs/utils/IServiceManager.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2005 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 "ServiceManager"
+
+#include <utils/IServiceManager.h>
+
+#include <utils/Debug.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/String8.h>
+#include <utils/SystemClock.h>
+
+#include <private/utils/Static.h>
+
+#include <unistd.h>
+
+namespace android {
+
+sp<IServiceManager> defaultServiceManager()
+{
+ if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
+
+ {
+ AutoMutex _l(gDefaultServiceManagerLock);
+ if (gDefaultServiceManager == NULL) {
+ gDefaultServiceManager = interface_cast<IServiceManager>(
+ ProcessState::self()->getContextObject(NULL));
+ }
+ }
+
+ return gDefaultServiceManager;
+}
+
+bool checkCallingPermission(const String16& permission)
+{
+ return checkCallingPermission(permission, NULL, NULL);
+}
+
+static String16 _permission("permission");
+
+bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
+{
+ IPCThreadState* ipcState = IPCThreadState::self();
+ int32_t pid = ipcState->getCallingPid();
+ int32_t uid = ipcState->getCallingUid();
+ if (outPid) *outPid = pid;
+ if (outUid) *outUid= uid;
+
+ sp<IPermissionController> pc;
+ gDefaultServiceManagerLock.lock();
+ pc = gPermissionController;
+ gDefaultServiceManagerLock.unlock();
+
+ int64_t startTime = 0;
+
+ while (true) {
+ if (pc != NULL) {
+ bool res = pc->checkPermission(permission, pid, uid);
+ if (res) {
+ if (startTime != 0) {
+ LOGI("Check passed after %d seconds for %s from uid=%d pid=%d",
+ (int)((uptimeMillis()-startTime)/1000),
+ String8(permission).string(), uid, pid);
+ }
+ return res;
+ }
+
+ // Is this a permission failure, or did the controller go away?
+ if (pc->asBinder()->isBinderAlive()) {
+ LOGW("Permission failure: %s from uid=%d pid=%d",
+ String8(permission).string(), uid, pid);
+ return false;
+ }
+
+ // Object is dead!
+ gDefaultServiceManagerLock.lock();
+ if (gPermissionController == pc) {
+ gPermissionController = NULL;
+ }
+ gDefaultServiceManagerLock.unlock();
+ }
+
+ // Need to retrieve the permission controller.
+ sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
+ if (binder == NULL) {
+ // Wait for the permission controller to come back...
+ if (startTime == 0) {
+ startTime = uptimeMillis();
+ LOGI("Waiting to check permission %s from uid=%d pid=%d",
+ String8(permission).string(), uid, pid);
+ }
+ sleep(1);
+ } else {
+ pc = interface_cast<IPermissionController>(binder);
+ // Install the new permission controller, and try again.
+ gDefaultServiceManagerLock.lock();
+ gPermissionController = pc;
+ gDefaultServiceManagerLock.unlock();
+ }
+ }
+}
+
+// ----------------------------------------------------------------------
+
+class BpServiceManager : public BpInterface<IServiceManager>
+{
+public:
+ BpServiceManager(const sp<IBinder>& impl)
+ : BpInterface<IServiceManager>(impl)
+ {
+ }
+
+ virtual sp<IBinder> getService(const String16& name) const
+ {
+ unsigned n;
+ for (n = 0; n < 5; n++){
+ sp<IBinder> svc = checkService(name);
+ if (svc != NULL) return svc;
+ LOGI("Waiting for sevice %s...\n", String8(name).string());
+ sleep(1);
+ }
+ return NULL;
+ }
+
+ virtual sp<IBinder> checkService( const String16& name) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+ data.writeString16(name);
+ remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
+ return reply.readStrongBinder();
+ }
+
+ virtual status_t addService(const String16& name, const sp<IBinder>& service)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+ data.writeString16(name);
+ data.writeStrongBinder(service);
+ status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
+ return err == NO_ERROR ? reply.readInt32() : err;
+ }
+
+ virtual Vector<String16> listServices()
+ {
+ Vector<String16> res;
+ int n = 0;
+
+ for (;;) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+ data.writeInt32(n++);
+ status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
+ if (err != NO_ERROR)
+ break;
+ res.add(reply.readString16());
+ }
+ return res;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnServiceManager::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ //printf("ServiceManager received: "); data.print();
+ switch(code) {
+ case GET_SERVICE_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ String16 which = data.readString16();
+ sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which);
+ reply->writeStrongBinder(b);
+ return NO_ERROR;
+ } break;
+ case CHECK_SERVICE_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ String16 which = data.readString16();
+ sp<IBinder> b = const_cast<BnServiceManager*>(this)->checkService(which);
+ reply->writeStrongBinder(b);
+ return NO_ERROR;
+ } break;
+ case ADD_SERVICE_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ String16 which = data.readString16();
+ sp<IBinder> b = data.readStrongBinder();
+ status_t err = addService(which, b);
+ reply->writeInt32(err);
+ return NO_ERROR;
+ } break;
+ case LIST_SERVICES_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ Vector<String16> list = listServices();
+ const size_t N = list.size();
+ reply->writeInt32(N);
+ for (size_t i=0; i<N; i++) {
+ reply->writeString16(list[i]);
+ }
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/libs/utils/InetAddress.cpp b/libs/utils/InetAddress.cpp
new file mode 100644
index 0000000..39a0a68
--- /dev/null
+++ b/libs/utils/InetAddress.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Internet address class.
+//
+#ifdef HAVE_WINSOCK
+# include <winsock2.h>
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+//# include <arpa/inet.h>
+# include <netdb.h>
+#endif
+
+#include <utils/inet_address.h>
+#include <utils/threads.h>
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+using namespace android;
+
+
+/*
+ * ===========================================================================
+ * InetAddress
+ * ===========================================================================
+ */
+
+// lock for the next couple of functions; could tuck into InetAddress
+static Mutex* gGHBNLock;
+
+/*
+ * Lock/unlock access to the hostent struct returned by gethostbyname().
+ */
+static inline void lock_gethostbyname(void)
+{
+ if (gGHBNLock == NULL)
+ gGHBNLock = new Mutex;
+ gGHBNLock->lock();
+}
+static inline void unlock_gethostbyname(void)
+{
+ assert(gGHBNLock != NULL);
+ gGHBNLock->unlock();
+}
+
+
+/*
+ * Constructor -- just init members. This is private so that callers
+ * are required to use getByName().
+ */
+InetAddress::InetAddress(void)
+ : mAddress(NULL), mLength(-1), mName(NULL)
+{
+}
+
+/*
+ * Destructor -- free address storage.
+ */
+InetAddress::~InetAddress(void)
+{
+ delete[] (char*) mAddress;
+ delete[] mName;
+}
+
+/*
+ * Copy constructor.
+ */
+InetAddress::InetAddress(const InetAddress& orig)
+{
+ *this = orig; // use assignment code
+}
+
+/*
+ * Assignment operator.
+ */
+InetAddress& InetAddress::operator=(const InetAddress& addr)
+{
+ // handle self-assignment
+ if (this == &addr)
+ return *this;
+ // copy mLength and mAddress
+ mLength = addr.mLength;
+ if (mLength > 0) {
+ mAddress = new char[mLength];
+ memcpy(mAddress, addr.mAddress, mLength);
+ LOG(LOG_DEBUG, "socket",
+ "HEY: copied %d bytes in assignment operator\n", mLength);
+ } else {
+ mAddress = NULL;
+ }
+ // copy mName
+ mName = new char[strlen(addr.mName)+1];
+ strcpy(mName, addr.mName);
+
+ return *this;
+}
+
+/*
+ * Create a new object from a name or a dotted-number IP notation.
+ *
+ * Returns NULL on failure.
+ */
+InetAddress*
+InetAddress::getByName(const char* host)
+{
+ InetAddress* newAddr = NULL;
+ struct sockaddr_in addr;
+ struct hostent* he;
+ DurationTimer hostTimer, lockTimer;
+
+ // gethostbyname() isn't reentrant, so we need to lock things until
+ // we can copy the data out.
+ lockTimer.start();
+ lock_gethostbyname();
+ hostTimer.start();
+
+ he = gethostbyname(host);
+ if (he == NULL) {
+ LOG(LOG_WARN, "socket", "WARNING: cannot resolve host %s\n", host);
+ unlock_gethostbyname();
+ return NULL;
+ }
+
+ memcpy(&addr.sin_addr, he->h_addr, he->h_length);
+ addr.sin_family = he->h_addrtype;
+ addr.sin_port = 0;
+
+ // got it, unlock us
+ hostTimer.stop();
+ he = NULL;
+ unlock_gethostbyname();
+
+ lockTimer.stop();
+ if ((long) lockTimer.durationUsecs() > 100000) {
+ long lockTime = (long) lockTimer.durationUsecs();
+ long hostTime = (long) hostTimer.durationUsecs();
+ LOG(LOG_DEBUG, "socket",
+ "Lookup of %s took %.3fs (gethostbyname=%.3fs lock=%.3fs)\n",
+ host, lockTime / 1000000.0, hostTime / 1000000.0,
+ (lockTime - hostTime) / 1000000.0);
+ }
+
+ // Alloc storage and copy it over.
+ newAddr = new InetAddress();
+ if (newAddr == NULL)
+ return NULL;
+
+ newAddr->mLength = sizeof(struct sockaddr_in);
+ newAddr->mAddress = new char[sizeof(struct sockaddr_in)];
+ if (newAddr->mAddress == NULL) {
+ delete newAddr;
+ return NULL;
+ }
+ memcpy(newAddr->mAddress, &addr, newAddr->mLength);
+
+ // Keep this for debug messages.
+ newAddr->mName = new char[strlen(host)+1];
+ if (newAddr->mName == NULL) {
+ delete newAddr;
+ return NULL;
+ }
+ strcpy(newAddr->mName, host);
+
+ return newAddr;
+}
+
+
+/*
+ * ===========================================================================
+ * InetSocketAddress
+ * ===========================================================================
+ */
+
+/*
+ * Create an address with the host wildcard (INADDR_ANY).
+ */
+bool InetSocketAddress::create(int port)
+{
+ assert(mAddress == NULL);
+
+ mAddress = InetAddress::getByName("0.0.0.0");
+ if (mAddress == NULL)
+ return false;
+ mPort = port;
+ return true;
+}
+
+/*
+ * Create address with host and port specified.
+ */
+bool InetSocketAddress::create(const InetAddress* addr, int port)
+{
+ assert(mAddress == NULL);
+
+ mAddress = new InetAddress(*addr); // make a copy
+ if (mAddress == NULL)
+ return false;
+ mPort = port;
+ return true;
+}
+
+/*
+ * Create address with host and port specified.
+ */
+bool InetSocketAddress::create(const char* host, int port)
+{
+ assert(mAddress == NULL);
+
+ mAddress = InetAddress::getByName(host);
+ if (mAddress == NULL)
+ return false;
+ mPort = port;
+ return true;
+}
+
diff --git a/libs/utils/LogSocket.cpp b/libs/utils/LogSocket.cpp
new file mode 100644
index 0000000..e64f794
--- /dev/null
+++ b/libs/utils/LogSocket.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+
+#ifndef HAVE_WINSOCK
+#define SOCKETLOG
+#endif
+
+#ifdef SOCKETLOG
+
+#define LOG_TAG "SOCKETLOG"
+
+#include <string.h>
+#include <cutils/log.h>
+#include "utils/LogSocket.h"
+#include "utils/logger.h"
+#include "cutils/hashmap.h"
+
+// defined in //device/data/etc/event-log-tags
+#define SOCKET_CLOSE_LOG 51000
+
+static Hashmap* statsMap = NULL;
+
+#define LOG_LIST_NUMBER 5
+
+typedef struct SocketStats {
+ int fd;
+ unsigned int send;
+ unsigned int recv;
+ unsigned int ip;
+ unsigned short port;
+ short reason;
+}SocketStats;
+
+SocketStats *get_socket_stats(int fd) {
+ if (statsMap == NULL) {
+ statsMap = hashmapCreate(8, &hashmapIntHash, &hashmapIntEquals);
+ }
+
+ SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
+ if (s == NULL) {
+ // LOGD("create SocketStats for fd %d", fd);
+ s = (SocketStats*) malloc(sizeof(SocketStats));
+ memset(s, 0, sizeof(SocketStats));
+ s->fd = fd;
+ hashmapPut(statsMap, &s->fd, s);
+ }
+ return s;
+}
+
+void log_socket_connect(int fd, unsigned int ip, unsigned short port) {
+ // LOGD("log_socket_connect for fd %d ip %d port%d", fd, ip, port);
+ SocketStats *s = get_socket_stats(fd);
+ s->ip = ip;
+ s->port = port;
+}
+
+void add_send_stats(int fd, int send) {
+ if (send <=0) {
+ LOGE("add_send_stats send %d", send);
+ return;
+ }
+ SocketStats *s = get_socket_stats(fd);
+ s->send += send;
+ // LOGD("add_send_stats for fd %d ip %d port%d", fd, s->ip, s->port);
+}
+
+void add_recv_stats(int fd, int recv) {
+ if (recv <=0) {
+ LOGE("add_recv_stats recv %d", recv);
+ return;
+ }
+ SocketStats *s = get_socket_stats(fd);
+ s->recv += recv;
+ // LOGD("add_recv_stats for fd %d ip %d port%d", fd, s->ip, s->port);
+}
+
+char* put_int(char* buf, int value) {
+ *buf = EVENT_TYPE_INT;
+ buf++;
+ memcpy(buf, &value, sizeof(int));
+ return buf + sizeof(int);
+}
+
+void log_socket_close(int fd, short reason) {
+ if (statsMap) {
+ SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
+ if (s != NULL) {
+ if (s->send != 0 || s->recv != 0) {
+ s->reason = reason;
+ // 5 int + list type need 2 bytes
+ char buf[LOG_LIST_NUMBER * 5 + 2];
+ buf[0] = EVENT_TYPE_LIST;
+ buf[1] = LOG_LIST_NUMBER;
+ char* writePos = buf + 2;
+ writePos = put_int(writePos, s->send);
+ writePos = put_int(writePos, s->recv);
+ writePos = put_int(writePos, s->ip);
+ writePos = put_int(writePos, s->port);
+ writePos = put_int(writePos, s->reason);
+
+ android_bWriteLog(SOCKET_CLOSE_LOG, buf, sizeof(buf));
+ // LOGD("send %d recv %d reason %d", s->send, s->recv, s->reason);
+ }
+ hashmapRemove(statsMap, &s->fd);
+ free(s);
+ }
+ }
+}
+
+#else
+void add_send_stats(int fd, int send) {}
+void add_recv_stats(int fd, int recv) {}
+void log_socket_close(int fd, short reason) {}
+void log_socket_connect(int fd, unsigned int ip, unsigned short port) {}
+#endif
diff --git a/libs/utils/MODULE_LICENSE_APACHE2 b/libs/utils/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/utils/MODULE_LICENSE_APACHE2
diff --git a/libs/utils/MemoryBase.cpp b/libs/utils/MemoryBase.cpp
new file mode 100644
index 0000000..f25e11c
--- /dev/null
+++ b/libs/utils/MemoryBase.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <utils/MemoryBase.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap,
+ ssize_t offset, size_t size)
+ : mSize(size), mOffset(offset), mHeap(heap)
+{
+}
+
+sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const
+{
+ if (offset) *offset = mOffset;
+ if (size) *size = mSize;
+ return mHeap;
+}
+
+MemoryBase::~MemoryBase()
+{
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/utils/MemoryDealer.cpp b/libs/utils/MemoryDealer.cpp
new file mode 100644
index 0000000..e6d1d18
--- /dev/null
+++ b/libs/utils/MemoryDealer.cpp
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "MemoryDealer"
+
+#include <utils/MemoryDealer.h>
+
+#include <utils/Log.h>
+#include <utils/IPCThreadState.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <utils/MemoryBase.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+
+namespace android {
+
+
+// ----------------------------------------------------------------------------
+
+class SimpleMemory : public MemoryBase {
+public:
+ SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
+ virtual ~SimpleMemory();
+};
+
+
+// ----------------------------------------------------------------------------
+
+MemoryDealer::Allocation::Allocation(
+ const sp<MemoryDealer>& dealer, ssize_t offset, size_t size,
+ const sp<IMemory>& memory)
+ : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory)
+{
+}
+
+MemoryDealer::Allocation::~Allocation()
+{
+ if (mSize) {
+ /* NOTE: it's VERY important to not free allocations of size 0 because
+ * they're special as they don't have any record in the allocator
+ * and could alias some real allocation (their offset is zero). */
+ mDealer->deallocate(mOffset);
+ }
+}
+
+sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
+ ssize_t* offset, size_t* size) const
+{
+ return mMemory->getMemory(offset, size);
+}
+
+// ----------------------------------------------------------------------------
+
+MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name)
+ : mHeap(new SharedHeap(size, flags, name)),
+ mAllocator(new SimpleBestFitAllocator(size))
+{
+}
+
+MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap)
+ : mHeap(heap),
+ mAllocator(new SimpleBestFitAllocator(heap->virtualSize()))
+{
+}
+
+MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap,
+ const sp<AllocatorInterface>& allocator)
+ : mHeap(heap), mAllocator(allocator)
+{
+}
+
+MemoryDealer::~MemoryDealer()
+{
+}
+
+sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
+{
+ sp<IMemory> memory;
+ const ssize_t offset = allocator()->allocate(size, flags);
+ if (offset >= 0) {
+ sp<IMemory> new_memory = heap()->mapMemory(offset, size);
+ if (new_memory != 0) {
+ memory = new Allocation(this, offset, size, new_memory);
+ } else {
+ LOGE("couldn't map [%8x, %d]", offset, size);
+ if (size) {
+ /* NOTE: it's VERY important to not free allocations of size 0
+ * because they're special as they don't have any record in the
+ * allocator and could alias some real allocation
+ * (their offset is zero). */
+ allocator()->deallocate(offset);
+ }
+ }
+ }
+ return memory;
+}
+
+void MemoryDealer::deallocate(size_t offset)
+{
+ allocator()->deallocate(offset);
+}
+
+void MemoryDealer::dump(const char* what, uint32_t flags) const
+{
+ allocator()->dump(what, flags);
+}
+
+const sp<HeapInterface>& MemoryDealer::heap() const {
+ return mHeap;
+}
+
+const sp<AllocatorInterface>& MemoryDealer::allocator() const {
+ return mAllocator;
+}
+
+// ----------------------------------------------------------------------------
+
+// align all the memory blocks on a cache-line boundary
+const int SimpleBestFitAllocator::kMemoryAlign = 32;
+
+SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
+{
+ size_t pagesize = getpagesize();
+ mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
+
+ chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
+ mList.insertHead(node);
+}
+
+SimpleBestFitAllocator::~SimpleBestFitAllocator()
+{
+ while(!mList.isEmpty()) {
+ delete mList.remove(mList.head());
+ }
+}
+
+size_t SimpleBestFitAllocator::size() const
+{
+ return mHeapSize;
+}
+
+size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
+{
+ Mutex::Autolock _l(mLock);
+ ssize_t offset = alloc(size, flags);
+ return offset;
+}
+
+status_t SimpleBestFitAllocator::deallocate(size_t offset)
+{
+ Mutex::Autolock _l(mLock);
+ chunk_t const * const freed = dealloc(offset);
+ if (freed) {
+ return NO_ERROR;
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
+{
+ if (size == 0) {
+ return 0;
+ }
+ size = (size + kMemoryAlign-1) / kMemoryAlign;
+ chunk_t* free_chunk = 0;
+ chunk_t* cur = mList.head();
+
+ size_t pagesize = getpagesize();
+ while (cur) {
+ int extra = 0;
+ if (flags & PAGE_ALIGNED)
+ extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
+
+ // best fit
+ if (cur->free && (cur->size >= (size+extra))) {
+ if ((!free_chunk) || (cur->size < free_chunk->size)) {
+ free_chunk = cur;
+ }
+ if (cur->size == size) {
+ break;
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (free_chunk) {
+ const size_t free_size = free_chunk->size;
+ free_chunk->free = 0;
+ free_chunk->size = size;
+ if (free_size > size) {
+ int extra = 0;
+ if (flags & PAGE_ALIGNED)
+ extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
+ if (extra) {
+ chunk_t* split = new chunk_t(free_chunk->start, extra);
+ free_chunk->start += extra;
+ mList.insertBefore(free_chunk, split);
+ }
+
+ LOGE_IF((flags&PAGE_ALIGNED) &&
+ ((free_chunk->start*kMemoryAlign)&(pagesize-1)),
+ "PAGE_ALIGNED requested, but page is not aligned!!!");
+
+ const ssize_t tail_free = free_size - (size+extra);
+ if (tail_free > 0) {
+ chunk_t* split = new chunk_t(
+ free_chunk->start + free_chunk->size, tail_free);
+ mList.insertAfter(free_chunk, split);
+ }
+ }
+ return (free_chunk->start)*kMemoryAlign;
+ }
+ return NO_MEMORY;
+}
+
+SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
+{
+ start = start / kMemoryAlign;
+ chunk_t* cur = mList.head();
+ while (cur) {
+ if (cur->start == start) {
+ LOG_FATAL_IF(cur->free,
+ "block at offset 0x%08lX of size 0x%08lX already freed",
+ cur->start*kMemoryAlign, cur->size*kMemoryAlign);
+
+ // merge freed blocks together
+ chunk_t* freed = cur;
+ cur->free = 1;
+ do {
+ chunk_t* const p = cur->prev;
+ chunk_t* const n = cur->next;
+ if (p && (p->free || !cur->size)) {
+ freed = p;
+ p->size += cur->size;
+ mList.remove(cur);
+ delete cur;
+ }
+ cur = n;
+ } while (cur && cur->free);
+
+ #ifndef NDEBUG
+ if (!freed->free) {
+ dump_l("dealloc (!freed->free)");
+ }
+ #endif
+ LOG_FATAL_IF(!freed->free,
+ "freed block at offset 0x%08lX of size 0x%08lX is not free!",
+ freed->start * kMemoryAlign, freed->size * kMemoryAlign);
+
+ return freed;
+ }
+ cur = cur->next;
+ }
+ return 0;
+}
+
+void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const
+{
+ Mutex::Autolock _l(mLock);
+ dump_l(what, flags);
+}
+
+void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const
+{
+ String8 result;
+ dump_l(result, what, flags);
+ LOGD("%s", result.string());
+}
+
+void SimpleBestFitAllocator::dump(String8& result,
+ const char* what, uint32_t flags) const
+{
+ Mutex::Autolock _l(mLock);
+ dump_l(result, what, flags);
+}
+
+void SimpleBestFitAllocator::dump_l(String8& result,
+ const char* what, uint32_t flags) const
+{
+ size_t size = 0;
+ int32_t i = 0;
+ chunk_t const* cur = mList.head();
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, " %s (%p, size=%u)\n",
+ what, this, (unsigned int)mHeapSize);
+
+ result.append(buffer);
+
+ while (cur) {
+ const char* errs[] = {"", "| link bogus NP",
+ "| link bogus PN", "| link bogus NP+PN" };
+ int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0;
+ int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0;
+
+ snprintf(buffer, SIZE, " %3u: %08x | 0x%08X | 0x%08X | %s %s\n",
+ i, int(cur), int(cur->start*kMemoryAlign),
+ int(cur->size*kMemoryAlign),
+ int(cur->free) ? "F" : "A",
+ errs[np|pn]);
+
+ result.append(buffer);
+
+ if (!cur->free)
+ size += cur->size*kMemoryAlign;
+
+ i++;
+ cur = cur->next;
+ }
+ snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024));
+ result.append(buffer);
+}
+
+// ----------------------------------------------------------------------------
+
+
+SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
+ : MemoryHeapBase(size, flags, name)
+{
+}
+
+SharedHeap::~SharedHeap()
+{
+}
+
+sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size)
+{
+ return new SimpleMemory(this, offset, size);
+}
+
+
+SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap,
+ ssize_t offset, size_t size)
+ : MemoryBase(heap, offset, size)
+{
+#ifndef NDEBUG
+ void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
+ memset(start_ptr, 0xda, size);
+#endif
+}
+
+SimpleMemory::~SimpleMemory()
+{
+ size_t freedOffset = getOffset();
+ size_t freedSize = getSize();
+
+ // keep the size to unmap in excess
+ size_t pagesize = getpagesize();
+ size_t start = freedOffset;
+ size_t end = start + freedSize;
+ start &= ~(pagesize-1);
+ end = (end + pagesize-1) & ~(pagesize-1);
+
+ // give back to the kernel the pages we don't need
+ size_t free_start = freedOffset;
+ size_t free_end = free_start + freedSize;
+ if (start < free_start)
+ start = free_start;
+ if (end > free_end)
+ end = free_end;
+ start = (start + pagesize-1) & ~(pagesize-1);
+ end &= ~(pagesize-1);
+
+ void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
+ size_t size = end-start;
+
+#ifndef NDEBUG
+ memset(start_ptr, 0xdf, size);
+#endif
+
+// MADV_REMOVE is not defined on Dapper based Goobuntu
+#ifdef MADV_REMOVE
+ if (size) {
+ int err = madvise(start_ptr, size, MADV_REMOVE);
+ LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
+ start_ptr, size, err<0 ? strerror(errno) : "Ok");
+ }
+#endif
+}
+
+}; // namespace android
diff --git a/libs/utils/MemoryHeapBase.cpp b/libs/utils/MemoryHeapBase.cpp
new file mode 100644
index 0000000..59963c9
--- /dev/null
+++ b/libs/utils/MemoryHeapBase.cpp
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MemoryHeapBase"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/ashmem.h>
+#include <cutils/atomic.h>
+
+#include <utils/MemoryHeapBase.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapBase::MemoryHeapBase()
+ : mFD(-1), mSize(0), mBase(MAP_FAILED),
+ mDevice(NULL), mNeedUnmap(false)
+{
+}
+
+MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
+ : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+ mDevice(0), mNeedUnmap(false)
+{
+ const size_t pagesize = getpagesize();
+ size = ((size + pagesize-1) & ~(pagesize-1));
+ int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
+ LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
+ if (fd >= 0) {
+ if (mapfd(fd, size) == NO_ERROR) {
+ if (flags & READ_ONLY) {
+ ashmem_set_prot_region(fd, PROT_READ);
+ }
+ }
+ }
+}
+
+MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
+ : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+ mDevice(0), mNeedUnmap(false)
+{
+ int fd = open(device, O_RDWR);
+ LOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
+ if (fd >= 0) {
+ const size_t pagesize = getpagesize();
+ size = ((size + pagesize-1) & ~(pagesize-1));
+ if (mapfd(fd, size) == NO_ERROR) {
+ mDevice = device;
+ }
+ }
+}
+
+MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags)
+ : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+ mDevice(0), mNeedUnmap(false)
+{
+ const size_t pagesize = getpagesize();
+ size = ((size + pagesize-1) & ~(pagesize-1));
+ mapfd(dup(fd), size);
+}
+
+status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
+{
+ if (mFD != -1) {
+ return INVALID_OPERATION;
+ }
+ mFD = fd;
+ mBase = base;
+ mSize = size;
+ mFlags = flags;
+ mDevice = device;
+ return NO_ERROR;
+}
+
+status_t MemoryHeapBase::mapfd(int fd, size_t size)
+{
+ if (size == 0) {
+ // try to figure out the size automatically
+#if HAVE_ANDROID_OS
+ // first try the PMEM ioctl
+ pmem_region reg;
+ int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, &reg);
+ if (err == 0)
+ size = reg.len;
+#endif
+ if (size == 0) { // try fstat
+ struct stat sb;
+ if (fstat(fd, &sb) == 0)
+ size = sb.st_size;
+ }
+ // if it didn't work, let mmap() fail.
+ }
+
+ void* base = (uint8_t*)mmap(0, size,
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (base == MAP_FAILED) {
+ LOGE("mmap(fd=%d, size=%u) failed (%s)",
+ fd, uint32_t(size), strerror(errno));
+ close(fd);
+ return -errno;
+ }
+ //LOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
+ mFD = fd;
+ mBase = base;
+ mSize = size;
+ mNeedUnmap = true;
+ return NO_ERROR;
+}
+
+MemoryHeapBase::~MemoryHeapBase()
+{
+ dispose();
+}
+
+void MemoryHeapBase::dispose()
+{
+ int fd = android_atomic_or(-1, &mFD);
+ if (fd >= 0) {
+ if (mNeedUnmap) {
+ //LOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
+ munmap(mBase, mSize);
+ }
+ mBase = 0;
+ mSize = 0;
+ close(fd);
+ }
+}
+
+int MemoryHeapBase::getHeapID() const {
+ return mFD;
+}
+
+void* MemoryHeapBase::getBase() const {
+ return mBase;
+}
+
+size_t MemoryHeapBase::getSize() const {
+ return mSize;
+}
+
+uint32_t MemoryHeapBase::getFlags() const {
+ return mFlags;
+}
+
+const char* MemoryHeapBase::getDevice() const {
+ return mDevice;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/utils/MemoryHeapPmem.cpp
new file mode 100644
index 0000000..1e5a1cc
--- /dev/null
+++ b/libs/utils/MemoryHeapPmem.cpp
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MemoryHeapPmem"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+
+#include <utils/MemoryHeapPmem.h>
+#include <utils/MemoryHeapBase.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryHeapPmem;
+
+class SubRegionMemory : public BnMemory {
+public:
+ SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
+ virtual ~SubRegionMemory();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+private:
+ friend class MemoryHeapPmem;
+ void revoke();
+ size_t mSize;
+ ssize_t mOffset;
+ sp<MemoryHeapPmem> mClientHeap;
+};
+
+SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
+ ssize_t offset, size_t size)
+ : mSize(size), mOffset(offset), mClientHeap(heap)
+{
+#ifndef NDEBUG
+ void* const start_ptr = (void*)(intptr_t(mClientHeap->base()) + offset);
+ memset(start_ptr, 0xda, size);
+#endif
+
+#if HAVE_ANDROID_OS
+ if (size > 0) {
+ const size_t pagesize = getpagesize();
+ size = (size + pagesize-1) & ~(pagesize-1);
+ int our_fd = heap->heapID();
+ struct pmem_region sub = { offset, size };
+ int err = ioctl(our_fd, PMEM_MAP, &sub);
+ LOGE_IF(err<0, "PMEM_MAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+}
+#endif
+}
+
+sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
+{
+ if (offset) *offset = mOffset;
+ if (size) *size = mSize;
+ return mClientHeap;
+}
+
+SubRegionMemory::~SubRegionMemory()
+{
+ revoke();
+}
+
+
+void SubRegionMemory::revoke()
+{
+ // NOTE: revoke() doesn't need to be protected by a lock because it
+ // can only be called from MemoryHeapPmem::revoke(), which means
+ // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
+ // which means MemoryHeapPmem::revoke() wouldn't have been able to
+ // promote() it.
+
+#if HAVE_ANDROID_OS
+ if (mClientHeap != NULL) {
+ int our_fd = mClientHeap->heapID();
+ struct pmem_region sub;
+ sub.offset = mOffset;
+ sub.len = mSize;
+ int err = ioctl(our_fd, PMEM_UNMAP, &sub);
+ LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+ mClientHeap.clear();
+ }
+#endif
+}
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
+ uint32_t flags)
+ : HeapInterface(), MemoryHeapBase()
+{
+ char const * const device = pmemHeap->getDevice();
+#if HAVE_ANDROID_OS
+ if (device) {
+ int fd = open(device, O_RDWR);
+ LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
+ if (fd >= 0) {
+ int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
+ if (err < 0) {
+ LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
+ strerror(errno), fd, pmemHeap->heapID());
+ close(fd);
+ } else {
+ // everything went well...
+ mParentHeap = pmemHeap;
+ MemoryHeapBase::init(fd,
+ pmemHeap->getBase(),
+ pmemHeap->getSize(),
+ pmemHeap->getFlags() | flags,
+ device);
+ }
+ }
+ }
+#else
+ mParentHeap = pmemHeap;
+ MemoryHeapBase::init(
+ dup(pmemHeap->heapID()),
+ pmemHeap->getBase(),
+ pmemHeap->getSize(),
+ pmemHeap->getFlags() | flags,
+ device);
+#endif
+}
+
+MemoryHeapPmem::~MemoryHeapPmem()
+{
+}
+
+sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
+{
+ sp<SubRegionMemory> memory;
+ if (heapID() > 0)
+ memory = new SubRegionMemory(this, offset, size);
+
+ if (memory != 0) {
+ Mutex::Autolock _l(mLock);
+ mAllocations.add(memory);
+ }
+ return memory;
+}
+
+status_t MemoryHeapPmem::slap()
+{
+#if HAVE_ANDROID_OS
+ size_t size = getSize();
+ const size_t pagesize = getpagesize();
+ size = (size + pagesize-1) & ~(pagesize-1);
+ int our_fd = getHeapID();
+ struct pmem_region sub = { 0, size };
+ int err = ioctl(our_fd, PMEM_MAP, &sub);
+ LOGE_IF(err<0, "PMEM_MAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+ return -errno;
+#else
+ return NO_ERROR;
+#endif
+}
+
+status_t MemoryHeapPmem::unslap()
+{
+#if HAVE_ANDROID_OS
+ size_t size = getSize();
+ const size_t pagesize = getpagesize();
+ size = (size + pagesize-1) & ~(pagesize-1);
+ int our_fd = getHeapID();
+ struct pmem_region sub = { 0, size };
+ int err = ioctl(our_fd, PMEM_UNMAP, &sub);
+ LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+ return -errno;
+#else
+ return NO_ERROR;
+#endif
+}
+
+void MemoryHeapPmem::revoke()
+{
+ Vector< wp<SubRegionMemory> > allocations;
+
+ { // scope for lock
+ Mutex::Autolock _l(mLock);
+ allocations = mAllocations;
+ mAllocations.clear();
+ }
+
+ ssize_t count = allocations.size();
+ for (ssize_t i=0 ; i<count ; i++) {
+ sp<SubRegionMemory> memory(allocations[i].promote());
+ if (memory != 0)
+ memory->revoke();
+ }
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/utils/NOTICE b/libs/utils/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/utils/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the 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/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp
new file mode 100644
index 0000000..3eca4b0
--- /dev/null
+++ b/libs/utils/Parcel.cpp
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (C) 2005 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 "Parcel"
+//#define LOG_NDEBUG 0
+
+#include <utils/Parcel.h>
+
+#include <utils/Binder.h>
+#include <utils/BpBinder.h>
+#include <utils/Debug.h>
+#include <utils/ProcessState.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/TextOutput.h>
+#include <utils/misc.h>
+
+#include <private/utils/binder_module.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#ifndef INT32_MAX
+#define INT32_MAX ((int32_t)(2147483647))
+#endif
+
+#define LOG_REFS(...)
+//#define LOG_REFS(...) LOG(LOG_DEBUG, "Parcel", __VA_ARGS__)
+
+// ---------------------------------------------------------------------------
+
+#define PAD_SIZE(s) (((s)+3)&~3)
+
+// XXX This can be made public if we want to provide
+// support for typed data.
+struct small_flat_data
+{
+ uint32_t type;
+ uint32_t data;
+};
+
+namespace android {
+
+void acquire_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who)
+{
+ switch (obj.type) {
+ case BINDER_TYPE_BINDER:
+ if (obj.binder) {
+ LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
+ static_cast<IBinder*>(obj.cookie)->incStrong(who);
+ }
+ return;
+ case BINDER_TYPE_WEAK_BINDER:
+ if (obj.binder)
+ static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);
+ return;
+ case BINDER_TYPE_HANDLE: {
+ const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
+ if (b != NULL) {
+ LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get());
+ b->incStrong(who);
+ }
+ return;
+ }
+ case BINDER_TYPE_WEAK_HANDLE: {
+ const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
+ if (b != NULL) b.get_refs()->incWeak(who);
+ return;
+ }
+ case BINDER_TYPE_FD: {
+ // intentionally blank -- nothing to do to acquire this, but we do
+ // recognize it as a legitimate object type.
+ return;
+ }
+ }
+
+ LOGD("Invalid object type 0x%08lx", obj.type);
+}
+
+void release_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who)
+{
+ switch (obj.type) {
+ case BINDER_TYPE_BINDER:
+ if (obj.binder) {
+ LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
+ static_cast<IBinder*>(obj.cookie)->decStrong(who);
+ }
+ return;
+ case BINDER_TYPE_WEAK_BINDER:
+ if (obj.binder)
+ static_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who);
+ return;
+ case BINDER_TYPE_HANDLE: {
+ const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
+ if (b != NULL) {
+ LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get());
+ b->decStrong(who);
+ }
+ return;
+ }
+ case BINDER_TYPE_WEAK_HANDLE: {
+ const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
+ if (b != NULL) b.get_refs()->decWeak(who);
+ return;
+ }
+ case BINDER_TYPE_FD: {
+ if (obj.cookie != (void*)0) close(obj.handle);
+ return;
+ }
+ }
+
+ LOGE("Invalid object type 0x%08lx", obj.type);
+}
+
+inline static status_t finish_flatten_binder(
+ const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out)
+{
+ return out->writeObject(flat, false);
+}
+
+status_t flatten_binder(const sp<ProcessState>& proc,
+ const sp<IBinder>& binder, Parcel* out)
+{
+ flat_binder_object obj;
+
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ if (binder != NULL) {
+ IBinder *local = binder->localBinder();
+ if (!local) {
+ BpBinder *proxy = binder->remoteBinder();
+ if (proxy == NULL) {
+ LOGE("null proxy");
+ }
+ const int32_t handle = proxy ? proxy->handle() : 0;
+ obj.type = BINDER_TYPE_HANDLE;
+ obj.handle = handle;
+ obj.cookie = NULL;
+ } else {
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = local->getWeakRefs();
+ obj.cookie = local;
+ }
+ } else {
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = NULL;
+ obj.cookie = NULL;
+ }
+
+ return finish_flatten_binder(binder, obj, out);
+}
+
+status_t flatten_binder(const sp<ProcessState>& proc,
+ const wp<IBinder>& binder, Parcel* out)
+{
+ flat_binder_object obj;
+
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ if (binder != NULL) {
+ sp<IBinder> real = binder.promote();
+ if (real != NULL) {
+ IBinder *local = real->localBinder();
+ if (!local) {
+ BpBinder *proxy = real->remoteBinder();
+ if (proxy == NULL) {
+ LOGE("null proxy");
+ }
+ const int32_t handle = proxy ? proxy->handle() : 0;
+ obj.type = BINDER_TYPE_WEAK_HANDLE;
+ obj.handle = handle;
+ obj.cookie = NULL;
+ } else {
+ obj.type = BINDER_TYPE_WEAK_BINDER;
+ obj.binder = binder.get_refs();
+ obj.cookie = binder.unsafe_get();
+ }
+ return finish_flatten_binder(real, obj, out);
+ }
+
+ // XXX How to deal? In order to flatten the given binder,
+ // we need to probe it for information, which requires a primary
+ // reference... but we don't have one.
+ //
+ // The OpenBinder implementation uses a dynamic_cast<> here,
+ // but we can't do that with the different reference counting
+ // implementation we are using.
+ LOGE("Unable to unflatten Binder weak reference!");
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = NULL;
+ obj.cookie = NULL;
+ return finish_flatten_binder(NULL, obj, out);
+
+ } else {
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = NULL;
+ obj.cookie = NULL;
+ return finish_flatten_binder(NULL, obj, out);
+ }
+}
+
+inline static status_t finish_unflatten_binder(
+ BpBinder* proxy, const flat_binder_object& flat, const Parcel& in)
+{
+ return NO_ERROR;
+}
+
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const Parcel& in, sp<IBinder>* out)
+{
+ const flat_binder_object* flat = in.readObject(false);
+
+ if (flat) {
+ switch (flat->type) {
+ case BINDER_TYPE_BINDER:
+ *out = static_cast<IBinder*>(flat->cookie);
+ return finish_unflatten_binder(NULL, *flat, in);
+ case BINDER_TYPE_HANDLE:
+ *out = proc->getStrongProxyForHandle(flat->handle);
+ return finish_unflatten_binder(
+ static_cast<BpBinder*>(out->get()), *flat, in);
+ }
+ }
+ return BAD_TYPE;
+}
+
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const Parcel& in, wp<IBinder>* out)
+{
+ const flat_binder_object* flat = in.readObject(false);
+
+ if (flat) {
+ switch (flat->type) {
+ case BINDER_TYPE_BINDER:
+ *out = static_cast<IBinder*>(flat->cookie);
+ return finish_unflatten_binder(NULL, *flat, in);
+ case BINDER_TYPE_WEAK_BINDER:
+ if (flat->binder != NULL) {
+ out->set_object_and_refs(
+ static_cast<IBinder*>(flat->cookie),
+ static_cast<RefBase::weakref_type*>(flat->binder));
+ } else {
+ *out = NULL;
+ }
+ return finish_unflatten_binder(NULL, *flat, in);
+ case BINDER_TYPE_HANDLE:
+ case BINDER_TYPE_WEAK_HANDLE:
+ *out = proc->getWeakProxyForHandle(flat->handle);
+ return finish_unflatten_binder(
+ static_cast<BpBinder*>(out->unsafe_get()), *flat, in);
+ }
+ }
+ return BAD_TYPE;
+}
+
+// ---------------------------------------------------------------------------
+
+Parcel::Parcel()
+{
+ initState();
+}
+
+Parcel::~Parcel()
+{
+ freeDataNoInit();
+}
+
+const uint8_t* Parcel::data() const
+{
+ return mData;
+}
+
+size_t Parcel::dataSize() const
+{
+ return (mDataSize > mDataPos ? mDataSize : mDataPos);
+}
+
+size_t Parcel::dataAvail() const
+{
+ // TODO: decide what to do about the possibility that this can
+ // report an available-data size that exceeds a Java int's max
+ // positive value, causing havoc. Fortunately this will only
+ // happen if someone constructs a Parcel containing more than two
+ // gigabytes of data, which on typical phone hardware is simply
+ // not possible.
+ return dataSize() - dataPosition();
+}
+
+size_t Parcel::dataPosition() const
+{
+ return mDataPos;
+}
+
+size_t Parcel::dataCapacity() const
+{
+ return mDataCapacity;
+}
+
+status_t Parcel::setDataSize(size_t size)
+{
+ status_t err;
+ err = continueWrite(size);
+ if (err == NO_ERROR) {
+ mDataSize = size;
+ LOGV("setDataSize Setting data size of %p to %d\n", this, mDataSize);
+ }
+ return err;
+}
+
+void Parcel::setDataPosition(size_t pos) const
+{
+ mDataPos = pos;
+ mNextObjectHint = 0;
+}
+
+status_t Parcel::setDataCapacity(size_t size)
+{
+ if (size > mDataSize) return continueWrite(size);
+ return NO_ERROR;
+}
+
+status_t Parcel::setData(const uint8_t* buffer, size_t len)
+{
+ status_t err = restartWrite(len);
+ if (err == NO_ERROR) {
+ memcpy(const_cast<uint8_t*>(data()), buffer, len);
+ mDataSize = len;
+ mFdsKnown = false;
+ }
+ return err;
+}
+
+status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)
+{
+ const sp<ProcessState> proc(ProcessState::self());
+ status_t err;
+ uint8_t *data = parcel->mData;
+ size_t *objects = parcel->mObjects;
+ size_t size = parcel->mObjectsSize;
+ int startPos = mDataPos;
+ int firstIndex = -1, lastIndex = -2;
+
+ if (len == 0) {
+ return NO_ERROR;
+ }
+
+ // range checks against the source parcel size
+ if ((offset > parcel->mDataSize)
+ || (len > parcel->mDataSize)
+ || (offset + len > parcel->mDataSize)) {
+ return BAD_VALUE;
+ }
+
+ // Count objects in range
+ for (int i = 0; i < (int) size; i++) {
+ size_t off = objects[i];
+ if ((off >= offset) && (off < offset + len)) {
+ if (firstIndex == -1) {
+ firstIndex = i;
+ }
+ lastIndex = i;
+ }
+ }
+ int numObjects = lastIndex - firstIndex + 1;
+
+ // grow data
+ err = growData(len);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ // append data
+ memcpy(mData + mDataPos, data + offset, len);
+ mDataPos += len;
+ mDataSize += len;
+
+ if (numObjects > 0) {
+ // grow objects
+ if (mObjectsCapacity < mObjectsSize + numObjects) {
+ int newSize = ((mObjectsSize + numObjects)*3)/2;
+ size_t *objects =
+ (size_t*)realloc(mObjects, newSize*sizeof(size_t));
+ if (objects == (size_t*)0) {
+ return NO_MEMORY;
+ }
+ mObjects = objects;
+ mObjectsCapacity = newSize;
+ }
+
+ // append and acquire objects
+ int idx = mObjectsSize;
+ for (int i = firstIndex; i <= lastIndex; i++) {
+ size_t off = objects[i] - offset + startPos;
+ mObjects[idx++] = off;
+ mObjectsSize++;
+
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(mData + off);
+ acquire_object(proc, *flat, this);
+
+ // take note if the object is a file descriptor
+ if (flat->type == BINDER_TYPE_FD) {
+ mHasFds = mFdsKnown = true;
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+bool Parcel::hasFileDescriptors() const
+{
+ if (!mFdsKnown) {
+ scanForFds();
+ }
+ return mHasFds;
+}
+
+status_t Parcel::writeInterfaceToken(const String16& interface)
+{
+ // currently the interface identification token is just its name as a string
+ return writeString16(interface);
+}
+
+bool Parcel::enforceInterface(const String16& interface) const
+{
+ String16 str = readString16();
+ if (str == interface) {
+ return true;
+ } else {
+ LOGW("**** enforceInterface() expected '%s' but read '%s'\n",
+ String8(interface).string(), String8(str).string());
+ return false;
+ }
+}
+
+const size_t* Parcel::objects() const
+{
+ return mObjects;
+}
+
+size_t Parcel::objectsCount() const
+{
+ return mObjectsSize;
+}
+
+status_t Parcel::errorCheck() const
+{
+ return mError;
+}
+
+void Parcel::setError(status_t err)
+{
+ mError = err;
+}
+
+status_t Parcel::finishWrite(size_t len)
+{
+ //printf("Finish write of %d\n", len);
+ mDataPos += len;
+ LOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos);
+ if (mDataPos > mDataSize) {
+ mDataSize = mDataPos;
+ LOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize);
+ }
+ //printf("New pos=%d, size=%d\n", mDataPos, mDataSize);
+ return NO_ERROR;
+}
+
+status_t Parcel::writeUnpadded(const void* data, size_t len)
+{
+ size_t end = mDataPos + len;
+ if (end < mDataPos) {
+ // integer overflow
+ return BAD_VALUE;
+ }
+
+ if (end <= mDataCapacity) {
+restart_write:
+ memcpy(mData+mDataPos, data, len);
+ return finishWrite(len);
+ }
+
+ status_t err = growData(len);
+ if (err == NO_ERROR) goto restart_write;
+ return err;
+}
+
+status_t Parcel::write(const void* data, size_t len)
+{
+ void* const d = writeInplace(len);
+ if (d) {
+ memcpy(d, data, len);
+ return NO_ERROR;
+ }
+ return mError;
+}
+
+void* Parcel::writeInplace(size_t len)
+{
+ const size_t padded = PAD_SIZE(len);
+
+ // sanity check for integer overflow
+ if (mDataPos+padded < mDataPos) {
+ return NULL;
+ }
+
+ if ((mDataPos+padded) <= mDataCapacity) {
+restart_write:
+ //printf("Writing %ld bytes, padded to %ld\n", len, padded);
+ uint8_t* const data = mData+mDataPos;
+
+ // Need to pad at end?
+ if (padded != len) {
+#if BYTE_ORDER == BIG_ENDIAN
+ static const uint32_t mask[4] = {
+ 0x00000000, 0xffffff00, 0xffff0000, 0xff000000
+ };
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+ static const uint32_t mask[4] = {
+ 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff
+ };
+#endif
+ //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len],
+ // *reinterpret_cast<void**>(data+padded-4));
+ *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len];
+ }
+
+ finishWrite(padded);
+ return data;
+ }
+
+ status_t err = growData(padded);
+ if (err == NO_ERROR) goto restart_write;
+ return NULL;
+}
+
+status_t Parcel::writeInt32(int32_t val)
+{
+ if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+ *reinterpret_cast<int32_t*>(mData+mDataPos) = val;
+ return finishWrite(sizeof(val));
+ }
+
+ status_t err = growData(sizeof(val));
+ if (err == NO_ERROR) goto restart_write;
+ return err;
+}
+
+status_t Parcel::writeInt64(int64_t val)
+{
+ if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+ *reinterpret_cast<int64_t*>(mData+mDataPos) = val;
+ return finishWrite(sizeof(val));
+ }
+
+ status_t err = growData(sizeof(val));
+ if (err == NO_ERROR) goto restart_write;
+ return err;
+}
+
+status_t Parcel::writeFloat(float val)
+{
+ if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+ *reinterpret_cast<float*>(mData+mDataPos) = val;
+ return finishWrite(sizeof(val));
+ }
+
+ status_t err = growData(sizeof(val));
+ if (err == NO_ERROR) goto restart_write;
+ return err;
+}
+
+status_t Parcel::writeDouble(double val)
+{
+ if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+ *reinterpret_cast<double*>(mData+mDataPos) = val;
+ return finishWrite(sizeof(val));
+ }
+
+ status_t err = growData(sizeof(val));
+ if (err == NO_ERROR) goto restart_write;
+ return err;
+}
+
+status_t Parcel::writeCString(const char* str)
+{
+ return write(str, strlen(str)+1);
+}
+
+status_t Parcel::writeString8(const String8& str)
+{
+ status_t err = writeInt32(str.bytes());
+ if (err == NO_ERROR) {
+ err = write(str.string(), str.bytes()+1);
+ }
+ return err;
+}
+
+status_t Parcel::writeString16(const String16& str)
+{
+ return writeString16(str.string(), str.size());
+}
+
+status_t Parcel::writeString16(const char16_t* str, size_t len)
+{
+ if (str == NULL) return writeInt32(-1);
+
+ status_t err = writeInt32(len);
+ if (err == NO_ERROR) {
+ len *= sizeof(char16_t);
+ uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
+ if (data) {
+ memcpy(data, str, len);
+ *reinterpret_cast<char16_t*>(data+len) = 0;
+ return NO_ERROR;
+ }
+ err = mError;
+ }
+ return err;
+}
+
+status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
+{
+ return flatten_binder(ProcessState::self(), val, this);
+}
+
+status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
+{
+ return flatten_binder(ProcessState::self(), val, this);
+}
+
+status_t Parcel::writeFileDescriptor(int fd)
+{
+ flat_binder_object obj;
+ obj.type = BINDER_TYPE_FD;
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ obj.handle = fd;
+ obj.cookie = (void*)0;
+ return writeObject(obj, true);
+}
+
+status_t Parcel::writeDupFileDescriptor(int fd)
+{
+ flat_binder_object obj;
+ obj.type = BINDER_TYPE_FD;
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ obj.handle = dup(fd);
+ obj.cookie = (void*)1;
+ return writeObject(obj, true);
+}
+
+status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
+{
+ const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
+ const bool enoughObjects = mObjectsSize < mObjectsCapacity;
+ if (enoughData && enoughObjects) {
+restart_write:
+ *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
+
+ // Need to write meta-data?
+ if (nullMetaData || val.binder != NULL) {
+ mObjects[mObjectsSize] = mDataPos;
+ acquire_object(ProcessState::self(), val, this);
+ mObjectsSize++;
+ }
+
+ // remember if it's a file descriptor
+ if (val.type == BINDER_TYPE_FD) {
+ mHasFds = mFdsKnown = true;
+ }
+
+ return finishWrite(sizeof(flat_binder_object));
+ }
+
+ if (!enoughData) {
+ const status_t err = growData(sizeof(val));
+ if (err != NO_ERROR) return err;
+ }
+ if (!enoughObjects) {
+ size_t newSize = ((mObjectsSize+2)*3)/2;
+ size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));
+ if (objects == NULL) return NO_MEMORY;
+ mObjects = objects;
+ mObjectsCapacity = newSize;
+ }
+
+ goto restart_write;
+}
+
+
+void Parcel::remove(size_t start, size_t amt)
+{
+ LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
+}
+
+status_t Parcel::read(void* outData, size_t len) const
+{
+ if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
+ memcpy(outData, mData+mDataPos, len);
+ mDataPos += PAD_SIZE(len);
+ LOGV("read Setting data pos of %p to %d\n", this, mDataPos);
+ return NO_ERROR;
+ }
+ return NOT_ENOUGH_DATA;
+}
+
+const void* Parcel::readInplace(size_t len) const
+{
+ if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += PAD_SIZE(len);
+ LOGV("readInplace Setting data pos of %p to %d\n", this, mDataPos);
+ return data;
+ }
+ return NULL;
+}
+
+status_t Parcel::readInt32(int32_t *pArg) const
+{
+ if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += sizeof(int32_t);
+ *pArg = *reinterpret_cast<const int32_t*>(data);
+ return NO_ERROR;
+ } else {
+ return NOT_ENOUGH_DATA;
+ }
+}
+
+int32_t Parcel::readInt32() const
+{
+ if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += sizeof(int32_t);
+ LOGV("readInt32 Setting data pos of %p to %d\n", this, mDataPos);
+ return *reinterpret_cast<const int32_t*>(data);
+ }
+ return 0;
+}
+
+
+status_t Parcel::readInt64(int64_t *pArg) const
+{
+ if ((mDataPos+sizeof(int64_t)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += sizeof(int64_t);
+ *pArg = *reinterpret_cast<const int64_t*>(data);
+ LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos);
+ return NO_ERROR;
+ } else {
+ return NOT_ENOUGH_DATA;
+ }
+}
+
+
+int64_t Parcel::readInt64() const
+{
+ if ((mDataPos+sizeof(int64_t)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += sizeof(int64_t);
+ LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos);
+ return *reinterpret_cast<const int64_t*>(data);
+ }
+ return 0;
+}
+
+status_t Parcel::readFloat(float *pArg) const
+{
+ if ((mDataPos+sizeof(float)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += sizeof(float);
+ LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos);
+ *pArg = *reinterpret_cast<const float*>(data);
+ return NO_ERROR;
+ } else {
+ return NOT_ENOUGH_DATA;
+ }
+}
+
+
+float Parcel::readFloat() const
+{
+ if ((mDataPos+sizeof(float)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += sizeof(float);
+ LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos);
+ return *reinterpret_cast<const float*>(data);
+ }
+ return 0;
+}
+
+status_t Parcel::readDouble(double *pArg) const
+{
+ if ((mDataPos+sizeof(double)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += sizeof(double);
+ LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos);
+ *pArg = *reinterpret_cast<const double*>(data);
+ return NO_ERROR;
+ } else {
+ return NOT_ENOUGH_DATA;
+ }
+}
+
+
+double Parcel::readDouble() const
+{
+ if ((mDataPos+sizeof(double)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += sizeof(double);
+ LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos);
+ return *reinterpret_cast<const double*>(data);
+ }
+ return 0;
+}
+
+
+const char* Parcel::readCString() const
+{
+ const size_t avail = mDataSize-mDataPos;
+ if (avail > 0) {
+ const char* str = reinterpret_cast<const char*>(mData+mDataPos);
+ // is the string's trailing NUL within the parcel's valid bounds?
+ const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
+ if (eos) {
+ const size_t len = eos - str;
+ mDataPos += PAD_SIZE(len+1);
+ LOGV("readCString Setting data pos of %p to %d\n", this, mDataPos);
+ return str;
+ }
+ }
+ return NULL;
+}
+
+String8 Parcel::readString8() const
+{
+ int32_t size = readInt32();
+ // watch for potential int overflow adding 1 for trailing NUL
+ if (size > 0 && size < INT32_MAX) {
+ const char* str = (const char*)readInplace(size+1);
+ if (str) return String8(str, size);
+ }
+ return String8();
+}
+
+String16 Parcel::readString16() const
+{
+ size_t len;
+ const char16_t* str = readString16Inplace(&len);
+ if (str) return String16(str, len);
+ LOGE("Reading a NULL string not supported here.");
+ return String16();
+}
+
+const char16_t* Parcel::readString16Inplace(size_t* outLen) const
+{
+ int32_t size = readInt32();
+ // watch for potential int overflow from size+1
+ if (size >= 0 && size < INT32_MAX) {
+ *outLen = size;
+ const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
+ if (str != NULL) {
+ return str;
+ }
+ }
+ *outLen = 0;
+ return NULL;
+}
+
+sp<IBinder> Parcel::readStrongBinder() const
+{
+ sp<IBinder> val;
+ unflatten_binder(ProcessState::self(), *this, &val);
+ return val;
+}
+
+wp<IBinder> Parcel::readWeakBinder() const
+{
+ wp<IBinder> val;
+ unflatten_binder(ProcessState::self(), *this, &val);
+ return val;
+}
+
+int Parcel::readFileDescriptor() const
+{
+ const flat_binder_object* flat = readObject(true);
+ if (flat) {
+ switch (flat->type) {
+ case BINDER_TYPE_FD:
+ //LOGI("Returning file descriptor %ld from parcel %p\n", flat->handle, this);
+ return flat->handle;
+ }
+ }
+ return BAD_TYPE;
+}
+
+const flat_binder_object* Parcel::readObject(bool nullMetaData) const
+{
+ const size_t DPOS = mDataPos;
+ if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
+ const flat_binder_object* obj
+ = reinterpret_cast<const flat_binder_object*>(mData+DPOS);
+ mDataPos = DPOS + sizeof(flat_binder_object);
+ if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) {
+ // When transfering a NULL object, we don't write it into
+ // the object list, so we don't want to check for it when
+ // reading.
+ LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+ return obj;
+ }
+
+ // Ensure that this object is valid...
+ size_t* const OBJS = mObjects;
+ const size_t N = mObjectsSize;
+ size_t opos = mNextObjectHint;
+
+ if (N > 0) {
+ LOGV("Parcel %p looking for obj at %d, hint=%d\n",
+ this, DPOS, opos);
+
+ // Start at the current hint position, looking for an object at
+ // the current data position.
+ if (opos < N) {
+ while (opos < (N-1) && OBJS[opos] < DPOS) {
+ opos++;
+ }
+ } else {
+ opos = N-1;
+ }
+ if (OBJS[opos] == DPOS) {
+ // Found it!
+ LOGV("Parcel found obj %d at index %d with forward search",
+ this, DPOS, opos);
+ mNextObjectHint = opos+1;
+ LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+ return obj;
+ }
+
+ // Look backwards for it...
+ while (opos > 0 && OBJS[opos] > DPOS) {
+ opos--;
+ }
+ if (OBJS[opos] == DPOS) {
+ // Found it!
+ LOGV("Parcel found obj %d at index %d with backward search",
+ this, DPOS, opos);
+ mNextObjectHint = opos+1;
+ LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+ return obj;
+ }
+ }
+ LOGW("Attempt to read object from Parcel %p at offset %d that is not in the object list",
+ this, DPOS);
+ }
+ return NULL;
+}
+
+void Parcel::closeFileDescriptors()
+{
+ size_t i = mObjectsSize;
+ if (i > 0) {
+ //LOGI("Closing file descriptors for %d objects...", mObjectsSize);
+ }
+ while (i > 0) {
+ i--;
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
+ if (flat->type == BINDER_TYPE_FD) {
+ //LOGI("Closing fd: %ld\n", flat->handle);
+ close(flat->handle);
+ }
+ }
+}
+
+const uint8_t* Parcel::ipcData() const
+{
+ return mData;
+}
+
+size_t Parcel::ipcDataSize() const
+{
+ return (mDataSize > mDataPos ? mDataSize : mDataPos);
+}
+
+const size_t* Parcel::ipcObjects() const
+{
+ return mObjects;
+}
+
+size_t Parcel::ipcObjectsCount() const
+{
+ return mObjectsSize;
+}
+
+void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)
+{
+ freeDataNoInit();
+ mError = NO_ERROR;
+ mData = const_cast<uint8_t*>(data);
+ mDataSize = mDataCapacity = dataSize;
+ //LOGI("setDataReference Setting data size of %p to %lu (pid=%d)\n", this, mDataSize, getpid());
+ mDataPos = 0;
+ LOGV("setDataReference Setting data pos of %p to %d\n", this, mDataPos);
+ mObjects = const_cast<size_t*>(objects);
+ mObjectsSize = mObjectsCapacity = objectsCount;
+ mNextObjectHint = 0;
+ mOwner = relFunc;
+ mOwnerCookie = relCookie;
+ scanForFds();
+}
+
+void Parcel::print(TextOutput& to, uint32_t flags) const
+{
+ to << "Parcel(";
+
+ if (errorCheck() != NO_ERROR) {
+ const status_t err = errorCheck();
+ to << "Error: " << (void*)err << " \"" << strerror(-err) << "\"";
+ } else if (dataSize() > 0) {
+ const uint8_t* DATA = data();
+ to << indent << HexDump(DATA, dataSize()) << dedent;
+ const size_t* OBJS = objects();
+ const size_t N = objectsCount();
+ for (size_t i=0; i<N; i++) {
+ const flat_binder_object* flat
+ = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);
+ to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
+ << TypeCode(flat->type & 0x7f7f7f00)
+ << " = " << flat->binder;
+ }
+ } else {
+ to << "NULL";
+ }
+
+ to << ")";
+}
+
+void Parcel::releaseObjects()
+{
+ const sp<ProcessState> proc(ProcessState::self());
+ size_t i = mObjectsSize;
+ uint8_t* const data = mData;
+ size_t* const objects = mObjects;
+ while (i > 0) {
+ i--;
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+ release_object(proc, *flat, this);
+ }
+}
+
+void Parcel::acquireObjects()
+{
+ const sp<ProcessState> proc(ProcessState::self());
+ size_t i = mObjectsSize;
+ uint8_t* const data = mData;
+ size_t* const objects = mObjects;
+ while (i > 0) {
+ i--;
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+ acquire_object(proc, *flat, this);
+ }
+}
+
+void Parcel::freeData()
+{
+ freeDataNoInit();
+ initState();
+}
+
+void Parcel::freeDataNoInit()
+{
+ if (mOwner) {
+ //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
+ mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
+ } else {
+ releaseObjects();
+ if (mData) free(mData);
+ if (mObjects) free(mObjects);
+ }
+}
+
+status_t Parcel::growData(size_t len)
+{
+ size_t newSize = ((mDataSize+len)*3)/2;
+ return (newSize <= mDataSize)
+ ? (status_t) NO_MEMORY
+ : continueWrite(newSize);
+}
+
+status_t Parcel::restartWrite(size_t desired)
+{
+ if (mOwner) {
+ freeData();
+ return continueWrite(desired);
+ }
+
+ uint8_t* data = (uint8_t*)realloc(mData, desired);
+ if (!data && desired > mDataCapacity) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+
+ releaseObjects();
+
+ if (data) {
+ mData = data;
+ mDataCapacity = desired;
+ }
+
+ mDataSize = mDataPos = 0;
+ LOGV("restartWrite Setting data size of %p to %d\n", this, mDataSize);
+ LOGV("restartWrite Setting data pos of %p to %d\n", this, mDataPos);
+
+ free(mObjects);
+ mObjects = NULL;
+ mObjectsSize = mObjectsCapacity = 0;
+ mNextObjectHint = 0;
+ mHasFds = false;
+ mFdsKnown = true;
+
+ return NO_ERROR;
+}
+
+status_t Parcel::continueWrite(size_t desired)
+{
+ // If shrinking, first adjust for any objects that appear
+ // after the new data size.
+ size_t objectsSize = mObjectsSize;
+ if (desired < mDataSize) {
+ if (desired == 0) {
+ objectsSize = 0;
+ } else {
+ while (objectsSize > 0) {
+ if (mObjects[objectsSize-1] < desired)
+ break;
+ objectsSize--;
+ }
+ }
+ }
+
+ if (mOwner) {
+ // If the size is going to zero, just release the owner's data.
+ if (desired == 0) {
+ freeData();
+ return NO_ERROR;
+ }
+
+ // If there is a different owner, we need to take
+ // posession.
+ uint8_t* data = (uint8_t*)malloc(desired);
+ if (!data) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+ size_t* objects = NULL;
+
+ if (objectsSize) {
+ objects = (size_t*)malloc(objectsSize*sizeof(size_t));
+ if (!objects) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+
+ // Little hack to only acquire references on objects
+ // we will be keeping.
+ size_t oldObjectsSize = mObjectsSize;
+ mObjectsSize = objectsSize;
+ acquireObjects();
+ mObjectsSize = oldObjectsSize;
+ }
+
+ if (mData) {
+ memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
+ }
+ if (objects && mObjects) {
+ memcpy(objects, mObjects, objectsSize*sizeof(size_t));
+ }
+ //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
+ mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
+ mOwner = NULL;
+
+ mData = data;
+ mObjects = objects;
+ mDataSize = (mDataSize < desired) ? mDataSize : desired;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ mDataCapacity = desired;
+ mObjectsSize = mObjectsCapacity = objectsSize;
+ mNextObjectHint = 0;
+
+ } else if (mData) {
+ if (objectsSize < mObjectsSize) {
+ // Need to release refs on any objects we are dropping.
+ const sp<ProcessState> proc(ProcessState::self());
+ for (size_t i=objectsSize; i<mObjectsSize; i++) {
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
+ if (flat->type == BINDER_TYPE_FD) {
+ // will need to rescan because we may have lopped off the only FDs
+ mFdsKnown = false;
+ }
+ release_object(proc, *flat, this);
+ }
+ size_t* objects =
+ (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
+ if (objects) {
+ mObjects = objects;
+ }
+ mObjectsSize = objectsSize;
+ mNextObjectHint = 0;
+ }
+
+ // We own the data, so we can just do a realloc().
+ if (desired > mDataCapacity) {
+ uint8_t* data = (uint8_t*)realloc(mData, desired);
+ if (data) {
+ mData = data;
+ mDataCapacity = desired;
+ } else if (desired > mDataCapacity) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+ } else {
+ mDataSize = desired;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ if (mDataPos > desired) {
+ mDataPos = desired;
+ LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
+ }
+ }
+
+ } else {
+ // This is the first data. Easy!
+ uint8_t* data = (uint8_t*)malloc(desired);
+ if (!data) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+
+ if(!(mDataCapacity == 0 && mObjects == NULL
+ && mObjectsCapacity == 0)) {
+ LOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
+ }
+
+ mData = data;
+ mDataSize = mDataPos = 0;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
+ mDataCapacity = desired;
+ }
+
+ return NO_ERROR;
+}
+
+void Parcel::initState()
+{
+ mError = NO_ERROR;
+ mData = 0;
+ mDataSize = 0;
+ mDataCapacity = 0;
+ mDataPos = 0;
+ LOGV("initState Setting data size of %p to %d\n", this, mDataSize);
+ LOGV("initState Setting data pos of %p to %d\n", this, mDataPos);
+ mObjects = NULL;
+ mObjectsSize = 0;
+ mObjectsCapacity = 0;
+ mNextObjectHint = 0;
+ mHasFds = false;
+ mFdsKnown = true;
+ mOwner = NULL;
+}
+
+void Parcel::scanForFds() const
+{
+ bool hasFds = false;
+ for (size_t i=0; i<mObjectsSize; i++) {
+ const flat_binder_object* flat
+ = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
+ if (flat->type == BINDER_TYPE_FD) {
+ hasFds = true;
+ break;
+ }
+ }
+ mHasFds = hasFds;
+ mFdsKnown = true;
+}
+
+}; // namespace android
diff --git a/libs/utils/Pipe.cpp b/libs/utils/Pipe.cpp
new file mode 100644
index 0000000..613906b
--- /dev/null
+++ b/libs/utils/Pipe.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Unidirectional pipe.
+//
+
+#include <utils/Pipe.h>
+#include <utils/Log.h>
+
+#if defined(HAVE_WIN32_IPC)
+# include <windows.h>
+#else
+# include <fcntl.h>
+# include <unistd.h>
+# include <errno.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+using namespace android;
+
+const unsigned long kInvalidHandle = (unsigned long) -1;
+
+
+/*
+ * Constructor. Do little.
+ */
+Pipe::Pipe(void)
+ : mReadNonBlocking(false), mReadHandle(kInvalidHandle),
+ mWriteHandle(kInvalidHandle)
+{
+}
+
+/*
+ * Destructor. Use the system-appropriate close call.
+ */
+Pipe::~Pipe(void)
+{
+#if defined(HAVE_WIN32_IPC)
+ if (mReadHandle != kInvalidHandle) {
+ if (!CloseHandle((HANDLE)mReadHandle))
+ LOG(LOG_WARN, "pipe", "failed closing read handle (%ld)\n",
+ mReadHandle);
+ }
+ if (mWriteHandle != kInvalidHandle) {
+ FlushFileBuffers((HANDLE)mWriteHandle);
+ if (!CloseHandle((HANDLE)mWriteHandle))
+ LOG(LOG_WARN, "pipe", "failed closing write handle (%ld)\n",
+ mWriteHandle);
+ }
+#else
+ if (mReadHandle != kInvalidHandle) {
+ if (close((int) mReadHandle) != 0)
+ LOG(LOG_WARN, "pipe", "failed closing read fd (%d)\n",
+ (int) mReadHandle);
+ }
+ if (mWriteHandle != kInvalidHandle) {
+ if (close((int) mWriteHandle) != 0)
+ LOG(LOG_WARN, "pipe", "failed closing write fd (%d)\n",
+ (int) mWriteHandle);
+ }
+#endif
+}
+
+/*
+ * Create the pipe.
+ *
+ * Use the POSIX stuff for everything but Windows.
+ */
+bool Pipe::create(void)
+{
+ assert(mReadHandle == kInvalidHandle);
+ assert(mWriteHandle == kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+ /* we use this across processes, so they need to be inheritable */
+ HANDLE handles[2];
+ SECURITY_ATTRIBUTES saAttr;
+
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
+
+ if (!CreatePipe(&handles[0], &handles[1], &saAttr, 0)) {
+ LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
+ return false;
+ }
+ mReadHandle = (unsigned long) handles[0];
+ mWriteHandle = (unsigned long) handles[1];
+ return true;
+#else
+ int fds[2];
+
+ if (pipe(fds) != 0) {
+ LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
+ return false;
+ }
+ mReadHandle = fds[0];
+ mWriteHandle = fds[1];
+ return true;
+#endif
+}
+
+/*
+ * Create a "half pipe". Please, no Segway riding.
+ */
+bool Pipe::createReader(unsigned long handle)
+{
+ mReadHandle = handle;
+ assert(mWriteHandle == kInvalidHandle);
+ return true;
+}
+
+/*
+ * Create a "half pipe" for writing.
+ */
+bool Pipe::createWriter(unsigned long handle)
+{
+ mWriteHandle = handle;
+ assert(mReadHandle == kInvalidHandle);
+ return true;
+}
+
+/*
+ * Return "true" if create() has been called successfully.
+ */
+bool Pipe::isCreated(void)
+{
+ // one or the other should be open
+ return (mReadHandle != kInvalidHandle || mWriteHandle != kInvalidHandle);
+}
+
+
+/*
+ * Read data from the pipe.
+ *
+ * For Linux and Darwin, just call read(). For Windows, implement
+ * non-blocking reads by calling PeekNamedPipe first.
+ */
+int Pipe::read(void* buf, int count)
+{
+ assert(mReadHandle != kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+ DWORD totalBytesAvail = count;
+ DWORD bytesRead;
+
+ if (mReadNonBlocking) {
+ // use PeekNamedPipe to adjust read count expectations
+ if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
+ &totalBytesAvail, NULL))
+ {
+ LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
+ return -1;
+ }
+
+ if (totalBytesAvail == 0)
+ return 0;
+ }
+
+ if (!ReadFile((HANDLE) mReadHandle, buf, totalBytesAvail, &bytesRead,
+ NULL))
+ {
+ DWORD err = GetLastError();
+ if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
+ return 0;
+ LOG(LOG_ERROR, "pipe", "ReadFile failed (err=%ld)\n", err);
+ return -1;
+ }
+
+ return (int) bytesRead;
+#else
+ int cc;
+ cc = ::read(mReadHandle, buf, count);
+ if (cc < 0 && errno == EAGAIN)
+ return 0;
+ return cc;
+#endif
+}
+
+/*
+ * Write data to the pipe.
+ *
+ * POSIX systems are trivial, Windows uses a different call and doesn't
+ * handle non-blocking writes.
+ *
+ * If we add non-blocking support here, we probably want to make it an
+ * all-or-nothing write.
+ *
+ * DO NOT use LOG() here, we could be writing a log message.
+ */
+int Pipe::write(const void* buf, int count)
+{
+ assert(mWriteHandle != kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+ DWORD bytesWritten;
+
+ if (mWriteNonBlocking) {
+ // BUG: can't use PeekNamedPipe() to get the amount of space
+ // left. Looks like we need to use "overlapped I/O" functions.
+ // I just don't care that much.
+ }
+
+ if (!WriteFile((HANDLE) mWriteHandle, buf, count, &bytesWritten, NULL)) {
+ // can't LOG, use stderr
+ fprintf(stderr, "WriteFile failed (err=%ld)\n", GetLastError());
+ return -1;
+ }
+
+ return (int) bytesWritten;
+#else
+ int cc;
+ cc = ::write(mWriteHandle, buf, count);
+ if (cc < 0 && errno == EAGAIN)
+ return 0;
+ return cc;
+#endif
+}
+
+/*
+ * Figure out if there is data available on the read fd.
+ *
+ * We return "true" on error because we want the caller to try to read
+ * from the pipe. They'll notice the read failure and do something
+ * appropriate.
+ */
+bool Pipe::readReady(void)
+{
+ assert(mReadHandle != kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+ DWORD totalBytesAvail;
+
+ if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
+ &totalBytesAvail, NULL))
+ {
+ LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
+ return true;
+ }
+
+ return (totalBytesAvail != 0);
+#else
+ errno = 0;
+ fd_set readfds;
+ struct timeval tv = { 0, 0 };
+ int cc;
+
+ FD_ZERO(&readfds);
+ FD_SET(mReadHandle, &readfds);
+
+ cc = select(mReadHandle+1, &readfds, NULL, NULL, &tv);
+ if (cc < 0) {
+ LOG(LOG_ERROR, "pipe", "select() failed\n");
+ return true;
+ } else if (cc == 0) {
+ /* timed out, nothing available */
+ return false;
+ } else if (cc == 1) {
+ /* our fd is ready */
+ return true;
+ } else {
+ LOG(LOG_ERROR, "pipe", "HUH? select() returned > 1\n");
+ return true;
+ }
+#endif
+}
+
+/*
+ * Enable or disable non-blocking mode for the read descriptor.
+ *
+ * NOTE: the calls succeed under Mac OS X, but the pipe doesn't appear to
+ * actually be in non-blocking mode. If this matters -- i.e. you're not
+ * using a select() call -- put a call to readReady() in front of the
+ * ::read() call, with a PIPE_NONBLOCK_BROKEN #ifdef in the Makefile for
+ * Darwin.
+ */
+bool Pipe::setReadNonBlocking(bool val)
+{
+ assert(mReadHandle != kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+ // nothing to do
+#else
+ int flags;
+
+ if (fcntl(mReadHandle, F_GETFL, &flags) == -1) {
+ LOG(LOG_ERROR, "pipe", "couldn't get flags for pipe read fd\n");
+ return false;
+ }
+ if (val)
+ flags |= O_NONBLOCK;
+ else
+ flags &= ~(O_NONBLOCK);
+ if (fcntl(mReadHandle, F_SETFL, &flags) == -1) {
+ LOG(LOG_ERROR, "pipe", "couldn't set flags for pipe read fd\n");
+ return false;
+ }
+#endif
+
+ mReadNonBlocking = val;
+ return true;
+}
+
+/*
+ * Enable or disable non-blocking mode for the write descriptor.
+ *
+ * As with setReadNonBlocking(), this does not work on the Mac.
+ */
+bool Pipe::setWriteNonBlocking(bool val)
+{
+ assert(mWriteHandle != kInvalidHandle);
+
+#if defined(HAVE_WIN32_IPC)
+ // nothing to do
+#else
+ int flags;
+
+ if (fcntl(mWriteHandle, F_GETFL, &flags) == -1) {
+ LOG(LOG_WARN, "pipe",
+ "Warning: couldn't get flags for pipe write fd (errno=%d)\n",
+ errno);
+ return false;
+ }
+ if (val)
+ flags |= O_NONBLOCK;
+ else
+ flags &= ~(O_NONBLOCK);
+ if (fcntl(mWriteHandle, F_SETFL, &flags) == -1) {
+ LOG(LOG_WARN, "pipe",
+ "Warning: couldn't set flags for pipe write fd (errno=%d)\n",
+ errno);
+ return false;
+ }
+#endif
+
+ mWriteNonBlocking = val;
+ return true;
+}
+
+/*
+ * Specify whether a file descriptor can be inherited by a child process.
+ * Under Linux this means setting the close-on-exec flag, under Windows
+ * this is SetHandleInformation(HANDLE_FLAG_INHERIT).
+ */
+bool Pipe::disallowReadInherit(void)
+{
+ if (mReadHandle == kInvalidHandle)
+ return false;
+
+#if defined(HAVE_WIN32_IPC)
+ if (SetHandleInformation((HANDLE) mReadHandle, HANDLE_FLAG_INHERIT, 0) == 0)
+ return false;
+#else
+ if (fcntl((int) mReadHandle, F_SETFD, FD_CLOEXEC) != 0)
+ return false;
+#endif
+ return true;
+}
+bool Pipe::disallowWriteInherit(void)
+{
+ if (mWriteHandle == kInvalidHandle)
+ return false;
+
+#if defined(HAVE_WIN32_IPC)
+ if (SetHandleInformation((HANDLE) mWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0)
+ return false;
+#else
+ if (fcntl((int) mWriteHandle, F_SETFD, FD_CLOEXEC) != 0)
+ return false;
+#endif
+ return true;
+}
+
+/*
+ * Close read descriptor.
+ */
+bool Pipe::closeRead(void)
+{
+ if (mReadHandle == kInvalidHandle)
+ return false;
+
+#if defined(HAVE_WIN32_IPC)
+ if (mReadHandle != kInvalidHandle) {
+ if (!CloseHandle((HANDLE)mReadHandle)) {
+ LOG(LOG_WARN, "pipe", "failed closing read handle\n");
+ return false;
+ }
+ }
+#else
+ if (mReadHandle != kInvalidHandle) {
+ if (close((int) mReadHandle) != 0) {
+ LOG(LOG_WARN, "pipe", "failed closing read fd\n");
+ return false;
+ }
+ }
+#endif
+ mReadHandle = kInvalidHandle;
+ return true;
+}
+
+/*
+ * Close write descriptor.
+ */
+bool Pipe::closeWrite(void)
+{
+ if (mWriteHandle == kInvalidHandle)
+ return false;
+
+#if defined(HAVE_WIN32_IPC)
+ if (mWriteHandle != kInvalidHandle) {
+ if (!CloseHandle((HANDLE)mWriteHandle)) {
+ LOG(LOG_WARN, "pipe", "failed closing write handle\n");
+ return false;
+ }
+ }
+#else
+ if (mWriteHandle != kInvalidHandle) {
+ if (close((int) mWriteHandle) != 0) {
+ LOG(LOG_WARN, "pipe", "failed closing write fd\n");
+ return false;
+ }
+ }
+#endif
+ mWriteHandle = kInvalidHandle;
+ return true;
+}
+
+/*
+ * Get the read handle.
+ */
+unsigned long Pipe::getReadHandle(void)
+{
+ assert(mReadHandle != kInvalidHandle);
+
+ return mReadHandle;
+}
+
+/*
+ * Get the write handle.
+ */
+unsigned long Pipe::getWriteHandle(void)
+{
+ assert(mWriteHandle != kInvalidHandle);
+
+ return mWriteHandle;
+}
+
diff --git a/libs/utils/ProcessState.cpp b/libs/utils/ProcessState.cpp
new file mode 100644
index 0000000..4567df6
--- /dev/null
+++ b/libs/utils/ProcessState.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2005 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 "ProcessState"
+
+#include <cutils/process_name.h>
+
+#include <utils/ProcessState.h>
+
+#include <utils/Atomic.h>
+#include <utils/BpBinder.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/IServiceManager.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include <private/utils/binder_module.h>
+#include <private/utils/Static.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#define BINDER_VM_SIZE (1*1024*1024)
+
+static bool gSingleProcess = false;
+
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// Global variables
+int mArgC;
+const char* const* mArgV;
+int mArgLen;
+
+class PoolThread : public Thread
+{
+public:
+ PoolThread(bool isMain)
+ : mIsMain(isMain)
+ {
+ }
+
+protected:
+ virtual bool threadLoop()
+ {
+ IPCThreadState::self()->joinThreadPool(mIsMain);
+ return false;
+ }
+
+ const bool mIsMain;
+};
+
+sp<ProcessState> ProcessState::self()
+{
+ if (gProcess != NULL) return gProcess;
+
+ AutoMutex _l(gProcessMutex);
+ if (gProcess == NULL) gProcess = new ProcessState;
+ return gProcess;
+}
+
+void ProcessState::setSingleProcess(bool singleProcess)
+{
+ gSingleProcess = singleProcess;
+}
+
+
+void ProcessState::setContextObject(const sp<IBinder>& object)
+{
+ setContextObject(object, String16("default"));
+}
+
+sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
+{
+ if (supportsProcesses()) {
+ return getStrongProxyForHandle(0);
+ } else {
+ return getContextObject(String16("default"), caller);
+ }
+}
+
+void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
+{
+ AutoMutex _l(mLock);
+ mContexts.add(name, object);
+}
+
+sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller)
+{
+ mLock.lock();
+ sp<IBinder> object(
+ mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL);
+ mLock.unlock();
+
+ //printf("Getting context object %s for %p\n", String8(name).string(), caller.get());
+
+ if (object != NULL) return object;
+
+ // Don't attempt to retrieve contexts if we manage them
+ if (mManagesContexts) {
+ LOGE("getContextObject(%s) failed, but we manage the contexts!\n",
+ String8(name).string());
+ return NULL;
+ }
+
+ IPCThreadState* ipc = IPCThreadState::self();
+ {
+ Parcel data, reply;
+ // no interface token on this magic transaction
+ data.writeString16(name);
+ data.writeStrongBinder(caller);
+ status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0);
+ if (result == NO_ERROR) {
+ object = reply.readStrongBinder();
+ }
+ }
+
+ ipc->flushCommands();
+
+ if (object != NULL) setContextObject(object, name);
+ return object;
+}
+
+bool ProcessState::supportsProcesses() const
+{
+ return mDriverFD >= 0;
+}
+
+void ProcessState::startThreadPool()
+{
+ AutoMutex _l(mLock);
+ if (!mThreadPoolStarted) {
+ mThreadPoolStarted = true;
+ spawnPooledThread(true);
+ }
+}
+
+bool ProcessState::isContextManager(void) const
+{
+ return mManagesContexts;
+}
+
+bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData)
+{
+ if (!mManagesContexts) {
+ AutoMutex _l(mLock);
+ mBinderContextCheckFunc = checkFunc;
+ mBinderContextUserData = userData;
+ if (mDriverFD >= 0) {
+ int dummy = 0;
+#if defined(HAVE_ANDROID_OS)
+ status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+#else
+ status_t result = INVALID_OPERATION;
+#endif
+ if (result == 0) {
+ mManagesContexts = true;
+ } else if (result == -1) {
+ mBinderContextCheckFunc = NULL;
+ mBinderContextUserData = NULL;
+ LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
+ }
+ } else {
+ // If there is no driver, our only world is the local
+ // process so we can always become the context manager there.
+ mManagesContexts = true;
+ }
+ }
+ return mManagesContexts;
+}
+
+ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
+{
+ const size_t N=mHandleToObject.size();
+ if (N <= (size_t)handle) {
+ handle_entry e;
+ e.binder = NULL;
+ e.refs = NULL;
+ status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
+ if (err < NO_ERROR) return NULL;
+ }
+ return &mHandleToObject.editItemAt(handle);
+}
+
+sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
+{
+ sp<IBinder> result;
+
+ AutoMutex _l(mLock);
+
+ handle_entry* e = lookupHandleLocked(handle);
+
+ if (e != NULL) {
+ // We need to create a new BpBinder if there isn't currently one, OR we
+ // are unable to acquire a weak reference on this current one. See comment
+ // in getWeakProxyForHandle() for more info about this.
+ IBinder* b = e->binder;
+ if (b == NULL || !e->refs->attemptIncWeak(this)) {
+ b = new BpBinder(handle);
+ e->binder = b;
+ if (b) e->refs = b->getWeakRefs();
+ result = b;
+ } else {
+ // This little bit of nastyness is to allow us to add a primary
+ // reference to the remote proxy when this team doesn't have one
+ // but another team is sending the handle to us.
+ result.force_set(b);
+ e->refs->decWeak(this);
+ }
+ }
+
+ return result;
+}
+
+wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
+{
+ wp<IBinder> result;
+
+ AutoMutex _l(mLock);
+
+ handle_entry* e = lookupHandleLocked(handle);
+
+ if (e != NULL) {
+ // We need to create a new BpBinder if there isn't currently one, OR we
+ // are unable to acquire a weak reference on this current one. The
+ // attemptIncWeak() is safe because we know the BpBinder destructor will always
+ // call expungeHandle(), which acquires the same lock we are holding now.
+ // We need to do this because there is a race condition between someone
+ // releasing a reference on this BpBinder, and a new reference on its handle
+ // arriving from the driver.
+ IBinder* b = e->binder;
+ if (b == NULL || !e->refs->attemptIncWeak(this)) {
+ b = new BpBinder(handle);
+ result = b;
+ e->binder = b;
+ if (b) e->refs = b->getWeakRefs();
+ } else {
+ result = b;
+ e->refs->decWeak(this);
+ }
+ }
+
+ return result;
+}
+
+void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
+{
+ AutoMutex _l(mLock);
+
+ handle_entry* e = lookupHandleLocked(handle);
+
+ // This handle may have already been replaced with a new BpBinder
+ // (if someone failed the AttemptIncWeak() above); we don't want
+ // to overwrite it.
+ if (e && e->binder == binder) e->binder = NULL;
+}
+
+void ProcessState::setArgs(int argc, const char* const argv[])
+{
+ mArgC = argc;
+ mArgV = (const char **)argv;
+
+ mArgLen = 0;
+ for (int i=0; i<argc; i++) {
+ mArgLen += strlen(argv[i]) + 1;
+ }
+ mArgLen--;
+}
+
+int ProcessState::getArgC() const
+{
+ return mArgC;
+}
+
+const char* const* ProcessState::getArgV() const
+{
+ return mArgV;
+}
+
+void ProcessState::setArgV0(const char* txt)
+{
+ if (mArgV != NULL) {
+ strncpy((char*)mArgV[0], txt, mArgLen);
+ set_process_name(txt);
+ }
+}
+
+void ProcessState::spawnPooledThread(bool isMain)
+{
+ if (mThreadPoolStarted) {
+ int32_t s = android_atomic_add(1, &mThreadPoolSeq);
+ char buf[32];
+ sprintf(buf, "Binder Thread #%d", s);
+ LOGV("Spawning new pooled thread, name=%s\n", buf);
+ sp<Thread> t = new PoolThread(isMain);
+ t->run(buf);
+ }
+}
+
+static int open_driver()
+{
+ if (gSingleProcess) {
+ return -1;
+ }
+
+ int fd = open("/dev/binder", O_RDWR);
+ if (fd >= 0) {
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ int vers;
+#if defined(HAVE_ANDROID_OS)
+ status_t result = ioctl(fd, BINDER_VERSION, &vers);
+#else
+ status_t result = -1;
+ errno = EPERM;
+#endif
+ if (result == -1) {
+ LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
+ close(fd);
+ fd = -1;
+ }
+ if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
+ LOGE("Binder driver protocol does not match user space protocol!");
+ close(fd);
+ fd = -1;
+ }
+#if defined(HAVE_ANDROID_OS)
+ size_t maxThreads = 15;
+ result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
+ if (result == -1) {
+ LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
+ }
+#endif
+
+ } else {
+ LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
+ }
+ return fd;
+}
+
+ProcessState::ProcessState()
+ : mDriverFD(open_driver())
+ , mVMStart(MAP_FAILED)
+ , mManagesContexts(false)
+ , mBinderContextCheckFunc(NULL)
+ , mBinderContextUserData(NULL)
+ , mThreadPoolStarted(false)
+ , mThreadPoolSeq(1)
+{
+ if (mDriverFD >= 0) {
+ // XXX Ideally, there should be a specific define for whether we
+ // have mmap (or whether we could possibly have the kernel module
+ // availabla).
+#if !defined(HAVE_WIN32_IPC)
+ // mmap the binder, providing a chunk of virtual address space to receive transactions.
+ mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
+ if (mVMStart == MAP_FAILED) {
+ // *sigh*
+ LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
+ close(mDriverFD);
+ mDriverFD = -1;
+ }
+#else
+ mDriverFD = -1;
+#endif
+ }
+ if (mDriverFD < 0) {
+ // Need to run without the driver, starting our own thread pool.
+ }
+}
+
+ProcessState::~ProcessState()
+{
+}
+
+}; // namespace android
diff --git a/libs/utils/README b/libs/utils/README
new file mode 100644
index 0000000..36a706d
--- /dev/null
+++ b/libs/utils/README
@@ -0,0 +1,14 @@
+Android Utility Function Library
+
+If you need a feature that is native to Linux but not present on other
+platforms, construct a platform-dependent implementation that shares
+the Linux interface. That way the actual device runs as "light" as
+possible.
+
+If that isn't feasible, create a system-independent interface and hide
+the details.
+
+The ultimate goal is *not* to create a super-duper platform abstraction
+layer. The goal is to provide an optimized solution for Linux with
+reasonable implementations for other platforms.
+
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
new file mode 100644
index 0000000..0bd1af4
--- /dev/null
+++ b/libs/utils/RefBase.cpp
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2005 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 "RefBase"
+
+#include <utils/RefBase.h>
+
+#include <utils/Atomic.h>
+#include <utils/CallStack.h>
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <typeinfo>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+// compile with refcounting debugging enabled
+#define DEBUG_REFS 0
+#define DEBUG_REFS_ENABLED_BY_DEFAULT 1
+#define DEBUG_REFS_CALLSTACK_ENABLED 1
+
+// log all reference counting operations
+#define PRINT_REFS 0
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+#define INITIAL_STRONG_VALUE (1<<28)
+
+// ---------------------------------------------------------------------------
+
+class RefBase::weakref_impl : public RefBase::weakref_type
+{
+public:
+ volatile int32_t mStrong;
+ volatile int32_t mWeak;
+ RefBase* const mBase;
+ volatile int32_t mFlags;
+
+
+#if !DEBUG_REFS
+
+ weakref_impl(RefBase* base)
+ : mStrong(INITIAL_STRONG_VALUE)
+ , mWeak(0)
+ , mBase(base)
+ , mFlags(0)
+ {
+ }
+
+ void addStrongRef(const void* /*id*/) { }
+ void removeStrongRef(const void* /*id*/) { }
+ void addWeakRef(const void* /*id*/) { }
+ void removeWeakRef(const void* /*id*/) { }
+ void printRefs() const { }
+ void trackMe(bool, bool) { }
+
+#else
+
+ weakref_impl(RefBase* base)
+ : mStrong(INITIAL_STRONG_VALUE)
+ , mWeak(0)
+ , mBase(base)
+ , mFlags(0)
+ , mStrongRefs(NULL)
+ , mWeakRefs(NULL)
+ , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
+ , mRetain(false)
+ {
+ //LOGI("NEW weakref_impl %p for RefBase %p", this, base);
+ }
+
+ ~weakref_impl()
+ {
+ LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
+ LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
+ }
+
+ void addStrongRef(const void* id)
+ {
+ addRef(&mStrongRefs, id, mStrong);
+ }
+
+ void removeStrongRef(const void* id)
+ {
+ if (!mRetain)
+ removeRef(&mStrongRefs, id);
+ else
+ addRef(&mStrongRefs, id, -mStrong);
+ }
+
+ void addWeakRef(const void* id)
+ {
+ addRef(&mWeakRefs, id, mWeak);
+ }
+
+ void removeWeakRef(const void* id)
+ {
+ if (!mRetain)
+ removeRef(&mWeakRefs, id);
+ else
+ addRef(&mWeakRefs, id, -mWeak);
+ }
+
+ void trackMe(bool track, bool retain)
+ {
+ mTrackEnabled = track;
+ mRetain = retain;
+ }
+
+ void printRefs() const
+ {
+ String8 text;
+
+ {
+ AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex);
+
+ char buf[128];
+ sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
+ text.append(buf);
+ printRefsLocked(&text, mStrongRefs);
+ sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
+ text.append(buf);
+ printRefsLocked(&text, mWeakRefs);
+ }
+
+ {
+ char name[100];
+ snprintf(name, 100, "/data/%p.stack", this);
+ int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
+ if (rc >= 0) {
+ write(rc, text.string(), text.length());
+ close(rc);
+ LOGD("STACK TRACE for %p saved in %s", this, name);
+ }
+ else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
+ name, strerror(errno));
+ }
+ }
+
+private:
+ struct ref_entry
+ {
+ ref_entry* next;
+ const void* id;
+#if DEBUG_REFS_CALLSTACK_ENABLED
+ CallStack stack;
+#endif
+ int32_t ref;
+ };
+
+ void addRef(ref_entry** refs, const void* id, int32_t mRef)
+ {
+ if (mTrackEnabled) {
+ AutoMutex _l(mMutex);
+ ref_entry* ref = new ref_entry;
+ // Reference count at the time of the snapshot, but before the
+ // update. Positive value means we increment, negative--we
+ // decrement the reference count.
+ ref->ref = mRef;
+ ref->id = id;
+#if DEBUG_REFS_CALLSTACK_ENABLED
+ ref->stack.update(2);
+#endif
+
+ ref->next = *refs;
+ *refs = ref;
+ }
+ }
+
+ void removeRef(ref_entry** refs, const void* id)
+ {
+ if (mTrackEnabled) {
+ AutoMutex _l(mMutex);
+
+ ref_entry* ref = *refs;
+ while (ref != NULL) {
+ if (ref->id == id) {
+ *refs = ref->next;
+ delete ref;
+ return;
+ }
+
+ refs = &ref->next;
+ ref = *refs;
+ }
+
+ LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
+ id, mBase, this);
+ }
+ }
+
+ void printRefsLocked(String8* out, const ref_entry* refs) const
+ {
+ char buf[128];
+ while (refs) {
+ char inc = refs->ref >= 0 ? '+' : '-';
+ sprintf(buf, "\t%c ID %p (ref %d):\n",
+ inc, refs->id, refs->ref);
+ out->append(buf);
+#if DEBUG_REFS_CALLSTACK_ENABLED
+ out->append(refs->stack.toString("\t\t"));
+#else
+ out->append("\t\t(call stacks disabled)");
+#endif
+ refs = refs->next;
+ }
+ }
+
+ Mutex mMutex;
+ ref_entry* mStrongRefs;
+ ref_entry* mWeakRefs;
+
+ bool mTrackEnabled;
+ // Collect stack traces on addref and removeref, instead of deleting the stack references
+ // on removeref that match the address ones.
+ bool mRetain;
+
+#if 0
+ void addRef(KeyedVector<const void*, int32_t>* refs, const void* id)
+ {
+ AutoMutex _l(mMutex);
+ ssize_t i = refs->indexOfKey(id);
+ if (i >= 0) {
+ ++(refs->editValueAt(i));
+ } else {
+ i = refs->add(id, 1);
+ }
+ }
+
+ void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id)
+ {
+ AutoMutex _l(mMutex);
+ ssize_t i = refs->indexOfKey(id);
+ LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id);
+ if (i >= 0) {
+ int32_t val = --(refs->editValueAt(i));
+ if (val == 0) {
+ refs->removeItemsAt(i);
+ }
+ }
+ }
+
+ void printRefs(const KeyedVector<const void*, int32_t>& refs)
+ {
+ const size_t N=refs.size();
+ for (size_t i=0; i<N; i++) {
+ printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i));
+ }
+ }
+
+ mutable Mutex mMutex;
+ KeyedVector<const void*, int32_t> mStrongRefs;
+ KeyedVector<const void*, int32_t> mWeakRefs;
+#endif
+
+#endif
+};
+
+// ---------------------------------------------------------------------------
+
+void RefBase::incStrong(const void* id) const
+{
+ weakref_impl* const refs = mRefs;
+ refs->addWeakRef(id);
+ refs->incWeak(id);
+
+ refs->addStrongRef(id);
+ const int32_t c = android_atomic_inc(&refs->mStrong);
+ LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
+#if PRINT_REFS
+ LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+ if (c != INITIAL_STRONG_VALUE) {
+ return;
+ }
+
+ android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
+ const_cast<RefBase*>(this)->onFirstRef();
+}
+
+void RefBase::decStrong(const void* id) const
+{
+ weakref_impl* const refs = mRefs;
+ refs->removeStrongRef(id);
+ const int32_t c = android_atomic_dec(&refs->mStrong);
+#if PRINT_REFS
+ LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+ LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
+ if (c == 1) {
+ const_cast<RefBase*>(this)->onLastStrongRef(id);
+ if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
+ delete this;
+ }
+ }
+ refs->removeWeakRef(id);
+ refs->decWeak(id);
+}
+
+void RefBase::forceIncStrong(const void* id) const
+{
+ weakref_impl* const refs = mRefs;
+ refs->addWeakRef(id);
+ refs->incWeak(id);
+
+ refs->addStrongRef(id);
+ const int32_t c = android_atomic_inc(&refs->mStrong);
+ LOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
+ refs);
+#if PRINT_REFS
+ LOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+
+ switch (c) {
+ case INITIAL_STRONG_VALUE:
+ android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
+ // fall through...
+ case 0:
+ const_cast<RefBase*>(this)->onFirstRef();
+ }
+}
+
+int32_t RefBase::getStrongCount() const
+{
+ return mRefs->mStrong;
+}
+
+
+
+RefBase* RefBase::weakref_type::refBase() const
+{
+ return static_cast<const weakref_impl*>(this)->mBase;
+}
+
+void RefBase::weakref_type::incWeak(const void* id)
+{
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+ impl->addWeakRef(id);
+ const int32_t c = android_atomic_inc(&impl->mWeak);
+ LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
+}
+
+void RefBase::weakref_type::decWeak(const void* id)
+{
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+ impl->removeWeakRef(id);
+ const int32_t c = android_atomic_dec(&impl->mWeak);
+ LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
+ if (c != 1) return;
+
+ if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
+ if (impl->mStrong == INITIAL_STRONG_VALUE)
+ delete impl->mBase;
+ else {
+// LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
+ delete impl;
+ }
+ } else {
+ impl->mBase->onLastWeakRef(id);
+ if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
+ delete impl->mBase;
+ }
+ }
+}
+
+bool RefBase::weakref_type::attemptIncStrong(const void* id)
+{
+ incWeak(id);
+
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+
+ int32_t curCount = impl->mStrong;
+ LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
+ this);
+ while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
+ if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
+ break;
+ }
+ curCount = impl->mStrong;
+ }
+
+ if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
+ bool allow;
+ if (curCount == INITIAL_STRONG_VALUE) {
+ // Attempting to acquire first strong reference... this is allowed
+ // if the object does NOT have a longer lifetime (meaning the
+ // implementation doesn't need to see this), or if the implementation
+ // allows it to happen.
+ allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
+ || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
+ } else {
+ // Attempting to revive the object... this is allowed
+ // if the object DOES have a longer lifetime (so we can safely
+ // call the object with only a weak ref) and the implementation
+ // allows it to happen.
+ allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
+ && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
+ }
+ if (!allow) {
+ decWeak(id);
+ return false;
+ }
+ curCount = android_atomic_inc(&impl->mStrong);
+
+ // If the strong reference count has already been incremented by
+ // someone else, the implementor of onIncStrongAttempted() is holding
+ // an unneeded reference. So call onLastStrongRef() here to remove it.
+ // (No, this is not pretty.) Note that we MUST NOT do this if we
+ // are in fact acquiring the first reference.
+ if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
+ impl->mBase->onLastStrongRef(id);
+ }
+ }
+
+ impl->addWeakRef(id);
+ impl->addStrongRef(id);
+
+#if PRINT_REFS
+ LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
+#endif
+
+ if (curCount == INITIAL_STRONG_VALUE) {
+ android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
+ impl->mBase->onFirstRef();
+ }
+
+ return true;
+}
+
+bool RefBase::weakref_type::attemptIncWeak(const void* id)
+{
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+
+ int32_t curCount = impl->mWeak;
+ LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
+ this);
+ while (curCount > 0) {
+ if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
+ break;
+ }
+ curCount = impl->mWeak;
+ }
+
+ if (curCount > 0) {
+ impl->addWeakRef(id);
+ }
+
+ return curCount > 0;
+}
+
+int32_t RefBase::weakref_type::getWeakCount() const
+{
+ return static_cast<const weakref_impl*>(this)->mWeak;
+}
+
+void RefBase::weakref_type::printRefs() const
+{
+ static_cast<const weakref_impl*>(this)->printRefs();
+}
+
+void RefBase::weakref_type::trackMe(bool enable, bool retain)
+{
+ static_cast<const weakref_impl*>(this)->trackMe(enable, retain);
+}
+
+RefBase::weakref_type* RefBase::createWeak(const void* id) const
+{
+ mRefs->incWeak(id);
+ return mRefs;
+}
+
+RefBase::weakref_type* RefBase::getWeakRefs() const
+{
+ return mRefs;
+}
+
+RefBase::RefBase()
+ : mRefs(new weakref_impl(this))
+{
+// LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
+}
+
+RefBase::~RefBase()
+{
+// LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);
+ if (mRefs->mWeak == 0) {
+// LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);
+ delete mRefs;
+ }
+}
+
+void RefBase::extendObjectLifetime(int32_t mode)
+{
+ android_atomic_or(mode, &mRefs->mFlags);
+}
+
+void RefBase::onFirstRef()
+{
+}
+
+void RefBase::onLastStrongRef(const void* /*id*/)
+{
+}
+
+bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+ return (flags&FIRST_INC_STRONG) ? true : false;
+}
+
+void RefBase::onLastWeakRef(const void* /*id*/)
+{
+}
+
+}; // namespace android
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
new file mode 100644
index 0000000..a5fe9fb
--- /dev/null
+++ b/libs/utils/ResourceTypes.cpp
@@ -0,0 +1,3969 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ResourceType"
+//#define LOG_NDEBUG 0
+
+#include <utils/Atomic.h>
+#include <utils/ByteOrder.h>
+#include <utils/Debug.h>
+#include <utils/ResourceTypes.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/TextOutput.h>
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#ifndef INT32_MAX
+#define INT32_MAX ((int32_t)(2147483647))
+#endif
+
+#define POOL_NOISY(x) //x
+#define XML_NOISY(x) //x
+#define TABLE_NOISY(x) //x
+#define TABLE_GETENTRY(x) //x
+#define TABLE_SUPER_NOISY(x) //x
+#define LOAD_TABLE_NOISY(x) //x
+
+namespace android {
+
+#ifdef HAVE_WINSOCK
+#undef nhtol
+#undef htonl
+
+#ifdef HAVE_LITTLE_ENDIAN
+#define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
+#define htonl(x) ntohl(x)
+#define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
+#define htons(x) ntohs(x)
+#else
+#define ntohl(x) (x)
+#define htonl(x) (x)
+#define ntohs(x) (x)
+#define htons(x) (x)
+#endif
+#endif
+
+static void printToLogFunc(void* cookie, const char* txt)
+{
+ LOGV("%s", txt);
+}
+
+// Standard C isspace() is only required to look at the low byte of its input, so
+// produces incorrect results for UTF-16 characters. For safety's sake, assume that
+// any high-byte UTF-16 code point is not whitespace.
+inline int isspace16(char16_t c) {
+ return (c < 0x0080 && isspace(c));
+}
+
+// range checked; guaranteed to NUL-terminate within the stated number of available slots
+// NOTE: if this truncates the dst string due to running out of space, no attempt is
+// made to avoid splitting surrogate pairs.
+static void strcpy16_dtoh(uint16_t* dst, const uint16_t* src, size_t avail)
+{
+ uint16_t* last = dst + avail - 1;
+ while (*src && (dst < last)) {
+ char16_t s = dtohs(*src);
+ *dst++ = s;
+ src++;
+ }
+ *dst = 0;
+}
+
+static status_t validate_chunk(const ResChunk_header* chunk,
+ size_t minSize,
+ const uint8_t* dataEnd,
+ const char* name)
+{
+ const uint16_t headerSize = dtohs(chunk->headerSize);
+ const uint32_t size = dtohl(chunk->size);
+
+ if (headerSize >= minSize) {
+ if (headerSize <= size) {
+ if (((headerSize|size)&0x3) == 0) {
+ if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) {
+ return NO_ERROR;
+ }
+ LOGW("%s data size %p extends beyond resource end %p.",
+ name, (void*)size,
+ (void*)(dataEnd-((const uint8_t*)chunk)));
+ return BAD_TYPE;
+ }
+ LOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
+ name, (int)size, (int)headerSize);
+ return BAD_TYPE;
+ }
+ LOGW("%s size %p is smaller than header size %p.",
+ name, (void*)size, (void*)(int)headerSize);
+ return BAD_TYPE;
+ }
+ LOGW("%s header size %p is too small.",
+ name, (void*)(int)headerSize);
+ return BAD_TYPE;
+}
+
+inline void Res_value::copyFrom_dtoh(const Res_value& src)
+{
+ size = dtohs(src.size);
+ res0 = src.res0;
+ dataType = src.dataType;
+ data = dtohl(src.data);
+}
+
+void Res_png_9patch::deviceToFile()
+{
+ for (int i = 0; i < numXDivs; i++) {
+ xDivs[i] = htonl(xDivs[i]);
+ }
+ for (int i = 0; i < numYDivs; i++) {
+ yDivs[i] = htonl(yDivs[i]);
+ }
+ paddingLeft = htonl(paddingLeft);
+ paddingRight = htonl(paddingRight);
+ paddingTop = htonl(paddingTop);
+ paddingBottom = htonl(paddingBottom);
+ for (int i=0; i<numColors; i++) {
+ colors[i] = htonl(colors[i]);
+ }
+}
+
+void Res_png_9patch::fileToDevice()
+{
+ for (int i = 0; i < numXDivs; i++) {
+ xDivs[i] = ntohl(xDivs[i]);
+ }
+ for (int i = 0; i < numYDivs; i++) {
+ yDivs[i] = ntohl(yDivs[i]);
+ }
+ paddingLeft = ntohl(paddingLeft);
+ paddingRight = ntohl(paddingRight);
+ paddingTop = ntohl(paddingTop);
+ paddingBottom = ntohl(paddingBottom);
+ for (int i=0; i<numColors; i++) {
+ colors[i] = ntohl(colors[i]);
+ }
+}
+
+size_t Res_png_9patch::serializedSize()
+{
+ return sizeof(Res_png_9patch)
+ + numXDivs * sizeof(int32_t)
+ + numYDivs * sizeof(int32_t)
+ + numColors * sizeof(uint32_t);
+}
+
+void* Res_png_9patch::serialize()
+{
+ void* newData = malloc(serializedSize());
+ serialize(newData);
+ return newData;
+}
+
+void Res_png_9patch::serialize(void * outData)
+{
+ char* data = (char*) outData;
+ memmove(data, this, sizeof(Res_png_9patch));
+ data += sizeof(Res_png_9patch);
+ memmove(data, this->xDivs, numXDivs * sizeof(int32_t));
+ data += numXDivs * sizeof(int32_t);
+ memmove(data, this->yDivs, numYDivs * sizeof(int32_t));
+ data += numYDivs * sizeof(int32_t);
+ memmove(data, this->colors, numColors * sizeof(uint32_t));
+}
+
+Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
+{
+ deserialize(inData, (Res_png_9patch*) inData);
+ return (Res_png_9patch*) inData;
+}
+
+void Res_png_9patch::deserialize(const void* inData, Res_png_9patch* outData) {
+ Res_png_9patch* patch = (Res_png_9patch*) inData;
+ if (inData != outData) {
+ memcpy(outData, inData, patch->serializedSize());
+ }
+ outData->wasDeserialized = true;
+ char* data = (char*)outData;
+ data += sizeof(Res_png_9patch);
+ outData->xDivs = (int32_t*) data;
+ data += patch->numXDivs * sizeof(int32_t);
+ outData->yDivs = (int32_t*) data;
+ data += patch->numYDivs * sizeof(int32_t);
+ outData->colors = (uint32_t*) data;
+}
+
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+
+ResStringPool::ResStringPool()
+ : mError(NO_INIT), mOwnedData(NULL)
+{
+}
+
+ResStringPool::ResStringPool(const void* data, size_t size, bool copyData)
+ : mError(NO_INIT), mOwnedData(NULL)
+{
+ setTo(data, size, copyData);
+}
+
+ResStringPool::~ResStringPool()
+{
+ uninit();
+}
+
+status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
+{
+ if (!data || !size) {
+ return (mError=BAD_TYPE);
+ }
+
+ uninit();
+
+ const bool notDeviceEndian = htods(0xf0) != 0xf0;
+
+ if (copyData || notDeviceEndian) {
+ mOwnedData = malloc(size);
+ if (mOwnedData == NULL) {
+ return (mError=NO_MEMORY);
+ }
+ memcpy(mOwnedData, data, size);
+ data = mOwnedData;
+ }
+
+ mHeader = (const ResStringPool_header*)data;
+
+ if (notDeviceEndian) {
+ ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader);
+ h->header.headerSize = dtohs(mHeader->header.headerSize);
+ h->header.type = dtohs(mHeader->header.type);
+ h->header.size = dtohl(mHeader->header.size);
+ h->stringCount = dtohl(mHeader->stringCount);
+ h->styleCount = dtohl(mHeader->styleCount);
+ h->flags = dtohl(mHeader->flags);
+ h->stringsStart = dtohl(mHeader->stringsStart);
+ h->stylesStart = dtohl(mHeader->stylesStart);
+ }
+
+ if (mHeader->header.headerSize > mHeader->header.size
+ || mHeader->header.size > size) {
+ LOGW("Bad string block: header size %d or total size %d is larger than data size %d\n",
+ (int)mHeader->header.headerSize, (int)mHeader->header.size, (int)size);
+ return (mError=BAD_TYPE);
+ }
+ mSize = mHeader->header.size;
+ mEntries = (const uint32_t*)
+ (((const uint8_t*)data)+mHeader->header.headerSize);
+
+ if (mHeader->stringCount > 0) {
+ if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount) // uint32 overflow?
+ || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t)))
+ > size) {
+ LOGW("Bad string block: entry of %d items extends past data size %d\n",
+ (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))),
+ (int)size);
+ return (mError=BAD_TYPE);
+ }
+ mStrings = (const char16_t*)
+ (((const uint8_t*)data)+mHeader->stringsStart);
+ if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) {
+ LOGW("Bad string block: string pool starts at %d, after total size %d\n",
+ (int)mHeader->stringsStart, (int)mHeader->header.size);
+ return (mError=BAD_TYPE);
+ }
+ if (mHeader->styleCount == 0) {
+ mStringPoolSize =
+ (mHeader->header.size-mHeader->stringsStart)/sizeof(uint16_t);
+ } else {
+ // check invariant: styles follow the strings
+ if (mHeader->stylesStart <= mHeader->stringsStart) {
+ LOGW("Bad style block: style block starts at %d, before strings at %d\n",
+ (int)mHeader->stylesStart, (int)mHeader->stringsStart);
+ return (mError=BAD_TYPE);
+ }
+ mStringPoolSize =
+ (mHeader->stylesStart-mHeader->stringsStart)/sizeof(uint16_t);
+ }
+
+ // check invariant: stringCount > 0 requires a string pool to exist
+ if (mStringPoolSize == 0) {
+ LOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount);
+ return (mError=BAD_TYPE);
+ }
+
+ if (notDeviceEndian) {
+ size_t i;
+ uint32_t* e = const_cast<uint32_t*>(mEntries);
+ for (i=0; i<mHeader->stringCount; i++) {
+ e[i] = dtohl(mEntries[i]);
+ }
+ char16_t* s = const_cast<char16_t*>(mStrings);
+ for (i=0; i<mStringPoolSize; i++) {
+ s[i] = dtohs(mStrings[i]);
+ }
+ }
+
+ if (mStrings[mStringPoolSize-1] != 0) {
+ LOGW("Bad string block: last string is not 0-terminated\n");
+ return (mError=BAD_TYPE);
+ }
+ } else {
+ mStrings = NULL;
+ mStringPoolSize = 0;
+ }
+
+ if (mHeader->styleCount > 0) {
+ mEntryStyles = mEntries + mHeader->stringCount;
+ // invariant: integer overflow in calculating mEntryStyles
+ if (mEntryStyles < mEntries) {
+ LOGW("Bad string block: integer overflow finding styles\n");
+ return (mError=BAD_TYPE);
+ }
+
+ if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
+ LOGW("Bad string block: entry of %d styles extends past data size %d\n",
+ (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader),
+ (int)size);
+ return (mError=BAD_TYPE);
+ }
+ mStyles = (const uint32_t*)
+ (((const uint8_t*)data)+mHeader->stylesStart);
+ if (mHeader->stylesStart >= mHeader->header.size) {
+ LOGW("Bad string block: style pool starts %d, after total size %d\n",
+ (int)mHeader->stylesStart, (int)mHeader->header.size);
+ return (mError=BAD_TYPE);
+ }
+ mStylePoolSize =
+ (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t);
+
+ if (notDeviceEndian) {
+ size_t i;
+ uint32_t* e = const_cast<uint32_t*>(mEntryStyles);
+ for (i=0; i<mHeader->styleCount; i++) {
+ e[i] = dtohl(mEntryStyles[i]);
+ }
+ uint32_t* s = const_cast<uint32_t*>(mStyles);
+ for (i=0; i<mStylePoolSize; i++) {
+ s[i] = dtohl(mStyles[i]);
+ }
+ }
+
+ const ResStringPool_span endSpan = {
+ { htodl(ResStringPool_span::END) },
+ htodl(ResStringPool_span::END), htodl(ResStringPool_span::END)
+ };
+ if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
+ &endSpan, sizeof(endSpan)) != 0) {
+ LOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
+ return (mError=BAD_TYPE);
+ }
+ } else {
+ mEntryStyles = NULL;
+ mStyles = NULL;
+ mStylePoolSize = 0;
+ }
+
+ return (mError=NO_ERROR);
+}
+
+status_t ResStringPool::getError() const
+{
+ return mError;
+}
+
+void ResStringPool::uninit()
+{
+ mError = NO_INIT;
+ if (mOwnedData) {
+ free(mOwnedData);
+ mOwnedData = NULL;
+ }
+}
+
+const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const
+{
+ if (mError == NO_ERROR && idx < mHeader->stringCount) {
+ const uint32_t off = (mEntries[idx]/sizeof(uint16_t));
+ if (off < (mStringPoolSize-1)) {
+ const char16_t* str = mStrings+off;
+ *outLen = *str;
+ if ((*str)&0x8000) {
+ str++;
+ *outLen = (((*outLen)&0x7fff)<<16) + *str;
+ }
+ if ((uint32_t)(str+1+*outLen-mStrings) < mStringPoolSize) {
+ return str+1;
+ } else {
+ LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
+ (int)idx, (int)(str+1+*outLen-mStrings), (int)mStringPoolSize);
+ }
+ } else {
+ LOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
+ (int)idx, (int)(off*sizeof(uint16_t)),
+ (int)(mStringPoolSize*sizeof(uint16_t)));
+ }
+ }
+ return NULL;
+}
+
+const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
+{
+ return styleAt(ref.index);
+}
+
+const ResStringPool_span* ResStringPool::styleAt(size_t idx) const
+{
+ if (mError == NO_ERROR && idx < mHeader->styleCount) {
+ const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t));
+ if (off < mStylePoolSize) {
+ return (const ResStringPool_span*)(mStyles+off);
+ } else {
+ LOGW("Bad string block: style #%d entry is at %d, past end at %d\n",
+ (int)idx, (int)(off*sizeof(uint32_t)),
+ (int)(mStylePoolSize*sizeof(uint32_t)));
+ }
+ }
+ return NULL;
+}
+
+ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
+{
+ if (mError != NO_ERROR) {
+ return mError;
+ }
+
+ size_t len;
+
+ if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
+ // Do a binary search for the string...
+ ssize_t l = 0;
+ ssize_t h = mHeader->stringCount-1;
+
+ ssize_t mid;
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const char16_t* s = stringAt(mid, &len);
+ int c = s ? strzcmp16(s, len, str, strLen) : -1;
+ POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+ String8(str).string(),
+ String8(s).string(),
+ c, (int)l, (int)mid, (int)h));
+ if (c == 0) {
+ return mid;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ } else {
+ // It is unusual to get the ID from an unsorted string block...
+ // most often this happens because we want to get IDs for style
+ // span tags; since those always appear at the end of the string
+ // block, start searching at the back.
+ for (int i=mHeader->stringCount-1; i>=0; i--) {
+ const char16_t* s = stringAt(i, &len);
+ POOL_NOISY(printf("Looking for %s, at %s, i=%d\n",
+ String8(str, strLen).string(),
+ String8(s).string(),
+ i));
+ if (s && strzcmp16(s, len, str, strLen) == 0) {
+ return i;
+ }
+ }
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+size_t ResStringPool::size() const
+{
+ return (mError == NO_ERROR) ? mHeader->stringCount : 0;
+}
+
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+
+ResXMLParser::ResXMLParser(const ResXMLTree& tree)
+ : mTree(tree), mEventCode(BAD_DOCUMENT)
+{
+}
+
+void ResXMLParser::restart()
+{
+ mCurNode = NULL;
+ mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT;
+}
+
+ResXMLParser::event_code_t ResXMLParser::getEventType() const
+{
+ return mEventCode;
+}
+
+ResXMLParser::event_code_t ResXMLParser::next()
+{
+ if (mEventCode == START_DOCUMENT) {
+ mCurNode = mTree.mRootNode;
+ mCurExt = mTree.mRootExt;
+ return (mEventCode=mTree.mRootCode);
+ } else if (mEventCode >= FIRST_CHUNK_CODE) {
+ return nextNode();
+ }
+ return mEventCode;
+}
+
+const int32_t ResXMLParser::getCommentID() const
+{
+ return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
+}
+
+const uint16_t* ResXMLParser::getComment(size_t* outLen) const
+{
+ int32_t id = getCommentID();
+ return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const uint32_t ResXMLParser::getLineNumber() const
+{
+ return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
+}
+
+const int32_t ResXMLParser::getTextID() const
+{
+ if (mEventCode == TEXT) {
+ return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
+ }
+ return -1;
+}
+
+const uint16_t* ResXMLParser::getText(size_t* outLen) const
+{
+ int32_t id = getTextID();
+ return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+ssize_t ResXMLParser::getTextValue(Res_value* outValue) const
+{
+ if (mEventCode == TEXT) {
+ outValue->copyFrom_dtoh(((const ResXMLTree_cdataExt*)mCurExt)->typedData);
+ return sizeof(Res_value);
+ }
+ return BAD_TYPE;
+}
+
+const int32_t ResXMLParser::getNamespacePrefixID() const
+{
+ if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
+ return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index);
+ }
+ return -1;
+}
+
+const uint16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const
+{
+ int32_t id = getNamespacePrefixID();
+ //printf("prefix=%d event=%p\n", id, mEventCode);
+ return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const int32_t ResXMLParser::getNamespaceUriID() const
+{
+ if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
+ return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index);
+ }
+ return -1;
+}
+
+const uint16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const
+{
+ int32_t id = getNamespaceUriID();
+ //printf("uri=%d event=%p\n", id, mEventCode);
+ return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const int32_t ResXMLParser::getElementNamespaceID() const
+{
+ if (mEventCode == START_TAG) {
+ return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
+ }
+ if (mEventCode == END_TAG) {
+ return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index);
+ }
+ return -1;
+}
+
+const uint16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
+{
+ int32_t id = getElementNamespaceID();
+ return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const int32_t ResXMLParser::getElementNameID() const
+{
+ if (mEventCode == START_TAG) {
+ return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index);
+ }
+ if (mEventCode == END_TAG) {
+ return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->name.index);
+ }
+ return -1;
+}
+
+const uint16_t* ResXMLParser::getElementName(size_t* outLen) const
+{
+ int32_t id = getElementNameID();
+ return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+size_t ResXMLParser::getAttributeCount() const
+{
+ if (mEventCode == START_TAG) {
+ return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount);
+ }
+ return 0;
+}
+
+const int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
+{
+ if (mEventCode == START_TAG) {
+ const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+ if (idx < dtohs(tag->attributeCount)) {
+ const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+ (((const uint8_t*)tag)
+ + dtohs(tag->attributeStart)
+ + (dtohs(tag->attributeSize)*idx));
+ return dtohl(attr->ns.index);
+ }
+ }
+ return -2;
+}
+
+const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const
+{
+ int32_t id = getAttributeNamespaceID(idx);
+ //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode);
+ //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
+ return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const int32_t ResXMLParser::getAttributeNameID(size_t idx) const
+{
+ if (mEventCode == START_TAG) {
+ const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+ if (idx < dtohs(tag->attributeCount)) {
+ const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+ (((const uint8_t*)tag)
+ + dtohs(tag->attributeStart)
+ + (dtohs(tag->attributeSize)*idx));
+ return dtohl(attr->name.index);
+ }
+ }
+ return -1;
+}
+
+const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
+{
+ int32_t id = getAttributeNameID(idx);
+ //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode);
+ //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
+ return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+const uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
+{
+ int32_t id = getAttributeNameID(idx);
+ if (id >= 0 && (size_t)id < mTree.mNumResIds) {
+ return dtohl(mTree.mResIds[id]);
+ }
+ return 0;
+}
+
+const int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
+{
+ if (mEventCode == START_TAG) {
+ const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+ if (idx < dtohs(tag->attributeCount)) {
+ const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+ (((const uint8_t*)tag)
+ + dtohs(tag->attributeStart)
+ + (dtohs(tag->attributeSize)*idx));
+ return dtohl(attr->rawValue.index);
+ }
+ }
+ return -1;
+}
+
+const uint16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
+{
+ int32_t id = getAttributeValueStringID(idx);
+ //XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id));
+ return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+}
+
+int32_t ResXMLParser::getAttributeDataType(size_t idx) const
+{
+ if (mEventCode == START_TAG) {
+ const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+ if (idx < dtohs(tag->attributeCount)) {
+ const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+ (((const uint8_t*)tag)
+ + dtohs(tag->attributeStart)
+ + (dtohs(tag->attributeSize)*idx));
+ return attr->typedValue.dataType;
+ }
+ }
+ return Res_value::TYPE_NULL;
+}
+
+int32_t ResXMLParser::getAttributeData(size_t idx) const
+{
+ if (mEventCode == START_TAG) {
+ const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+ if (idx < dtohs(tag->attributeCount)) {
+ const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+ (((const uint8_t*)tag)
+ + dtohs(tag->attributeStart)
+ + (dtohs(tag->attributeSize)*idx));
+ return dtohl(attr->typedValue.data);
+ }
+ }
+ return 0;
+}
+
+ssize_t ResXMLParser::getAttributeValue(size_t idx, Res_value* outValue) const
+{
+ if (mEventCode == START_TAG) {
+ const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
+ if (idx < dtohs(tag->attributeCount)) {
+ const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
+ (((const uint8_t*)tag)
+ + dtohs(tag->attributeStart)
+ + (dtohs(tag->attributeSize)*idx));
+ outValue->copyFrom_dtoh(attr->typedValue);
+ return sizeof(Res_value);
+ }
+ }
+ return BAD_TYPE;
+}
+
+ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const
+{
+ String16 nsStr(ns != NULL ? ns : "");
+ String16 attrStr(attr);
+ return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0,
+ attrStr.string(), attrStr.size());
+}
+
+ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
+ const char16_t* attr, size_t attrLen) const
+{
+ if (mEventCode == START_TAG) {
+ const size_t N = getAttributeCount();
+ for (size_t i=0; i<N; i++) {
+ size_t curNsLen, curAttrLen;
+ const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
+ const char16_t* curAttr = getAttributeName(i, &curAttrLen);
+ //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n",
+ // i, ns, attr, curNs, curAttr);
+ //printf(" --> attr=%s, curAttr=%s\n",
+ // String8(attr).string(), String8(curAttr).string());
+ if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) {
+ if (ns == NULL) {
+ if (curNs == NULL) return i;
+ } else if (curNs != NULL) {
+ //printf(" --> ns=%s, curNs=%s\n",
+ // String8(ns).string(), String8(curNs).string());
+ if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i;
+ }
+ }
+ }
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+ssize_t ResXMLParser::indexOfID() const
+{
+ if (mEventCode == START_TAG) {
+ const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->idIndex);
+ if (idx > 0) return (idx-1);
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t ResXMLParser::indexOfClass() const
+{
+ if (mEventCode == START_TAG) {
+ const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->classIndex);
+ if (idx > 0) return (idx-1);
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t ResXMLParser::indexOfStyle() const
+{
+ if (mEventCode == START_TAG) {
+ const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->styleIndex);
+ if (idx > 0) return (idx-1);
+ }
+ return NAME_NOT_FOUND;
+}
+
+ResXMLParser::event_code_t ResXMLParser::nextNode()
+{
+ if (mEventCode < 0) {
+ return mEventCode;
+ }
+
+ do {
+ const ResXMLTree_node* next = (const ResXMLTree_node*)
+ (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size));
+ //LOGW("Next node: prev=%p, next=%p\n", mCurNode, next);
+
+ if (((const uint8_t*)next) >= mTree.mDataEnd) {
+ mCurNode = NULL;
+ return (mEventCode=END_DOCUMENT);
+ }
+
+ if (mTree.validateNode(next) != NO_ERROR) {
+ mCurNode = NULL;
+ return (mEventCode=BAD_DOCUMENT);
+ }
+
+ mCurNode = next;
+ const uint16_t headerSize = dtohs(next->header.headerSize);
+ const uint32_t totalSize = dtohl(next->header.size);
+ mCurExt = ((const uint8_t*)next) + headerSize;
+ size_t minExtSize = 0;
+ event_code_t eventCode = (event_code_t)dtohs(next->header.type);
+ switch ((mEventCode=eventCode)) {
+ case RES_XML_START_NAMESPACE_TYPE:
+ case RES_XML_END_NAMESPACE_TYPE:
+ minExtSize = sizeof(ResXMLTree_namespaceExt);
+ break;
+ case RES_XML_START_ELEMENT_TYPE:
+ minExtSize = sizeof(ResXMLTree_attrExt);
+ break;
+ case RES_XML_END_ELEMENT_TYPE:
+ minExtSize = sizeof(ResXMLTree_endElementExt);
+ break;
+ case RES_XML_CDATA_TYPE:
+ minExtSize = sizeof(ResXMLTree_cdataExt);
+ break;
+ default:
+ LOGW("Unknown XML block: header type %d in node at %d\n",
+ (int)dtohs(next->header.type),
+ (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)));
+ continue;
+ }
+
+ if ((totalSize-headerSize) < minExtSize) {
+ LOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n",
+ (int)dtohs(next->header.type),
+ (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)),
+ (int)(totalSize-headerSize), (int)minExtSize);
+ return (mEventCode=BAD_DOCUMENT);
+ }
+
+ //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n",
+ // mCurNode, mCurExt, headerSize, minExtSize);
+
+ return eventCode;
+ } while (true);
+}
+
+void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const
+{
+ pos->eventCode = mEventCode;
+ pos->curNode = mCurNode;
+ pos->curExt = mCurExt;
+}
+
+void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos)
+{
+ mEventCode = pos.eventCode;
+ mCurNode = pos.curNode;
+ mCurExt = pos.curExt;
+}
+
+
+// --------------------------------------------------------------------
+
+static volatile int32_t gCount = 0;
+
+ResXMLTree::ResXMLTree()
+ : ResXMLParser(*this)
+ , mError(NO_INIT), mOwnedData(NULL)
+{
+ //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+ restart();
+}
+
+ResXMLTree::ResXMLTree(const void* data, size_t size, bool copyData)
+ : ResXMLParser(*this)
+ , mError(NO_INIT), mOwnedData(NULL)
+{
+ //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+ setTo(data, size, copyData);
+}
+
+ResXMLTree::~ResXMLTree()
+{
+ //LOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
+ uninit();
+}
+
+status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
+{
+ uninit();
+ mEventCode = START_DOCUMENT;
+
+ if (copyData) {
+ mOwnedData = malloc(size);
+ if (mOwnedData == NULL) {
+ return (mError=NO_MEMORY);
+ }
+ memcpy(mOwnedData, data, size);
+ data = mOwnedData;
+ }
+
+ mHeader = (const ResXMLTree_header*)data;
+ mSize = dtohl(mHeader->header.size);
+ if (dtohs(mHeader->header.headerSize) > mSize || mSize > size) {
+ LOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n",
+ (int)dtohs(mHeader->header.headerSize),
+ (int)dtohl(mHeader->header.size), (int)size);
+ mError = BAD_TYPE;
+ restart();
+ return mError;
+ }
+ mDataEnd = ((const uint8_t*)mHeader) + mSize;
+
+ mStrings.uninit();
+ mRootNode = NULL;
+ mResIds = NULL;
+ mNumResIds = 0;
+
+ // First look for a couple interesting chunks: the string block
+ // and first XML node.
+ const ResChunk_header* chunk =
+ (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize));
+ const ResChunk_header* lastChunk = chunk;
+ while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) &&
+ ((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) {
+ status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML");
+ if (err != NO_ERROR) {
+ mError = err;
+ goto done;
+ }
+ const uint16_t type = dtohs(chunk->type);
+ const size_t size = dtohl(chunk->size);
+ XML_NOISY(printf("Scanning @ %p: type=0x%x, size=0x%x\n",
+ (void*)(((uint32_t)chunk)-((uint32_t)mHeader)), type, size));
+ if (type == RES_STRING_POOL_TYPE) {
+ mStrings.setTo(chunk, size);
+ } else if (type == RES_XML_RESOURCE_MAP_TYPE) {
+ mResIds = (const uint32_t*)
+ (((const uint8_t*)chunk)+dtohs(chunk->headerSize));
+ mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/sizeof(uint32_t);
+ } else if (type >= RES_XML_FIRST_CHUNK_TYPE
+ && type <= RES_XML_LAST_CHUNK_TYPE) {
+ if (validateNode((const ResXMLTree_node*)chunk) != NO_ERROR) {
+ mError = BAD_TYPE;
+ goto done;
+ }
+ mCurNode = (const ResXMLTree_node*)lastChunk;
+ if (nextNode() == BAD_DOCUMENT) {
+ mError = BAD_TYPE;
+ goto done;
+ }
+ mRootNode = mCurNode;
+ mRootExt = mCurExt;
+ mRootCode = mEventCode;
+ break;
+ } else {
+ XML_NOISY(printf("Skipping unknown chunk!\n"));
+ }
+ lastChunk = chunk;
+ chunk = (const ResChunk_header*)
+ (((const uint8_t*)chunk) + size);
+ }
+
+ if (mRootNode == NULL) {
+ LOGW("Bad XML block: no root element node found\n");
+ mError = BAD_TYPE;
+ goto done;
+ }
+
+ mError = mStrings.getError();
+
+done:
+ restart();
+ return mError;
+}
+
+status_t ResXMLTree::getError() const
+{
+ return mError;
+}
+
+void ResXMLTree::uninit()
+{
+ mError = NO_INIT;
+ if (mOwnedData) {
+ free(mOwnedData);
+ mOwnedData = NULL;
+ }
+ restart();
+}
+
+const ResStringPool& ResXMLTree::getStrings() const
+{
+ return mStrings;
+}
+
+status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
+{
+ const uint16_t eventCode = dtohs(node->header.type);
+
+ status_t err = validate_chunk(
+ &node->header, sizeof(ResXMLTree_node),
+ mDataEnd, "ResXMLTree_node");
+
+ if (err >= NO_ERROR) {
+ // Only perform additional validation on START nodes
+ if (eventCode != RES_XML_START_ELEMENT_TYPE) {
+ return NO_ERROR;
+ }
+
+ const uint16_t headerSize = dtohs(node->header.headerSize);
+ const uint32_t size = dtohl(node->header.size);
+ const ResXMLTree_attrExt* attrExt = (const ResXMLTree_attrExt*)
+ (((const uint8_t*)node) + headerSize);
+ // check for sensical values pulled out of the stream so far...
+ if ((size >= headerSize + sizeof(ResXMLTree_attrExt))
+ && ((void*)attrExt > (void*)node)) {
+ const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize))
+ * dtohs(attrExt->attributeCount);
+ if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) {
+ return NO_ERROR;
+ }
+ LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
+ (unsigned int)(dtohs(attrExt->attributeStart)+attrSize),
+ (unsigned int)(size-headerSize));
+ }
+ else {
+ LOGW("Bad XML start block: node header size 0x%x, size 0x%x\n",
+ (unsigned int)headerSize, (unsigned int)size);
+ }
+ return BAD_TYPE;
+ }
+
+ return err;
+
+#if 0
+ const bool isStart = dtohs(node->header.type) == RES_XML_START_ELEMENT_TYPE;
+
+ const uint16_t headerSize = dtohs(node->header.headerSize);
+ const uint32_t size = dtohl(node->header.size);
+
+ if (headerSize >= (isStart ? sizeof(ResXMLTree_attrNode) : sizeof(ResXMLTree_node))) {
+ if (size >= headerSize) {
+ if (((const uint8_t*)node) <= (mDataEnd-size)) {
+ if (!isStart) {
+ return NO_ERROR;
+ }
+ if ((((size_t)dtohs(node->attributeSize))*dtohs(node->attributeCount))
+ <= (size-headerSize)) {
+ return NO_ERROR;
+ }
+ LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
+ ((int)dtohs(node->attributeSize))*dtohs(node->attributeCount),
+ (int)(size-headerSize));
+ return BAD_TYPE;
+ }
+ LOGW("Bad XML block: node at 0x%x extends beyond data end 0x%x\n",
+ (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), (int)mSize);
+ return BAD_TYPE;
+ }
+ LOGW("Bad XML block: node at 0x%x header size 0x%x smaller than total size 0x%x\n",
+ (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
+ (int)headerSize, (int)size);
+ return BAD_TYPE;
+ }
+ LOGW("Bad XML block: node at 0x%x header size 0x%x too small\n",
+ (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
+ (int)headerSize);
+ return BAD_TYPE;
+#endif
+}
+
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+
+struct ResTable::Header
+{
+ Header() : ownedData(NULL), header(NULL) { }
+
+ void* ownedData;
+ const ResTable_header* header;
+ size_t size;
+ const uint8_t* dataEnd;
+ size_t index;
+ void* cookie;
+
+ ResStringPool values;
+};
+
+struct ResTable::Type
+{
+ Type(const Header* _header, const Package* _package, size_t count)
+ : header(_header), package(_package), entryCount(count),
+ typeSpec(NULL), typeSpecFlags(NULL) { }
+ const Header* const header;
+ const Package* const package;
+ const size_t entryCount;
+ const ResTable_typeSpec* typeSpec;
+ const uint32_t* typeSpecFlags;
+ Vector<const ResTable_type*> configs;
+};
+
+struct ResTable::Package
+{
+ Package(const Header* _header, const ResTable_package* _package)
+ : header(_header), package(_package) { }
+ ~Package()
+ {
+ size_t i = types.size();
+ while (i > 0) {
+ i--;
+ delete types[i];
+ }
+ }
+
+ const Header* const header;
+ const ResTable_package* const package;
+ Vector<Type*> types;
+
+ const Type* getType(size_t idx) const {
+ return idx < types.size() ? types[idx] : NULL;
+ }
+};
+
+// A group of objects describing a particular resource package.
+// The first in 'package' is always the root object (from the resource
+// table that defined the package); the ones after are skins on top of it.
+struct ResTable::PackageGroup
+{
+ PackageGroup(const String16& _name, uint32_t _id)
+ : name(_name), id(_id), typeCount(0), bags(NULL) { }
+ ~PackageGroup() {
+ clearBagCache();
+ const size_t N = packages.size();
+ for (size_t i=0; i<N; i++) {
+ delete packages[i];
+ }
+ }
+
+ void clearBagCache() {
+ if (bags) {
+ TABLE_NOISY(printf("bags=%p\n", bags));
+ Package* pkg = packages[0];
+ TABLE_NOISY(printf("typeCount=%x\n", typeCount));
+ for (size_t i=0; i<typeCount; i++) {
+ TABLE_NOISY(printf("type=%d\n", i));
+ const Type* type = pkg->getType(i);
+ if (type != NULL) {
+ bag_set** typeBags = bags[i];
+ TABLE_NOISY(printf("typeBags=%p\n", typeBags));
+ if (typeBags) {
+ TABLE_NOISY(printf("type->entryCount=%x\n", type->entryCount));
+ const size_t N = type->entryCount;
+ for (size_t j=0; j<N; j++) {
+ if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
+ free(typeBags[j]);
+ }
+ free(typeBags);
+ }
+ }
+ }
+ free(bags);
+ bags = NULL;
+ }
+ }
+
+ String16 const name;
+ uint32_t const id;
+ Vector<Package*> packages;
+
+ // Taken from the root package.
+ ResStringPool typeStrings;
+ ResStringPool keyStrings;
+ size_t typeCount;
+
+ // Computed attribute bags, first indexed by the type and second
+ // by the entry in that type.
+ bag_set*** bags;
+};
+
+struct ResTable::bag_set
+{
+ size_t numAttrs; // number in array
+ size_t availAttrs; // total space in array
+ uint32_t typeSpecFlags;
+ // Followed by 'numAttr' bag_entry structures.
+};
+
+ResTable::Theme::Theme(const ResTable& table)
+ : mTable(table)
+{
+ memset(mPackages, 0, sizeof(mPackages));
+}
+
+ResTable::Theme::~Theme()
+{
+ for (size_t i=0; i<Res_MAXPACKAGE; i++) {
+ package_info* pi = mPackages[i];
+ if (pi != NULL) {
+ free_package(pi);
+ }
+ }
+}
+
+void ResTable::Theme::free_package(package_info* pi)
+{
+ for (size_t j=0; j<pi->numTypes; j++) {
+ theme_entry* te = pi->types[j].entries;
+ if (te != NULL) {
+ free(te);
+ }
+ }
+ free(pi);
+}
+
+ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
+{
+ package_info* newpi = (package_info*)malloc(
+ sizeof(package_info) + (pi->numTypes*sizeof(type_info)));
+ newpi->numTypes = pi->numTypes;
+ for (size_t j=0; j<newpi->numTypes; j++) {
+ size_t cnt = pi->types[j].numEntries;
+ newpi->types[j].numEntries = cnt;
+ theme_entry* te = pi->types[j].entries;
+ if (te != NULL) {
+ theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
+ newpi->types[j].entries = newte;
+ memcpy(newte, te, cnt*sizeof(theme_entry));
+ } else {
+ newpi->types[j].entries = NULL;
+ }
+ }
+ return newpi;
+}
+
+status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
+{
+ const bag_entry* bag;
+ uint32_t bagTypeSpecFlags = 0;
+ mTable.lock();
+ const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags);
+ TABLE_NOISY(LOGV("Applying style 0x%08x to theme %p, count=%d", resID, this, N));
+ if (N < 0) {
+ mTable.unlock();
+ return N;
+ }
+
+ uint32_t curPackage = 0xffffffff;
+ ssize_t curPackageIndex = 0;
+ package_info* curPI = NULL;
+ uint32_t curType = 0xffffffff;
+ size_t numEntries = 0;
+ theme_entry* curEntries = NULL;
+
+ const bag_entry* end = bag + N;
+ while (bag < end) {
+ const uint32_t attrRes = bag->map.name.ident;
+ const uint32_t p = Res_GETPACKAGE(attrRes);
+ const uint32_t t = Res_GETTYPE(attrRes);
+ const uint32_t e = Res_GETENTRY(attrRes);
+
+ if (curPackage != p) {
+ const ssize_t pidx = mTable.getResourcePackageIndex(attrRes);
+ if (pidx < 0) {
+ LOGE("Style contains key with bad package: 0x%08x\n", attrRes);
+ bag++;
+ continue;
+ }
+ curPackage = p;
+ curPackageIndex = pidx;
+ curPI = mPackages[pidx];
+ if (curPI == NULL) {
+ PackageGroup* const grp = mTable.mPackageGroups[pidx];
+ int cnt = grp->typeCount;
+ curPI = (package_info*)malloc(
+ sizeof(package_info) + (cnt*sizeof(type_info)));
+ curPI->numTypes = cnt;
+ memset(curPI->types, 0, cnt*sizeof(type_info));
+ mPackages[pidx] = curPI;
+ }
+ curType = 0xffffffff;
+ }
+ if (curType != t) {
+ if (t >= curPI->numTypes) {
+ LOGE("Style contains key with bad type: 0x%08x\n", attrRes);
+ bag++;
+ continue;
+ }
+ curType = t;
+ curEntries = curPI->types[t].entries;
+ if (curEntries == NULL) {
+ PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
+ const Type* type = grp->packages[0]->getType(t);
+ int cnt = type != NULL ? type->entryCount : 0;
+ curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry));
+ memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry));
+ curPI->types[t].numEntries = cnt;
+ curPI->types[t].entries = curEntries;
+ }
+ numEntries = curPI->types[t].numEntries;
+ }
+ if (e >= numEntries) {
+ LOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
+ bag++;
+ continue;
+ }
+ theme_entry* curEntry = curEntries + e;
+ TABLE_NOISY(LOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
+ attrRes, bag->map.value.dataType, bag->map.value.data,
+ curEntry->value.dataType));
+ if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
+ curEntry->stringBlock = bag->stringBlock;
+ curEntry->typeSpecFlags |= bagTypeSpecFlags;
+ curEntry->value = bag->map.value;
+ }
+
+ bag++;
+ }
+
+ mTable.unlock();
+
+ //LOGI("Applying style 0x%08x (force=%d) theme %p...\n", resID, force, this);
+ //dumpToLog();
+
+ return NO_ERROR;
+}
+
+status_t ResTable::Theme::setTo(const Theme& other)
+{
+ //LOGI("Setting theme %p from theme %p...\n", this, &other);
+ //dumpToLog();
+ //other.dumpToLog();
+
+ if (&mTable == &other.mTable) {
+ for (size_t i=0; i<Res_MAXPACKAGE; i++) {
+ if (mPackages[i] != NULL) {
+ free_package(mPackages[i]);
+ }
+ if (other.mPackages[i] != NULL) {
+ mPackages[i] = copy_package(other.mPackages[i]);
+ } else {
+ mPackages[i] = NULL;
+ }
+ }
+ } else {
+ // @todo: need to really implement this, not just copy
+ // the system package (which is still wrong because it isn't
+ // fixing up resource references).
+ for (size_t i=0; i<Res_MAXPACKAGE; i++) {
+ if (mPackages[i] != NULL) {
+ free_package(mPackages[i]);
+ }
+ if (i == 0 && other.mPackages[i] != NULL) {
+ mPackages[i] = copy_package(other.mPackages[i]);
+ } else {
+ mPackages[i] = NULL;
+ }
+ }
+ }
+
+ //LOGI("Final theme:");
+ //dumpToLog();
+
+ return NO_ERROR;
+}
+
+ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
+ uint32_t* outTypeSpecFlags) const
+{
+ int cnt = 20;
+
+ if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0;
+
+ do {
+ const ssize_t p = mTable.getResourcePackageIndex(resID);
+ const uint32_t t = Res_GETTYPE(resID);
+ const uint32_t e = Res_GETENTRY(resID);
+
+ TABLE_NOISY(LOGV("Looking up attr 0x%08x in theme %p", resID, this));
+
+ if (p >= 0) {
+ const package_info* const pi = mPackages[p];
+ if (pi != NULL) {
+ if (t < pi->numTypes) {
+ const type_info& ti = pi->types[t];
+ if (e < ti.numEntries) {
+ const theme_entry& te = ti.entries[e];
+ if (outTypeSpecFlags != NULL) {
+ *outTypeSpecFlags |= te.typeSpecFlags;
+ }
+ const uint8_t type = te.value.dataType;
+ if (type == Res_value::TYPE_ATTRIBUTE) {
+ if (cnt > 0) {
+ cnt--;
+ resID = te.value.data;
+ continue;
+ }
+ LOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
+ return BAD_INDEX;
+ } else if (type != Res_value::TYPE_NULL) {
+ *outValue = te.value;
+ return te.stringBlock;
+ }
+ return BAD_INDEX;
+ }
+ }
+ }
+ }
+ break;
+
+ } while (true);
+
+ return BAD_INDEX;
+}
+
+ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
+ ssize_t blockIndex, uint32_t* outLastRef,
+ uint32_t* inoutTypeSpecFlags) const
+{
+ //printf("Resolving type=0x%x\n", inOutValue->dataType);
+ if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
+ uint32_t newTypeSpecFlags;
+ blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags);
+ if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags;
+ //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType);
+ if (blockIndex < 0) {
+ return blockIndex;
+ }
+ }
+ return mTable.resolveReference(inOutValue, blockIndex, outLastRef);
+}
+
+void ResTable::Theme::dumpToLog() const
+{
+ LOGI("Theme %p:\n", this);
+ for (size_t i=0; i<Res_MAXPACKAGE; i++) {
+ package_info* pi = mPackages[i];
+ if (pi == NULL) continue;
+
+ LOGI(" Package #0x%02x:\n", (int)(i+1));
+ for (size_t j=0; j<pi->numTypes; j++) {
+ type_info& ti = pi->types[j];
+ if (ti.numEntries == 0) continue;
+
+ LOGI(" Type #0x%02x:\n", (int)(j+1));
+ for (size_t k=0; k<ti.numEntries; k++) {
+ theme_entry& te = ti.entries[k];
+ if (te.value.dataType == Res_value::TYPE_NULL) continue;
+ LOGI(" 0x%08x: t=0x%x, d=0x%08x (block=%d)\n",
+ (int)Res_MAKEID(i, j, k),
+ te.value.dataType, (int)te.value.data, (int)te.stringBlock);
+ }
+ }
+ }
+}
+
+ResTable::ResTable()
+ : mError(NO_INIT)
+{
+ memset(&mParams, 0, sizeof(mParams));
+ memset(mPackageMap, 0, sizeof(mPackageMap));
+ //LOGI("Creating ResTable %p\n", this);
+}
+
+ResTable::ResTable(const void* data, size_t size, void* cookie, bool copyData)
+ : mError(NO_INIT)
+{
+ memset(&mParams, 0, sizeof(mParams));
+ memset(mPackageMap, 0, sizeof(mPackageMap));
+ add(data, size, cookie, copyData);
+ LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
+ //LOGI("Creating ResTable %p\n", this);
+}
+
+ResTable::~ResTable()
+{
+ //LOGI("Destroying ResTable in %p\n", this);
+ uninit();
+}
+
+inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
+{
+ return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
+}
+
+status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData)
+{
+ return add(data, size, cookie, NULL, copyData);
+}
+
+status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
+{
+ const void* data = asset->getBuffer(true);
+ if (data == NULL) {
+ LOGW("Unable to get buffer of resource asset file");
+ return UNKNOWN_ERROR;
+ }
+ size_t size = (size_t)asset->getLength();
+ return add(data, size, cookie, asset, copyData);
+}
+
+status_t ResTable::add(const void* data, size_t size, void* cookie,
+ Asset* asset, bool copyData)
+{
+ if (!data) return NO_ERROR;
+ Header* header = new Header;
+ header->index = mHeaders.size();
+ header->cookie = cookie;
+ mHeaders.add(header);
+
+ const bool notDeviceEndian = htods(0xf0) != 0xf0;
+
+ LOAD_TABLE_NOISY(
+ LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d\n",
+ data, size, cookie, asset, copyData));
+
+ if (copyData || notDeviceEndian) {
+ header->ownedData = malloc(size);
+ if (header->ownedData == NULL) {
+ return (mError=NO_MEMORY);
+ }
+ memcpy(header->ownedData, data, size);
+ data = header->ownedData;
+ }
+
+ header->header = (const ResTable_header*)data;
+ header->size = dtohl(header->header->header.size);
+ //LOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size,
+ // dtohl(header->header->header.size), header->header->header.size);
+ LOAD_TABLE_NOISY(LOGV("Loading ResTable @%p:\n", header->header));
+ LOAD_TABLE_NOISY(printHexData(2, header->header, header->size < 256 ? header->size : 256,
+ 16, 16, 0, false, printToLogFunc));
+ if (dtohs(header->header->header.headerSize) > header->size
+ || header->size > size) {
+ LOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
+ (int)dtohs(header->header->header.headerSize),
+ (int)header->size, (int)size);
+ return (mError=BAD_TYPE);
+ }
+ if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) {
+ LOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n",
+ (int)dtohs(header->header->header.headerSize),
+ (int)header->size);
+ return (mError=BAD_TYPE);
+ }
+ header->dataEnd = ((const uint8_t*)header->header) + header->size;
+
+ // Iterate through all chunks.
+ size_t curPackage = 0;
+
+ const ResChunk_header* chunk =
+ (const ResChunk_header*)(((const uint8_t*)header->header)
+ + dtohs(header->header->header.headerSize));
+ while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) &&
+ ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) {
+ status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable");
+ if (err != NO_ERROR) {
+ return (mError=err);
+ }
+ TABLE_NOISY(LOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
+ dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
+ (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
+ const size_t csize = dtohl(chunk->size);
+ const uint16_t ctype = dtohs(chunk->type);
+ if (ctype == RES_STRING_POOL_TYPE) {
+ if (header->values.getError() != NO_ERROR) {
+ // Only use the first string chunk; ignore any others that
+ // may appear.
+ status_t err = header->values.setTo(chunk, csize);
+ if (err != NO_ERROR) {
+ return (mError=err);
+ }
+ } else {
+ LOGW("Multiple string chunks found in resource table.");
+ }
+ } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
+ if (curPackage >= dtohl(header->header->packageCount)) {
+ LOGW("More package chunks were found than the %d declared in the header.",
+ dtohl(header->header->packageCount));
+ return (mError=BAD_TYPE);
+ }
+ if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
+ return mError;
+ }
+ curPackage++;
+ } else {
+ LOGW("Unknown chunk type %p in table at %p.\n",
+ (void*)(int)(ctype),
+ (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
+ }
+ chunk = (const ResChunk_header*)
+ (((const uint8_t*)chunk) + csize);
+ }
+
+ if (curPackage < dtohl(header->header->packageCount)) {
+ LOGW("Fewer package chunks (%d) were found than the %d declared in the header.",
+ (int)curPackage, dtohl(header->header->packageCount));
+ return (mError=BAD_TYPE);
+ }
+ mError = header->values.getError();
+ if (mError != NO_ERROR) {
+ LOGW("No string values found in resource table!");
+ }
+ TABLE_NOISY(LOGV("Returning from add with mError=%d\n", mError));
+ return mError;
+}
+
+status_t ResTable::getError() const
+{
+ return mError;
+}
+
+void ResTable::uninit()
+{
+ mError = NO_INIT;
+ size_t N = mPackageGroups.size();
+ for (size_t i=0; i<N; i++) {
+ PackageGroup* g = mPackageGroups[i];
+ delete g;
+ }
+ N = mHeaders.size();
+ for (size_t i=0; i<N; i++) {
+ Header* header = mHeaders[i];
+ if (header->ownedData) {
+ free(header->ownedData);
+ }
+ delete header;
+ }
+
+ mPackageGroups.clear();
+ mHeaders.clear();
+}
+
+bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
+{
+ if (mError != NO_ERROR) {
+ return false;
+ }
+
+ const ssize_t p = getResourcePackageIndex(resID);
+ const int t = Res_GETTYPE(resID);
+ const int e = Res_GETENTRY(resID);
+
+ if (p < 0) {
+ LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+ return false;
+ }
+ if (t < 0) {
+ LOGW("No type identifier when getting name for resource number 0x%08x", resID);
+ return false;
+ }
+
+ const PackageGroup* const grp = mPackageGroups[p];
+ if (grp == NULL) {
+ LOGW("Bad identifier when getting name for resource number 0x%08x", resID);
+ return false;
+ }
+ if (grp->packages.size() > 0) {
+ const Package* const package = grp->packages[0];
+
+ const ResTable_type* type;
+ const ResTable_entry* entry;
+ ssize_t offset = getEntry(package, t, e, NULL, &type, &entry, NULL);
+ if (offset <= 0) {
+ return false;
+ }
+
+ outName->package = grp->name.string();
+ outName->packageLen = grp->name.size();
+ outName->type = grp->typeStrings.stringAt(t, &outName->typeLen);
+ outName->name = grp->keyStrings.stringAt(
+ dtohl(entry->key.index), &outName->nameLen);
+ return true;
+ }
+
+ return false;
+}
+
+ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag,
+ uint32_t* outSpecFlags) const
+{
+ if (mError != NO_ERROR) {
+ return mError;
+ }
+
+ const ssize_t p = getResourcePackageIndex(resID);
+ const int t = Res_GETTYPE(resID);
+ const int e = Res_GETENTRY(resID);
+
+ if (p < 0) {
+ LOGW("No package identifier when getting value for resource number 0x%08x", resID);
+ return BAD_INDEX;
+ }
+ if (t < 0) {
+ LOGW("No type identifier when getting value for resource number 0x%08x", resID);
+ return BAD_INDEX;
+ }
+
+ const Res_value* bestValue = NULL;
+ const Package* bestPackage = NULL;
+ ResTable_config bestItem;
+ memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up
+
+ if (outSpecFlags != NULL) *outSpecFlags = 0;
+
+ // Look through all resource packages, starting with the most
+ // recently added.
+ const PackageGroup* const grp = mPackageGroups[p];
+ if (grp == NULL) {
+ LOGW("Bad identifier when getting value for resource number 0x%08x", resID);
+ return false;
+ }
+ size_t ip = grp->packages.size();
+ while (ip > 0) {
+ ip--;
+
+ const Package* const package = grp->packages[ip];
+
+ const ResTable_type* type;
+ const ResTable_entry* entry;
+ const Type* typeClass;
+ ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+ if (offset <= 0) {
+ if (offset < 0) {
+ LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %d: 0x%08x\n",
+ resID, t, e, (int)ip, (int)offset);
+ return offset;
+ }
+ continue;
+ }
+
+ if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) {
+ if (!mayBeBag) {
+ LOGW("Requesting resource %p failed because it is complex\n",
+ (void*)resID);
+ }
+ continue;
+ }
+
+ TABLE_NOISY(aout << "Resource type data: "
+ << HexDump(type, dtohl(type->header.size)) << endl);
+
+ if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) {
+ LOGW("ResTable_item at %d is beyond type chunk data %d",
+ (int)offset, dtohl(type->header.size));
+ return BAD_TYPE;
+ }
+
+ const Res_value* item =
+ (const Res_value*)(((const uint8_t*)type) + offset);
+ ResTable_config thisConfig;
+ thisConfig.copyFromDtoH(type->config);
+
+ if (outSpecFlags != NULL) {
+ if (typeClass->typeSpecFlags != NULL) {
+ *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+ } else {
+ *outSpecFlags = -1;
+ }
+ }
+
+ if (bestPackage != NULL && bestItem.isBetterThan(thisConfig)) {
+ continue;
+ }
+
+ bestItem = thisConfig;
+ bestValue = item;
+ bestPackage = package;
+ }
+
+ TABLE_NOISY(printf("Found result: package %p\n", bestPackage));
+
+ if (bestValue) {
+ outValue->size = dtohs(bestValue->size);
+ outValue->res0 = bestValue->res0;
+ outValue->dataType = bestValue->dataType;
+ outValue->data = dtohl(bestValue->data);
+ TABLE_NOISY(size_t len;
+ printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
+ bestPackage->header->index,
+ outValue->dataType,
+ outValue->dataType == bestValue->TYPE_STRING
+ ? String8(bestPackage->header->values.stringAt(
+ outValue->data, &len)).string()
+ : "",
+ outValue->data));
+ return bestPackage->header->index;
+ }
+
+ return BAD_INDEX;
+}
+
+ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
+ uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags) const
+{
+ int count=0;
+ while (blockIndex >= 0 && value->dataType == value->TYPE_REFERENCE
+ && value->data != 0 && count < 20) {
+ if (outLastRef) *outLastRef = value->data;
+ uint32_t lastRef = value->data;
+ uint32_t newFlags = 0;
+ const ssize_t newIndex = getResource(value->data, value, true, &newFlags);
+ //LOGI("Resolving reference d=%p: newIndex=%d, t=0x%02x, d=%p\n",
+ // (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data);
+ //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
+ if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags;
+ if (newIndex < 0) {
+ // This can fail if the resource being referenced is a style...
+ // in this case, just return the reference, and expect the
+ // caller to deal with.
+ return blockIndex;
+ }
+ blockIndex = newIndex;
+ count++;
+ }
+ return blockIndex;
+}
+
+const char16_t* ResTable::valueToString(
+ const Res_value* value, size_t stringBlock,
+ char16_t tmpBuffer[TMP_BUFFER_SIZE], size_t* outLen)
+{
+ if (!value) {
+ return NULL;
+ }
+ if (value->dataType == value->TYPE_STRING) {
+ return getTableStringBlock(stringBlock)->stringAt(value->data, outLen);
+ }
+ // XXX do int to string conversions.
+ return NULL;
+}
+
+ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const
+{
+ mLock.lock();
+ ssize_t err = getBagLocked(resID, outBag);
+ if (err < NO_ERROR) {
+ //printf("*** get failed! unlocking\n");
+ mLock.unlock();
+ }
+ return err;
+}
+
+void ResTable::unlockBag(const bag_entry* bag) const
+{
+ //printf("<<< unlockBag %p\n", this);
+ mLock.unlock();
+}
+
+void ResTable::lock() const
+{
+ mLock.lock();
+}
+
+void ResTable::unlock() const
+{
+ mLock.unlock();
+}
+
+ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
+ uint32_t* outTypeSpecFlags) const
+{
+ if (mError != NO_ERROR) {
+ return mError;
+ }
+
+ const ssize_t p = getResourcePackageIndex(resID);
+ const int t = Res_GETTYPE(resID);
+ const int e = Res_GETENTRY(resID);
+
+ if (p < 0) {
+ LOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID);
+ return BAD_INDEX;
+ }
+ if (t < 0) {
+ LOGW("No type identifier when getting bag for resource number 0x%08x", resID);
+ return BAD_INDEX;
+ }
+
+ //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t);
+ PackageGroup* const grp = mPackageGroups[p];
+ if (grp == NULL) {
+ LOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
+ return false;
+ }
+
+ if (t >= (int)grp->typeCount) {
+ LOGW("Type identifier 0x%x is larger than type count 0x%x",
+ t+1, (int)grp->typeCount);
+ return BAD_INDEX;
+ }
+
+ const Package* const basePackage = grp->packages[0];
+
+ const Type* const typeConfigs = basePackage->getType(t);
+
+ const size_t NENTRY = typeConfigs->entryCount;
+ if (e >= (int)NENTRY) {
+ LOGW("Entry identifier 0x%x is larger than entry count 0x%x",
+ e, (int)typeConfigs->entryCount);
+ return BAD_INDEX;
+ }
+
+ // First see if we've already computed this bag...
+ if (grp->bags) {
+ bag_set** typeSet = grp->bags[t];
+ if (typeSet) {
+ bag_set* set = typeSet[e];
+ if (set) {
+ if (set != (bag_set*)0xFFFFFFFF) {
+ if (outTypeSpecFlags != NULL) {
+ *outTypeSpecFlags = set->typeSpecFlags;
+ }
+ *outBag = (bag_entry*)(set+1);
+ //LOGI("Found existing bag for: %p\n", (void*)resID);
+ return set->numAttrs;
+ }
+ LOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
+ resID);
+ return BAD_INDEX;
+ }
+ }
+ }
+
+ // Bag not found, we need to compute it!
+ if (!grp->bags) {
+ grp->bags = (bag_set***)malloc(sizeof(bag_set*)*grp->typeCount);
+ if (!grp->bags) return NO_MEMORY;
+ memset(grp->bags, 0, sizeof(bag_set*)*grp->typeCount);
+ }
+
+ bag_set** typeSet = grp->bags[t];
+ if (!typeSet) {
+ typeSet = (bag_set**)malloc(sizeof(bag_set*)*NENTRY);
+ if (!typeSet) return NO_MEMORY;
+ memset(typeSet, 0, sizeof(bag_set*)*NENTRY);
+ grp->bags[t] = typeSet;
+ }
+
+ // Mark that we are currently working on this one.
+ typeSet[e] = (bag_set*)0xFFFFFFFF;
+
+ // This is what we are building.
+ bag_set* set = NULL;
+
+ TABLE_NOISY(LOGI("Building bag: %p\n", (void*)resID));
+
+ // Now collect all bag attributes from all packages.
+ size_t ip = grp->packages.size();
+ while (ip > 0) {
+ ip--;
+
+ const Package* const package = grp->packages[ip];
+
+ const ResTable_type* type;
+ const ResTable_entry* entry;
+ const Type* typeClass;
+ LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, t, e);
+ ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+ LOGV("Resulting offset=%d\n", offset);
+ if (offset <= 0) {
+ if (offset < 0) {
+ if (set) free(set);
+ return offset;
+ }
+ continue;
+ }
+
+ if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) == 0) {
+ LOGW("Skipping entry %p in package table %d because it is not complex!\n",
+ (void*)resID, (int)ip);
+ continue;
+ }
+
+ const uint16_t entrySize = dtohs(entry->size);
+ const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
+ ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
+ const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
+ ? dtohl(((const ResTable_map_entry*)entry)->count) : 0;
+
+ size_t N = count;
+
+ TABLE_NOISY(LOGI("Found map: size=%p parent=%p count=%d\n",
+ entrySize, parent, count));
+
+ if (set == NULL) {
+ // If this map inherits from another, we need to start
+ // with its parent's values. Otherwise start out empty.
+ TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
+ entrySize, parent));
+ if (parent) {
+ const bag_entry* parentBag;
+ uint32_t parentTypeSpecFlags = 0;
+ const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
+ const size_t NT = ((NP >= 0) ? NP : 0) + N;
+ set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
+ if (set == NULL) {
+ return NO_MEMORY;
+ }
+ if (NP > 0) {
+ memcpy(set+1, parentBag, NP*sizeof(bag_entry));
+ set->numAttrs = NP;
+ TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
+ } else {
+ TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
+ set->numAttrs = 0;
+ }
+ set->availAttrs = NT;
+ set->typeSpecFlags = parentTypeSpecFlags;
+ } else {
+ set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
+ if (set == NULL) {
+ return NO_MEMORY;
+ }
+ set->numAttrs = 0;
+ set->availAttrs = N;
+ set->typeSpecFlags = 0;
+ }
+ }
+
+ if (typeClass->typeSpecFlags != NULL) {
+ set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+ } else {
+ set->typeSpecFlags = -1;
+ }
+
+ // Now merge in the new attributes...
+ ssize_t curOff = offset;
+ const ResTable_map* map;
+ bag_entry* entries = (bag_entry*)(set+1);
+ size_t curEntry = 0;
+ uint32_t pos = 0;
+ TABLE_NOISY(LOGI("Starting with set %p, entries=%p, avail=%d\n",
+ set, entries, set->availAttrs));
+ while (pos < count) {
+ TABLE_NOISY(printf("Now at %p\n", (void*)curOff));
+
+ if ((size_t)curOff > (dtohl(type->header.size)-sizeof(ResTable_map))) {
+ LOGW("ResTable_map at %d is beyond type chunk data %d",
+ (int)curOff, dtohl(type->header.size));
+ return BAD_TYPE;
+ }
+ map = (const ResTable_map*)(((const uint8_t*)type) + curOff);
+ N++;
+
+ const uint32_t newName = htodl(map->name.ident);
+ bool isInside;
+ uint32_t oldName = 0;
+ while ((isInside=(curEntry < set->numAttrs))
+ && (oldName=entries[curEntry].map.name.ident) < newName) {
+ TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n",
+ curEntry, entries[curEntry].map.name.ident));
+ curEntry++;
+ }
+
+ if ((!isInside) || oldName != newName) {
+ // This is a new attribute... figure out what to do with it.
+ if (set->numAttrs >= set->availAttrs) {
+ // Need to alloc more memory...
+ const size_t newAvail = set->availAttrs+N;
+ set = (bag_set*)realloc(set,
+ sizeof(bag_set)
+ + sizeof(bag_entry)*newAvail);
+ if (set == NULL) {
+ return NO_MEMORY;
+ }
+ set->availAttrs = newAvail;
+ entries = (bag_entry*)(set+1);
+ TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n",
+ set, entries, set->availAttrs));
+ }
+ if (isInside) {
+ // Going in the middle, need to make space.
+ memmove(entries+curEntry+1, entries+curEntry,
+ sizeof(bag_entry)*(set->numAttrs-curEntry));
+ set->numAttrs++;
+ }
+ TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n",
+ curEntry, newName));
+ } else {
+ TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n",
+ curEntry, oldName));
+ }
+
+ bag_entry* cur = entries+curEntry;
+
+ cur->stringBlock = package->header->index;
+ cur->map.name.ident = newName;
+ cur->map.value.copyFrom_dtoh(map->value);
+ TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n",
+ curEntry, cur, cur->stringBlock, cur->map.name.ident,
+ cur->map.value.dataType, cur->map.value.data));
+
+ // On to the next!
+ curEntry++;
+ pos++;
+ const size_t size = dtohs(map->value.size);
+ curOff += size + sizeof(*map)-sizeof(map->value);
+ };
+ if (curEntry > set->numAttrs) {
+ set->numAttrs = curEntry;
+ }
+ }
+
+ // And this is it...
+ typeSet[e] = set;
+ if (set) {
+ if (outTypeSpecFlags != NULL) {
+ *outTypeSpecFlags = set->typeSpecFlags;
+ }
+ *outBag = (bag_entry*)(set+1);
+ TABLE_NOISY(LOGI("Returning %d attrs\n", set->numAttrs));
+ return set->numAttrs;
+ }
+ return BAD_INDEX;
+}
+
+void ResTable::setParameters(const ResTable_config* params)
+{
+ mLock.lock();
+ TABLE_GETENTRY(LOGI("Setting parameters: imsi:%d/%d lang:%c%c cnt:%c%c "
+ "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n",
+ params->mcc, params->mnc,
+ params->language[0] ? params->language[0] : '-',
+ params->language[1] ? params->language[1] : '-',
+ params->country[0] ? params->country[0] : '-',
+ params->country[1] ? params->country[1] : '-',
+ params->orientation,
+ params->touchscreen,
+ params->density,
+ params->keyboard,
+ params->inputFlags,
+ params->navigation,
+ params->screenWidth,
+ params->screenHeight));
+ mParams = *params;
+ for (size_t i=0; i<mPackageGroups.size(); i++) {
+ TABLE_NOISY(LOGI("CLEARING BAGS FOR GROUP %d!", i));
+ mPackageGroups[i]->clearBagCache();
+ }
+ mLock.unlock();
+}
+
+void ResTable::getParameters(ResTable_config* params) const
+{
+ mLock.lock();
+ *params = mParams;
+ mLock.unlock();
+}
+
+struct id_name_map {
+ uint32_t id;
+ size_t len;
+ char16_t name[6];
+};
+
+const static id_name_map ID_NAMES[] = {
+ { ResTable_map::ATTR_TYPE, 5, { '^', 't', 'y', 'p', 'e' } },
+ { ResTable_map::ATTR_L10N, 5, { '^', 'l', '1', '0', 'n' } },
+ { ResTable_map::ATTR_MIN, 4, { '^', 'm', 'i', 'n' } },
+ { ResTable_map::ATTR_MAX, 4, { '^', 'm', 'a', 'x' } },
+ { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } },
+ { ResTable_map::ATTR_ZERO, 5, { '^', 'z', 'e', 'r', 'o' } },
+ { ResTable_map::ATTR_ONE, 4, { '^', 'o', 'n', 'e' } },
+ { ResTable_map::ATTR_TWO, 4, { '^', 't', 'w', 'o' } },
+ { ResTable_map::ATTR_FEW, 4, { '^', 'f', 'e', 'w' } },
+ { ResTable_map::ATTR_MANY, 5, { '^', 'm', 'a', 'n', 'y' } },
+};
+
+uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen,
+ const char16_t* type, size_t typeLen,
+ const char16_t* package,
+ size_t packageLen,
+ uint32_t* outTypeSpecFlags) const
+{
+ TABLE_SUPER_NOISY(printf("Identifier for name: error=%d\n", mError));
+
+ // Check for internal resource identifier as the very first thing, so
+ // that we will always find them even when there are no resources.
+ if (name[0] == '^') {
+ const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0]));
+ size_t len;
+ for (int i=0; i<N; i++) {
+ const id_name_map* m = ID_NAMES + i;
+ len = m->len;
+ if (len != nameLen) {
+ continue;
+ }
+ for (size_t j=1; j<len; j++) {
+ if (m->name[j] != name[j]) {
+ goto nope;
+ }
+ }
+ return m->id;
+nope:
+ ;
+ }
+ if (nameLen > 7) {
+ if (name[1] == 'i' && name[2] == 'n'
+ && name[3] == 'd' && name[4] == 'e' && name[5] == 'x'
+ && name[6] == '_') {
+ int index = atoi(String8(name + 7, nameLen - 7).string());
+ if (Res_CHECKID(index)) {
+ LOGW("Array resource index: %d is too large.",
+ index);
+ return 0;
+ }
+ return Res_MAKEARRAY(index);
+ }
+ }
+ return 0;
+ }
+
+ if (mError != NO_ERROR) {
+ return 0;
+ }
+
+ // Figure out the package and type we are looking in...
+
+ const char16_t* packageEnd = NULL;
+ const char16_t* typeEnd = NULL;
+ const char16_t* const nameEnd = name+nameLen;
+ const char16_t* p = name;
+ while (p < nameEnd) {
+ if (*p == ':') packageEnd = p;
+ else if (*p == '/') typeEnd = p;
+ p++;
+ }
+ if (*name == '@') name++;
+ if (name >= nameEnd) {
+ return 0;
+ }
+
+ if (packageEnd) {
+ package = name;
+ packageLen = packageEnd-name;
+ name = packageEnd+1;
+ } else if (!package) {
+ return 0;
+ }
+
+ if (typeEnd) {
+ type = name;
+ typeLen = typeEnd-name;
+ name = typeEnd+1;
+ } else if (!type) {
+ return 0;
+ }
+
+ if (name >= nameEnd) {
+ return 0;
+ }
+ nameLen = nameEnd-name;
+
+ TABLE_NOISY(printf("Looking for identifier: type=%s, name=%s, package=%s\n",
+ String8(type, typeLen).string(),
+ String8(name, nameLen).string(),
+ String8(package, packageLen).string()));
+
+ const size_t NG = mPackageGroups.size();
+ for (size_t ig=0; ig<NG; ig++) {
+ const PackageGroup* group = mPackageGroups[ig];
+
+ if (strzcmp16(package, packageLen,
+ group->name.string(), group->name.size())) {
+ TABLE_NOISY(printf("Skipping package group: %s\n", String8(group->name).string()));
+ continue;
+ }
+
+ const ssize_t ti = group->typeStrings.indexOfString(type, typeLen);
+ if (ti < 0) {
+ TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string()));
+ continue;
+ }
+
+ const ssize_t ei = group->keyStrings.indexOfString(name, nameLen);
+ if (ei < 0) {
+ TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string()));
+ continue;
+ }
+
+ TABLE_NOISY(printf("Search indices: type=%d, name=%d\n", ti, ei));
+
+ const Type* const typeConfigs = group->packages[0]->getType(ti);
+ if (typeConfigs == NULL || typeConfigs->configs.size() <= 0) {
+ TABLE_NOISY(printf("Expected type structure not found in package %s for idnex %d\n",
+ String8(group->name).string(), ti));
+ }
+
+ size_t NTC = typeConfigs->configs.size();
+ for (size_t tci=0; tci<NTC; tci++) {
+ const ResTable_type* const ty = typeConfigs->configs[tci];
+ const uint32_t typeOffset = dtohl(ty->entriesStart);
+
+ const uint8_t* const end = ((const uint8_t*)ty) + dtohl(ty->header.size);
+ const uint32_t* const eindex = (const uint32_t*)
+ (((const uint8_t*)ty) + dtohs(ty->header.headerSize));
+
+ const size_t NE = dtohl(ty->entryCount);
+ for (size_t i=0; i<NE; i++) {
+ uint32_t offset = dtohl(eindex[i]);
+ if (offset == ResTable_type::NO_ENTRY) {
+ continue;
+ }
+
+ offset += typeOffset;
+
+ if (offset > (dtohl(ty->header.size)-sizeof(ResTable_entry))) {
+ LOGW("ResTable_entry at %d is beyond type chunk data %d",
+ offset, dtohl(ty->header.size));
+ return 0;
+ }
+ if ((offset&0x3) != 0) {
+ LOGW("ResTable_entry at %d (pkg=%d type=%d ent=%d) is not on an integer boundary when looking for %s:%s/%s",
+ (int)offset, (int)group->id, (int)ti+1, (int)i,
+ String8(package, packageLen).string(),
+ String8(type, typeLen).string(),
+ String8(name, nameLen).string());
+ return 0;
+ }
+
+ const ResTable_entry* const entry = (const ResTable_entry*)
+ (((const uint8_t*)ty) + offset);
+ if (dtohs(entry->size) < sizeof(*entry)) {
+ LOGW("ResTable_entry size %d is too small", dtohs(entry->size));
+ return BAD_TYPE;
+ }
+
+ TABLE_SUPER_NOISY(printf("Looking at entry #%d: want str %d, have %d\n",
+ i, ei, dtohl(entry->key.index)));
+ if (dtohl(entry->key.index) == (size_t)ei) {
+ if (outTypeSpecFlags) {
+ *outTypeSpecFlags = typeConfigs->typeSpecFlags[i];
+ }
+ return Res_MAKEID(group->id-1, ti, i);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen,
+ String16* outPackage,
+ String16* outType,
+ String16* outName,
+ const String16* defType,
+ const String16* defPackage,
+ const char** outErrorMsg)
+{
+ const char16_t* packageEnd = NULL;
+ const char16_t* typeEnd = NULL;
+ const char16_t* p = refStr;
+ const char16_t* const end = p + refLen;
+ while (p < end) {
+ if (*p == ':') packageEnd = p;
+ else if (*p == '/') {
+ typeEnd = p;
+ break;
+ }
+ p++;
+ }
+ p = refStr;
+ if (*p == '@') p++;
+
+ if (packageEnd) {
+ *outPackage = String16(p, packageEnd-p);
+ p = packageEnd+1;
+ } else {
+ if (!defPackage) {
+ if (outErrorMsg) {
+ *outErrorMsg = "No resource package specified";
+ }
+ return false;
+ }
+ *outPackage = *defPackage;
+ }
+ if (typeEnd) {
+ *outType = String16(p, typeEnd-p);
+ p = typeEnd+1;
+ } else {
+ if (!defType) {
+ if (outErrorMsg) {
+ *outErrorMsg = "No resource type specified";
+ }
+ return false;
+ }
+ *outType = *defType;
+ }
+ *outName = String16(p, end-p);
+ return true;
+}
+
+static uint32_t get_hex(char c, bool* outError)
+{
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ return c - 'a' + 0xa;
+ } else if (c >= 'A' && c <= 'F') {
+ return c - 'A' + 0xa;
+ }
+ *outError = true;
+ return 0;
+}
+
+struct unit_entry
+{
+ const char* name;
+ size_t len;
+ uint8_t type;
+ uint32_t unit;
+ float scale;
+};
+
+static const unit_entry unitNames[] = {
+ { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f },
+ { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
+ { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
+ { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f },
+ { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f },
+ { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f },
+ { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f },
+ { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 },
+ { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static bool parse_unit(const char* str, Res_value* outValue,
+ float* outScale, const char** outEnd)
+{
+ const char* end = str;
+ while (*end != 0 && !isspace((unsigned char)*end)) {
+ end++;
+ }
+ const size_t len = end-str;
+
+ const char* realEnd = end;
+ while (*realEnd != 0 && isspace((unsigned char)*realEnd)) {
+ realEnd++;
+ }
+ if (*realEnd != 0) {
+ return false;
+ }
+
+ const unit_entry* cur = unitNames;
+ while (cur->name) {
+ if (len == cur->len && strncmp(cur->name, str, len) == 0) {
+ outValue->dataType = cur->type;
+ outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT;
+ *outScale = cur->scale;
+ *outEnd = end;
+ //printf("Found unit %s for %s\n", cur->name, str);
+ return true;
+ }
+ cur++;
+ }
+
+ return false;
+}
+
+
+bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
+{
+ while (len > 0 && isspace16(*s)) {
+ s++;
+ len--;
+ }
+
+ if (len <= 0) {
+ return false;
+ }
+
+ size_t i = 0;
+ int32_t val = 0;
+ bool neg = false;
+
+ if (*s == '-') {
+ neg = true;
+ i++;
+ }
+
+ if (s[i] < '0' || s[i] > '9') {
+ return false;
+ }
+
+ // Decimal or hex?
+ if (s[i] == '0' && s[i+1] == 'x') {
+ if (outValue)
+ outValue->dataType = outValue->TYPE_INT_HEX;
+ i += 2;
+ bool error = false;
+ while (i < len && !error) {
+ val = (val*16) + get_hex(s[i], &error);
+ i++;
+ }
+ if (error) {
+ return false;
+ }
+ } else {
+ if (outValue)
+ outValue->dataType = outValue->TYPE_INT_DEC;
+ while (i < len) {
+ if (s[i] < '0' || s[i] > '9') {
+ return false;
+ }
+ val = (val*10) + s[i]-'0';
+ i++;
+ }
+ }
+
+ if (neg) val = -val;
+
+ while (i < len && isspace16(s[i])) {
+ i++;
+ }
+
+ if (i == len) {
+ if (outValue)
+ outValue->data = val;
+ return true;
+ }
+
+ return false;
+}
+
+bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
+{
+ while (len > 0 && isspace16(*s)) {
+ s++;
+ len--;
+ }
+
+ if (len <= 0) {
+ return false;
+ }
+
+ char buf[128];
+ int i=0;
+ while (len > 0 && *s != 0 && i < 126) {
+ if (*s > 255) {
+ return false;
+ }
+ buf[i++] = *s++;
+ len--;
+ }
+
+ if (len > 0) {
+ return false;
+ }
+ if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+ return false;
+ }
+
+ buf[i] = 0;
+ const char* end;
+ float f = strtof(buf, (char**)&end);
+
+ if (*end != 0 && !isspace((unsigned char)*end)) {
+ // Might be a unit...
+ float scale;
+ if (parse_unit(end, outValue, &scale, &end)) {
+ f *= scale;
+ const bool neg = f < 0;
+ if (neg) f = -f;
+ uint64_t bits = (uint64_t)(f*(1<<23)+.5f);
+ uint32_t radix;
+ uint32_t shift;
+ if ((bits&0x7fffff) == 0) {
+ // Always use 23p0 if there is no fraction, just to make
+ // things easier to read.
+ radix = Res_value::COMPLEX_RADIX_23p0;
+ shift = 23;
+ } else if ((bits&0xffffffffff800000LL) == 0) {
+ // Magnitude is zero -- can fit in 0 bits of precision.
+ radix = Res_value::COMPLEX_RADIX_0p23;
+ shift = 0;
+ } else if ((bits&0xffffffff80000000LL) == 0) {
+ // Magnitude can fit in 8 bits of precision.
+ radix = Res_value::COMPLEX_RADIX_8p15;
+ shift = 8;
+ } else if ((bits&0xffffff8000000000LL) == 0) {
+ // Magnitude can fit in 16 bits of precision.
+ radix = Res_value::COMPLEX_RADIX_16p7;
+ shift = 16;
+ } else {
+ // Magnitude needs entire range, so no fractional part.
+ radix = Res_value::COMPLEX_RADIX_23p0;
+ shift = 23;
+ }
+ int32_t mantissa = (int32_t)(
+ (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK);
+ if (neg) {
+ mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK;
+ }
+ outValue->data |=
+ (radix<<Res_value::COMPLEX_RADIX_SHIFT)
+ | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT);
+ //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n",
+ // f * (neg ? -1 : 1), bits, f*(1<<23),
+ // radix, shift, outValue->data);
+ return true;
+ }
+ return false;
+ }
+
+ while (*end != 0 && isspace((unsigned char)*end)) {
+ end++;
+ }
+
+ if (*end == 0) {
+ if (outValue) {
+ outValue->dataType = outValue->TYPE_FLOAT;
+ *(float*)(&outValue->data) = f;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ResTable::stringToValue(Res_value* outValue, String16* outString,
+ const char16_t* s, size_t len,
+ bool preserveSpaces, bool coerceType,
+ uint32_t attrID,
+ const String16* defType,
+ const String16* defPackage,
+ Accessor* accessor,
+ void* accessorCookie,
+ uint32_t attrType,
+ bool enforcePrivate) const
+{
+ bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting();
+ const char* errorMsg = NULL;
+
+ outValue->size = sizeof(Res_value);
+ outValue->res0 = 0;
+
+ // First strip leading/trailing whitespace. Do this before handling
+ // escapes, so they can be used to force whitespace into the string.
+ if (!preserveSpaces) {
+ while (len > 0 && isspace16(*s)) {
+ s++;
+ len--;
+ }
+ while (len > 0 && isspace16(s[len-1])) {
+ len--;
+ }
+ // If the string ends with '\', then we keep the space after it.
+ if (len > 0 && s[len-1] == '\\' && s[len] != 0) {
+ len++;
+ }
+ }
+
+ //printf("Value for: %s\n", String8(s, len).string());
+
+ uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
+ uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
+ bool fromAccessor = false;
+ if (attrID != 0 && !Res_INTERNALID(attrID)) {
+ const ssize_t p = getResourcePackageIndex(attrID);
+ const bag_entry* bag;
+ ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
+ //printf("For attr 0x%08x got bag of %d\n", attrID, cnt);
+ if (cnt >= 0) {
+ while (cnt > 0) {
+ //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data);
+ switch (bag->map.name.ident) {
+ case ResTable_map::ATTR_TYPE:
+ attrType = bag->map.value.data;
+ break;
+ case ResTable_map::ATTR_MIN:
+ attrMin = bag->map.value.data;
+ break;
+ case ResTable_map::ATTR_MAX:
+ attrMax = bag->map.value.data;
+ break;
+ case ResTable_map::ATTR_L10N:
+ l10nReq = bag->map.value.data;
+ break;
+ }
+ bag++;
+ cnt--;
+ }
+ unlockBag(bag);
+ } else if (accessor && accessor->getAttributeType(attrID, &attrType)) {
+ fromAccessor = true;
+ if (attrType == ResTable_map::TYPE_ENUM
+ || attrType == ResTable_map::TYPE_FLAGS
+ || attrType == ResTable_map::TYPE_INTEGER) {
+ accessor->getAttributeMin(attrID, &attrMin);
+ accessor->getAttributeMax(attrID, &attrMax);
+ }
+ if (localizationSetting) {
+ l10nReq = accessor->getAttributeL10N(attrID);
+ }
+ }
+ }
+
+ const bool canStringCoerce =
+ coerceType && (attrType&ResTable_map::TYPE_STRING) != 0;
+
+ if (*s == '@') {
+ outValue->dataType = outValue->TYPE_REFERENCE;
+
+ // Note: we don't check attrType here because the reference can
+ // be to any other type; we just need to count on the client making
+ // sure the referenced type is correct.
+
+ //printf("Looking up ref: %s\n", String8(s, len).string());
+
+ // It's a reference!
+ if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
+ outValue->data = 0;
+ return true;
+ } else {
+ bool createIfNotFound = false;
+ const char16_t* resourceRefName;
+ int resourceNameLen;
+ if (len > 2 && s[1] == '+') {
+ createIfNotFound = true;
+ resourceRefName = s + 2;
+ resourceNameLen = len - 2;
+ } else if (len > 2 && s[1] == '*') {
+ enforcePrivate = false;
+ resourceRefName = s + 2;
+ resourceNameLen = len - 2;
+ } else {
+ createIfNotFound = false;
+ resourceRefName = s + 1;
+ resourceNameLen = len - 1;
+ }
+ String16 package, type, name;
+ if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name,
+ defType, defPackage, &errorMsg)) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, errorMsg);
+ }
+ return false;
+ }
+
+ uint32_t specFlags = 0;
+ uint32_t rid = identifierForName(name.string(), name.size(), type.string(),
+ type.size(), package.string(), package.size(), &specFlags);
+ if (rid != 0) {
+ if (enforcePrivate) {
+ if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "Resource is not public.");
+ }
+ return false;
+ }
+ }
+ if (!accessor) {
+ outValue->data = rid;
+ return true;
+ }
+ rid = Res_MAKEID(
+ accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
+ Res_GETTYPE(rid), Res_GETENTRY(rid));
+ TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n",
+ String8(package).string(), String8(type).string(),
+ String8(name).string(), rid));
+ outValue->data = rid;
+ return true;
+ }
+
+ if (accessor) {
+ uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
+ createIfNotFound);
+ if (rid != 0) {
+ TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n",
+ String8(package).string(), String8(type).string(),
+ String8(name).string(), rid));
+ outValue->data = rid;
+ return true;
+ }
+ }
+ }
+
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "No resource found that matches the given name");
+ }
+ return false;
+ }
+
+ // if we got to here, and localization is required and it's not a reference,
+ // complain and bail.
+ if (l10nReq == ResTable_map::L10N_SUGGESTED) {
+ if (localizationSetting) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "This attribute must be localized.");
+ }
+ }
+ }
+
+ if (*s == '#') {
+ // It's a color! Convert to an integer of the form 0xaarrggbb.
+ uint32_t color = 0;
+ bool error = false;
+ if (len == 4) {
+ outValue->dataType = outValue->TYPE_INT_COLOR_RGB4;
+ color |= 0xFF000000;
+ color |= get_hex(s[1], &error) << 20;
+ color |= get_hex(s[1], &error) << 16;
+ color |= get_hex(s[2], &error) << 12;
+ color |= get_hex(s[2], &error) << 8;
+ color |= get_hex(s[3], &error) << 4;
+ color |= get_hex(s[3], &error);
+ } else if (len == 5) {
+ outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4;
+ color |= get_hex(s[1], &error) << 28;
+ color |= get_hex(s[1], &error) << 24;
+ color |= get_hex(s[2], &error) << 20;
+ color |= get_hex(s[2], &error) << 16;
+ color |= get_hex(s[3], &error) << 12;
+ color |= get_hex(s[3], &error) << 8;
+ color |= get_hex(s[4], &error) << 4;
+ color |= get_hex(s[4], &error);
+ } else if (len == 7) {
+ outValue->dataType = outValue->TYPE_INT_COLOR_RGB8;
+ color |= 0xFF000000;
+ color |= get_hex(s[1], &error) << 20;
+ color |= get_hex(s[2], &error) << 16;
+ color |= get_hex(s[3], &error) << 12;
+ color |= get_hex(s[4], &error) << 8;
+ color |= get_hex(s[5], &error) << 4;
+ color |= get_hex(s[6], &error);
+ } else if (len == 9) {
+ outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8;
+ color |= get_hex(s[1], &error) << 28;
+ color |= get_hex(s[2], &error) << 24;
+ color |= get_hex(s[3], &error) << 20;
+ color |= get_hex(s[4], &error) << 16;
+ color |= get_hex(s[5], &error) << 12;
+ color |= get_hex(s[6], &error) << 8;
+ color |= get_hex(s[7], &error) << 4;
+ color |= get_hex(s[8], &error);
+ } else {
+ error = true;
+ }
+ if (!error) {
+ if ((attrType&ResTable_map::TYPE_COLOR) == 0) {
+ if (!canStringCoerce) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie,
+ "Color types not allowed");
+ }
+ return false;
+ }
+ } else {
+ outValue->data = color;
+ //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color);
+ return true;
+ }
+ } else {
+ if ((attrType&ResTable_map::TYPE_COLOR) != 0) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "Color value not valid --"
+ " must be #rgb, #argb, #rrggbb, or #aarrggbb");
+ }
+ #if 0
+ fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
+ "Resource File", //(const char*)in->getPrintableSource(),
+ String8(*curTag).string(),
+ String8(s, len).string());
+ #endif
+ return false;
+ }
+ }
+ }
+
+ if (*s == '?') {
+ outValue->dataType = outValue->TYPE_ATTRIBUTE;
+
+ // Note: we don't check attrType here because the reference can
+ // be to any other type; we just need to count on the client making
+ // sure the referenced type is correct.
+
+ //printf("Looking up attr: %s\n", String8(s, len).string());
+
+ static const String16 attr16("attr");
+ String16 package, type, name;
+ if (!expandResourceRef(s+1, len-1, &package, &type, &name,
+ &attr16, defPackage, &errorMsg)) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, errorMsg);
+ }
+ return false;
+ }
+
+ //printf("Pkg: %s, Type: %s, Name: %s\n",
+ // String8(package).string(), String8(type).string(),
+ // String8(name).string());
+ uint32_t specFlags = 0;
+ uint32_t rid =
+ identifierForName(name.string(), name.size(),
+ type.string(), type.size(),
+ package.string(), package.size(), &specFlags);
+ if (rid != 0) {
+ if (enforcePrivate) {
+ if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "Attribute is not public.");
+ }
+ return false;
+ }
+ }
+ if (!accessor) {
+ outValue->data = rid;
+ return true;
+ }
+ rid = Res_MAKEID(
+ accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
+ Res_GETTYPE(rid), Res_GETENTRY(rid));
+ //printf("Incl %s:%s/%s: 0x%08x\n",
+ // String8(package).string(), String8(type).string(),
+ // String8(name).string(), rid);
+ outValue->data = rid;
+ return true;
+ }
+
+ if (accessor) {
+ uint32_t rid = accessor->getCustomResource(package, type, name);
+ if (rid != 0) {
+ //printf("Mine %s:%s/%s: 0x%08x\n",
+ // String8(package).string(), String8(type).string(),
+ // String8(name).string(), rid);
+ outValue->data = rid;
+ return true;
+ }
+ }
+
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "No resource found that matches the given name");
+ }
+ return false;
+ }
+
+ if (stringToInt(s, len, outValue)) {
+ if ((attrType&ResTable_map::TYPE_INTEGER) == 0) {
+ // If this type does not allow integers, but does allow floats,
+ // fall through on this error case because the float type should
+ // be able to accept any integer value.
+ if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "Integer types not allowed");
+ }
+ return false;
+ }
+ } else {
+ if (((int32_t)outValue->data) < ((int32_t)attrMin)
+ || ((int32_t)outValue->data) > ((int32_t)attrMax)) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "Integer value out of range");
+ }
+ return false;
+ }
+ return true;
+ }
+ }
+
+ if (stringToFloat(s, len, outValue)) {
+ if (outValue->dataType == Res_value::TYPE_DIMENSION) {
+ if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) {
+ return true;
+ }
+ if (!canStringCoerce) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "Dimension types not allowed");
+ }
+ return false;
+ }
+ } else if (outValue->dataType == Res_value::TYPE_FRACTION) {
+ if ((attrType&ResTable_map::TYPE_FRACTION) != 0) {
+ return true;
+ }
+ if (!canStringCoerce) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "Fraction types not allowed");
+ }
+ return false;
+ }
+ } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) {
+ if (!canStringCoerce) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "Float types not allowed");
+ }
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ if (len == 4) {
+ if ((s[0] == 't' || s[0] == 'T') &&
+ (s[1] == 'r' || s[1] == 'R') &&
+ (s[2] == 'u' || s[2] == 'U') &&
+ (s[3] == 'e' || s[3] == 'E')) {
+ if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
+ if (!canStringCoerce) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "Boolean types not allowed");
+ }
+ return false;
+ }
+ } else {
+ outValue->dataType = outValue->TYPE_INT_BOOLEAN;
+ outValue->data = (uint32_t)-1;
+ return true;
+ }
+ }
+ }
+
+ if (len == 5) {
+ if ((s[0] == 'f' || s[0] == 'F') &&
+ (s[1] == 'a' || s[1] == 'A') &&
+ (s[2] == 'l' || s[2] == 'L') &&
+ (s[3] == 's' || s[3] == 'S') &&
+ (s[4] == 'e' || s[4] == 'E')) {
+ if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
+ if (!canStringCoerce) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "Boolean types not allowed");
+ }
+ return false;
+ }
+ } else {
+ outValue->dataType = outValue->TYPE_INT_BOOLEAN;
+ outValue->data = 0;
+ return true;
+ }
+ }
+ }
+
+ if ((attrType&ResTable_map::TYPE_ENUM) != 0) {
+ const ssize_t p = getResourcePackageIndex(attrID);
+ const bag_entry* bag;
+ ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
+ //printf("Got %d for enum\n", cnt);
+ if (cnt >= 0) {
+ resource_name rname;
+ while (cnt > 0) {
+ if (!Res_INTERNALID(bag->map.name.ident)) {
+ //printf("Trying attr #%08x\n", bag->map.name.ident);
+ if (getResourceName(bag->map.name.ident, &rname)) {
+ #if 0
+ printf("Matching %s against %s (0x%08x)\n",
+ String8(s, len).string(),
+ String8(rname.name, rname.nameLen).string(),
+ bag->map.name.ident);
+ #endif
+ if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
+ outValue->dataType = bag->map.value.dataType;
+ outValue->data = bag->map.value.data;
+ unlockBag(bag);
+ return true;
+ }
+ }
+
+ }
+ bag++;
+ cnt--;
+ }
+ unlockBag(bag);
+ }
+
+ if (fromAccessor) {
+ if (accessor->getAttributeEnum(attrID, s, len, outValue)) {
+ return true;
+ }
+ }
+ }
+
+ if ((attrType&ResTable_map::TYPE_FLAGS) != 0) {
+ const ssize_t p = getResourcePackageIndex(attrID);
+ const bag_entry* bag;
+ ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
+ //printf("Got %d for flags\n", cnt);
+ if (cnt >= 0) {
+ bool failed = false;
+ resource_name rname;
+ outValue->dataType = Res_value::TYPE_INT_HEX;
+ outValue->data = 0;
+ const char16_t* end = s + len;
+ const char16_t* pos = s;
+ while (pos < end && !failed) {
+ const char16_t* start = pos;
+ end++;
+ while (pos < end && *pos != '|') {
+ pos++;
+ }
+ //printf("Looking for: %s\n", String8(start, pos-start).string());
+ const bag_entry* bagi = bag;
+ ssize_t i;
+ for (i=0; i<cnt; i++, bagi++) {
+ if (!Res_INTERNALID(bagi->map.name.ident)) {
+ //printf("Trying attr #%08x\n", bagi->map.name.ident);
+ if (getResourceName(bagi->map.name.ident, &rname)) {
+ #if 0
+ printf("Matching %s against %s (0x%08x)\n",
+ String8(start,pos-start).string(),
+ String8(rname.name, rname.nameLen).string(),
+ bagi->map.name.ident);
+ #endif
+ if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
+ outValue->data |= bagi->map.value.data;
+ break;
+ }
+ }
+ }
+ }
+ if (i >= cnt) {
+ // Didn't find this flag identifier.
+ failed = true;
+ }
+ if (pos < end) {
+ pos++;
+ }
+ }
+ unlockBag(bag);
+ if (!failed) {
+ //printf("Final flag value: 0x%lx\n", outValue->data);
+ return true;
+ }
+ }
+
+
+ if (fromAccessor) {
+ if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
+ //printf("Final flag value: 0x%lx\n", outValue->data);
+ return true;
+ }
+ }
+ }
+
+ if ((attrType&ResTable_map::TYPE_STRING) == 0) {
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, "String types not allowed");
+ }
+ return false;
+ }
+
+ // Generic string handling...
+ outValue->dataType = outValue->TYPE_STRING;
+ if (outString) {
+ bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg);
+ if (accessor != NULL) {
+ accessor->reportError(accessorCookie, errorMsg);
+ }
+ return failed;
+ }
+
+ return true;
+}
+
+bool ResTable::collectString(String16* outString,
+ const char16_t* s, size_t len,
+ bool preserveSpaces,
+ const char** outErrorMsg,
+ bool append)
+{
+ String16 tmp;
+
+ char quoted = 0;
+ const char16_t* p = s;
+ while (p < (s+len)) {
+ while (p < (s+len)) {
+ const char16_t c = *p;
+ if (c == '\\') {
+ break;
+ }
+ if (!preserveSpaces) {
+ if (quoted == 0 && isspace16(c)
+ && (c != ' ' || isspace16(*(p+1)))) {
+ break;
+ }
+ if (c == '"' && (quoted == 0 || quoted == '"')) {
+ break;
+ }
+ if (c == '\'' && (quoted == 0 || quoted == '\'')) {
+ break;
+ }
+ }
+ p++;
+ }
+ if (p < (s+len)) {
+ if (p > s) {
+ tmp.append(String16(s, p-s));
+ }
+ if (!preserveSpaces && (*p == '"' || *p == '\'')) {
+ if (quoted == 0) {
+ quoted = *p;
+ } else {
+ quoted = 0;
+ }
+ p++;
+ } else if (!preserveSpaces && isspace16(*p)) {
+ // Space outside of a quote -- consume all spaces and
+ // leave a single plain space char.
+ tmp.append(String16(" "));
+ p++;
+ while (p < (s+len) && isspace16(*p)) {
+ p++;
+ }
+ } else if (*p == '\\') {
+ p++;
+ if (p < (s+len)) {
+ switch (*p) {
+ case 't':
+ tmp.append(String16("\t"));
+ break;
+ case 'n':
+ tmp.append(String16("\n"));
+ break;
+ case '#':
+ tmp.append(String16("#"));
+ break;
+ case '@':
+ tmp.append(String16("@"));
+ break;
+ case '?':
+ tmp.append(String16("?"));
+ break;
+ case '"':
+ tmp.append(String16("\""));
+ break;
+ case '\'':
+ tmp.append(String16("'"));
+ break;
+ case '\\':
+ tmp.append(String16("\\"));
+ break;
+ case 'u':
+ {
+ char16_t chr = 0;
+ int i = 0;
+ while (i < 4 && p[1] != 0) {
+ p++;
+ i++;
+ int c;
+ if (*p >= '0' && *p <= '9') {
+ c = *p - '0';
+ } else if (*p >= 'a' && *p <= 'f') {
+ c = *p - 'a' + 10;
+ } else if (*p >= 'A' && *p <= 'F') {
+ c = *p - 'A' + 10;
+ } else {
+ if (outErrorMsg) {
+ *outErrorMsg = "Bad character in \\u unicode escape sequence";
+ }
+ return false;
+ }
+ chr = (chr<<4) | c;
+ }
+ tmp.append(String16(&chr, 1));
+ } break;
+ default:
+ // ignore unknown escape chars.
+ break;
+ }
+ p++;
+ }
+ }
+ len -= (p-s);
+ s = p;
+ }
+ }
+
+ if (tmp.size() != 0) {
+ if (len > 0) {
+ tmp.append(String16(s, len));
+ }
+ if (append) {
+ outString->append(tmp);
+ } else {
+ outString->setTo(tmp);
+ }
+ } else {
+ if (append) {
+ outString->append(String16(s, len));
+ } else {
+ outString->setTo(s, len);
+ }
+ }
+
+ return true;
+}
+
+size_t ResTable::getBasePackageCount() const
+{
+ if (mError != NO_ERROR) {
+ return 0;
+ }
+ return mPackageGroups.size();
+}
+
+const char16_t* ResTable::getBasePackageName(size_t idx) const
+{
+ if (mError != NO_ERROR) {
+ return 0;
+ }
+ LOG_FATAL_IF(idx >= mPackageGroups.size(),
+ "Requested package index %d past package count %d",
+ (int)idx, (int)mPackageGroups.size());
+ return mPackageGroups[idx]->name.string();
+}
+
+uint32_t ResTable::getBasePackageId(size_t idx) const
+{
+ if (mError != NO_ERROR) {
+ return 0;
+ }
+ LOG_FATAL_IF(idx >= mPackageGroups.size(),
+ "Requested package index %d past package count %d",
+ (int)idx, (int)mPackageGroups.size());
+ return mPackageGroups[idx]->id;
+}
+
+size_t ResTable::getTableCount() const
+{
+ return mHeaders.size();
+}
+
+const ResStringPool* ResTable::getTableStringBlock(size_t index) const
+{
+ return &mHeaders[index]->values;
+}
+
+void* ResTable::getTableCookie(size_t index) const
+{
+ return mHeaders[index]->cookie;
+}
+
+void ResTable::getConfigurations(Vector<ResTable_config>* configs) const
+{
+ const size_t I = mPackageGroups.size();
+ for (size_t i=0; i<I; i++) {
+ const PackageGroup* packageGroup = mPackageGroups[i];
+ const size_t J = packageGroup->packages.size();
+ for (size_t j=0; j<J; j++) {
+ const Package* package = packageGroup->packages[j];
+ const size_t K = package->types.size();
+ for (size_t k=0; k<K; k++) {
+ const Type* type = package->types[k];
+ if (type == NULL) continue;
+ const size_t L = type->configs.size();
+ for (size_t l=0; l<L; l++) {
+ const ResTable_type* config = type->configs[l];
+ const ResTable_config* cfg = &config->config;
+ // only insert unique
+ const size_t M = configs->size();
+ size_t m;
+ for (m=0; m<M; m++) {
+ if (0 == (*configs)[m].compare(*cfg)) {
+ break;
+ }
+ }
+ // if we didn't find it
+ if (m == M) {
+ configs->add(*cfg);
+ }
+ }
+ }
+ }
+ }
+}
+
+void ResTable::getLocales(Vector<String8>* locales) const
+{
+ Vector<ResTable_config> configs;
+ LOGD("calling getConfigurations");
+ getConfigurations(&configs);
+ LOGD("called getConfigurations size=%d", (int)configs.size());
+ const size_t I = configs.size();
+ for (size_t i=0; i<I; i++) {
+ char locale[6];
+ configs[i].getLocale(locale);
+ const size_t J = locales->size();
+ size_t j;
+ for (j=0; j<J; j++) {
+ if (0 == strcmp(locale, (*locales)[j].string())) {
+ break;
+ }
+ }
+ if (j == J) {
+ locales->add(String8(locale));
+ }
+ }
+}
+
+ssize_t ResTable::getEntry(
+ const Package* package, int typeIndex, int entryIndex,
+ const ResTable_config* config,
+ const ResTable_type** outType, const ResTable_entry** outEntry,
+ const Type** outTypeClass) const
+{
+ LOGV("Getting entry from package %p\n", package);
+ const ResTable_package* const pkg = package->package;
+
+ const Type* allTypes = package->getType(typeIndex);
+ LOGV("allTypes=%p\n", allTypes);
+ if (allTypes == NULL) {
+ LOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
+ return 0;
+ }
+
+ if ((size_t)entryIndex >= allTypes->entryCount) {
+ LOGW("getEntry failing because entryIndex %d is beyond type entryCount %d",
+ entryIndex, (int)allTypes->entryCount);
+ return BAD_TYPE;
+ }
+
+ const ResTable_type* type = NULL;
+ uint32_t offset = ResTable_type::NO_ENTRY;
+ ResTable_config bestConfig;
+ memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up
+
+ const size_t NT = allTypes->configs.size();
+ for (size_t i=0; i<NT; i++) {
+ const ResTable_type* const thisType = allTypes->configs[i];
+ if (thisType == NULL) continue;
+
+ ResTable_config thisConfig;
+ thisConfig.copyFromDtoH(thisType->config);
+
+ TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d lang:%c%c=%c%c cnt:%c%c=%c%c "
+ "orien:%d=%d touch:%d=%d density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d\n",
+ entryIndex, typeIndex+1, dtohl(thisType->config.size),
+ thisConfig.mcc, thisConfig.mnc,
+ config ? config->mcc : 0, config ? config->mnc : 0,
+ thisConfig.language[0] ? thisConfig.language[0] : '-',
+ thisConfig.language[1] ? thisConfig.language[1] : '-',
+ config && config->language[0] ? config->language[0] : '-',
+ config && config->language[1] ? config->language[1] : '-',
+ thisConfig.country[0] ? thisConfig.country[0] : '-',
+ thisConfig.country[1] ? thisConfig.country[1] : '-',
+ config && config->country[0] ? config->country[0] : '-',
+ config && config->country[1] ? config->country[1] : '-',
+ thisConfig.orientation,
+ config ? config->orientation : 0,
+ thisConfig.touchscreen,
+ config ? config->touchscreen : 0,
+ thisConfig.density,
+ config ? config->density : 0,
+ thisConfig.keyboard,
+ config ? config->keyboard : 0,
+ thisConfig.inputFlags,
+ config ? config->inputFlags : 0,
+ thisConfig.navigation,
+ config ? config->navigation : 0,
+ thisConfig.screenWidth,
+ config ? config->screenWidth : 0,
+ thisConfig.screenHeight,
+ config ? config->screenHeight : 0));
+
+ // Check to make sure this one is valid for the current parameters.
+ if (config && !thisConfig.match(*config)) {
+ TABLE_GETENTRY(LOGI("Does not match config!\n"));
+ continue;
+ }
+
+ // Check if there is the desired entry in this type.
+
+ const uint8_t* const end = ((const uint8_t*)thisType)
+ + dtohl(thisType->header.size);
+ const uint32_t* const eindex = (const uint32_t*)
+ (((const uint8_t*)thisType) + dtohs(thisType->header.headerSize));
+
+ uint32_t thisOffset = dtohl(eindex[entryIndex]);
+ if (thisOffset == ResTable_type::NO_ENTRY) {
+ TABLE_GETENTRY(LOGI("Skipping because it is not defined!\n"));
+ continue;
+ }
+
+ if (type != NULL) {
+ // Check if this one is less specific than the last found. If so,
+ // we will skip it. We check starting with things we most care
+ // about to those we least care about.
+ if (!thisConfig.isBetterThan(bestConfig, config)) {
+ TABLE_GETENTRY(LOGI("This config is worse than last!\n"));
+ continue;
+ }
+ }
+
+ type = thisType;
+ offset = thisOffset;
+ bestConfig = thisConfig;
+ TABLE_GETENTRY(LOGI("Best entry so far -- using it!\n"));
+ if (!config) break;
+ }
+
+ if (type == NULL) {
+ TABLE_GETENTRY(LOGI("No value found for requested entry!\n"));
+ return BAD_INDEX;
+ }
+
+ offset += dtohl(type->entriesStart);
+ TABLE_NOISY(aout << "Looking in resource table " << package->header->header
+ << ", typeOff="
+ << (void*)(((const char*)type)-((const char*)package->header->header))
+ << ", offset=" << (void*)offset << endl);
+
+ if (offset > (dtohl(type->header.size)-sizeof(ResTable_entry))) {
+ LOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
+ offset, dtohl(type->header.size));
+ return BAD_TYPE;
+ }
+ if ((offset&0x3) != 0) {
+ LOGW("ResTable_entry at 0x%x is not on an integer boundary",
+ offset);
+ return BAD_TYPE;
+ }
+
+ const ResTable_entry* const entry = (const ResTable_entry*)
+ (((const uint8_t*)type) + offset);
+ if (dtohs(entry->size) < sizeof(*entry)) {
+ LOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size));
+ return BAD_TYPE;
+ }
+
+ *outType = type;
+ *outEntry = entry;
+ if (outTypeClass != NULL) {
+ *outTypeClass = allTypes;
+ }
+ return offset + dtohs(entry->size);
+}
+
+status_t ResTable::parsePackage(const ResTable_package* const pkg,
+ const Header* const header)
+{
+ const uint8_t* base = (const uint8_t*)pkg;
+ status_t err = validate_chunk(&pkg->header, sizeof(*pkg),
+ header->dataEnd, "ResTable_package");
+ if (err != NO_ERROR) {
+ return (mError=err);
+ }
+
+ const size_t pkgSize = dtohl(pkg->header.size);
+
+ if (dtohl(pkg->typeStrings) >= pkgSize) {
+ LOGW("ResTable_package type strings at %p are past chunk size %p.",
+ (void*)dtohl(pkg->typeStrings), (void*)pkgSize);
+ return (mError=BAD_TYPE);
+ }
+ if ((dtohl(pkg->typeStrings)&0x3) != 0) {
+ LOGW("ResTable_package type strings at %p is not on an integer boundary.",
+ (void*)dtohl(pkg->typeStrings));
+ return (mError=BAD_TYPE);
+ }
+ if (dtohl(pkg->keyStrings) >= pkgSize) {
+ LOGW("ResTable_package key strings at %p are past chunk size %p.",
+ (void*)dtohl(pkg->keyStrings), (void*)pkgSize);
+ return (mError=BAD_TYPE);
+ }
+ if ((dtohl(pkg->keyStrings)&0x3) != 0) {
+ LOGW("ResTable_package key strings at %p is not on an integer boundary.",
+ (void*)dtohl(pkg->keyStrings));
+ return (mError=BAD_TYPE);
+ }
+
+ Package* package = NULL;
+ PackageGroup* group = NULL;
+ uint32_t id = dtohl(pkg->id);
+ if (id != 0 && id < 256) {
+ size_t idx = mPackageMap[id];
+ if (idx == 0) {
+ idx = mPackageGroups.size()+1;
+
+ char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
+ strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
+ group = new PackageGroup(String16(tmpName), id);
+ if (group == NULL) {
+ return (mError=NO_MEMORY);
+ }
+
+ err = group->typeStrings.setTo(base+dtohl(pkg->typeStrings),
+ header->dataEnd-(base+dtohl(pkg->typeStrings)));
+ if (err != NO_ERROR) {
+ return (mError=err);
+ }
+ err = group->keyStrings.setTo(base+dtohl(pkg->keyStrings),
+ header->dataEnd-(base+dtohl(pkg->keyStrings)));
+ if (err != NO_ERROR) {
+ return (mError=err);
+ }
+
+ //printf("Adding new package id %d at index %d\n", id, idx);
+ err = mPackageGroups.add(group);
+ if (err < NO_ERROR) {
+ return (mError=err);
+ }
+ mPackageMap[id] = (uint8_t)idx;
+ } else {
+ group = mPackageGroups.itemAt(idx-1);
+ if (group == NULL) {
+ return (mError=UNKNOWN_ERROR);
+ }
+ }
+ package = new Package(header, pkg);
+ if (package == NULL) {
+ return (mError=NO_MEMORY);
+ }
+ err = group->packages.add(package);
+ if (err < NO_ERROR) {
+ return (mError=err);
+ }
+ } else {
+ LOG_ALWAYS_FATAL("Skins not supported!");
+ return NO_ERROR;
+ }
+
+
+ // Iterate through all chunks.
+ size_t curPackage = 0;
+
+ const ResChunk_header* chunk =
+ (const ResChunk_header*)(((const uint8_t*)pkg)
+ + dtohs(pkg->header.headerSize));
+ const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
+ while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
+ ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
+ TABLE_NOISY(LOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
+ dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
+ (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
+ const size_t csize = dtohl(chunk->size);
+ const uint16_t ctype = dtohs(chunk->type);
+ if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
+ const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk);
+ err = validate_chunk(&typeSpec->header, sizeof(*typeSpec),
+ endPos, "ResTable_typeSpec");
+ if (err != NO_ERROR) {
+ return (mError=err);
+ }
+
+ const size_t typeSpecSize = dtohl(typeSpec->header.size);
+
+ LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
+ (void*)(base-(const uint8_t*)chunk),
+ dtohs(typeSpec->header.type),
+ dtohs(typeSpec->header.headerSize),
+ (void*)typeSize));
+ // look for block overrun or int overflow when multiplying by 4
+ if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
+ || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*dtohl(typeSpec->entryCount))
+ > typeSpecSize)) {
+ LOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.",
+ (void*)(dtohs(typeSpec->header.headerSize)
+ +(sizeof(uint32_t)*dtohl(typeSpec->entryCount))),
+ (void*)typeSpecSize);
+ return (mError=BAD_TYPE);
+ }
+
+ if (typeSpec->id == 0) {
+ LOGW("ResTable_type has an id of 0.");
+ return (mError=BAD_TYPE);
+ }
+
+ while (package->types.size() < typeSpec->id) {
+ package->types.add(NULL);
+ }
+ Type* t = package->types[typeSpec->id-1];
+ if (t == NULL) {
+ t = new Type(header, package, dtohl(typeSpec->entryCount));
+ package->types.editItemAt(typeSpec->id-1) = t;
+ } else if (dtohl(typeSpec->entryCount) != t->entryCount) {
+ LOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
+ (int)dtohl(typeSpec->entryCount), (int)t->entryCount);
+ return (mError=BAD_TYPE);
+ }
+ t->typeSpecFlags = (const uint32_t*)(
+ ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
+ t->typeSpec = typeSpec;
+
+ } else if (ctype == RES_TABLE_TYPE_TYPE) {
+ const ResTable_type* type = (const ResTable_type*)(chunk);
+ err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4,
+ endPos, "ResTable_type");
+ if (err != NO_ERROR) {
+ return (mError=err);
+ }
+
+ const size_t typeSize = dtohl(type->header.size);
+
+ LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n",
+ (void*)(base-(const uint8_t*)chunk),
+ dtohs(type->header.type),
+ dtohs(type->header.headerSize),
+ (void*)typeSize));
+ if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*dtohl(type->entryCount))
+ > typeSize) {
+ LOGW("ResTable_type entry index to %p extends beyond chunk end %p.",
+ (void*)(dtohs(type->header.headerSize)
+ +(sizeof(uint32_t)*dtohl(type->entryCount))),
+ (void*)typeSize);
+ return (mError=BAD_TYPE);
+ }
+ if (dtohl(type->entryCount) != 0
+ && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
+ LOGW("ResTable_type entriesStart at %p extends beyond chunk end %p.",
+ (void*)dtohl(type->entriesStart), (void*)typeSize);
+ return (mError=BAD_TYPE);
+ }
+ if (type->id == 0) {
+ LOGW("ResTable_type has an id of 0.");
+ return (mError=BAD_TYPE);
+ }
+
+ while (package->types.size() < type->id) {
+ package->types.add(NULL);
+ }
+ Type* t = package->types[type->id-1];
+ if (t == NULL) {
+ t = new Type(header, package, dtohl(type->entryCount));
+ package->types.editItemAt(type->id-1) = t;
+ } else if (dtohl(type->entryCount) != t->entryCount) {
+ LOGW("ResTable_type entry count inconsistent: given %d, previously %d",
+ (int)dtohl(type->entryCount), (int)t->entryCount);
+ return (mError=BAD_TYPE);
+ }
+
+ TABLE_GETENTRY(
+ ResTable_config thisConfig;
+ thisConfig.copyFromDtoH(type->config);
+ LOGI("Adding config to type %d: imsi:%d/%d lang:%c%c cnt:%c%c "
+ "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n",
+ type->id,
+ thisConfig.mcc, thisConfig.mnc,
+ thisConfig.language[0] ? thisConfig.language[0] : '-',
+ thisConfig.language[1] ? thisConfig.language[1] : '-',
+ thisConfig.country[0] ? thisConfig.country[0] : '-',
+ thisConfig.country[1] ? thisConfig.country[1] : '-',
+ thisConfig.orientation,
+ thisConfig.touchscreen,
+ thisConfig.density,
+ thisConfig.keyboard,
+ thisConfig.inputFlags,
+ thisConfig.navigation,
+ thisConfig.screenWidth,
+ thisConfig.screenHeight));
+ t->configs.add(type);
+ } else {
+ status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
+ endPos, "ResTable_package:unknown");
+ if (err != NO_ERROR) {
+ return (mError=err);
+ }
+ }
+ chunk = (const ResChunk_header*)
+ (((const uint8_t*)chunk) + csize);
+ }
+
+ if (group->typeCount == 0) {
+ group->typeCount = package->types.size();
+ }
+
+ return NO_ERROR;
+}
+
+#ifndef HAVE_ANDROID_OS
+#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
+
+#define CHAR16_ARRAY_EQ(constant, var, len) \
+ ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
+
+void ResTable::print() const
+{
+ printf("mError=0x%x (%s)\n", mError, strerror(mError));
+#if 0
+ printf("mParams=%c%c-%c%c,\n",
+ mParams.language[0], mParams.language[1],
+ mParams.country[0], mParams.country[1]);
+#endif
+ size_t pgCount = mPackageGroups.size();
+ printf("Package Groups (%d)\n", (int)pgCount);
+ for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
+ const PackageGroup* pg = mPackageGroups[pgIndex];
+ printf("Package Group %d id=%d packageCount=%d name=%s\n",
+ (int)pgIndex, pg->id, (int)pg->packages.size(),
+ String8(pg->name).string());
+
+ size_t pkgCount = pg->packages.size();
+ for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
+ const Package* pkg = pg->packages[pkgIndex];
+ size_t typeCount = pkg->types.size();
+ printf(" Package %d id=%d name=%s typeCount=%d\n", (int)pkgIndex,
+ pkg->package->id, String8(String16(pkg->package->name)).string(),
+ (int)typeCount);
+ for (size_t typeIndex=0; typeIndex<typeCount; typeIndex++) {
+ const Type* typeConfigs = pkg->getType(typeIndex);
+ if (typeConfigs == NULL) {
+ printf(" type %d NULL\n", (int)typeIndex);
+ continue;
+ }
+ const size_t NTC = typeConfigs->configs.size();
+ printf(" type %d configCount=%d entryCount=%d\n",
+ (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
+ if (typeConfigs->typeSpecFlags != NULL) {
+ for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
+ uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+ | (0x00ff0000 & ((typeIndex+1)<<16))
+ | (0x0000ffff & (entryIndex));
+ resource_name resName;
+ this->getResourceName(resID, &resName);
+ printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
+ resID,
+ CHAR16_TO_CSTR(resName.package, resName.packageLen),
+ CHAR16_TO_CSTR(resName.type, resName.typeLen),
+ CHAR16_TO_CSTR(resName.name, resName.nameLen),
+ dtohl(typeConfigs->typeSpecFlags[entryIndex]));
+ }
+ }
+ for (size_t configIndex=0; configIndex<NTC; configIndex++) {
+ const ResTable_type* type = typeConfigs->configs[configIndex];
+ if ((((int)type)&0x3) != 0) {
+ printf(" NON-INTEGER ResTable_type ADDRESS: %p\n", type);
+ continue;
+ }
+ printf(" config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%d key=%d infl=%d nav=%d w=%d h=%d\n",
+ (int)configIndex,
+ type->config.language[0] ? type->config.language[0] : '-',
+ type->config.language[1] ? type->config.language[1] : '-',
+ type->config.country[0] ? type->config.country[0] : '-',
+ type->config.country[1] ? type->config.country[1] : '-',
+ type->config.orientation,
+ type->config.touchscreen,
+ dtohs(type->config.density),
+ type->config.keyboard,
+ type->config.inputFlags,
+ type->config.navigation,
+ dtohs(type->config.screenWidth),
+ dtohs(type->config.screenHeight));
+ size_t entryCount = dtohl(type->entryCount);
+ uint32_t entriesStart = dtohl(type->entriesStart);
+ if ((entriesStart&0x3) != 0) {
+ printf(" NON-INTEGER ResTable_type entriesStart OFFSET: %p\n", (void*)entriesStart);
+ continue;
+ }
+ uint32_t typeSize = dtohl(type->header.size);
+ if ((typeSize&0x3) != 0) {
+ printf(" NON-INTEGER ResTable_type header.size: %p\n", (void*)typeSize);
+ continue;
+ }
+ for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
+
+ const uint8_t* const end = ((const uint8_t*)type)
+ + dtohl(type->header.size);
+ const uint32_t* const eindex = (const uint32_t*)
+ (((const uint8_t*)type) + dtohs(type->header.headerSize));
+
+ uint32_t thisOffset = dtohl(eindex[entryIndex]);
+ if (thisOffset == ResTable_type::NO_ENTRY) {
+ continue;
+ }
+
+ uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+ | (0x00ff0000 & ((typeIndex+1)<<16))
+ | (0x0000ffff & (entryIndex));
+ resource_name resName;
+ this->getResourceName(resID, &resName);
+ printf(" resource 0x%08x %s:%s/%s: ", resID,
+ CHAR16_TO_CSTR(resName.package, resName.packageLen),
+ CHAR16_TO_CSTR(resName.type, resName.typeLen),
+ CHAR16_TO_CSTR(resName.name, resName.nameLen));
+ if ((thisOffset&0x3) != 0) {
+ printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset);
+ continue;
+ }
+ if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
+ printf("OFFSET OUT OF BOUNDS: %p+%p (size is %p)\n",
+ (void*)entriesStart, (void*)thisOffset,
+ (void*)typeSize);
+ continue;
+ }
+
+ const ResTable_entry* ent = (const ResTable_entry*)
+ (((const uint8_t*)type) + entriesStart + thisOffset);
+ if (((entriesStart + thisOffset)&0x3) != 0) {
+ printf("NON-INTEGER ResTable_entry OFFSET: %p\n",
+ (void*)(entriesStart + thisOffset));
+ continue;
+ }
+ if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
+ printf("<bag>");
+ } else {
+ uint16_t esize = dtohs(ent->size);
+ if ((esize&0x3) != 0) {
+ printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
+ continue;
+ }
+ if ((thisOffset+esize) > typeSize) {
+ printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n",
+ (void*)entriesStart, (void*)thisOffset,
+ (void*)esize, (void*)typeSize);
+ continue;
+ }
+
+ const Res_value* value = (const Res_value*)
+ (((const uint8_t*)ent) + esize);
+ printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
+ (int)value->dataType, (int)dtohl(value->data),
+ (int)dtohs(value->size), (int)value->res0);
+ }
+
+ if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
+ printf(" (PUBLIC)");
+ }
+ printf("\n");
+ }
+ }
+ }
+ }
+ }
+}
+
+#endif // HAVE_ANDROID_OS
+
+} // namespace android
diff --git a/libs/utils/SharedBuffer.cpp b/libs/utils/SharedBuffer.cpp
new file mode 100644
index 0000000..3555fb7
--- /dev/null
+++ b/libs/utils/SharedBuffer.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/SharedBuffer.h>
+#include <utils/Atomic.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+SharedBuffer* SharedBuffer::alloc(size_t size)
+{
+ SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
+ if (sb) {
+ sb->mRefs = 1;
+ sb->mSize = size;
+ }
+ return sb;
+}
+
+
+ssize_t SharedBuffer::dealloc(const SharedBuffer* released)
+{
+ if (released->mRefs != 0) return -1; // XXX: invalid operation
+ free(const_cast<SharedBuffer*>(released));
+ return 0;
+}
+
+SharedBuffer* SharedBuffer::edit() const
+{
+ if (onlyOwner()) {
+ return const_cast<SharedBuffer*>(this);
+ }
+ SharedBuffer* sb = alloc(mSize);
+ if (sb) {
+ memcpy(sb->data(), data(), size());
+ release();
+ }
+ return sb;
+}
+
+SharedBuffer* SharedBuffer::editResize(size_t newSize) const
+{
+ if (onlyOwner()) {
+ SharedBuffer* buf = const_cast<SharedBuffer*>(this);
+ if (buf->mSize == newSize) return buf;
+ buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
+ if (buf != NULL) {
+ buf->mSize = newSize;
+ return buf;
+ }
+ }
+ SharedBuffer* sb = alloc(newSize);
+ if (sb) {
+ const size_t mySize = mSize;
+ memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize);
+ release();
+ }
+ return sb;
+}
+
+SharedBuffer* SharedBuffer::attemptEdit() const
+{
+ if (onlyOwner()) {
+ return const_cast<SharedBuffer*>(this);
+ }
+ return 0;
+}
+
+SharedBuffer* SharedBuffer::reset(size_t new_size) const
+{
+ // cheap-o-reset.
+ SharedBuffer* sb = alloc(new_size);
+ if (sb) {
+ release();
+ }
+ return sb;
+}
+
+void SharedBuffer::acquire() const {
+ android_atomic_inc(&mRefs);
+}
+
+int32_t SharedBuffer::release(uint32_t flags) const
+{
+ int32_t prev = 1;
+ if (onlyOwner() || ((prev = android_atomic_dec(&mRefs)) == 1)) {
+ mRefs = 0;
+ if ((flags & eKeepStorage) == 0) {
+ free(const_cast<SharedBuffer*>(this));
+ }
+ }
+ return prev;
+}
+
+
+}; // namespace android
diff --git a/libs/utils/Socket.cpp b/libs/utils/Socket.cpp
new file mode 100644
index 0000000..51509a3
--- /dev/null
+++ b/libs/utils/Socket.cpp
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Internet address class.
+//
+
+#ifdef HAVE_WINSOCK
+// This needs to come first, or Cygwin gets concerned about a potential
+// clash between WinSock and <sys/types.h>.
+# include <winsock2.h>
+#endif
+
+#include <utils/Socket.h>
+#include <utils/inet_address.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+#ifndef HAVE_WINSOCK
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+
+/*
+ * ===========================================================================
+ * Socket
+ * ===========================================================================
+ */
+
+#ifndef INVALID_SOCKET
+# define INVALID_SOCKET (-1)
+#endif
+#define UNDEF_SOCKET ((unsigned long) INVALID_SOCKET)
+
+/*static*/ bool Socket::mBootInitialized = false;
+
+/*
+ * Extract system-dependent error code.
+ */
+static inline int getSocketError(void) {
+#ifdef HAVE_WINSOCK
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+/*
+ * One-time initialization for socket code.
+ */
+/*static*/ bool Socket::bootInit(void)
+{
+#ifdef HAVE_WINSOCK
+ WSADATA wsaData;
+ int err;
+
+ err = WSAStartup(MAKEWORD(2, 0), &wsaData);
+ if (err != 0) {
+ LOG(LOG_ERROR, "socket", "Unable to start WinSock\n");
+ return false;
+ }
+
+ LOG(LOG_INFO, "socket", "Using WinSock v%d.%d\n",
+ LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
+#endif
+
+ mBootInitialized = true;
+ return true;
+}
+
+/*
+ * One-time shutdown for socket code.
+ */
+/*static*/ void Socket::finalShutdown(void)
+{
+#ifdef HAVE_WINSOCK
+ WSACleanup();
+#endif
+ mBootInitialized = false;
+}
+
+
+/*
+ * Simple constructor. Allow the application to create us and then make
+ * bind/connect calls.
+ */
+Socket::Socket(void)
+ : mSock(UNDEF_SOCKET)
+{
+ if (!mBootInitialized)
+ LOG(LOG_WARN, "socket", "WARNING: sockets not initialized\n");
+}
+
+/*
+ * Destructor. Closes the socket and resets our storage.
+ */
+Socket::~Socket(void)
+{
+ close();
+}
+
+
+/*
+ * Create a socket and connect to the specified host and port.
+ */
+int Socket::connect(const char* host, int port)
+{
+ if (mSock != UNDEF_SOCKET) {
+ LOG(LOG_WARN, "socket", "Socket already connected\n");
+ return -1;
+ }
+
+ InetSocketAddress sockAddr;
+ if (!sockAddr.create(host, port))
+ return -1;
+
+ //return doConnect(sockAddr);
+ int foo;
+ foo = doConnect(sockAddr);
+ return foo;
+}
+
+/*
+ * Create a socket and connect to the specified host and port.
+ */
+int Socket::connect(const InetAddress* addr, int port)
+{
+ if (mSock != UNDEF_SOCKET) {
+ LOG(LOG_WARN, "socket", "Socket already connected\n");
+ return -1;
+ }
+
+ InetSocketAddress sockAddr;
+ if (!sockAddr.create(addr, port))
+ return -1;
+
+ return doConnect(sockAddr);
+}
+
+/*
+ * Finish creating a socket by connecting to the remote host.
+ *
+ * Returns 0 on success.
+ */
+int Socket::doConnect(const InetSocketAddress& sockAddr)
+{
+#ifdef HAVE_WINSOCK
+ SOCKET sock;
+#else
+ int sock;
+#endif
+ const InetAddress* addr = sockAddr.getAddress();
+ int port = sockAddr.getPort();
+ struct sockaddr_in inaddr;
+ DurationTimer connectTimer;
+
+ assert(sizeof(struct sockaddr_in) == addr->getAddressLength());
+ memcpy(&inaddr, addr->getAddress(), addr->getAddressLength());
+ inaddr.sin_port = htons(port);
+
+ //fprintf(stderr, "--- connecting to %s:%d\n",
+ // sockAddr.getHostName(), port);
+
+ sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sock == INVALID_SOCKET) {
+ int err = getSocketError();
+ LOG(LOG_ERROR, "socket", "Unable to create socket (err=%d)\n", err);
+ return (err != 0) ? err : -1;
+ }
+
+ connectTimer.start();
+
+ if (::connect(sock, (struct sockaddr*) &inaddr, sizeof(inaddr)) != 0) {
+ int err = getSocketError();
+ LOG(LOG_WARN, "socket", "Connect to %s:%d failed: %d\n",
+ sockAddr.getHostName(), port, err);
+ return (err != 0) ? err : -1;
+ }
+
+ connectTimer.stop();
+ if ((long) connectTimer.durationUsecs() > 100000) {
+ LOG(LOG_INFO, "socket",
+ "Connect to %s:%d took %.3fs\n", sockAddr.getHostName(),
+ port, ((long) connectTimer.durationUsecs()) / 1000000.0);
+ }
+
+ mSock = (unsigned long) sock;
+ LOG(LOG_VERBOSE, "socket",
+ "--- connected to %s:%d\n", sockAddr.getHostName(), port);
+ return 0;
+}
+
+
+/*
+ * Close the socket if it needs closing.
+ */
+bool Socket::close(void)
+{
+ if (mSock != UNDEF_SOCKET) {
+ //fprintf(stderr, "--- closing socket %lu\n", mSock);
+#ifdef HAVE_WINSOCK
+ if (::closesocket((SOCKET) mSock) != 0)
+ return false;
+#else
+ if (::close((int) mSock) != 0)
+ return false;
+#endif
+ }
+
+ mSock = UNDEF_SOCKET;
+
+ return true;
+}
+
+/*
+ * Read data from socket.
+ *
+ * Standard semantics: read up to "len" bytes into "buf". Returns the
+ * number of bytes read, or less than zero on error.
+ */
+int Socket::read(void* buf, ssize_t len) const
+{
+ if (mSock == UNDEF_SOCKET) {
+ LOG(LOG_ERROR, "socket", "ERROR: read on invalid socket\n");
+ return -500;
+ }
+
+#ifdef HAVE_WINSOCK
+ SOCKET sock = (SOCKET) mSock;
+#else
+ int sock = (int) mSock;
+#endif
+ int cc;
+
+ cc = recv(sock, (char*)buf, len, 0);
+ if (cc < 0) {
+ int err = getSocketError();
+ return (err > 0) ? -err : -1;
+ }
+
+ return cc;
+}
+
+/*
+ * Write data to a socket.
+ *
+ * Standard semantics: write up to "len" bytes into "buf". Returns the
+ * number of bytes written, or less than zero on error.
+ */
+int Socket::write(const void* buf, ssize_t len) const
+{
+ if (mSock == UNDEF_SOCKET) {
+ LOG(LOG_ERROR, "socket", "ERROR: write on invalid socket\n");
+ return -500;
+ }
+
+#ifdef HAVE_WINSOCK
+ SOCKET sock = (SOCKET) mSock;
+#else
+ int sock = (int) mSock;
+#endif
+ int cc;
+
+ cc = send(sock, (const char*)buf, len, 0);
+ if (cc < 0) {
+ int err = getSocketError();
+ return (err > 0) ? -err : -1;
+ }
+
+ return cc;
+}
+
+
+/*
+ * ===========================================================================
+ * Socket tests
+ * ===========================================================================
+ */
+
+/*
+ * Read all data from the socket. The data is read into a buffer that
+ * expands as needed.
+ *
+ * On exit, the buffer is returned, and the length of the data is stored
+ * in "*sz". A null byte is added to the end, but is not included in
+ * the length.
+ */
+static char* socketReadAll(const Socket& s, int *sz)
+{
+ int max, r;
+ char *data, *ptr, *tmp;
+
+ data = (char*) malloc(max = 32768);
+ if (data == NULL)
+ return NULL;
+
+ ptr = data;
+
+ for (;;) {
+ if ((ptr - data) == max) {
+ tmp = (char*) realloc(data, max *= 2);
+ if(tmp == 0) {
+ free(data);
+ return 0;
+ }
+ }
+ r = s.read(ptr, max - (ptr - data));
+ if (r == 0)
+ break;
+ if (r < 0) {
+ LOG(LOG_WARN, "socket", "WARNING: socket read failed (res=%d)\n",r);
+ break;
+ }
+ ptr += r;
+ }
+
+ if ((ptr - data) == max) {
+ tmp = (char*) realloc(data, max + 1);
+ if (tmp == NULL) {
+ free(data);
+ return NULL;
+ }
+ }
+ *ptr = '\0';
+ *sz = (ptr - data);
+ return data;
+}
+
+/*
+ * Exercise the Socket class.
+ */
+void android::TestSockets(void)
+{
+ printf("----- SOCKET TEST ------\n");
+ Socket::bootInit();
+
+ char* buf = NULL;
+ int len, cc;
+ const char* kTestStr =
+ "GET / HTTP/1.0\n"
+ "Connection: close\n"
+ "\n";
+
+ Socket sock;
+ if (sock.connect("www.google.com", 80) != 0) {
+ fprintf(stderr, "socket connected failed\n");
+ goto bail;
+ }
+
+ cc = sock.write(kTestStr, strlen(kTestStr));
+ if (cc != (int) strlen(kTestStr)) {
+ fprintf(stderr, "write failed, res=%d\n", cc);
+ goto bail;
+ }
+ buf = socketReadAll(sock, &len);
+
+ printf("GOT '%s'\n", buf);
+
+bail:
+ sock.close();
+ free(buf);
+}
+
diff --git a/libs/utils/Static.cpp b/libs/utils/Static.cpp
new file mode 100644
index 0000000..93f7e4f
--- /dev/null
+++ b/libs/utils/Static.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <private/utils/Static.h>
+
+#include <utils/BufferedTextOutput.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+
+namespace android {
+
+class LibUtilsFirstStatics
+{
+public:
+ LibUtilsFirstStatics()
+ {
+ initialize_string8();
+ initialize_string16();
+ }
+
+ ~LibUtilsFirstStatics()
+ {
+ terminate_string16();
+ terminate_string8();
+ }
+};
+
+static LibUtilsFirstStatics gFirstStatics;
+int gDarwinCantLoadAllObjects = 1;
+
+// ------------ Text output streams
+
+Vector<int32_t> gTextBuffers;
+
+class LogTextOutput : public BufferedTextOutput
+{
+public:
+ LogTextOutput() : BufferedTextOutput(MULTITHREADED) { }
+ virtual ~LogTextOutput() { };
+
+protected:
+ virtual status_t writeLines(const struct iovec& vec, size_t N)
+ {
+ android_writevLog(&vec, N);
+ return NO_ERROR;
+ }
+};
+
+class FdTextOutput : public BufferedTextOutput
+{
+public:
+ FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { }
+ virtual ~FdTextOutput() { };
+
+protected:
+ virtual status_t writeLines(const struct iovec& vec, size_t N)
+ {
+ writev(mFD, &vec, N);
+ return NO_ERROR;
+ }
+
+private:
+ int mFD;
+};
+
+static LogTextOutput gLogTextOutput;
+static FdTextOutput gStdoutTextOutput(STDOUT_FILENO);
+static FdTextOutput gStderrTextOutput(STDERR_FILENO);
+
+TextOutput& alog(gLogTextOutput);
+TextOutput& aout(gStdoutTextOutput);
+TextOutput& aerr(gStderrTextOutput);
+
+#ifndef LIBUTILS_NATIVE
+
+// ------------ ProcessState.cpp
+
+Mutex gProcessMutex;
+sp<ProcessState> gProcess;
+
+class LibUtilsIPCtStatics
+{
+public:
+ LibUtilsIPCtStatics()
+ {
+ }
+
+ ~LibUtilsIPCtStatics()
+ {
+ IPCThreadState::shutdown();
+ }
+};
+
+static LibUtilsIPCtStatics gIPCStatics;
+
+// ------------ ServiceManager.cpp
+
+Mutex gDefaultServiceManagerLock;
+sp<IServiceManager> gDefaultServiceManager;
+sp<IPermissionController> gPermissionController;
+
+#endif
+
+} // namespace android
diff --git a/libs/utils/StopWatch.cpp b/libs/utils/StopWatch.cpp
new file mode 100644
index 0000000..68a1c52
--- /dev/null
+++ b/libs/utils/StopWatch.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2005 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 "StopWatch"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/StopWatch.h>
+
+/*****************************************************************************/
+
+namespace android {
+
+
+StopWatch::StopWatch(const char *name, int clock, uint32_t flags)
+ : mName(name), mClock(clock), mFlags(flags),
+ mStartTime(0), mNumLaps(0)
+{
+ mStartTime = systemTime(mClock);
+}
+
+StopWatch::~StopWatch()
+{
+ nsecs_t elapsed = elapsedTime();
+ const int n = mNumLaps;
+ LOGD("StopWatch %s (us): %lld ", mName, ns2us(elapsed));
+ for (int i=0 ; i<n ; i++) {
+ const nsecs_t soFar = mLaps[i].soFar;
+ const nsecs_t thisLap = mLaps[i].thisLap;
+ LOGD(" [%d: %lld, %lld]", i, ns2us(soFar), ns2us(thisLap));
+ }
+}
+
+const char* StopWatch::name() const
+{
+ return mName;
+}
+
+nsecs_t StopWatch::lap()
+{
+ nsecs_t elapsed = elapsedTime();
+ if (mNumLaps >= 8) {
+ elapsed = 0;
+ } else {
+ const int n = mNumLaps;
+ mLaps[n].soFar = elapsed;
+ mLaps[n].thisLap = n ? (elapsed - mLaps[n-1].soFar) : elapsed;
+ mNumLaps = n+1;
+ }
+ return elapsed;
+}
+
+nsecs_t StopWatch::elapsedTime() const
+{
+ return systemTime(mClock) - mStartTime;
+}
+
+
+/*****************************************************************************/
+
+}; // namespace android
+
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
new file mode 100644
index 0000000..1f81cad
--- /dev/null
+++ b/libs/utils/String16.cpp
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#include <utils/String16.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/TextOutput.h>
+#include <utils/threads.h>
+
+#include <private/utils/Static.h>
+
+#ifdef HAVE_WINSOCK
+# undef nhtol
+# undef htonl
+# undef nhtos
+# undef htons
+
+# ifdef HAVE_LITTLE_ENDIAN
+# define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
+# define htonl(x) ntohl(x)
+# define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
+# define htons(x) ntohs(x)
+# else
+# define ntohl(x) (x)
+# define htonl(x) (x)
+# define ntohs(x) (x)
+# define htons(x) (x)
+# endif
+#else
+# include <netinet/in.h>
+#endif
+
+#include <memory.h>
+#include <stdio.h>
+#include <ctype.h>
+
+// ---------------------------------------------------------------------------
+
+int strcmp16(const char16_t *s1, const char16_t *s2)
+{
+ char16_t ch;
+ int d = 0;
+
+ while ( 1 ) {
+ d = (int)(ch = *s1++) - (int)*s2++;
+ if ( d || !ch )
+ break;
+ }
+
+ return d;
+}
+
+int strncmp16(const char16_t *s1, const char16_t *s2, size_t n)
+{
+ char16_t ch;
+ int d = 0;
+
+ while ( n-- ) {
+ d = (int)(ch = *s1++) - (int)*s2++;
+ if ( d || !ch )
+ break;
+ }
+
+ return d;
+}
+
+char16_t *strcpy16(char16_t *dst, const char16_t *src)
+{
+ char16_t *q = dst;
+ const char16_t *p = src;
+ char16_t ch;
+
+ do {
+ *q++ = ch = *p++;
+ } while ( ch );
+
+ return dst;
+}
+
+size_t strlen16(const char16_t *s)
+{
+ const char16_t *ss = s;
+ while ( *ss )
+ ss++;
+ return ss-s;
+}
+
+
+char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n)
+{
+ char16_t *q = dst;
+ const char16_t *p = src;
+ char ch;
+
+ while (n) {
+ n--;
+ *q++ = ch = *p++;
+ if ( !ch )
+ break;
+ }
+
+ *q = 0;
+
+ return dst;
+}
+
+size_t strnlen16(const char16_t *s, size_t maxlen)
+{
+ const char16_t *ss = s;
+
+ /* Important: the maxlen test must precede the reference through ss;
+ since the byte beyond the maximum may segfault */
+ while ((maxlen > 0) && *ss) {
+ ss++;
+ maxlen--;
+ }
+ return ss-s;
+}
+
+int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
+{
+ const char16_t* e1 = s1+n1;
+ const char16_t* e2 = s2+n2;
+
+ while (s1 < e1 && s2 < e2) {
+ const int d = (int)*s1++ - (int)*s2++;
+ if (d) {
+ return d;
+ }
+ }
+
+ return n1 < n2
+ ? (0 - (int)*s2)
+ : (n1 > n2
+ ? ((int)*s1 - 0)
+ : 0);
+}
+
+int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2)
+{
+ const char16_t* e1 = s1H+n1;
+ const char16_t* e2 = s2N+n2;
+
+ while (s1H < e1 && s2N < e2) {
+ const char16_t c2 = ntohs(*s2N);
+ const int d = (int)*s1H++ - (int)c2;
+ s2N++;
+ if (d) {
+ return d;
+ }
+ }
+
+ return n1 < n2
+ ? (0 - (int)ntohs(*s2N))
+ : (n1 > n2
+ ? ((int)*s1H - 0)
+ : 0);
+}
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+static inline size_t
+utf8_char_len(uint8_t ch)
+{
+ return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1;
+}
+
+#define UTF8_SHIFT_AND_MASK(unicode, byte) (unicode)<<=6; (unicode) |= (0x3f & (byte));
+
+static inline uint32_t
+utf8_to_utf32(const uint8_t *src, size_t length)
+{
+ uint32_t unicode;
+
+ switch (length)
+ {
+ case 1:
+ return src[0];
+ case 2:
+ unicode = src[0] & 0x1f;
+ UTF8_SHIFT_AND_MASK(unicode, src[1])
+ return unicode;
+ case 3:
+ unicode = src[0] & 0x0f;
+ UTF8_SHIFT_AND_MASK(unicode, src[1])
+ UTF8_SHIFT_AND_MASK(unicode, src[2])
+ return unicode;
+ case 4:
+ unicode = src[0] & 0x07;
+ UTF8_SHIFT_AND_MASK(unicode, src[1])
+ UTF8_SHIFT_AND_MASK(unicode, src[2])
+ UTF8_SHIFT_AND_MASK(unicode, src[3])
+ return unicode;
+ default:
+ return 0xffff;
+ }
+
+ //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result);
+}
+
+// ---------------------------------------------------------------------------
+
+static SharedBuffer* gEmptyStringBuf = NULL;
+static char16_t* gEmptyString = NULL;
+
+static inline char16_t* getEmptyString()
+{
+ gEmptyStringBuf->acquire();
+ return gEmptyString;
+}
+
+void initialize_string16()
+{
+ SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
+ char16_t* str = (char16_t*)buf->data();
+ *str = 0;
+ gEmptyStringBuf = buf;
+ gEmptyString = str;
+}
+
+void terminate_string16()
+{
+ SharedBuffer::bufferFromData(gEmptyString)->release();
+ gEmptyStringBuf = NULL;
+ gEmptyString = NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+// Note: not dealing with generating surrogate pairs.
+static char16_t* allocFromUTF8(const char* in, size_t len)
+{
+ if (len == 0) return getEmptyString();
+
+ size_t chars = 0;
+ const char* end = in+len;
+ const char* p = in;
+
+ while (p < end) {
+ chars++;
+ p += utf8_char_len(*p);
+ }
+
+ SharedBuffer* buf = SharedBuffer::alloc((chars+1)*sizeof(char16_t));
+ if (buf) {
+ p = in;
+ char16_t* str = (char16_t*)buf->data();
+ char16_t* d = str;
+ while (p < end) {
+ size_t len = utf8_char_len(*p);
+ *d++ = (char16_t)utf8_to_utf32((const uint8_t*)p, len);
+ p += len;
+ }
+ *d = 0;
+
+ //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
+ //printHexData(1, str, buf->size(), 16, 1);
+ //printf("\n");
+
+ return str;
+ }
+
+ return getEmptyString();
+}
+
+// ---------------------------------------------------------------------------
+
+String16::String16()
+ : mString(getEmptyString())
+{
+}
+
+String16::String16(const String16& o)
+ : mString(o.mString)
+{
+ SharedBuffer::bufferFromData(mString)->acquire();
+}
+
+String16::String16(const String16& o, size_t len, size_t begin)
+ : mString(getEmptyString())
+{
+ setTo(o, len, begin);
+}
+
+String16::String16(const char16_t* o)
+{
+ size_t len = strlen16(o);
+ SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
+ LOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (buf) {
+ char16_t* str = (char16_t*)buf->data();
+ strcpy16(str, o);
+ mString = str;
+ return;
+ }
+
+ mString = getEmptyString();
+}
+
+String16::String16(const char16_t* o, size_t len)
+{
+ SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
+ LOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (buf) {
+ char16_t* str = (char16_t*)buf->data();
+ memcpy(str, o, len*sizeof(char16_t));
+ str[len] = 0;
+ mString = str;
+ return;
+ }
+
+ mString = getEmptyString();
+}
+
+String16::String16(const String8& o)
+ : mString(allocFromUTF8(o.string(), o.size()))
+{
+}
+
+String16::String16(const char* o)
+ : mString(allocFromUTF8(o, strlen(o)))
+{
+}
+
+String16::String16(const char* o, size_t len)
+ : mString(allocFromUTF8(o, len))
+{
+}
+
+String16::~String16()
+{
+ SharedBuffer::bufferFromData(mString)->release();
+}
+
+void String16::setTo(const String16& other)
+{
+ SharedBuffer::bufferFromData(other.mString)->acquire();
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = other.mString;
+}
+
+status_t String16::setTo(const String16& other, size_t len, size_t begin)
+{
+ const size_t N = other.size();
+ if (begin >= N) {
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = getEmptyString();
+ return NO_ERROR;
+ }
+ if ((begin+len) > N) len = N-begin;
+ if (begin == 0 && len == N) {
+ setTo(other);
+ return NO_ERROR;
+ }
+
+ if (&other == this) {
+ LOG_ALWAYS_FATAL("Not implemented");
+ }
+
+ return setTo(other.string()+begin, len);
+}
+
+status_t String16::setTo(const char16_t* other)
+{
+ return setTo(other, strlen16(other));
+}
+
+status_t String16::setTo(const char16_t* other, size_t len)
+{
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize((len+1)*sizeof(char16_t));
+ if (buf) {
+ char16_t* str = (char16_t*)buf->data();
+ memcpy(str, other, len*sizeof(char16_t));
+ str[len] = 0;
+ mString = str;
+ return NO_ERROR;
+ }
+ return NO_MEMORY;
+}
+
+status_t String16::append(const String16& other)
+{
+ const size_t myLen = size();
+ const size_t otherLen = other.size();
+ if (myLen == 0) {
+ setTo(other);
+ return NO_ERROR;
+ } else if (otherLen == 0) {
+ return NO_ERROR;
+ }
+
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize((myLen+otherLen+1)*sizeof(char16_t));
+ if (buf) {
+ char16_t* str = (char16_t*)buf->data();
+ memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
+ mString = str;
+ return NO_ERROR;
+ }
+ return NO_MEMORY;
+}
+
+status_t String16::append(const char16_t* chrs, size_t otherLen)
+{
+ const size_t myLen = size();
+ if (myLen == 0) {
+ setTo(chrs, otherLen);
+ return NO_ERROR;
+ } else if (otherLen == 0) {
+ return NO_ERROR;
+ }
+
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize((myLen+otherLen+1)*sizeof(char16_t));
+ if (buf) {
+ char16_t* str = (char16_t*)buf->data();
+ memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
+ str[myLen+otherLen] = 0;
+ mString = str;
+ return NO_ERROR;
+ }
+ return NO_MEMORY;
+}
+
+status_t String16::insert(size_t pos, const char16_t* chrs)
+{
+ return insert(pos, chrs, strlen16(chrs));
+}
+
+status_t String16::insert(size_t pos, const char16_t* chrs, size_t len)
+{
+ const size_t myLen = size();
+ if (myLen == 0) {
+ return setTo(chrs, len);
+ return NO_ERROR;
+ } else if (len == 0) {
+ return NO_ERROR;
+ }
+
+ if (pos > myLen) pos = myLen;
+
+ #if 0
+ printf("Insert in to %s: pos=%d, len=%d, myLen=%d, chrs=%s\n",
+ String8(*this).string(), pos,
+ len, myLen, String8(chrs, len).string());
+ #endif
+
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize((myLen+len+1)*sizeof(char16_t));
+ if (buf) {
+ char16_t* str = (char16_t*)buf->data();
+ if (pos < myLen) {
+ memmove(str+pos+len, str+pos, (myLen-pos)*sizeof(char16_t));
+ }
+ memcpy(str+pos, chrs, len*sizeof(char16_t));
+ str[myLen+len] = 0;
+ mString = str;
+ #if 0
+ printf("Result (%d chrs): %s\n", size(), String8(*this).string());
+ #endif
+ return NO_ERROR;
+ }
+ return NO_MEMORY;
+}
+
+ssize_t String16::findFirst(char16_t c) const
+{
+ const char16_t* str = string();
+ const char16_t* p = str;
+ const char16_t* e = p + size();
+ while (p < e) {
+ if (*p == c) {
+ return p-str;
+ }
+ p++;
+ }
+ return -1;
+}
+
+ssize_t String16::findLast(char16_t c) const
+{
+ const char16_t* str = string();
+ const char16_t* p = str;
+ const char16_t* e = p + size();
+ while (p < e) {
+ e--;
+ if (*e == c) {
+ return e-str;
+ }
+ }
+ return -1;
+}
+
+bool String16::startsWith(const String16& prefix) const
+{
+ const size_t ps = prefix.size();
+ if (ps > size()) return false;
+ return strzcmp16(mString, ps, prefix.string(), ps) == 0;
+}
+
+bool String16::startsWith(const char16_t* prefix) const
+{
+ const size_t ps = strlen16(prefix);
+ if (ps > size()) return false;
+ return strncmp16(mString, prefix, ps) == 0;
+}
+
+status_t String16::makeLower()
+{
+ const size_t N = size();
+ const char16_t* str = string();
+ char16_t* edit = NULL;
+ for (size_t i=0; i<N; i++) {
+ const char16_t v = str[i];
+ if (v >= 'A' && v <= 'Z') {
+ if (!edit) {
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
+ if (!buf) {
+ return NO_MEMORY;
+ }
+ edit = (char16_t*)buf->data();
+ mString = str = edit;
+ }
+ edit[i] = tolower((char)v);
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
+{
+ const size_t N = size();
+ const char16_t* str = string();
+ char16_t* edit = NULL;
+ for (size_t i=0; i<N; i++) {
+ if (str[i] == replaceThis) {
+ if (!edit) {
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
+ if (!buf) {
+ return NO_MEMORY;
+ }
+ edit = (char16_t*)buf->data();
+ mString = str = edit;
+ }
+ edit[i] = withThis;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t String16::remove(size_t len, size_t begin)
+{
+ const size_t N = size();
+ if (begin >= N) {
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = getEmptyString();
+ return NO_ERROR;
+ }
+ if ((begin+len) > N) len = N-begin;
+ if (begin == 0 && len == N) {
+ return NO_ERROR;
+ }
+
+ if (begin > 0) {
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize((N+1)*sizeof(char16_t));
+ if (!buf) {
+ return NO_MEMORY;
+ }
+ char16_t* str = (char16_t*)buf->data();
+ memmove(str, str+begin, (N-begin+1)*sizeof(char16_t));
+ mString = str;
+ }
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize((len+1)*sizeof(char16_t));
+ if (buf) {
+ char16_t* str = (char16_t*)buf->data();
+ str[len] = 0;
+ mString = str;
+ return NO_ERROR;
+ }
+ return NO_MEMORY;
+}
+
+TextOutput& operator<<(TextOutput& to, const String16& val)
+{
+ to << String8(val).string();
+ return to;
+}
+
+}; // namespace android
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
new file mode 100644
index 0000000..ab843f6
--- /dev/null
+++ b/libs/utils/String8.cpp
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#include <utils/String8.h>
+
+#include <utils/Log.h>
+#include <utils/String16.h>
+#include <utils/TextOutput.h>
+#include <utils/threads.h>
+
+#include <private/utils/Static.h>
+
+#include <ctype.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+static const uint32_t kByteMask = 0x000000BF;
+static const uint32_t kByteMark = 0x00000080;
+
+// Surrogates aren't valid for UTF-32 characters, so define some
+// constants that will let us screen them out.
+static const uint32_t kUnicodeSurrogateHighStart = 0x0000D800;
+static const uint32_t kUnicodeSurrogateHighEnd = 0x0000DBFF;
+static const uint32_t kUnicodeSurrogateLowStart = 0x0000DC00;
+static const uint32_t kUnicodeSurrogateLowEnd = 0x0000DFFF;
+static const uint32_t kUnicodeSurrogateStart = kUnicodeSurrogateHighStart;
+static const uint32_t kUnicodeSurrogateEnd = kUnicodeSurrogateLowEnd;
+
+// Mask used to set appropriate bits in first byte of UTF-8 sequence,
+// indexed by number of bytes in the sequence.
+static const uint32_t kFirstByteMark[] = {
+ 0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0
+};
+
+// Separator used by resource paths. This is not platform dependent contrary
+// to OS_PATH_SEPARATOR.
+#define RES_PATH_SEPARATOR '/'
+
+// Return number of utf8 bytes required for the character.
+static size_t utf32_to_utf8_bytes(uint32_t srcChar)
+{
+ size_t bytesToWrite;
+
+ // Figure out how many bytes the result will require.
+ if (srcChar < 0x00000080)
+ {
+ bytesToWrite = 1;
+ }
+ else if (srcChar < 0x00000800)
+ {
+ bytesToWrite = 2;
+ }
+ else if (srcChar < 0x00010000)
+ {
+ if ((srcChar < kUnicodeSurrogateStart)
+ || (srcChar > kUnicodeSurrogateEnd))
+ {
+ bytesToWrite = 3;
+ }
+ else
+ {
+ // Surrogates are invalid UTF-32 characters.
+ return 0;
+ }
+ }
+ // Max code point for Unicode is 0x0010FFFF.
+ else if (srcChar < 0x00110000)
+ {
+ bytesToWrite = 4;
+ }
+ else
+ {
+ // Invalid UTF-32 character.
+ return 0;
+ }
+
+ return bytesToWrite;
+}
+
+// Write out the source character to <dstP>.
+
+static void utf32_to_utf8(uint8_t* dstP, uint32_t srcChar, size_t bytes)
+{
+ dstP += bytes;
+ switch (bytes)
+ { /* note: everything falls through. */
+ case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+ case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+ case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+ case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+static SharedBuffer* gEmptyStringBuf = NULL;
+static char* gEmptyString = NULL;
+
+extern int gDarwinCantLoadAllObjects;
+int gDarwinIsReallyAnnoying;
+
+static inline char* getEmptyString()
+{
+ gEmptyStringBuf->acquire();
+ return gEmptyString;
+}
+
+void initialize_string8()
+{
+#ifdef LIBUTILS_NATIVE
+ // Bite me, Darwin!
+ gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
+#endif
+
+ SharedBuffer* buf = SharedBuffer::alloc(1);
+ char* str = (char*)buf->data();
+ *str = 0;
+ gEmptyStringBuf = buf;
+ gEmptyString = str;
+}
+
+void terminate_string8()
+{
+ SharedBuffer::bufferFromData(gEmptyString)->release();
+ gEmptyStringBuf = NULL;
+ gEmptyString = NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+static char* allocFromUTF8(const char* in, size_t len)
+{
+ if (len > 0) {
+ SharedBuffer* buf = SharedBuffer::alloc(len+1);
+ LOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (buf) {
+ char* str = (char*)buf->data();
+ memcpy(str, in, len);
+ str[len] = 0;
+ return str;
+ }
+ return NULL;
+ }
+
+ return getEmptyString();
+}
+
+// Note: not dealing with expanding surrogate pairs.
+static char* allocFromUTF16(const char16_t* in, size_t len)
+{
+ if (len == 0) return getEmptyString();
+
+ size_t bytes = 0;
+ const char16_t* end = in+len;
+ const char16_t* p = in;
+
+ while (p < end) {
+ bytes += utf32_to_utf8_bytes(*p);
+ p++;
+ }
+
+ SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+ LOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (buf) {
+ p = in;
+ char* str = (char*)buf->data();
+ char* d = str;
+ while (p < end) {
+ uint32_t c = *p++;
+ size_t len = utf32_to_utf8_bytes(c);
+ utf32_to_utf8((uint8_t*)d, c, len);
+ d += len;
+ }
+ *d = 0;
+
+ return str;
+ }
+
+ return getEmptyString();
+}
+
+// ---------------------------------------------------------------------------
+
+String8::String8()
+ : mString(getEmptyString())
+{
+}
+
+String8::String8(const String8& o)
+ : mString(o.mString)
+{
+ SharedBuffer::bufferFromData(mString)->acquire();
+}
+
+String8::String8(const char* o)
+ : mString(allocFromUTF8(o, strlen(o)))
+{
+ if (mString == NULL) {
+ mString = getEmptyString();
+ }
+}
+
+String8::String8(const char* o, size_t len)
+ : mString(allocFromUTF8(o, len))
+{
+ if (mString == NULL) {
+ mString = getEmptyString();
+ }
+}
+
+String8::String8(const String16& o)
+ : mString(allocFromUTF16(o.string(), o.size()))
+{
+}
+
+String8::String8(const char16_t* o)
+ : mString(allocFromUTF16(o, strlen16(o)))
+{
+}
+
+String8::String8(const char16_t* o, size_t len)
+ : mString(allocFromUTF16(o, len))
+{
+}
+
+String8::~String8()
+{
+ SharedBuffer::bufferFromData(mString)->release();
+}
+
+void String8::setTo(const String8& other)
+{
+ SharedBuffer::bufferFromData(other.mString)->acquire();
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = other.mString;
+}
+
+status_t String8::setTo(const char* other)
+{
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = allocFromUTF8(other, strlen(other));
+ if (mString) return NO_ERROR;
+
+ mString = getEmptyString();
+ return NO_MEMORY;
+}
+
+status_t String8::setTo(const char* other, size_t len)
+{
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = allocFromUTF8(other, len);
+ if (mString) return NO_ERROR;
+
+ mString = getEmptyString();
+ return NO_MEMORY;
+}
+
+status_t String8::setTo(const char16_t* other, size_t len)
+{
+ SharedBuffer::bufferFromData(mString)->release();
+ mString = allocFromUTF16(other, len);
+ if (mString) return NO_ERROR;
+
+ mString = getEmptyString();
+ return NO_MEMORY;
+}
+
+status_t String8::append(const String8& other)
+{
+ const size_t otherLen = other.bytes();
+ if (bytes() == 0) {
+ setTo(other);
+ return NO_ERROR;
+ } else if (otherLen == 0) {
+ return NO_ERROR;
+ }
+
+ return real_append(other.string(), otherLen);
+}
+
+status_t String8::append(const char* other)
+{
+ return append(other, strlen(other));
+}
+
+status_t String8::append(const char* other, size_t otherLen)
+{
+ if (bytes() == 0) {
+ return setTo(other, otherLen);
+ } else if (otherLen == 0) {
+ return NO_ERROR;
+ }
+
+ return real_append(other, otherLen);
+}
+
+status_t String8::real_append(const char* other, size_t otherLen)
+{
+ const size_t myLen = bytes();
+
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize(myLen+otherLen+1);
+ if (buf) {
+ char* str = (char*)buf->data();
+ memcpy(str+myLen, other, otherLen+1);
+ mString = str;
+ return NO_ERROR;
+ }
+ return NO_MEMORY;
+}
+
+char* String8::lockBuffer(size_t size)
+{
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize(size+1);
+ if (buf) {
+ char* str = (char*)buf->data();
+ mString = str;
+ return str;
+ }
+ return NULL;
+}
+
+void String8::unlockBuffer()
+{
+ unlockBuffer(strlen(mString));
+}
+
+status_t String8::unlockBuffer(size_t size)
+{
+ if (size != this->size()) {
+ SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+ ->editResize(size+1);
+ if (buf) {
+ char* str = (char*)buf->data();
+ str[size] = 0;
+ mString = str;
+ return NO_ERROR;
+ }
+ }
+
+ return NO_MEMORY;
+}
+
+ssize_t String8::find(const char* other, size_t start) const
+{
+ size_t len = size();
+ if (start >= len) {
+ return -1;
+ }
+ const char* s = mString+start;
+ const char* p = strstr(s, other);
+ return p ? p-mString : -1;
+}
+
+void String8::toLower()
+{
+ toLower(0, size());
+}
+
+void String8::toLower(size_t start, size_t length)
+{
+ const size_t len = size();
+ if (start >= len) {
+ return;
+ }
+ if (start+length > len) {
+ length = len-start;
+ }
+ char* buf = lockBuffer(len);
+ buf += start;
+ while (length > 0) {
+ *buf = tolower(*buf);
+ buf++;
+ length--;
+ }
+ unlockBuffer(len);
+}
+
+void String8::toUpper()
+{
+ toUpper(0, size());
+}
+
+void String8::toUpper(size_t start, size_t length)
+{
+ const size_t len = size();
+ if (start >= len) {
+ return;
+ }
+ if (start+length > len) {
+ length = len-start;
+ }
+ char* buf = lockBuffer(len);
+ buf += start;
+ while (length > 0) {
+ *buf = toupper(*buf);
+ buf++;
+ length--;
+ }
+ unlockBuffer(len);
+}
+
+TextOutput& operator<<(TextOutput& to, const String8& val)
+{
+ to << val.string();
+ return to;
+}
+
+// ---------------------------------------------------------------------------
+// Path functions
+
+
+void String8::setPathName(const char* name)
+{
+ setPathName(name, strlen(name));
+}
+
+void String8::setPathName(const char* name, size_t len)
+{
+ char* buf = lockBuffer(len);
+
+ memcpy(buf, name, len);
+
+ // remove trailing path separator, if present
+ if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
+ len--;
+
+ buf[len] = '\0';
+
+ unlockBuffer(len);
+}
+
+String8 String8::getPathLeaf(void) const
+{
+ const char* cp;
+ const char*const buf = mString;
+
+ cp = strrchr(buf, OS_PATH_SEPARATOR);
+ if (cp == NULL)
+ return String8(*this);
+ else
+ return String8(cp+1);
+}
+
+String8 String8::getPathDir(void) const
+{
+ const char* cp;
+ const char*const str = mString;
+
+ cp = strrchr(str, OS_PATH_SEPARATOR);
+ if (cp == NULL)
+ return String8("");
+ else
+ return String8(str, cp - str);
+}
+
+String8 String8::walkPath(String8* outRemains) const
+{
+ const char* cp;
+ const char*const str = mString;
+ const char* buf = str;
+
+ cp = strchr(buf, OS_PATH_SEPARATOR);
+ if (cp == buf) {
+ // don't include a leading '/'.
+ buf = buf+1;
+ cp = strchr(buf, OS_PATH_SEPARATOR);
+ }
+
+ if (cp == NULL) {
+ String8 res = buf != str ? String8(buf) : *this;
+ if (outRemains) *outRemains = String8("");
+ return res;
+ }
+
+ String8 res(buf, cp-buf);
+ if (outRemains) *outRemains = String8(cp+1);
+ return res;
+}
+
+/*
+ * Helper function for finding the start of an extension in a pathname.
+ *
+ * Returns a pointer inside mString, or NULL if no extension was found.
+ */
+char* String8::find_extension(void) const
+{
+ const char* lastSlash;
+ const char* lastDot;
+ int extLen;
+ const char* const str = mString;
+
+ // only look at the filename
+ lastSlash = strrchr(str, OS_PATH_SEPARATOR);
+ if (lastSlash == NULL)
+ lastSlash = str;
+ else
+ lastSlash++;
+
+ // find the last dot
+ lastDot = strrchr(lastSlash, '.');
+ if (lastDot == NULL)
+ return NULL;
+
+ // looks good, ship it
+ return const_cast<char*>(lastDot);
+}
+
+String8 String8::getPathExtension(void) const
+{
+ char* ext;
+
+ ext = find_extension();
+ if (ext != NULL)
+ return String8(ext);
+ else
+ return String8("");
+}
+
+String8 String8::getBasePath(void) const
+{
+ char* ext;
+ const char* const str = mString;
+
+ ext = find_extension();
+ if (ext == NULL)
+ return String8(*this);
+ else
+ return String8(str, ext - str);
+}
+
+String8& String8::appendPath(const char* name)
+{
+ // TODO: The test below will fail for Win32 paths. Fix later or ignore.
+ if (name[0] != OS_PATH_SEPARATOR) {
+ if (*name == '\0') {
+ // nothing to do
+ return *this;
+ }
+
+ size_t len = length();
+ if (len == 0) {
+ // no existing filename, just use the new one
+ setPathName(name);
+ return *this;
+ }
+
+ // make room for oldPath + '/' + newPath
+ int newlen = strlen(name);
+
+ char* buf = lockBuffer(len+1+newlen);
+
+ // insert a '/' if needed
+ if (buf[len-1] != OS_PATH_SEPARATOR)
+ buf[len++] = OS_PATH_SEPARATOR;
+
+ memcpy(buf+len, name, newlen+1);
+ len += newlen;
+
+ unlockBuffer(len);
+
+ return *this;
+ } else {
+ setPathName(name);
+ return *this;
+ }
+}
+
+String8& String8::convertToResPath()
+{
+#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
+ size_t len = length();
+ if (len > 0) {
+ char * buf = lockBuffer(len);
+ for (char * end = buf + len; buf < end; ++buf) {
+ if (*buf == OS_PATH_SEPARATOR)
+ *buf = RES_PATH_SEPARATOR;
+ }
+ unlockBuffer(len);
+ }
+#endif
+ return *this;
+}
+
+
+}; // namespace android
diff --git a/libs/utils/SystemClock.cpp b/libs/utils/SystemClock.cpp
new file mode 100644
index 0000000..2bdc0ce
--- /dev/null
+++ b/libs/utils/SystemClock.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * System clock functions.
+ */
+
+#if HAVE_ANDROID_OS
+#include <linux/ioctl.h>
+#include <linux/rtc.h>
+#include <utils/Atomic.h>
+#include <linux/android_alarm.h>
+#endif
+
+#include <sys/time.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <utils/SystemClock.h>
+#include <utils/Timers.h>
+
+#define LOG_TAG "SystemClock"
+#include "utils/Log.h"
+
+namespace android {
+
+/*
+ * Set the current time. This only works when running as root.
+ */
+int setCurrentTimeMillis(int64_t millis)
+{
+#if WIN32
+ // not implemented
+ return -1;
+#else
+ struct timeval tv;
+#if HAVE_ANDROID_OS
+ struct timespec ts;
+ int fd;
+ int res;
+#endif
+ int ret = 0;
+
+ if (millis <= 0 || millis / 1000LL >= INT_MAX) {
+ return -1;
+ }
+
+ tv.tv_sec = (time_t) (millis / 1000LL);
+ tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
+
+ LOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
+
+#if HAVE_ANDROID_OS
+ fd = open("/dev/alarm", O_RDWR);
+ if(fd < 0) {
+ LOGW("Unable to open alarm driver: %s\n", strerror(errno));
+ return -1;
+ }
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+ if(res < 0) {
+ LOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
+ ret = -1;
+ }
+ close(fd);
+#else
+ if (settimeofday(&tv, NULL) != 0) {
+ LOGW("Unable to set clock to %d.%d: %s\n",
+ (int) tv.tv_sec, (int) tv.tv_usec, strerror(errno));
+ ret = -1;
+ }
+#endif
+
+ return ret;
+#endif // WIN32
+}
+
+/*
+ * native public static long uptimeMillis();
+ */
+int64_t uptimeMillis()
+{
+ int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+ return (int64_t) nanoseconds_to_milliseconds(when);
+}
+
+/*
+ * native public static long elapsedRealtime();
+ */
+int64_t elapsedRealtime()
+{
+#if HAVE_ANDROID_OS
+ static int s_fd = -1;
+
+ if (s_fd == -1) {
+ int fd = open("/dev/alarm", O_RDONLY);
+ if (android_atomic_cmpxchg(-1, fd, &s_fd)) {
+ close(fd);
+ }
+ }
+
+ struct timespec ts;
+ int result = ioctl(s_fd,
+ ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
+
+ if (result == 0) {
+ int64_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+ return (int64_t) nanoseconds_to_milliseconds(when);
+ } else {
+ // XXX: there was an error, probably because the driver didn't
+ // exist ... this should return
+ // a real error, like an exception!
+ int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+ return (int64_t) nanoseconds_to_milliseconds(when);
+ }
+#else
+ int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+ return (int64_t) nanoseconds_to_milliseconds(when);
+#endif
+}
+
+}; // namespace android
diff --git a/libs/utils/TextOutput.cpp b/libs/utils/TextOutput.cpp
new file mode 100644
index 0000000..cebee99
--- /dev/null
+++ b/libs/utils/TextOutput.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#include <utils/TextOutput.h>
+
+#include <utils/Debug.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+TextOutput& operator<<(TextOutput& to, bool val)
+{
+ if (val) to.print("true", 4);
+ else to.print("false", 5);
+ return to;
+}
+
+TextOutput& operator<<(TextOutput& to, int val)
+{
+ char buf[16];
+ sprintf(buf, "%d", val);
+ to.print(buf, strlen(buf));
+ return to;
+}
+
+TextOutput& operator<<(TextOutput& to, long val)
+{
+ char buf[16];
+ sprintf(buf, "%ld", val);
+ to.print(buf, strlen(buf));
+ return to;
+}
+
+TextOutput& operator<<(TextOutput& to, unsigned int val)
+{
+ char buf[16];
+ sprintf(buf, "%u", val);
+ to.print(buf, strlen(buf));
+ return to;
+}
+
+TextOutput& operator<<(TextOutput& to, unsigned long val)
+{
+ char buf[16];
+ sprintf(buf, "%lu", val);
+ to.print(buf, strlen(buf));
+ return to;
+}
+
+TextOutput& operator<<(TextOutput& to, long long val)
+{
+ char buf[32];
+ sprintf(buf, "%Ld", val);
+ to.print(buf, strlen(buf));
+ return to;
+}
+
+TextOutput& operator<<(TextOutput& to, unsigned long long val)
+{
+ char buf[32];
+ sprintf(buf, "%Lu", val);
+ to.print(buf, strlen(buf));
+ return to;
+}
+
+static TextOutput& print_float(TextOutput& to, double value)
+{
+ char buf[64];
+ sprintf(buf, "%g", value);
+ if( !strchr(buf, '.') && !strchr(buf, 'e') &&
+ !strchr(buf, 'E') ) {
+ strncat(buf, ".0", sizeof(buf)-1);
+ }
+ to.print(buf, strlen(buf));
+ return to;
+}
+
+TextOutput& operator<<(TextOutput& to, float val)
+{
+ return print_float(to,val);
+}
+
+TextOutput& operator<<(TextOutput& to, double val)
+{
+ return print_float(to,val);
+}
+
+TextOutput& operator<<(TextOutput& to, const void* val)
+{
+ char buf[16];
+ sprintf(buf, "%p", val);
+ to.print(buf, strlen(buf));
+ return to;
+}
+
+static void textOutputPrinter(void* cookie, const char* txt)
+{
+ ((TextOutput*)cookie)->print(txt, strlen(txt));
+}
+
+TextOutput& operator<<(TextOutput& to, const TypeCode& val)
+{
+ printTypeCode(val.typeCode(), textOutputPrinter, (void*)&to);
+ return to;
+}
+
+HexDump::HexDump(const void *buf, size_t size, size_t bytesPerLine)
+ : mBuffer(buf)
+ , mSize(size)
+ , mBytesPerLine(bytesPerLine)
+ , mSingleLineCutoff(16)
+ , mAlignment(4)
+ , mCArrayStyle(false)
+{
+ if (bytesPerLine >= 16) mAlignment = 4;
+ else if (bytesPerLine >= 8) mAlignment = 2;
+ else mAlignment = 1;
+}
+
+TextOutput& operator<<(TextOutput& to, const HexDump& val)
+{
+ printHexData(0, val.buffer(), val.size(), val.bytesPerLine(),
+ val.singleLineCutoff(), val.alignment(), val.carrayStyle(),
+ textOutputPrinter, (void*)&to);
+ return to;
+}
+
+}; // namespace android
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
new file mode 100644
index 0000000..74271ba
--- /dev/null
+++ b/libs/utils/Threads.cpp
@@ -0,0 +1,1126 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "libutils.threads"
+
+#include <utils/threads.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+# include <sched.h>
+# include <sys/resource.h>
+#elif defined(HAVE_WIN32_THREADS)
+# include <windows.h>
+# include <stdint.h>
+# include <process.h>
+# define HAVE_CREATETHREAD // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW
+#endif
+
+#if defined(HAVE_FUTEX)
+#include <private/utils/futex_synchro.h>
+#endif
+
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+
+/*
+ * ===========================================================================
+ * Thread wrappers
+ * ===========================================================================
+ */
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+#if defined(HAVE_PTHREADS)
+#if 0
+#pragma mark -
+#pragma mark PTHREAD
+#endif
+// ----------------------------------------------------------------------------
+
+/*
+ * Create and run a new thead.
+ *
+ * We create it "detached", so it cleans up after itself.
+ */
+
+typedef void* (*android_pthread_entry)(void*);
+
+struct thread_data_t {
+ thread_func_t entryFunction;
+ void* userData;
+ int priority;
+ char * threadName;
+
+ // we use this trampoline when we need to set the priority with
+ // nice/setpriority.
+ static int trampoline(const thread_data_t* t) {
+ thread_func_t f = t->entryFunction;
+ void* u = t->userData;
+ int prio = t->priority;
+ char * name = t->threadName;
+ delete t;
+ setpriority(PRIO_PROCESS, 0, prio);
+ if (name) {
+#if defined(HAVE_PRCTL)
+ // Mac OS doesn't have this, and we build libutil for the host too
+ int hasAt = 0;
+ int hasDot = 0;
+ char *s = name;
+ while (*s) {
+ if (*s == '.') hasDot = 1;
+ else if (*s == '@') hasAt = 1;
+ s++;
+ }
+ int len = s - name;
+ if (len < 15 || hasAt || !hasDot) {
+ s = name;
+ } else {
+ s = name + len - 15;
+ }
+ prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);
+#endif
+ free(name);
+ }
+ return f(u);
+ }
+};
+
+int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
+ void *userData,
+ const char* threadName,
+ int32_t threadPriority,
+ size_t threadStackSize,
+ android_thread_id_t *threadId)
+{
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+#ifdef HAVE_ANDROID_OS /* valgrind is rejecting RT-priority create reqs */
+ if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
+ // We could avoid the trampoline if there was a way to get to the
+ // android_thread_id_t (pid) from pthread_t
+ thread_data_t* t = new thread_data_t;
+ t->priority = threadPriority;
+ t->threadName = threadName ? strdup(threadName) : NULL;
+ t->entryFunction = entryFunction;
+ t->userData = userData;
+ entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
+ userData = t;
+ }
+#endif
+
+ if (threadStackSize) {
+ pthread_attr_setstacksize(&attr, threadStackSize);
+ }
+
+ errno = 0;
+ pthread_t thread;
+ int result = pthread_create(&thread, &attr,
+ (android_pthread_entry)entryFunction, userData);
+ if (result != 0) {
+ LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"
+ "(android threadPriority=%d)",
+ entryFunction, result, errno, threadPriority);
+ return 0;
+ }
+
+ if (threadId != NULL) {
+ *threadId = (android_thread_id_t)thread; // XXX: this is not portable
+ }
+ return 1;
+}
+
+android_thread_id_t androidGetThreadId()
+{
+ return (android_thread_id_t)pthread_self();
+}
+
+// ----------------------------------------------------------------------------
+#elif defined(HAVE_WIN32_THREADS)
+#if 0
+#pragma mark -
+#pragma mark WIN32_THREADS
+#endif
+// ----------------------------------------------------------------------------
+
+/*
+ * Trampoline to make us __stdcall-compliant.
+ *
+ * We're expected to delete "vDetails" when we're done.
+ */
+struct threadDetails {
+ int (*func)(void*);
+ void* arg;
+};
+static __stdcall unsigned int threadIntermediary(void* vDetails)
+{
+ struct threadDetails* pDetails = (struct threadDetails*) vDetails;
+ int result;
+
+ result = (*(pDetails->func))(pDetails->arg);
+
+ delete pDetails;
+
+ LOG(LOG_VERBOSE, "thread", "thread exiting\n");
+ return (unsigned int) result;
+}
+
+/*
+ * Create and run a new thread.
+ */
+static bool doCreateThread(android_thread_func_t fn, void* arg, android_thread_id_t *id)
+{
+ HANDLE hThread;
+ struct threadDetails* pDetails = new threadDetails; // must be on heap
+ unsigned int thrdaddr;
+
+ pDetails->func = fn;
+ pDetails->arg = arg;
+
+#if defined(HAVE__BEGINTHREADEX)
+ hThread = (HANDLE) _beginthreadex(NULL, 0, threadIntermediary, pDetails, 0,
+ &thrdaddr);
+ if (hThread == 0)
+#elif defined(HAVE_CREATETHREAD)
+ hThread = CreateThread(NULL, 0,
+ (LPTHREAD_START_ROUTINE) threadIntermediary,
+ (void*) pDetails, 0, (DWORD*) &thrdaddr);
+ if (hThread == NULL)
+#endif
+ {
+ LOG(LOG_WARN, "thread", "WARNING: thread create failed\n");
+ return false;
+ }
+
+#if defined(HAVE_CREATETHREAD)
+ /* close the management handle */
+ CloseHandle(hThread);
+#endif
+
+ if (id != NULL) {
+ *id = (android_thread_id_t)thrdaddr;
+ }
+
+ return true;
+}
+
+int androidCreateRawThreadEtc(android_thread_func_t fn,
+ void *userData,
+ const char* threadName,
+ int32_t threadPriority,
+ size_t threadStackSize,
+ android_thread_id_t *threadId)
+{
+ return doCreateThread( fn, userData, threadId);
+}
+
+android_thread_id_t androidGetThreadId()
+{
+ return (android_thread_id_t)GetCurrentThreadId();
+}
+
+// ----------------------------------------------------------------------------
+#else
+#error "Threads not supported"
+#endif
+
+// ----------------------------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Common Thread functions
+#endif
+
+int androidCreateThread(android_thread_func_t fn, void* arg)
+{
+ return createThreadEtc(fn, arg);
+}
+
+int androidCreateThreadGetID(android_thread_func_t fn, void *arg, android_thread_id_t *id)
+{
+ return createThreadEtc(fn, arg, "android:unnamed_thread",
+ PRIORITY_DEFAULT, 0, id);
+}
+
+static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
+
+int androidCreateThreadEtc(android_thread_func_t entryFunction,
+ void *userData,
+ const char* threadName,
+ int32_t threadPriority,
+ size_t threadStackSize,
+ android_thread_id_t *threadId)
+{
+ return gCreateThreadFn(entryFunction, userData, threadName,
+ threadPriority, threadStackSize, threadId);
+}
+
+void androidSetCreateThreadFunc(android_create_thread_fn func)
+{
+ gCreateThreadFn = func;
+}
+
+namespace android {
+
+/*
+ * ===========================================================================
+ * Mutex class
+ * ===========================================================================
+ */
+
+#if 0
+#pragma mark -
+#pragma mark Mutex
+#endif
+
+#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
+/*
+ * Simple pthread wrapper.
+ */
+
+Mutex::Mutex()
+{
+ _init();
+}
+
+Mutex::Mutex(const char* name)
+{
+ // XXX: name not used for now
+ _init();
+}
+
+void Mutex::_init()
+{
+ pthread_mutex_t* pMutex = new pthread_mutex_t;
+ pthread_mutex_init(pMutex, NULL);
+ mState = pMutex;
+}
+
+Mutex::~Mutex()
+{
+ delete (pthread_mutex_t*) mState;
+}
+
+status_t Mutex::lock()
+{
+ int res;
+ while ((res=pthread_mutex_lock((pthread_mutex_t*) mState)) == EINTR) ;
+ return -res;
+}
+
+void Mutex::unlock()
+{
+ pthread_mutex_unlock((pthread_mutex_t*) mState);
+}
+
+status_t Mutex::tryLock()
+{
+ int res;
+ while ((res=pthread_mutex_trylock((pthread_mutex_t*) mState)) == EINTR) ;
+ return -res;
+}
+
+#elif defined(HAVE_FUTEX)
+#if 0
+#pragma mark -
+#endif
+
+#define STATE ((futex_mutex_t*) (&mState))
+
+Mutex::Mutex()
+{
+ _init();
+}
+
+Mutex::Mutex(const char* name)
+{
+ _init();
+}
+
+void
+Mutex::_init()
+{
+ futex_mutex_init(STATE);
+}
+
+Mutex::~Mutex()
+{
+}
+
+status_t Mutex::lock()
+{
+ int res;
+ while ((res=futex_mutex_lock(STATE, FUTEX_WAIT_INFINITE)) == EINTR) ;
+ return -res;
+}
+
+void Mutex::unlock()
+{
+ futex_mutex_unlock(STATE);
+}
+
+status_t Mutex::tryLock()
+{
+ int res;
+ while ((res=futex_mutex_trylock(STATE)) == EINTR) ;
+ return -res;
+}
+#undef STATE
+
+#elif defined(HAVE_WIN32_THREADS)
+#if 0
+#pragma mark -
+#endif
+
+Mutex::Mutex()
+{
+ HANDLE hMutex;
+
+ assert(sizeof(hMutex) == sizeof(mState));
+
+ hMutex = CreateMutex(NULL, FALSE, NULL);
+ mState = (void*) hMutex;
+}
+
+Mutex::Mutex(const char* name)
+{
+ // XXX: name not used for now
+ HANDLE hMutex;
+
+ hMutex = CreateMutex(NULL, FALSE, NULL);
+ mState = (void*) hMutex;
+}
+
+Mutex::~Mutex()
+{
+ CloseHandle((HANDLE) mState);
+}
+
+status_t Mutex::lock()
+{
+ DWORD dwWaitResult;
+ dwWaitResult = WaitForSingleObject((HANDLE) mState, INFINITE);
+ return dwWaitResult != WAIT_OBJECT_0 ? -1 : NO_ERROR;
+}
+
+void Mutex::unlock()
+{
+ if (!ReleaseMutex((HANDLE) mState))
+ LOG(LOG_WARN, "thread", "WARNING: bad result from unlocking mutex\n");
+}
+
+status_t Mutex::tryLock()
+{
+ DWORD dwWaitResult;
+
+ dwWaitResult = WaitForSingleObject((HANDLE) mState, 0);
+ if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT)
+ LOG(LOG_WARN, "thread", "WARNING: bad result from try-locking mutex\n");
+ return (dwWaitResult == WAIT_OBJECT_0) ? 0 : -1;
+}
+
+#else
+#error "Somebody forgot to implement threads for this platform."
+#endif
+
+
+/*
+ * ===========================================================================
+ * Condition class
+ * ===========================================================================
+ */
+
+#if 0
+#pragma mark -
+#pragma mark Condition
+#endif
+
+#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
+
+/*
+ * Constructor. This is a simple pthread wrapper.
+ */
+Condition::Condition()
+{
+ pthread_cond_t* pCond = new pthread_cond_t;
+
+ pthread_cond_init(pCond, NULL);
+ mState = pCond;
+}
+
+/*
+ * Destructor.
+ */
+Condition::~Condition()
+{
+ pthread_cond_destroy((pthread_cond_t*) mState);
+ delete (pthread_cond_t*) mState;
+}
+
+/*
+ * Wait on a condition variable. Lock the mutex before calling.
+ */
+
+status_t Condition::wait(Mutex& mutex)
+{
+ assert(mutex.mState != NULL);
+
+ int cc;
+ while ((cc = pthread_cond_wait((pthread_cond_t*)mState,
+ (pthread_mutex_t*) mutex.mState)) == EINTR) ;
+ return -cc;
+}
+
+status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
+{
+ assert(mutex.mState != NULL);
+
+ struct timespec ts;
+ ts.tv_sec = abstime/1000000000;
+ ts.tv_nsec = abstime-(ts.tv_sec*1000000000);
+
+ int cc;
+ while ((cc = pthread_cond_timedwait((pthread_cond_t*)mState,
+ (pthread_mutex_t*) mutex.mState, &ts)) == EINTR) ;
+ return -cc;
+}
+
+status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
+{
+ return wait(mutex, systemTime()+reltime);
+}
+
+/*
+ * Signal the condition variable, allowing one thread to continue.
+ */
+void Condition::signal()
+{
+ pthread_cond_signal((pthread_cond_t*) mState);
+}
+
+/*
+ * Signal the condition variable, allowing all threads to continue.
+ */
+void Condition::broadcast()
+{
+ pthread_cond_broadcast((pthread_cond_t*) mState);
+}
+
+#elif defined(HAVE_FUTEX)
+#if 0
+#pragma mark -
+#endif
+
+#define STATE ((futex_cond_t*) (&mState))
+
+/*
+ * Constructor. This is a simple pthread wrapper.
+ */
+Condition::Condition()
+{
+ futex_cond_init(STATE);
+}
+
+/*
+ * Destructor.
+ */
+Condition::~Condition()
+{
+}
+
+/*
+ * Wait on a condition variable. Lock the mutex before calling.
+ */
+
+status_t Condition::wait(Mutex& mutex)
+{
+ assert(mutex.mState != NULL);
+
+ int res;
+ while ((res = futex_cond_wait(STATE,
+ (futex_mutex_t*)(&mutex.mState), FUTEX_WAIT_INFINITE)) == -EINTR) ;
+
+ return -res;
+}
+
+status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
+{
+ nsecs_t reltime = abstime - systemTime();
+ if (reltime <= 0) return true;
+ return waitRelative(mutex, reltime);
+}
+
+status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
+{
+ assert(mutex.mState != NULL);
+ int res;
+ unsigned msec = ns2ms(reltime);
+ if(msec == 0)
+ return true;
+ // This code will not time out at the correct time if interrupted by signals
+ while ((res = futex_cond_wait(STATE,
+ (futex_mutex_t*)(&mutex.mState), msec)) == -EINTR) ;
+ return res;
+}
+
+/*
+ * Signal the condition variable, allowing one thread to continue.
+ */
+void Condition::signal()
+{
+ futex_cond_signal(STATE);
+}
+
+/*
+ * Signal the condition variable, allowing all threads to continue.
+ */
+void Condition::broadcast()
+{
+ futex_cond_broadcast(STATE);
+}
+
+#undef STATE
+
+#elif defined(HAVE_WIN32_THREADS)
+#if 0
+#pragma mark -
+#endif
+
+/*
+ * Windows doesn't have a condition variable solution. It's possible
+ * to create one, but it's easy to get it wrong. For a discussion, and
+ * the origin of this implementation, see:
+ *
+ * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ *
+ * The implementation shown on the page does NOT follow POSIX semantics.
+ * As an optimization they require acquiring the external mutex before
+ * calling signal() and broadcast(), whereas POSIX only requires grabbing
+ * it before calling wait(). The implementation here has been un-optimized
+ * to have the correct behavior.
+ */
+typedef struct WinCondition {
+ // Number of waiting threads.
+ int waitersCount;
+
+ // Serialize access to waitersCount.
+ CRITICAL_SECTION waitersCountLock;
+
+ // Semaphore used to queue up threads waiting for the condition to
+ // become signaled.
+ HANDLE sema;
+
+ // An auto-reset event used by the broadcast/signal thread to wait
+ // for all the waiting thread(s) to wake up and be released from
+ // the semaphore.
+ HANDLE waitersDone;
+
+ // This mutex wouldn't be necessary if we required that the caller
+ // lock the external mutex before calling signal() and broadcast().
+ // I'm trying to mimic pthread semantics though.
+ HANDLE internalMutex;
+
+ // Keeps track of whether we were broadcasting or signaling. This
+ // allows us to optimize the code if we're just signaling.
+ bool wasBroadcast;
+
+ status_t wait(WinCondition* condState, HANDLE hMutex, nsecs_t* abstime)
+ {
+ // Increment the wait count, avoiding race conditions.
+ EnterCriticalSection(&condState->waitersCountLock);
+ condState->waitersCount++;
+ //printf("+++ wait: incr waitersCount to %d (tid=%ld)\n",
+ // condState->waitersCount, getThreadId());
+ LeaveCriticalSection(&condState->waitersCountLock);
+
+ DWORD timeout = INFINITE;
+ if (abstime) {
+ nsecs_t reltime = *abstime - systemTime();
+ if (reltime < 0)
+ reltime = 0;
+ timeout = reltime/1000000;
+ }
+
+ // Atomically release the external mutex and wait on the semaphore.
+ DWORD res =
+ SignalObjectAndWait(hMutex, condState->sema, timeout, FALSE);
+
+ //printf("+++ wait: awake (tid=%ld)\n", getThreadId());
+
+ // Reacquire lock to avoid race conditions.
+ EnterCriticalSection(&condState->waitersCountLock);
+
+ // No longer waiting.
+ condState->waitersCount--;
+
+ // Check to see if we're the last waiter after a broadcast.
+ bool lastWaiter = (condState->wasBroadcast && condState->waitersCount == 0);
+
+ //printf("+++ wait: lastWaiter=%d (wasBc=%d wc=%d)\n",
+ // lastWaiter, condState->wasBroadcast, condState->waitersCount);
+
+ LeaveCriticalSection(&condState->waitersCountLock);
+
+ // If we're the last waiter thread during this particular broadcast
+ // then signal broadcast() that we're all awake. It'll drop the
+ // internal mutex.
+ if (lastWaiter) {
+ // Atomically signal the "waitersDone" event and wait until we
+ // can acquire the internal mutex. We want to do this in one step
+ // because it ensures that everybody is in the mutex FIFO before
+ // any thread has a chance to run. Without it, another thread
+ // could wake up, do work, and hop back in ahead of us.
+ SignalObjectAndWait(condState->waitersDone, condState->internalMutex,
+ INFINITE, FALSE);
+ } else {
+ // Grab the internal mutex.
+ WaitForSingleObject(condState->internalMutex, INFINITE);
+ }
+
+ // Release the internal and grab the external.
+ ReleaseMutex(condState->internalMutex);
+ WaitForSingleObject(hMutex, INFINITE);
+
+ return res == WAIT_OBJECT_0 ? NO_ERROR : -1;
+ }
+} WinCondition;
+
+/*
+ * Constructor. Set up the WinCondition stuff.
+ */
+Condition::Condition()
+{
+ WinCondition* condState = new WinCondition;
+
+ condState->waitersCount = 0;
+ condState->wasBroadcast = false;
+ // semaphore: no security, initial value of 0
+ condState->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
+ InitializeCriticalSection(&condState->waitersCountLock);
+ // auto-reset event, not signaled initially
+ condState->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
+ // used so we don't have to lock external mutex on signal/broadcast
+ condState->internalMutex = CreateMutex(NULL, FALSE, NULL);
+
+ mState = condState;
+}
+
+/*
+ * Destructor. Free Windows resources as well as our allocated storage.
+ */
+Condition::~Condition()
+{
+ WinCondition* condState = (WinCondition*) mState;
+ if (condState != NULL) {
+ CloseHandle(condState->sema);
+ CloseHandle(condState->waitersDone);
+ delete condState;
+ }
+}
+
+
+status_t Condition::wait(Mutex& mutex)
+{
+ WinCondition* condState = (WinCondition*) mState;
+ HANDLE hMutex = (HANDLE) mutex.mState;
+
+ return ((WinCondition*)mState)->wait(condState, hMutex, NULL);
+}
+
+status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
+{
+ WinCondition* condState = (WinCondition*) mState;
+ HANDLE hMutex = (HANDLE) mutex.mState;
+
+ return ((WinCondition*)mState)->wait(condState, hMutex, &abstime);
+}
+
+status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
+{
+ return wait(mutex, systemTime()+reltime);
+}
+
+/*
+ * Signal the condition variable, allowing one thread to continue.
+ */
+void Condition::signal()
+{
+ WinCondition* condState = (WinCondition*) mState;
+
+ // Lock the internal mutex. This ensures that we don't clash with
+ // broadcast().
+ WaitForSingleObject(condState->internalMutex, INFINITE);
+
+ EnterCriticalSection(&condState->waitersCountLock);
+ bool haveWaiters = (condState->waitersCount > 0);
+ LeaveCriticalSection(&condState->waitersCountLock);
+
+ // If no waiters, then this is a no-op. Otherwise, knock the semaphore
+ // down a notch.
+ if (haveWaiters)
+ ReleaseSemaphore(condState->sema, 1, 0);
+
+ // Release internal mutex.
+ ReleaseMutex(condState->internalMutex);
+}
+
+/*
+ * Signal the condition variable, allowing all threads to continue.
+ *
+ * First we have to wake up all threads waiting on the semaphore, then
+ * we wait until all of the threads have actually been woken before
+ * releasing the internal mutex. This ensures that all threads are woken.
+ */
+void Condition::broadcast()
+{
+ WinCondition* condState = (WinCondition*) mState;
+
+ // Lock the internal mutex. This keeps the guys we're waking up
+ // from getting too far.
+ WaitForSingleObject(condState->internalMutex, INFINITE);
+
+ EnterCriticalSection(&condState->waitersCountLock);
+ bool haveWaiters = false;
+
+ if (condState->waitersCount > 0) {
+ haveWaiters = true;
+ condState->wasBroadcast = true;
+ }
+
+ if (haveWaiters) {
+ // Wake up all the waiters.
+ ReleaseSemaphore(condState->sema, condState->waitersCount, 0);
+
+ LeaveCriticalSection(&condState->waitersCountLock);
+
+ // Wait for all awakened threads to acquire the counting semaphore.
+ // The last guy who was waiting sets this.
+ WaitForSingleObject(condState->waitersDone, INFINITE);
+
+ // Reset wasBroadcast. (No crit section needed because nobody
+ // else can wake up to poke at it.)
+ condState->wasBroadcast = 0;
+ } else {
+ // nothing to do
+ LeaveCriticalSection(&condState->waitersCountLock);
+ }
+
+ // Release internal mutex.
+ ReleaseMutex(condState->internalMutex);
+}
+
+#else
+#error "condition variables not supported on this platform"
+#endif
+
+
+/*
+ * ===========================================================================
+ * ReadWriteLock class
+ * ===========================================================================
+ */
+
+#if 0
+#pragma mark -
+#pragma mark ReadWriteLock
+#endif
+
+/*
+ * Add a reader. Readers are nice. They share.
+ */
+void ReadWriteLock::lockForRead()
+{
+ mLock.lock();
+ while (mNumWriters > 0) {
+ LOG(LOG_DEBUG, "thread", "+++ lockForRead: waiting\n");
+ mReadWaiter.wait(mLock);
+ }
+ assert(mNumWriters == 0);
+ mNumReaders++;
+#if defined(PRINT_RENDER_TIMES)
+ if (mNumReaders == 1)
+ mDebugTimer.start();
+#endif
+ mLock.unlock();
+}
+
+/*
+ * Try to add a reader. If it doesn't work right away, return "false".
+ */
+bool ReadWriteLock::tryLockForRead()
+{
+ mLock.lock();
+ if (mNumWriters > 0) {
+ mLock.unlock();
+ return false;
+ }
+ assert(mNumWriters == 0);
+ mNumReaders++;
+#if defined(PRINT_RENDER_TIMES)
+ if (mNumReaders == 1)
+ mDebugTimer.start();
+#endif
+ mLock.unlock();
+ return true;
+}
+
+/*
+ * Remove a reader.
+ */
+void ReadWriteLock::unlockForRead()
+{
+ mLock.lock();
+ if (mNumReaders == 0) {
+ LOG(LOG_WARN, "thread",
+ "WARNING: unlockForRead requested, but not locked\n");
+ return;
+ }
+ assert(mNumReaders > 0);
+ assert(mNumWriters == 0);
+ mNumReaders--;
+ if (mNumReaders == 0) { // last reader?
+#if defined(PRINT_RENDER_TIMES)
+ mDebugTimer.stop();
+ printf(" rdlk held %.3f msec\n",
+ (double) mDebugTimer.durationUsecs() / 1000.0);
+#endif
+ //printf("+++ signaling writers (if any)\n");
+ mWriteWaiter.signal(); // wake one writer (if any)
+ }
+ mLock.unlock();
+}
+
+/*
+ * Add a writer. This requires exclusive access to the object.
+ */
+void ReadWriteLock::lockForWrite()
+{
+ mLock.lock();
+ while (mNumReaders > 0 || mNumWriters > 0) {
+ LOG(LOG_DEBUG, "thread", "+++ lockForWrite: waiting\n");
+ mWriteWaiter.wait(mLock);
+ }
+ assert(mNumReaders == 0);
+ assert(mNumWriters == 0);
+ mNumWriters++;
+#if defined(PRINT_RENDER_TIMES)
+ mDebugTimer.start();
+#endif
+ mLock.unlock();
+}
+
+/*
+ * Try to add a writer. If it doesn't work right away, return "false".
+ */
+bool ReadWriteLock::tryLockForWrite()
+{
+ mLock.lock();
+ if (mNumReaders > 0 || mNumWriters > 0) {
+ mLock.unlock();
+ return false;
+ }
+ assert(mNumReaders == 0);
+ assert(mNumWriters == 0);
+ mNumWriters++;
+#if defined(PRINT_RENDER_TIMES)
+ mDebugTimer.start();
+#endif
+ mLock.unlock();
+ return true;
+}
+
+/*
+ * Remove a writer.
+ */
+void ReadWriteLock::unlockForWrite()
+{
+ mLock.lock();
+ if (mNumWriters == 0) {
+ LOG(LOG_WARN, "thread",
+ "WARNING: unlockForWrite requested, but not locked\n");
+ return;
+ }
+ assert(mNumWriters == 1);
+ mNumWriters--;
+#if defined(PRINT_RENDER_TIMES)
+ mDebugTimer.stop();
+ //printf(" wrlk held %.3f msec\n",
+ // (double) mDebugTimer.durationUsecs() / 1000.0);
+#endif
+ // mWriteWaiter.signal(); // should other writers get first dibs?
+ //printf("+++ signaling readers (if any)\n");
+ mReadWaiter.broadcast(); // wake all readers (if any)
+ mLock.unlock();
+}
+
+// ----------------------------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Thread::Thread
+#endif
+
+/*
+ * This is our thread object!
+ */
+
+Thread::Thread(bool canCallJava)
+ : mCanCallJava(canCallJava),
+ mThread(thread_id_t(-1)),
+ mLock("Thread::mLock"),
+ mStatus(NO_ERROR),
+ mExitPending(false), mRunning(false)
+{
+}
+
+Thread::~Thread()
+{
+}
+
+status_t Thread::readyToRun()
+{
+ return NO_ERROR;
+}
+
+status_t Thread::run(const char* name, int32_t priority, size_t stack)
+{
+ Mutex::Autolock _l(mLock);
+
+ if (mRunning) {
+ // thread already started
+ return INVALID_OPERATION;
+ }
+
+ // reset status and exitPending to their default value, so we can
+ // try again after an error happened (either below, or in readyToRun())
+ mStatus = NO_ERROR;
+ mExitPending = false;
+ mThread = thread_id_t(-1);
+
+ // hold a strong reference on ourself
+ mHoldSelf = this;
+
+ bool res;
+ if (mCanCallJava) {
+ res = createThreadEtc(_threadLoop,
+ this, name, priority, stack, &mThread);
+ } else {
+ res = androidCreateRawThreadEtc(_threadLoop,
+ this, name, priority, stack, &mThread);
+ }
+
+ if (res == false) {
+ mStatus = UNKNOWN_ERROR; // something happened!
+ mRunning = false;
+ mThread = thread_id_t(-1);
+ }
+
+ if (mStatus < 0) {
+ // something happened, don't leak
+ mHoldSelf.clear();
+ }
+
+ return mStatus;
+}
+
+int Thread::_threadLoop(void* user)
+{
+ Thread* const self = static_cast<Thread*>(user);
+ sp<Thread> strong(self->mHoldSelf);
+ wp<Thread> weak(strong);
+ self->mHoldSelf.clear();
+
+ // we're about to run...
+ self->mStatus = self->readyToRun();
+ if (self->mStatus!=NO_ERROR || self->mExitPending) {
+ // pretend the thread never started...
+ self->mExitPending = false;
+ self->mRunning = false;
+ return 0;
+ }
+
+ // thread is running now
+ self->mRunning = true;
+
+ do {
+ bool result = self->threadLoop();
+ if (result == false || self->mExitPending) {
+ self->mExitPending = true;
+ self->mLock.lock();
+ self->mRunning = false;
+ self->mThreadExitedCondition.signal();
+ self->mLock.unlock();
+ break;
+ }
+
+ // Release our strong reference, to let a chance to the thread
+ // to die a peaceful death.
+ strong.clear();
+ // And immediately, reacquire a strong reference for the next loop
+ strong = weak.promote();
+ } while(strong != 0);
+
+ return 0;
+}
+
+void Thread::requestExit()
+{
+ mExitPending = true;
+}
+
+status_t Thread::requestExitAndWait()
+{
+ if (mStatus == OK) {
+
+ if (mThread == getThreadId()) {
+ LOGW(
+ "Thread (this=%p): don't call waitForExit() from this "
+ "Thread object's thread. It's a guaranteed deadlock!",
+ this);
+ return WOULD_BLOCK;
+ }
+
+ requestExit();
+
+ Mutex::Autolock _l(mLock);
+ while (mRunning == true) {
+ mThreadExitedCondition.wait(mLock);
+ }
+ mExitPending = false;
+ }
+ return mStatus;
+}
+
+bool Thread::exitPending() const
+{
+ return mExitPending;
+}
+
+
+
+}; // namespace android
diff --git a/libs/utils/TimerProbe.cpp b/libs/utils/TimerProbe.cpp
new file mode 100644
index 0000000..835480d
--- /dev/null
+++ b/libs/utils/TimerProbe.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#include <utils/TimerProbe.h>
+
+#if ENABLE_TIMER_PROBE
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "time"
+
+namespace android {
+
+Vector<TimerProbe::Bucket> TimerProbe::gBuckets;
+TimerProbe* TimerProbe::gExecuteChain;
+int TimerProbe::gIndent;
+timespec TimerProbe::gRealBase;
+
+TimerProbe::TimerProbe(const char tag[], int* slot) : mTag(tag)
+{
+ mNext = gExecuteChain;
+ gExecuteChain = this;
+ mIndent = gIndent;
+ gIndent += 1;
+ if (mIndent > 0) {
+ if (*slot == 0) {
+ int count = gBuckets.add();
+ *slot = count;
+ Bucket& bucket = gBuckets.editItemAt(count);
+ memset(&bucket, 0, sizeof(Bucket));
+ bucket.mTag = tag;
+ bucket.mSlotPtr = slot;
+ bucket.mIndent = mIndent;
+ }
+ mBucket = *slot;
+ }
+ clock_gettime(CLOCK_REALTIME, &mRealStart);
+ if (gRealBase.tv_sec == 0)
+ gRealBase = mRealStart;
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mPStart);
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mTStart);
+}
+
+void TimerProbe::end()
+{
+ timespec realEnd, pEnd, tEnd;
+ clock_gettime(CLOCK_REALTIME, &realEnd);
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &pEnd);
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tEnd);
+ print(realEnd, pEnd, tEnd);
+ mTag = NULL;
+}
+
+TimerProbe::~TimerProbe()
+{
+ if (mTag != NULL)
+ end();
+ gExecuteChain = mNext;
+ gIndent--;
+}
+
+
+uint32_t TimerProbe::ElapsedTime(const timespec& start, const timespec& end)
+{
+ int sec = end.tv_sec - start.tv_sec;
+ int nsec = end.tv_nsec - start.tv_nsec;
+ if (nsec < 0) {
+ sec--;
+ nsec += 1000000000;
+ }
+ return sec * 1000000 + nsec / 1000;
+}
+
+void TimerProbe::print(const timespec& r, const timespec& p,
+ const timespec& t) const
+{
+ uint32_t es = ElapsedTime(gRealBase, mRealStart);
+ uint32_t er = ElapsedTime(mRealStart, r);
+ uint32_t ep = ElapsedTime(mPStart, p);
+ uint32_t et = ElapsedTime(mTStart, t);
+ if (mIndent > 0) {
+ Bucket& bucket = gBuckets.editItemAt(mBucket);
+ if (bucket.mStart == 0)
+ bucket.mStart = es;
+ bucket.mReal += er;
+ bucket.mProcess += ep;
+ bucket.mThread += et;
+ bucket.mCount++;
+ return;
+ }
+ int index = 0;
+ int buckets = gBuckets.size();
+ int count = 1;
+ const char* tag = mTag;
+ int indent = mIndent;
+ do {
+ LOGD("%-30.30s: (%3d) %-5.*s time=%-10.3f real=%7dus process=%7dus (%3d%%) thread=%7dus (%3d%%)\n",
+ tag, count, indent > 5 ? 5 : indent, "+++++", es / 1000000.0,
+ er, ep, ep * 100 / er, et, et * 100 / er);
+ if (index >= buckets)
+ break;
+ Bucket& bucket = gBuckets.editItemAt(index);
+ count = bucket.mCount;
+ es = bucket.mStart;
+ er = bucket.mReal;
+ ep = bucket.mProcess;
+ et = bucket.mThread;
+ tag = bucket.mTag;
+ indent = bucket.mIndent;
+ *bucket.mSlotPtr = 0;
+ } while (++index); // always true
+ gBuckets.clear();
+}
+
+}; // namespace android
+
+#endif
diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp
new file mode 100644
index 0000000..2abc811
--- /dev/null
+++ b/libs/utils/Timers.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Timer functions.
+//
+#include <utils/Timers.h>
+#include <utils/ported.h> // may need usleep
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+#ifdef HAVE_WIN32_THREADS
+#include <windows.h>
+#endif
+
+nsecs_t systemTime(int clock)
+{
+#if defined(HAVE_POSIX_CLOCKS)
+ static const clockid_t clocks[] = {
+ CLOCK_REALTIME,
+ CLOCK_MONOTONIC,
+ CLOCK_PROCESS_CPUTIME_ID,
+ CLOCK_THREAD_CPUTIME_ID
+ };
+ struct timespec t;
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(clocks[clock], &t);
+ return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+#else
+ // we don't support the clocks here.
+ struct timeval t;
+ t.tv_sec = t.tv_usec = 0;
+ gettimeofday(&t, NULL);
+ return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
+#endif
+}
+
+//#define MONITOR_USLEEP
+
+/*
+ * Sleep long enough that we'll wake up "interval" milliseconds after
+ * the previous snooze.
+ *
+ * The "nextTick" argument is updated on each call, and should be passed
+ * in every time. Set its fields to zero on the first call.
+ *
+ * Returns the #of intervals we have overslept, which will be zero if we're
+ * on time. [Currently just returns 0 or 1.]
+ */
+int sleepForInterval(long interval, struct timeval* pNextTick)
+{
+ struct timeval now;
+ long long timeBeforeNext;
+ long sleepTime = 0;
+ bool overSlept = false;
+ //int usleepBias = 0;
+
+#ifdef USLEEP_BIAS
+ /*
+ * Linux likes to add 9000ms or so.
+ * [not using this for now]
+ */
+ //usleepBias = USLEEP_BIAS;
+#endif
+
+ gettimeofday(&now, NULL);
+
+ if (pNextTick->tv_sec == 0) {
+ /* special-case for first time through */
+ *pNextTick = now;
+ sleepTime = interval;
+ android::DurationTimer::addToTimeval(pNextTick, interval);
+ } else {
+ /*
+ * Compute how much time there is before the next tick. If this
+ * value is negative, we've run over. If we've run over a little
+ * bit we can shorten the next frame to keep the pace steady, but
+ * if we've dramatically overshot we need to re-sync.
+ */
+ timeBeforeNext = android::DurationTimer::subtractTimevals(pNextTick, &now);
+ //printf("TOP: now=%ld.%ld next=%ld.%ld diff=%ld\n",
+ // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
+ // (long) timeBeforeNext);
+ if (timeBeforeNext < -interval) {
+ /* way over */
+ overSlept = true;
+ sleepTime = 0;
+ *pNextTick = now;
+ } else if (timeBeforeNext <= 0) {
+ /* slightly over, keep the pace steady */
+ overSlept = true;
+ sleepTime = 0;
+ } else if (timeBeforeNext <= interval) {
+ /* right on schedule */
+ sleepTime = timeBeforeNext;
+ } else if (timeBeforeNext > interval && timeBeforeNext <= 2*interval) {
+ /* sleep call returned early; do a longer sleep this time */
+ sleepTime = timeBeforeNext;
+ } else if (timeBeforeNext > interval) {
+ /* we went back in time -- somebody updated system clock? */
+ /* (could also be a *seriously* broken usleep()) */
+ LOG(LOG_DEBUG, "",
+ " Impossible: timeBeforeNext = %ld\n", (long)timeBeforeNext);
+ sleepTime = 0;
+ *pNextTick = now;
+ }
+ android::DurationTimer::addToTimeval(pNextTick, interval);
+ }
+ //printf(" Before sleep: now=%ld.%ld next=%ld.%ld sleepTime=%ld\n",
+ // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
+ // sleepTime);
+
+ /*
+ * Sleep for the designated period of time.
+ *
+ * Linux tends to sleep for longer than requested, often by 17-18ms.
+ * MinGW tends to sleep for less than requested, by as much as 14ms,
+ * but occasionally oversleeps for 40+ms (looks like some external
+ * factors plus round-off on a 64Hz clock). Cygwin is pretty steady.
+ *
+ * If you start the MinGW version, and then launch the Cygwin version,
+ * the MinGW clock becomes more erratic. Not entirely sure why.
+ *
+ * (There's a lot of stuff here; it's really just a usleep() call with
+ * a bunch of instrumentation.)
+ */
+ if (sleepTime > 0) {
+#if defined(MONITOR_USLEEP)
+ struct timeval before, after;
+ long long actual;
+
+ gettimeofday(&before, NULL);
+ usleep((long) sleepTime);
+ gettimeofday(&after, NULL);
+
+ /* check usleep() accuracy; default Linux threads are pretty sloppy */
+ actual = android::DurationTimer::subtractTimevals(&after, &before);
+ if ((long) actual < sleepTime - 14000 /*(sleepTime/10)*/ ||
+ (long) actual > sleepTime + 20000 /*(sleepTime/10)*/)
+ {
+ LOG(LOG_DEBUG, "", " Odd usleep: req=%ld, actual=%ld\n", sleepTime,
+ (long) actual);
+ }
+#else
+#ifdef HAVE_WIN32_THREADS
+ Sleep( sleepTime/1000 );
+#else
+ usleep((long) sleepTime);
+#endif
+#endif
+ }
+
+ //printf("slept %d\n", sleepTime);
+
+ if (overSlept)
+ return 1; // close enough
+ else
+ return 0;
+}
+
+
+/*
+ * ===========================================================================
+ * DurationTimer
+ * ===========================================================================
+ */
+
+using namespace android;
+
+// Start the timer.
+void DurationTimer::start(void)
+{
+ gettimeofday(&mStartWhen, NULL);
+}
+
+// Stop the timer.
+void DurationTimer::stop(void)
+{
+ gettimeofday(&mStopWhen, NULL);
+}
+
+// Get the duration in microseconds.
+long long DurationTimer::durationUsecs(void) const
+{
+ return (long) subtractTimevals(&mStopWhen, &mStartWhen);
+}
+
+// Subtract two timevals. Returns the difference (ptv1-ptv2) in
+// microseconds.
+/*static*/ long long DurationTimer::subtractTimevals(const struct timeval* ptv1,
+ const struct timeval* ptv2)
+{
+ long long stop = ((long long) ptv1->tv_sec) * 1000000LL +
+ ((long long) ptv1->tv_usec);
+ long long start = ((long long) ptv2->tv_sec) * 1000000LL +
+ ((long long) ptv2->tv_usec);
+ return stop - start;
+}
+
+// Add the specified amount of time to the timeval.
+/*static*/ void DurationTimer::addToTimeval(struct timeval* ptv, long usec)
+{
+ if (usec < 0) {
+ LOG(LOG_WARN, "", "Negative values not supported in addToTimeval\n");
+ return;
+ }
+
+ // normalize tv_usec if necessary
+ if (ptv->tv_usec >= 1000000) {
+ ptv->tv_sec += ptv->tv_usec / 1000000;
+ ptv->tv_usec %= 1000000;
+ }
+
+ ptv->tv_usec += usec % 1000000;
+ if (ptv->tv_usec >= 1000000) {
+ ptv->tv_usec -= 1000000;
+ ptv->tv_sec++;
+ }
+ ptv->tv_sec += usec / 1000000;
+}
+
diff --git a/libs/utils/Unicode.cpp b/libs/utils/Unicode.cpp
new file mode 100644
index 0000000..33f535f
--- /dev/null
+++ b/libs/utils/Unicode.cpp
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+#include "utils/AndroidUnicode.h"
+#include "characterData.h"
+
+#define LOG_TAG "Unicode"
+#include "utils/Log.h"
+
+// ICU headers for using macros
+#include <unicode/utf16.h>
+
+#define MIN_RADIX 2
+#define MAX_RADIX 36
+
+#define TYPE_SHIFT 0
+#define TYPE_MASK ((1<<5)-1)
+
+#define DIRECTION_SHIFT (TYPE_SHIFT+5)
+#define DIRECTION_MASK ((1<<5)-1)
+
+#define MIRRORED_SHIFT (DIRECTION_SHIFT+5)
+#define MIRRORED_MASK ((1<<1)-1)
+
+#define TOUPPER_SHIFT (MIRRORED_SHIFT+1)
+#define TOUPPER_MASK ((1<<6)-1)
+
+#define TOLOWER_SHIFT (TOUPPER_SHIFT+6)
+#define TOLOWER_MASK ((1<<6)-1)
+
+#define TOTITLE_SHIFT (TOLOWER_SHIFT+6)
+#define TOTITLE_MASK ((1<<2)-1)
+
+#define MIRROR_SHIFT (TOTITLE_SHIFT+2)
+#define MIRROR_MASK ((1<<5)-1)
+
+#define NUMERIC_SHIFT (TOTITLE_SHIFT+2)
+#define NUMERIC_MASK ((1<<7)-1)
+
+#define DECOMPOSITION_SHIFT (11)
+#define DECOMPOSITION_MASK ((1<<5)-1)
+
+/*
+ * Returns the value stored in the CharacterData tables that contains
+ * an index into the packed data table and the decomposition type.
+ */
+static uint16_t findCharacterValue(UChar32 c)
+{
+ LOG_ASSERT(c >= 0 && c <= 0x10FFFF, "findCharacterValue received an invalid codepoint");
+ if (c < 256)
+ return CharacterData::LATIN1_DATA[c];
+
+ // Rotate the bits because the tables are separated into even and odd codepoints
+ c = (c >> 1) | ((c & 1) << 20);
+
+ CharacterData::Range search = CharacterData::FULL_DATA[c >> 16];
+ const uint32_t* array = search.array;
+
+ // This trick is so that that compare in the while loop does not
+ // need to shift the array entry down by 16
+ c <<= 16;
+ c |= 0xFFFF;
+
+ int high = (int)search.length - 1;
+ int low = 0;
+
+ if (high < 0)
+ return 0;
+
+ while (low < high - 1)
+ {
+ int probe = (high + low) >> 1;
+
+ // The entries contain the codepoint in the high 16 bits and the index
+ // into PACKED_DATA in the low 16.
+ if (array[probe] > (unsigned)c)
+ high = probe;
+ else
+ low = probe;
+ }
+
+ LOG_ASSERT((array[low] <= (unsigned)c), "A suitable range was not found");
+ return array[low] & 0xFFFF;
+}
+
+uint32_t android::Unicode::getPackedData(UChar32 c)
+{
+ // findCharacterValue returns a 16-bit value with the top 5 bits containing a decomposition type
+ // and the remaining bits containing an index.
+ return CharacterData::PACKED_DATA[findCharacterValue(c) & 0x7FF];
+}
+
+android::Unicode::CharType android::Unicode::getType(UChar32 c)
+{
+ if (c < 0 || c >= 0x10FFFF)
+ return CHARTYPE_UNASSIGNED;
+ return (CharType)((getPackedData(c) >> TYPE_SHIFT) & TYPE_MASK);
+}
+
+android::Unicode::DecompositionType android::Unicode::getDecompositionType(UChar32 c)
+{
+ // findCharacterValue returns a 16-bit value with the top 5 bits containing a decomposition type
+ // and the remaining bits containing an index.
+ return (DecompositionType)((findCharacterValue(c) >> DECOMPOSITION_SHIFT) & DECOMPOSITION_MASK);
+}
+
+int android::Unicode::getDigitValue(UChar32 c, int radix)
+{
+ if (radix < MIN_RADIX || radix > MAX_RADIX)
+ return -1;
+
+ int tempValue = radix;
+
+ if (c >= '0' && c <= '9')
+ tempValue = c - '0';
+ else if (c >= 'a' && c <= 'z')
+ tempValue = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'Z')
+ tempValue = c - 'A' + 10;
+
+ return tempValue < radix ? tempValue : -1;
+}
+
+int android::Unicode::getNumericValue(UChar32 c)
+{
+ if (isMirrored(c))
+ return -1;
+
+ return (int) CharacterData::NUMERICS[((getPackedData(c) >> NUMERIC_SHIFT) & NUMERIC_MASK)];
+}
+
+UChar32 android::Unicode::toLower(UChar32 c)
+{
+ return c + CharacterData::LCDIFF[(getPackedData(c) >> TOLOWER_SHIFT) & TOLOWER_MASK];
+}
+
+UChar32 android::Unicode::toUpper(UChar32 c)
+{
+ return c + CharacterData::UCDIFF[(getPackedData(c) >> TOUPPER_SHIFT) & TOUPPER_MASK];
+}
+
+android::Unicode::Direction android::Unicode::getDirectionality(UChar32 c)
+{
+ uint32_t data = getPackedData(c);
+
+ if (0 == data)
+ return DIRECTIONALITY_UNDEFINED;
+
+ Direction d = (Direction) ((data >> DIRECTION_SHIFT) & DIRECTION_MASK);
+
+ if (DIRECTION_MASK == d)
+ return DIRECTIONALITY_UNDEFINED;
+
+ return d;
+}
+
+bool android::Unicode::isMirrored(UChar32 c)
+{
+ return ((getPackedData(c) >> MIRRORED_SHIFT) & MIRRORED_MASK) != 0;
+}
+
+UChar32 android::Unicode::toMirror(UChar32 c)
+{
+ if (!isMirrored(c))
+ return c;
+
+ return c + CharacterData::MIRROR_DIFF[(getPackedData(c) >> MIRROR_SHIFT) & MIRROR_MASK];
+}
+
+UChar32 android::Unicode::toTitle(UChar32 c)
+{
+ int32_t diff = CharacterData::TCDIFF[(getPackedData(c) >> TOTITLE_SHIFT) & TOTITLE_MASK];
+
+ if (TOTITLE_MASK == diff)
+ return toUpper(c);
+
+ return c + diff;
+}
+
+
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
new file mode 100644
index 0000000..2c2d667
--- /dev/null
+++ b/libs/utils/VectorImpl.cpp
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2005 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 "Vector"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/SharedBuffer.h>
+#include <utils/VectorImpl.h>
+
+/*****************************************************************************/
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+const size_t kMinVectorCapacity = 4;
+
+static inline size_t max(size_t a, size_t b) {
+ return a>b ? a : b;
+}
+
+// ----------------------------------------------------------------------------
+
+VectorImpl::VectorImpl(size_t itemSize, uint32_t flags)
+ : mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize)
+{
+}
+
+VectorImpl::VectorImpl(const VectorImpl& rhs)
+ : mStorage(rhs.mStorage), mCount(rhs.mCount),
+ mFlags(rhs.mFlags), mItemSize(rhs.mItemSize)
+{
+ if (mStorage) {
+ SharedBuffer::sharedBuffer(mStorage)->acquire();
+ }
+}
+
+VectorImpl::~VectorImpl()
+{
+ LOG_ASSERT(!mCount,
+ "[%p] "
+ "subclasses of VectorImpl must call finish_vector()"
+ " in their destructor. Leaking %d bytes.",
+ this, (int)(mCount*mItemSize));
+ // We can't call _do_destroy() here because the vtable is already gone.
+}
+
+VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
+{
+ LOG_ASSERT(mItemSize == rhs.mItemSize,
+ "Vector<> have different types (this=%p, rhs=%p)", this, &rhs);
+ if (this != &rhs) {
+ release_storage();
+ if (rhs.mCount) {
+ mStorage = rhs.mStorage;
+ mCount = rhs.mCount;
+ SharedBuffer::sharedBuffer(mStorage)->acquire();
+ } else {
+ mStorage = 0;
+ mCount = 0;
+ }
+ }
+ return *this;
+}
+
+void* VectorImpl::editArrayImpl()
+{
+ if (mStorage) {
+ SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage)->attemptEdit();
+ if (sb == 0) {
+ sb = SharedBuffer::alloc(capacity() * mItemSize);
+ if (sb) {
+ _do_copy(sb->data(), mStorage, mCount);
+ release_storage();
+ mStorage = sb->data();
+ }
+ }
+ }
+ return mStorage;
+}
+
+size_t VectorImpl::capacity() const
+{
+ if (mStorage) {
+ return SharedBuffer::sharedBuffer(mStorage)->size() / mItemSize;
+ }
+ return 0;
+}
+
+ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index)
+{
+ if (index > size())
+ return BAD_INDEX;
+ void* where = _grow(index, vector.size());
+ if (where) {
+ _do_copy(where, vector.arrayImpl(), vector.size());
+ }
+ return where ? index : (ssize_t)NO_MEMORY;
+}
+
+ssize_t VectorImpl::appendVector(const VectorImpl& vector)
+{
+ return insertVectorAt(vector, size());
+}
+
+ssize_t VectorImpl::insertAt(size_t index, size_t numItems)
+{
+ return insertAt(0, index, numItems);
+}
+
+ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems)
+{
+ if (index > size())
+ return BAD_INDEX;
+ void* where = _grow(index, numItems);
+ if (where) {
+ if (item) {
+ _do_splat(where, item, numItems);
+ } else {
+ _do_construct(where, numItems);
+ }
+ }
+ return where ? index : (ssize_t)NO_MEMORY;
+}
+
+static int sortProxy(const void* lhs, const void* rhs, void* func)
+{
+ return (*(VectorImpl::compar_t)func)(lhs, rhs);
+}
+
+status_t VectorImpl::sort(VectorImpl::compar_t cmp)
+{
+ return sort(sortProxy, (void*)cmp);
+}
+
+status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state)
+{
+ // the sort must be stable. we're using insertion sort which
+ // is well suited for small and already sorted arrays
+ // for big arrays, it could be better to use mergesort
+ const ssize_t count = size();
+ if (count > 1) {
+ void* array = const_cast<void*>(arrayImpl());
+ void* temp = 0;
+ ssize_t i = 1;
+ while (i < count) {
+ void* item = reinterpret_cast<char*>(array) + mItemSize*(i);
+ void* curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
+ if (cmp(curr, item, state) > 0) {
+
+ if (!temp) {
+ // we're going to have to modify the array...
+ array = editArrayImpl();
+ if (!array) return NO_MEMORY;
+ temp = malloc(mItemSize);
+ if (!temp) return NO_MEMORY;
+ _do_construct(temp, 1);
+ item = reinterpret_cast<char*>(array) + mItemSize*(i);
+ curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
+ }
+
+ _do_copy(temp, item, 1);
+
+ ssize_t j = i-1;
+ void* next = reinterpret_cast<char*>(array) + mItemSize*(i);
+ do {
+ _do_copy(next, curr, 1);
+ next = curr;
+ --j;
+ curr = reinterpret_cast<char*>(array) + mItemSize*(j);
+ } while (j>=0 && (cmp(curr, temp, state) > 0));
+
+ _do_copy(next, temp, 1);
+ }
+ i++;
+ }
+
+ if (temp) {
+ _do_destroy(temp, 1);
+ free(temp);
+ }
+ }
+ return NO_ERROR;
+}
+
+void VectorImpl::pop()
+{
+ if (size())
+ removeItemsAt(size()-1, 1);
+}
+
+void VectorImpl::push()
+{
+ push(0);
+}
+
+void VectorImpl::push(const void* item)
+{
+ insertAt(item, size());
+}
+
+ssize_t VectorImpl::add()
+{
+ return add(0);
+}
+
+ssize_t VectorImpl::add(const void* item)
+{
+ return insertAt(item, size());
+}
+
+ssize_t VectorImpl::replaceAt(size_t index)
+{
+ return replaceAt(0, index);
+}
+
+ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
+{
+ LOG_ASSERT(index<size(),
+ "[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
+
+ void* item = editItemLocation(index);
+ if (item == 0)
+ return NO_MEMORY;
+ _do_destroy(item, 1);
+ if (prototype == 0) {
+ _do_construct(item, 1);
+ } else {
+ _do_copy(item, prototype, 1);
+ }
+ return ssize_t(index);
+}
+
+ssize_t VectorImpl::removeItemsAt(size_t index, size_t count)
+{
+ LOG_ASSERT((index+count)<=size(),
+ "[%p] remove: index=%d, count=%d, size=%d",
+ this, (int)index, (int)count, (int)size());
+
+ if ((index+count) > size())
+ return BAD_VALUE;
+ _shrink(index, count);
+ return index;
+}
+
+void VectorImpl::finish_vector()
+{
+ release_storage();
+ mStorage = 0;
+ mCount = 0;
+}
+
+void VectorImpl::clear()
+{
+ _shrink(0, mCount);
+}
+
+void* VectorImpl::editItemLocation(size_t index)
+{
+ LOG_ASSERT(index<capacity(),
+ "[%p] itemLocation: index=%d, capacity=%d, count=%d",
+ this, (int)index, (int)capacity(), (int)mCount);
+
+ void* buffer = editArrayImpl();
+ if (buffer)
+ return reinterpret_cast<char*>(buffer) + index*mItemSize;
+ return 0;
+}
+
+const void* VectorImpl::itemLocation(size_t index) const
+{
+ LOG_ASSERT(index<capacity(),
+ "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
+ this, (int)index, (int)capacity(), (int)mCount);
+
+ const void* buffer = arrayImpl();
+ if (buffer)
+ return reinterpret_cast<const char*>(buffer) + index*mItemSize;
+ return 0;
+}
+
+ssize_t VectorImpl::setCapacity(size_t new_capacity)
+{
+ size_t current_capacity = capacity();
+ ssize_t amount = new_capacity - size();
+ if (amount <= 0) {
+ // we can't reduce the capacity
+ return current_capacity;
+ }
+ SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+ if (sb) {
+ void* array = sb->data();
+ _do_copy(array, mStorage, size());
+ release_storage();
+ mStorage = const_cast<void*>(array);
+ } else {
+ return NO_MEMORY;
+ }
+ return new_capacity;
+}
+
+void VectorImpl::release_storage()
+{
+ if (mStorage) {
+ const SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage);
+ if (sb->release(SharedBuffer::eKeepStorage) == 1) {
+ _do_destroy(mStorage, mCount);
+ SharedBuffer::dealloc(sb);
+ }
+ }
+}
+
+void* VectorImpl::_grow(size_t where, size_t amount)
+{
+// LOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
+// this, (int)where, (int)amount, (int)mCount, (int)capacity());
+
+ if (where > mCount)
+ where = mCount;
+
+ const size_t new_size = mCount + amount;
+ if (capacity() < new_size) {
+ const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2);
+// LOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
+ if ((mStorage) &&
+ (mCount==where) &&
+ (mFlags & HAS_TRIVIAL_COPY) &&
+ (mFlags & HAS_TRIVIAL_DTOR))
+ {
+ const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
+ SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
+ mStorage = sb->data();
+ } else {
+ SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+ if (sb) {
+ void* array = sb->data();
+ if (where>0) {
+ _do_copy(array, mStorage, where);
+ }
+ if (mCount>where) {
+ const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
+ void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+ _do_copy(dest, from, mCount-where);
+ }
+ release_storage();
+ mStorage = const_cast<void*>(array);
+ }
+ }
+ } else {
+ ssize_t s = mCount-where;
+ if (s>0) {
+ void* array = editArrayImpl();
+ void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+ const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
+ _do_move_forward(to, from, s);
+ }
+ }
+ mCount += amount;
+ void* free_space = const_cast<void*>(itemLocation(where));
+ return free_space;
+}
+
+void VectorImpl::_shrink(size_t where, size_t amount)
+{
+ if (!mStorage)
+ return;
+
+// LOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
+// this, (int)where, (int)amount, (int)mCount, (int)capacity());
+
+ if (where >= mCount)
+ where = mCount - amount;
+
+ const size_t new_size = mCount - amount;
+ if (new_size*3 < capacity()) {
+ const size_t new_capacity = max(kMinVectorCapacity, new_size*2);
+// LOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity);
+ if ((where == mCount-amount) &&
+ (mFlags & HAS_TRIVIAL_COPY) &&
+ (mFlags & HAS_TRIVIAL_DTOR))
+ {
+ const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
+ SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
+ mStorage = sb->data();
+ } else {
+ SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+ if (sb) {
+ void* array = sb->data();
+ if (where>0) {
+ _do_copy(array, mStorage, where);
+ }
+ if (mCount > where+amount) {
+ const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
+ void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
+ _do_copy(dest, from, mCount-(where+amount));
+ }
+ release_storage();
+ mStorage = const_cast<void*>(array);
+ }
+ }
+ } else {
+ void* array = editArrayImpl();
+ void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
+ _do_destroy(to, amount);
+ ssize_t s = mCount-(where+amount);
+ if (s>0) {
+ const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+ _do_move_backward(to, from, s);
+ }
+ }
+
+ // adjust the number of items...
+ mCount -= amount;
+}
+
+size_t VectorImpl::itemSize() const {
+ return mItemSize;
+}
+
+void VectorImpl::_do_construct(void* storage, size_t num) const
+{
+ if (!(mFlags & HAS_TRIVIAL_CTOR)) {
+ do_construct(storage, num);
+ }
+}
+
+void VectorImpl::_do_destroy(void* storage, size_t num) const
+{
+ if (!(mFlags & HAS_TRIVIAL_DTOR)) {
+ do_destroy(storage, num);
+ }
+}
+
+void VectorImpl::_do_copy(void* dest, const void* from, size_t num) const
+{
+ if (!(mFlags & HAS_TRIVIAL_COPY)) {
+ do_copy(dest, from, num);
+ } else {
+ memcpy(dest, from, num*itemSize());
+ }
+}
+
+void VectorImpl::_do_splat(void* dest, const void* item, size_t num) const {
+ do_splat(dest, item, num);
+}
+
+void VectorImpl::_do_move_forward(void* dest, const void* from, size_t num) const {
+ do_move_forward(dest, from, num);
+}
+
+void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) const {
+ do_move_backward(dest, from, num);
+}
+
+void VectorImpl::reservedVectorImpl1() { }
+void VectorImpl::reservedVectorImpl2() { }
+void VectorImpl::reservedVectorImpl3() { }
+void VectorImpl::reservedVectorImpl4() { }
+void VectorImpl::reservedVectorImpl5() { }
+void VectorImpl::reservedVectorImpl6() { }
+void VectorImpl::reservedVectorImpl7() { }
+void VectorImpl::reservedVectorImpl8() { }
+
+/*****************************************************************************/
+
+SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags)
+ : VectorImpl(itemSize, flags)
+{
+}
+
+SortedVectorImpl::SortedVectorImpl(const VectorImpl& rhs)
+: VectorImpl(rhs)
+{
+}
+
+SortedVectorImpl::~SortedVectorImpl()
+{
+}
+
+SortedVectorImpl& SortedVectorImpl::operator = (const SortedVectorImpl& rhs)
+{
+ return static_cast<SortedVectorImpl&>( VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)) );
+}
+
+ssize_t SortedVectorImpl::indexOf(const void* item) const
+{
+ return _indexOrderOf(item);
+}
+
+size_t SortedVectorImpl::orderOf(const void* item) const
+{
+ size_t o;
+ _indexOrderOf(item, &o);
+ return o;
+}
+
+ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const
+{
+ // binary search
+ ssize_t err = NAME_NOT_FOUND;
+ ssize_t l = 0;
+ ssize_t h = size()-1;
+ ssize_t mid;
+ const void* a = arrayImpl();
+ const size_t s = itemSize();
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const void* const curr = reinterpret_cast<const char *>(a) + (mid*s);
+ const int c = do_compare(curr, item);
+ if (c == 0) {
+ err = l = mid;
+ break;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ if (order) *order = l;
+ return err;
+}
+
+ssize_t SortedVectorImpl::add(const void* item)
+{
+ size_t order;
+ ssize_t index = _indexOrderOf(item, &order);
+ if (index < 0) {
+ index = VectorImpl::insertAt(item, order, 1);
+ } else {
+ index = VectorImpl::replaceAt(item, index);
+ }
+ return index;
+}
+
+ssize_t SortedVectorImpl::merge(const VectorImpl& vector)
+{
+ // naive merge...
+ if (!vector.isEmpty()) {
+ const void* buffer = vector.arrayImpl();
+ const size_t is = itemSize();
+ size_t s = vector.size();
+ for (size_t i=0 ; i<s ; i++) {
+ ssize_t err = add( reinterpret_cast<const char*>(buffer) + i*is );
+ if (err<0) {
+ return err;
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector)
+{
+ // we've merging a sorted vector... nice!
+ ssize_t err = NO_ERROR;
+ if (!vector.isEmpty()) {
+ // first take care of the case where the vectors are sorted together
+ if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) {
+ err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&>(vector), 0);
+ } else if (do_compare(vector.arrayImpl(), itemLocation(size()-1)) >= 0) {
+ err = VectorImpl::appendVector(static_cast<const VectorImpl&>(vector));
+ } else {
+ // this could be made a little better
+ err = merge(static_cast<const VectorImpl&>(vector));
+ }
+ }
+ return err;
+}
+
+ssize_t SortedVectorImpl::remove(const void* item)
+{
+ ssize_t i = indexOf(item);
+ if (i>=0) {
+ VectorImpl::removeItemsAt(i, 1);
+ }
+ return i;
+}
+
+void SortedVectorImpl::reservedSortedVectorImpl1() { };
+void SortedVectorImpl::reservedSortedVectorImpl2() { };
+void SortedVectorImpl::reservedSortedVectorImpl3() { };
+void SortedVectorImpl::reservedSortedVectorImpl4() { };
+void SortedVectorImpl::reservedSortedVectorImpl5() { };
+void SortedVectorImpl::reservedSortedVectorImpl6() { };
+void SortedVectorImpl::reservedSortedVectorImpl7() { };
+void SortedVectorImpl::reservedSortedVectorImpl8() { };
+
+
+/*****************************************************************************/
+
+}; // namespace android
+
diff --git a/libs/utils/ZipEntry.cpp b/libs/utils/ZipEntry.cpp
new file mode 100644
index 0000000..fbc9e67
--- /dev/null
+++ b/libs/utils/ZipEntry.cpp
@@ -0,0 +1,696 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Access to entries in a Zip archive.
+//
+
+#define LOG_TAG "zip"
+
+#include "utils/ZipEntry.h"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Initialize a new ZipEntry structure from a FILE* positioned at a
+ * CentralDirectoryEntry.
+ *
+ * On exit, the file pointer will be at the start of the next CDE or
+ * at the EOCD.
+ */
+status_t ZipEntry::initFromCDE(FILE* fp)
+{
+ status_t result;
+ long posn;
+ bool hasDD;
+
+ //LOGV("initFromCDE ---\n");
+
+ /* read the CDE */
+ result = mCDE.read(fp);
+ if (result != NO_ERROR) {
+ LOGD("mCDE.read failed\n");
+ return result;
+ }
+
+ //mCDE.dump();
+
+ /* using the info in the CDE, go load up the LFH */
+ posn = ftell(fp);
+ if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
+ LOGD("local header seek failed (%ld)\n",
+ mCDE.mLocalHeaderRelOffset);
+ return UNKNOWN_ERROR;
+ }
+
+ result = mLFH.read(fp);
+ if (result != NO_ERROR) {
+ LOGD("mLFH.read failed\n");
+ return result;
+ }
+
+ if (fseek(fp, posn, SEEK_SET) != 0)
+ return UNKNOWN_ERROR;
+
+ //mLFH.dump();
+
+ /*
+ * We *might* need to read the Data Descriptor at this point and
+ * integrate it into the LFH. If this bit is set, the CRC-32,
+ * compressed size, and uncompressed size will be zero. In practice
+ * these seem to be rare.
+ */
+ hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
+ if (hasDD) {
+ // do something clever
+ //LOGD("+++ has data descriptor\n");
+ }
+
+ /*
+ * Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr"
+ * flag is set, because the LFH is incomplete. (Not a problem, since we
+ * prefer the CDE values.)
+ */
+ if (!hasDD && !compareHeaders()) {
+ LOGW("WARNING: header mismatch\n");
+ // keep going?
+ }
+
+ /*
+ * If the mVersionToExtract is greater than 20, we may have an
+ * issue unpacking the record -- could be encrypted, compressed
+ * with something we don't support, or use Zip64 extensions. We
+ * can defer worrying about that to when we're extracting data.
+ */
+
+ return NO_ERROR;
+}
+
+/*
+ * Initialize a new entry. Pass in the file name and an optional comment.
+ *
+ * Initializes the CDE and the LFH.
+ */
+void ZipEntry::initNew(const char* fileName, const char* comment)
+{
+ assert(fileName != NULL && *fileName != '\0'); // name required
+
+ /* most fields are properly initialized by constructor */
+ mCDE.mVersionMadeBy = kDefaultMadeBy;
+ mCDE.mVersionToExtract = kDefaultVersion;
+ mCDE.mCompressionMethod = kCompressStored;
+ mCDE.mFileNameLength = strlen(fileName);
+ if (comment != NULL)
+ mCDE.mFileCommentLength = strlen(comment);
+ mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does
+
+ if (mCDE.mFileNameLength > 0) {
+ mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+ strcpy((char*) mCDE.mFileName, fileName);
+ }
+ if (mCDE.mFileCommentLength > 0) {
+ /* TODO: stop assuming null-terminated ASCII here? */
+ mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+ strcpy((char*) mCDE.mFileComment, comment);
+ }
+
+ copyCDEtoLFH();
+}
+
+/*
+ * Initialize a new entry, starting with the ZipEntry from a different
+ * archive.
+ *
+ * Initializes the CDE and the LFH.
+ */
+status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
+ const ZipEntry* pEntry)
+{
+ /*
+ * Copy everything in the CDE over, then fix up the hairy bits.
+ */
+ memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
+
+ if (mCDE.mFileNameLength > 0) {
+ mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+ if (mCDE.mFileName == NULL)
+ return NO_MEMORY;
+ strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
+ }
+ if (mCDE.mFileCommentLength > 0) {
+ mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+ if (mCDE.mFileComment == NULL)
+ return NO_MEMORY;
+ strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
+ }
+ if (mCDE.mExtraFieldLength > 0) {
+ /* we null-terminate this, though it may not be a string */
+ mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
+ if (mCDE.mExtraField == NULL)
+ return NO_MEMORY;
+ memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
+ mCDE.mExtraFieldLength+1);
+ }
+
+ /* construct the LFH from the CDE */
+ copyCDEtoLFH();
+
+ /*
+ * The LFH "extra" field is independent of the CDE "extra", so we
+ * handle it here.
+ */
+ assert(mLFH.mExtraField == NULL);
+ mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
+ if (mLFH.mExtraFieldLength > 0) {
+ mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
+ if (mLFH.mExtraField == NULL)
+ return NO_MEMORY;
+ memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
+ mLFH.mExtraFieldLength+1);
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Insert pad bytes in the LFH by tweaking the "extra" field. This will
+ * potentially confuse something that put "extra" data in here earlier,
+ * but I can't find an actual problem.
+ */
+status_t ZipEntry::addPadding(int padding)
+{
+ if (padding <= 0)
+ return INVALID_OPERATION;
+
+ //LOGI("HEY: adding %d pad bytes to existing %d in %s\n",
+ // padding, mLFH.mExtraFieldLength, mCDE.mFileName);
+
+ if (mLFH.mExtraFieldLength > 0) {
+ /* extend existing field */
+ unsigned char* newExtra;
+
+ newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
+ if (newExtra == NULL)
+ return NO_MEMORY;
+ memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
+ memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
+
+ delete[] mLFH.mExtraField;
+ mLFH.mExtraField = newExtra;
+ mLFH.mExtraFieldLength += padding;
+ } else {
+ /* create new field */
+ mLFH.mExtraField = new unsigned char[padding];
+ memset(mLFH.mExtraField, 0, padding);
+ mLFH.mExtraFieldLength = padding;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Set the fields in the LFH equal to the corresponding fields in the CDE.
+ *
+ * This does not touch the LFH "extra" field.
+ */
+void ZipEntry::copyCDEtoLFH(void)
+{
+ mLFH.mVersionToExtract = mCDE.mVersionToExtract;
+ mLFH.mGPBitFlag = mCDE.mGPBitFlag;
+ mLFH.mCompressionMethod = mCDE.mCompressionMethod;
+ mLFH.mLastModFileTime = mCDE.mLastModFileTime;
+ mLFH.mLastModFileDate = mCDE.mLastModFileDate;
+ mLFH.mCRC32 = mCDE.mCRC32;
+ mLFH.mCompressedSize = mCDE.mCompressedSize;
+ mLFH.mUncompressedSize = mCDE.mUncompressedSize;
+ mLFH.mFileNameLength = mCDE.mFileNameLength;
+ // the "extra field" is independent
+
+ delete[] mLFH.mFileName;
+ if (mLFH.mFileNameLength > 0) {
+ mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
+ strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
+ } else {
+ mLFH.mFileName = NULL;
+ }
+}
+
+/*
+ * Set some information about a file after we add it.
+ */
+void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+ int compressionMethod)
+{
+ mCDE.mCompressionMethod = compressionMethod;
+ mCDE.mCRC32 = crc32;
+ mCDE.mCompressedSize = compLen;
+ mCDE.mUncompressedSize = uncompLen;
+ mCDE.mCompressionMethod = compressionMethod;
+ if (compressionMethod == kCompressDeflated) {
+ mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used
+ }
+ copyCDEtoLFH();
+}
+
+/*
+ * See if the data in mCDE and mLFH match up. This is mostly useful for
+ * debugging these classes, but it can be used to identify damaged
+ * archives.
+ *
+ * Returns "false" if they differ.
+ */
+bool ZipEntry::compareHeaders(void) const
+{
+ if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
+ LOGV("cmp: VersionToExtract\n");
+ return false;
+ }
+ if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
+ LOGV("cmp: GPBitFlag\n");
+ return false;
+ }
+ if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
+ LOGV("cmp: CompressionMethod\n");
+ return false;
+ }
+ if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
+ LOGV("cmp: LastModFileTime\n");
+ return false;
+ }
+ if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
+ LOGV("cmp: LastModFileDate\n");
+ return false;
+ }
+ if (mCDE.mCRC32 != mLFH.mCRC32) {
+ LOGV("cmp: CRC32\n");
+ return false;
+ }
+ if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
+ LOGV("cmp: CompressedSize\n");
+ return false;
+ }
+ if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
+ LOGV("cmp: UncompressedSize\n");
+ return false;
+ }
+ if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
+ LOGV("cmp: FileNameLength\n");
+ return false;
+ }
+#if 0 // this seems to be used for padding, not real data
+ if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
+ LOGV("cmp: ExtraFieldLength\n");
+ return false;
+ }
+#endif
+ if (mCDE.mFileName != NULL) {
+ if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
+ LOGV("cmp: FileName\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/*
+ * Convert the DOS date/time stamp into a UNIX time stamp.
+ */
+time_t ZipEntry::getModWhen(void) const
+{
+ struct tm parts;
+
+ parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
+ parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
+ parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
+ parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
+ parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
+ parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
+ parts.tm_wday = parts.tm_yday = 0;
+ parts.tm_isdst = -1; // DST info "not available"
+
+ return mktime(&parts);
+}
+
+/*
+ * Set the CDE/LFH timestamp from UNIX time.
+ */
+void ZipEntry::setModWhen(time_t when)
+{
+#ifdef HAVE_LOCALTIME_R
+ struct tm tmResult;
+#endif
+ time_t even;
+ unsigned short zdate, ztime;
+
+ struct tm* ptm;
+
+ /* round up to an even number of seconds */
+ even = (time_t)(((unsigned long)(when) + 1) & (~1));
+
+ /* expand */
+#ifdef HAVE_LOCALTIME_R
+ ptm = localtime_r(&even, &tmResult);
+#else
+ ptm = localtime(&even);
+#endif
+
+ int year;
+ year = ptm->tm_year;
+ if (year < 80)
+ year = 80;
+
+ zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
+ ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
+
+ mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
+ mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
+}
+
+
+/*
+ * ===========================================================================
+ * ZipEntry::LocalFileHeader
+ * ===========================================================================
+ */
+
+/*
+ * Read a local file header.
+ *
+ * On entry, "fp" points to the signature at the start of the header.
+ * On exit, "fp" points to the start of data.
+ */
+status_t ZipEntry::LocalFileHeader::read(FILE* fp)
+{
+ status_t result = NO_ERROR;
+ unsigned char buf[kLFHLen];
+
+ assert(mFileName == NULL);
+ assert(mExtraField == NULL);
+
+ if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+ LOGD("whoops: didn't find expected signature\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
+ mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
+ mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
+ mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
+ mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
+ mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
+ mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
+ mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
+ mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
+ mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
+
+ // TODO: validate sizes
+
+ /* grab filename */
+ if (mFileNameLength != 0) {
+ mFileName = new unsigned char[mFileNameLength+1];
+ if (mFileName == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileName[mFileNameLength] = '\0';
+ }
+
+ /* grab extra field */
+ if (mExtraFieldLength != 0) {
+ mExtraField = new unsigned char[mExtraFieldLength+1];
+ if (mExtraField == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mExtraField[mExtraFieldLength] = '\0';
+ }
+
+bail:
+ return result;
+}
+
+/*
+ * Write a local file header.
+ */
+status_t ZipEntry::LocalFileHeader::write(FILE* fp)
+{
+ unsigned char buf[kLFHLen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
+ ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
+ ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
+ ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
+ ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
+ ZipEntry::putLongLE(&buf[0x0e], mCRC32);
+ ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
+ ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
+ ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
+ ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
+
+ if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
+ return UNKNOWN_ERROR;
+
+ /* write filename */
+ if (mFileNameLength != 0) {
+ if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write "extra field" */
+ if (mExtraFieldLength != 0) {
+ if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
+/*
+ * Dump the contents of a LocalFileHeader object.
+ */
+void ZipEntry::LocalFileHeader::dump(void) const
+{
+ LOGD(" LocalFileHeader contents:\n");
+ LOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
+ mVersionToExtract, mGPBitFlag, mCompressionMethod);
+ LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+ mLastModFileTime, mLastModFileDate, mCRC32);
+ LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
+ mCompressedSize, mUncompressedSize);
+ LOGD(" filenameLen=%u extraLen=%u\n",
+ mFileNameLength, mExtraFieldLength);
+ if (mFileName != NULL)
+ LOGD(" filename: '%s'\n", mFileName);
+}
+
+
+/*
+ * ===========================================================================
+ * ZipEntry::CentralDirEntry
+ * ===========================================================================
+ */
+
+/*
+ * Read the central dir entry that appears next in the file.
+ *
+ * On entry, "fp" should be positioned on the signature bytes for the
+ * entry. On exit, "fp" will point at the signature word for the next
+ * entry or for the EOCD.
+ */
+status_t ZipEntry::CentralDirEntry::read(FILE* fp)
+{
+ status_t result = NO_ERROR;
+ unsigned char buf[kCDELen];
+
+ /* no re-use */
+ assert(mFileName == NULL);
+ assert(mExtraField == NULL);
+ assert(mFileComment == NULL);
+
+ if (fread(buf, 1, kCDELen, fp) != kCDELen) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+ LOGD("Whoops: didn't find expected signature\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
+ mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
+ mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
+ mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
+ mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
+ mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
+ mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
+ mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
+ mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
+ mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
+ mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
+ mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
+ mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
+ mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
+ mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
+ mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
+
+ // TODO: validate sizes and offsets
+
+ /* grab filename */
+ if (mFileNameLength != 0) {
+ mFileName = new unsigned char[mFileNameLength+1];
+ if (mFileName == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileName[mFileNameLength] = '\0';
+ }
+
+ /* read "extra field" */
+ if (mExtraFieldLength != 0) {
+ mExtraField = new unsigned char[mExtraFieldLength+1];
+ if (mExtraField == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mExtraField[mExtraFieldLength] = '\0';
+ }
+
+
+ /* grab comment, if any */
+ if (mFileCommentLength != 0) {
+ mFileComment = new unsigned char[mFileCommentLength+1];
+ if (mFileComment == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+ {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileComment[mFileCommentLength] = '\0';
+ }
+
+bail:
+ return result;
+}
+
+/*
+ * Write a central dir entry.
+ */
+status_t ZipEntry::CentralDirEntry::write(FILE* fp)
+{
+ unsigned char buf[kCDELen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
+ ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
+ ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
+ ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
+ ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
+ ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
+ ZipEntry::putLongLE(&buf[0x10], mCRC32);
+ ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
+ ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
+ ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
+ ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
+ ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
+ ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
+ ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
+ ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
+ ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
+
+ if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
+ return UNKNOWN_ERROR;
+
+ /* write filename */
+ if (mFileNameLength != 0) {
+ if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write "extra field" */
+ if (mExtraFieldLength != 0) {
+ if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write comment */
+ if (mFileCommentLength != 0) {
+ if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Dump the contents of a CentralDirEntry object.
+ */
+void ZipEntry::CentralDirEntry::dump(void) const
+{
+ LOGD(" CentralDirEntry contents:\n");
+ LOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
+ mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
+ LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+ mLastModFileTime, mLastModFileDate, mCRC32);
+ LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
+ mCompressedSize, mUncompressedSize);
+ LOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
+ mFileNameLength, mExtraFieldLength, mFileCommentLength);
+ LOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
+ mDiskNumberStart, mInternalAttrs, mExternalAttrs,
+ mLocalHeaderRelOffset);
+
+ if (mFileName != NULL)
+ LOGD(" filename: '%s'\n", mFileName);
+ if (mFileComment != NULL)
+ LOGD(" comment: '%s'\n", mFileComment);
+}
+
diff --git a/libs/utils/ZipFile.cpp b/libs/utils/ZipFile.cpp
new file mode 100644
index 0000000..89aa874
--- /dev/null
+++ b/libs/utils/ZipFile.cpp
@@ -0,0 +1,1296 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Access to Zip archives.
+//
+
+#define LOG_TAG "zip"
+
+#include "utils/ZipFile.h"
+#include "utils/ZipUtils.h"
+#include "utils/Log.h"
+
+#include <zlib.h>
+#define DEF_MEM_LEVEL 8 // normally in zutil.h?
+
+#include <memory.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Some environments require the "b", some choke on it.
+ */
+#define FILE_OPEN_RO "rb"
+#define FILE_OPEN_RW "r+b"
+#define FILE_OPEN_RW_CREATE "w+b"
+
+/* should live somewhere else? */
+static status_t errnoToStatus(int err)
+{
+ if (err == ENOENT)
+ return NAME_NOT_FOUND;
+ else if (err == EACCES)
+ return PERMISSION_DENIED;
+ else
+ return UNKNOWN_ERROR;
+}
+
+/*
+ * Open a file and parse its guts.
+ */
+status_t ZipFile::open(const char* zipFileName, int flags)
+{
+ bool newArchive = false;
+
+ assert(mZipFp == NULL); // no reopen
+
+ if ((flags & kOpenTruncate))
+ flags |= kOpenCreate; // trunc implies create
+
+ if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
+ return INVALID_OPERATION; // not both
+ if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
+ return INVALID_OPERATION; // not neither
+ if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
+ return INVALID_OPERATION; // create requires write
+
+ if (flags & kOpenTruncate) {
+ newArchive = true;
+ } else {
+ newArchive = (access(zipFileName, F_OK) != 0);
+ if (!(flags & kOpenCreate) && newArchive) {
+ /* not creating, must already exist */
+ LOGD("File %s does not exist", zipFileName);
+ return NAME_NOT_FOUND;
+ }
+ }
+
+ /* open the file */
+ const char* openflags;
+ if (flags & kOpenReadWrite) {
+ if (newArchive)
+ openflags = FILE_OPEN_RW_CREATE;
+ else
+ openflags = FILE_OPEN_RW;
+ } else {
+ openflags = FILE_OPEN_RO;
+ }
+ mZipFp = fopen(zipFileName, openflags);
+ if (mZipFp == NULL) {
+ int err = errno;
+ LOGD("fopen failed: %d\n", err);
+ return errnoToStatus(err);
+ }
+
+ status_t result;
+ if (!newArchive) {
+ /*
+ * Load the central directory. If that fails, then this probably
+ * isn't a Zip archive.
+ */
+ result = readCentralDir();
+ } else {
+ /*
+ * Newly-created. The EndOfCentralDir constructor actually
+ * sets everything to be the way we want it (all zeroes). We
+ * set mNeedCDRewrite so that we create *something* if the
+ * caller doesn't add any files. (We could also just unlink
+ * the file if it's brand new and nothing was added, but that's
+ * probably doing more than we really should -- the user might
+ * have a need for empty zip files.)
+ */
+ mNeedCDRewrite = true;
+ result = NO_ERROR;
+ }
+
+ if (flags & kOpenReadOnly)
+ mReadOnly = true;
+ else
+ assert(!mReadOnly);
+
+ return result;
+}
+
+/*
+ * Return the Nth entry in the archive.
+ */
+ZipEntry* ZipFile::getEntryByIndex(int idx) const
+{
+ if (idx < 0 || idx >= (int) mEntries.size())
+ return NULL;
+
+ return mEntries[idx];
+}
+
+/*
+ * Find an entry by name.
+ */
+ZipEntry* ZipFile::getEntryByName(const char* fileName) const
+{
+ /*
+ * Do a stupid linear string-compare search.
+ *
+ * There are various ways to speed this up, especially since it's rare
+ * to intermingle changes to the archive with "get by name" calls. We
+ * don't want to sort the mEntries vector itself, however, because
+ * it's used to recreate the Central Directory.
+ *
+ * (Hash table works, parallel list of pointers in sorted order is good.)
+ */
+ int idx;
+
+ for (idx = mEntries.size()-1; idx >= 0; idx--) {
+ ZipEntry* pEntry = mEntries[idx];
+ if (!pEntry->getDeleted() &&
+ strcmp(fileName, pEntry->getFileName()) == 0)
+ {
+ return pEntry;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Empty the mEntries vector.
+ */
+void ZipFile::discardEntries(void)
+{
+ int count = mEntries.size();
+
+ while (--count >= 0)
+ delete mEntries[count];
+
+ mEntries.clear();
+}
+
+
+/*
+ * Find the central directory and read the contents.
+ *
+ * The fun thing about ZIP archives is that they may or may not be
+ * readable from start to end. In some cases, notably for archives
+ * that were written to stdout, the only length information is in the
+ * central directory at the end of the file.
+ *
+ * Of course, the central directory can be followed by a variable-length
+ * comment field, so we have to scan through it backwards. The comment
+ * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
+ * itself, plus apparently sometimes people throw random junk on the end
+ * just for the fun of it.
+ *
+ * This is all a little wobbly. If the wrong value ends up in the EOCD
+ * area, we're hosed. This appears to be the way that everbody handles
+ * it though, so we're in pretty good company if this fails.
+ */
+status_t ZipFile::readCentralDir(void)
+{
+ status_t result = NO_ERROR;
+ unsigned char* buf = NULL;
+ off_t fileLength, seekStart;
+ long readAmount;
+ int i;
+
+ fseek(mZipFp, 0, SEEK_END);
+ fileLength = ftell(mZipFp);
+ rewind(mZipFp);
+
+ /* too small to be a ZIP archive? */
+ if (fileLength < EndOfCentralDir::kEOCDLen) {
+ LOGD("Length is %ld -- too small\n", (long)fileLength);
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
+ if (buf == NULL) {
+ LOGD("Failure allocating %d bytes for EOCD search",
+ EndOfCentralDir::kMaxEOCDSearch);
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
+ seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
+ readAmount = EndOfCentralDir::kMaxEOCDSearch;
+ } else {
+ seekStart = 0;
+ readAmount = (long) fileLength;
+ }
+ if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
+ LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /* read the last part of the file into the buffer */
+ if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
+ LOGD("short file? wanted %ld\n", readAmount);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /* find the end-of-central-dir magic */
+ for (i = readAmount - 4; i >= 0; i--) {
+ if (buf[i] == 0x50 &&
+ ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
+ {
+ LOGV("+++ Found EOCD at buf+%d\n", i);
+ break;
+ }
+ }
+ if (i < 0) {
+ LOGD("EOCD not found, not Zip\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ /* extract eocd values */
+ result = mEOCD.readBuf(buf + i, readAmount - i);
+ if (result != NO_ERROR) {
+ LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
+ goto bail;
+ }
+ //mEOCD.dump();
+
+ if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
+ mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
+ {
+ LOGD("Archive spanning not supported\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ /*
+ * So far so good. "mCentralDirSize" is the size in bytes of the
+ * central directory, so we can just seek back that far to find it.
+ * We can also seek forward mCentralDirOffset bytes from the
+ * start of the file.
+ *
+ * We're not guaranteed to have the rest of the central dir in the
+ * buffer, nor are we guaranteed that the central dir will have any
+ * sort of convenient size. We need to skip to the start of it and
+ * read the header, then the other goodies.
+ *
+ * The only thing we really need right now is the file comment, which
+ * we're hoping to preserve.
+ */
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ LOGD("Failure seeking to central dir offset %ld\n",
+ mEOCD.mCentralDirOffset);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * Loop through and read the central dir entries.
+ */
+ LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
+ int entry;
+ for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
+ ZipEntry* pEntry = new ZipEntry;
+
+ result = pEntry->initFromCDE(mZipFp);
+ if (result != NO_ERROR) {
+ LOGD("initFromCDE failed\n");
+ delete pEntry;
+ goto bail;
+ }
+
+ mEntries.add(pEntry);
+ }
+
+
+ /*
+ * If all went well, we should now be back at the EOCD.
+ */
+ {
+ unsigned char checkBuf[4];
+ if (fread(checkBuf, 1, 4, mZipFp) != 4) {
+ LOGD("EOCD check read failed\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+ if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
+ LOGD("EOCD read check failed\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ LOGV("+++ EOCD read check passed\n");
+ }
+
+bail:
+ delete[] buf;
+ return result;
+}
+
+
+/*
+ * Add a new file to the archive.
+ *
+ * This requires creating and populating a ZipEntry structure, and copying
+ * the data into the file at the appropriate position. The "appropriate
+ * position" is the current location of the central directory, which we
+ * casually overwrite (we can put it back later).
+ *
+ * If we were concerned about safety, we would want to make all changes
+ * in a temp file and then overwrite the original after everything was
+ * safely written. Not really a concern for us.
+ */
+status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
+ const char* storageName, int sourceType, int compressionMethod,
+ ZipEntry** ppEntry)
+{
+ ZipEntry* pEntry = NULL;
+ status_t result = NO_ERROR;
+ long lfhPosn, startPosn, endPosn, uncompressedLen;
+ FILE* inputFp = NULL;
+ unsigned long crc;
+ time_t modWhen;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+
+ assert(compressionMethod == ZipEntry::kCompressDeflated ||
+ compressionMethod == ZipEntry::kCompressStored);
+
+ /* make sure we're in a reasonable state */
+ assert(mZipFp != NULL);
+ assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+ /* make sure it doesn't already exist */
+ if (getEntryByName(storageName) != NULL)
+ return ALREADY_EXISTS;
+
+ if (!data) {
+ inputFp = fopen(fileName, FILE_OPEN_RO);
+ if (inputFp == NULL)
+ return errnoToStatus(errno);
+ }
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ pEntry = new ZipEntry;
+ pEntry->initNew(storageName, NULL);
+
+ /*
+ * From here on out, failures are more interesting.
+ */
+ mNeedCDRewrite = true;
+
+ /*
+ * Write the LFH, even though it's still mostly blank. We need it
+ * as a place-holder. In theory the LFH isn't necessary, but in
+ * practice some utilities demand it.
+ */
+ lfhPosn = ftell(mZipFp);
+ pEntry->mLFH.write(mZipFp);
+ startPosn = ftell(mZipFp);
+
+ /*
+ * Copy the data in, possibly compressing it as we go.
+ */
+ if (sourceType == ZipEntry::kCompressStored) {
+ if (compressionMethod == ZipEntry::kCompressDeflated) {
+ bool failed = false;
+ result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
+ if (result != NO_ERROR) {
+ LOGD("compression failed, storing\n");
+ failed = true;
+ } else {
+ /*
+ * Make sure it has compressed "enough". This probably ought
+ * to be set through an API call, but I don't expect our
+ * criteria to change over time.
+ */
+ long src = inputFp ? ftell(inputFp) : size;
+ long dst = ftell(mZipFp) - startPosn;
+ if (dst + (dst / 10) > src) {
+ LOGD("insufficient compression (src=%ld dst=%ld), storing\n",
+ src, dst);
+ failed = true;
+ }
+ }
+
+ if (failed) {
+ compressionMethod = ZipEntry::kCompressStored;
+ if (inputFp) rewind(inputFp);
+ fseek(mZipFp, startPosn, SEEK_SET);
+ /* fall through to kCompressStored case */
+ }
+ }
+ /* handle "no compression" request, or failed compression from above */
+ if (compressionMethod == ZipEntry::kCompressStored) {
+ if (inputFp) {
+ result = copyFpToFp(mZipFp, inputFp, &crc);
+ } else {
+ result = copyDataToFp(mZipFp, data, size, &crc);
+ }
+ if (result != NO_ERROR) {
+ // don't need to truncate; happens in CDE rewrite
+ LOGD("failed copying data in\n");
+ goto bail;
+ }
+ }
+
+ // currently seeked to end of file
+ uncompressedLen = inputFp ? ftell(inputFp) : size;
+ } else if (sourceType == ZipEntry::kCompressDeflated) {
+ /* we should support uncompressed-from-compressed, but it's not
+ * important right now */
+ assert(compressionMethod == ZipEntry::kCompressDeflated);
+
+ bool scanResult;
+ int method;
+ long compressedLen;
+
+ scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
+ &compressedLen, &crc);
+ if (!scanResult || method != ZipEntry::kCompressDeflated) {
+ LOGD("this isn't a deflated gzip file?");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
+ if (result != NO_ERROR) {
+ LOGD("failed copying gzip data in\n");
+ goto bail;
+ }
+ } else {
+ assert(false);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * We could write the "Data Descriptor", but there doesn't seem to
+ * be any point since we're going to go back and write the LFH.
+ *
+ * Update file offsets.
+ */
+ endPosn = ftell(mZipFp); // seeked to end of compressed data
+
+ /*
+ * Success! Fill out new values.
+ */
+ pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
+ compressionMethod);
+ modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
+ pEntry->setModWhen(modWhen);
+ pEntry->setLFHOffset(lfhPosn);
+ mEOCD.mNumEntries++;
+ mEOCD.mTotalNumEntries++;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+ mEOCD.mCentralDirOffset = endPosn;
+
+ /*
+ * Go back and write the LFH.
+ */
+ if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ pEntry->mLFH.write(mZipFp);
+
+ /*
+ * Add pEntry to the list.
+ */
+ mEntries.add(pEntry);
+ if (ppEntry != NULL)
+ *ppEntry = pEntry;
+ pEntry = NULL;
+
+bail:
+ if (inputFp != NULL)
+ fclose(inputFp);
+ delete pEntry;
+ return result;
+}
+
+/*
+ * Add an entry by copying it from another zip file. If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+ int padding, ZipEntry** ppEntry)
+{
+ ZipEntry* pEntry = NULL;
+ status_t result;
+ long lfhPosn, endPosn;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+
+ /* make sure we're in a reasonable state */
+ assert(mZipFp != NULL);
+ assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ pEntry = new ZipEntry;
+ if (pEntry == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
+ if (result != NO_ERROR)
+ goto bail;
+ if (padding != 0) {
+ result = pEntry->addPadding(padding);
+ if (result != NO_ERROR)
+ goto bail;
+ }
+
+ /*
+ * From here on out, failures are more interesting.
+ */
+ mNeedCDRewrite = true;
+
+ /*
+ * Write the LFH. Since we're not recompressing the data, we already
+ * have all of the fields filled out.
+ */
+ lfhPosn = ftell(mZipFp);
+ pEntry->mLFH.write(mZipFp);
+
+ /*
+ * Copy the data over.
+ *
+ * If the "has data descriptor" flag is set, we want to copy the DD
+ * fields as well. This is a fixed-size area immediately following
+ * the data.
+ */
+ if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
+ {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ off_t copyLen;
+ copyLen = pSourceEntry->getCompressedLen();
+ if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
+ copyLen += ZipEntry::kDataDescriptorLen;
+
+ if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
+ != NO_ERROR)
+ {
+ LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * Update file offsets.
+ */
+ endPosn = ftell(mZipFp);
+
+ /*
+ * Success! Fill out new values.
+ */
+ pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset
+ mEOCD.mNumEntries++;
+ mEOCD.mTotalNumEntries++;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+ mEOCD.mCentralDirOffset = endPosn;
+
+ /*
+ * Add pEntry to the list.
+ */
+ mEntries.add(pEntry);
+ if (ppEntry != NULL)
+ *ppEntry = pEntry;
+ pEntry = NULL;
+
+ result = NO_ERROR;
+
+bail:
+ delete pEntry;
+ return result;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data.
+ */
+status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
+{
+ unsigned char tmpBuf[32768];
+ size_t count;
+
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+
+ while (1) {
+ count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
+ if (ferror(srcFp) || ferror(dstFp))
+ return errnoToStatus(errno);
+ if (count == 0)
+ break;
+
+ *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+ if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+ LOGD("fwrite %d bytes failed\n", (int) count);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "dstFp" will be seeked immediately past the data.
+ */
+status_t ZipFile::copyDataToFp(FILE* dstFp,
+ const void* data, size_t size, unsigned long* pCRC32)
+{
+ size_t count;
+
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+ if (size > 0) {
+ *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
+ if (fwrite(data, 1, size, dstFp) != size) {
+ LOGD("fwrite %d bytes failed\n", (int) size);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Copy some of the bytes in "src" to "dst".
+ *
+ * If "pCRC32" is NULL, the CRC will not be computed.
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data just written.
+ */
+status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+ unsigned long* pCRC32)
+{
+ unsigned char tmpBuf[32768];
+ size_t count;
+
+ if (pCRC32 != NULL)
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+
+ while (length) {
+ long readSize;
+
+ readSize = sizeof(tmpBuf);
+ if (readSize > length)
+ readSize = length;
+
+ count = fread(tmpBuf, 1, readSize, srcFp);
+ if ((long) count != readSize) { // error or unexpected EOF
+ LOGD("fread %d bytes failed\n", (int) readSize);
+ return UNKNOWN_ERROR;
+ }
+
+ if (pCRC32 != NULL)
+ *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+ if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+ LOGD("fwrite %d bytes failed\n", (int) count);
+ return UNKNOWN_ERROR;
+ }
+
+ length -= readSize;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Compress all of the data in "srcFp" and write it to "dstFp".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the compressed data.
+ */
+status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
+ const void* data, size_t size, unsigned long* pCRC32)
+{
+ status_t result = NO_ERROR;
+ const size_t kBufSize = 32768;
+ unsigned char* inBuf = NULL;
+ unsigned char* outBuf = NULL;
+ z_stream zstream;
+ bool atEof = false; // no feof() aviailable yet
+ unsigned long crc;
+ int zerr;
+
+ /*
+ * Create an input buffer and an output buffer.
+ */
+ inBuf = new unsigned char[kBufSize];
+ outBuf = new unsigned char[kBufSize];
+ if (inBuf == NULL || outBuf == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ /*
+ * Initialize the zlib stream.
+ */
+ memset(&zstream, 0, sizeof(zstream));
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zstream.opaque = Z_NULL;
+ zstream.next_in = NULL;
+ zstream.avail_in = 0;
+ zstream.next_out = outBuf;
+ zstream.avail_out = kBufSize;
+ zstream.data_type = Z_UNKNOWN;
+
+ zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ if (zerr != Z_OK) {
+ result = UNKNOWN_ERROR;
+ if (zerr == Z_VERSION_ERROR) {
+ LOGE("Installed zlib is not compatible with linked version (%s)\n",
+ ZLIB_VERSION);
+ } else {
+ LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
+ }
+ goto bail;
+ }
+
+ crc = crc32(0L, Z_NULL, 0);
+
+ /*
+ * Loop while we have data.
+ */
+ do {
+ size_t getSize;
+ int flush;
+
+ /* only read if the input buffer is empty */
+ if (zstream.avail_in == 0 && !atEof) {
+ LOGV("+++ reading %d bytes\n", (int)kBufSize);
+ if (data) {
+ getSize = size > kBufSize ? kBufSize : size;
+ memcpy(inBuf, data, getSize);
+ data = ((const char*)data) + getSize;
+ size -= getSize;
+ } else {
+ getSize = fread(inBuf, 1, kBufSize, srcFp);
+ if (ferror(srcFp)) {
+ LOGD("deflate read failed (errno=%d)\n", errno);
+ goto z_bail;
+ }
+ }
+ if (getSize < kBufSize) {
+ LOGV("+++ got %d bytes, EOF reached\n",
+ (int)getSize);
+ atEof = true;
+ }
+
+ crc = crc32(crc, inBuf, getSize);
+
+ zstream.next_in = inBuf;
+ zstream.avail_in = getSize;
+ }
+
+ if (atEof)
+ flush = Z_FINISH; /* tell zlib that we're done */
+ else
+ flush = Z_NO_FLUSH; /* more to come! */
+
+ zerr = deflate(&zstream, flush);
+ if (zerr != Z_OK && zerr != Z_STREAM_END) {
+ LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
+ result = UNKNOWN_ERROR;
+ goto z_bail;
+ }
+
+ /* write when we're full or when we're done */
+ if (zstream.avail_out == 0 ||
+ (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
+ {
+ LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
+ if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
+ (size_t)(zstream.next_out - outBuf))
+ {
+ LOGD("write %d failed in deflate\n",
+ (int) (zstream.next_out - outBuf));
+ goto z_bail;
+ }
+
+ zstream.next_out = outBuf;
+ zstream.avail_out = kBufSize;
+ }
+ } while (zerr == Z_OK);
+
+ assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+
+ *pCRC32 = crc;
+
+z_bail:
+ deflateEnd(&zstream); /* free up any allocated structures */
+
+bail:
+ delete[] inBuf;
+ delete[] outBuf;
+
+ return result;
+}
+
+/*
+ * Mark an entry as deleted.
+ *
+ * We will eventually need to crunch the file down, but if several files
+ * are being removed (perhaps as part of an "update" process) we can make
+ * things considerably faster by deferring the removal to "flush" time.
+ */
+status_t ZipFile::remove(ZipEntry* pEntry)
+{
+ /*
+ * Should verify that pEntry is actually part of this archive, and
+ * not some stray ZipEntry from a different file.
+ */
+
+ /* mark entry as deleted, and mark archive as dirty */
+ pEntry->setDeleted();
+ mNeedCDRewrite = true;
+ return NO_ERROR;
+}
+
+/*
+ * Flush any pending writes.
+ *
+ * In particular, this will crunch out deleted entries, and write the
+ * Central Directory and EOCD if we have stomped on them.
+ */
+status_t ZipFile::flush(void)
+{
+ status_t result = NO_ERROR;
+ long eocdPosn;
+ int i, count;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+ if (!mNeedCDRewrite)
+ return NO_ERROR;
+
+ assert(mZipFp != NULL);
+
+ result = crunchArchive();
+ if (result != NO_ERROR)
+ return result;
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
+ return UNKNOWN_ERROR;
+
+ count = mEntries.size();
+ for (i = 0; i < count; i++) {
+ ZipEntry* pEntry = mEntries[i];
+ pEntry->mCDE.write(mZipFp);
+ }
+
+ eocdPosn = ftell(mZipFp);
+ mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
+
+ mEOCD.write(mZipFp);
+
+ /*
+ * If we had some stuff bloat up during compression and get replaced
+ * with plain files, or if we deleted some entries, there's a lot
+ * of wasted space at the end of the file. Remove it now.
+ */
+ if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
+ LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
+ // not fatal
+ }
+
+ /* should we clear the "newly added" flag in all entries now? */
+
+ mNeedCDRewrite = false;
+ return NO_ERROR;
+}
+
+/*
+ * Crunch deleted files out of an archive by shifting the later files down.
+ *
+ * Because we're not using a temp file, we do the operation inside the
+ * current file.
+ */
+status_t ZipFile::crunchArchive(void)
+{
+ status_t result = NO_ERROR;
+ int i, count;
+ long delCount, adjust;
+
+#if 0
+ printf("CONTENTS:\n");
+ for (i = 0; i < (int) mEntries.size(); i++) {
+ printf(" %d: lfhOff=%ld del=%d\n",
+ i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
+ }
+ printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset);
+#endif
+
+ /*
+ * Roll through the set of files, shifting them as appropriate. We
+ * could probably get a slight performance improvement by sliding
+ * multiple files down at once (because we could use larger reads
+ * when operating on batches of small files), but it's not that useful.
+ */
+ count = mEntries.size();
+ delCount = adjust = 0;
+ for (i = 0; i < count; i++) {
+ ZipEntry* pEntry = mEntries[i];
+ long span;
+
+ if (pEntry->getLFHOffset() != 0) {
+ long nextOffset;
+
+ /* Get the length of this entry by finding the offset
+ * of the next entry. Directory entries don't have
+ * file offsets, so we need to find the next non-directory
+ * entry.
+ */
+ nextOffset = 0;
+ for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
+ nextOffset = mEntries[ii]->getLFHOffset();
+ if (nextOffset == 0)
+ nextOffset = mEOCD.mCentralDirOffset;
+ span = nextOffset - pEntry->getLFHOffset();
+
+ assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
+ } else {
+ /* This is a directory entry. It doesn't have
+ * any actual file contents, so there's no need to
+ * move anything.
+ */
+ span = 0;
+ }
+
+ //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
+ // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
+
+ if (pEntry->getDeleted()) {
+ adjust += span;
+ delCount++;
+
+ delete pEntry;
+ mEntries.removeAt(i);
+
+ /* adjust loop control */
+ count--;
+ i--;
+ } else if (span != 0 && adjust > 0) {
+ /* shuffle this entry back */
+ //printf("+++ Shuffling '%s' back %ld\n",
+ // pEntry->getFileName(), adjust);
+ result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
+ pEntry->getLFHOffset(), span);
+ if (result != NO_ERROR) {
+ /* this is why you use a temp file */
+ LOGE("error during crunch - archive is toast\n");
+ return result;
+ }
+
+ pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
+ }
+ }
+
+ /*
+ * Fix EOCD info. We have to wait until the end to do some of this
+ * because we use mCentralDirOffset to determine "span" for the
+ * last entry.
+ */
+ mEOCD.mCentralDirOffset -= adjust;
+ mEOCD.mNumEntries -= delCount;
+ mEOCD.mTotalNumEntries -= delCount;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+
+ assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
+ assert(mEOCD.mNumEntries == count);
+
+ return result;
+}
+
+/*
+ * Works like memmove(), but on pieces of a file.
+ */
+status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
+{
+ if (dst == src || n <= 0)
+ return NO_ERROR;
+
+ unsigned char readBuf[32768];
+
+ if (dst < src) {
+ /* shift stuff toward start of file; must read from start */
+ while (n != 0) {
+ size_t getSize = sizeof(readBuf);
+ if (getSize > n)
+ getSize = n;
+
+ if (fseek(fp, (long) src, SEEK_SET) != 0) {
+ LOGD("filemove src seek %ld failed\n", (long) src);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fread(readBuf, 1, getSize, fp) != getSize) {
+ LOGD("filemove read %ld off=%ld failed\n",
+ (long) getSize, (long) src);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fseek(fp, (long) dst, SEEK_SET) != 0) {
+ LOGD("filemove dst seek %ld failed\n", (long) dst);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fwrite(readBuf, 1, getSize, fp) != getSize) {
+ LOGD("filemove write %ld off=%ld failed\n",
+ (long) getSize, (long) dst);
+ return UNKNOWN_ERROR;
+ }
+
+ src += getSize;
+ dst += getSize;
+ n -= getSize;
+ }
+ } else {
+ /* shift stuff toward end of file; must read from end */
+ assert(false); // write this someday, maybe
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
+/*
+ * Get the modification time from a file descriptor.
+ */
+time_t ZipFile::getModTime(int fd)
+{
+ struct stat sb;
+
+ if (fstat(fd, &sb) < 0) {
+ LOGD("HEY: fstat on fd %d failed\n", fd);
+ return (time_t) -1;
+ }
+
+ return sb.st_mtime;
+}
+
+
+#if 0 /* this is a bad idea */
+/*
+ * Get a copy of the Zip file descriptor.
+ *
+ * We don't allow this if the file was opened read-write because we tend
+ * to leave the file contents in an uncertain state between calls to
+ * flush(). The duplicated file descriptor should only be valid for reads.
+ */
+int ZipFile::getZipFd(void) const
+{
+ if (!mReadOnly)
+ return INVALID_OPERATION;
+ assert(mZipFp != NULL);
+
+ int fd;
+ fd = dup(fileno(mZipFp));
+ if (fd < 0) {
+ LOGD("didn't work, errno=%d\n", errno);
+ }
+
+ return fd;
+}
+#endif
+
+
+#if 0
+/*
+ * Expand data.
+ */
+bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
+{
+ return false;
+}
+#endif
+
+// free the memory when you're done
+void* ZipFile::uncompress(const ZipEntry* entry)
+{
+ size_t unlen = entry->getUncompressedLen();
+ size_t clen = entry->getCompressedLen();
+
+ void* buf = malloc(unlen);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ fseek(mZipFp, 0, SEEK_SET);
+
+ off_t offset = entry->getFileOffset();
+ if (fseek(mZipFp, offset, SEEK_SET) != 0) {
+ goto bail;
+ }
+
+ switch (entry->getCompressionMethod())
+ {
+ case ZipEntry::kCompressStored: {
+ ssize_t amt = fread(buf, 1, unlen, mZipFp);
+ if (amt != (ssize_t)unlen) {
+ goto bail;
+ }
+#if 0
+ printf("data...\n");
+ const unsigned char* p = (unsigned char*)buf;
+ const unsigned char* end = p+unlen;
+ for (int i=0; i<32 && p < end; i++) {
+ printf("0x%08x ", (int)(offset+(i*0x10)));
+ for (int j=0; j<0x10 && p < end; j++) {
+ printf(" %02x", *p);
+ p++;
+ }
+ printf("\n");
+ }
+#endif
+
+ }
+ break;
+ case ZipEntry::kCompressDeflated: {
+ if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
+ goto bail;
+ }
+ }
+ break;
+ default:
+ goto bail;
+ }
+ return buf;
+
+bail:
+ free(buf);
+ return NULL;
+}
+
+
+/*
+ * ===========================================================================
+ * ZipFile::EndOfCentralDir
+ * ===========================================================================
+ */
+
+/*
+ * Read the end-of-central-dir fields.
+ *
+ * "buf" should be positioned at the EOCD signature, and should contain
+ * the entire EOCD area including the comment.
+ */
+status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
+{
+ /* don't allow re-use */
+ assert(mComment == NULL);
+
+ if (len < kEOCDLen) {
+ /* looks like ZIP file got truncated */
+ LOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
+ kEOCDLen, len);
+ return INVALID_OPERATION;
+ }
+
+ /* this should probably be an assert() */
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
+ return UNKNOWN_ERROR;
+
+ mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
+ mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
+ mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
+ mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
+ mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
+ mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
+ mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
+
+ // TODO: validate mCentralDirOffset
+
+ if (mCommentLen > 0) {
+ if (kEOCDLen + mCommentLen > len) {
+ LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
+ kEOCDLen, mCommentLen, len);
+ return UNKNOWN_ERROR;
+ }
+ mComment = new unsigned char[mCommentLen];
+ memcpy(mComment, buf + kEOCDLen, mCommentLen);
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Write an end-of-central-directory section.
+ */
+status_t ZipFile::EndOfCentralDir::write(FILE* fp)
+{
+ unsigned char buf[kEOCDLen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
+ ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
+ ZipEntry::putShortLE(&buf[0x08], mNumEntries);
+ ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
+ ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
+ ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
+ ZipEntry::putShortLE(&buf[0x14], mCommentLen);
+
+ if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
+ return UNKNOWN_ERROR;
+ if (mCommentLen > 0) {
+ assert(mComment != NULL);
+ if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Dump the contents of an EndOfCentralDir object.
+ */
+void ZipFile::EndOfCentralDir::dump(void) const
+{
+ LOGD(" EndOfCentralDir contents:\n");
+ LOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
+ mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
+ LOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n",
+ mCentralDirSize, mCentralDirOffset, mCommentLen);
+}
+
diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp
new file mode 100644
index 0000000..d312daf
--- /dev/null
+++ b/libs/utils/ZipFileCRO.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include "utils/ZipFileCRO.h"
+#include "utils/ZipFileRO.h"
+
+using namespace android;
+
+ZipFileCRO ZipFileXRO_open(const char* path) {
+ ZipFileRO* zip = new ZipFileRO();
+ if (zip->open(path) == NO_ERROR) {
+ return (ZipFileCRO)zip;
+ }
+ return NULL;
+}
+
+void ZipFileCRO_destroy(ZipFileCRO zipToken) {
+ ZipFileRO* zip = (ZipFileRO*)zipToken;
+ delete zip;
+}
+
+ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zipToken,
+ const char* fileName) {
+ ZipFileRO* zip = (ZipFileRO*)zipToken;
+ return (ZipEntryCRO)zip->findEntryByName(fileName);
+}
+
+bool ZipFileCRO_getEntryInfo(ZipFileCRO zipToken, ZipEntryRO entryToken,
+ int* pMethod, long* pUncompLen,
+ long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) {
+ ZipFileRO* zip = (ZipFileRO*)zipToken;
+ ZipEntryRO entry = (ZipEntryRO)entryToken;
+ return zip->getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset,
+ pModWhen, pCrc32);
+}
+
+bool ZipFileCRO_uncompressEntry(ZipFileCRO zipToken, ZipEntryRO entryToken, int fd) {
+ ZipFileRO* zip = (ZipFileRO*)zipToken;
+ ZipEntryRO entry = (ZipEntryRO)entryToken;
+ return zip->uncompressEntry(entry, fd);
+}
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
new file mode 100644
index 0000000..ae8c719
--- /dev/null
+++ b/libs/utils/ZipFileRO.cpp
@@ -0,0 +1,724 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//
+// Read-only access to Zip archives, with minimal heap allocation.
+//
+#define LOG_TAG "zipro"
+//#define LOG_NDEBUG 0
+#include "utils/ZipFileRO.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <zlib.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Zip file constants.
+ */
+#define kEOCDSignature 0x06054b50
+#define kEOCDLen 22
+#define kEOCDNumEntries 8 // offset to #of entries in file
+#define kEOCDFileOffset 16 // offset to central directory
+
+#define kMaxCommentLen 65535 // longest possible in ushort
+#define kMaxEOCDSearch (kMaxCommentLen + kEOCDLen)
+
+#define kLFHSignature 0x04034b50
+#define kLFHLen 30 // excluding variable-len fields
+#define kLFHNameLen 26 // offset to filename length
+#define kLFHExtraLen 28 // offset to extra length
+
+#define kCDESignature 0x02014b50
+#define kCDELen 46 // excluding variable-len fields
+#define kCDEMethod 10 // offset to compression method
+#define kCDEModWhen 12 // offset to modification timestamp
+#define kCDECRC 16 // offset to entry CRC
+#define kCDECompLen 20 // offset to compressed length
+#define kCDEUncompLen 24 // offset to uncompressed length
+#define kCDENameLen 28 // offset to filename length
+#define kCDEExtraLen 30 // offset to extra length
+#define kCDECommentLen 32 // offset to comment length
+#define kCDELocalOffset 42 // offset to local hdr
+
+/*
+ * The values we return for ZipEntryRO use 0 as an invalid value, so we
+ * want to adjust the hash table index by a fixed amount. Using a large
+ * value helps insure that people don't mix & match arguments, e.g. to
+ * findEntryByIndex().
+ */
+#define kZipEntryAdj 10000
+
+/*
+ * Convert a ZipEntryRO to a hash table index, verifying that it's in a
+ * valid range.
+ */
+int ZipFileRO::entryToIndex(const ZipEntryRO entry) const
+{
+ long ent = ((long) entry) - kZipEntryAdj;
+ if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) {
+ LOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent);
+ return -1;
+ }
+ return ent;
+}
+
+
+/*
+ * Open the specified file read-only. We memory-map the entire thing and
+ * close the file before returning.
+ */
+status_t ZipFileRO::open(const char* zipFileName)
+{
+ int fd = -1;
+ off_t length;
+
+ assert(mFileMap == NULL);
+
+ /*
+ * Open and map the specified file.
+ */
+ fd = ::open(zipFileName, O_RDONLY);
+ if (fd < 0) {
+ LOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno));
+ return NAME_NOT_FOUND;
+ }
+
+ length = lseek(fd, 0, SEEK_END);
+ if (length < 0) {
+ close(fd);
+ return UNKNOWN_ERROR;
+ }
+
+ mFileMap = new FileMap();
+ if (mFileMap == NULL) {
+ close(fd);
+ return NO_MEMORY;
+ }
+ if (!mFileMap->create(zipFileName, fd, 0, length, true)) {
+ LOGW("Unable to map '%s': %s\n", zipFileName, strerror(errno));
+ close(fd);
+ return UNKNOWN_ERROR;
+ }
+
+ mFd = fd;
+
+ /*
+ * Got it mapped, verify it and create data structures for fast access.
+ */
+ if (!parseZipArchive()) {
+ mFileMap->release();
+ mFileMap = NULL;
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+/*
+ * Parse the Zip archive, verifying its contents and initializing internal
+ * data structures.
+ */
+bool ZipFileRO::parseZipArchive(void)
+{
+#define CHECK_OFFSET(_off) { \
+ if ((unsigned int) (_off) >= maxOffset) { \
+ LOGE("ERROR: bad offset %u (max %d): %s\n", \
+ (unsigned int) (_off), maxOffset, #_off); \
+ goto bail; \
+ } \
+ }
+ const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
+ const unsigned char* ptr;
+ size_t length = mFileMap->getDataLength();
+ bool result = false;
+ unsigned int i, numEntries, cdOffset;
+ unsigned int val;
+
+ /*
+ * The first 4 bytes of the file will either be the local header
+ * signature for the first file (kLFHSignature) or, if the archive doesn't
+ * have any files in it, the end-of-central-directory signature
+ * (kEOCDSignature).
+ */
+ val = get4LE(basePtr);
+ if (val == kEOCDSignature) {
+ LOGI("Found Zip archive, but it looks empty\n");
+ goto bail;
+ } else if (val != kLFHSignature) {
+ LOGV("Not a Zip archive (found 0x%08x)\n", val);
+ goto bail;
+ }
+
+ /*
+ * Find the EOCD. We'll find it immediately unless they have a file
+ * comment.
+ */
+ ptr = basePtr + length - kEOCDLen;
+
+ while (ptr >= basePtr) {
+ if (*ptr == (kEOCDSignature & 0xff) && get4LE(ptr) == kEOCDSignature)
+ break;
+ ptr--;
+ }
+ if (ptr < basePtr) {
+ LOGI("Could not find end-of-central-directory in Zip\n");
+ goto bail;
+ }
+
+ /*
+ * There are two interesting items in the EOCD block: the number of
+ * entries in the file, and the file offset of the start of the
+ * central directory.
+ *
+ * (There's actually a count of the #of entries in this file, and for
+ * all files which comprise a spanned archive, but for our purposes
+ * we're only interested in the current file. Besides, we expect the
+ * two to be equivalent for our stuff.)
+ */
+ numEntries = get2LE(ptr + kEOCDNumEntries);
+ cdOffset = get4LE(ptr + kEOCDFileOffset);
+
+ /* valid offsets are [0,EOCD] */
+ unsigned int maxOffset;
+ maxOffset = (ptr - basePtr) +1;
+
+ LOGV("+++ numEntries=%d cdOffset=%d\n", numEntries, cdOffset);
+ if (numEntries == 0 || cdOffset >= length) {
+ LOGW("Invalid entries=%d offset=%d (len=%zd)\n",
+ numEntries, cdOffset, length);
+ goto bail;
+ }
+
+ /*
+ * Create hash table. We have a minimum 75% load factor, possibly as
+ * low as 50% after we round off to a power of 2.
+ */
+ mNumEntries = numEntries;
+ mHashTableSize = roundUpPower2(1 + ((numEntries * 4) / 3));
+ mHashTable = (HashEntry*) calloc(1, sizeof(HashEntry) * mHashTableSize);
+
+ /*
+ * Walk through the central directory, adding entries to the hash
+ * table.
+ */
+ ptr = basePtr + cdOffset;
+ for (i = 0; i < numEntries; i++) {
+ unsigned int fileNameLen, extraLen, commentLen, localHdrOffset;
+ const unsigned char* localHdr;
+ unsigned int hash;
+
+ if (get4LE(ptr) != kCDESignature) {
+ LOGW("Missed a central dir sig (at %d)\n", i);
+ goto bail;
+ }
+ if (ptr + kCDELen > basePtr + length) {
+ LOGW("Ran off the end (at %d)\n", i);
+ goto bail;
+ }
+
+ localHdrOffset = get4LE(ptr + kCDELocalOffset);
+ CHECK_OFFSET(localHdrOffset);
+ fileNameLen = get2LE(ptr + kCDENameLen);
+ extraLen = get2LE(ptr + kCDEExtraLen);
+ commentLen = get2LE(ptr + kCDECommentLen);
+
+ //LOGV("+++ %d: localHdr=%d fnl=%d el=%d cl=%d\n",
+ // i, localHdrOffset, fileNameLen, extraLen, commentLen);
+ //LOGV(" '%.*s'\n", fileNameLen, ptr + kCDELen);
+
+ /* add the CDE filename to the hash table */
+ hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
+ addToHash((const char*)ptr + kCDELen, fileNameLen, hash);
+
+ localHdr = basePtr + localHdrOffset;
+ if (get4LE(localHdr) != kLFHSignature) {
+ LOGW("Bad offset to local header: %d (at %d)\n",
+ localHdrOffset, i);
+ goto bail;
+ }
+
+ ptr += kCDELen + fileNameLen + extraLen + commentLen;
+ CHECK_OFFSET(ptr - basePtr);
+ }
+
+ result = true;
+
+bail:
+ return result;
+#undef CHECK_OFFSET
+}
+
+
+/*
+ * Simple string hash function for non-null-terminated strings.
+ */
+/*static*/ unsigned int ZipFileRO::computeHash(const char* str, int len)
+{
+ unsigned int hash = 0;
+
+ while (len--)
+ hash = hash * 31 + *str++;
+
+ return hash;
+}
+
+/*
+ * Add a new entry to the hash table.
+ */
+void ZipFileRO::addToHash(const char* str, int strLen, unsigned int hash)
+{
+ int ent = hash & (mHashTableSize-1);
+
+ /*
+ * We over-allocate the table, so we're guaranteed to find an empty slot.
+ */
+ while (mHashTable[ent].name != NULL)
+ ent = (ent + 1) & (mHashTableSize-1);
+
+ mHashTable[ent].name = str;
+ mHashTable[ent].nameLen = strLen;
+}
+
+/*
+ * Find a matching entry.
+ *
+ * Returns 0 if not found.
+ */
+ZipEntryRO ZipFileRO::findEntryByName(const char* fileName) const
+{
+ int nameLen = strlen(fileName);
+ unsigned int hash = computeHash(fileName, nameLen);
+ int ent = hash & (mHashTableSize-1);
+
+ while (mHashTable[ent].name != NULL) {
+ if (mHashTable[ent].nameLen == nameLen &&
+ memcmp(mHashTable[ent].name, fileName, nameLen) == 0)
+ {
+ /* match */
+ return (ZipEntryRO) (ent + kZipEntryAdj);
+ }
+
+ ent = (ent + 1) & (mHashTableSize-1);
+ }
+
+ return NULL;
+}
+
+/*
+ * Find the Nth entry.
+ *
+ * This currently involves walking through the sparse hash table, counting
+ * non-empty entries. If we need to speed this up we can either allocate
+ * a parallel lookup table or (perhaps better) provide an iterator interface.
+ */
+ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const
+{
+ if (idx < 0 || idx >= mNumEntries) {
+ LOGW("Invalid index %d\n", idx);
+ return NULL;
+ }
+
+ for (int ent = 0; ent < mHashTableSize; ent++) {
+ if (mHashTable[ent].name != NULL) {
+ if (idx-- == 0)
+ return (ZipEntryRO) (ent + kZipEntryAdj);
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Get the useful fields from the zip entry.
+ *
+ * Returns "false" if the offsets to the fields or the contents of the fields
+ * appear to be bogus.
+ */
+bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen,
+ long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const
+{
+ int ent = entryToIndex(entry);
+ if (ent < 0)
+ return false;
+
+ /*
+ * Recover the start of the central directory entry from the filename
+ * pointer.
+ */
+ const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
+ const unsigned char* ptr = (const unsigned char*) mHashTable[ent].name;
+ size_t zipLength = mFileMap->getDataLength();
+
+ ptr -= kCDELen;
+
+ int method = get2LE(ptr + kCDEMethod);
+ if (pMethod != NULL)
+ *pMethod = method;
+
+ if (pModWhen != NULL)
+ *pModWhen = get4LE(ptr + kCDEModWhen);
+ if (pCrc32 != NULL)
+ *pCrc32 = get4LE(ptr + kCDECRC);
+
+ /*
+ * We need to make sure that the lengths are not so large that somebody
+ * trying to map the compressed or uncompressed data runs off the end
+ * of the mapped region.
+ */
+ unsigned long localHdrOffset = get4LE(ptr + kCDELocalOffset);
+ if (localHdrOffset + kLFHLen >= zipLength) {
+ LOGE("ERROR: bad local hdr offset in zip\n");
+ return false;
+ }
+ const unsigned char* localHdr = basePtr + localHdrOffset;
+ off_t dataOffset = localHdrOffset + kLFHLen
+ + get2LE(localHdr + kLFHNameLen) + get2LE(localHdr + kLFHExtraLen);
+ if ((unsigned long) dataOffset >= zipLength) {
+ LOGE("ERROR: bad data offset in zip\n");
+ return false;
+ }
+
+ if (pCompLen != NULL) {
+ *pCompLen = get4LE(ptr + kCDECompLen);
+ if (*pCompLen < 0 || (size_t)(dataOffset + *pCompLen) >= zipLength) {
+ LOGE("ERROR: bad compressed length in zip\n");
+ return false;
+ }
+ }
+ if (pUncompLen != NULL) {
+ *pUncompLen = get4LE(ptr + kCDEUncompLen);
+ if (*pUncompLen < 0) {
+ LOGE("ERROR: negative uncompressed length in zip\n");
+ return false;
+ }
+ if (method == kCompressStored &&
+ (size_t)(dataOffset + *pUncompLen) >= zipLength)
+ {
+ LOGE("ERROR: bad uncompressed length in zip\n");
+ return false;
+ }
+ }
+
+ if (pOffset != NULL) {
+ *pOffset = dataOffset;
+ }
+ return true;
+}
+
+/*
+ * Copy the entry's filename to the buffer.
+ */
+int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen)
+ const
+{
+ int ent = entryToIndex(entry);
+ if (ent < 0)
+ return -1;
+
+ int nameLen = mHashTable[ent].nameLen;
+ if (bufLen < nameLen+1)
+ return nameLen+1;
+
+ memcpy(buffer, mHashTable[ent].name, nameLen);
+ buffer[nameLen] = '\0';
+ return 0;
+}
+
+/*
+ * Create a new FileMap object that spans the data in "entry".
+ */
+FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const
+{
+ /*
+ * TODO: the efficient way to do this is to modify FileMap to allow
+ * sub-regions of a file to be mapped. A reference-counting scheme
+ * can manage the base memory mapping. For now, we just create a brand
+ * new mapping off of the Zip archive file descriptor.
+ */
+
+ FileMap* newMap;
+ long compLen;
+ off_t offset;
+
+ if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL))
+ return NULL;
+
+ newMap = new FileMap();
+ if (!newMap->create(mFileMap->getFileName(), mFd, offset, compLen, true)) {
+ newMap->release();
+ return NULL;
+ }
+
+ return newMap;
+}
+
+/*
+ * Uncompress an entry, in its entirety, into the provided output buffer.
+ *
+ * This doesn't verify the data's CRC, which might be useful for
+ * uncompressed data. The caller should be able to manage it.
+ */
+bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const
+{
+ const int kSequentialMin = 32768;
+ bool result = false;
+ int ent = entryToIndex(entry);
+ if (ent < 0)
+ return -1;
+
+ const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
+ int method;
+ long uncompLen, compLen;
+ off_t offset;
+
+ getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
+
+ /*
+ * Experiment with madvise hint. When we want to uncompress a file,
+ * we pull some stuff out of the central dir entry and then hit a
+ * bunch of compressed or uncompressed data sequentially. The CDE
+ * visit will cause a limited amount of read-ahead because it's at
+ * the end of the file. We could end up doing lots of extra disk
+ * access if the file we're prying open is small. Bottom line is we
+ * probably don't want to turn MADV_SEQUENTIAL on and leave it on.
+ *
+ * So, if the compressed size of the file is above a certain minimum
+ * size, temporarily boost the read-ahead in the hope that the extra
+ * pair of system calls are negated by a reduction in page faults.
+ */
+ if (compLen > kSequentialMin)
+ mFileMap->advise(FileMap::SEQUENTIAL);
+
+ if (method == kCompressStored) {
+ memcpy(buffer, basePtr + offset, uncompLen);
+ } else {
+ if (!inflateBuffer(buffer, basePtr + offset, uncompLen, compLen))
+ goto bail;
+ }
+
+ if (compLen > kSequentialMin)
+ mFileMap->advise(FileMap::NORMAL);
+
+ result = true;
+
+bail:
+ return result;
+}
+
+/*
+ * Uncompress an entry, in its entirety, to an open file descriptor.
+ *
+ * This doesn't verify the data's CRC, but probably should.
+ */
+bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const
+{
+ bool result = false;
+ int ent = entryToIndex(entry);
+ if (ent < 0)
+ return -1;
+
+ const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
+ int method;
+ long uncompLen, compLen;
+ off_t offset;
+
+ getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
+
+ if (method == kCompressStored) {
+ ssize_t actual;
+
+ actual = write(fd, basePtr + offset, uncompLen);
+ if (actual < 0) {
+ LOGE("Write failed: %s\n", strerror(errno));
+ goto bail;
+ } else if (actual != uncompLen) {
+ LOGE("Partial write during uncompress (%d of %ld)\n",
+ (int)actual, uncompLen);
+ goto bail;
+ } else {
+ LOGI("+++ successful write\n");
+ }
+ } else {
+ if (!inflateBuffer(fd, basePtr+offset, uncompLen, compLen))
+ goto bail;
+ }
+
+ result = true;
+
+bail:
+ return result;
+}
+
+/*
+ * Uncompress "deflate" data from one buffer to another.
+ */
+/*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf,
+ long uncompLen, long compLen)
+{
+ bool result = false;
+ z_stream zstream;
+ int zerr;
+
+ /*
+ * Initialize the zlib stream struct.
+ */
+ memset(&zstream, 0, sizeof(zstream));
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zstream.opaque = Z_NULL;
+ zstream.next_in = (Bytef*)inBuf;
+ zstream.avail_in = compLen;
+ zstream.next_out = (Bytef*) outBuf;
+ zstream.avail_out = uncompLen;
+ zstream.data_type = Z_UNKNOWN;
+
+ /*
+ * Use the undocumented "negative window bits" feature to tell zlib
+ * that there's no zlib header waiting for it.
+ */
+ zerr = inflateInit2(&zstream, -MAX_WBITS);
+ if (zerr != Z_OK) {
+ if (zerr == Z_VERSION_ERROR) {
+ LOGE("Installed zlib is not compatible with linked version (%s)\n",
+ ZLIB_VERSION);
+ } else {
+ LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+ }
+ goto bail;
+ }
+
+ /*
+ * Expand data.
+ */
+ zerr = inflate(&zstream, Z_FINISH);
+ if (zerr != Z_STREAM_END) {
+ LOGW("Zip inflate failed, zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
+ zerr, zstream.next_in, zstream.avail_in,
+ zstream.next_out, zstream.avail_out);
+ goto z_bail;
+ }
+
+ /* paranoia */
+ if ((long) zstream.total_out != uncompLen) {
+ LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+ zstream.total_out, uncompLen);
+ goto z_bail;
+ }
+
+ result = true;
+
+z_bail:
+ inflateEnd(&zstream); /* free up any allocated structures */
+
+bail:
+ return result;
+}
+
+/*
+ * Uncompress "deflate" data from one buffer to an open file descriptor.
+ */
+/*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf,
+ long uncompLen, long compLen)
+{
+ bool result = false;
+ const int kWriteBufSize = 32768;
+ unsigned char writeBuf[kWriteBufSize];
+ z_stream zstream;
+ int zerr;
+
+ /*
+ * Initialize the zlib stream struct.
+ */
+ memset(&zstream, 0, sizeof(zstream));
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zstream.opaque = Z_NULL;
+ zstream.next_in = (Bytef*)inBuf;
+ zstream.avail_in = compLen;
+ zstream.next_out = (Bytef*) writeBuf;
+ zstream.avail_out = sizeof(writeBuf);
+ zstream.data_type = Z_UNKNOWN;
+
+ /*
+ * Use the undocumented "negative window bits" feature to tell zlib
+ * that there's no zlib header waiting for it.
+ */
+ zerr = inflateInit2(&zstream, -MAX_WBITS);
+ if (zerr != Z_OK) {
+ if (zerr == Z_VERSION_ERROR) {
+ LOGE("Installed zlib is not compatible with linked version (%s)\n",
+ ZLIB_VERSION);
+ } else {
+ LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+ }
+ goto bail;
+ }
+
+ /*
+ * Loop while we have more to do.
+ */
+ do {
+ /*
+ * Expand data.
+ */
+ zerr = inflate(&zstream, Z_NO_FLUSH);
+ if (zerr != Z_OK && zerr != Z_STREAM_END) {
+ LOGW("zlib inflate: zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
+ zerr, zstream.next_in, zstream.avail_in,
+ zstream.next_out, zstream.avail_out);
+ goto z_bail;
+ }
+
+ /* write when we're full or when we're done */
+ if (zstream.avail_out == 0 ||
+ (zerr == Z_STREAM_END && zstream.avail_out != sizeof(writeBuf)))
+ {
+ long writeSize = zstream.next_out - writeBuf;
+ int cc = write(fd, writeBuf, writeSize);
+ if (cc != (int) writeSize) {
+ LOGW("write failed in inflate (%d vs %ld)\n", cc, writeSize);
+ goto z_bail;
+ }
+
+ zstream.next_out = writeBuf;
+ zstream.avail_out = sizeof(writeBuf);
+ }
+ } while (zerr == Z_OK);
+
+ assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+
+ /* paranoia */
+ if ((long) zstream.total_out != uncompLen) {
+ LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+ zstream.total_out, uncompLen);
+ goto z_bail;
+ }
+
+ result = true;
+
+z_bail:
+ inflateEnd(&zstream); /* free up any allocated structures */
+
+bail:
+ return result;
+}
diff --git a/libs/utils/ZipUtils.cpp b/libs/utils/ZipUtils.cpp
new file mode 100644
index 0000000..bfbacfe
--- /dev/null
+++ b/libs/utils/ZipUtils.cpp
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//
+// Misc zip/gzip utility functions.
+//
+
+#define LOG_TAG "ziputil"
+
+#include "utils/ZipUtils.h"
+#include "utils/ZipFileRO.h"
+#include "utils/Log.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <zlib.h>
+
+using namespace android;
+
+/*
+ * Utility function that expands zip/gzip "deflate" compressed data
+ * into a buffer.
+ *
+ * "fd" is an open file positioned at the start of the "deflate" data
+ * "buf" must hold at least "uncompressedLen" bytes.
+ */
+/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
+ long uncompressedLen, long compressedLen)
+{
+ bool result = false;
+ const unsigned long kReadBufSize = 32768;
+ unsigned char* readBuf = NULL;
+ z_stream zstream;
+ int zerr;
+ unsigned long compRemaining;
+
+ assert(uncompressedLen >= 0);
+ assert(compressedLen >= 0);
+
+ readBuf = new unsigned char[kReadBufSize];
+ if (readBuf == NULL)
+ goto bail;
+ compRemaining = compressedLen;
+
+ /*
+ * Initialize the zlib stream.
+ */
+ memset(&zstream, 0, sizeof(zstream));
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zstream.opaque = Z_NULL;
+ zstream.next_in = NULL;
+ zstream.avail_in = 0;
+ zstream.next_out = (Bytef*) buf;
+ zstream.avail_out = uncompressedLen;
+ zstream.data_type = Z_UNKNOWN;
+
+ /*
+ * Use the undocumented "negative window bits" feature to tell zlib
+ * that there's no zlib header waiting for it.
+ */
+ zerr = inflateInit2(&zstream, -MAX_WBITS);
+ if (zerr != Z_OK) {
+ if (zerr == Z_VERSION_ERROR) {
+ LOGE("Installed zlib is not compatible with linked version (%s)\n",
+ ZLIB_VERSION);
+ } else {
+ LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+ }
+ goto bail;
+ }
+
+ /*
+ * Loop while we have data.
+ */
+ do {
+ unsigned long getSize;
+
+ /* read as much as we can */
+ if (zstream.avail_in == 0) {
+ getSize = (compRemaining > kReadBufSize) ?
+ kReadBufSize : compRemaining;
+ LOGV("+++ reading %ld bytes (%ld left)\n",
+ getSize, compRemaining);
+
+ int cc = read(fd, readBuf, getSize);
+ if (cc != (int) getSize) {
+ LOGD("inflate read failed (%d vs %ld)\n",
+ cc, getSize);
+ goto z_bail;
+ }
+
+ compRemaining -= getSize;
+
+ zstream.next_in = readBuf;
+ zstream.avail_in = getSize;
+ }
+
+ /* uncompress the data */
+ zerr = inflate(&zstream, Z_NO_FLUSH);
+ if (zerr != Z_OK && zerr != Z_STREAM_END) {
+ LOGD("zlib inflate call failed (zerr=%d)\n", zerr);
+ goto z_bail;
+ }
+
+ /* output buffer holds all, so no need to write the output */
+ } while (zerr == Z_OK);
+
+ assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+
+ if ((long) zstream.total_out != uncompressedLen) {
+ LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+ zstream.total_out, uncompressedLen);
+ goto z_bail;
+ }
+
+ // success!
+ result = true;
+
+z_bail:
+ inflateEnd(&zstream); /* free up any allocated structures */
+
+bail:
+ delete[] readBuf;
+ return result;
+}
+
+/*
+ * Utility function that expands zip/gzip "deflate" compressed data
+ * into a buffer.
+ *
+ * (This is a clone of the previous function, but it takes a FILE* instead
+ * of an fd. We could pass fileno(fd) to the above, but we can run into
+ * trouble when "fp" has a different notion of what fd's file position is.)
+ *
+ * "fp" is an open file positioned at the start of the "deflate" data
+ * "buf" must hold at least "uncompressedLen" bytes.
+ */
+/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
+ long uncompressedLen, long compressedLen)
+{
+ bool result = false;
+ const unsigned long kReadBufSize = 32768;
+ unsigned char* readBuf = NULL;
+ z_stream zstream;
+ int zerr;
+ unsigned long compRemaining;
+
+ assert(uncompressedLen >= 0);
+ assert(compressedLen >= 0);
+
+ readBuf = new unsigned char[kReadBufSize];
+ if (readBuf == NULL)
+ goto bail;
+ compRemaining = compressedLen;
+
+ /*
+ * Initialize the zlib stream.
+ */
+ memset(&zstream, 0, sizeof(zstream));
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zstream.opaque = Z_NULL;
+ zstream.next_in = NULL;
+ zstream.avail_in = 0;
+ zstream.next_out = (Bytef*) buf;
+ zstream.avail_out = uncompressedLen;
+ zstream.data_type = Z_UNKNOWN;
+
+ /*
+ * Use the undocumented "negative window bits" feature to tell zlib
+ * that there's no zlib header waiting for it.
+ */
+ zerr = inflateInit2(&zstream, -MAX_WBITS);
+ if (zerr != Z_OK) {
+ if (zerr == Z_VERSION_ERROR) {
+ LOGE("Installed zlib is not compatible with linked version (%s)\n",
+ ZLIB_VERSION);
+ } else {
+ LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
+ }
+ goto bail;
+ }
+
+ /*
+ * Loop while we have data.
+ */
+ do {
+ unsigned long getSize;
+
+ /* read as much as we can */
+ if (zstream.avail_in == 0) {
+ getSize = (compRemaining > kReadBufSize) ?
+ kReadBufSize : compRemaining;
+ LOGV("+++ reading %ld bytes (%ld left)\n",
+ getSize, compRemaining);
+
+ int cc = fread(readBuf, getSize, 1, fp);
+ if (cc != (int) getSize) {
+ LOGD("inflate read failed (%d vs %ld)\n",
+ cc, getSize);
+ goto z_bail;
+ }
+
+ compRemaining -= getSize;
+
+ zstream.next_in = readBuf;
+ zstream.avail_in = getSize;
+ }
+
+ /* uncompress the data */
+ zerr = inflate(&zstream, Z_NO_FLUSH);
+ if (zerr != Z_OK && zerr != Z_STREAM_END) {
+ LOGD("zlib inflate call failed (zerr=%d)\n", zerr);
+ goto z_bail;
+ }
+
+ /* output buffer holds all, so no need to write the output */
+ } while (zerr == Z_OK);
+
+ assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+
+ if ((long) zstream.total_out != uncompressedLen) {
+ LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+ zstream.total_out, uncompressedLen);
+ goto z_bail;
+ }
+
+ // success!
+ result = true;
+
+z_bail:
+ inflateEnd(&zstream); /* free up any allocated structures */
+
+bail:
+ delete[] readBuf;
+ return result;
+}
+
+/*
+ * Look at the contents of a gzip archive. We want to know where the
+ * data starts, and how long it will be after it is uncompressed.
+ *
+ * We expect to find the CRC and length as the last 8 bytes on the file.
+ * This is a pretty reasonable thing to expect for locally-compressed
+ * files, but there's a small chance that some extra padding got thrown
+ * on (the man page talks about compressed data written to tape). We
+ * don't currently deal with that here. If "gzip -l" whines, we're going
+ * to fail too.
+ *
+ * On exit, "fp" is pointing at the start of the compressed data.
+ */
+/*static*/ bool ZipUtils::examineGzip(FILE* fp, int* pCompressionMethod,
+ long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32)
+{
+ enum { // flags
+ FTEXT = 0x01,
+ FHCRC = 0x02,
+ FEXTRA = 0x04,
+ FNAME = 0x08,
+ FCOMMENT = 0x10,
+ };
+ int ic;
+ int method, flags;
+ int i;
+
+ ic = getc(fp);
+ if (ic != 0x1f || getc(fp) != 0x8b)
+ return false; // not gzip
+ method = getc(fp);
+ flags = getc(fp);
+
+ /* quick sanity checks */
+ if (method == EOF || flags == EOF)
+ return false;
+ if (method != ZipFileRO::kCompressDeflated)
+ return false;
+
+ /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */
+ for (i = 0; i < 6; i++)
+ (void) getc(fp);
+ /* consume "extra" field, if present */
+ if ((flags & FEXTRA) != 0) {
+ int len;
+
+ len = getc(fp);
+ len |= getc(fp) << 8;
+ while (len-- && getc(fp) != EOF)
+ ;
+ }
+ /* consume filename, if present */
+ if ((flags & FNAME) != 0) {
+ do {
+ ic = getc(fp);
+ } while (ic != 0 && ic != EOF);
+ }
+ /* consume comment, if present */
+ if ((flags & FCOMMENT) != 0) {
+ do {
+ ic = getc(fp);
+ } while (ic != 0 && ic != EOF);
+ }
+ /* consume 16-bit header CRC, if present */
+ if ((flags & FHCRC) != 0) {
+ (void) getc(fp);
+ (void) getc(fp);
+ }
+
+ if (feof(fp) || ferror(fp))
+ return false;
+
+ /* seek to the end; CRC and length are in the last 8 bytes */
+ long curPosn = ftell(fp);
+ unsigned char buf[8];
+ fseek(fp, -8, SEEK_END);
+ *pCompressedLen = ftell(fp) - curPosn;
+
+ if (fread(buf, 1, 8, fp) != 8)
+ return false;
+ /* seek back to start of compressed data */
+ fseek(fp, curPosn, SEEK_SET);
+
+ *pCompressionMethod = method;
+ *pCRC32 = ZipFileRO::get4LE(&buf[0]);
+ *pUncompressedLen = ZipFileRO::get4LE(&buf[4]);
+
+ return true;
+}
+
diff --git a/libs/utils/characterData.h b/libs/utils/characterData.h
new file mode 100644
index 0000000..e931d99
--- /dev/null
+++ b/libs/utils/characterData.h
@@ -0,0 +1,730 @@
+/*
+ * 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.
+ */
+
+// Automatically generated on 07-11-2006 by make-CharacterDataC
+// DO NOT EDIT DIRECTLY
+namespace CharacterData {
+
+ // Structure containing an array of ranges
+ struct Range {
+ int length;
+ const uint32_t* array;
+ };
+
+ // For Latin1 characters just index into this array to get the index and decomposition
+ static const uint16_t LATIN1_DATA[] = {
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0002, 0x0003, 0x0002, 0x0004, 0x0003, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0003, 0x0003, 0x0002,
+ 0x0005, 0x0006, 0x0006, 0x0007, 0x0008, 0x0007, 0x0006, 0x0006,
+ 0x0009, 0x000A, 0x0006, 0x000B, 0x000C, 0x000D, 0x000C, 0x000C,
+ 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015,
+ 0x0016, 0x0017, 0x000C, 0x0006, 0x0018, 0x0019, 0x001A, 0x0006,
+ 0x0006, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021,
+ 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029,
+ 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031,
+ 0x0032, 0x0033, 0x0034, 0x0035, 0x0006, 0x0036, 0x0037, 0x0038,
+ 0x0037, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0035, 0x0019, 0x0036, 0x0019, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x5853, 0x0006, 0x0008, 0x0008, 0x0008, 0x0008, 0x0054, 0x0054,
+ 0x1037, 0x0054, 0x7855, 0x0056, 0x0019, 0x0057, 0x0054, 0x1037,
+ 0x0058, 0x0059, 0x785A, 0x785B, 0x1037, 0x105C, 0x0054, 0x0006,
+ 0x1037, 0x785D, 0x7855, 0x005E, 0x305F, 0x305F, 0x305F, 0x0006,
+ 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0060, 0x0860,
+ 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860,
+ 0x0060, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0019,
+ 0x0060, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0060, 0x0055,
+ 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0061, 0x0861,
+ 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861,
+ 0x0061, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0019,
+ 0x0061, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0061, 0x0862
+ };
+
+ // Each of these arrays is stripped into ranges. In order to build the arrays, each
+ // codepoint was bit-shifted so that even and odd characters were separated into different
+ // arrays. The identifier of each array is the top byte after bit-shifting.
+ // The numbers stored in the array are the bit-shifted codepoint, the decomposition, and an
+ // index into another array of all possible packed data values. The top 16 bits are the
+ // codepoint and the bottom 16 are the decomposition and index. The top 5 bits for the decomposition
+ // and the rest for the index.
+ static const uint32_t a0[] = {
+ 0x00800863, 0x00880063, 0x00890863, 0x00930063, 0x00940863, 0x00980864, 0x00991063, 0x009A0863,
+ 0x009C0055, 0x009D0865, 0x00A01065, 0x00A10065, 0x00A20865, 0x00A50063, 0x00A60863, 0x00A90063,
+ 0x00AA0863, 0x00B30063, 0x00B40863, 0x00BC0866, 0x00BD0865, 0x00C00055, 0x00C10063, 0x00C30067,
+ 0x00C40065, 0x00C50068, 0x00C60065, 0x00C70069, 0x00C8006A, 0x00C90065, 0x00CA006B, 0x00CB006C,
+ 0x00CC0063, 0x00CD006D, 0x00CE006C, 0x00CF006E, 0x00D00863, 0x00D10063, 0x00D3006F, 0x00D40065,
+ 0x00D50055, 0x00D60063, 0x00D7006F, 0x00D80865, 0x00D90070, 0x00DA0065, 0x00DC0063, 0x00DD0055,
+ 0x00DE0063, 0x00DF0055, 0x00E00071, 0x00E21072, 0x00E31073, 0x00E41074, 0x00E51072, 0x00E61073,
+ 0x00E70865, 0x00EF0863, 0x00F20063, 0x00F30863, 0x00F80855, 0x00F91074, 0x00FA0863, 0x00FB0075,
+ 0x00FC0863, 0x010E0063, 0x010F0863, 0x01100076, 0x01110063, 0x01130863, 0x011A0055, 0x011D0077,
+ 0x011E0065, 0x011F0077, 0x01200055, 0x01210078, 0x01280055, 0x012A0079, 0x012B007A, 0x012C0055,
+ 0x0130007A, 0x01310055, 0x0134007B, 0x01350055, 0x0139007C, 0x013A0055, 0x0140007D, 0x01410055,
+ 0x0144007D, 0x0145007E, 0x01460055, 0x0149007F, 0x014A0080, 0x014B0055, 0x01587881, 0x015D0082,
+ 0x015E0081, 0x01610037, 0x01630082, 0x01680081, 0x01690037, 0x016C1037, 0x016F0037, 0x01707881,
+ 0x01730037, 0x01770081, 0x01780037, 0x01800083, 0x01A00883, 0x01A10083, 0x01A20883, 0x01A30083,
+ 0x01B80078, 0x01BA0837, 0x01BB0078, 0x01BD1081, 0x01BE0078, 0x01BF0806, 0x01C00078, 0x01C21037,
+ 0x01C30884, 0x01C40885, 0x01C60886, 0x01C70887, 0x01C80855, 0x01C90060, 0x01D10078, 0x01D20060,
+ 0x01D50860, 0x01D60888, 0x01D70889, 0x01D80855, 0x01D90061, 0x01E1008A, 0x01E20061, 0x01E50861,
+ 0x01E6088B, 0x01E7088C, 0x01E8108D, 0x01E91077, 0x01EA0877, 0x01EB108E, 0x01EC0063, 0x01F8108F,
+ 0x01F91090, 0x01FA1091, 0x01FB0019, 0x01FC0065, 0x01FD0063, 0x01FE0055, 0x01FF0077, 0x02000892,
+ 0x02010092, 0x02060892, 0x02080060, 0x02180061, 0x02280893, 0x02290093, 0x022E0893, 0x02300063,
+ 0x023B0863, 0x023C0063, 0x02410094, 0x02420083, 0x02440095, 0x02450063, 0x02600077, 0x02610865,
+ 0x02620065, 0x02680863, 0x026A0063, 0x026B0863, 0x026C0063, 0x026D0863, 0x02700063, 0x02710863,
+ 0x02740063, 0x02750863, 0x027B0063, 0x027C0863, 0x027D0078, 0x02800063, 0x02880078, 0x02990096,
+ 0x02AC0078, 0x02AD0097, 0x02B00078, 0x02B10098, 0x02C40078, 0x02C50099, 0x02C60078, 0x02C90083,
+ 0x02DD0078, 0x02DE0083, 0x02DF009A, 0x02E10083, 0x02E3009A, 0x02E40078, 0x02E8009B, 0x02F60078,
+ 0x02F8009B, 0x02FA009A, 0x02FB0078, 0x0300009C, 0x03020078, 0x0306000C, 0x03070054, 0x03080083,
+ 0x030B0078, 0x030F009D, 0x03100078, 0x0311089E, 0x0314009E, 0x031E0078, 0x0320009F, 0x0321009E,
+ 0x03260083, 0x033000A0, 0x033100A1, 0x033200A2, 0x033300A3, 0x033400A4, 0x03350007, 0x033600A5,
+ 0x0337009E, 0x03380083, 0x0339009E, 0x033B109E, 0x033D009E, 0x0360089E, 0x0362009E, 0x036A009D,
+ 0x036B0083, 0x036F0095, 0x03700083, 0x0373009F, 0x03740083, 0x0377009E, 0x0378000E, 0x03790010,
+ 0x037A0012, 0x037B0014, 0x037C0016, 0x037D009E, 0x037F00A6, 0x0380009D, 0x03870078, 0x0388009E,
+ 0x03980083, 0x03A60078, 0x03A7009E, 0x03B70078, 0x03C0009E, 0x03D30083, 0x03D90078, 0x04810083,
+ 0x04820071, 0x049A0871, 0x049B0071, 0x049D0078, 0x049E0083, 0x049F00A7, 0x04A10083, 0x04A500A7,
+ 0x04A70078, 0x04A80071, 0x04A90083, 0x04AB0078, 0x04AC0871, 0x04B00071, 0x04B10083, 0x04B20097,
+ 0x04B300A8, 0x04B400A9, 0x04B500AA, 0x04B600AB, 0x04B700AC, 0x04B80097, 0x04B90078, 0x04C100A7,
+ 0x04C20078, 0x04C30071, 0x04C70078, 0x04C80071, 0x04C90078, 0x04CA0071, 0x04DA0078, 0x04DB0071,
+ 0x04DD0078, 0x04DE0083, 0x04DF00A7, 0x04E10083, 0x04E30078, 0x04E400A7, 0x04E50078, 0x04E608A7,
+ 0x04E70071, 0x04E80078, 0x04EE0871, 0x04EF0078, 0x04F00071, 0x04F10083, 0x04F20078, 0x04F300A8,
+ 0x04F400A9, 0x04F500AA, 0x04F600AB, 0x04F700AC, 0x04F80071, 0x04F90008, 0x04FA00AD, 0x04FB00AE,
+ 0x04FC00AF, 0x04FD0094, 0x04FE0078, 0x05010083, 0x05020078, 0x05030071, 0x05060078, 0x05080071,
+ 0x05090078, 0x050A0071, 0x051A0078, 0x051B0871, 0x051C0071, 0x051D0078, 0x051E0083, 0x051F00A7,
+ 0x05210083, 0x05220078, 0x05240083, 0x05250078, 0x05260083, 0x05270078, 0x052D0871, 0x052E0071,
+ 0x052F0871, 0x05300078, 0x053300A8, 0x053400A9, 0x053500AA, 0x053600AB, 0x053700AC, 0x05380083,
+ 0x05390071, 0x053B0078, 0x05410083, 0x05420078, 0x05430071, 0x05470078, 0x05480071, 0x05490078,
+ 0x054A0071, 0x055A0078, 0x055B0071, 0x055D0078, 0x055E0083, 0x055F00A7, 0x05610083, 0x05630078,
+ 0x05640083, 0x05650078, 0x056600A7, 0x05670078, 0x05680071, 0x05690078, 0x05700071, 0x05710083,
+ 0x05720078, 0x057300A8, 0x057400A9, 0x057500AA, 0x057600AB, 0x057700AC, 0x05780078, 0x058100A7,
+ 0x05820078, 0x05830071, 0x05870078, 0x05880071, 0x05890078, 0x058A0071, 0x059A0078, 0x059B0071,
+ 0x059D0078, 0x059E0083, 0x059F00A7, 0x05A10083, 0x05A20078, 0x05A408A7, 0x05A50078, 0x05A608A7,
+ 0x05A70078, 0x05AB0083, 0x05AC0078, 0x05AE0871, 0x05AF0078, 0x05B00071, 0x05B10078, 0x05B300A8,
+ 0x05B400A9, 0x05B500AA, 0x05B600AB, 0x05B700AC, 0x05B80094, 0x05B90078, 0x05C10083, 0x05C20078,
+ 0x05C30071, 0x05C60078, 0x05C70071, 0x05CA0871, 0x05CB0078, 0x05CD0071, 0x05D00078, 0x05D20071,
+ 0x05D30078, 0x05D40071, 0x05D60078, 0x05D70071, 0x05DD0078, 0x05DF00A7, 0x05E00083, 0x05E100A7,
+ 0x05E20078, 0x05E300A7, 0x05E508A7, 0x05E70078, 0x05F300A8, 0x05F400A9, 0x05F500AA, 0x05F600AB,
+ 0x05F700AC, 0x05F800B0, 0x05F900B1, 0x05FA0054, 0x05FE0078, 0x060100A7, 0x06020078, 0x06030071,
+ 0x061A0078, 0x061B0071, 0x061D0078, 0x061F0083, 0x062100A7, 0x06230083, 0x06240883, 0x06250083,
+ 0x06270078, 0x062B0083, 0x062C0078, 0x06300071, 0x06310078, 0x063300A8, 0x063400A9, 0x063500AA,
+ 0x063600AB, 0x063700AC, 0x06380078, 0x064100A7, 0x06420078, 0x06430071, 0x065A0078, 0x065B0071,
+ 0x065D0078, 0x065E0083, 0x065F00A7, 0x066008A7, 0x066100A7, 0x066300B2, 0x066408A7, 0x06660083,
+ 0x06670078, 0x066B00A7, 0x066C0078, 0x066F0071, 0x06710078, 0x067300A8, 0x067400A9, 0x067500AA,
+ 0x067600AB, 0x067700AC, 0x06780078, 0x068100A7, 0x06820078, 0x06830071, 0x069D0078, 0x069F00A7,
+ 0x06A10083, 0x06A20078, 0x06A300A7, 0x06A508A7, 0x06A70078, 0x06B00071, 0x06B10078, 0x06B300A8,
+ 0x06B400A9, 0x06B500AA, 0x06B600AB, 0x06B700AC, 0x06B80078, 0x06C100A7, 0x06C20078, 0x06C30071,
+ 0x06CC0078, 0x06CD0071, 0x06D90078, 0x06DA0071, 0x06DE0078, 0x06E00071, 0x06E40078, 0x06E50083,
+ 0x06E60078, 0x06E800A7, 0x06E90083, 0x06EC00A7, 0x06ED08A7, 0x06F00078, 0x06F900A7, 0x06FA0097,
+ 0x06FB0078, 0x07010071, 0x071A0083, 0x071E0078, 0x07200071, 0x07230081, 0x07240083, 0x072800A8,
+ 0x072900A9, 0x072A00AA, 0x072B00AB, 0x072C00AC, 0x072D0097, 0x072E0078, 0x07410071, 0x07430078,
+ 0x07440071, 0x07460078, 0x074A0071, 0x074C0078, 0x074D0071, 0x07500078, 0x07510071, 0x07520078,
+ 0x07550071, 0x07560078, 0x07570071, 0x075A0083, 0x075D0078, 0x075E0083, 0x075F0078, 0x07600071,
+ 0x07630081, 0x07640083, 0x07670078, 0x076800A8, 0x076900A9, 0x076A00AA, 0x076B00AB, 0x076C00AC,
+ 0x076D0078, 0x076E1071, 0x076F0078, 0x07800071, 0x07810094, 0x07820097, 0x07865897, 0x07870097,
+ 0x078A0094, 0x078C0083, 0x078D0094, 0x079000A8, 0x079100A9, 0x079200AA, 0x079300AB, 0x079400AC,
+ 0x079500B3, 0x079A0094, 0x079D00B4, 0x079F00A7, 0x07A00071, 0x07A40078, 0x07A50071, 0x07A90871,
+ 0x07AA0071, 0x07AE0871, 0x07AF0071, 0x07B60078, 0x07B90083, 0x07BB0883, 0x07BD0083, 0x07C40071,
+ 0x07C60078, 0x07C80083, 0x07CC0078, 0x07CD0083, 0x07D10883, 0x07D20083, 0x07D60883, 0x07D70083,
+ 0x07DF0094, 0x07E30083, 0x07E40094, 0x07E70078, 0x07E80097, 0x07E90078, 0x08000071, 0x08110078,
+ 0x08120071, 0x08130871, 0x08140078, 0x08150071, 0x081600A7, 0x08170083, 0x081A0078, 0x081B0083,
+ 0x081C00A7, 0x081D0078, 0x082000A8, 0x082100A9, 0x082200AA, 0x082300AB, 0x082400AC, 0x08250097,
+ 0x08280071, 0x082B00A7, 0x082C0083, 0x082D0078, 0x085000B5, 0x08630078, 0x08680071, 0x087E7881,
+ 0x087F0078, 0x08800071, 0x08AD0078, 0x08B00071, 0x08D20078, 0x08D40071, 0x08FD0078, 0x09000071,
+ 0x09270078, 0x09280071, 0x092F0078, 0x09300071, 0x09470078, 0x09480071, 0x095B0078, 0x095C0071,
+ 0x09630078, 0x09640071, 0x098B0078, 0x098C0071, 0x09AE0078, 0x09B00094, 0x09B10097, 0x09B500B6,
+ 0x09B600B7, 0x09B700B8, 0x09B800B9, 0x09B900B0, 0x09BA00BA, 0x09BB00BB, 0x09BC00BC, 0x09BD00BD,
+ 0x09BE00BE, 0x09BF0078, 0x09C00071, 0x09C80054, 0x09CD0078, 0x09D00071, 0x09FB0078, 0x0A010071,
+ 0x0B370097, 0x0B380071, 0x0B3C0078, 0x0B400005, 0x0B410071, 0x0B4E00BF, 0x0B4F0078, 0x0B500071,
+ 0x0B760097, 0x0B7700C0, 0x0B7800C1, 0x0B790078, 0x0B800071, 0x0B890083, 0x0B8B0078, 0x0B900071,
+ 0x0B990083, 0x0B9B0097, 0x0B9C0078, 0x0BA00071, 0x0BA90083, 0x0BAA0078, 0x0BB00071, 0x0BB90083,
+ 0x0BBA0078, 0x0BC00071, 0x0BDA00C2, 0x0BDB00A7, 0x0BDC0083, 0x0BDF00A7, 0x0BE30083, 0x0BE400A7,
+ 0x0BE50083, 0x0BEA0097, 0x0BEE0071, 0x0BEF0078, 0x0BF000A8, 0x0BF100A9, 0x0BF200AA, 0x0BF300AB,
+ 0x0BF400AC, 0x0BF50078, 0x0BF800C3, 0x0BF900C4, 0x0BFA00C5, 0x0BFB00C6, 0x0BFC00C7, 0x0BFD0078,
+ 0x0C000006, 0x0C030099, 0x0C040006, 0x0C060083, 0x0C070005, 0x0C0800A8, 0x0C0900A9, 0x0C0A00AA,
+ 0x0C0B00AB, 0x0C0C00AC, 0x0C0D0078, 0x0C100071, 0x0C3C0078, 0x0C400071, 0x0C550078, 0x0C800071,
+ 0x0C8F0078, 0x0C900083, 0x0C9200A7, 0x0C940083, 0x0C9500C8, 0x0C960078, 0x0C9800A7, 0x0C990083,
+ 0x0C9A00A7, 0x0C9D0083, 0x0C9E0078, 0x0CA00054, 0x0CA10078, 0x0CA20006, 0x0CA300A8, 0x0CA400A9,
+ 0x0CA500AA, 0x0CA600AB, 0x0CA700AC, 0x0CA80071, 0x0CB70078, 0x0CB80071, 0x0CBB0078, 0x0CC00071,
+ 0x0CD50078, 0x0CD800A7, 0x0CE10071, 0x0CE400A7, 0x0CE50078, 0x0CE800A8, 0x0CE900A9, 0x0CEA00AA,
+ 0x0CEB00AB, 0x0CEC00AC, 0x0CED0078, 0x0CEF0006, 0x0CF00054, 0x0D000071, 0x0D0C0083, 0x0D0D00A7,
+ 0x0D0E0078, 0x0D0F0097, 0x0D100078, 0x0E800055, 0x0E967881, 0x0EA70081, 0x0EA87881, 0x0EB17055,
+ 0x0EB60055, 0x0EBC7881, 0x0EBD0055, 0x0ECE7881, 0x0EE00083, 0x0EE20078, 0x0F000863, 0x0F4B0855,
+ 0x0F4D1055, 0x0F4E0078, 0x0F500863, 0x0F7D0078, 0x0F8008C9, 0x0F8408CA, 0x0F8808C9, 0x0F8B0078,
+ 0x0F8C08CA, 0x0F8F0078, 0x0F9008C9, 0x0F9408CA, 0x0F9808C9, 0x0F9C08CA, 0x0FA008C9, 0x0FA30078,
+ 0x0FA408CA, 0x0FA70078, 0x0FA80855, 0x0FAC0078, 0x0FB008C9, 0x0FB408CA, 0x0FB808CB, 0x0FB908CC,
+ 0x0FBB08CD, 0x0FBC08CE, 0x0FBD08CF, 0x0FBE08D0, 0x0FBF0078, 0x0FC008C9, 0x0FC408D1, 0x0FC808C9,
+ 0x0FCC08D1, 0x0FD008C9, 0x0FD408D1, 0x0FD808C9, 0x0FD90855, 0x0FDC08CA, 0x0FDD08D2, 0x0FDE08D3,
+ 0x0FDF08D4, 0x0FE01037, 0x0FE10855, 0x0FE408D5, 0x0FE608D3, 0x0FE70837, 0x0FE808C9, 0x0FE90855,
+ 0x0FEA0078, 0x0FEB0855, 0x0FEC08CA, 0x0FED08D6, 0x0FEE0078, 0x0FEF0837, 0x0FF008C9, 0x0FF10855,
+ 0x0FF408CA, 0x0FF508D7, 0x0FF608D8, 0x0FF70837, 0x0FF80078, 0x0FF90855, 0x0FFC08D9, 0x0FFD08DA,
+ 0x0FFE08D3, 0x0FFF1037, 0x10000805, 0x10011005, 0x10060057, 0x100700C2, 0x10080099, 0x100B0006,
+ 0x100C00DB, 0x100D00B4, 0x100E00DB, 0x100F00B4, 0x10100006, 0x10121006, 0x101400DC, 0x101500DD,
+ 0x101600DE, 0x101700DF, 0x10180007, 0x101A1007, 0x101B1006, 0x101C0006, 0x101D00E0, 0x101E1006,
+ 0x10200038, 0x10210006, 0x102200E1, 0x1023000A, 0x10241006, 0x10250006, 0x10290019, 0x102A0038,
+ 0x102B0006, 0x10300057, 0x10320078, 0x10350057, 0x103878E2, 0x10390078, 0x103A78E3, 0x103B78E4,
+ 0x103C78E5, 0x103D780B, 0x103E7819, 0x103F780A, 0x104070E2, 0x1041705A, 0x104270E3, 0x104370E4,
+ 0x104470E5, 0x1045700B, 0x10467019, 0x1047700A, 0x10487081, 0x104B0078, 0x10500008, 0x10541008,
+ 0x10550008, 0x105B0078, 0x10680083, 0x106F0095, 0x10730083, 0x10760078, 0x10801054, 0x10812877,
+ 0x10820054, 0x10831054, 0x10840054, 0x10852855, 0x10862877, 0x10872855, 0x10882877, 0x108A0054,
+ 0x108B1054, 0x108C0054, 0x108D2877, 0x108F0054, 0x10907854, 0x10922877, 0x109308E6, 0x10942877,
+ 0x109508E7, 0x10962877, 0x10970058, 0x10982877, 0x10990054, 0x109A2855, 0x109B1071, 0x109D0054,
+ 0x109E2855, 0x109F2877, 0x10A028E8, 0x10A10019, 0x10A32855, 0x10A50054, 0x10A70078, 0x10AA305F,
+ 0x10B010E9, 0x10B110EA, 0x10B210EB, 0x10B310EC, 0x10B410ED, 0x10B510EE, 0x10B610EF, 0x10B710F0,
+ 0x10B810F1, 0x10B910F2, 0x10BA10F3, 0x10BB10F4, 0x10BC10F5, 0x10BD10F6, 0x10BE10F7, 0x10BF10F8,
+ 0x10C000F9, 0x10C100FA, 0x10C20078, 0x10C80019, 0x10CB0054, 0x10CD0819, 0x10CE0054, 0x10D00019,
+ 0x10D10054, 0x10D30019, 0x10D40054, 0x10D70819, 0x10D80054, 0x10E70819, 0x10E80054, 0x10E90019,
+ 0x10EB0054, 0x10FA0019, 0x110100E8, 0x110208E8, 0x11030019, 0x110400FB, 0x110608FC, 0x11070019,
+ 0x1109000B, 0x110A0019, 0x110B00E8, 0x110C0019, 0x110D00E8, 0x110F0019, 0x111000E8, 0x111208E8,
+ 0x11140019, 0x111610E8, 0x111700E8, 0x111810E8, 0x111900E8, 0x111A0019, 0x111E00FD, 0x111F00E8,
+ 0x112208E8, 0x112300E8, 0x11270019, 0x112900FD, 0x112B0019, 0x113008E8, 0x113200FD, 0x11360019,
+ 0x113708FD, 0x113900FD, 0x113A08FD, 0x113B00FD, 0x113C08FD, 0x113D00FD, 0x114008FD, 0x114100FD,
+ 0x114208FD, 0x114300FD, 0x114408FD, 0x114500FD, 0x114600E8, 0x11470019, 0x114800FE, 0x114A0019,
+ 0x114C00FF, 0x114D0019, 0x115100FD, 0x11520019, 0x11530100, 0x11540101, 0x115500E8, 0x115608E8,
+ 0x115800FD, 0x115C00E8, 0x115D0019, 0x115F00E8, 0x11600019, 0x116500FE, 0x11670019, 0x116800FD,
+ 0x11690019, 0x116B00FD, 0x117008FD, 0x117200FD, 0x117508FD, 0x11770019, 0x117800FD, 0x11790102,
+ 0x117B0103, 0x117C00E8, 0x117D0104, 0x117F0105, 0x11800054, 0x118400FD, 0x11860054, 0x119000E8,
+ 0x11910054, 0x1195080A, 0x11960054, 0x119B0094, 0x11BE0019, 0x11BF0054, 0x11CE0019, 0x11DA00B4,
+ 0x11DB0006, 0x11DC0054, 0x11EE0078, 0x12000054, 0x12140078, 0x12200054, 0x12260078, 0x12301906,
+ 0x12311907, 0x12321908, 0x12331909, 0x1234190A, 0x1235190B, 0x1236190C, 0x1237190D, 0x1238190E,
+ 0x1239190F, 0x123A1106, 0x123B1107, 0x123C1108, 0x123D1109, 0x123E110A, 0x123F110B, 0x1240110C,
+ 0x1241110D, 0x1242110E, 0x1243110F, 0x1244105D, 0x1245105B, 0x12461110, 0x12471111, 0x12481112,
+ 0x12491113, 0x124A1114, 0x124B1115, 0x124C1116, 0x124D1117, 0x124E1094, 0x125B1918, 0x12681919,
+ 0x127518C3, 0x1276011A, 0x1277011B, 0x1278011C, 0x1279011D, 0x127A011E, 0x127B00C4, 0x127C00C5,
+ 0x127D00C6, 0x127E00C7, 0x127F011F, 0x12800054, 0x12FC0019, 0x13000054, 0x134F0078, 0x13500054,
+ 0x13560094, 0x13570054, 0x13590078, 0x13810054, 0x13850078, 0x13860054, 0x13940078, 0x13950054,
+ 0x13A60078, 0x13A80054, 0x13AA0078, 0x13AB0054, 0x13B00078, 0x13B10054, 0x13B40009, 0x13BB0106,
+ 0x13BC0107, 0x13BD0108, 0x13BE0109, 0x13BF010A, 0x13C00106, 0x13C10107, 0x13C20108, 0x13C30109,
+ 0x13C4010A, 0x13C50106, 0x13C60107, 0x13C70108, 0x13C80109, 0x13C9010A, 0x13CA0054, 0x13CB0078,
+ 0x13CC0054, 0x13D80078, 0x13D90054, 0x13E000E8, 0x13E10019, 0x13E200FE, 0x13E3000A, 0x13E40078,
+ 0x13E80019, 0x13EA00E8, 0x13EB00FE, 0x13EC0019, 0x13EE00E8, 0x13EF00FE, 0x13F00019, 0x13F100FD,
+ 0x13F30009, 0x13F60078, 0x13F80019, 0x14000094, 0x14800019, 0x14C2000A, 0x14C70120, 0x14C80121,
+ 0x14C9000A, 0x14CD0019, 0x14CE00E8, 0x14D80019, 0x14DC0122, 0x14DD0019, 0x14E000FD, 0x14E100E8,
+ 0x14E200FD, 0x14E30019, 0x14E700E8, 0x14E800FE, 0x14EA00FD, 0x14EB0019, 0x14EC0009, 0x14EE00E8,
+ 0x14EF0019, 0x14F200E8, 0x14F30019, 0x14F400E8, 0x14F50019, 0x14FA00E8, 0x14FC00FD, 0x14FD0019,
+ 0x14FE0009, 0x14FF0019, 0x150500E8, 0x150610E8, 0x150700E8, 0x15110019, 0x151200E8, 0x15140019,
+ 0x151600FE, 0x15180019, 0x151A00FD, 0x151B0019, 0x151E00FD, 0x151F00E8, 0x15200019, 0x152C00E8,
+ 0x152D0019, 0x153200FD, 0x15330019, 0x153500E8, 0x15370019, 0x153800E8, 0x15390019, 0x153A10E8,
+ 0x153B1019, 0x153C0019, 0x153D00FE, 0x153E00E8, 0x153F00FE, 0x154300E8, 0x154600FE, 0x154700E8,
+ 0x154900FE, 0x154F00E8, 0x155100FE, 0x15520019, 0x155300FD, 0x15570019, 0x155800FE, 0x155900E8,
+ 0x155A00FE, 0x155B00E8, 0x155E00FE, 0x156400E8, 0x156700FE, 0x156C0019, 0x156E08E8, 0x156F0123,
+ 0x15700019, 0x157100E8, 0x15720124, 0x157300E8, 0x15740019, 0x157600FD, 0x157700E8, 0x15780019,
+ 0x157C00FE, 0x157E0019, 0x15800054, 0x158A0078, 0x16000096, 0x16180098, 0x16300078, 0x16400063,
+ 0x16720055, 0x16730054, 0x16760078, 0x167D0006, 0x16800125, 0x16930078, 0x16980071, 0x16B30078,
+ 0x16C00071, 0x16CC0078, 0x16D00071, 0x16F00078, 0x17000006, 0x17010126, 0x17030006, 0x170500E0,
+ 0x17060126, 0x17070006, 0x170C0078, 0x170E0126, 0x170F0078, 0x17400054, 0x174D0078, 0x174E0054,
+ 0x177A0078, 0x17801054, 0x17EB0078, 0x17F80054, 0x17FE0078, 0x18008805, 0x18010006, 0x18020054,
+ 0x18030071, 0x18040009, 0x18090054, 0x180A0009, 0x180E0099, 0x180F00BF, 0x18100054, 0x18110127,
+ 0x18120128, 0x18130129, 0x1814012A, 0x18150083, 0x18180099, 0x18190081, 0x181B1054, 0x181C112B,
+ 0x181D112C, 0x181E0071, 0x181F0054, 0x18200078, 0x18210071, 0x18260871, 0x18320071, 0x18380871,
+ 0x18390071, 0x183A0871, 0x183C0071, 0x183D0871, 0x183F0071, 0x184A0871, 0x184B0071, 0x184C0078,
+ 0x184D0083, 0x184E1037, 0x184F0881, 0x18500099, 0x18510071, 0x18560871, 0x18620071, 0x18680871,
+ 0x18690071, 0x186A0871, 0x186C0071, 0x186D0871, 0x186F0071, 0x187A0871, 0x187B0071, 0x187C0871,
+ 0x187E0081, 0x187F0881, 0x18800078, 0x18830071, 0x18970078, 0x18991071, 0x18C80094, 0x18C978AD,
+ 0x18CA78AE, 0x18CB7894, 0x18D00071, 0x18DC0078, 0x18E00054, 0x18E80078, 0x18F80071, 0x19001094,
+ 0x190F1054, 0x191010AD, 0x191110AE, 0x1912112D, 0x1913112E, 0x1914112F, 0x19151094, 0x19220078,
+ 0x19286854, 0x19291930, 0x192A1931, 0x192B1932, 0x192C1933, 0x192D1934, 0x192E1935, 0x192F1936,
+ 0x19301894, 0x193E1854, 0x194018AD, 0x194118AE, 0x1942192D, 0x1943192E, 0x1944192F, 0x19451894,
+ 0x19591937, 0x195A1938, 0x195B1939, 0x195C193A, 0x195D193B, 0x195E193C, 0x195F193D, 0x19601094,
+ 0x19666854, 0x19681894, 0x19806894, 0x19AC1094, 0x19B96894, 0x19BC6854, 0x19BE6894, 0x19EF6854,
+ 0x19F01094, 0x1A000071, 0x26DB0078, 0x26E00054, 0x27000071, 0x4FDE0078, 0x50000071, 0x52470078,
+ 0x52480054, 0x52640078, 0x53800037, 0x538C0078, 0x54000071, 0x540100C8, 0x54020071, 0x54030083,
+ 0x54040071, 0x541200A7, 0x54130083, 0x54140054, 0x54160078, 0x56000071, 0x6BD20078, 0x6C00013E,
+ 0x7000013F, 0x7C800871, 0x7D070071, 0x7D080871, 0x7D0A0071, 0x7D0B0871, 0x7D120071, 0x7D130871,
+ 0x7D140071, 0x7D150871, 0x7D170078, 0x7D180871, 0x7D360078, 0x7D380871, 0x7D6D0078, 0x7D801055,
+ 0x7D840078, 0x7D8A1055, 0x7D8C0078, 0x7D8F0083, 0x7D90289B, 0x7D95089B, 0x7DA10078, 0x7DA2089B,
+ 0x7DA8409E, 0x7DAA389E, 0x7DAB409E, 0x7DAC389E, 0x7DAD409E, 0x7DAE389E, 0x7DAF409E, 0x7DB0389E,
+ 0x7DB1409E, 0x7DB2389E, 0x7DB3409E, 0x7DB4389E, 0x7DB5409E, 0x7DB6389E, 0x7DB7409E, 0x7DB8389E,
+ 0x7DB9409E, 0x7DBA389E, 0x7DBB409E, 0x7DBC389E, 0x7DBD409E, 0x7DBE389E, 0x7DBF409E, 0x7DC0389E,
+ 0x7DC1409E, 0x7DC8389E, 0x7DC9409E, 0x7DCA389E, 0x7DCB409E, 0x7DCC389E, 0x7DCD409E, 0x7DCE389E,
+ 0x7DCF409E, 0x7DD1389E, 0x7DD2409E, 0x7DD4389E, 0x7DD5409E, 0x7DD6389E, 0x7DD7409E, 0x7DD90078,
+ 0x7DEA209E, 0x7DEB489E, 0x7DEC209E, 0x7DEF409E, 0x7DF3389E, 0x7DF5409E, 0x7DFC389E, 0x7DFD209E,
+ 0x7DFE409E, 0x7DFF389E, 0x7E00409E, 0x7E32209E, 0x7E4C389E, 0x7E70489E, 0x7E7B409E, 0x7E89209E,
+ 0x7E97389E, 0x7E9A489E, 0x7E9E209E, 0x7E9F00B4, 0x7EA00078, 0x7EA8389E, 0x7EAC209E, 0x7EAE389E,
+ 0x7EAF209E, 0x7EB0389E, 0x7EB1209E, 0x7EB4389E, 0x7EB5209E, 0x7EB8389E, 0x7EBA209E, 0x7EC3389E,
+ 0x7EC80078, 0x7EC9389E, 0x7ECB209E, 0x7ECC389E, 0x7ECD209E, 0x7EDA389E, 0x7EDB209E, 0x7EDC389E,
+ 0x7EDE209E, 0x7EE2389E, 0x7EE3209E, 0x7EE40078, 0x7EF8409E, 0x7EFE4140, 0x7EFF0078, 0x7F000083,
+ 0x7F088006, 0x7F0C80BF, 0x7F0D0078, 0x7F100083, 0x7F120078, 0x7F188006, 0x7F198099, 0x7F1A8038,
+ 0x7F1B80BF, 0x7F230006, 0x7F2480BF, 0x7F251006, 0x7F271038, 0x7F28600C, 0x7F2A6006, 0x7F2C6099,
+ 0x7F2D60BF, 0x7F306006, 0x7F31600B, 0x7F326019, 0x7F346006, 0x7F356007, 0x7F360078, 0x7F38409E,
+ 0x7F41209E, 0x7F46489E, 0x7F47209E, 0x7F49489E, 0x7F4A209E, 0x7F4C489E, 0x7F4D209E, 0x7F4E489E,
+ 0x7F4F209E, 0x7F50489E, 0x7F51209E, 0x7F52489E, 0x7F53209E, 0x7F54489E, 0x7F55209E, 0x7F5A489E,
+ 0x7F5B209E, 0x7F5C489E, 0x7F5D209E, 0x7F5E489E, 0x7F5F209E, 0x7F60489E, 0x7F61209E, 0x7F62489E,
+ 0x7F63209E, 0x7F64489E, 0x7F65209E, 0x7F66489E, 0x7F67209E, 0x7F68489E, 0x7F69209E, 0x7F6A489E,
+ 0x7F6B209E, 0x7F6C489E, 0x7F6D209E, 0x7F6E489E, 0x7F6F209E, 0x7F70489E, 0x7F71209E, 0x7F72489E,
+ 0x7F73209E, 0x7F74489E, 0x7F75209E, 0x7F76489E, 0x7F77209E, 0x7F7A489E, 0x7F7B209E, 0x7F7F0078,
+ 0x7F818806, 0x7F828808, 0x7F838806, 0x7F848809, 0x7F858806, 0x7F86880C, 0x7F88880E, 0x7F898810,
+ 0x7F8A8812, 0x7F8B8814, 0x7F8C8816, 0x7F8D880C, 0x7F8E8818, 0x7F8F881A, 0x7F908806, 0x7F918860,
+ 0x7F9E8806, 0x7F9F8837, 0x7FA18861, 0x7FAE8819, 0x7FB0880A, 0x7FB15009, 0x7FB25006, 0x7FB35071,
+ 0x7FB85081, 0x7FB95071, 0x7FCF5081, 0x7FD05071, 0x7FE00078, 0x7FE15071, 0x7FE40078, 0x7FE55071,
+ 0x7FE80078, 0x7FE95071, 0x7FEC0078, 0x7FED5071, 0x7FEF0078, 0x7FF08808, 0x7FF18819, 0x7FF28854,
+ 0x7FF38808, 0x7FF45054, 0x7FF55019, 0x7FF75054, 0x7FF80078, 0x7FFD0141, 0x7FFE0054, 0x7FFF0078,
+ 0x80000071, 0x80060078, 0x80070071, 0x801F0078, 0x80200071, 0x80270078, 0x80280071, 0x802F0078,
+ 0x80400071, 0x807E0078, 0x80800097, 0x80810094, 0x80820078, 0x808400B6, 0x808500B7, 0x808600B8,
+ 0x808700B9, 0x808800B0, 0x808900BA, 0x808A00BB, 0x808B00BC, 0x808C00BD, 0x808D0142, 0x808E0143,
+ 0x808F0144, 0x80900145, 0x809100B1, 0x80920146, 0x80930147, 0x80940148, 0x80950149, 0x8096014A,
+ 0x8097014B, 0x8098014C, 0x8099014D, 0x809A0078, 0x809C0094, 0x80A0014E, 0x80A1014F, 0x80A20150,
+ 0x80A30151, 0x80A40152, 0x80A50150, 0x80A60153, 0x80A70151, 0x80A80154, 0x80A90155, 0x80AA0156,
+ 0x80AB0157, 0x80AC014F, 0x80AE0158, 0x80B00154, 0x80B30150, 0x80B50155, 0x80B60153, 0x80B90151,
+ 0x80BA0150, 0x80BB005F, 0x80BD0054, 0x80C500C3, 0x80C60078, 0x81800071, 0x819000AD, 0x819100B0,
+ 0x81920078, 0x81980071, 0x81A50159, 0x81A60078, 0x81C00071, 0x81CF0078, 0x81D00071, 0x81E20078,
+ 0x81E40071, 0x81E80094, 0x81E90158, 0x81EA015A, 0x81EB0078, 0x8200015B, 0x8214015C, 0x82280071,
+ 0x824F0078, 0x825000A8, 0x825100A9, 0x825200AA, 0x825300AB, 0x825400AC, 0x82550078, 0x8400009B,
+ 0x84030078, 0x8404009B, 0x841B0078, 0x841C009B, 0x841D0078, 0x841E009B, 0x841F0078, 0x8500009B,
+ 0x85010083, 0x85020078, 0x85030083, 0x85040078, 0x85060083, 0x8508009B, 0x850A0078, 0x850B009B,
+ 0x850C0078, 0x850D009B, 0x851A0078, 0x851C0083, 0x851E0078, 0x8520015D, 0x8521015E, 0x8522015F,
+ 0x85230160, 0x85240078, 0x8528009A, 0x852D0078, 0xE8000094, 0xE87B0078, 0xE8800094, 0xE8940078,
+ 0xE8950094, 0xE8AF0894, 0xE8B300A7, 0xE8B40083, 0xE8B50094, 0xE8B700A7, 0xE8BA0057, 0xE8BE0083,
+ 0xE8C20094, 0xE8C30083, 0xE8C60094, 0xE8D50083, 0xE8D70094, 0xE8DE0894, 0xE8E10094, 0xE8EF0078,
+ 0xE9000054, 0xE9210083, 0xE9230078, 0xE9800054, 0xE9AC0078, 0xEA002877, 0xEA0D2855, 0xEA1A2877,
+ 0xEA272855, 0xEA342877, 0xEA412855, 0xEA4E2877, 0xEA500078, 0xEA512877, 0xEA520078, 0xEA532877,
+ 0xEA540078, 0xEA552877, 0xEA5B2855, 0xEA5D0078, 0xEA5F2855, 0xEA620078, 0xEA632855, 0xEA682877,
+ 0xEA752855, 0xEA822877, 0xEA830078, 0xEA842877, 0xEA860078, 0xEA872877, 0xEA8F2855, 0xEA9C2877,
+ 0xEA9D0078, 0xEA9E2877, 0xEAA40078, 0xEAA52877, 0xEAA92855, 0xEAB62877, 0xEAC32855, 0xEAD02877,
+ 0xEADD2855, 0xEAEA2877, 0xEAF72855, 0xEB042877, 0xEB112855, 0xEB1E2877, 0xEB2B2855, 0xEB382877,
+ 0xEB452855, 0xEB530078, 0xEB542877, 0xEB612855, 0xEB712877, 0xEB7E2855, 0xEB8E2877, 0xEB9B2855,
+ 0xEBAB2877, 0xEBB82855, 0xEBC82877, 0xEBD52855, 0xEBE50078, 0xEBE7280E, 0xEBE82810, 0xEBE92812,
+ 0xEBEA2814, 0xEBEB2816, 0xEBEC280E, 0xEBED2810, 0xEBEE2812, 0xEBEF2814, 0xEBF02816, 0xEBF1280E,
+ 0xEBF22810, 0xEBF32812, 0xEBF42814, 0xEBF52816, 0xEBF6280E, 0xEBF72810, 0xEBF82812, 0xEBF92814,
+ 0xEBFA2816, 0xEBFB280E, 0xEBFC2810, 0xEBFD2812, 0xEBFE2814, 0xEBFF2816, 0xEC000078
+ };
+
+ static const uint32_t a1[] = {
+ 0x00000071, 0x536C0078, 0x7C000871, 0x7D0F0078
+ };
+
+ static const uint32_t a7[] = {
+ 0x00100057, 0x00400078, 0x00800083, 0x00F80078, 0x8000013F, 0xFFFF0078
+ };
+
+ static const uint32_t a8[] = {
+ 0x0000013F, 0x7FFF0078
+ };
+
+ static const uint32_t a16[] = {
+ 0x00800865, 0x00880065, 0x00890865, 0x00930065, 0x00940865, 0x00980161, 0x00991065, 0x009A0865,
+ 0x009C0863, 0x009F1063, 0x00A00063, 0x00A10863, 0x00A41055, 0x00A50065, 0x00A60865, 0x00A90065,
+ 0x00AA0865, 0x00B30065, 0x00B40865, 0x00BC0863, 0x00BF1162, 0x00C00163, 0x00C10065, 0x00C30063,
+ 0x00C40068, 0x00C50063, 0x00C60055, 0x00C70164, 0x00C80063, 0x00C90068, 0x00CA0165, 0x00CB0166,
+ 0x00CC0065, 0x00CD0055, 0x00CE0167, 0x00CF0168, 0x00D00865, 0x00D10065, 0x00D30063, 0x00D4006F,
+ 0x00D50055, 0x00D60065, 0x00D70863, 0x00D80070, 0x00D90063, 0x00DB0169, 0x00DC0065, 0x00DD0071,
+ 0x00DE0065, 0x00DF016A, 0x00E00071, 0x00E21074, 0x00E31072, 0x00E41073, 0x00E51074, 0x00E60863,
+ 0x00EE016B, 0x00EF0865, 0x00F20065, 0x00F30865, 0x00F81072, 0x00F91073, 0x00FA0865, 0x00FB016C,
+ 0x00FC0865, 0x010E0065, 0x010F0865, 0x01100055, 0x01110065, 0x01130865, 0x011A0055, 0x011D0063,
+ 0x011E016D, 0x011F0055, 0x0120016E, 0x01210078, 0x01280055, 0x0129016F, 0x012A0055, 0x012B007A,
+ 0x012C0170, 0x012D0171, 0x012E0055, 0x01310172, 0x01320055, 0x01340173, 0x01350055, 0x01370173,
+ 0x01380055, 0x013A0174, 0x013B0055, 0x0141007D, 0x01420055, 0x0145007E, 0x01460055, 0x01587881,
+ 0x015C0082, 0x015D0081, 0x01610037, 0x01630082, 0x01680081, 0x01690037, 0x016C1037, 0x016F0037,
+ 0x01707881, 0x01720037, 0x01800083, 0x01A00883, 0x01A20175, 0x01A30083, 0x01B80078, 0x01BA0037,
+ 0x01BB0078, 0x01C20837, 0x01C30806, 0x01C40885, 0x01C50078, 0x01C70887, 0x01C80060, 0x01D50860,
+ 0x01D60889, 0x01D80061, 0x01E50861, 0x01E6088C, 0x01E70078, 0x01E81176, 0x01E90877, 0x01EA1177,
+ 0x01EB0055, 0x01EC0065, 0x01F81093, 0x01F90055, 0x01FA1178, 0x01FB0063, 0x01FC10D8, 0x01FD0065,
+ 0x01FE0077, 0x02000892, 0x02020092, 0x02030892, 0x02040092, 0x02060892, 0x02070092, 0x02080060,
+ 0x020C0860, 0x020D0060, 0x02180061, 0x021C0861, 0x021D0061, 0x02280893, 0x022A0093, 0x022B0893,
+ 0x022C0093, 0x022E0893, 0x022F0093, 0x02300065, 0x023B0865, 0x023C0065, 0x02410083, 0x02430078,
+ 0x02440095, 0x02450065, 0x02600863, 0x02610063, 0x02670078, 0x02680865, 0x026A0065, 0x026B0865,
+ 0x026C0065, 0x026D0865, 0x02700065, 0x02710865, 0x02740065, 0x02750865, 0x027B0065, 0x027C0865,
+ 0x027D0078, 0x02800065, 0x02880078, 0x02980096, 0x02AB0078, 0x02AC0081, 0x02AD0097, 0x02B00098,
+ 0x02C31055, 0x02C40097, 0x02C50078, 0x02C80083, 0x02E1009A, 0x02E20083, 0x02E40078, 0x02E8009B,
+ 0x02F50078, 0x02F8009B, 0x02F9009A, 0x02FA0078, 0x0300009C, 0x03020078, 0x03050140, 0x0306009D,
+ 0x03070054, 0x03080083, 0x030B0078, 0x030D009D, 0x030E0078, 0x030F009D, 0x0310009E, 0x0311089E,
+ 0x0313009E, 0x031D0078, 0x0320009E, 0x03250083, 0x032F0078, 0x03300179, 0x0331017A, 0x0332017B,
+ 0x0333017C, 0x0334017D, 0x033500A5, 0x0336009D, 0x0337009E, 0x033A109E, 0x033C009E, 0x0369089E,
+ 0x036A009E, 0x036B0083, 0x036E009C, 0x036F0083, 0x0372009F, 0x03730083, 0x03740054, 0x03750083,
+ 0x0377009E, 0x0378000F, 0x03790011, 0x037A0013, 0x037B0015, 0x037C0017, 0x037D009E, 0x037E00A6,
+ 0x037F009E, 0x0380009D, 0x03870057, 0x03880083, 0x0389009E, 0x03980083, 0x03A50078, 0x03A6009E,
+ 0x03B70078, 0x03C0009E, 0x03D30083, 0x03D8009E, 0x03D90078, 0x04800083, 0x048100A7, 0x04820071,
+ 0x04940871, 0x04950071, 0x04980871, 0x04990071, 0x049D0078, 0x049E0071, 0x049F00A7, 0x04A00083,
+ 0x04A400A7, 0x04A60083, 0x04A70078, 0x04A80083, 0x04AA0078, 0x04AC0871, 0x04B00071, 0x04B10083,
+ 0x04B20097, 0x04B3017E, 0x04B4017F, 0x04B50180, 0x04B60181, 0x04B70182, 0x04B80078, 0x04BE0071,
+ 0x04BF0078, 0x04C00083, 0x04C100A7, 0x04C20071, 0x04C60078, 0x04C70071, 0x04C80078, 0x04C90071,
+ 0x04D40078, 0x04D50071, 0x04D80078, 0x04DB0071, 0x04DD0078, 0x04DE0071, 0x04DF00A7, 0x04E00083,
+ 0x04E20078, 0x04E300A7, 0x04E40078, 0x04E508A7, 0x04E60083, 0x04E70078, 0x04EB00A7, 0x04EC0078,
+ 0x04EE0871, 0x04F00071, 0x04F10083, 0x04F20078, 0x04F3017E, 0x04F4017F, 0x04F50180, 0x04F60181,
+ 0x04F70182, 0x04F80071, 0x04F90008, 0x04FA00B6, 0x04FB00B7, 0x04FC0183, 0x04FD0078, 0x05000083,
+ 0x050100A7, 0x05020071, 0x05050078, 0x05070071, 0x05080078, 0x05090071, 0x05140078, 0x05150071,
+ 0x05180078, 0x05190871, 0x051A0071, 0x051B0078, 0x051C0071, 0x051D0078, 0x051F00A7, 0x05200083,
+ 0x05210078, 0x05230083, 0x05240078, 0x05250083, 0x05270078, 0x052C0871, 0x052E0078, 0x0533017E,
+ 0x0534017F, 0x05350180, 0x05360181, 0x05370182, 0x05380083, 0x05390071, 0x053A0078, 0x05400083,
+ 0x054100A7, 0x05420071, 0x05540078, 0x05550071, 0x05580078, 0x05590071, 0x055D0078, 0x055E0071,
+ 0x055F00A7, 0x05600083, 0x056400A7, 0x05660083, 0x05670078, 0x05700071, 0x05710083, 0x05720078,
+ 0x0573017E, 0x0574017F, 0x05750180, 0x05760181, 0x05770182, 0x05780008, 0x05790078, 0x05800083,
+ 0x058100A7, 0x05820071, 0x05860078, 0x05870071, 0x05880078, 0x05890071, 0x05940078, 0x05950071,
+ 0x05980078, 0x05990071, 0x059D0078, 0x059E0071, 0x059F0083, 0x05A20078, 0x05A300A7, 0x05A40078,
+ 0x05A508A7, 0x05A60083, 0x05A70078, 0x05AB00A7, 0x05AC0078, 0x05AE0871, 0x05AF0071, 0x05B10078,
+ 0x05B3017E, 0x05B4017F, 0x05B50180, 0x05B60181, 0x05B70182, 0x05B80071, 0x05B90078, 0x05C10071,
+ 0x05C50078, 0x05C70071, 0x05C80078, 0x05C90071, 0x05CB0078, 0x05CC0071, 0x05CD0078, 0x05CF0071,
+ 0x05D00078, 0x05D10071, 0x05D20078, 0x05D40071, 0x05D50078, 0x05D70071, 0x05DD0078, 0x05DF00A7,
+ 0x05E10078, 0x05E300A7, 0x05E40078, 0x05E508A7, 0x05E60083, 0x05E70078, 0x05EB00A7, 0x05EC0078,
+ 0x05F3017E, 0x05F4017F, 0x05F50180, 0x05F60181, 0x05F70182, 0x05F80184, 0x05F90054, 0x05FC0008,
+ 0x05FD0078, 0x060000A7, 0x06020071, 0x06060078, 0x06070071, 0x06080078, 0x06090071, 0x06140078,
+ 0x06150071, 0x061D0078, 0x061F0083, 0x062000A7, 0x06220078, 0x06230083, 0x06240078, 0x06250083,
+ 0x06270078, 0x062A0083, 0x062B0078, 0x06300071, 0x06310078, 0x0633017E, 0x0634017F, 0x06350180,
+ 0x06360181, 0x06370182, 0x06380078, 0x064100A7, 0x06420071, 0x06460078, 0x06470071, 0x06480078,
+ 0x06490071, 0x06540078, 0x06550071, 0x065D0078, 0x065E0071, 0x065F00B2, 0x066000A7, 0x06620078,
+ 0x066308A7, 0x06640078, 0x066508A7, 0x06660083, 0x06670078, 0x066A00A7, 0x066B0078, 0x06700071,
+ 0x06710078, 0x0673017E, 0x0674017F, 0x06750180, 0x06760181, 0x06770182, 0x06780078, 0x068100A7,
+ 0x06820071, 0x06860078, 0x06870071, 0x06880078, 0x06890071, 0x06940078, 0x06950071, 0x069D0078,
+ 0x069F00A7, 0x06A00083, 0x06A20078, 0x06A300A7, 0x06A40078, 0x06A508A7, 0x06A60083, 0x06A70078,
+ 0x06AB00A7, 0x06AC0078, 0x06B00071, 0x06B10078, 0x06B3017E, 0x06B4017F, 0x06B50180, 0x06B60181,
+ 0x06B70182, 0x06B80078, 0x06C100A7, 0x06C20071, 0x06CB0078, 0x06CD0071, 0x06DF0078, 0x06E00071,
+ 0x06E30078, 0x06E700A7, 0x06E90083, 0x06EA0078, 0x06EC00A7, 0x06EE08A7, 0x06EF00A7, 0x06F00078,
+ 0x06F900A7, 0x06FA0078, 0x07000071, 0x07180083, 0x07191071, 0x071A0083, 0x071D0078, 0x071F0008,
+ 0x07200071, 0x07230083, 0x07270097, 0x0728017E, 0x0729017F, 0x072A0180, 0x072B0181, 0x072C0182,
+ 0x072D0097, 0x072E0078, 0x07400071, 0x07410078, 0x07430071, 0x07440078, 0x07460071, 0x07470078,
+ 0x074A0071, 0x07540078, 0x07550071, 0x07580083, 0x07591071, 0x075A0083, 0x075E0071, 0x075F0078,
+ 0x07600071, 0x07620078, 0x07640083, 0x07670078, 0x0768017E, 0x0769017F, 0x076A0180, 0x076B0181,
+ 0x076C0182, 0x076D0078, 0x076E1071, 0x076F0078, 0x07800094, 0x07820097, 0x07890094, 0x078C0083,
+ 0x078D0094, 0x0790017E, 0x0791017F, 0x07920180, 0x07930181, 0x07940182, 0x079500B3, 0x079A0083,
+ 0x079D00BF, 0x079F00A7, 0x07A00071, 0x07A10871, 0x07A20071, 0x07A60871, 0x07A70071, 0x07AB0871,
+ 0x07AC0071, 0x07B40871, 0x07B50078, 0x07B80083, 0x07B90883, 0x07BB1083, 0x07BD0083, 0x07BF00A7,
+ 0x07C00883, 0x07C10083, 0x07C20097, 0x07C30083, 0x07C40071, 0x07C60078, 0x07C80083, 0x07C90883,
+ 0x07CA0083, 0x07CE0883, 0x07CF0083, 0x07D30883, 0x07D40083, 0x07DC0883, 0x07DD0083, 0x07DE0078,
+ 0x07DF0094, 0x07E60078, 0x07E70094, 0x07E80097, 0x07E90078, 0x08000071, 0x08150078, 0x08160083,
+ 0x081800A7, 0x08190078, 0x081B0083, 0x081D0078, 0x0820017E, 0x0821017F, 0x08220180, 0x08230181,
+ 0x08240182, 0x08250097, 0x08280071, 0x082B00A7, 0x082C0083, 0x082D0078, 0x085000B5, 0x08630078,
+ 0x08680071, 0x087D0097, 0x087E0078, 0x08800071, 0x08AD0078, 0x08AF0071, 0x08D10078, 0x08D40071,
+ 0x08FD0078, 0x09000071, 0x09240078, 0x09250071, 0x09270078, 0x09280071, 0x092B0078, 0x092D0071,
+ 0x092F0078, 0x09300071, 0x09440078, 0x09450071, 0x09470078, 0x09480071, 0x09580078, 0x09590071,
+ 0x095B0078, 0x095C0071, 0x095F0078, 0x09610071, 0x09630078, 0x09640071, 0x096B0078, 0x096C0071,
+ 0x09880078, 0x09890071, 0x098B0078, 0x098C0071, 0x09AD0078, 0x09AF0083, 0x09B00097, 0x09B400AD,
+ 0x09B500AE, 0x09B6012D, 0x09B7012E, 0x09B8012F, 0x09B90185, 0x09BA0186, 0x09BB0187, 0x09BC0188,
+ 0x09BD0184, 0x09BE0078, 0x09C00071, 0x09C80054, 0x09CD0078, 0x09D00071, 0x09FA0078, 0x0A000071,
+ 0x0B360097, 0x0B370071, 0x0B3B0078, 0x0B400071, 0x0B4D00B4, 0x0B4E0078, 0x0B500071, 0x0B750097,
+ 0x0B770189, 0x0B780078, 0x0B800071, 0x0B860078, 0x0B870071, 0x0B890083, 0x0B8A0078, 0x0B900071,
+ 0x0B990083, 0x0B9A0097, 0x0B9B0078, 0x0BA00071, 0x0BA90083, 0x0BAA0078, 0x0BB00071, 0x0BB60078,
+ 0x0BB70071, 0x0BB80078, 0x0BB90083, 0x0BBA0078, 0x0BC00071, 0x0BDA00C2, 0x0BDB0083, 0x0BDF00A7,
+ 0x0BE40083, 0x0BEA0097, 0x0BEB0081, 0x0BEC0097, 0x0BED0008, 0x0BEE0083, 0x0BEF0078, 0x0BF0017E,
+ 0x0BF1017F, 0x0BF20180, 0x0BF30181, 0x0BF40182, 0x0BF50078, 0x0BF80106, 0x0BF90107, 0x0BFA0108,
+ 0x0BFB0109, 0x0BFC010A, 0x0BFD0078, 0x0C000006, 0x0C050083, 0x0C070078, 0x0C08017E, 0x0C09017F,
+ 0x0C0A0180, 0x0C0B0181, 0x0C0C0182, 0x0C0D0078, 0x0C100071, 0x0C210081, 0x0C220071, 0x0C3C0078,
+ 0x0C400071, 0x0C540083, 0x0C550078, 0x0C800071, 0x0C8E0078, 0x0C900083, 0x0C9100A7, 0x0C930083,
+ 0x0C9400C8, 0x0C960078, 0x0C9800A7, 0x0C9C0083, 0x0C9E0078, 0x0CA20006, 0x0CA3017E, 0x0CA4017F,
+ 0x0CA50180, 0x0CA60181, 0x0CA70182, 0x0CA80071, 0x0CB70078, 0x0CB80071, 0x0CBA0078, 0x0CC00071,
+ 0x0CD50078, 0x0CD800A7, 0x0CE00071, 0x0CE400A7, 0x0CE50078, 0x0CE8017E, 0x0CE9017F, 0x0CEA0180,
+ 0x0CEB0181, 0x0CEC0182, 0x0CED0078, 0x0CEF0006, 0x0CF00054, 0x0D000071, 0x0D0B0083, 0x0D0C00A7,
+ 0x0D0E0078, 0x0D0F0097, 0x0D100078, 0x0E800055, 0x0E967881, 0x0E970081, 0x0E987881, 0x0E9D0081,
+ 0x0E9E7881, 0x0EB17055, 0x0EB50055, 0x0ECD7881, 0x0EE00083, 0x0EE20078, 0x0F000865, 0x0F4B0855,
+ 0x0F4D098A, 0x0F4E0078, 0x0F500865, 0x0F7D0078, 0x0F8008C9, 0x0F8408CA, 0x0F8808C9, 0x0F8B0078,
+ 0x0F8C08CA, 0x0F8F0078, 0x0F9008C9, 0x0F9408CA, 0x0F9808C9, 0x0F9C08CA, 0x0FA008C9, 0x0FA30078,
+ 0x0FA408CA, 0x0FA70078, 0x0FA808C9, 0x0FAC08CA, 0x0FB008C9, 0x0FB408CA, 0x0FB808CB, 0x0FB908CC,
+ 0x0FBB08CD, 0x0FBC08CE, 0x0FBD08CF, 0x0FBE08D0, 0x0FBF0078, 0x0FC008C9, 0x0FC408D1, 0x0FC808C9,
+ 0x0FCC08D1, 0x0FD008C9, 0x0FD408D1, 0x0FD808C9, 0x0FD9098B, 0x0FDA0078, 0x0FDB0855, 0x0FDC08CA,
+ 0x0FDD08D2, 0x0FDE1037, 0x0FE00837, 0x0FE1098B, 0x0FE20078, 0x0FE30855, 0x0FE408D5, 0x0FE60837,
+ 0x0FE808C9, 0x0FE90855, 0x0FEA0078, 0x0FEB0855, 0x0FEC08CA, 0x0FED08D6, 0x0FEE0837, 0x0FF008C9,
+ 0x0FF10855, 0x0FF20890, 0x0FF30855, 0x0FF408CA, 0x0FF508D7, 0x0FF60837, 0x0FF80078, 0x0FF9098B,
+ 0x0FFA0078, 0x0FFB0855, 0x0FFC08D9, 0x0FFD08DA, 0x0FFE0837, 0x0FFF0078, 0x10000805, 0x10011005,
+ 0x10035805, 0x10041005, 0x10050057, 0x1007018C, 0x10085899, 0x10090099, 0x100B1006, 0x100C018D,
+ 0x100D00DB, 0x100E018D, 0x100F00DB, 0x10100006, 0x10121006, 0x10130006, 0x1014018E, 0x1015018F,
+ 0x10160190, 0x10175853, 0x10180007, 0x10191007, 0x101A0006, 0x101B1006, 0x101C0126, 0x101D0006,
+ 0x101F0038, 0x10200006, 0x10220009, 0x10231006, 0x10250006, 0x102B1006, 0x102C0006, 0x102F1005,
+ 0x10300057, 0x10320078, 0x10350057, 0x10387855, 0x10390078, 0x103A7910, 0x103B7911, 0x103C7912,
+ 0x103D780B, 0x103E7809, 0x103F7855, 0x1040705D, 0x1041705B, 0x10427110, 0x10437111, 0x10447112,
+ 0x1045700B, 0x10467009, 0x10470078, 0x10487081, 0x104A0078, 0x10500008, 0x105B0078, 0x10680083,
+ 0x106E0095, 0x10700083, 0x10710095, 0x10720083, 0x10760078, 0x10801054, 0x10831077, 0x10841054,
+ 0x10852877, 0x10872855, 0x10882877, 0x10892855, 0x108A2877, 0x108B0054, 0x108C2877, 0x108F0054,
+ 0x10901054, 0x10910054, 0x10950991, 0x10962877, 0x10972855, 0x10982877, 0x109A1071, 0x109C2855,
+ 0x109D1054, 0x109E2855, 0x109F2877, 0x10A00019, 0x10A22877, 0x10A32855, 0x10A50019, 0x10A60078,
+ 0x10A9305F, 0x10AF3106, 0x10B01192, 0x10B11193, 0x10B21194, 0x10B31195, 0x10B41196, 0x10B51197,
+ 0x10B61198, 0x10B71199, 0x10B8119A, 0x10B9119B, 0x10BA119C, 0x10BB119D, 0x10BC119E, 0x10BD119F,
+ 0x10BE11A0, 0x10BF11A1, 0x10C001A2, 0x10C101A3, 0x10C20078, 0x10C80019, 0x10CA0054, 0x10CD0819,
+ 0x10CE0054, 0x10D10019, 0x10D20054, 0x10E60854, 0x10E70819, 0x10E80054, 0x10FA0019, 0x110000E8,
+ 0x11020019, 0x110408FB, 0x110500FC, 0x11070019, 0x110800E8, 0x11090059, 0x110A01A4, 0x110B0019,
+ 0x110D00E8, 0x11110019, 0x111500E8, 0x111610E8, 0x111800E8, 0x111A0019, 0x111C00E8, 0x111E00FE,
+ 0x111F00E8, 0x112008E8, 0x112101A5, 0x112200E8, 0x112308E8, 0x112500E8, 0x11260019, 0x112900FE,
+ 0x112B0019, 0x112F00E8, 0x11300019, 0x113200FE, 0x11360819, 0x113708FE, 0x113900FE, 0x113A08FE,
+ 0x113B00FE, 0x113C08FE, 0x113D00FE, 0x114008FE, 0x114100FE, 0x114208FE, 0x114300FE, 0x114408FE,
+ 0x114500FE, 0x11460019, 0x114700FD, 0x11490019, 0x115100FE, 0x11520019, 0x115300E8, 0x115401A6,
+ 0x115608E8, 0x115800FE, 0x115C0019, 0x115F00E8, 0x11600019, 0x116400FD, 0x116601A7, 0x11670019,
+ 0x116800FE, 0x11690019, 0x116B00FE, 0x117008FE, 0x117200FE, 0x117508FE, 0x11770019, 0x117800FE,
+ 0x11790102, 0x117A00E8, 0x117B0103, 0x117C00E8, 0x117D0104, 0x117E0105, 0x117F00E8, 0x11800054,
+ 0x118400FE, 0x11860054, 0x119000E8, 0x11910054, 0x11940809, 0x11950054, 0x119B0094, 0x11BD0054,
+ 0x11CA0094, 0x11CB0054, 0x11CD0019, 0x11DA00BF, 0x11DB0054, 0x11EE0078, 0x12000054, 0x12130078,
+ 0x12200054, 0x12250078, 0x123018C4, 0x123118C5, 0x123218C6, 0x123318C7, 0x1234191F, 0x1235191A,
+ 0x1236191B, 0x1237191C, 0x1238191D, 0x1239191E, 0x123A10C4, 0x123B10C5, 0x123C10C6, 0x123D10C7,
+ 0x123E111F, 0x123F111A, 0x1240111B, 0x1241111C, 0x1242111D, 0x1243111E, 0x1244105A, 0x124510E3,
+ 0x124610E4, 0x124710E5, 0x124811A8, 0x124911A9, 0x124A11AA, 0x124B11AB, 0x124C11AC, 0x124D11AD,
+ 0x124E1094, 0x125B1918, 0x12681919, 0x1275010B, 0x1276010C, 0x1277010D, 0x1278010E, 0x1279010F,
+ 0x127A0106, 0x127B0107, 0x127C0108, 0x127D0109, 0x127E010A, 0x127F00C3, 0x12800054, 0x12DB0019,
+ 0x12DC0054, 0x12E00019, 0x12E10054, 0x12FC0019, 0x13000054, 0x13370019, 0x13380054, 0x134E0078,
+ 0x13500054, 0x13590078, 0x13800054, 0x13820078, 0x13830054, 0x13850078, 0x13860054, 0x13A90078,
+ 0x13AC0054, 0x13AF0078, 0x13B00054, 0x13B4000A, 0x13BB00C4, 0x13BC00C5, 0x13BD00C6, 0x13BE00C7,
+ 0x13BF011F, 0x13C000C4, 0x13C100C5, 0x13C200C6, 0x13C300C7, 0x13C4011F, 0x13C500C4, 0x13C600C5,
+ 0x13C700C6, 0x13C800C7, 0x13C9011F, 0x13CA0078, 0x13CC0054, 0x13DF0078, 0x13E00019, 0x13E100FD,
+ 0x13E20009, 0x13E30078, 0x13E80019, 0x13E900E8, 0x13EA00FD, 0x13EB0019, 0x13EE00FD, 0x13EF0019,
+ 0x13F100FE, 0x13F3000A, 0x13F60078, 0x13F80019, 0x14000094, 0x14800019, 0x14C10009, 0x14C601AE,
+ 0x14C701AF, 0x14C80009, 0x14CC0019, 0x14CD00E8, 0x14D80019, 0x14E000FE, 0x14E100E8, 0x14E200FE,
+ 0x14E30019, 0x14E400E8, 0x14E50019, 0x14E700FD, 0x14E90019, 0x14EA00FE, 0x14EB0019, 0x14EC000A,
+ 0x14EE0019, 0x14F000E8, 0x14F30019, 0x14F400E8, 0x14F50019, 0x14FA01B0, 0x14FB00E8, 0x14FC00FE,
+ 0x14FD0019, 0x14FE000A, 0x14FF0019, 0x150500E8, 0x150E0019, 0x150F00E8, 0x15110019, 0x151400E8,
+ 0x151500FD, 0x15170019, 0x151A00FE, 0x151B0019, 0x151E00FE, 0x151F0019, 0x152B00E8, 0x152C0019,
+ 0x153200FE, 0x15330019, 0x153500E8, 0x15380019, 0x153900E8, 0x153A1019, 0x153B0019, 0x153C00FD,
+ 0x153D00E8, 0x153E00FD, 0x154200E8, 0x154500FD, 0x154600E8, 0x154800FD, 0x154E00E8, 0x155000FD,
+ 0x155100E8, 0x15520019, 0x155300FE, 0x155700FD, 0x155800E8, 0x155900FD, 0x155A00E8, 0x155D00FD,
+ 0x156300E8, 0x156600FD, 0x156B0019, 0x157101B1, 0x15730019, 0x157600FE, 0x15770019, 0x157900E8,
+ 0x157A0019, 0x157B00FD, 0x157D00E8, 0x157F0019, 0x15800054, 0x158A0078, 0x16000096, 0x16170078,
+ 0x16180098, 0x162F0078, 0x16400065, 0x16720054, 0x16750078, 0x167C0006, 0x167E005F, 0x167F0006,
+ 0x16800125, 0x16930078, 0x16980071, 0x16B30078, 0x16B77881, 0x16B80078, 0x16C00071, 0x16CB0078,
+ 0x16D00071, 0x16D30078, 0x16D40071, 0x16D70078, 0x16D80071, 0x16DB0078, 0x16DC0071, 0x16DF0078,
+ 0x16E00071, 0x16E30078, 0x16E40071, 0x16E70078, 0x16E80071, 0x16EB0078, 0x16EC0071, 0x16EF0078,
+ 0x17000006, 0x170100E0, 0x17030006, 0x17040126, 0x17050006, 0x170600E0, 0x17070006, 0x170B0099,
+ 0x170C0078, 0x170E00E0, 0x170F0078, 0x17400054, 0x174F1054, 0x17500054, 0x17791054, 0x177A0078,
+ 0x17801054, 0x17EB0078, 0x17F80054, 0x17FE0078, 0x18000006, 0x18020081, 0x180301B2, 0x1804000A,
+ 0x18090054, 0x180A000A, 0x180E00B4, 0x180F00BF, 0x181001B3, 0x181101B4, 0x181201B5, 0x181301B6,
+ 0x181401B7, 0x18150083, 0x18180081, 0x181B0054, 0x181C11B8, 0x181D0081, 0x181E0006, 0x181F0054,
+ 0x18200071, 0x18320871, 0x18350071, 0x18380871, 0x183A0071, 0x183B0871, 0x183D0071, 0x183E0871,
+ 0x183F0071, 0x184B0078, 0x184C0083, 0x184D1037, 0x184E0081, 0x184F8071, 0x18500071, 0x18620871,
+ 0x18650071, 0x18680871, 0x186A0071, 0x186B0871, 0x186D0071, 0x186E0871, 0x186F0071, 0x187B0871,
+ 0x187D0006, 0x187E0081, 0x187F8071, 0x18800078, 0x18820071, 0x18960078, 0x18981071, 0x18C70078,
+ 0x18C80094, 0x18C978B6, 0x18CA78B7, 0x18CB7894, 0x18D00071, 0x18DC0078, 0x18E00054, 0x18E80078,
+ 0x18F80071, 0x19001094, 0x190E1054, 0x190F0078, 0x191010B6, 0x191110B7, 0x191210B8, 0x191310B9,
+ 0x191410B0, 0x19151094, 0x19220078, 0x192819B9, 0x192919BA, 0x192A19BB, 0x192B19BC, 0x192C19BD,
+ 0x192D19BE, 0x192E19BF, 0x192F19C0, 0x19301894, 0x193E1854, 0x193F0094, 0x194018B6, 0x194118B7,
+ 0x194218B8, 0x194318B9, 0x194418B0, 0x19451894, 0x195819C1, 0x195919C2, 0x195A19C3, 0x195B19C4,
+ 0x195C19C5, 0x195D19C6, 0x195E19C7, 0x195F19C8, 0x19601094, 0x19666854, 0x19681894, 0x197F0078,
+ 0x19806894, 0x19AC1094, 0x19B86894, 0x19BB6854, 0x19BD6894, 0x19EF6854, 0x19F01094, 0x19FF6854,
+ 0x1A000071, 0x26DB0078, 0x26E00054, 0x27000071, 0x4FDE0078, 0x50000071, 0x500A0081, 0x500B0071,
+ 0x52460078, 0x52480054, 0x52630078, 0x53800037, 0x538B0078, 0x54000071, 0x54050083, 0x54060071,
+ 0x541100A7, 0x54120083, 0x541300A7, 0x54140054, 0x54160078, 0x56000071, 0x6BD20078, 0x6C00013E,
+ 0x7000013F, 0x7C800871, 0x7D070071, 0x7D0A0871, 0x7D0F0071, 0x7D120871, 0x7D130071, 0x7D150871,
+ 0x7D170078, 0x7D180871, 0x7D350078, 0x7D380871, 0x7D6D0078, 0x7D801055, 0x7D830078, 0x7D891055,
+ 0x7D8C0078, 0x7D8E089B, 0x7D90289B, 0x7D94280B, 0x7D95089B, 0x7D9B0078, 0x7D9C089B, 0x7D9E0078,
+ 0x7DA0089B, 0x7DA20078, 0x7DA3089B, 0x7DA7109B, 0x7DA8209E, 0x7DAA489E, 0x7DAB209E, 0x7DAC489E,
+ 0x7DAD209E, 0x7DAE489E, 0x7DAF209E, 0x7DB0489E, 0x7DB1209E, 0x7DB2489E, 0x7DB3209E, 0x7DB4489E,
+ 0x7DB5209E, 0x7DB6489E, 0x7DB7209E, 0x7DB8489E, 0x7DB9209E, 0x7DBA489E, 0x7DBB209E, 0x7DBC489E,
+ 0x7DBD209E, 0x7DBE489E, 0x7DBF209E, 0x7DC0489E, 0x7DC1209E, 0x7DC8489E, 0x7DC9209E, 0x7DCA489E,
+ 0x7DCB209E, 0x7DCC489E, 0x7DCD209E, 0x7DCE489E, 0x7DCF209E, 0x7DD1489E, 0x7DD2209E, 0x7DD4489E,
+ 0x7DD5209E, 0x7DD6489E, 0x7DD7209E, 0x7DD90078, 0x7DE9409E, 0x7DEA389E, 0x7DEB409E, 0x7DEF209E,
+ 0x7DF3489E, 0x7DF5209E, 0x7DFC409E, 0x7DFD389E, 0x7DFE209E, 0x7DFF489E, 0x7E00409E, 0x7E32209E,
+ 0x7E4B389E, 0x7E6F489E, 0x7E7A409E, 0x7E88209E, 0x7E96389E, 0x7E9A489E, 0x7E9E409E, 0x7E9F00BF,
+ 0x7EA00078, 0x7EA8209E, 0x7EA9389E, 0x7EAD209E, 0x7EAE389E, 0x7EAF209E, 0x7EB0389E, 0x7EB3209E,
+ 0x7EB5389E, 0x7EB7209E, 0x7EB9389E, 0x7EBA209E, 0x7EBB389E, 0x7EBC209E, 0x7EBE389E, 0x7EBF209E,
+ 0x7EC1389E, 0x7EC2209E, 0x7EC4389E, 0x7EC5209E, 0x7EC6389E, 0x7EC80078, 0x7EC9389E, 0x7ECB209E,
+ 0x7ECE389E, 0x7ECF209E, 0x7EDA389E, 0x7EDB209E, 0x7EE1389E, 0x7EE3209E, 0x7EE40078, 0x7EF8409E,
+ 0x7EFE0054, 0x7EFF0078, 0x7F000083, 0x7F088006, 0x7F0B80B4, 0x7F0C8006, 0x7F0D0078, 0x7F100083,
+ 0x7F120078, 0x7F188099, 0x7F198038, 0x7F1A80B4, 0x7F220006, 0x7F2380B4, 0x7F241006, 0x7F261038,
+ 0x7F286006, 0x7F290078, 0x7F2A600C, 0x7F2B6006, 0x7F2C60B4, 0x7F2F6007, 0x7F306006, 0x7F31600D,
+ 0x7F326019, 0x7F330078, 0x7F346008, 0x7F356006, 0x7F360078, 0x7F38489E, 0x7F39009E, 0x7F3A0078,
+ 0x7F3B489E, 0x7F40409E, 0x7F45389E, 0x7F46409E, 0x7F48389E, 0x7F49409E, 0x7F4B389E, 0x7F4C409E,
+ 0x7F4D389E, 0x7F4E409E, 0x7F4F389E, 0x7F50409E, 0x7F51389E, 0x7F52409E, 0x7F53389E, 0x7F54409E,
+ 0x7F59389E, 0x7F5A409E, 0x7F5B389E, 0x7F5C409E, 0x7F5D389E, 0x7F5E409E, 0x7F5F389E, 0x7F60409E,
+ 0x7F61389E, 0x7F62409E, 0x7F63389E, 0x7F64409E, 0x7F65389E, 0x7F66409E, 0x7F67389E, 0x7F68409E,
+ 0x7F69389E, 0x7F6A409E, 0x7F6B389E, 0x7F6C409E, 0x7F6D389E, 0x7F6E409E, 0x7F6F389E, 0x7F70409E,
+ 0x7F71389E, 0x7F72409E, 0x7F73389E, 0x7F74409E, 0x7F75389E, 0x7F76409E, 0x7F79389E, 0x7F7A409E,
+ 0x7F7E0078, 0x7F7F0057, 0x7F808806, 0x7F818807, 0x7F838806, 0x7F84880A, 0x7F85880B, 0x7F86880D,
+ 0x7F87880C, 0x7F88880F, 0x7F898811, 0x7F8A8813, 0x7F8B8815, 0x7F8C8817, 0x7F8D8806, 0x7F8E8819,
+ 0x7F8F8806, 0x7F908860, 0x7F9D8835, 0x7F9E8836, 0x7F9F8838, 0x7FA08861, 0x7FAD8835, 0x7FAE8836,
+ 0x7FAF8809, 0x7FB05006, 0x7FB1500A, 0x7FB25006, 0x7FB35071, 0x7FCF5081, 0x7FD05071, 0x7FDF0078,
+ 0x7FE15071, 0x7FE40078, 0x7FE55071, 0x7FE80078, 0x7FE95071, 0x7FEC0078, 0x7FED5071, 0x7FEE0078,
+ 0x7FF08808, 0x7FF18837, 0x7FF28808, 0x7FF30078, 0x7FF45019, 0x7FF65054, 0x7FF70078, 0x7FFC0141,
+ 0x7FFE0054, 0x7FFF0078, 0x80000071, 0x80130078, 0x80140071, 0x801D0078, 0x801E0071, 0x80270078,
+ 0x80280071, 0x802F0078, 0x80400071, 0x807D0078, 0x80800006, 0x80810078, 0x808300AD, 0x808400AE,
+ 0x8085012D, 0x8086012E, 0x8087012F, 0x80880185, 0x80890186, 0x808A0187, 0x808B0188, 0x808C0184,
+ 0x808D01C9, 0x808E01CA, 0x808F01CB, 0x809001CC, 0x809101CD, 0x809201CE, 0x809301CF, 0x809401D0,
+ 0x809500BE, 0x809601D1, 0x809701D2, 0x809801D3, 0x809901D4, 0x809A0078, 0x809B0094, 0x80A0014E,
+ 0x80A10152, 0x80A20153, 0x80A30157, 0x80A40154, 0x80A50155, 0x80A60156, 0x80A70152, 0x80A80150,
+ 0x80A90153, 0x80AA01D5, 0x80AB0154, 0x80AC014F, 0x80AD0158, 0x80AF0152, 0x80B00154, 0x80B201D6,
+ 0x80B30150, 0x80B501D7, 0x80B60153, 0x80B80156, 0x80B90152, 0x80BA005F, 0x80BC0054, 0x80C50078,
+ 0x81800071, 0x818F0078, 0x8190012D, 0x819100BB, 0x81920078, 0x81980071, 0x81A50078, 0x81C00071,
+ 0x81CF0097, 0x81D00071, 0x81E20078, 0x81E40071, 0x81E8014F, 0x81E90154, 0x81EA0155, 0x81EB0078,
+ 0x8200015B, 0x8214015C, 0x82280071, 0x824F0078, 0x8250017E, 0x8251017F, 0x82520180, 0x82530181,
+ 0x82540182, 0x82550078, 0x8400009B, 0x84030078, 0x8405009B, 0x841C0078, 0x841F009B, 0x84200078,
+ 0x85000083, 0x85030078, 0x85060083, 0x8508009B, 0x851A0078, 0x851C0083, 0x851D0078, 0x851F0083,
+ 0x852001D8, 0x852101D9, 0x852201DA, 0x852301DB, 0x85240078, 0x8528009A, 0x852C0078, 0xE8000094,
+ 0xE87B0078, 0xE8800094, 0xE8930078, 0xE8950094, 0xE8AF0894, 0xE8B200A7, 0xE8B30083, 0xE8B50094,
+ 0xE8B600A7, 0xE8B90057, 0xE8BD0083, 0xE8C10094, 0xE8C20083, 0xE8C60094, 0xE8D50083, 0xE8D70094,
+ 0xE8DD0894, 0xE8E00094, 0xE8EF0078, 0xE9000054, 0xE9210083, 0xE9220054, 0xE9230078, 0xE9800054,
+ 0xE9AB0078, 0xEA002877, 0xEA0D2855, 0xEA1A2877, 0xEA272855, 0xEA2A0078, 0xEA2B2855, 0xEA342877,
+ 0xEA412855, 0xEA4E0078, 0xEA4F2877, 0xEA500078, 0xEA522877, 0xEA530078, 0xEA542877, 0xEA560078,
+ 0xEA572877, 0xEA5B2855, 0xEA682877, 0xEA752855, 0xEA822877, 0xEA850078, 0xEA862877, 0xEA8A0078,
+ 0xEA8B2877, 0xEA8E0078, 0xEA8F2855, 0xEA9C2877, 0xEA9F0078, 0xEAA02877, 0xEAA20078, 0xEAA52877,
+ 0xEAA80078, 0xEAA92855, 0xEAB62877, 0xEAC32855, 0xEAD02877, 0xEADD2855, 0xEAEA2877, 0xEAF72855,
+ 0xEB042877, 0xEB112855, 0xEB1E2877, 0xEB2B2855, 0xEB382877, 0xEB452855, 0xEB530078, 0xEB542877,
+ 0xEB6029DC, 0xEB612855, 0xEB6D29DC, 0xEB6E2855, 0xEB712877, 0xEB7D29DC, 0xEB7E2855, 0xEB8A29DC,
+ 0xEB8B2855, 0xEB8E2877, 0xEB9A29DC, 0xEB9B2855, 0xEBA729DC, 0xEBA82855, 0xEBAB2877, 0xEBB729DC,
+ 0xEBB82855, 0xEBC429DC, 0xEBC52855, 0xEBC82877, 0xEBD429DC, 0xEBD52855, 0xEBE129DC, 0xEBE22855,
+ 0xEBE50078, 0xEBE7280F, 0xEBE82811, 0xEBE92813, 0xEBEA2815, 0xEBEB2817, 0xEBEC280F, 0xEBED2811,
+ 0xEBEE2813, 0xEBEF2815, 0xEBF02817, 0xEBF1280F, 0xEBF22811, 0xEBF32813, 0xEBF42815, 0xEBF52817,
+ 0xEBF6280F, 0xEBF72811, 0xEBF82813, 0xEBF92815, 0xEBFA2817, 0xEBFB280F, 0xEBFC2811, 0xEBFD2813,
+ 0xEBFE2815, 0xEBFF2817, 0xEC000078
+ };
+
+ static const uint32_t a17[] = {
+ 0x00000071, 0x536B0078, 0x7C000871, 0x7D0F0078
+ };
+
+ static const uint32_t a23[] = {
+ 0x00000057, 0x00010078, 0x00100057, 0x00400078, 0x00800083, 0x00F80078, 0x8000013F, 0xFFFF0078
+ };
+
+ static const uint32_t a24[] = {
+ 0x0000013F, 0x7FFF0078
+ };
+
+
+ // The full set of all arrays to be searched.
+ static const Range FULL_DATA[] = {
+ {sizeof(a0)/sizeof(uint32_t), a0},
+ {sizeof(a1)/sizeof(uint32_t), a1},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {sizeof(a7)/sizeof(uint32_t), a7},
+ {sizeof(a8)/sizeof(uint32_t), a8},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {sizeof(a16)/sizeof(uint32_t), a16},
+ {sizeof(a17)/sizeof(uint32_t), a17},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {sizeof(a23)/sizeof(uint32_t), a23},
+ {sizeof(a24)/sizeof(uint32_t), a24},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0}
+ };
+
+ // Array of uppercase differences
+ static const short UCDIFF[] = {
+ 0, -32, 743, 121, -1, -232, -300, 97,
+ 163, 130, 56, -2, -79, -210, -206, -205,
+ -202, -203, -207, -209, -211, -213, -214, -218,
+ -217, -219, -83, 84, -38, -37, -31, -64,
+ -63, -62, -57, -47, -54, -86, -80, 7,
+ -96, -48, -59, 8, 74, 86, 100, 128,
+ 112, 126, 9, -7205, -16, -26, -7264, -40
+ };
+
+ // Array of lowercase differences
+ static const short LCDIFF[] = {
+ 0, 32, 1, -199, -121, 210, 206, 205,
+ 79, 202, 203, 207, 211, 209, 213, 214,
+ 218, 217, 219, 2, -97, -56, -130, -163,
+ 83, 38, 37, 64, 63, -60, -7, 80,
+ 48, 7264, -8, -74, -9, -86, -100, -112,
+ -128, -126, -7517, -8383, -8262, 16, 26, 40
+ };
+
+ // Array of titlecase differences
+ static const short TCDIFF[] = {
+ 3, 1, 0, -1
+ };
+
+ // Array of mirrored character differences
+ static const short MIRROR_DIFF[] = {
+ 0, 1, -1, 2, -2, 16, -16, 3,
+ -3, 2016, 138, 1824, 2104, 2108, 2106, -138,
+ 8, 7, -8, -7, -1824, -2016, -2104, -2106,
+ -2108
+ };
+
+ // Array of all possible numeric values
+ static const int NUMERICS[] = {
+ -1, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, -2, 100, 1000,
+ 40, 50, 60, 70, 80, 90, 10000, 500,
+ 5000, 36, 37, 38, 39, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 200, 300,
+ 400, 600, 700, 800, 900, 2000, 3000, 4000,
+ 6000, 7000, 8000, 9000, 20000, 30000, 40000, 50000,
+ 60000, 70000, 80000, 90000
+ };
+
+ // All possible packed data values, no duplicates
+ static const uint32_t PACKED_DATA[] = {
+ 0x00000000, 0x0000012F, 0x0000016F, 0x0000014F, 0x0000018F, 0x0000018C, 0x000001B8, 0x000000B8,
+ 0x000000BA, 0x020005B5, 0x040005B6, 0x00000099, 0x000000F8, 0x00000094, 0x02000069, 0x04000069,
+ 0x06000069, 0x08000069, 0x0A000069, 0x0C000069, 0x0E000069, 0x10000069, 0x12000069, 0x14000069,
+ 0x060005B9, 0x000001B9, 0x080005B9, 0x16020001, 0x18020001, 0x1A020001, 0x1C020001, 0x1E020001,
+ 0x20020001, 0x22020001, 0x24020001, 0x26020001, 0x28020001, 0x2A020001, 0x2C020001, 0x2E020001,
+ 0x30020001, 0x32020001, 0x34020001, 0x36020001, 0x38020001, 0x3A020001, 0x3C020001, 0x3E020001,
+ 0x40020001, 0x42020001, 0x44020001, 0x46020001, 0x48020001, 0x060005B5, 0x080005B6, 0x000001BB,
+ 0x000001B7, 0x16000802, 0x18000802, 0x1A000802, 0x1C000802, 0x1E000802, 0x20000802, 0x22000802,
+ 0x24000802, 0x26000802, 0x28000802, 0x2A000802, 0x2C000802, 0x2E000802, 0x30000802, 0x32000802,
+ 0x34000802, 0x36000802, 0x38000802, 0x3A000802, 0x3C000802, 0x3E000802, 0x40000802, 0x42000802,
+ 0x44000802, 0x46000802, 0x48000802, 0x000000EC, 0x000001BC, 0x00000002, 0x0A0005BD, 0x00000130,
+ 0x000000BC, 0x000000B9, 0x0600006B, 0x0800006B, 0x00001002, 0x0400006B, 0x0C0005BE, 0x4A0001AB,
+ 0x00020001, 0x00000802, 0x00001802, 0x00040001, 0x00060001, 0x00002002, 0x00080001, 0x000C0001,
+ 0x000E0001, 0x00100001, 0x00140001, 0x00160001, 0x00180001, 0x00004002, 0x00004802, 0x00200001,
+ 0x00220001, 0x00000005, 0x00A60001, 0x01805802, 0x01042003, 0x00280001, 0x002C0001, 0x00000001,
+ 0x00000000, 0x00007002, 0x00007802, 0x00009802, 0x0000A802, 0x0000B802, 0x0000C002, 0x0000C802,
+ 0x0000D002, 0x00000004, 0x000001A4, 0x00000106, 0x00320001, 0x00340001, 0x00360001, 0x00380001,
+ 0x0000E002, 0x0000E802, 0x0000F002, 0x0000F802, 0x00010002, 0x00010802, 0x00012002, 0x00012802,
+ 0x00013802, 0x003A0001, 0x003E0001, 0x00013002, 0x0000001C, 0x00000107, 0x00400001, 0x00000018,
+ 0x00014802, 0x000001B4, 0x00000038, 0x00000025, 0x00000050, 0x00000058, 0x00000045, 0x00000044,
+ 0x020000C9, 0x060000C9, 0x0A0000C9, 0x0E0000C9, 0x120000C9, 0x000000D8, 0x0000005C, 0x00000008,
+ 0x02000009, 0x06000009, 0x0A000009, 0x0E000009, 0x12000009, 0x0400000B, 0x0800000B, 0x0000000B,
+ 0x1600000B, 0x4E00000B, 0x00000006, 0x4A00000B, 0x000001B5, 0x00420001, 0x0600000B, 0x0A00000B,
+ 0x0E00000B, 0x1200000B, 0x3E00000B, 0x5200000B, 0x5600000B, 0x5A00000B, 0x5C00000B, 0x000001B6,
+ 0x2400000A, 0x2800000A, 0x00000010, 0x020001AB, 0x060001AB, 0x0A0001AB, 0x0E0001AB, 0x120001AB,
+ 0x00000108, 0x00015802, 0x00440001, 0x00016002, 0x00016802, 0x00017002, 0x00017802, 0x00018002,
+ 0x00018802, 0x00440003, 0x00460001, 0x00480003, 0x00019802, 0x004A0001, 0x004C0001, 0x004E0001,
+ 0x003C0001, 0x00500001, 0x00520001, 0x000001BD, 0x0000018D, 0x000001D0, 0x00000250, 0x00000230,
+ 0x040005BE, 0x000000F9, 0x0200006B, 0x0A00006B, 0x0E00006B, 0x1200006B, 0x00540001, 0x00560001,
+ 0x000005B9, 0x045A000A, 0x085A000A, 0x0C5A000A, 0x105A000A, 0x145A000A, 0x185A000A, 0x525A000A,
+ 0x5E5A000A, 0x0401A00A, 0x0801A00A, 0x0C01A00A, 0x1001A00A, 0x1401A00A, 0x1801A00A, 0x5201A00A,
+ 0x5E01A00A, 0x4E00000A, 0x5C00000A, 0x0E0005B9, 0x100005B9, 0x020005B9, 0x040005B9, 0x160005B9,
+ 0x180005B9, 0x1A0005B9, 0x200005B9, 0x220005B9, 0x240005B9, 0x260005B9, 0x040001AB, 0x080001AB,
+ 0x0C0001AB, 0x100001AB, 0x140001AB, 0x180001AB, 0x1C0001AB, 0x200001AB, 0x240001AB, 0x280001AB,
+ 0x0C00006B, 0x1000006B, 0x1400006B, 0x1800006B, 0x1C00006B, 0x2000006B, 0x2400006B, 0x2800006B,
+ 0x005C001C, 0x0001A81C, 0x1A0001AB, 0x1E0001AB, 0x220001AB, 0x260001AB, 0x2A0001AB, 0x160001AB,
+ 0x020005B6, 0x100005B6, 0x280005B9, 0x2C0005B9, 0x300005B9, 0x0001B002, 0x020005BD, 0x0600000A,
+ 0x0A00000A, 0x0E00000A, 0x1200000A, 0x1600000A, 0x3E00000A, 0x0C00000B, 0x1000000B, 0x1400000B,
+ 0x2E0001AB, 0x320001AB, 0x360001AB, 0x3A0001AB, 0x3E0001AB, 0x420001AB, 0x460001AB, 0x640001AB,
+ 0x680001AB, 0x6A0001AB, 0x6E0001AB, 0x720001AB, 0x760001AB, 0x7A0001AB, 0x00000013, 0x00000012,
+ 0x0000005A, 0x000001B0, 0x7C00000B, 0x8000000B, 0x8200000B, 0x8600000B, 0x8C00000B, 0x6000000B,
+ 0x9200000B, 0x9600000B, 0x9800000B, 0x9C00000B, 0xA000000B, 0xA400000B, 0x4A0001AA, 0x040001AA,
+ 0x520001AA, 0x600001AA, 0x0C0001AA, 0x5E0001AA, 0x160001AA, 0x4C0001AA, 0x4E0001AA, 0x9E0001AA,
+ 0x060001AA, 0x8800000A, 0x2A0001AA, 0x005E0001, 0x0001B802, 0x0400002B, 0x0800002B, 0x1600002B,
+ 0x4C00002B, 0x00002802, 0x00003002, 0x000A0001, 0x00120001, 0x00003802, 0x001A0001, 0x001C0001,
+ 0x001E0001, 0x00240001, 0x00005002, 0x00006002, 0x002A0001, 0x002E0001, 0x00300001, 0x00006802,
+ 0x00008002, 0x00008802, 0x00009002, 0x0000A002, 0x0000B002, 0x0000D906, 0x00011002, 0x00011802,
+ 0x00014002, 0x040000C9, 0x080000C9, 0x0C0000C9, 0x100000C9, 0x140000C9, 0x04000009, 0x08000009,
+ 0x0C000009, 0x10000009, 0x14000009, 0x2200000B, 0x4C00000B, 0x2A00000B, 0x5000000B, 0x5400000B,
+ 0x5800000B, 0x2600000A, 0x00015002, 0x00019002, 0x00000030, 0x000001BE, 0x0000014E, 0x00000210,
+ 0x000001F0, 0x00580001, 0x065A000A, 0x0A5A000A, 0x0E5A000A, 0x125A000A, 0x165A000A, 0x1A5A000A,
+ 0x4C5A000A, 0x4E5A000A, 0x0601A00A, 0x0A01A00A, 0x0E01A00A, 0x1201A00A, 0x1601A00A, 0x1A01A00A,
+ 0x4C01A00A, 0x4E01A00A, 0x6000000A, 0x0000000A, 0x120005B9, 0x140005B9, 0x1C0005B9, 0x1E0005B9,
+ 0x1600006B, 0x1A00006B, 0x1E00006B, 0x2200006B, 0x2600006B, 0x2A00006B, 0x0E0005B5, 0x040005B5,
+ 0x2A0005B9, 0x2E0005B9, 0x0200000A, 0x0400000A, 0x0800000A, 0x0C00000A, 0x1000000A, 0x1400000A,
+ 0x2A00000A, 0x2C0001AB, 0x300001AB, 0x340001AB, 0x380001AB, 0x3C0001AB, 0x400001AB, 0x440001AB,
+ 0x480001AB, 0x620001AB, 0x660001AB, 0x500001AB, 0x6C0001AB, 0x700001AB, 0x740001AB, 0x780001AB,
+ 0x520001AB, 0x7E00000B, 0x5E00000B, 0x8400000B, 0x8800000B, 0x8A00000B, 0x8E00000B, 0x9000000B,
+ 0x9400000B, 0x9A00000B, 0x9E00000B, 0xA200000B, 0xA600000B, 0x5C0001AA, 0x3E0001AA, 0x7E0001AA,
+ 0x0600002B, 0x0A00002B, 0x2A00002B, 0x4E00002B, 0x00000019
+ };
+}
diff --git a/libs/utils/executablepath_darwin.cpp b/libs/utils/executablepath_darwin.cpp
new file mode 100644
index 0000000..2e3c3a0
--- /dev/null
+++ b/libs/utils/executablepath_darwin.cpp
@@ -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.
+ */
+
+#include <utils/executablepath.h>
+#import <Carbon/Carbon.h>
+#include <unistd.h>
+
+void executablepath(char s[PATH_MAX])
+{
+ ProcessSerialNumber psn;
+ GetCurrentProcess(&psn);
+ CFDictionaryRef dict;
+ dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
+ CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
+ CFSTR("CFBundleExecutable"));
+ CFStringGetCString(value, s, PATH_MAX+1, kCFStringEncodingUTF8);
+}
+
diff --git a/libs/utils/executablepath_linux.cpp b/libs/utils/executablepath_linux.cpp
new file mode 100644
index 0000000..b8d2a3d
--- /dev/null
+++ b/libs/utils/executablepath_linux.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#include <utils/executablepath.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+
+void executablepath(char exe[PATH_MAX])
+{
+ char proc[100];
+ sprintf(proc, "/proc/%d/exe", getpid());
+
+ int err = readlink(proc, exe, PATH_MAX);
+}
+
diff --git a/libs/utils/futex_synchro.c b/libs/utils/futex_synchro.c
new file mode 100644
index 0000000..c13760d
--- /dev/null
+++ b/libs/utils/futex_synchro.c
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <limits.h>
+
+#include <sys/time.h>
+#include <sched.h>
+
+#include <errno.h>
+
+#include <private/utils/futex_synchro.h>
+
+
+// This futex glue code is need on desktop linux, but is part of klibc on ARM
+#if !defined(__arm__)
+
+#include <sys/syscall.h>
+typedef unsigned int u32;
+#define asmlinkage
+#define __user
+#include <linux/futex.h>
+#include <utils/Atomic.h>
+
+
+int futex (int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3)
+{
+ int err = syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
+ return err == 0 ? 0 : -errno;
+}
+
+int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout)
+{
+ return futex((int*)ftx, FUTEX_WAIT, val, timeout, NULL, 0);
+}
+
+int __futex_wake(volatile void *ftx, int count)
+{
+ return futex((int*)ftx, FUTEX_WAKE, count, NULL, NULL, 0);
+}
+
+int __atomic_cmpxchg(int old, int _new, volatile int *ptr)
+{
+ return android_atomic_cmpxchg(old, _new, ptr);
+}
+
+int __atomic_swap(int _new, volatile int *ptr)
+{
+ return android_atomic_swap(_new, ptr);
+}
+
+int __atomic_dec(volatile int *ptr)
+{
+ return android_atomic_dec(ptr);
+}
+
+#else // !defined(__arm__)
+
+int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout);
+int __futex_wake(volatile void *ftx, int count);
+
+int __atomic_cmpxchg(int old, int _new, volatile int *ptr);
+int __atomic_swap(int _new, volatile int *ptr);
+int __atomic_dec(volatile int *ptr);
+
+#endif // !defined(__arm__)
+
+
+// lock states
+//
+// 0: unlocked
+// 1: locked, no waiters
+// 2: locked, maybe waiters
+
+void futex_mutex_init(futex_mutex_t *m)
+{
+ m->value = 0;
+}
+
+int futex_mutex_lock(futex_mutex_t *m, unsigned msec)
+{
+ if(__atomic_cmpxchg(0, 1, &m->value) == 0) {
+ return 0;
+ }
+ if(msec == FUTEX_WAIT_INFINITE) {
+ while(__atomic_swap(2, &m->value) != 0) {
+ __futex_wait(&m->value, 2, 0);
+ }
+ } else {
+ struct timespec ts;
+ ts.tv_sec = msec / 1000;
+ ts.tv_nsec = (msec % 1000) * 1000000;
+ while(__atomic_swap(2, &m->value) != 0) {
+ if(__futex_wait(&m->value, 2, &ts) == -ETIMEDOUT) {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+int futex_mutex_trylock(futex_mutex_t *m)
+{
+ if(__atomic_cmpxchg(0, 1, &m->value) == 0) {
+ return 0;
+ }
+ return -1;
+}
+
+void futex_mutex_unlock(futex_mutex_t *m)
+{
+ if(__atomic_dec(&m->value) != 1) {
+ m->value = 0;
+ __futex_wake(&m->value, 1);
+ }
+}
+
+/* XXX *technically* there is a race condition that could allow
+ * XXX a signal to be missed. If thread A is preempted in _wait()
+ * XXX after unlocking the mutex and before waiting, and if other
+ * XXX threads call signal or broadcast UINT_MAX times (exactly),
+ * XXX before thread A is scheduled again and calls futex_wait(),
+ * XXX then the signal will be lost.
+ */
+
+void futex_cond_init(futex_cond_t *c)
+{
+ c->value = 0;
+}
+
+int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec)
+{
+ if(msec == FUTEX_WAIT_INFINITE){
+ int oldvalue = c->value;
+ futex_mutex_unlock(m);
+ __futex_wait(&c->value, oldvalue, 0);
+ futex_mutex_lock(m, FUTEX_WAIT_INFINITE);
+ return 0;
+ } else {
+ int oldvalue = c->value;
+ struct timespec ts;
+ ts.tv_sec = msec / 1000;
+ ts.tv_nsec = (msec % 1000) * 1000000;
+ futex_mutex_unlock(m);
+ const int err = __futex_wait(&c->value, oldvalue, &ts);
+ futex_mutex_lock(m, FUTEX_WAIT_INFINITE);
+ return err;
+ }
+}
+
+void futex_cond_signal(futex_cond_t *c)
+{
+ __atomic_dec(&c->value);
+ __futex_wake(&c->value, 1);
+}
+
+void futex_cond_broadcast(futex_cond_t *c)
+{
+ __atomic_dec(&c->value);
+ __futex_wake(&c->value, INT_MAX);
+}
+
diff --git a/libs/utils/misc.cpp b/libs/utils/misc.cpp
new file mode 100644
index 0000000..dc89d15
--- /dev/null
+++ b/libs/utils/misc.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Miscellaneous utility functions.
+//
+#include <utils/misc.h>
+
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+
+using namespace android;
+
+namespace android {
+
+/*
+ * Like strdup(), but uses C++ "new" operator instead of malloc.
+ */
+char* strdupNew(const char* str)
+{
+ char* newStr;
+ int len;
+
+ if (str == NULL)
+ return NULL;
+
+ len = strlen(str);
+ newStr = new char[len+1];
+ memcpy(newStr, str, len+1);
+
+ return newStr;
+}
+
+/*
+ * Concatenate an argument vector.
+ */
+char* concatArgv(int argc, const char* const argv[])
+{
+ char* newStr = NULL;
+ int len, totalLen, posn, idx;
+
+ /*
+ * First, figure out the total length.
+ */
+ totalLen = idx = 0;
+ while (1) {
+ if (idx == argc || argv[idx] == NULL)
+ break;
+ if (idx)
+ totalLen++; // leave a space between args
+ totalLen += strlen(argv[idx]);
+ idx++;
+ }
+
+ /*
+ * Alloc the string.
+ */
+ newStr = new char[totalLen +1];
+ if (newStr == NULL)
+ return NULL;
+
+ /*
+ * Finally, allocate the string and copy data over.
+ */
+ idx = posn = 0;
+ while (1) {
+ if (idx == argc || argv[idx] == NULL)
+ break;
+ if (idx)
+ newStr[posn++] = ' ';
+
+ len = strlen(argv[idx]);
+ memcpy(&newStr[posn], argv[idx], len);
+ posn += len;
+
+ idx++;
+ }
+
+ assert(posn == totalLen);
+ newStr[posn] = '\0';
+
+ return newStr;
+}
+
+/*
+ * Count the #of args in an argument vector. Don't count the final NULL.
+ */
+int countArgv(const char* const argv[])
+{
+ int count = 0;
+
+ while (argv[count] != NULL)
+ count++;
+
+ return count;
+}
+
+
+#include <stdio.h>
+/*
+ * Get a file's type.
+ */
+FileType getFileType(const char* fileName)
+{
+ struct stat sb;
+
+ if (stat(fileName, &sb) < 0) {
+ if (errno == ENOENT || errno == ENOTDIR)
+ return kFileTypeNonexistent;
+ else {
+ fprintf(stderr, "getFileType got errno=%d on '%s'\n",
+ errno, fileName);
+ return kFileTypeUnknown;
+ }
+ } else {
+ if (S_ISREG(sb.st_mode))
+ return kFileTypeRegular;
+ else if (S_ISDIR(sb.st_mode))
+ return kFileTypeDirectory;
+ else if (S_ISCHR(sb.st_mode))
+ return kFileTypeCharDev;
+ else if (S_ISBLK(sb.st_mode))
+ return kFileTypeBlockDev;
+ else if (S_ISFIFO(sb.st_mode))
+ return kFileTypeFifo;
+#ifdef HAVE_SYMLINKS
+ else if (S_ISLNK(sb.st_mode))
+ return kFileTypeSymlink;
+ else if (S_ISSOCK(sb.st_mode))
+ return kFileTypeSocket;
+#endif
+ else
+ return kFileTypeUnknown;
+ }
+}
+
+/*
+ * Get a file's modification date.
+ */
+time_t getFileModDate(const char* fileName)
+{
+ struct stat sb;
+
+ if (stat(fileName, &sb) < 0)
+ return (time_t) -1;
+
+ return sb.st_mtime;
+}
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ * Found on http://graphics.stanford.edu/~seander/bithacks.html.
+ */
+unsigned int roundUpPower2(unsigned int val)
+{
+ val--;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val++;
+
+ return val;
+}
+
+}; // namespace android
+
diff --git a/libs/utils/ported.cpp b/libs/utils/ported.cpp
new file mode 100644
index 0000000..656e46f
--- /dev/null
+++ b/libs/utils/ported.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Ports of standard functions that don't exist on a specific platform.
+//
+// Note these are NOT in the "android" namespace.
+//
+#include <utils/ported.h>
+
+#if defined(NEED_GETTIMEOFDAY) || defined(NEED_USLEEP)
+# include <sys/time.h>
+# include <windows.h>
+#endif
+
+
+#if defined(NEED_GETTIMEOFDAY)
+/*
+ * Replacement gettimeofday() for Windows environments (primarily MinGW).
+ *
+ * Ignores "tz".
+ */
+int gettimeofday(struct timeval* ptv, struct timezone* tz)
+{
+ long long nsTime; // time in 100ns units since Jan 1 1601
+ FILETIME ft;
+
+ if (tz != NULL) {
+ // oh well
+ }
+
+ ::GetSystemTimeAsFileTime(&ft);
+ nsTime = (long long) ft.dwHighDateTime << 32 |
+ (long long) ft.dwLowDateTime;
+ // convert to time in usec since Jan 1 1970
+ ptv->tv_usec = (long) ((nsTime / 10LL) % 1000000LL);
+ ptv->tv_sec = (long) ((nsTime - 116444736000000000LL) / 10000000LL);
+
+ return 0;
+}
+#endif
+
+#if defined(NEED_USLEEP)
+//
+// Replacement usleep for Windows environments (primarily MinGW).
+//
+void usleep(unsigned long usec)
+{
+ // Win32 API function Sleep() takes milliseconds
+ ::Sleep((usec + 500) / 1000);
+}
+#endif
+
+#if 0 //defined(NEED_PIPE)
+//
+// Replacement pipe() command for MinGW
+//
+// The _O_NOINHERIT flag sets bInheritHandle to FALSE in the
+// SecurityAttributes argument to CreatePipe(). This means the handles
+// aren't inherited when a new process is created. The examples I've seen
+// use it, possibly because there's a lot of junk going on behind the
+// scenes. (I'm assuming "process" and "thread" are different here, so
+// we should be okay spinning up a thread.) The recommended practice is
+// to dup() the descriptor you want the child to have.
+//
+// It appears that unnamed pipes can't do non-blocking ("overlapped") I/O.
+// You can't use select() either, since that only works on sockets. The
+// Windows API calls that are useful here all operate on a HANDLE, not
+// an integer file descriptor, and I don't think you can get there from
+// here. The "named pipe" stuff is insane.
+//
+int pipe(int filedes[2])
+{
+ return _pipe(filedes, 0, _O_BINARY | _O_NOINHERIT);
+}
+#endif
+
+#if defined(NEED_SETENV)
+/*
+ * MinGW lacks these. For now, just stub them out so the code compiles.
+ */
+int setenv(const char* name, const char* value, int overwrite)
+{
+ return 0;
+}
+void unsetenv(const char* name)
+{
+}
+char* getenv(const char* name)
+{
+ return NULL;
+}
+#endif
diff --git a/opengl/libGLES_CM/Android.mk b/opengl/libGLES_CM/Android.mk
new file mode 100644
index 0000000..a0081ef
--- /dev/null
+++ b/opengl/libGLES_CM/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Build the wrapper OpenGL ES library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= gl_wrapper.cpp.arm gl_logger.cpp
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libui
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libGLES_CM
+
+# needed on sim build because of weird logging issues
+ifeq ($(TARGET_SIMULATOR),true)
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/opengl/libGLES_CM/egl_entries.cpp b/opengl/libGLES_CM/egl_entries.cpp
new file mode 100644
index 0000000..ba46f40
--- /dev/null
+++ b/opengl/libGLES_CM/egl_entries.cpp
@@ -0,0 +1,46 @@
+EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType)
+EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
+EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
+EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)
+EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)
+
+EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint *)
+EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePbufferSurface, EGLDisplay, EGLConfig, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLBoolean, eglQuerySurface, EGLDisplay, EGLSurface, EGLint, EGLint *)
+EGL_ENTRY(EGLContext, eglCreateContext, EGLDisplay, EGLConfig, EGLContext, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroyContext, EGLDisplay, EGLContext)
+EGL_ENTRY(EGLBoolean, eglMakeCurrent, EGLDisplay, EGLSurface, EGLSurface, EGLContext)
+EGL_ENTRY(EGLContext, eglGetCurrentContext, void)
+EGL_ENTRY(EGLSurface, eglGetCurrentSurface, EGLint)
+EGL_ENTRY(EGLDisplay, eglGetCurrentDisplay, void)
+EGL_ENTRY(EGLBoolean, eglQueryContext, EGLDisplay, EGLContext, EGLint, EGLint *)
+EGL_ENTRY(EGLBoolean, eglWaitGL, void)
+EGL_ENTRY(EGLBoolean, eglWaitNative, EGLint)
+EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType)
+EGL_ENTRY(EGLint, eglGetError, void)
+EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint)
+EGL_ENTRY(proc_t, eglGetProcAddress, const char *)
+
+/* EGL 1.1 */
+
+EGL_ENTRY(EGLBoolean, eglSurfaceAttrib, EGLDisplay, EGLSurface, EGLint, EGLint)
+EGL_ENTRY(EGLBoolean, eglBindTexImage, EGLDisplay, EGLSurface, EGLint)
+EGL_ENTRY(EGLBoolean, eglReleaseTexImage, EGLDisplay, EGLSurface, EGLint)
+EGL_ENTRY(EGLBoolean, eglSwapInterval, EGLDisplay, EGLint)
+
+/* EGL 1.2 */
+
+EGL_ENTRY(EGLBoolean, eglBindAPI, EGLenum)
+EGL_ENTRY(EGLenum, eglQueryAPI, void)
+EGL_ENTRY(EGLBoolean, eglWaitClient, void)
+EGL_ENTRY(EGLBoolean, eglReleaseThread, void)
+EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint *)
+
+/* Android extentions */
+
+EGL_ENTRY(EGLBoolean, eglSwapRectangleANDROID, EGLDisplay, EGLSurface , EGLint, EGLint, EGLint, EGLint)
+EGL_ENTRY(const char*, eglQueryStringConfigANDROID, EGLDisplay, EGLConfig, EGLint)
diff --git a/opengl/libGLES_CM/enumextract.sh b/opengl/libGLES_CM/enumextract.sh
new file mode 100644
index 0000000..5707302
--- /dev/null
+++ b/opengl/libGLES_CM/enumextract.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+awk '
+/^#define GL_/ {
+ names[count] = $2;
+ values[count] = $3;
+ sort[count] = $3 + 0;
+ count++;
+}
+END {
+ for (i = 1; i < count; i++) {
+ for (j = 0; j < i; j++) {
+ if (sort[i] < sort[j]) {
+ tn = names[i];
+ tv = values[i];
+ ts = sort[i];
+ names[i] = names[j];
+ values[i] = values[j];
+ sort[i] = sort[j];
+ names[j] = tn;
+ values[j] = tv;
+ sort[j] = ts;
+ }
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ printf("GLENUM(%s, %s)\n", names[i], values[i]);
+ }
+}
+' < $1
+
diff --git a/opengl/libGLES_CM/gl_api.cpp b/opengl/libGLES_CM/gl_api.cpp
new file mode 100644
index 0000000..ed3bdaa
--- /dev/null
+++ b/opengl/libGLES_CM/gl_api.cpp
@@ -0,0 +1,606 @@
+void API_ENTRY(glActiveTexture)(GLenum texture) {
+ CALL_GL_API(glActiveTexture, texture);
+}
+
+void API_ENTRY(glAlphaFunc)(GLenum func, GLclampf ref) {
+ CALL_GL_API(glAlphaFunc, func, ref);
+}
+
+void API_ENTRY(glAlphaFuncx)(GLenum func, GLclampx ref) {
+ CALL_GL_API(glAlphaFuncx, func, ref);
+}
+
+void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
+ CALL_GL_API(glBindTexture, target, texture);
+}
+
+void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
+ CALL_GL_API(glBlendFunc, sfactor, dfactor);
+}
+
+void API_ENTRY(glClear)(GLbitfield mask) {
+ CALL_GL_API(glClear, mask);
+}
+
+void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ CALL_GL_API(glClearColor, red, green, blue, alpha);
+}
+
+void API_ENTRY(glClearColorx)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
+ CALL_GL_API(glClearColorx, red, green, blue, alpha);
+}
+
+void API_ENTRY(glClearDepthf)(GLclampf depth) {
+ CALL_GL_API(glClearDepthf, depth);
+}
+
+void API_ENTRY(glClearDepthx)(GLclampx depth) {
+ CALL_GL_API(glClearDepthx, depth);
+}
+
+void API_ENTRY(glClearStencil)(GLint s) {
+ CALL_GL_API(glClearStencil, s);
+}
+
+void API_ENTRY(glClientActiveTexture)(GLenum texture) {
+ CALL_GL_API(glClientActiveTexture, texture);
+}
+
+void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
+ CALL_GL_API(glColor4f, red, green, blue, alpha);
+}
+
+void API_ENTRY(glColor4x)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) {
+ CALL_GL_API(glColor4x, red, green, blue, alpha);
+}
+
+void API_ENTRY(glColorMask)(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
+ CALL_GL_API(glColorMask, r, g, b, a);
+}
+
+void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
+{
+ CALL_GL_API(glColorPointer, size, type, stride, ptr);
+}
+
+void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLsizei imageSize, const GLvoid *data) {
+ CALL_GL_API(glCompressedTexImage2D, target, level, internalformat,
+ width, height, border, imageSize, data);
+}
+
+void API_ENTRY(glCompressedTexSubImage2D)( GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize,
+ const GLvoid *data) {
+ CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset,
+ width, height, format, imageSize, data);
+}
+
+void API_ENTRY(glCopyTexImage2D)( GLenum target, GLint level, GLenum internalformat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border) {
+ CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y,
+ width, height, border);
+}
+
+void API_ENTRY(glCopyTexSubImage2D)( GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLint x, GLint y, GLsizei width,
+ GLsizei height) {
+ CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y,
+ width, height);
+}
+
+void API_ENTRY(glCullFace)(GLenum mode) {
+ CALL_GL_API(glCullFace, mode);
+}
+
+void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) {
+ CALL_GL_API(glDeleteTextures, n, textures);
+}
+
+void API_ENTRY(glDepthFunc)(GLenum func) {
+ CALL_GL_API(glDepthFunc, func);
+}
+
+void API_ENTRY(glDepthMask)(GLboolean flag) {
+ CALL_GL_API(glDepthMask, flag);
+}
+
+void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
+ CALL_GL_API(glDepthRangef, zNear, zFar);
+}
+
+void API_ENTRY(glDepthRangex)(GLclampx zNear, GLclampx zFar) {
+ CALL_GL_API(glDepthRangex, zNear, zFar);
+}
+
+void API_ENTRY(glDisable)(GLenum cap) {
+ CALL_GL_API(glDisable, cap);
+}
+
+void API_ENTRY(glDisableClientState)(GLenum array) {
+ CALL_GL_API(glDisableClientState, array);
+}
+
+void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
+ CALL_GL_API(glDrawArrays, mode, first, count);
+}
+
+void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count,
+ GLenum type, const GLvoid *indices) {
+ CALL_GL_API(glDrawElements, mode, count, type, indices);
+}
+
+void API_ENTRY(glEnable)(GLenum cap) {
+ CALL_GL_API(glEnable, cap);
+}
+
+void API_ENTRY(glEnableClientState)(GLenum array) {
+ CALL_GL_API(glEnableClientState, array);
+}
+
+void API_ENTRY(glFinish)(void) {
+ CALL_GL_API(glFinish);
+}
+
+void API_ENTRY(glFlush)(void) {
+ CALL_GL_API(glFlush);
+}
+
+void API_ENTRY(glFogf)(GLenum pname, GLfloat param) {
+ CALL_GL_API(glFogf, pname, param);
+}
+
+void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glFogfv, pname, params);
+}
+
+void API_ENTRY(glFogx)(GLenum pname, GLfixed param) {
+ CALL_GL_API(glFogx, pname, param);
+}
+
+void API_ENTRY(glFogxv)(GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glFogxv, pname, params);
+}
+
+void API_ENTRY(glFrontFace)(GLenum mode) {
+ CALL_GL_API(glFrontFace, mode);
+}
+
+void API_ENTRY(glFrustumf)(GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar) {
+ CALL_GL_API(glFrustumf, left, right, bottom, top, zNear, zFar);
+}
+
+void API_ENTRY(glFrustumx)(GLfixed left, GLfixed right,
+ GLfixed bottom, GLfixed top,
+ GLfixed zNear, GLfixed zFar) {
+ CALL_GL_API(glFrustumx, left, right, bottom, top, zNear, zFar);
+}
+
+void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) {
+ CALL_GL_API(glGenTextures, n, textures);
+}
+
+GLenum API_ENTRY(glGetError)(void) {
+ CALL_GL_API_RETURN(glGetError);
+}
+
+void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *params) {
+ CALL_GL_API(glGetIntegerv, pname, params);
+}
+
+const GLubyte * API_ENTRY(glGetString)(GLenum name) {
+ CALL_GL_API_RETURN(glGetString, name);
+}
+
+void API_ENTRY(glHint)(GLenum target, GLenum mode) {
+ CALL_GL_API(glHint, target, mode);
+}
+
+void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) {
+ CALL_GL_API(glLightModelf, pname, param);
+}
+
+void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glLightModelfv, pname, params);
+}
+
+void API_ENTRY(glLightModelx)(GLenum pname, GLfixed param) {
+ CALL_GL_API(glLightModelx, pname, param);
+}
+
+void API_ENTRY(glLightModelxv)(GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glLightModelxv, pname, params);
+}
+
+void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) {
+ CALL_GL_API(glLightf, light, pname, param);
+}
+
+void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glLightfv, light, pname, params);
+}
+
+void API_ENTRY(glLightx)(GLenum light, GLenum pname, GLfixed param) {
+ CALL_GL_API(glLightx, light, pname, param);
+}
+
+void API_ENTRY(glLightxv)(GLenum light, GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glLightxv, light, pname, params);
+}
+
+void API_ENTRY(glLineWidth)(GLfloat width) {
+ CALL_GL_API(glLineWidth, width);
+}
+
+void API_ENTRY(glLineWidthx)(GLfixed width) {
+ CALL_GL_API(glLineWidthx, width);
+}
+
+void API_ENTRY(glLoadIdentity)(void) {
+ CALL_GL_API(glLoadIdentity);
+}
+
+void API_ENTRY(glLoadMatrixf)(const GLfloat *m) {
+ CALL_GL_API(glLoadMatrixf, m);
+}
+
+void API_ENTRY(glLoadMatrixx)(const GLfixed *m) {
+ CALL_GL_API(glLoadMatrixx, m);
+}
+
+void API_ENTRY(glLogicOp)(GLenum opcode) {
+ CALL_GL_API(glLogicOp, opcode);
+}
+
+void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) {
+ CALL_GL_API(glMaterialf, face, pname, param);
+}
+
+void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glMaterialfv, face, pname, params);
+}
+
+void API_ENTRY(glMaterialx)(GLenum face, GLenum pname, GLfixed param) {
+ CALL_GL_API(glMaterialx, face, pname, param);
+}
+
+void API_ENTRY(glMaterialxv)(GLenum face, GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glMaterialxv, face, pname, params);
+}
+
+void API_ENTRY(glMatrixMode)(GLenum mode) {
+ CALL_GL_API(glMatrixMode, mode);
+}
+
+void API_ENTRY(glMultMatrixf)(const GLfloat *m) {
+ CALL_GL_API(glMultMatrixf, m);
+}
+
+void API_ENTRY(glMultMatrixx)(const GLfixed *m) {
+ CALL_GL_API(glMultMatrixx, m);
+}
+
+void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) {
+ CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q);
+}
+
+void API_ENTRY(glMultiTexCoord4x)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) {
+ CALL_GL_API(glMultiTexCoord4x, target, s, t, r, q);
+}
+
+void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) {
+ CALL_GL_API(glNormal3f, nx, ny, nz);
+}
+
+void API_ENTRY(glNormal3x)(GLfixed nx, GLfixed ny, GLfixed nz) {
+ CALL_GL_API(glNormal3x, nx, ny, nz);
+}
+
+void API_ENTRY(glNormalPointer)(GLenum type, GLsizei stride, const GLvoid *pointer) {
+ CALL_GL_API(glNormalPointer, type, stride, pointer);
+}
+
+void API_ENTRY(glOrthof)( GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar) {
+ CALL_GL_API(glOrthof, left, right, bottom, top, zNear, zFar);
+}
+
+void API_ENTRY(glOrthox)( GLfixed left, GLfixed right,
+ GLfixed bottom, GLfixed top,
+ GLfixed zNear, GLfixed zFar) {
+ CALL_GL_API(glOrthox, left, right, bottom, top, zNear, zFar);
+}
+
+void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
+ CALL_GL_API(glPixelStorei, pname, param);
+}
+
+void API_ENTRY(glPointSize)(GLfloat size) {
+ CALL_GL_API(glPointSize, size);
+}
+
+void API_ENTRY(glPointSizex)(GLfixed size) {
+ CALL_GL_API(glPointSizex, size);
+}
+
+void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
+ CALL_GL_API(glPolygonOffset, factor, units);
+}
+
+void API_ENTRY(glPolygonOffsetx)(GLfixed factor, GLfixed units) {
+ CALL_GL_API(glPolygonOffsetx, factor, units);
+}
+
+void API_ENTRY(glPopMatrix)(void) {
+ CALL_GL_API(glPopMatrix);
+}
+
+void API_ENTRY(glPushMatrix)(void) {
+ CALL_GL_API(glPushMatrix);
+}
+
+void API_ENTRY(glReadPixels)( GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid *pixels) {
+ CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
+}
+
+void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glRotatef, angle, x, y, z);
+}
+
+void API_ENTRY(glRotatex)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) {
+ CALL_GL_API(glRotatex, angle, x, y, z);
+}
+
+void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
+ CALL_GL_API(glSampleCoverage, value, invert);
+}
+
+void API_ENTRY(glSampleCoveragex)(GLclampx value, GLboolean invert) {
+ CALL_GL_API(glSampleCoveragex, value, invert);
+}
+
+void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glScalef, x, y, z);
+}
+
+void API_ENTRY(glScalex)(GLfixed x, GLfixed y, GLfixed z) {
+ CALL_GL_API(glScalex, x, y, z);
+}
+
+void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glScissor, x, y, width, height);
+}
+
+void API_ENTRY(glShadeModel)(GLenum mode) {
+ CALL_GL_API(glShadeModel, mode);
+}
+
+void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
+ CALL_GL_API(glStencilFunc, func, ref, mask);
+}
+
+void API_ENTRY(glStencilMask)(GLuint mask) {
+ CALL_GL_API(glStencilMask, mask);
+}
+
+void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
+ CALL_GL_API(glStencilOp, fail, zfail, zpass);
+}
+
+void API_ENTRY(glTexCoordPointer)( GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer) {
+ CALL_GL_API(glTexCoordPointer, size, type, stride, pointer);
+}
+
+void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) {
+ CALL_GL_API(glTexEnvf, target, pname, param);
+}
+
+void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glTexEnvfv, target, pname, params);
+}
+
+void API_ENTRY(glTexEnvx)(GLenum target, GLenum pname, GLfixed param) {
+ CALL_GL_API(glTexEnvx, target, pname, param);
+}
+
+void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glTexEnvxv, target, pname, params);
+}
+
+void API_ENTRY(glTexImage2D)( GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border, GLenum format,
+ GLenum type, const GLvoid *pixels) {
+ CALL_GL_API(glTexImage2D, target, level, internalformat, width, height,
+ border, format, type, pixels);
+}
+
+void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
+ CALL_GL_API(glTexParameterf, target, pname, param);
+}
+
+void API_ENTRY(glTexParameterx)(GLenum target, GLenum pname, GLfixed param) {
+ CALL_GL_API(glTexParameterx, target, pname, param);
+}
+
+void API_ENTRY(glTexSubImage2D)( GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid *pixels) {
+ CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset,
+ width, height, format, type, pixels);
+}
+
+void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glTranslatef, x, y, z);
+}
+
+void API_ENTRY(glTranslatex)(GLfixed x, GLfixed y, GLfixed z) {
+ CALL_GL_API(glTranslatex, x, y, z);
+}
+
+void API_ENTRY(glVertexPointer)( GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer) {
+ CALL_GL_API(glVertexPointer, size, type, stride, pointer);
+}
+
+void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glViewport, x, y, width, height);
+}
+
+// ES 1.1
+void API_ENTRY(glClipPlanef)(GLenum plane, const GLfloat *equation) {
+ CALL_GL_API(glClipPlanef, plane, equation);
+}
+void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) {
+ CALL_GL_API(glClipPlanex, plane, equation);
+}
+void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
+ CALL_GL_API(glBindBuffer, target, buffer);
+}
+void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) {
+ CALL_GL_API(glBufferData, target, size, data, usage);
+}
+void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) {
+ CALL_GL_API(glBufferSubData, target, offset, size, data);
+}
+void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) {
+ CALL_GL_API(glDeleteBuffers, n, buffers);
+}
+void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) {
+ CALL_GL_API(glGenBuffers, n, buffers);
+}
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *params) {
+ CALL_GL_API(glGetBooleanv, pname, params);
+}
+void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) {
+ CALL_GL_API(glGetFixedv, pname, params);
+}
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *params) {
+ CALL_GL_API(glGetFloatv, pname, params);
+}
+void API_ENTRY(glGetPointerv)(GLenum pname, void **params) {
+ CALL_GL_API(glGetPointerv, pname, params);
+}
+void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) {
+ CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetClipPlanef)(GLenum pname, GLfloat eqn[4]) {
+ CALL_GL_API(glGetClipPlanef, pname, eqn);
+}
+void API_ENTRY(glGetClipPlanex)(GLenum pname, GLfixed eqn[4]) {
+ CALL_GL_API(glGetClipPlanex, pname, eqn);
+}
+void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) {
+ CALL_GL_API(glGetLightxv, light, pname, params);
+}
+void API_ENTRY(glGetLightfv)(GLenum light, GLenum pname, GLfloat *params) {
+ CALL_GL_API(glGetLightfv, light, pname, params);
+}
+void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) {
+ CALL_GL_API(glGetMaterialxv, face, pname, params);
+}
+void API_ENTRY(glGetMaterialfv)(GLenum face, GLenum pname, GLfloat *params) {
+ CALL_GL_API(glGetMaterialfv, face, pname, params);
+}
+void API_ENTRY(glGetTexEnvfv)(GLenum env, GLenum pname, GLfloat *params) {
+ CALL_GL_API(glGetTexEnvfv, env, pname, params);
+}
+void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) {
+ CALL_GL_API(glGetTexEnviv, env, pname, params);
+}
+void API_ENTRY(glGetTexEnvxv)(GLenum env, GLenum pname, GLfixed *params) {
+ CALL_GL_API(glGetTexEnvxv, env, pname, params);
+}
+void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) {
+ CALL_GL_API(glGetTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) {
+ CALL_GL_API(glGetTexParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetTexParameterxv)(GLenum target, GLenum pname, GLfixed *params) {
+ CALL_GL_API(glGetTexParameterxv, target, pname, params);
+}
+GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
+ CALL_GL_API_RETURN(glIsBuffer, buffer);
+}
+GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
+ CALL_GL_API_RETURN(glIsEnabled, cap);
+}
+GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
+ CALL_GL_API_RETURN(glIsTexture, texture);
+}
+void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) {
+ CALL_GL_API(glPointParameterf, pname, param);
+}
+void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glPointParameterfv, pname, params);
+}
+void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) {
+ CALL_GL_API(glPointParameterx, pname, param);
+}
+void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glPointParameterxv, pname, params);
+}
+void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) {
+ CALL_GL_API(glColor4ub, red, green, blue, alpha);
+}
+void API_ENTRY(glTexEnvi)(GLenum target, GLenum pname, GLint param) {
+ CALL_GL_API(glTexEnvi, target, pname, param);
+}
+void API_ENTRY(glTexEnviv)(GLenum target, GLenum pname, const GLint *params) {
+ CALL_GL_API(glTexEnviv, target, pname, params);
+}
+
+void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glTexParameterfv, target, pname, params);
+}
+
+void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) {
+ CALL_GL_API(glTexParameteriv, target, pname, params);
+}
+
+void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
+ CALL_GL_API(glTexParameteri, target, pname, param);
+}
+void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glTexParameterxv, target, pname, params);
+}
+void API_ENTRY(glPointSizePointerOES)(GLenum type, GLsizei stride, const GLvoid *pointer) {
+ CALL_GL_API(glPointSizePointerOES, type, stride, pointer);
+}
+
+// Extensions
+void API_ENTRY(glDrawTexsOES)(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
+ CALL_GL_API(glDrawTexsOES, x, y, z, w, h);
+}
+void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint w, GLint h) {
+ CALL_GL_API(glDrawTexiOES, x, y, z, w, h);
+}
+void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h) {
+ CALL_GL_API(glDrawTexfOES, x, y, z, w, h);
+}
+void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
+ CALL_GL_API(glDrawTexxOES, x, y, z, w, h);
+}
+void API_ENTRY(glDrawTexsvOES)(const GLshort* coords) {
+ CALL_GL_API(glDrawTexsvOES, coords);
+}
+void API_ENTRY(glDrawTexivOES)(const GLint* coords) {
+ CALL_GL_API(glDrawTexivOES, coords);
+}
+void API_ENTRY(glDrawTexfvOES)(const GLfloat* coords) {
+ CALL_GL_API(glDrawTexfvOES, coords);
+}
+void API_ENTRY(glDrawTexxvOES)(const GLfixed* coords) {
+ CALL_GL_API(glDrawTexxvOES, coords);
+}
+GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed* mantissa, GLint* exponent) {
+ CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent);
+}
diff --git a/opengl/libGLES_CM/gl_entries.cpp b/opengl/libGLES_CM/gl_entries.cpp
new file mode 100644
index 0000000..3279322
--- /dev/null
+++ b/opengl/libGLES_CM/gl_entries.cpp
@@ -0,0 +1,159 @@
+GL_ENTRY(void, glColor4f, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glColor4x, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glNormal3f, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glNormal3x, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glCullFace, GLenum)
+GL_ENTRY(void, glFrontFace, GLenum)
+GL_ENTRY(void, glDisable, GLenum)
+GL_ENTRY(void, glEnable, GLenum)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(const GLubyte*, glGetString, GLenum)
+GL_ENTRY(void, glGetIntegerv, GLenum, GLint *)
+GL_ENTRY(void, glColorMask, GLboolean, GLboolean, GLboolean, GLboolean)
+GL_ENTRY(void, glDepthMask, GLboolean)
+GL_ENTRY(void, glStencilMask, GLuint)
+GL_ENTRY(void, glDepthFunc, GLenum)
+GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glLogicOp, GLenum opcode)
+GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)
+GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColor, GLclampf r, GLclampf g, GLclampf b, GLclampf a)
+GL_ENTRY(void, glClearColorx, GLclampx r, GLclampx g, GLclampx b, GLclampx a)
+GL_ENTRY(void, glClearDepthf, GLclampf depth)
+GL_ENTRY(void, glClearDepthx, GLclampx depth)
+GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glPointSize, GLfloat)
+GL_ENTRY(void, glPointSizex, GLfixed)
+GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glHint, GLenum, GLenum mode)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLineWidthx, GLfixed width)
+GL_ENTRY(void, glShadeModel, GLenum)
+GL_ENTRY(void, glLightModelf, GLenum, GLfloat)
+GL_ENTRY(void, glLightModelfv, GLenum, const GLfloat *)
+GL_ENTRY(void, glLightModelx, GLenum, GLfixed)
+GL_ENTRY(void, glLightModelxv, GLenum, const GLfixed *)
+GL_ENTRY(void, glLightf, GLenum, GLenum, GLfloat)
+GL_ENTRY(void, glLightfv, GLenum, GLenum, const GLfloat *)
+GL_ENTRY(void, glLightx, GLenum, GLenum, GLfixed)
+GL_ENTRY(void, glLightxv, GLenum, GLenum, const GLfixed *)
+GL_ENTRY(void, glMaterialf, GLenum, GLenum, GLfloat)
+GL_ENTRY(void, glMaterialfv, GLenum, GLenum, const GLfloat *)
+GL_ENTRY(void, glMaterialx, GLenum, GLenum, GLfixed)
+GL_ENTRY(void, glMaterialxv, GLenum, GLenum, const GLfixed *)
+GL_ENTRY(void, glFogf, GLenum, GLfloat)
+GL_ENTRY(void, glFogfv, GLenum, const GLfloat *)
+GL_ENTRY(void, glFogx, GLenum, GLfixed)
+GL_ENTRY(void, glFogxv, GLenum, const GLfixed *)
+GL_ENTRY(void, glVertexPointer, GLint, GLenum, GLsizei, const GLvoid *)
+GL_ENTRY(void, glColorPointer, GLint, GLenum, GLsizei, const GLvoid *)
+GL_ENTRY(void, glNormalPointer, GLenum, GLsizei, const GLvoid *)
+GL_ENTRY(void, glTexCoordPointer, GLint, GLenum, GLsizei, const GLvoid *)
+GL_ENTRY(void, glEnableClientState, GLenum)
+GL_ENTRY(void, glDisableClientState, GLenum)
+GL_ENTRY(void, glClientActiveTexture, GLenum)
+GL_ENTRY(void, glDrawArrays, GLenum, GLint first, GLsizei)
+GL_ENTRY(void, glDrawElements, GLenum, GLsizei, GLenum, const GLvoid *)
+GL_ENTRY(void, glLoadIdentity, void)
+GL_ENTRY(void, glLoadMatrixf, const GLfloat*)
+GL_ENTRY(void, glLoadMatrixx, const GLfixed*)
+GL_ENTRY(void, glMatrixMode, GLenum mode)
+GL_ENTRY(void, glMultMatrixf, const GLfloat*)
+GL_ENTRY(void, glMultMatrixx, const GLfixed*)
+GL_ENTRY(void, glPopMatrix, void)
+GL_ENTRY(void, glPushMatrix, void)
+GL_ENTRY(void, glFrustumf, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glFrustumx, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glOrthof, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glOrthox, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glRotatef, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glRotatex, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glScalef, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glScalex, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glTranslatef, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glTranslatex, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glViewport, GLint, GLint, GLsizei, GLsizei)
+GL_ENTRY(void, glActiveTexture, GLenum)
+GL_ENTRY(void, glBindTexture, GLenum, GLuint)
+GL_ENTRY(void, glGenTextures, GLsizei, GLuint*)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *)
+GL_ENTRY(void, glMultiTexCoord4f, GLenum, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glMultiTexCoord4x, GLenum, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glPixelStorei, GLenum, GLint)
+GL_ENTRY(void, glTexEnvf, GLenum, GLenum, GLfloat)
+GL_ENTRY(void, glTexEnvfv, GLenum, GLenum, const GLfloat*)
+GL_ENTRY(void, glTexEnvx, GLenum, GLenum, GLfixed)
+GL_ENTRY(void, glTexEnvxv, GLenum, GLenum, const GLfixed*)
+GL_ENTRY(void, glTexParameterf, GLenum, GLenum, GLfloat)
+GL_ENTRY(void, glTexParameterx, GLenum, GLenum, GLfixed)
+GL_ENTRY(void, glCompressedTexImage2D, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)
+GL_ENTRY(void, glCopyTexImage2D, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)
+GL_ENTRY(void, glTexImage2D, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)
+GL_ENTRY(void, glTexSubImage2D, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)
+GL_ENTRY(void, glReadPixels, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *)
+
+// 1.1 additions
+GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat*)
+GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed*)
+GL_ENTRY(void, glBindBuffer, GLenum, GLuint)
+GL_ENTRY(void, glBufferData, GLenum, GLsizeiptr, const GLvoid*, GLenum)
+GL_ENTRY(void, glBufferSubData, GLenum, GLintptr, GLsizeiptr, const GLvoid*)
+GL_ENTRY(void, glDeleteBuffers, GLsizei, const GLuint*)
+GL_ENTRY(void, glGenBuffers, GLsizei, GLuint*)
+GL_ENTRY(void, glGetBooleanv, GLenum, GLboolean *)
+GL_ENTRY(void, glGetFixedv, GLenum, GLfixed *)
+GL_ENTRY(void, glGetFloatv, GLenum, GLfloat *)
+GL_ENTRY(void, glGetPointerv, GLenum, void **)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum, GLenum, GLint *)
+GL_ENTRY(void, glGetClipPlanef, GLenum, GLfloat[4])
+GL_ENTRY(void, glGetClipPlanex, GLenum, GLfixed[4])
+GL_ENTRY(void, glGetLightxv, GLenum, GLenum, GLfixed *)
+GL_ENTRY(void, glGetLightfv, GLenum, GLenum, GLfloat *)
+GL_ENTRY(void, glGetMaterialxv, GLenum, GLenum, GLfixed *)
+GL_ENTRY(void, glGetMaterialfv, GLenum, GLenum, GLfloat *)
+GL_ENTRY(void, glGetTexEnvfv, GLenum, GLenum, GLfloat *)
+GL_ENTRY(void, glGetTexEnviv, GLenum, GLenum, GLint *)
+GL_ENTRY(void, glGetTexEnvxv, GLenum, GLenum, GLfixed *)
+GL_ENTRY(void, glGetTexParameterfv, GLenum, GLenum, GLfloat *)
+GL_ENTRY(void, glGetTexParameteriv, GLenum, GLenum, GLint *)
+GL_ENTRY(void, glGetTexParameterxv, GLenum, GLenum, GLfixed *)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum)
+GL_ENTRY(GLboolean, glIsTexture, GLuint)
+GL_ENTRY(void, glPointParameterf, GLenum, GLfloat)
+GL_ENTRY(void, glPointParameterfv, GLenum, const GLfloat *)
+GL_ENTRY(void, glPointParameterx, GLenum, GLfixed)
+GL_ENTRY(void, glPointParameterxv, GLenum, const GLfixed *)
+GL_ENTRY(void, glColor4ub, GLubyte, GLubyte, GLubyte, GLubyte)
+GL_ENTRY(void, glTexEnvi, GLenum, GLenum, GLint)
+GL_ENTRY(void, glTexEnviv, GLenum, GLenum, const GLint *)
+GL_ENTRY(void, glTexParameterfv, GLenum, GLenum, const GLfloat *)
+GL_ENTRY(void, glTexParameteriv, GLenum, GLenum, const GLint *)
+GL_ENTRY(void, glTexParameteri, GLenum, GLenum, GLint)
+GL_ENTRY(void, glTexParameterxv, GLenum, GLenum, const GLfixed *)
+GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid*)
+
+// Extensions
+GL_ENTRY(void, glDrawTexsOES, GLshort, GLshort, GLshort, GLshort, GLshort)
+GL_ENTRY(void, glDrawTexiOES, GLint, GLint, GLint, GLint, GLint)
+GL_ENTRY(void, glDrawTexfOES, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)
+GL_ENTRY(void, glDrawTexxOES, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)
+GL_ENTRY(void, glDrawTexsvOES, const GLshort*)
+GL_ENTRY(void, glDrawTexivOES, const GLint*)
+GL_ENTRY(void, glDrawTexfvOES, const GLfloat*)
+GL_ENTRY(void, glDrawTexxvOES, const GLfixed*)
+GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed* mantissa, GLint* exponent)
+
diff --git a/opengl/libGLES_CM/gl_enums.in b/opengl/libGLES_CM/gl_enums.in
new file mode 100644
index 0000000..ffc2fad
--- /dev/null
+++ b/opengl/libGLES_CM/gl_enums.in
@@ -0,0 +1,261 @@
+GLENUM(GL_POINTS, 0x0000)
+GLENUM(GL_LINES, 0x0001)
+GLENUM(GL_LINE_LOOP, 0x0002)
+GLENUM(GL_LINE_STRIP, 0x0003)
+GLENUM(GL_TRIANGLES, 0x0004)
+GLENUM(GL_TRIANGLE_STRIP, 0x0005)
+GLENUM(GL_TRIANGLE_FAN, 0x0006)
+GLENUM(GL_ADD, 0x0104)
+GLENUM(GL_NEVER, 0x0200)
+GLENUM(GL_LESS, 0x0201)
+GLENUM(GL_EQUAL, 0x0202)
+GLENUM(GL_LEQUAL, 0x0203)
+GLENUM(GL_GREATER, 0x0204)
+GLENUM(GL_NOTEQUAL, 0x0205)
+GLENUM(GL_GEQUAL, 0x0206)
+GLENUM(GL_ALWAYS, 0x0207)
+GLENUM(GL_SRC_COLOR, 0x0300)
+GLENUM(GL_ONE_MINUS_SRC_COLOR, 0x0301)
+GLENUM(GL_SRC_ALPHA, 0x0302)
+GLENUM(GL_ONE_MINUS_SRC_ALPHA, 0x0303)
+GLENUM(GL_DST_ALPHA, 0x0304)
+GLENUM(GL_ONE_MINUS_DST_ALPHA, 0x0305)
+GLENUM(GL_DST_COLOR, 0x0306)
+GLENUM(GL_ONE_MINUS_DST_COLOR, 0x0307)
+GLENUM(GL_SRC_ALPHA_SATURATE, 0x0308)
+GLENUM(GL_FRONT, 0x0404)
+GLENUM(GL_BACK, 0x0405)
+GLENUM(GL_FRONT_AND_BACK, 0x0408)
+GLENUM(GL_INVALID_ENUM, 0x0500)
+GLENUM(GL_INVALID_VALUE, 0x0501)
+GLENUM(GL_INVALID_OPERATION, 0x0502)
+GLENUM(GL_STACK_OVERFLOW, 0x0503)
+GLENUM(GL_STACK_UNDERFLOW, 0x0504)
+GLENUM(GL_OUT_OF_MEMORY, 0x0505)
+GLENUM(GL_EXP, 0x0800)
+GLENUM(GL_EXP2, 0x0801)
+GLENUM(GL_CW, 0x0900)
+GLENUM(GL_CCW, 0x0901)
+GLENUM(GL_POINT_SMOOTH, 0x0B10)
+GLENUM(GL_SMOOTH_POINT_SIZE_RANGE, 0x0B12)
+GLENUM(GL_LINE_SMOOTH, 0x0B20)
+GLENUM(GL_SMOOTH_LINE_WIDTH_RANGE, 0x0B22)
+GLENUM(GL_CULL_FACE, 0x0B44)
+GLENUM(GL_LIGHTING, 0x0B50)
+GLENUM(GL_LIGHT_MODEL_TWO_SIDE, 0x0B52)
+GLENUM(GL_LIGHT_MODEL_AMBIENT, 0x0B53)
+GLENUM(GL_COLOR_MATERIAL, 0x0B57)
+GLENUM(GL_FOG, 0x0B60)
+GLENUM(GL_FOG_DENSITY, 0x0B62)
+GLENUM(GL_FOG_START, 0x0B63)
+GLENUM(GL_FOG_END, 0x0B64)
+GLENUM(GL_FOG_MODE, 0x0B65)
+GLENUM(GL_FOG_COLOR, 0x0B66)
+GLENUM(GL_DEPTH_TEST, 0x0B71)
+GLENUM(GL_STENCIL_TEST, 0x0B90)
+GLENUM(GL_NORMALIZE, 0x0BA1)
+GLENUM(GL_ALPHA_TEST, 0x0BC0)
+GLENUM(GL_DITHER, 0x0BD0)
+GLENUM(GL_BLEND, 0x0BE2)
+GLENUM(GL_COLOR_LOGIC_OP, 0x0BF2)
+GLENUM(GL_SCISSOR_TEST, 0x0C11)
+GLENUM(GL_PERSPECTIVE_CORRECTION_HINT, 0x0C50)
+GLENUM(GL_POINT_SMOOTH_HINT, 0x0C51)
+GLENUM(GL_LINE_SMOOTH_HINT, 0x0C52)
+GLENUM(GL_POLYGON_SMOOTH_HINT, 0x0C53)
+GLENUM(GL_FOG_HINT, 0x0C54)
+GLENUM(GL_UNPACK_ALIGNMENT, 0x0CF5)
+GLENUM(GL_PACK_ALIGNMENT, 0x0D05)
+GLENUM(GL_MAX_LIGHTS, 0x0D31)
+GLENUM(GL_MAX_CLIP_PLANES, 0x0D32)
+GLENUM(GL_MAX_TEXTURE_SIZE, 0x0D33)
+GLENUM(GL_MAX_MODELVIEW_STACK_DEPTH, 0x0D36)
+GLENUM(GL_MAX_PROJECTION_STACK_DEPTH, 0x0D38)
+GLENUM(GL_MAX_TEXTURE_STACK_DEPTH, 0x0D39)
+GLENUM(GL_MAX_VIEWPORT_DIMS, 0x0D3A)
+GLENUM(GL_RED_BITS, 0x0D52)
+GLENUM(GL_GREEN_BITS, 0x0D53)
+GLENUM(GL_BLUE_BITS, 0x0D54)
+GLENUM(GL_ALPHA_BITS, 0x0D55)
+GLENUM(GL_DEPTH_BITS, 0x0D56)
+GLENUM(GL_STENCIL_BITS, 0x0D57)
+GLENUM(GL_TEXTURE_2D, 0x0DE1)
+GLENUM(GL_DONT_CARE, 0x1100)
+GLENUM(GL_FASTEST, 0x1101)
+GLENUM(GL_NICEST, 0x1102)
+GLENUM(GL_AMBIENT, 0x1200)
+GLENUM(GL_DIFFUSE, 0x1201)
+GLENUM(GL_SPECULAR, 0x1202)
+GLENUM(GL_POSITION, 0x1203)
+GLENUM(GL_SPOT_DIRECTION, 0x1204)
+GLENUM(GL_SPOT_EXPONENT, 0x1205)
+GLENUM(GL_SPOT_CUTOFF, 0x1206)
+GLENUM(GL_CONSTANT_ATTENUATION, 0x1207)
+GLENUM(GL_LINEAR_ATTENUATION, 0x1208)
+GLENUM(GL_QUADRATIC_ATTENUATION, 0x1209)
+GLENUM(GL_BYTE, 0x1400)
+GLENUM(GL_UNSIGNED_BYTE, 0x1401)
+GLENUM(GL_SHORT, 0x1402)
+GLENUM(GL_UNSIGNED_SHORT, 0x1403)
+GLENUM(GL_FLOAT, 0x1406)
+GLENUM(GL_FIXED, 0x140C)
+GLENUM(GL_CLEAR, 0x1500)
+GLENUM(GL_AND, 0x1501)
+GLENUM(GL_AND_REVERSE, 0x1502)
+GLENUM(GL_COPY, 0x1503)
+GLENUM(GL_AND_INVERTED, 0x1504)
+GLENUM(GL_NOOP, 0x1505)
+GLENUM(GL_XOR, 0x1506)
+GLENUM(GL_OR, 0x1507)
+GLENUM(GL_NOR, 0x1508)
+GLENUM(GL_EQUIV, 0x1509)
+GLENUM(GL_INVERT, 0x150A)
+GLENUM(GL_OR_REVERSE, 0x150B)
+GLENUM(GL_COPY_INVERTED, 0x150C)
+GLENUM(GL_OR_INVERTED, 0x150D)
+GLENUM(GL_NAND, 0x150E)
+GLENUM(GL_SET, 0x150F)
+GLENUM(GL_EMISSION, 0x1600)
+GLENUM(GL_SHININESS, 0x1601)
+GLENUM(GL_AMBIENT_AND_DIFFUSE, 0x1602)
+GLENUM(GL_MODELVIEW, 0x1700)
+GLENUM(GL_PROJECTION, 0x1701)
+GLENUM(GL_TEXTURE, 0x1702)
+GLENUM(GL_ALPHA, 0x1906)
+GLENUM(GL_RGB, 0x1907)
+GLENUM(GL_RGBA, 0x1908)
+GLENUM(GL_LUMINANCE, 0x1909)
+GLENUM(GL_LUMINANCE_ALPHA, 0x190A)
+GLENUM(GL_FLAT, 0x1D00)
+GLENUM(GL_SMOOTH, 0x1D01)
+GLENUM(GL_KEEP, 0x1E00)
+GLENUM(GL_REPLACE, 0x1E01)
+GLENUM(GL_REPLACE, 0x1E01)
+GLENUM(GL_INCR, 0x1E02)
+GLENUM(GL_DECR, 0x1E03)
+GLENUM(GL_VENDOR, 0x1F00)
+GLENUM(GL_RENDERER, 0x1F01)
+GLENUM(GL_VERSION, 0x1F02)
+GLENUM(GL_EXTENSIONS, 0x1F03)
+GLENUM(GL_MODULATE, 0x2100)
+GLENUM(GL_DECAL, 0x2101)
+GLENUM(GL_TEXTURE_ENV_MODE, 0x2200)
+GLENUM(GL_TEXTURE_ENV_COLOR, 0x2201)
+GLENUM(GL_TEXTURE_ENV, 0x2300)
+GLENUM(GL_NEAREST, 0x2600)
+GLENUM(GL_LINEAR, 0x2601)
+GLENUM(GL_NEAREST_MIPMAP_NEAREST, 0x2700)
+GLENUM(GL_LINEAR_MIPMAP_NEAREST, 0x2701)
+GLENUM(GL_NEAREST_MIPMAP_LINEAR, 0x2702)
+GLENUM(GL_LINEAR_MIPMAP_LINEAR, 0x2703)
+GLENUM(GL_TEXTURE_MAG_FILTER, 0x2800)
+GLENUM(GL_TEXTURE_MIN_FILTER, 0x2801)
+GLENUM(GL_TEXTURE_WRAP_S, 0x2802)
+GLENUM(GL_TEXTURE_WRAP_T, 0x2803)
+GLENUM(GL_CLAMP, 0x2900)
+GLENUM(GL_REPEAT, 0x2901)
+GLENUM(GL_CLIP_PLANE0, 0x3000)
+GLENUM(GL_CLIP_PLANE1, 0x3001)
+GLENUM(GL_CLIP_PLANE2, 0x3002)
+GLENUM(GL_CLIP_PLANE3, 0x3003)
+GLENUM(GL_CLIP_PLANE4, 0x3004)
+GLENUM(GL_CLIP_PLANE5, 0x3005)
+GLENUM(GL_LIGHT0, 0x4000)
+GLENUM(GL_LIGHT1, 0x4001)
+GLENUM(GL_LIGHT2, 0x4002)
+GLENUM(GL_LIGHT3, 0x4003)
+GLENUM(GL_LIGHT4, 0x4004)
+GLENUM(GL_LIGHT5, 0x4005)
+GLENUM(GL_LIGHT6, 0x4006)
+GLENUM(GL_LIGHT7, 0x4007)
+GLENUM(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0x7E80)
+GLENUM(GL_UNSIGNED_SHORT_4_4_4_4, 0x8033)
+GLENUM(GL_UNSIGNED_SHORT_5_5_5_1, 0x8034)
+GLENUM(GL_POLYGON_OFFSET_FILL, 0x8037)
+GLENUM(GL_RESCALE_NORMAL, 0x803A)
+GLENUM(GL_VERTEX_ARRAY, 0x8074)
+GLENUM(GL_NORMAL_ARRAY, 0x8075)
+GLENUM(GL_COLOR_ARRAY, 0x8076)
+GLENUM(GL_TEXTURE_COORD_ARRAY, 0x8078)
+GLENUM(GL_MULTISAMPLE, 0x809D)
+GLENUM(GL_SAMPLE_ALPHA_TO_COVERAGE, 0x809E)
+GLENUM(GL_SAMPLE_ALPHA_TO_ONE, 0x809F)
+GLENUM(GL_SAMPLE_COVERAGE, 0x80A0)
+GLENUM(GL_MAX_ELEMENTS_VERTICES, 0x80E8)
+GLENUM(GL_MAX_ELEMENTS_INDICES, 0x80E9)
+GLENUM(GL_CLAMP_TO_EDGE, 0x812F)
+GLENUM(GL_GENERATE_MIPMAP, 0x8191)
+GLENUM(GL_GENERATE_MIPMAP_HINT, 0x8192)
+GLENUM(GL_UNSIGNED_SHORT_5_6_5, 0x8363)
+GLENUM(GL_ALIASED_POINT_SIZE_RANGE, 0x846D)
+GLENUM(GL_ALIASED_LINE_WIDTH_RANGE, 0x846E)
+GLENUM(GL_TEXTURE0, 0x84C0)
+GLENUM(GL_TEXTURE1, 0x84C1)
+GLENUM(GL_TEXTURE2, 0x84C2)
+GLENUM(GL_TEXTURE3, 0x84C3)
+GLENUM(GL_TEXTURE4, 0x84C4)
+GLENUM(GL_TEXTURE5, 0x84C5)
+GLENUM(GL_TEXTURE6, 0x84C6)
+GLENUM(GL_TEXTURE7, 0x84C7)
+GLENUM(GL_TEXTURE8, 0x84C8)
+GLENUM(GL_TEXTURE9, 0x84C9)
+GLENUM(GL_TEXTURE10, 0x84CA)
+GLENUM(GL_TEXTURE11, 0x84CB)
+GLENUM(GL_TEXTURE12, 0x84CC)
+GLENUM(GL_TEXTURE13, 0x84CD)
+GLENUM(GL_TEXTURE14, 0x84CE)
+GLENUM(GL_TEXTURE15, 0x84CF)
+GLENUM(GL_TEXTURE16, 0x84D0)
+GLENUM(GL_TEXTURE17, 0x84D1)
+GLENUM(GL_TEXTURE18, 0x84D2)
+GLENUM(GL_TEXTURE19, 0x84D3)
+GLENUM(GL_TEXTURE20, 0x84D4)
+GLENUM(GL_TEXTURE21, 0x84D5)
+GLENUM(GL_TEXTURE22, 0x84D6)
+GLENUM(GL_TEXTURE23, 0x84D7)
+GLENUM(GL_TEXTURE24, 0x84D8)
+GLENUM(GL_TEXTURE25, 0x84D9)
+GLENUM(GL_TEXTURE26, 0x84DA)
+GLENUM(GL_TEXTURE27, 0x84DB)
+GLENUM(GL_TEXTURE28, 0x84DC)
+GLENUM(GL_TEXTURE29, 0x84DD)
+GLENUM(GL_TEXTURE30, 0x84DE)
+GLENUM(GL_TEXTURE31, 0x84DF)
+GLENUM(GL_MAX_TEXTURE_UNITS, 0x84E2)
+GLENUM(GL_NUM_COMPRESSED_TEXTURE_FORMATS, 0x86A2)
+GLENUM(GL_COMPRESSED_TEXTURE_FORMATS, 0x86A3)
+GLENUM(GL_BUFFER_SIZE, 0x8764)
+GLENUM(GL_BUFFER_USAGE, 0x8765)
+GLENUM(GL_POINT_SPRITE_OES, 0x8861)
+GLENUM(GL_COORD_REPLACE_OES, 0x8862)
+GLENUM(GL_ARRAY_BUFFER, 0x8892)
+GLENUM(GL_ELEMENT_ARRAY_BUFFER, 0x8893)
+GLENUM(GL_ARRAY_BUFFER_BINDING, 0x8894)
+GLENUM(GL_ELEMENT_ARRAY_BUFFER_BINDING, 0x8895)
+GLENUM(GL_VERTEX_ARRAY_BUFFER_BINDING, 0x8896)
+GLENUM(GL_NORMAL_ARRAY_BUFFER_BINDING, 0x8897)
+GLENUM(GL_COLOR_ARRAY_BUFFER_BINDING, 0x8898)
+GLENUM(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, 0x889A)
+GLENUM(GL_STATIC_DRAW, 0x88E4)
+GLENUM(GL_DYNAMIC_DRAW, 0x88E8)
+GLENUM(GL_POINT_SIZE_ARRAY_TYPE_OES, 0x898A)
+GLENUM(GL_POINT_SIZE_ARRAY_STRIDE_OES, 0x898B)
+GLENUM(GL_POINT_SIZE_ARRAY_POINTER_OES, 0x898C)
+GLENUM(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898D)
+GLENUM(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898E)
+GLENUM(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898F)
+GLENUM(GL_PALETTE4_RGB8_OES, 0x8B90)
+GLENUM(GL_PALETTE4_RGBA8_OES, 0x8B91)
+GLENUM(GL_PALETTE4_R5_G6_B5_OES, 0x8B92)
+GLENUM(GL_PALETTE4_RGBA4_OES, 0x8B93)
+GLENUM(GL_PALETTE4_RGB5_A1_OES, 0x8B94)
+GLENUM(GL_PALETTE8_RGB8_OES, 0x8B95)
+GLENUM(GL_PALETTE8_RGBA8_OES, 0x8B96)
+GLENUM(GL_PALETTE8_R5_G6_B5_OES, 0x8B97)
+GLENUM(GL_PALETTE8_RGBA4_OES, 0x8B98)
+GLENUM(GL_PALETTE8_RGB5_A1_OES, 0x8B99)
+GLENUM(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, 0x8B9A)
+GLENUM(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, 0x8B9B)
+GLENUM(GL_POINT_SIZE_ARRAY_OES, 0x8B9C)
+GLENUM(GL_TEXTURE_CROP_RECT_OES, 0x8B9D)
+GLENUM(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES, 0x8B9F)
diff --git a/opengl/libGLES_CM/gl_logger.cpp b/opengl/libGLES_CM/gl_logger.cpp
new file mode 100644
index 0000000..14b5a39
--- /dev/null
+++ b/opengl/libGLES_CM/gl_logger.cpp
@@ -0,0 +1,1059 @@
+/*
+ ** 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.
+ */
+
+#define LOG_TAG "GLLogger"
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+
+#include <sys/ioctl.h>
+
+#include <GLES/egl.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <cutils/properties.h>
+
+#include <utils/String8.h>
+
+#include "gl_logger.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+#undef NELEM
+#define NELEM(x) (sizeof(x)/sizeof(*(x)))
+
+template<typename T>
+static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
+{
+ while (first <= last) {
+ int mid = (first + last) / 2;
+ if (key > sortedArray[mid].key) {
+ first = mid + 1;
+ } else if (key < sortedArray[mid].key) {
+ last = mid - 1;
+ } else {
+ return mid;
+ }
+ }
+ return -1;
+}
+
+struct pair_t {
+ const char* name;
+ int key;
+};
+
+static const pair_t gEnumMap[] = {
+ #define GLENUM(NAME, VALUE) { #NAME, VALUE },
+ #include "gl_enums.in"
+ #undef GLENUM
+};
+
+// ----------------------------------------------------------------------------
+
+template<typename TYPE>
+class GLLogValue {
+public:
+ GLLogValue(TYPE value) : mValue(value) { }
+ const TYPE& getValue() const { return mValue; }
+ String8 toString() const {
+ return convertToString(mValue);
+ }
+private:
+ const TYPE& mValue;
+ String8 convertToString(unsigned int v) const {
+ char buf[16];
+ snprintf(buf, 16, "%u", v);
+ return String8(buf);
+ }
+ String8 convertToString(unsigned long v) const {
+ char buf[16];
+ snprintf(buf, 16, "%lu", v);
+ return String8(buf);
+ }
+ String8 convertToString(int v) const {
+ char buf[16];
+ snprintf(buf, 16, "%d", v);
+ return String8(buf);
+ }
+ String8 convertToString(long v) const {
+ char buf[16];
+ snprintf(buf, 16, "%ld", v);
+ return String8(buf);
+ }
+ String8 convertToString(float v) const {
+ char buf[16];
+ snprintf(buf, 16, "%f", v);
+ return String8(buf);
+ }
+ String8 convertToString(void const* v) const {
+ char buf[16];
+ snprintf(buf, 16, "%p", v);
+ return String8(buf);
+ }
+};
+
+class GLLogEnum : public GLLogValue<GLenum> {
+public:
+ GLLogEnum(GLenum v) : GLLogValue<GLenum>(v) { }
+ String8 toString() const {
+ GLenum v = getValue();
+ int i = binarySearch<pair_t>(gEnumMap, 0, NELEM(gEnumMap)-1, v);
+ if (i >= 0) {
+ return String8(gEnumMap[i].name);
+ } else {
+ char buf[16];
+ snprintf(buf, 16, "0x%04x", v);
+ return String8(buf);
+ }
+ }
+};
+
+class GLLogClearBitfield : public GLLogValue<GLbitfield> {
+public:
+ GLLogClearBitfield(GLbitfield v) : GLLogValue<GLbitfield>(v) { }
+ String8 toString() const {
+ char buf[16];
+ snprintf(buf, 16, "0x%08x", getValue());
+ return String8(buf);
+ }
+};
+
+class GLLogBool : public GLLogValue<GLboolean> {
+public:
+ GLLogBool(GLboolean v) : GLLogValue<GLboolean>(v) { }
+ String8 toString() const {
+ GLboolean v = getValue();
+ if (v == GL_TRUE) return String8("GL_TRUE");
+ if (v == GL_FALSE) return String8("GL_FALSE");
+ return GLLogValue<GLboolean>::toString();
+ }
+};
+
+class GLLogFixed : public GLLogValue<GLfixed> {
+public:
+ GLLogFixed(GLfixed v) : GLLogValue<GLfixed>(v) { }
+ String8 toString() const {
+ char buf[16];
+ snprintf(buf, 16, "0x%08x", getValue());
+ return String8(buf);
+ }
+};
+
+
+template <typename TYPE>
+class GLLogBuffer : public GLLogValue<TYPE *> {
+public:
+ GLLogBuffer(TYPE* buffer, size_t count = -1)
+ : GLLogValue<TYPE*>(buffer)
+ { // output buffer
+ }
+ GLLogBuffer(TYPE const* buffer, size_t count = -1)
+ : GLLogValue<TYPE*>(const_cast<TYPE*>(buffer))
+ { // input buffer
+ }
+};
+
+class GLLog
+{
+public:
+ GLLog(const char* name) : mNumParams(0) {
+ mString.append(name);
+ mString.append("(");
+ }
+
+ ~GLLog() {
+ LOGD("%s);", mString.string());
+ }
+
+ GLLog& operator << (unsigned char v) {
+ return *this << GLLogValue<unsigned int>(v);
+ }
+ GLLog& operator << (short v) {
+ return *this << GLLogValue<unsigned int>(v);
+ }
+ GLLog& operator << (unsigned int v) {
+ return *this << GLLogValue<unsigned int>(v);
+ }
+ GLLog& operator << (int v) {
+ return *this << GLLogValue<int>(v);
+ }
+ GLLog& operator << (long v) {
+ return *this << GLLogValue<long>(v);
+ }
+ GLLog& operator << (unsigned long v) {
+ return *this << GLLogValue<unsigned long>(v);
+ }
+ GLLog& operator << (float v) {
+ return *this << GLLogValue<float>(v);
+ }
+ GLLog& operator << (const void* v) {
+ return *this << GLLogValue<const void* >(v);
+ }
+
+ template <typename TYPE>
+ GLLog& operator << (const TYPE& rhs) {
+ if (mNumParams > 0)
+ mString.append(", ");
+ mString.append(rhs.toString());
+ mNumParams++;
+ return *this;
+ }
+
+ const String8& string() const { return mString; }
+private:
+ GLLog(const GLLog&);
+
+ String8 mString;
+ int mNumParams;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+#define API_ENTRY(api) log_##api
+#define CALL_GL_API(_x, ...)
+#define CALL_GL_API_RETURN(_x, ...) return(0);
+
+void API_ENTRY(glActiveTexture)(GLenum texture) {
+ CALL_GL_API(glActiveTexture, texture);
+ GLLog("glActiveTexture") << GLLogEnum(texture);
+}
+
+void API_ENTRY(glAlphaFunc)(GLenum func, GLclampf ref) {
+ CALL_GL_API(glAlphaFunc, func, ref);
+ GLLog("glAlphaFunc") << GLLogEnum(func) << ref;
+}
+
+void API_ENTRY(glAlphaFuncx)(GLenum func, GLclampx ref) {
+ CALL_GL_API(glAlphaFuncx, func, ref);
+ GLLog("glAlphaFuncx") << GLLogEnum(func) << GLLogFixed(ref);
+}
+
+void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
+ CALL_GL_API(glBindTexture, target, texture);
+ GLLog("glBindTexture") << GLLogEnum(target) << texture;
+}
+
+void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
+ CALL_GL_API(glBlendFunc, sfactor, dfactor);
+ GLLog("glBlendFunc") << GLLogEnum(sfactor) << GLLogEnum(dfactor);
+}
+
+void API_ENTRY(glClear)(GLbitfield mask) {
+ CALL_GL_API(glClear, mask);
+ GLLog("glClear") << GLLogClearBitfield(mask);
+}
+
+void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ CALL_GL_API(glClearColor, red, green, blue, alpha);
+ GLLog("glClearColor") << red << green << blue << alpha;
+}
+
+void API_ENTRY(glClearColorx)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
+ CALL_GL_API(glClearColorx, red, green, blue, alpha);
+ GLLog("glClearColorx") << GLLogFixed(red) << GLLogFixed(green) << GLLogFixed(blue) << GLLogFixed(alpha);
+}
+
+void API_ENTRY(glClearDepthf)(GLclampf depth) {
+ CALL_GL_API(glClearDepthf, depth);
+ GLLog("glClearDepthf") << depth;
+}
+
+void API_ENTRY(glClearDepthx)(GLclampx depth) {
+ CALL_GL_API(glClearDepthx, depth);
+ GLLog("glClearDepthx") << GLLogFixed(depth);
+}
+
+void API_ENTRY(glClearStencil)(GLint s) {
+ CALL_GL_API(glClearStencil, s);
+ GLLog("glClearStencil") << s;
+}
+
+void API_ENTRY(glClientActiveTexture)(GLenum texture) {
+ CALL_GL_API(glClientActiveTexture, texture);
+ GLLog("glClientActiveTexture") << GLLogEnum(texture);
+}
+
+void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
+ CALL_GL_API(glColor4f, red, green, blue, alpha);
+ GLLog("glColor4f") << red << green << blue << alpha;
+}
+
+void API_ENTRY(glColor4x)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) {
+ CALL_GL_API(glColor4x, red, green, blue, alpha);
+ GLLog("glColor4x") << GLLogFixed(red) << GLLogFixed(green) << GLLogFixed(blue) << GLLogFixed(alpha);
+}
+
+void API_ENTRY(glColorMask)(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
+ CALL_GL_API(glColorMask, r, g, b, a);
+ GLLog("glColorMask") << GLLogBool(r) << GLLogBool(g) << GLLogBool(b) << GLLogBool(a);
+}
+
+void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
+{
+ CALL_GL_API(glColorPointer, size, type, stride, ptr);
+ GLLog("glColorPointer") << size << GLLogEnum(type) << stride << ptr;
+}
+
+void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLsizei imageSize, const GLvoid *data) {
+ CALL_GL_API(glCompressedTexImage2D, target, level, internalformat,
+ width, height, border, imageSize, data);
+ GLLog("glCompressedTexImage2D")
+ << GLLogEnum(target) << level << GLLogEnum(internalformat)
+ << width << height << border << imageSize << data;
+}
+
+void API_ENTRY(glCompressedTexSubImage2D)( GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize,
+ const GLvoid *data) {
+ CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset,
+ width, height, format, imageSize, data);
+ GLLog("glCompressedTexSubImage2D")
+ << GLLogEnum(target) << level << xoffset << yoffset
+ << width << height << GLLogEnum(format) << imageSize << data;
+}
+
+void API_ENTRY(glCopyTexImage2D)( GLenum target, GLint level, GLenum internalformat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border) {
+ CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y,
+ width, height, border);
+ GLLog("glCopyTexImage2D")
+ << GLLogEnum(target) << level << GLLogEnum(internalformat)
+ << x << y << width << height << border;
+}
+
+void API_ENTRY(glCopyTexSubImage2D)( GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLint x, GLint y, GLsizei width,
+ GLsizei height) {
+ CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y,
+ width, height);
+ GLLog("glCopyTexSubImage2D")
+ << GLLogEnum(target) << level << xoffset << yoffset
+ << x << y << width << height;
+}
+
+void API_ENTRY(glCullFace)(GLenum mode) {
+ CALL_GL_API(glCullFace, mode);
+ GLLog("glCullFace") << GLLogEnum(mode);
+}
+
+void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) {
+ CALL_GL_API(glDeleteTextures, n, textures);
+ GLLog("glDeleteTextures") << n << GLLogBuffer<GLuint>(textures, n);
+}
+
+void API_ENTRY(glDepthFunc)(GLenum func) {
+ CALL_GL_API(glDepthFunc, func);
+ GLLog("glDepthFunc") << GLLogEnum(func);
+}
+
+void API_ENTRY(glDepthMask)(GLboolean flag) {
+ CALL_GL_API(glDepthMask, flag);
+ GLLog("glDepthMask") << GLLogBool(flag);
+}
+
+void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
+ CALL_GL_API(glDepthRangef, zNear, zFar);
+ GLLog("glDepthRangef") << zNear << zFar;
+}
+
+void API_ENTRY(glDepthRangex)(GLclampx zNear, GLclampx zFar) {
+ CALL_GL_API(glDepthRangex, zNear, zFar);
+ GLLog("glDepthRangex") << GLLogFixed(zNear) << GLLogFixed(zFar);
+}
+
+void API_ENTRY(glDisable)(GLenum cap) {
+ CALL_GL_API(glDisable, cap);
+ GLLog("glDisable") << GLLogEnum(cap);
+}
+
+void API_ENTRY(glDisableClientState)(GLenum array) {
+ CALL_GL_API(glDisableClientState, array);
+ GLLog("glDisableClientState") << GLLogEnum(array);
+}
+
+void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
+ CALL_GL_API(glDrawArrays, mode, first, count);
+ GLLog("glDrawArrays") << GLLogEnum(mode) << first << count;
+}
+
+void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count,
+ GLenum type, const GLvoid *indices) {
+ CALL_GL_API(glDrawElements, mode, count, type, indices);
+ GLLog log("glDrawElements");
+ log << GLLogEnum(mode) << count << GLLogEnum(type);
+ if (type == GL_UNSIGNED_BYTE) {
+ log << GLLogBuffer<GLubyte>(static_cast<const GLubyte*>(indices), count);
+ } else {
+ log << GLLogBuffer<GLushort>(static_cast<const GLushort*>(indices), count);
+ }
+ log;
+}
+
+void API_ENTRY(glEnable)(GLenum cap) {
+ CALL_GL_API(glEnable, cap);
+ GLLog("glEnable") << GLLogEnum(cap);
+}
+
+void API_ENTRY(glEnableClientState)(GLenum array) {
+ CALL_GL_API(glEnableClientState, array);
+ GLLog("glEnableClientState") << GLLogEnum(array);
+}
+
+void API_ENTRY(glFinish)(void) {
+ CALL_GL_API(glFinish);
+ GLLog("glFinish");
+}
+
+void API_ENTRY(glFlush)(void) {
+ CALL_GL_API(glFlush);
+ GLLog("glFlush");
+}
+
+void API_ENTRY(glFogf)(GLenum pname, GLfloat param) {
+ CALL_GL_API(glFogf, pname, param);
+ GLLog("glFogf") << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glFogfv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glFogfv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glFogx)(GLenum pname, GLfixed param) {
+ CALL_GL_API(glFogx, pname, param);
+ GLLog("glFogx") << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glFogxv)(GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glFogxv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glFogfx") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+
+void API_ENTRY(glFrontFace)(GLenum mode) {
+ CALL_GL_API(glFrontFace, mode);
+ GLLog("glFrontFace") << GLLogEnum(mode);
+ }
+
+void API_ENTRY(glFrustumf)(GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar) {
+ CALL_GL_API(glFrustumf, left, right, bottom, top, zNear, zFar);
+ GLLog("glFrustumf") << left << right << bottom << top << zNear << zFar;
+}
+
+void API_ENTRY(glFrustumx)(GLfixed left, GLfixed right,
+ GLfixed bottom, GLfixed top,
+ GLfixed zNear, GLfixed zFar) {
+ CALL_GL_API(glFrustumx, left, right, bottom, top, zNear, zFar);
+ GLLog("glFrustumx")
+ << GLLogFixed(left) << GLLogFixed(right)
+ << GLLogFixed(bottom) << GLLogFixed(top)
+ << GLLogFixed(zNear) << GLLogFixed(zFar);
+}
+
+void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) {
+ CALL_GL_API(glGenTextures, n, textures);
+ GLLog("glGenTextures") << n << GLLogBuffer<GLuint>(textures, n);
+}
+
+GLenum API_ENTRY(glGetError)(void) {
+ GLLog("glGetError");
+ CALL_GL_API_RETURN(glGetError);
+}
+
+void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *params) {
+ CALL_GL_API(glGetIntegerv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetIntegerv") << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+
+const GLubyte * API_ENTRY(glGetString)(GLenum name) {
+ GLLog("glGetString") << GLLogEnum(name);
+ CALL_GL_API_RETURN(glGetString, name);
+}
+
+void API_ENTRY(glHint)(GLenum target, GLenum mode) {
+ CALL_GL_API(glHint, target, mode);
+ GLLog("GLenum") << GLLogEnum(target) << GLLogEnum(mode);
+}
+
+void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) {
+ CALL_GL_API(glLightModelf, pname, param);
+ GLLog("glLightModelf") << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glLightModelfv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glLightModelfv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glLightModelx)(GLenum pname, GLfixed param) {
+ CALL_GL_API(glLightModelx, pname, param);
+ GLLog("glLightModelx") << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glLightModelxv)(GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glLightModelxv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glLightModelxv") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+
+void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) {
+ CALL_GL_API(glLightf, light, pname, param);
+ GLLog("glLightf") << GLLogEnum(light) << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glLightfv, light, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glLightfv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glLightx)(GLenum light, GLenum pname, GLfixed param) {
+ CALL_GL_API(glLightx, light, pname, param);
+ GLLog("glLightx") << GLLogEnum(light) << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glLightxv)(GLenum light, GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glLightxv, light, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glLightxv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+
+void API_ENTRY(glLineWidth)(GLfloat width) {
+ CALL_GL_API(glLineWidth, width);
+ GLLog("glLineWidth") << width;
+}
+
+void API_ENTRY(glLineWidthx)(GLfixed width) {
+ CALL_GL_API(glLineWidthx, width);
+ GLLog("glLineWidth") << GLLogFixed(width);
+}
+
+void API_ENTRY(glLoadIdentity)(void) {
+ CALL_GL_API(glLoadIdentity);
+ GLLog("glLoadIdentity");
+}
+
+void API_ENTRY(glLoadMatrixf)(const GLfloat *m) {
+ CALL_GL_API(glLoadMatrixf, m);
+ GLLog("glLoadMatrixf") << GLLogBuffer<GLfloat>(m, 16);
+}
+
+void API_ENTRY(glLoadMatrixx)(const GLfixed *m) {
+ CALL_GL_API(glLoadMatrixx, m);
+ GLLog("glLoadMatrixx") << GLLogBuffer<GLfixed>(m, 16);
+}
+
+void API_ENTRY(glLogicOp)(GLenum opcode) {
+ CALL_GL_API(glLogicOp, opcode);
+ GLLog("glLogicOp") << GLLogEnum(opcode);
+}
+
+void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) {
+ CALL_GL_API(glMaterialf, face, pname, param);
+ GLLog("glMaterialf") << GLLogEnum(face) << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glMaterialfv, face, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glMaterialfv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glMaterialx)(GLenum face, GLenum pname, GLfixed param) {
+ CALL_GL_API(glMaterialx, face, pname, param);
+ GLLog("glMaterialx") << GLLogEnum(face) << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glMaterialxv)(GLenum face, GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glMaterialxv, face, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glMaterialxv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+
+void API_ENTRY(glMatrixMode)(GLenum mode) {
+ CALL_GL_API(glMatrixMode, mode);
+ GLLog("glMatrixMode") << GLLogEnum(mode);
+}
+
+void API_ENTRY(glMultMatrixf)(const GLfloat *m) {
+ CALL_GL_API(glMultMatrixf, m);
+ GLLog("glMultMatrixf") << GLLogBuffer<GLfloat>(m, 16);
+}
+
+void API_ENTRY(glMultMatrixx)(const GLfixed *m) {
+ CALL_GL_API(glMultMatrixx, m);
+ GLLog("glMultMatrixx") << GLLogBuffer<GLfixed>(m, 16);
+}
+
+void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) {
+ CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q);
+ GLLog("glMultiTexCoord4f") << GLLogEnum(target) << s << t << r << q;
+}
+
+void API_ENTRY(glMultiTexCoord4x)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) {
+ CALL_GL_API(glMultiTexCoord4x, target, s, t, r, q);
+ GLLog("glMultiTexCoord4x") << GLLogEnum(target)
+ << GLLogFixed(s) << GLLogFixed(t) << GLLogFixed(r) << GLLogFixed(q);
+}
+
+void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) {
+ CALL_GL_API(glNormal3f, nx, ny, nz);
+ GLLog("glNormal3f") << nx << ny << nz;
+}
+
+void API_ENTRY(glNormal3x)(GLfixed nx, GLfixed ny, GLfixed nz) {
+ CALL_GL_API(glNormal3x, nx, ny, nz);
+ GLLog("glNormal3x") << GLLogFixed(nx) << GLLogFixed(ny) << GLLogFixed(nz);
+}
+
+void API_ENTRY(glNormalPointer)(GLenum type, GLsizei stride, const GLvoid *pointer) {
+ CALL_GL_API(glNormalPointer, type, stride, pointer);
+ GLLog("glNormalPointer") << GLLogEnum(type) << stride << pointer;
+}
+
+void API_ENTRY(glOrthof)( GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar) {
+ CALL_GL_API(glOrthof, left, right, bottom, top, zNear, zFar);
+ GLLog("glOrthof") << left << right << bottom << top << zNear << zFar;
+}
+
+void API_ENTRY(glOrthox)( GLfixed left, GLfixed right,
+ GLfixed bottom, GLfixed top,
+ GLfixed zNear, GLfixed zFar) {
+ CALL_GL_API(glOrthox, left, right, bottom, top, zNear, zFar);
+ GLLog("glOrthox") << GLLogFixed(left) << GLLogFixed(right)
+ << GLLogFixed(bottom) << GLLogFixed(top)
+ << GLLogFixed(zNear) << GLLogFixed(zFar);
+}
+
+void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
+ CALL_GL_API(glPixelStorei, pname, param);
+ GLLog("glPixelStorei") << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glPointSize)(GLfloat size) {
+ CALL_GL_API(glPointSize, size);
+ GLLog("glPointSize") << size;
+}
+
+void API_ENTRY(glPointSizex)(GLfixed size) {
+ CALL_GL_API(glPointSizex, size);
+ GLLog("glPointSizex") << GLLogFixed(size);
+}
+
+void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
+ CALL_GL_API(glPolygonOffset, factor, units);
+ GLLog("glPolygonOffset") << factor << units;
+}
+
+void API_ENTRY(glPolygonOffsetx)(GLfixed factor, GLfixed units) {
+ CALL_GL_API(glPolygonOffsetx, factor, units);
+ GLLog("glPolygonOffsetx") << GLLogFixed(factor) << GLLogFixed(units);
+}
+
+void API_ENTRY(glPopMatrix)(void) {
+ CALL_GL_API(glPopMatrix);
+ GLLog("glPopMatrix");
+}
+
+void API_ENTRY(glPushMatrix)(void) {
+ CALL_GL_API(glPushMatrix);
+ GLLog("glPushMatrix");
+}
+
+void API_ENTRY(glReadPixels)( GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid *pixels) {
+ CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glReadPixels") << x << y << width << height << GLLogEnum(format) << GLLogEnum(type)
+ << GLLogBuffer<unsigned char>(static_cast<unsigned char *>(pixels));
+}
+
+void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glRotatef, angle, x, y, z);
+ GLLog("glRotatef") << angle << x << y << z;
+}
+
+void API_ENTRY(glRotatex)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) {
+ CALL_GL_API(glRotatex, angle, x, y, z);
+ GLLog("glRotatex") << GLLogFixed(angle) << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z);
+}
+
+void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
+ CALL_GL_API(glSampleCoverage, value, invert);
+ GLLog("glSampleCoverage") << value << GLLogBool(invert);
+}
+
+void API_ENTRY(glSampleCoveragex)(GLclampx value, GLboolean invert) {
+ CALL_GL_API(glSampleCoveragex, value, invert);
+ GLLog("glSampleCoveragex") << GLLogFixed(value) << GLLogBool(invert);
+}
+
+void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glScalef, x, y, z);
+ GLLog("glScalef") << x << y << z;
+}
+
+void API_ENTRY(glScalex)(GLfixed x, GLfixed y, GLfixed z) {
+ CALL_GL_API(glScalex, x, y, z);
+ GLLog("glScalex") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z);
+}
+
+void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glScissor, x, y, width, height);
+ GLLog("glScissor") << x << y << width << height;
+}
+
+void API_ENTRY(glShadeModel)(GLenum mode) {
+ CALL_GL_API(glShadeModel, mode);
+ GLLog("glShadeModel") << GLLogEnum(mode);
+}
+
+void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
+ CALL_GL_API(glStencilFunc, func, ref, mask);
+ GLLog("glStencilFunc") << GLLogEnum(func) << ref << mask;
+}
+
+void API_ENTRY(glStencilMask)(GLuint mask) {
+ CALL_GL_API(glStencilMask, mask);
+ GLLog("glStencilMask") << mask;
+}
+
+void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
+ CALL_GL_API(glStencilOp, fail, zfail, zpass);
+ GLLog("glStencilOp") << GLLogEnum(fail) << GLLogEnum(zfail) << GLLogEnum(zpass);
+}
+
+void API_ENTRY(glTexCoordPointer)( GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer) {
+ CALL_GL_API(glTexCoordPointer, size, type, stride, pointer);
+ GLLog("glTexCoordPointer") << size << GLLogEnum(type) << stride << pointer;
+}
+
+void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) {
+ CALL_GL_API(glTexEnvf, target, pname, param);
+ GLLog("glTexEnvf") << GLLogEnum(target) << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glTexEnvfv, target, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glTexEnvx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glTexEnvx)(GLenum target, GLenum pname, GLfixed param) {
+ CALL_GL_API(glTexEnvx, target, pname, param);
+ GLLog("glTexEnvx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glTexEnvxv, target, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glTexEnvxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+
+void API_ENTRY(glTexImage2D)( GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border, GLenum format,
+ GLenum type, const GLvoid *pixels) {
+ CALL_GL_API(glTexImage2D, target, level, internalformat, width, height,
+ border, format, type, pixels);
+ GLLog("glTexImage2D") << GLLogEnum(target) << level << GLLogEnum(internalformat)
+ << width << height << border << GLLogEnum(format) << GLLogEnum(type)
+ << GLLogBuffer<unsigned char>( static_cast<const unsigned char *>(pixels));
+}
+
+void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
+ CALL_GL_API(glTexParameterf, target, pname, param);
+ GLLog("glTexParameterf") << GLLogEnum(target) << GLLogEnum(pname) << param;
+}
+
+void API_ENTRY(glTexParameterx)(GLenum target, GLenum pname, GLfixed param) {
+ CALL_GL_API(glTexParameterx, target, pname, param);
+ GLLog("glTexParameterx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogFixed(param);
+}
+
+void API_ENTRY(glTexSubImage2D)( GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid *pixels) {
+ CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset,
+ width, height, format, type, pixels);
+ GLLog("glTexSubImage2D") << GLLogEnum(target) << level << xoffset << yoffset
+ << width << height << GLLogEnum(format) << GLLogEnum(type)
+ << GLLogBuffer<unsigned char>( static_cast<const unsigned char *>(pixels));
+}
+
+void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glTranslatef, x, y, z);
+ GLLog("glTranslatef") << x << y << z;
+}
+
+void API_ENTRY(glTranslatex)(GLfixed x, GLfixed y, GLfixed z) {
+ CALL_GL_API(glTranslatex, x, y, z);
+ GLLog("glTranslatex") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z);
+}
+
+void API_ENTRY(glVertexPointer)( GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer) {
+ CALL_GL_API(glVertexPointer, size, type, stride, pointer);
+ GLLog("glVertexPointer") << size << GLLogEnum(type) << stride << pointer;
+}
+
+void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glViewport, x, y, width, height);
+ GLLog("glViewport") << x << y << width << height;
+}
+
+// ES 1.1
+void API_ENTRY(glClipPlanef)(GLenum plane, const GLfloat *equation) {
+ CALL_GL_API(glClipPlanef, plane, equation);
+ GLLog("glClipPlanef") << GLLogEnum(plane) << GLLogBuffer<GLfloat>(equation, 4);
+}
+void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) {
+ CALL_GL_API(glClipPlanex, plane, equation);
+ GLLog("glClipPlanex") << GLLogEnum(plane) << GLLogBuffer<GLfixed>(equation, 4);
+}
+void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
+ CALL_GL_API(glBindBuffer, target, buffer);
+ GLLog("glBindBuffer") << GLLogEnum(target) << buffer;
+}
+void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) {
+ CALL_GL_API(glBufferData, target, size, data, usage);
+ GLLog("glBufferData") << GLLogEnum(target) << size
+ << GLLogBuffer<unsigned char>(static_cast<const unsigned char*>(data), size);
+}
+void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) {
+ CALL_GL_API(glBufferSubData, target, offset, size, data);
+ GLLog("glBufferSubData") << GLLogEnum(target) << offset << size
+ << GLLogBuffer<unsigned char>(static_cast<const unsigned char*>(data), size);
+}
+void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) {
+ CALL_GL_API(glDeleteBuffers, n, buffers);
+ GLLog("glDeleteBuffers") << n << GLLogBuffer<GLuint>(buffers, n);
+}
+void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) {
+ CALL_GL_API(glGenBuffers, n, buffers);
+ GLLog("glGenBuffers") << n << GLLogBuffer<GLuint>(buffers, n);
+}
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *params) {
+ CALL_GL_API(glGetBooleanv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetBooleanv") << GLLogEnum(pname) << GLLogBuffer<GLboolean>(params);
+}
+void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) {
+ CALL_GL_API(glGetFixedv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetFixedv") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *params) {
+ CALL_GL_API(glGetFloatv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetFloatv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glGetPointerv)(GLenum pname, void **params) {
+ CALL_GL_API(glGetPointerv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetPointerv") << GLLogEnum(pname) << GLLogBuffer<void*>(params);
+}
+void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) {
+ // XXX: we need to compute the size of this buffer
+ CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+ GLLog("glGetBufferParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+void API_ENTRY(glGetClipPlanef)(GLenum pname, GLfloat eqn[4]) {
+ CALL_GL_API(glGetClipPlanef, pname, eqn);
+ GLLog("glGetClipPlanef") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(eqn, 4);
+}
+void API_ENTRY(glGetClipPlanex)(GLenum pname, GLfixed eqn[4]) {
+ CALL_GL_API(glGetClipPlanex, pname, eqn);
+ GLLog("glGetClipPlanex") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(eqn, 4);
+}
+void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) {
+ CALL_GL_API(glGetLightxv, light, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetLightxv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glGetLightfv)(GLenum light, GLenum pname, GLfloat *params) {
+ CALL_GL_API(glGetLightfv, light, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetLightfv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) {
+ CALL_GL_API(glGetMaterialxv, face, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetMaterialxv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glGetMaterialfv)(GLenum face, GLenum pname, GLfloat *params) {
+ CALL_GL_API(glGetMaterialfv, face, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetMaterialfv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glGetTexEnvfv)(GLenum env, GLenum pname, GLfloat *params) {
+ CALL_GL_API(glGetTexEnvfv, env, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetTexEnvfv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) {
+ CALL_GL_API(glGetTexEnviv, env, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetTexEnviv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+void API_ENTRY(glGetTexEnvxv)(GLenum env, GLenum pname, GLfixed *params) {
+ CALL_GL_API(glGetTexEnvxv, env, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetTexEnvxv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) {
+ CALL_GL_API(glGetTexParameterfv, target, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetTexParameterfv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) {
+ CALL_GL_API(glGetTexParameteriv, target, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetTexParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+void API_ENTRY(glGetTexParameterxv)(GLenum target, GLenum pname, GLfixed *params) {
+ CALL_GL_API(glGetTexParameterxv, target, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glGetTexParameterxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
+ GLLog("glIsBuffer") << buffer;
+ CALL_GL_API_RETURN(glIsBuffer, buffer);
+}
+GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
+ GLLog("glIsEnabled") << GLLogEnum(cap);
+ CALL_GL_API_RETURN(glIsEnabled, cap);
+}
+GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
+ GLLog("glIsTexture") << texture;
+ CALL_GL_API_RETURN(glIsTexture, texture);
+}
+void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) {
+ CALL_GL_API(glPointParameterf, pname, param);
+ GLLog("glPointParameterf") << GLLogEnum(pname) << param;
+}
+void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glPointParameterfv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glPointParameterfv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) {
+ CALL_GL_API(glPointParameterx, pname, param);
+ GLLog("glPointParameterx") << GLLogEnum(pname) << GLLogFixed(param);
+}
+void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glPointParameterxv, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glPointParameterxv") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) {
+ CALL_GL_API(glColor4ub, red, green, blue, alpha);
+ GLLog("glColor4ub") << red << green << blue << alpha;
+}
+void API_ENTRY(glTexEnvi)(GLenum target, GLenum pname, GLint param) {
+ CALL_GL_API(glTexEnvi, target, pname, param);
+ GLLog("glTexEnvi") << GLLogEnum(target) << GLLogEnum(pname) << param;
+}
+void API_ENTRY(glTexEnviv)(GLenum target, GLenum pname, const GLint *params) {
+ CALL_GL_API(glTexEnviv, target, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glTexEnviv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+
+void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) {
+ CALL_GL_API(glTexParameterfv, target, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glTexParameterfv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
+}
+
+void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) {
+ CALL_GL_API(glTexParameteriv, target, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glTexParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
+}
+
+void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
+ CALL_GL_API(glTexParameteri, target, pname, param);
+ GLLog("glTexParameteri") << GLLogEnum(target) << GLLogEnum(pname) << param;
+}
+void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) {
+ CALL_GL_API(glTexParameterxv, target, pname, params);
+ // XXX: we need to compute the size of this buffer
+ GLLog("glTexParameterxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
+}
+void API_ENTRY(glPointSizePointerOES)(GLenum type, GLsizei stride, const GLvoid *pointer) {
+ CALL_GL_API(glPointSizePointerOES, type, stride, pointer);
+ GLLog("glPointSizePointerOES") << GLLogEnum(type) << stride << pointer;
+}
+
+// Extensions
+void API_ENTRY(glDrawTexsOES)(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
+ CALL_GL_API(glDrawTexsOES, x, y, z, w, h);
+ GLLog("glDrawTexsOES") << x << y << z << w << h;
+}
+void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint w, GLint h) {
+ CALL_GL_API(glDrawTexiOES, x, y, z, w, h);
+ GLLog("glDrawTexiOES") << x << y << z << w << h;
+}
+void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h) {
+ CALL_GL_API(glDrawTexfOES, x, y, z, w, h);
+ GLLog("glDrawTexfOES") << x << y << z << w << h;
+}
+void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
+ CALL_GL_API(glDrawTexxOES, x, y, z, w, h);
+ GLLog("glDrawTexfOES") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z) << GLLogFixed(w) << GLLogFixed(h);
+}
+void API_ENTRY(glDrawTexsvOES)(const GLshort* coords) {
+ CALL_GL_API(glDrawTexsvOES, coords);
+ GLLog("glDrawTexsvOES") << GLLogBuffer<GLshort>(coords, 5);
+}
+void API_ENTRY(glDrawTexivOES)(const GLint* coords) {
+ CALL_GL_API(glDrawTexivOES, coords);
+ GLLog("glDrawTexivOES") << GLLogBuffer<GLint>(coords, 5);
+}
+void API_ENTRY(glDrawTexfvOES)(const GLfloat* coords) {
+ CALL_GL_API(glDrawTexfvOES, coords);
+ GLLog("glDrawTexfvOES") << GLLogBuffer<GLfloat>(coords, 5);
+}
+void API_ENTRY(glDrawTexxvOES)(const GLfixed* coords) {
+ CALL_GL_API(glDrawTexxvOES, coords);
+ GLLog("glDrawTexxvOES") << GLLogBuffer<GLfixed>(coords, 5);
+}
+GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed* mantissa, GLint* exponent) {
+ GLLog("glQueryMatrixxOES") << GLLogBuffer<GLfixed>(mantissa, 16) << GLLogBuffer<GLfixed>(exponent, 16);
+ CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent);
+}
diff --git a/opengl/libGLES_CM/gl_logger.h b/opengl/libGLES_CM/gl_logger.h
new file mode 100644
index 0000000..59e31c7
--- /dev/null
+++ b/opengl/libGLES_CM/gl_logger.h
@@ -0,0 +1,26 @@
+/*
+ ** 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.
+ */
+
+#ifndef ANDROID_GL_LOGGER_H
+#define ANDROID_GL_LOGGER_H
+
+extern "C" {
+#define GL_ENTRY(r, api, ...) r log_##api(__VA_ARGS__);
+#include "gl_entries.cpp"
+#undef GL_ENTRY
+};
+
+#endif /* ANDROID_GL_LOGGER_H */
diff --git a/opengl/libGLES_CM/gl_wrapper.cpp b/opengl/libGLES_CM/gl_wrapper.cpp
new file mode 100644
index 0000000..5da4f9a
--- /dev/null
+++ b/opengl/libGLES_CM/gl_wrapper.cpp
@@ -0,0 +1,1663 @@
+/*
+ ** 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.
+ */
+
+#define LOG_TAG "GLLogger"
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+
+#include <sys/ioctl.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+#include <GLES/egl.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <cutils/properties.h>
+#include <cutils/memory.h>
+
+#include <utils/IMemory.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Parcel.h>
+
+#include <ui/EGLDisplaySurface.h>
+#include <ui/ISurfaceComposer.h>
+
+#include "gl_logger.h"
+
+#undef NELEM
+
+#define GL_LOGGER 0
+#define USE_SLOW_BINDING 0
+#define NELEM(x) (sizeof(x)/sizeof(*(x)))
+#define MAX_NUMBER_OF_GL_EXTENSIONS 32
+#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
+#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+// EGLDisplay are global, not attached to a given thread
+static const unsigned int NUM_DISPLAYS = 1;
+static const unsigned int IMPL_HARDWARE = 0;
+static const unsigned int IMPL_SOFTWARE = 1;
+static const unsigned int IMPL_HARDWARE_CONTEXT_LOST = 2;
+static const unsigned int IMPL_SOFTWARE_CONTEXT_LOST = 3;
+static const unsigned int IMPL_NO_CONTEXT = 4;
+
+// ----------------------------------------------------------------------------
+
+struct gl_hooks_t;
+
+struct egl_connection_t
+{
+ void volatile * dso;
+ gl_hooks_t * hooks;
+ EGLint major;
+ EGLint minor;
+ int unavailable;
+};
+
+template <int MAGIC>
+struct egl_object_t
+{
+ egl_object_t() : magic(MAGIC) { }
+ ~egl_object_t() { magic = 0; }
+ bool isValid() const { return magic == MAGIC; }
+private:
+ uint32_t magic;
+};
+
+struct egl_display_t : public egl_object_t<'_dpy'>
+{
+ EGLDisplay dpys[2];
+ EGLConfig* configs[2];
+ EGLint numConfigs[2];
+ EGLint numTotalConfigs;
+ char const* extensionsString;
+ volatile int32_t refs;
+ struct strings_t {
+ char const * vendor;
+ char const * version;
+ char const * clientApi;
+ char const * extensions;
+ char const * extensions_config;
+ };
+ strings_t queryString[2];
+};
+
+struct egl_surface_t : public egl_object_t<'_srf'>
+{
+ egl_surface_t(EGLDisplay dpy, EGLSurface surface,
+ NativeWindowType window, int impl, egl_connection_t const* cnx)
+ : dpy(dpy), surface(surface), window(window), impl(impl), cnx(cnx)
+ {
+ // NOTE: window must be incRef'ed and connected already
+ }
+ ~egl_surface_t() {
+ if (window) {
+ if (window->disconnect)
+ window->disconnect(window);
+ window->decRef(window);
+ }
+ }
+ EGLDisplay dpy;
+ EGLSurface surface;
+ NativeWindowType window;
+ int impl;
+ egl_connection_t const* cnx;
+};
+
+struct egl_context_t : public egl_object_t<'_ctx'>
+{
+ egl_context_t(EGLDisplay dpy, EGLContext context,
+ int impl, egl_connection_t const* cnx)
+ : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
+ {
+ }
+ EGLDisplay dpy;
+ EGLContext context;
+ EGLSurface read;
+ EGLSurface draw;
+ int impl;
+ egl_connection_t const* cnx;
+};
+
+struct tls_t
+{
+ tls_t() : error(EGL_SUCCESS), ctx(0) { }
+ EGLint error;
+ EGLContext ctx;
+};
+
+
+// GL / EGL hooks
+
+typedef void(*proc_t)();
+
+struct gl_hooks_t {
+ struct gl_t {
+ #define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
+ #include "gl_entries.cpp"
+ #undef GL_ENTRY
+ } gl;
+ struct egl_t {
+ #define EGL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
+ #include "egl_entries.cpp"
+ #undef EGL_ENTRY
+ } egl;
+ struct gl_ext_t {
+ void (*extensions[MAX_NUMBER_OF_GL_EXTENSIONS])(void);
+ } ext;
+};
+
+static char const * const gl_names[] = {
+ #define GL_ENTRY(_r, _api, ...) #_api,
+ #include "gl_entries.cpp"
+ #undef GL_ENTRY
+ NULL
+};
+
+static char const * const egl_names[] = {
+ #define EGL_ENTRY(_r, _api, ...) #_api,
+ #include "egl_entries.cpp"
+ #undef EGL_ENTRY
+ NULL
+};
+
+static void gl_unimplemented() {
+ LOGE("called unimplemented OpenGL ES API");
+}
+
+// ----------------------------------------------------------------------------
+
+static egl_connection_t gEGLImpl[2];
+static egl_display_t gDisplay[NUM_DISPLAYS];
+static gl_hooks_t gHooks[5];
+static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_key_t gEGLThreadLocalStorageKey = -1;
+
+// ----------------------------------------------------------------------------
+
+#if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && !GL_LOGGER
+
+#include <sys/tls.h>
+// We have a dedicated TLS slot in bionic
+static inline void setGlThreadSpecific(gl_hooks_t const *value) {
+ ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL_API] = (uint32_t)value;
+}
+static gl_hooks_t const* getGlThreadSpecific() {
+ gl_hooks_t const* hooks = (gl_hooks_t const *)(((unsigned const *)__get_tls())[TLS_SLOT_OPENGL_API]);
+ if (hooks) return hooks;
+ return &gHooks[IMPL_NO_CONTEXT];
+}
+
+#else
+
+static pthread_key_t gGLWrapperKey = -1;
+static inline void setGlThreadSpecific(gl_hooks_t const *value) {
+ pthread_setspecific(gGLWrapperKey, value);
+}
+static gl_hooks_t const* getGlThreadSpecific() {
+ gl_hooks_t const* hooks = static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
+ if (hooks) return hooks;
+ return &gHooks[IMPL_NO_CONTEXT];
+}
+
+#endif
+
+static __attribute__((noinline))
+const char *egl_strerror(EGLint err)
+{
+ switch (err){
+ case EGL_SUCCESS: return "EGL_SUCCESS";
+ case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
+ case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
+ case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
+ case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
+ case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
+ case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
+ default: return "UNKNOWN";
+ }
+}
+
+static __attribute__((noinline))
+void clearTLS() {
+ if (gEGLThreadLocalStorageKey != -1) {
+ tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
+ if (tls) {
+ delete tls;
+ pthread_setspecific(gEGLThreadLocalStorageKey, 0);
+ }
+ }
+}
+
+static tls_t* getTLS()
+{
+ tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
+ if (tls == 0) {
+ tls = new tls_t;
+ pthread_setspecific(gEGLThreadLocalStorageKey, tls);
+ }
+ return tls;
+}
+
+template<typename T>
+static __attribute__((noinline))
+T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
+ if (gEGLThreadLocalStorageKey == -1) {
+ pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
+ if (gEGLThreadLocalStorageKey == -1)
+ pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
+ pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
+ }
+ tls_t* tls = getTLS();
+ if (tls->error != error) {
+ LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
+ tls->error = error;
+ }
+ return returnValue;
+}
+
+static __attribute__((noinline))
+GLint getError() {
+ if (gEGLThreadLocalStorageKey == -1)
+ return EGL_SUCCESS;
+ tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
+ if (!tls) return EGL_SUCCESS;
+ GLint error = tls->error;
+ tls->error = EGL_SUCCESS;
+ return error;
+}
+
+static __attribute__((noinline))
+void setContext(EGLContext ctx) {
+ if (gEGLThreadLocalStorageKey == -1) {
+ pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
+ if (gEGLThreadLocalStorageKey == -1)
+ pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
+ pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
+ }
+ tls_t* tls = getTLS();
+ tls->ctx = ctx;
+}
+
+static __attribute__((noinline))
+EGLContext getContext() {
+ if (gEGLThreadLocalStorageKey == -1)
+ return EGL_NO_CONTEXT;
+ tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
+ if (!tls) return EGL_NO_CONTEXT;
+ return tls->ctx;
+}
+
+/*****************************************************************************/
+
+/*
+ * we provide our own allocators for the GPU regions, these
+ * allocators go through surfaceflinger
+ */
+
+static Mutex gRegionsLock;
+static request_gpu_t gRegions;
+static sp<ISurfaceComposer> gSurfaceManager;
+ISurfaceComposer* GLES_localSurfaceManager = 0;
+
+const sp<ISurfaceComposer>& getSurfaceFlinger()
+{
+ Mutex::Autolock _l(gRegionsLock);
+
+ /*
+ * There is a little bit of voodoo magic here. We want to access
+ * surfaceflinger for allocating GPU regions, however, when we are
+ * running as part of surfaceflinger, we want to bypass the
+ * service manager because surfaceflinger might not be registered yet.
+ * SurfaceFlinger will populate "GLES_localSurfaceManager" with its
+ * own address, so we can just use that.
+ */
+ if (gSurfaceManager == 0) {
+ if (GLES_localSurfaceManager) {
+ // we're running in SurfaceFlinger's context
+ gSurfaceManager = GLES_localSurfaceManager;
+ } else {
+ // we're a remote process or not part of surfaceflinger,
+ // go through the service manager
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm != NULL) {
+ sp<IBinder> binder = sm->getService(String16("SurfaceFlinger"));
+ gSurfaceManager = interface_cast<ISurfaceComposer>(binder);
+ }
+ }
+ }
+ return gSurfaceManager;
+}
+
+class GPURevokeRequester : public BnGPUCallback
+{
+public:
+ virtual void gpuLost() {
+ LOGD("CONTEXT_LOST: Releasing GPU upon request from SurfaceFlinger.");
+ gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_HARDWARE_CONTEXT_LOST];
+ }
+};
+
+static sp<GPURevokeRequester> gRevokerCallback;
+
+static request_gpu_t* gpu_acquire(void* user)
+{
+ sp<ISurfaceComposer> server( getSurfaceFlinger() );
+
+ Mutex::Autolock _l(gRegionsLock);
+ if (server == NULL) {
+ return 0;
+ }
+
+ ISurfaceComposer::gpu_info_t info;
+ gRevokerCallback = new GPURevokeRequester();
+ status_t err = server->requestGPU(gRevokerCallback, &info);
+ if (err != NO_ERROR) {
+ LOGD("requestGPU returned %d", err);
+ return 0;
+ }
+
+ bool failed = false;
+ request_gpu_t* gpu = &gRegions;
+ memset(gpu, 0, sizeof(*gpu));
+
+ if (info.regs != 0) {
+ sp<IMemoryHeap> heap(info.regs->getMemory());
+ if (heap != 0) {
+ int fd = heap->heapID();
+ gpu->regs.fd = fd;
+ gpu->regs.base = info.regs->pointer();
+ gpu->regs.size = info.regs->size();
+ gpu->regs.user = info.regs.get();
+#if HAVE_ANDROID_OS
+ struct pmem_region region;
+ if (ioctl(fd, PMEM_GET_PHYS, &region) >= 0)
+ gpu->regs.phys = (void*)region.offset;
+#endif
+ info.regs->incStrong(gpu);
+ } else {
+ LOGE("GPU register handle %p is invalid!", info.regs.get());
+ failed = true;
+ }
+ }
+
+ for (size_t i=0 ; i<info.count && !failed ; i++) {
+ sp<IMemory>& region(info.regions[i].region);
+ if (region != 0) {
+ sp<IMemoryHeap> heap(region->getMemory());
+ if (heap != 0) {
+ const int fd = heap->heapID();
+ gpu->gpu[i].fd = fd;
+ gpu->gpu[i].base = region->pointer();
+ gpu->gpu[i].size = region->size();
+ gpu->gpu[i].user = region.get();
+ gpu->gpu[i].offset = info.regions[i].reserved;
+#if HAVE_ANDROID_OS
+ struct pmem_region reg;
+ if (ioctl(fd, PMEM_GET_PHYS, &reg) >= 0)
+ gpu->gpu[i].phys = (void*)reg.offset;
+#endif
+ region->incStrong(gpu);
+ } else {
+ LOGE("GPU region handle [%d, %p] is invalid!", i, region.get());
+ failed = true;
+ }
+ }
+ }
+
+ if (failed) {
+ // something went wrong, clean up everything!
+ if (gpu->regs.user) {
+ static_cast<IMemory*>(gpu->regs.user)->decStrong(gpu);
+ for (size_t i=0 ; i<info.count ; i++) {
+ if (gpu->gpu[i].user) {
+ static_cast<IMemory*>(gpu->gpu[i].user)->decStrong(gpu);
+ }
+ }
+ }
+ }
+
+ gpu->count = info.count;
+ return gpu;
+}
+
+static int gpu_release(void*, request_gpu_t* gpu)
+{
+ sp<IMemory> regs;
+
+ { // scope for lock
+ Mutex::Autolock _l(gRegionsLock);
+ regs = static_cast<IMemory*>(gpu->regs.user);
+ gpu->regs.user = 0;
+ if (regs != 0) regs->decStrong(gpu);
+
+ for (int i=0 ; i<gpu->count ; i++) {
+ sp<IMemory> r(static_cast<IMemory*>(gpu->gpu[i].user));
+ gpu->gpu[i].user = 0;
+ if (r != 0) r->decStrong(gpu);
+ }
+ }
+
+ // there is a special transaction to relinquish the GPU
+ // (it will happen automatically anyway if we don't do this)
+ Parcel data, reply;
+ // NOTE: this transaction does not require an interface token
+ regs->asBinder()->transact(1000, data, &reply);
+ return 1;
+}
+
+/*****************************************************************************/
+
+static __attribute__((noinline))
+void *load_driver(const char* driver, gl_hooks_t* hooks)
+{
+ void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
+ LOGE_IF(!dso,
+ "couldn't load <%s> library (%s)",
+ driver, dlerror());
+
+ if (dso) {
+ void** curr;
+ char const * const * api;
+ gl_hooks_t::gl_t* gl = &hooks->gl;
+ curr = (void**)gl;
+ api = gl_names;
+ while (*api) {
+ void* f = dlsym(dso, *api);
+ //LOGD("<%s> @ 0x%p", *api, f);
+ if (f == NULL) {
+ //LOGW("<%s> not found in %s", *api, driver);
+ f = (void*)gl_unimplemented;
+ }
+ *curr++ = f;
+ api++;
+ }
+ gl_hooks_t::egl_t* egl = &hooks->egl;
+ curr = (void**)egl;
+ api = egl_names;
+ while (*api) {
+ void* f = dlsym(dso, *api);
+ if (f == NULL) {
+ //LOGW("<%s> not found in %s", *api, driver);
+ f = (void*)0;
+ }
+ *curr++ = f;
+ api++;
+ }
+
+ // hook this driver up with surfaceflinger if needed
+ register_gpu_t register_gpu =
+ (register_gpu_t)dlsym(dso, "oem_register_gpu");
+
+ if (register_gpu != NULL) {
+ if (getSurfaceFlinger() != 0) {
+ register_gpu(dso, gpu_acquire, gpu_release);
+ }
+ }
+ }
+ return dso;
+}
+
+template<typename T>
+static __attribute__((noinline))
+int binarySearch(
+ T const sortedArray[], int first, int last, T key)
+{
+ while (first <= last) {
+ int mid = (first + last) / 2;
+ if (key > sortedArray[mid]) {
+ first = mid + 1;
+ } else if (key < sortedArray[mid]) {
+ last = mid - 1;
+ } else {
+ return mid;
+ }
+ }
+ return -1;
+}
+
+static int cmp_configs(const void* a, const void *b)
+{
+ EGLConfig c0 = *(EGLConfig const *)a;
+ EGLConfig c1 = *(EGLConfig const *)b;
+ return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
+}
+
+static char const * const gVendorString = "Android";
+static char const * const gVersionString = "1.2 Android META-EGL";
+static char const * const gClientApiString = "OpenGL ES";
+
+struct extention_map_t {
+ const char* name;
+ void (*address)(void);
+};
+
+static const extention_map_t gExtentionMap[] = {
+ { "eglSwapRectangleANDROID", (void(*)())&eglSwapRectangleANDROID },
+ { "eglQueryStringConfigANDROID", (void(*)())&eglQueryStringConfigANDROID },
+};
+
+static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
+
+static void(*findProcAddress(const char* name,
+ const extention_map_t* map, size_t n))()
+{
+ for (uint32_t i=0 ; i<n ; i++) {
+ if (!strcmp(name, map[i].name)) {
+ return map[i].address;
+ }
+ }
+ return NULL;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+
+// ----------------------------------------------------------------------------
+// extensions for the framework
+// ----------------------------------------------------------------------------
+
+void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+ const GLvoid *ptr, GLsizei count) {
+ glColorPointer(size, type, stride, ptr);
+}
+void glNormalPointerBounds(GLenum type, GLsizei stride,
+ const GLvoid *pointer, GLsizei count) {
+ glNormalPointer(type, stride, pointer);
+}
+void glTexCoordPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count) {
+ glTexCoordPointer(size, type, stride, pointer);
+}
+void glVertexPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count) {
+ glVertexPointer(size, type, stride, pointer);
+}
+
+
+// ----------------------------------------------------------------------------
+// Actual GL wrappers
+// ----------------------------------------------------------------------------
+
+#if __OPTIMIZE__ && defined(__arm__) && !defined(__thumb__) && !USE_SLOW_BINDING && !GL_LOGGER
+
+ #define API_ENTRY(_api) __attribute__((naked)) _api
+ #define CALL_GL_API(_api, ...) \
+ asm volatile( \
+ "mov r12, #0xFFFF0FFF \n" \
+ "ldr r12, [r12, #-15] \n" \
+ "ldr r12, [r12, %[tls]] \n" \
+ "cmp r12, #0 \n" \
+ "ldrne pc, [r12, %[api]] \n" \
+ "bx lr \n" \
+ : \
+ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
+ [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+ : \
+ );
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ CALL_GL_API(_api, __VA_ARGS__) \
+ return 0; // placate gcc's warnings. never reached.
+
+#else
+
+ #define API_ENTRY(_api) _api
+ #if GL_LOGGER
+
+ #define CALL_GL_API(_api, ...) \
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+ log_##_api(__VA_ARGS__); \
+ _c->_api(__VA_ARGS__);
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+ log_##_api(__VA_ARGS__); \
+ return _c->_api(__VA_ARGS__)
+
+ #else
+
+ #define CALL_GL_API(_api, ...) \
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+ _c->_api(__VA_ARGS__);
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+ return _c->_api(__VA_ARGS__)
+
+ #endif
+
+#endif
+
+#include "gl_api.cpp"
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+static int gl_context_lost() {
+ setGlThreadSpecific(&gHooks[IMPL_HARDWARE_CONTEXT_LOST]);
+ return 0;
+}
+static int egl_context_lost() {
+ setGlThreadSpecific(&gHooks[IMPL_HARDWARE_CONTEXT_LOST]);
+ return EGL_FALSE;
+}
+static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
+ usleep(100000); // don't use all the CPU
+ setGlThreadSpecific(&gHooks[IMPL_HARDWARE_CONTEXT_LOST]);
+ return EGL_FALSE;
+}
+static GLint egl_context_lost_get_error() {
+ return EGL_CONTEXT_LOST;
+}
+static int ext_context_lost() {
+ return 0;
+}
+
+static void gl_no_context() {
+ LOGE("call to OpenGL ES API with no current context");
+}
+static void early_egl_init(void)
+{
+#if !defined(HAVE_ANDROID_OS) || USE_SLOW_BINDING || GL_LOGGER
+ pthread_key_create(&gGLWrapperKey, NULL);
+#endif
+ uint32_t addr = (uint32_t)((void*)gl_no_context);
+ android_memset32((uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT], addr, sizeof(gHooks[IMPL_NO_CONTEXT]));
+ setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+}
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
+
+
+static inline
+egl_display_t* get_display(EGLDisplay dpy)
+{
+ uintptr_t index = uintptr_t(dpy)-1U;
+ return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
+}
+
+static inline
+egl_surface_t* get_surface(EGLSurface surface)
+{
+ egl_surface_t* s = (egl_surface_t *)surface;
+ return s;
+}
+
+static inline
+egl_context_t* get_context(EGLContext context)
+{
+ egl_context_t* c = (egl_context_t *)context;
+ return c;
+}
+
+static egl_connection_t* validate_display_config(
+ EGLDisplay dpy, EGLConfig config,
+ egl_display_t const*& dp, int& impl, int& index)
+{
+ dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
+
+ impl = uintptr_t(config)>>24;
+ if (uint32_t(impl) >= 2) {
+ return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
+ }
+ index = uintptr_t(config) & 0xFFFFFF;
+ if (index >= dp->numConfigs[impl]) {
+ return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
+ }
+ egl_connection_t* const cnx = &gEGLImpl[impl];
+ if (cnx->dso == 0) {
+ return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
+ }
+ return cnx;
+}
+
+static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
+{
+ if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (!get_display(dpy)->isValid())
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (!ctx) // TODO: make sure context is a valid object
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (!get_context(ctx)->isValid())
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ return EGL_TRUE;
+}
+
+static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
+{
+ if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (!get_display(dpy)->isValid())
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (!surface) // TODO: make sure surface is a valid object
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (!get_surface(surface)->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return EGL_TRUE;
+}
+
+static void add_extension(egl_display_t* dp, char const*& p, const char* ext)
+{
+ if (!strstr(p, ext)) {
+ p = (char const*)realloc((void*)p, strlen(p) + 1 + strlen(ext) + 1);
+ strcat((char*)p, " ");
+ strcat((char*)p, ext);
+ }
+ if (!strstr(dp->extensionsString, ext)) {
+ char const*& es = dp->extensionsString;
+ es = (char const*)realloc((void*)es, strlen(es) + 1 + strlen(ext) + 1);
+ strcat((char*)es, " ");
+ strcat((char*)es, ext);
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+EGLDisplay eglGetDisplay(NativeDisplayType display)
+{
+ if (sEarlyInitState) {
+ return EGL_NO_DISPLAY;
+ }
+
+ uint32_t index = uint32_t(display);
+ if (index >= NUM_DISPLAYS) {
+ return EGL_NO_DISPLAY;
+ }
+
+ EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
+ egl_display_t* d = &gDisplay[index];
+
+ // dynamically load all our EGL implementations for that display
+ // and call into the real eglGetGisplay()
+ egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
+ if (cnx->dso == 0) {
+ cnx->hooks = &gHooks[IMPL_SOFTWARE];
+ cnx->dso = load_driver("libagl.so", cnx->hooks);
+ }
+ if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
+ d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
+ LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
+ "No EGLDisplay for software EGL!");
+ }
+
+ cnx = &gEGLImpl[IMPL_HARDWARE];
+ if (cnx->dso == 0 && cnx->unavailable == 0) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.hw", value, "1");
+ if (atoi(value) != 0) {
+ cnx->hooks = &gHooks[IMPL_HARDWARE];
+ cnx->dso = load_driver("libhgl.so", cnx->hooks);
+ } else {
+ LOGD("3D hardware acceleration is disabled");
+ }
+ }
+ if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
+ android_memset32(
+ (uint32_t*)(void*)&gHooks[IMPL_HARDWARE_CONTEXT_LOST].gl,
+ (uint32_t)((void*)gl_context_lost),
+ sizeof(gHooks[IMPL_HARDWARE_CONTEXT_LOST].gl));
+ android_memset32(
+ (uint32_t*)(void*)&gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl,
+ (uint32_t)((void*)egl_context_lost),
+ sizeof(gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl));
+ android_memset32(
+ (uint32_t*)(void*)&gHooks[IMPL_HARDWARE_CONTEXT_LOST].ext,
+ (uint32_t)((void*)ext_context_lost),
+ sizeof(gHooks[IMPL_HARDWARE_CONTEXT_LOST].ext));
+
+ gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl.eglSwapBuffers =
+ egl_context_lost_swap_buffers;
+
+ gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl.eglGetError =
+ egl_context_lost_get_error;
+
+ gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl.eglTerminate =
+ gHooks[IMPL_HARDWARE].egl.eglTerminate;
+
+ d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
+ if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
+ dlclose((void*)cnx->dso);
+ cnx->dso = 0;
+ // in case of failure, we want to make sure we don't try again
+ // as it's expensive.
+ cnx->unavailable = 1;
+ }
+ }
+
+ return dpy;
+}
+
+// ----------------------------------------------------------------------------
+// Initialization
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+ egl_display_t * const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ if (android_atomic_inc(&dp->refs) > 0) {
+ if (major != NULL) *major = 1;
+ if (minor != NULL) *minor = 2;
+ return EGL_TRUE;
+ }
+
+ setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+
+ // initialize each EGL and
+ // build our own extension string first, based on the extension we know
+ // and the extension supported by our client implementation
+ dp->extensionsString = strdup("EGL_ANDROID_query_string_config");
+ for (int i=0 ; i<2 ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ cnx->major = -1;
+ cnx->minor = -1;
+ if (cnx->dso && cnx->hooks->egl.eglInitialize(
+ dp->dpys[i], &cnx->major, &cnx->minor)) {
+
+ //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
+ // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
+
+ // get the query-strings for this display for each implementation
+ dp->queryString[i].vendor =
+ cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
+ dp->queryString[i].version =
+ cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
+ dp->queryString[i].extensions = strdup(
+ cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
+ dp->queryString[i].clientApi =
+ cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
+
+ // Dynamically insert extensions we know about
+ if (cnx->hooks->egl.eglSwapRectangleANDROID)
+ add_extension(dp, dp->queryString[i].extensions,
+ "EGL_ANDROID_swap_rectangle");
+
+ if (cnx->hooks->egl.eglQueryStringConfigANDROID)
+ add_extension(dp, dp->queryString[i].extensions,
+ "EGL_ANDROID_query_string_config");
+ }
+ }
+
+ // Build the extension list that depends on the current config.
+ // It is the intersection of our extension list and the
+ // underlaying EGL's extensions list
+ EGLBoolean res = EGL_FALSE;
+ for (int i=0 ; i<2 ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
+ char const* const their_extensions = dp->queryString[i].extensions;
+ char* our_extensions = strdup(dp->extensionsString);
+ char* const our_extensions_org = our_extensions;
+ char* extensions_config = (char*)calloc(strlen(our_extensions)+2, 1);
+ char* p;
+ do {
+ p = strchr(our_extensions, ' ');
+ if (p) *p++ = 0;
+ else p = strchr(our_extensions, 0);
+ if (strstr(their_extensions, our_extensions)) {
+ strcat(extensions_config, our_extensions);
+ strcat(extensions_config, " ");
+ }
+ our_extensions = p;
+ } while (*p);
+ free((void*)our_extensions_org);
+
+ // remove the trailling white space
+ if (extensions_config[0] != 0) {
+ size_t l = strlen(extensions_config) - 1; // new size
+ extensions_config[l] = 0; // remove the trailling white space
+ extensions_config = (char*)realloc(extensions_config, l+1);
+ } else {
+ extensions_config = (char*)realloc(extensions_config, 1);
+ }
+ dp->queryString[i].extensions_config = extensions_config;
+
+ EGLint n;
+ if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
+ dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
+ if (dp->configs[i]) {
+ if (cnx->hooks->egl.eglGetConfigs(
+ dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
+ {
+ // sort the configurations so we can do binary searches
+ qsort( dp->configs[i],
+ dp->numConfigs[i],
+ sizeof(EGLConfig), cmp_configs);
+
+ dp->numTotalConfigs += n;
+ res = EGL_TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ if (res == EGL_TRUE) {
+ if (major != NULL) *major = 1;
+ if (minor != NULL) *minor = 2;
+ return EGL_TRUE;
+ }
+ return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy)
+{
+ egl_display_t* const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (android_atomic_dec(&dp->refs) != 1)
+ return EGL_TRUE;
+
+ EGLBoolean res = EGL_FALSE;
+ for (int i=0 ; i<2 ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ cnx->hooks->egl.eglTerminate(dp->dpys[i]);
+
+ /* REVISIT: it's unclear what to do if eglTerminate() fails,
+ * on one end we shouldn't care, on the other end if it fails
+ * it might not be safe to call dlclose() (there could be some
+ * threads around). */
+
+ free(dp->configs[i]);
+ free((void*)dp->queryString[i].extensions_config);
+ free((void*)dp->queryString[i].extensions);
+ dp->numConfigs[i] = 0;
+ dp->dpys[i] = EGL_NO_DISPLAY;
+ dlclose((void*)cnx->dso);
+ cnx->dso = 0;
+ res = EGL_TRUE;
+ }
+ }
+ free((void*)dp->extensionsString);
+ dp->extensionsString = 0;
+ dp->numTotalConfigs = 0;
+ clearTLS();
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+// configuration
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglGetConfigs( EGLDisplay dpy,
+ EGLConfig *configs,
+ EGLint config_size, EGLint *num_config)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ GLint numConfigs = dp->numTotalConfigs;
+ if (!configs) {
+ *num_config = numConfigs;
+ return EGL_TRUE;
+ }
+ GLint n = 0;
+ for (int j=0 ; j<2 ; j++) {
+ for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
+ *configs++ = MAKE_CONFIG(j, i);
+ config_size--;
+ n++;
+ }
+ }
+
+ *num_config = n;
+ return EGL_TRUE;
+}
+
+EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ if (configs == 0) {
+ *num_config = 0;
+ return EGL_TRUE;
+ }
+
+ EGLBoolean res = EGL_FALSE;
+ *num_config = 0;
+ for (int i=0 ; i<2 ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ EGLint n;
+ if (cnx->hooks->egl.eglChooseConfig(
+ dp->dpys[i], attrib_list, configs, config_size, &n))
+ {
+ // now we need to convert these client EGLConfig to our
+ // internal EGLConfig format. This is done in O(n log n).
+ for (int j=0 ; j<n ; j++) {
+ int index = binarySearch<EGLConfig>(
+ dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
+ if (index >= 0) {
+ configs[j] = MAKE_CONFIG(i, index);
+ } else {
+ return setError(EGL_BAD_CONFIG, EGL_FALSE);
+ }
+ }
+ configs += n;
+ config_size -= n;
+ *num_config += n;
+ res = EGL_TRUE;
+ }
+ }
+ }
+ return res;
+}
+
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value)
+{
+ egl_display_t const* dp = 0;
+ int i=0, index=0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+ if (!cnx) return EGL_FALSE;
+ return cnx->hooks->egl.eglGetConfigAttrib(
+ dp->dpys[i], dp->configs[i][index], attribute, value);
+}
+
+// ----------------------------------------------------------------------------
+// surfaces
+// ----------------------------------------------------------------------------
+
+EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
+ NativeWindowType window,
+ const EGLint *attrib_list)
+{
+ egl_display_t const* dp = 0;
+ int i=0, index=0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+ if (cnx) {
+ // window must be connected upon calling underlying
+ // eglCreateWindowSurface
+ if (window) {
+ window->incRef(window);
+ if (window->connect)
+ window->connect(window);
+ }
+
+ EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
+ dp->dpys[i], dp->configs[i][index], window, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
+ return s;
+ }
+
+ // something went wrong, disconnect and free window
+ // (will disconnect() automatically)
+ if (window) {
+ window->decRef(window);
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
+ NativePixmapType pixmap,
+ const EGLint *attrib_list)
+{
+ egl_display_t const* dp = 0;
+ int i=0, index=0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+ if (cnx) {
+ EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
+ dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+ return s;
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list)
+{
+ egl_display_t const* dp = 0;
+ int i=0, index=0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+ if (cnx) {
+ EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
+ dp->dpys[i], dp->configs[i][index], attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+ return s;
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
+{
+ if (!validate_display_surface(dpy, surface))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(surface);
+
+ EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
+ dp->dpys[s->impl], s->surface);
+
+ delete s;
+ return result;
+}
+
+EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint *value)
+{
+ if (!validate_display_surface(dpy, surface))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(surface);
+
+ return s->cnx->hooks->egl.eglQuerySurface(
+ dp->dpys[s->impl], s->surface, attribute, value);
+}
+
+// ----------------------------------------------------------------------------
+// contextes
+// ----------------------------------------------------------------------------
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_list, const EGLint *attrib_list)
+{
+ egl_display_t const* dp = 0;
+ int i=0, index=0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+ if (cnx) {
+ EGLContext context = cnx->hooks->egl.eglCreateContext(
+ dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
+ if (context != EGL_NO_CONTEXT) {
+ egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
+ return c;
+ }
+ }
+ return EGL_NO_CONTEXT;
+}
+
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+ if (!validate_display_context(dpy, ctx))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_context_t * const c = get_context(ctx);
+ EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
+ dp->dpys[c->impl], c->context);
+ delete c;
+ return result;
+}
+
+EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
+ ctx == EGL_NO_CONTEXT)
+ {
+ EGLBoolean result = EGL_TRUE;
+ ctx = getContext();
+ if (ctx) {
+ egl_context_t * const c = get_context(ctx);
+ result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
+ if (result == EGL_TRUE) {
+ setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+ setContext(EGL_NO_CONTEXT);
+ }
+ }
+ return result;
+ }
+
+ if (!validate_display_context(dpy, ctx))
+ return EGL_FALSE;
+
+ egl_context_t * const c = get_context(ctx);
+ if (draw != EGL_NO_SURFACE) {
+ egl_surface_t const * d = get_surface(draw);
+ if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (d->impl != c->impl)
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
+ draw = d->surface;
+ }
+ if (read != EGL_NO_SURFACE) {
+ egl_surface_t const * r = get_surface(read);
+ if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (r->impl != c->impl)
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
+ read = r->surface;
+ }
+ EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
+ dp->dpys[c->impl], draw, read, c->context);
+
+ if (result == EGL_TRUE) {
+ setGlThreadSpecific(c->cnx->hooks);
+ setContext(ctx);
+ c->read = read;
+ c->draw = draw;
+ }
+ return result;
+}
+
+
+EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
+ EGLint attribute, EGLint *value)
+{
+ if (!validate_display_context(dpy, ctx))
+ return EGL_FALSE;
+
+ egl_display_t const * const dp = get_display(dpy);
+ egl_context_t * const c = get_context(ctx);
+
+ return c->cnx->hooks->egl.eglQueryContext(
+ dp->dpys[c->impl], c->context, attribute, value);
+}
+
+EGLContext eglGetCurrentContext(void)
+{
+ EGLContext ctx = getContext();
+ return ctx;
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw)
+{
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
+ switch (readdraw) {
+ case EGL_READ: return c->read;
+ case EGL_DRAW: return c->draw;
+ default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLDisplay eglGetCurrentDisplay(void)
+{
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
+ return c->dpy;
+ }
+ return EGL_NO_DISPLAY;
+}
+
+EGLBoolean eglWaitGL(void)
+{
+ EGLBoolean res = EGL_TRUE;
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (uint32_t(c->impl)>=2)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ egl_connection_t* const cnx = &gEGLImpl[c->impl];
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ res = cnx->hooks->egl.eglWaitGL();
+ }
+ return res;
+}
+
+EGLBoolean eglWaitNative(EGLint engine)
+{
+ EGLBoolean res = EGL_TRUE;
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (uint32_t(c->impl)>=2)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ egl_connection_t* const cnx = &gEGLImpl[c->impl];
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ res = cnx->hooks->egl.eglWaitNative(engine);
+ }
+ return res;
+}
+
+EGLint eglGetError(void)
+{
+ EGLint result = EGL_SUCCESS;
+ for (int i=0 ; i<2 ; i++) {
+ EGLint err = EGL_SUCCESS;
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso)
+ err = cnx->hooks->egl.eglGetError();
+ if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
+ result = err;
+ }
+ if (result == EGL_SUCCESS)
+ result = getError();
+ return result;
+}
+
+void (*eglGetProcAddress(const char *procname))()
+{
+ void (*addr)();
+ addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
+ if (addr) return addr;
+
+ return NULL; // TODO: finish implementation below
+
+ addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
+ if (addr) return addr;
+
+ addr = 0;
+ int slot = -1;
+ for (int i=0 ; i<2 ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ if (cnx->hooks->egl.eglGetProcAddress) {
+ addr = cnx->hooks->egl.eglGetProcAddress(procname);
+ if (addr) {
+ if (slot == -1) {
+ slot = 0; // XXX: find free slot
+ if (slot == -1) {
+ addr = 0;
+ break;
+ }
+ }
+ cnx->hooks->ext.extensions[slot] = addr;
+ }
+ }
+ }
+ }
+
+ if (slot >= 0) {
+ addr = 0; // XXX: address of stub 'slot'
+ gGLExtentionMap[slot].name = strdup(procname);
+ gGLExtentionMap[slot].address = addr;
+ }
+
+ return addr;
+
+
+ /*
+ * TODO: For OpenGL ES extensions, we must generate a stub
+ * that looks like
+ * mov r12, #0xFFFF0FFF
+ * ldr r12, [r12, #-15]
+ * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
+ * mov r12, [r12, #api_offset]
+ * ldrne pc, r12
+ * mov pc, #unsupported_extension
+ *
+ * and write the address of the extension in *all*
+ * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
+ *
+ */
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
+{
+ if (!validate_display_surface(dpy, draw))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(draw);
+ return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
+}
+
+EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
+ NativePixmapType target)
+{
+ if (!validate_display_surface(dpy, surface))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(surface);
+ return s->cnx->hooks->egl.eglCopyBuffers(
+ dp->dpys[s->impl], s->surface, target);
+}
+
+const char* eglQueryString(EGLDisplay dpy, EGLint name)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ switch (name) {
+ case EGL_VENDOR:
+ return gVendorString;
+ case EGL_VERSION:
+ return gVersionString;
+ case EGL_EXTENSIONS:
+ return dp->extensionsString;
+ case EGL_CLIENT_APIS:
+ return gClientApiString;
+ }
+ return setError(EGL_BAD_PARAMETER, (const char *)0);
+}
+
+
+// ----------------------------------------------------------------------------
+// EGL 1.1
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSurfaceAttrib(
+ EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+{
+ if (!validate_display_surface(dpy, surface))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->hooks->egl.eglSurfaceAttrib) {
+ return s->cnx->hooks->egl.eglSurfaceAttrib(
+ dp->dpys[s->impl], s->surface, attribute, value);
+ }
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+}
+
+EGLBoolean eglBindTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ if (!validate_display_surface(dpy, surface))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->hooks->egl.eglBindTexImage) {
+ return s->cnx->hooks->egl.eglBindTexImage(
+ dp->dpys[s->impl], s->surface, buffer);
+ }
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+}
+
+EGLBoolean eglReleaseTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ if (!validate_display_surface(dpy, surface))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->hooks->egl.eglReleaseTexImage) {
+ return s->cnx->hooks->egl.eglReleaseTexImage(
+ dp->dpys[s->impl], s->surface, buffer);
+ }
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+ egl_display_t * const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ EGLBoolean res = EGL_TRUE;
+ for (int i=0 ; i<2 ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ if (cnx->hooks->egl.eglSwapInterval) {
+ if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
+ res = EGL_FALSE;
+ }
+ }
+ }
+ }
+ return res;
+}
+
+
+// ----------------------------------------------------------------------------
+// EGL 1.2
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglWaitClient(void)
+{
+ EGLBoolean res = EGL_TRUE;
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (uint32_t(c->impl)>=2)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ egl_connection_t* const cnx = &gEGLImpl[c->impl];
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (cnx->hooks->egl.eglWaitClient) {
+ res = cnx->hooks->egl.eglWaitClient();
+ } else {
+ res = cnx->hooks->egl.eglWaitGL();
+ }
+ }
+ return res;
+}
+
+EGLBoolean eglBindAPI(EGLenum api)
+{
+ // bind this API on all EGLs
+ EGLBoolean res = EGL_TRUE;
+ for (int i=0 ; i<2 ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ if (cnx->hooks->egl.eglBindAPI) {
+ if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
+ res = EGL_FALSE;
+ }
+ }
+ }
+ }
+ return res;
+}
+
+EGLenum eglQueryAPI(void)
+{
+ for (int i=0 ; i<2 ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ if (cnx->hooks->egl.eglQueryAPI) {
+ // the first one we find is okay, because they all
+ // should be the same
+ return cnx->hooks->egl.eglQueryAPI();
+ }
+ }
+ }
+ // or, it can only be OpenGL ES
+ return EGL_OPENGL_ES_API;
+}
+
+EGLBoolean eglReleaseThread(void)
+{
+ for (int i=0 ; i<2 ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ if (cnx->hooks->egl.eglReleaseThread) {
+ cnx->hooks->egl.eglReleaseThread();
+ }
+ }
+ }
+ clearTLS();
+ return EGL_TRUE;
+}
+
+EGLSurface eglCreatePbufferFromClientBuffer(
+ EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+ EGLConfig config, const EGLint *attrib_list)
+{
+ egl_display_t const* dp = 0;
+ int i=0, index=0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+ if (!cnx) return EGL_FALSE;
+ if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
+ return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
+ dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
+ }
+ return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
+}
+
+// ----------------------------------------------------------------------------
+// Android extentions
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSwapRectangleANDROID(
+ EGLDisplay dpy, EGLSurface draw,
+ EGLint l, EGLint t, EGLint w, EGLint h)
+{
+ if (!validate_display_surface(dpy, draw))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(draw);
+ if (s->cnx->hooks->egl.eglSwapRectangleANDROID) {
+ return s->cnx->hooks->egl.eglSwapRectangleANDROID(
+ dp->dpys[s->impl], s->surface, l, t, w, h);
+ }
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+}
+
+const char* eglQueryStringConfigANDROID(
+ EGLDisplay dpy, EGLConfig config, EGLint name)
+{
+ egl_display_t const* dp = 0;
+ int i=0, index=0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+ if (cnx) {
+ return dp->queryString[i].extensions_config;
+ }
+ return setError(EGL_BAD_PARAMETER, (const char *)0);
+}
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
new file mode 100644
index 0000000..a3dff76
--- /dev/null
+++ b/opengl/libagl/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Build the software OpenGL ES library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ egl.cpp \
+ state.cpp \
+ texture.cpp \
+ Tokenizer.cpp \
+ TokenManager.cpp \
+ TextureObjectManager.cpp \
+ BufferObjectManager.cpp \
+ array.cpp.arm \
+ fp.cpp.arm \
+ light.cpp.arm \
+ matrix.cpp.arm \
+ mipmap.cpp.arm \
+ primitives.cpp.arm \
+ vertex.cpp.arm
+
+ifeq ($(TARGET_ARCH),arm)
+ LOCAL_SRC_FILES += fixed_asm.S iterators.S
+ LOCAL_CFLAGS += -fstrict-aliasing
+endif
+
+LOCAL_SHARED_LIBRARIES := libcutils libutils libpixelflinger
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libagl
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libagl/BufferObjectManager.cpp b/opengl/libagl/BufferObjectManager.cpp
new file mode 100644
index 0000000..6bf28ee
--- /dev/null
+++ b/opengl/libagl/BufferObjectManager.cpp
@@ -0,0 +1,103 @@
+/*
+ ** 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.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Errors.h>
+
+#include <GLES/gl.h>
+
+#include "BufferObjectManager.h"
+
+
+namespace android {
+
+using namespace gl;
+
+// ----------------------------------------------------------------------------
+
+EGLBufferObjectManager::EGLBufferObjectManager()
+: TokenManager(), mCount(0)
+{
+}
+
+EGLBufferObjectManager::~EGLBufferObjectManager()
+{
+ // destroy all the buffer objects and their storage
+ GLsizei n = mBuffers.size();
+ for (GLsizei i=0 ; i<n ; i++) {
+ buffer_t* bo = mBuffers.valueAt(i);
+ free(bo->data);
+ delete bo;
+ }
+}
+
+buffer_t const* EGLBufferObjectManager::bind(GLuint buffer)
+{
+ Mutex::Autolock _l(mLock);
+ int32_t i = mBuffers.indexOfKey(buffer);
+ if (i >= 0) {
+ return mBuffers.valueAt(i);
+ }
+ buffer_t* bo = new buffer_t;
+ bo->data = 0;
+ bo->usage = GL_STATIC_DRAW;
+ bo->size = 0;
+ bo->name = buffer;
+ mBuffers.add(buffer, bo);
+ return bo;
+}
+
+int EGLBufferObjectManager::allocateStore(buffer_t* bo,
+ GLsizeiptr size, GLenum usage)
+{
+ Mutex::Autolock _l(mLock);
+ if (size != bo->size) {
+ uint8_t* data = (uint8_t*)malloc(size);
+ if (data == 0)
+ return -1;
+ free(bo->data);
+ bo->data = data;
+ bo->size = size;
+ }
+ bo->usage = usage;
+ return 0;
+}
+
+void EGLBufferObjectManager::deleteBuffers(GLsizei n, const GLuint* buffers)
+{
+ Mutex::Autolock _l(mLock);
+ while (n--) {
+ const GLuint t = *buffers++;
+ if (t) {
+ int32_t index = mBuffers.indexOfKey(t);
+ if (index >= 0) {
+ buffer_t* bo = mBuffers.valueAt(index);
+ free(bo->data);
+ mBuffers.removeItemsAt(index);
+ delete bo;
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/opengl/libagl/BufferObjectManager.h b/opengl/libagl/BufferObjectManager.h
new file mode 100644
index 0000000..9e9340a
--- /dev/null
+++ b/opengl/libagl/BufferObjectManager.h
@@ -0,0 +1,85 @@
+/*
+ **
+ ** Copyright 2006, 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_OPENGLES_BUFFER_OBJECT_MANAGER_H
+#define ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Errors.h>
+
+#include <GLES/gl.h>
+
+#include "Tokenizer.h"
+#include "TokenManager.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+namespace gl {
+
+struct buffer_t {
+ GLsizeiptr size;
+ GLenum usage;
+ uint8_t* data;
+ uint32_t name;
+};
+
+};
+
+class EGLBufferObjectManager : public TokenManager
+{
+public:
+ EGLBufferObjectManager();
+ ~EGLBufferObjectManager();
+
+ // protocol for sp<>
+ inline void incStrong(const void* id) const;
+ inline void decStrong(const void* id) const;
+ typedef void weakref_type;
+
+ gl::buffer_t const* bind(GLuint buffer);
+ int allocateStore(gl::buffer_t* bo, GLsizeiptr size, GLenum usage);
+ void deleteBuffers(GLsizei n, const GLuint* buffers);
+
+private:
+ mutable volatile int32_t mCount;
+ mutable Mutex mLock;
+ KeyedVector<GLuint, gl::buffer_t*> mBuffers;
+};
+
+void EGLBufferObjectManager::incStrong(const void* id) const {
+ android_atomic_inc(&mCount);
+}
+void EGLBufferObjectManager::decStrong(const void* id) const {
+ if (android_atomic_dec(&mCount) == 1) {
+ delete this;
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
+
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
new file mode 100644
index 0000000..12fae63
--- /dev/null
+++ b/opengl/libagl/TextureObjectManager.cpp
@@ -0,0 +1,309 @@
+/*
+ ** Copyright 2006, 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "context.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+EGLTextureObject::EGLTextureObject()
+ : mCount(0), mSize(0)
+{
+ init();
+}
+
+EGLTextureObject::~EGLTextureObject()
+{
+ if (!direct) {
+ if (mSize && surface.data)
+ free(surface.data);
+ if (mMipmaps)
+ freeMipmaps();
+ }
+}
+
+void EGLTextureObject::init()
+{
+ memset(&surface, 0, sizeof(surface));
+ surface.version = sizeof(surface);
+ mMipmaps = 0;
+ mNumExtraLod = 0;
+ mIsComplete = false;
+ wraps = GL_REPEAT;
+ wrapt = GL_REPEAT;
+ min_filter = GL_LINEAR;
+ mag_filter = GL_LINEAR;
+ internalformat = 0;
+ memset(crop_rect, 0, sizeof(crop_rect));
+ generate_mipmap = GL_FALSE;
+ direct = GL_FALSE;
+}
+
+void EGLTextureObject::copyParameters(const sp<EGLTextureObject>& old)
+{
+ wraps = old->wraps;
+ wrapt = old->wrapt;
+ min_filter = old->min_filter;
+ mag_filter = old->mag_filter;
+ memcpy(crop_rect, old->crop_rect, sizeof(crop_rect));
+ generate_mipmap = old->generate_mipmap;
+ direct = old->direct;
+}
+
+status_t EGLTextureObject::allocateMipmaps()
+{
+ // here, by construction, mMipmaps=0 && mNumExtraLod=0
+
+ if (!surface.data)
+ return NO_INIT;
+
+ int w = surface.width;
+ int h = surface.height;
+ const int numLods = 31 - gglClz(max(w,h));
+ if (numLods <= 0)
+ return NO_ERROR;
+
+ mMipmaps = (GGLSurface*)malloc(numLods * sizeof(GGLSurface));
+ if (!mMipmaps)
+ return NO_MEMORY;
+
+ memset(mMipmaps, 0, numLods * sizeof(GGLSurface));
+ mNumExtraLod = numLods;
+ return NO_ERROR;
+}
+
+void EGLTextureObject::freeMipmaps()
+{
+ if (mMipmaps) {
+ for (int i=0 ; i<mNumExtraLod ; i++) {
+ if (mMipmaps[i].data) {
+ free(mMipmaps[i].data);
+ }
+ }
+ free(mMipmaps);
+ mMipmaps = 0;
+ mNumExtraLod = 0;
+ }
+}
+
+const GGLSurface& EGLTextureObject::mip(int lod) const
+{
+ if (lod<=0 || !mMipmaps)
+ return surface;
+ lod = min(lod-1, mNumExtraLod-1);
+ return mMipmaps[lod];
+}
+
+GGLSurface& EGLTextureObject::editMip(int lod)
+{
+ return const_cast<GGLSurface&>(mip(lod));
+}
+
+status_t EGLTextureObject::setSurface(GGLSurface const* s)
+{
+ // XXX: glFlush() on 's'
+ if (mSize && surface.data) {
+ free(surface.data);
+ }
+ surface = *s;
+ internalformat = 0;
+
+ // we should keep the crop_rect, but it's delicate because
+ // the new size of the surface could make it invalid.
+ // so for now, we just loose it.
+ memset(crop_rect, 0, sizeof(crop_rect));
+
+ // it would be nice id we could keep the generate_mipmap flag
+ // we would have to generate them right now though.
+ generate_mipmap = GL_FALSE;
+
+ direct = GL_TRUE;
+ mSize = 0; // we don't own this surface
+ if (mMipmaps)
+ freeMipmaps();
+ mIsComplete = true;
+ return NO_ERROR;
+}
+
+status_t EGLTextureObject::reallocate(
+ GLint level, int w, int h, int s,
+ int format, int compressedFormat, int bpr)
+{
+ const size_t size = h * bpr;
+ if (level == 0)
+ {
+ if (size!=mSize || !surface.data) {
+ if (mSize && surface.data) {
+ free(surface.data);
+ }
+ surface.data = (GGLubyte*)malloc(size);
+ if (!surface.data) {
+ mSize = 0;
+ mIsComplete = false;
+ return NO_MEMORY;
+ }
+ mSize = size;
+ }
+ surface.version = sizeof(GGLSurface);
+ surface.width = w;
+ surface.height = h;
+ surface.stride = s;
+ surface.format = format;
+ surface.compressedFormat = compressedFormat;
+ if (mMipmaps)
+ freeMipmaps();
+ mIsComplete = true;
+ }
+ else
+ {
+ if (!mMipmaps) {
+ if (allocateMipmaps() != NO_ERROR)
+ return NO_MEMORY;
+ }
+
+ LOGW_IF(level-1 >= mNumExtraLod,
+ "specifying mipmap level %d, but # of level is %d",
+ level, mNumExtraLod+1);
+
+ GGLSurface& mipmap = editMip(level);
+ if (mipmap.data)
+ free(mipmap.data);
+
+ mipmap.data = (GGLubyte*)malloc(size);
+ if (!mipmap.data) {
+ memset(&mipmap, 0, sizeof(GGLSurface));
+ mIsComplete = false;
+ return NO_MEMORY;
+ }
+
+ mipmap.version = sizeof(GGLSurface);
+ mipmap.width = w;
+ mipmap.height = h;
+ mipmap.stride = s;
+ mipmap.format = format;
+ mipmap.compressedFormat = compressedFormat;
+
+ // check if the texture is complete
+ mIsComplete = true;
+ const GGLSurface* prev = &surface;
+ for (int i=0 ; i<mNumExtraLod ; i++) {
+ const GGLSurface* curr = mMipmaps + i;
+ if (curr->format != surface.format) {
+ mIsComplete = false;
+ break;
+ }
+
+ uint32_t w = (prev->width >> 1) ? : 1;
+ uint32_t h = (prev->height >> 1) ? : 1;
+ if (w != curr->width || h != curr->height) {
+ mIsComplete = false;
+ break;
+ }
+ prev = curr;
+ }
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+EGLSurfaceManager::EGLSurfaceManager()
+ : TokenManager(), mCount(0)
+{
+}
+
+EGLSurfaceManager::~EGLSurfaceManager()
+{
+ // everything gets freed automatically here...
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::createTexture(GLuint name)
+{
+ sp<EGLTextureObject> result;
+
+ Mutex::Autolock _l(mLock);
+ if (mTextures.indexOfKey(name) >= 0)
+ return result; // already exists!
+
+ result = new EGLTextureObject();
+
+ status_t err = mTextures.add(name, result);
+ if (err < 0)
+ result.clear();
+
+ return result;
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::removeTexture(GLuint name)
+{
+ Mutex::Autolock _l(mLock);
+ const ssize_t index = mTextures.indexOfKey(name);
+ if (index >= 0) {
+ sp<EGLTextureObject> result(mTextures.valueAt(index));
+ mTextures.removeItemsAt(index);
+ return result;
+ }
+ return 0;
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::replaceTexture(GLuint name)
+{
+ sp<EGLTextureObject> tex;
+ Mutex::Autolock _l(mLock);
+ const ssize_t index = mTextures.indexOfKey(name);
+ if (index >= 0) {
+ const sp<EGLTextureObject>& old = mTextures.valueAt(index);
+ const uint32_t refs = old->getStrongCount();
+ if (ggl_likely(refs == 1)) {
+ // we're the only owner
+ tex = old;
+ } else {
+ // keep the texture's parameters
+ tex = new EGLTextureObject();
+ tex->copyParameters(old);
+ mTextures.removeItemsAt(index);
+ mTextures.add(name, tex);
+ }
+ }
+ return tex;
+}
+
+void EGLSurfaceManager::deleteTextures(GLsizei n, const GLuint *tokens)
+{
+ // free all texures
+ Mutex::Autolock _l(mLock);
+ for (GLsizei i=0 ; i<n ; i++) {
+ const GLuint t(*tokens++);
+ if (t) {
+ mTextures.removeItem(t);
+ }
+ }
+}
+
+sp<EGLTextureObject> EGLSurfaceManager::texture(GLuint name)
+{
+ Mutex::Autolock _l(mLock);
+ const ssize_t index = mTextures.indexOfKey(name);
+ if (index >= 0)
+ return mTextures.valueAt(index);
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
new file mode 100644
index 0000000..74ed1a4
--- /dev/null
+++ b/opengl/libagl/TextureObjectManager.h
@@ -0,0 +1,140 @@
+/*
+** Copyright 2006, 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_OPENGLES_SURFACE_H
+#define ANDROID_OPENGLES_SURFACE_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Errors.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#include "Tokenizer.h"
+#include "TokenManager.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class EGLTextureObject
+{
+public:
+ EGLTextureObject();
+ ~EGLTextureObject();
+
+ // protocol for sp<>
+ inline void incStrong(const void* id) const;
+ inline void decStrong(const void* id) const;
+ inline uint32_t getStrongCount() const;
+
+ status_t setSurface(GGLSurface const* s);
+ status_t reallocate(GLint level,
+ int w, int h, int s,
+ int format, int compressedFormat, int bpr);
+ inline size_t size() const;
+ const GGLSurface& mip(int lod) const;
+ GGLSurface& editMip(int lod);
+ bool hasMipmaps() const { return mMipmaps!=0; }
+ bool isComplete() const { return mIsComplete; }
+ void copyParameters(const sp<EGLTextureObject>& old);
+
+private:
+ status_t allocateMipmaps();
+ void freeMipmaps();
+ void init();
+ mutable int32_t mCount;
+ size_t mSize;
+ GGLSurface *mMipmaps;
+ int mNumExtraLod;
+ bool mIsComplete;
+
+public:
+ GGLSurface surface;
+ GLenum wraps;
+ GLenum wrapt;
+ GLenum min_filter;
+ GLenum mag_filter;
+ GLenum internalformat;
+ GLint crop_rect[4];
+ GLint generate_mipmap;
+ GLint direct;
+};
+
+void EGLTextureObject::incStrong(const void* id) const {
+ android_atomic_inc(&mCount);
+}
+void EGLTextureObject::decStrong(const void* id) const {
+ if (android_atomic_dec(&mCount) == 1) {
+ delete this;
+ }
+}
+uint32_t EGLTextureObject::getStrongCount() const {
+ return mCount;
+}
+size_t EGLTextureObject::size() const {
+ return mSize;
+}
+
+// ----------------------------------------------------------------------------
+
+class EGLSurfaceManager : public TokenManager
+{
+public:
+ EGLSurfaceManager();
+ ~EGLSurfaceManager();
+
+ // protocol for sp<>
+ inline void incStrong(const void* id) const;
+ inline void decStrong(const void* id) const;
+ typedef void weakref_type;
+
+ sp<EGLTextureObject> createTexture(GLuint name);
+ sp<EGLTextureObject> removeTexture(GLuint name);
+ sp<EGLTextureObject> replaceTexture(GLuint name);
+ void deleteTextures(GLsizei n, const GLuint *tokens);
+ sp<EGLTextureObject> texture(GLuint name);
+
+private:
+ mutable int32_t mCount;
+ mutable Mutex mLock;
+ KeyedVector< GLuint, sp<EGLTextureObject> > mTextures;
+};
+
+void EGLSurfaceManager::incStrong(const void* id) const {
+ android_atomic_inc(&mCount);
+}
+void EGLSurfaceManager::decStrong(const void* id) const {
+ if (android_atomic_dec(&mCount) == 1) {
+ delete this;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_SURFACE_H
+
diff --git a/opengl/libagl/TokenManager.cpp b/opengl/libagl/TokenManager.cpp
new file mode 100644
index 0000000..eea6025
--- /dev/null
+++ b/opengl/libagl/TokenManager.cpp
@@ -0,0 +1,62 @@
+/* libs/opengles/surface.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "TokenManager.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+TokenManager::TokenManager()
+{
+ // token 0 is always reserved
+ mTokenizer.reserve(0);
+}
+
+TokenManager::~TokenManager()
+{
+}
+
+status_t TokenManager::getToken(GLsizei n, GLuint *tokens)
+{
+ Mutex::Autolock _l(mLock);
+ for (GLsizei i=0 ; i<n ; i++)
+ *tokens++ = mTokenizer.acquire();
+ return NO_ERROR;
+}
+
+void TokenManager::recycleTokens(GLsizei n, const GLuint *tokens)
+{
+ Mutex::Autolock _l(mLock);
+ for (int i=0 ; i<n ; i++) {
+ const GLuint token = *tokens++;
+ if (token) {
+ mTokenizer.release(token);
+ }
+ }
+}
+
+bool TokenManager::isTokenValid(GLuint token) const
+{
+ Mutex::Autolock _l(mLock);
+ return mTokenizer.isAcquired(token);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/opengl/libagl/TokenManager.h b/opengl/libagl/TokenManager.h
new file mode 100644
index 0000000..49c1469
--- /dev/null
+++ b/opengl/libagl/TokenManager.h
@@ -0,0 +1,53 @@
+/*
+** Copyright 2006, 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_OPENGLES_TOKEN_MANAGER_H
+#define ANDROID_OPENGLES_TOKEN_MANAGER_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <GLES/gl.h>
+
+#include "Tokenizer.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class TokenManager
+{
+public:
+ TokenManager();
+ ~TokenManager();
+
+ status_t getToken(GLsizei n, GLuint *tokens);
+ void recycleTokens(GLsizei n, const GLuint *tokens);
+ bool isTokenValid(GLuint token) const;
+
+private:
+ mutable Mutex mLock;
+ Tokenizer mTokenizer;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_TOKEN_MANAGER_H
+
diff --git a/opengl/libagl/Tokenizer.cpp b/opengl/libagl/Tokenizer.cpp
new file mode 100644
index 0000000..9b3ea1a
--- /dev/null
+++ b/opengl/libagl/Tokenizer.cpp
@@ -0,0 +1,173 @@
+/* libs/opengles/Tokenizer.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <stdio.h>
+
+#include "Tokenizer.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+ANDROID_BASIC_TYPES_TRAITS(Tokenizer::run_t)
+
+Tokenizer::Tokenizer()
+{
+}
+
+Tokenizer::Tokenizer(const Tokenizer& other)
+ : mRanges(other.mRanges)
+{
+}
+
+Tokenizer::~Tokenizer()
+{
+}
+
+uint32_t Tokenizer::acquire()
+{
+ if (!mRanges.size() || mRanges[0].first) {
+ _insertTokenAt(0,0);
+ return 0;
+ }
+
+ // just extend the first run
+ const run_t& run = mRanges[0];
+ uint32_t token = run.first + run.length;
+ _insertTokenAt(token, 1);
+ return token;
+}
+
+bool Tokenizer::isAcquired(uint32_t token) const
+{
+ return (_indexOrderOf(token) >= 0);
+}
+
+status_t Tokenizer::reserve(uint32_t token)
+{
+ size_t o;
+ const ssize_t i = _indexOrderOf(token, &o);
+ if (i >= 0) {
+ return BAD_VALUE; // this token is already taken
+ }
+ ssize_t err = _insertTokenAt(token, o);
+ return (err<0) ? err : status_t(NO_ERROR);
+}
+
+status_t Tokenizer::release(uint32_t token)
+{
+ const ssize_t i = _indexOrderOf(token);
+ if (i >= 0) {
+ const run_t& run = mRanges[i];
+ if ((token >= run.first) && (token < run.first+run.length)) {
+ // token in this range, we need to split
+ run_t& run = mRanges.editItemAt(i);
+ if ((token == run.first) || (token == run.first+run.length-1)) {
+ if (token == run.first) {
+ run.first += 1;
+ }
+ run.length -= 1;
+ if (run.length == 0) {
+ // XXX: should we systematically remove a run that's empty?
+ mRanges.removeItemsAt(i);
+ }
+ } else {
+ // split the run
+ run_t new_run;
+ new_run.first = token+1;
+ new_run.length = run.first+run.length - new_run.first;
+ run.length = token - run.first;
+ mRanges.insertAt(new_run, i+1);
+ }
+ return NO_ERROR;
+ }
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t Tokenizer::_indexOrderOf(uint32_t token, size_t* order) const
+{
+ // binary search
+ ssize_t err = NAME_NOT_FOUND;
+ ssize_t l = 0;
+ ssize_t h = mRanges.size()-1;
+ ssize_t mid;
+ const run_t* a = mRanges.array();
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const run_t* const curr = a + mid;
+ int c = 0;
+ if (token < curr->first) c = 1;
+ else if (token >= curr->first+curr->length) c = -1;
+ if (c == 0) {
+ err = l = mid;
+ break;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ if (order) *order = l;
+ return err;
+}
+
+ssize_t Tokenizer::_insertTokenAt(uint32_t token, size_t index)
+{
+ const size_t c = mRanges.size();
+
+ if (index >= 1) {
+ // do we need to merge with the previous run?
+ run_t& p = mRanges.editItemAt(index-1);
+ if (p.first+p.length == token) {
+ p.length += 1;
+ if (index < c) {
+ const run_t& n = mRanges[index];
+ if (token+1 == n.first) {
+ p.length += n.length;
+ mRanges.removeItemsAt(index);
+ }
+ }
+ return index;
+ }
+ }
+
+ if (index < c) {
+ // do we need to merge with the next run?
+ run_t& n = mRanges.editItemAt(index);
+ if (token+1 == n.first) {
+ n.first -= 1;
+ n.length += 1;
+ return index;
+ }
+ }
+
+ return mRanges.insertAt(run_t(token,1), index);
+}
+
+void Tokenizer::dump() const
+{
+ const run_t* ranges = mRanges.array();
+ const size_t c = mRanges.size();
+ LOGD("Tokenizer (%p, size = %u)\n", this, c);
+ for (size_t i=0 ; i<c ; i++) {
+ LOGD("%u: (%u, %u)\n", i, ranges[i].first, ranges[i].length);
+ }
+}
+
+}; // namespace android
+
diff --git a/opengl/libagl/Tokenizer.h b/opengl/libagl/Tokenizer.h
new file mode 100644
index 0000000..ac555cb
--- /dev/null
+++ b/opengl/libagl/Tokenizer.h
@@ -0,0 +1,59 @@
+/* libs/opengles/Tokenizer.h
+**
+** Copyright 2006, 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_OPENGLES_TOKENIZER_H
+#define ANDROID_OPENGLES_TOKENIZER_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+class Tokenizer
+{
+public:
+ Tokenizer();
+ Tokenizer(const Tokenizer& other);
+ ~Tokenizer();
+
+ uint32_t acquire();
+ status_t reserve(uint32_t token);
+ status_t release(uint32_t token);
+ bool isAcquired(uint32_t token) const;
+
+ void dump() const;
+
+ struct run_t {
+ run_t() {};
+ run_t(uint32_t f, uint32_t l) : first(f), length(l) {}
+ uint32_t first;
+ uint32_t length;
+ };
+private:
+ ssize_t _indexOrderOf(uint32_t token, size_t* order=0) const;
+ ssize_t _insertTokenAt(uint32_t token, size_t index);
+ Vector<run_t> mRanges;
+};
+
+}; // namespace android
+
+// ----------------------------------------------------------------------------
+
+#endif // ANDROID_OPENGLES_TOKENIZER_H
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
new file mode 100644
index 0000000..1f6757d
--- /dev/null
+++ b/opengl/libagl/array.cpp
@@ -0,0 +1,1557 @@
+/*
+** Copyright 2006, 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.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "light.h"
+#include "primitives.h"
+#include "texture.h"
+#include "BufferObjectManager.h"
+
+// ----------------------------------------------------------------------------
+
+#define VC_CACHE_STATISTICS 0
+#define VC_CACHE_TYPE_NONE 0
+#define VC_CACHE_TYPE_INDEXED 1
+#define VC_CACHE_TYPE_LRU 2
+#define VC_CACHE_TYPE VC_CACHE_TYPE_INDEXED
+
+#if VC_CACHE_STATISTICS
+#include <utils/Timers.h>
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static void validate_arrays(ogles_context_t* c, GLenum mode);
+
+static void compileElements__generic(ogles_context_t*,
+ vertex_t*, GLint, GLsizei);
+static void compileElement__generic(ogles_context_t*,
+ vertex_t*, GLint);
+
+static void drawPrimitivesPoints(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesLineStrip(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesLineLoop(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesLines(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesTriangleStrip(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesTriangleFan(ogles_context_t*, GLint, GLsizei);
+static void drawPrimitivesTriangles(ogles_context_t*, GLint, GLsizei);
+
+static void drawIndexedPrimitivesPoints(ogles_context_t*,
+ GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesLineStrip(ogles_context_t*,
+ GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesLineLoop(ogles_context_t*,
+ GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesLines(ogles_context_t*,
+ GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesTriangleStrip(ogles_context_t*,
+ GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesTriangleFan(ogles_context_t*,
+ GLsizei, const GLvoid*);
+static void drawIndexedPrimitivesTriangles(ogles_context_t*,
+ GLsizei, const GLvoid*);
+
+// ----------------------------------------------------------------------------
+
+typedef void (*arrays_prims_fct_t)(ogles_context_t*, GLint, GLsizei);
+static const arrays_prims_fct_t drawArraysPrims[] = {
+ drawPrimitivesPoints,
+ drawPrimitivesLines,
+ drawPrimitivesLineLoop,
+ drawPrimitivesLineStrip,
+ drawPrimitivesTriangles,
+ drawPrimitivesTriangleStrip,
+ drawPrimitivesTriangleFan
+};
+
+typedef void (*elements_prims_fct_t)(ogles_context_t*, GLsizei, const GLvoid*);
+static const elements_prims_fct_t drawElementsPrims[] = {
+ drawIndexedPrimitivesPoints,
+ drawIndexedPrimitivesLines,
+ drawIndexedPrimitivesLineLoop,
+ drawIndexedPrimitivesLineStrip,
+ drawIndexedPrimitivesTriangles,
+ drawIndexedPrimitivesTriangleStrip,
+ drawIndexedPrimitivesTriangleFan
+};
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void ogles_init_array(ogles_context_t* c)
+{
+ c->arrays.vertex.size = 4;
+ c->arrays.vertex.type = GL_FLOAT;
+ c->arrays.color.size = 4;
+ c->arrays.color.type = GL_FLOAT;
+ c->arrays.normal.size = 4;
+ c->arrays.normal.type = GL_FLOAT;
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ c->arrays.texture[i].size = 4;
+ c->arrays.texture[i].type = GL_FLOAT;
+ }
+ c->vc.init();
+
+ if (!c->vc.vBuffer) {
+ // this could have failed
+ ogles_error(c, GL_OUT_OF_MEMORY);
+ }
+}
+
+void ogles_uninit_array(ogles_context_t* c)
+{
+ c->vc.uninit();
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Array fetchers
+#endif
+
+static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) {
+ memcpy(v, c->current.color.v, sizeof(vec4_t));
+}
+static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) {
+ memcpy(v, c->currentColorClamped.v, sizeof(vec4_t));
+}
+static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) {
+ memcpy(v, c->currentNormal.v, sizeof(vec3_t));
+}
+static void currentTexCoord(ogles_context_t* c, GLfixed* v, const GLvoid*) {
+ memcpy(v, c->current.texture[c->arrays.tmu].v, sizeof(vec4_t));
+}
+
+
+static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) {
+}
+static void fetch2b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
+ v[0] = gglIntToFixed(p[0]);
+ v[1] = gglIntToFixed(p[1]);
+}
+static void fetch2s(ogles_context_t*, GLfixed* v, const GLshort* p) {
+ v[0] = gglIntToFixed(p[0]);
+ v[1] = gglIntToFixed(p[1]);
+}
+static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
+ memcpy(v, p, 2*sizeof(GLfixed));
+}
+static void fetch2f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
+ v[0] = gglFloatToFixed(p[0]);
+ v[1] = gglFloatToFixed(p[1]);
+}
+static void fetch3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
+ v[0] = gglIntToFixed(p[0]);
+ v[1] = gglIntToFixed(p[1]);
+ v[2] = gglIntToFixed(p[2]);
+}
+static void fetch3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
+ v[0] = gglIntToFixed(p[0]);
+ v[1] = gglIntToFixed(p[1]);
+ v[2] = gglIntToFixed(p[2]);
+}
+static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
+ memcpy(v, p, 3*sizeof(GLfixed));
+}
+static void fetch3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
+ v[0] = gglFloatToFixed(p[0]);
+ v[1] = gglFloatToFixed(p[1]);
+ v[2] = gglFloatToFixed(p[2]);
+}
+static void fetch4b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
+ v[0] = gglIntToFixed(p[0]);
+ v[1] = gglIntToFixed(p[1]);
+ v[2] = gglIntToFixed(p[2]);
+ v[3] = gglIntToFixed(p[3]);
+}
+static void fetch4s(ogles_context_t*, GLfixed* v, const GLshort* p) {
+ v[0] = gglIntToFixed(p[0]);
+ v[1] = gglIntToFixed(p[1]);
+ v[2] = gglIntToFixed(p[2]);
+ v[3] = gglIntToFixed(p[3]);
+}
+static void fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
+ memcpy(v, p, 4*sizeof(GLfixed));
+}
+static void fetch4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
+ v[0] = gglFloatToFixed(p[0]);
+ v[1] = gglFloatToFixed(p[1]);
+ v[2] = gglFloatToFixed(p[2]);
+ v[3] = gglFloatToFixed(p[3]);
+}
+static void fetchExpand4ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
+ v[0] = GGL_UB_TO_X(p[0]);
+ v[1] = GGL_UB_TO_X(p[1]);
+ v[2] = GGL_UB_TO_X(p[2]);
+ v[3] = GGL_UB_TO_X(p[3]);
+}
+static void fetchClamp4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
+ v[0] = gglClampx(p[0]);
+ v[1] = gglClampx(p[1]);
+ v[2] = gglClampx(p[2]);
+ v[3] = gglClampx(p[3]);
+}
+static void fetchClamp4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
+ v[0] = gglClampx(gglFloatToFixed(p[0]));
+ v[1] = gglClampx(gglFloatToFixed(p[1]));
+ v[2] = gglClampx(gglFloatToFixed(p[2]));
+ v[3] = gglClampx(gglFloatToFixed(p[3]));
+}
+static void fetchExpand3ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
+ v[0] = GGL_UB_TO_X(p[0]);
+ v[1] = GGL_UB_TO_X(p[1]);
+ v[2] = GGL_UB_TO_X(p[2]);
+ v[3] = 0x10000;
+}
+static void fetchClamp3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
+ v[0] = gglClampx(p[0]);
+ v[1] = gglClampx(p[1]);
+ v[2] = gglClampx(p[2]);
+ v[3] = 0x10000;
+}
+static void fetchClamp3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
+ v[0] = gglClampx(gglFloatToFixed(p[0]));
+ v[1] = gglClampx(gglFloatToFixed(p[1]));
+ v[2] = gglClampx(gglFloatToFixed(p[2]));
+ v[3] = 0x10000;
+}
+static void fetchExpand3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
+ v[0] = GGL_B_TO_X(p[0]);
+ v[1] = GGL_B_TO_X(p[1]);
+ v[2] = GGL_B_TO_X(p[2]);
+}
+static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
+ v[0] = GGL_S_TO_X(p[0]);
+ v[1] = GGL_S_TO_X(p[1]);
+ v[2] = GGL_S_TO_X(p[2]);
+}
+
+typedef array_t::fetcher_t fn_t;
+
+static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x}
+ { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
+ (fn_t)fetch3f, 0, 0, 0, 0, 0,
+ (fn_t)fetch3x },
+ { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
+ (fn_t)fetch4f, 0, 0, 0, 0, 0,
+ (fn_t)fetch4x },
+};
+static const fn_t color_clamp_fct[2][16] = { // size={3,4}, type={ub,f,x}
+ { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
+ (fn_t)fetchClamp3f, 0, 0, 0, 0, 0,
+ (fn_t)fetchClamp3x },
+ { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
+ (fn_t)fetchClamp4f, 0, 0, 0, 0, 0,
+ (fn_t)fetchClamp4x },
+};
+static const fn_t normal_fct[1][16] = { // size={3}, type={b,s,f,x}
+ { (fn_t)fetchExpand3b, 0,
+ (fn_t)fetchExpand3s, 0, 0, 0,
+ (fn_t)fetch3f, 0, 0, 0, 0, 0,
+ (fn_t)fetch3x },
+};
+static const fn_t vertex_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
+ { (fn_t)fetch2b, 0,
+ (fn_t)fetch2s, 0, 0, 0,
+ (fn_t)fetch2f, 0, 0, 0, 0, 0,
+ (fn_t)fetch3x },
+ { (fn_t)fetch3b, 0,
+ (fn_t)fetch3s, 0, 0, 0,
+ (fn_t)fetch3f, 0, 0, 0, 0, 0,
+ (fn_t)fetch3x },
+ { (fn_t)fetch4b, 0,
+ (fn_t)fetch4s, 0, 0, 0,
+ (fn_t)fetch4f, 0, 0, 0, 0, 0,
+ (fn_t)fetch4x }
+};
+static const fn_t texture_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
+ { (fn_t)fetch2b, 0,
+ (fn_t)fetch2s, 0, 0, 0,
+ (fn_t)fetch2f, 0, 0, 0, 0, 0,
+ (fn_t)fetch2x },
+ { (fn_t)fetch3b, 0,
+ (fn_t)fetch3s, 0, 0, 0,
+ (fn_t)fetch3f, 0, 0, 0, 0, 0,
+ (fn_t)fetch3x },
+ { (fn_t)fetch4b, 0,
+ (fn_t)fetch4s, 0, 0, 0,
+ (fn_t)fetch4f, 0, 0, 0, 0, 0,
+ (fn_t)fetch4x }
+};
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark array_t
+#endif
+
+void array_t::init(
+ GLint size, GLenum type, GLsizei stride,
+ const GLvoid *pointer, const buffer_t* bo, GLsizei count)
+{
+ if (!stride) {
+ stride = size;
+ switch (type) {
+ case GL_SHORT:
+ case GL_UNSIGNED_SHORT:
+ stride *= 2;
+ break;
+ case GL_FLOAT:
+ case GL_FIXED:
+ stride *= 4;
+ break;
+ }
+ }
+ this->size = size;
+ this->type = type;
+ this->stride = stride;
+ this->pointer = pointer;
+ this->bo = bo;
+ this->bounds = count;
+}
+
+inline void array_t::resolve()
+{
+ physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark vertex_cache_t
+#endif
+
+void vertex_cache_t::init()
+{
+ // make sure the size of vertex_t allows cache-line alignment
+ CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize;
+
+ const int align = 32;
+ const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
+ const size_t size = s*sizeof(vertex_t) + align;
+ base = malloc(size);
+ if (base) {
+ memset(base, 0, size);
+ vBuffer = (vertex_t*)((size_t(base) + align - 1) & ~(align-1));
+ vCache = vBuffer + VERTEX_BUFFER_SIZE;
+ sequence = 0;
+ }
+}
+
+void vertex_cache_t::uninit()
+{
+ free(base);
+ base = vBuffer = vCache = 0;
+}
+
+void vertex_cache_t::clear()
+{
+#if VC_CACHE_STATISTICS
+ startTime = systemTime(SYSTEM_TIME_THREAD);
+ total = 0;
+ misses = 0;
+#endif
+
+#if VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
+ vertex_t* v = vBuffer;
+ size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
+ do {
+ v->mru = 0;
+ v++;
+ } while (--count);
+#endif
+
+ sequence += INDEX_SEQ;
+ if (sequence >= 0x80000000LU) {
+ sequence = INDEX_SEQ;
+ vertex_t* v = vBuffer;
+ size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
+ do {
+ v->index = 0;
+ v++;
+ } while (--count);
+ }
+}
+
+void vertex_cache_t::dump_stats(GLenum mode)
+{
+#if VC_CACHE_STATISTICS
+ nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime;
+ uint32_t hits = total - misses;
+ uint32_t prim_count;
+ switch (mode) {
+ case GL_POINTS: prim_count = total; break;
+ case GL_LINE_STRIP: prim_count = total - 1; break;
+ case GL_LINE_LOOP: prim_count = total - 1; break;
+ case GL_LINES: prim_count = total / 2; break;
+ case GL_TRIANGLE_STRIP: prim_count = total - 2; break;
+ case GL_TRIANGLE_FAN: prim_count = total - 2; break;
+ case GL_TRIANGLES: prim_count = total / 3; break;
+ default: return;
+ }
+ printf( "total=%5u, hits=%5u, miss=%5u, hitrate=%3u%%,"
+ " prims=%5u, time=%6u us, prims/s=%d, v/t=%f\n",
+ total, hits, misses, (hits*100)/total,
+ prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time),
+ float(misses) / prim_count);
+#endif
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+static __attribute__((noinline))
+void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable)
+{
+ const int tmu = c->arrays.activeTexture;
+ array_t* a;
+ switch (array) {
+ case GL_COLOR_ARRAY: a = &c->arrays.color; break;
+ case GL_NORMAL_ARRAY: a = &c->arrays.normal; break;
+ case GL_TEXTURE_COORD_ARRAY: a = &c->arrays.texture[tmu]; break;
+ case GL_VERTEX_ARRAY: a = &c->arrays.vertex; break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ a->enable = enable ? GL_TRUE : GL_FALSE;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Vertex Cache
+#endif
+
+static __attribute__((noinline))
+vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index)
+{
+ #if VC_CACHE_STATISTICS
+ c->vc.misses++;
+ #endif
+ if (ggl_unlikely(v->locked)) {
+ // we're just looking for an entry in the cache that is not locked.
+ // and we know that there cannot be more than 2 locked entries
+ // because a triangle needs at most 3 vertices.
+ // We never use the first and second entries because they might be in
+ // use by the striper or faner. Any other entry will do as long as
+ // it's not locked.
+ // We compute directly the index of a "free" entry from the locked
+ // state of v[2] and v[3].
+ v = c->vc.vBuffer + 2;
+ v += v[0].locked | (v[1].locked<<1);
+ }
+ // note: compileElement clears v->flags
+ c->arrays.compileElement(c, v, index);
+ v->locked = 1;
+ return v;
+}
+
+static __attribute__((noinline))
+vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
+{
+ index |= c->vc.sequence;
+
+#if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
+
+ vertex_t* const v = c->vc.vCache +
+ (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
+
+ if (ggl_likely(v->index == index)) {
+ v->locked = 1;
+ return v;
+ }
+ return cache_vertex(c, v, index);
+
+#elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
+
+ vertex_t* v = c->vc.vCache +
+ (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
+
+ // always record LRU in v[0]
+ if (ggl_likely(v[0].index == index)) {
+ v[0].locked = 1;
+ v[0].mru = 0;
+ return &v[0];
+ }
+
+ if (ggl_likely(v[1].index == index)) {
+ v[1].locked = 1;
+ v[0].mru = 1;
+ return &v[1];
+ }
+
+ const int lru = 1 - v[0].mru;
+ v[0].mru = lru;
+ return cache_vertex(c, &v[lru], index);
+
+#elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE
+
+ // just for debugging...
+ vertex_t* v = c->vc.vBuffer + 2;
+ return cache_vertex(c, v, index);
+
+#endif
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Primitive Assembly
+#endif
+
+void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count)
+{
+ if (ggl_unlikely(count < 1))
+ return;
+
+ // vertex cache size must be multiple of 1
+ const GLsizei vcs =
+ (vertex_cache_t::VERTEX_BUFFER_SIZE +
+ vertex_cache_t::VERTEX_CACHE_SIZE);
+ do {
+ vertex_t* v = c->vc.vBuffer;
+ GLsizei num = count > vcs ? vcs : count;
+ c->arrays.cull = vertex_t::CLIP_ALL;
+ c->arrays.compileElements(c, v, first, num);
+ first += num;
+ count -= num;
+ if (!c->arrays.cull) {
+ // quick/trivial reject of the whole batch
+ do {
+ const uint32_t cc = v[0].flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderPoint(c, v);
+ v++;
+ num--;
+ } while (num);
+ }
+ } while (count);
+}
+
+// ----------------------------------------------------------------------------
+
+void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count)
+{
+ if (ggl_unlikely(count < 2))
+ return;
+
+ vertex_t *v, *v0, *v1;
+ c->arrays.cull = vertex_t::CLIP_ALL;
+ c->arrays.compileElement(c, c->vc.vBuffer, first);
+ first += 1;
+ count -= 1;
+
+ // vertex cache size must be multiple of 1
+ const GLsizei vcs =
+ (vertex_cache_t::VERTEX_BUFFER_SIZE +
+ vertex_cache_t::VERTEX_CACHE_SIZE - 1);
+ do {
+ v0 = c->vc.vBuffer + 0;
+ v = c->vc.vBuffer + 1;
+ GLsizei num = count > vcs ? vcs : count;
+ c->arrays.compileElements(c, v, first, num);
+ first += num;
+ count -= num;
+ if (!c->arrays.cull) {
+ // quick/trivial reject of the whole batch
+ do {
+ v1 = v++;
+ const uint32_t cc = v0->flags & v1->flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderLine(c, v0, v1);
+ v0 = v1;
+ num--;
+ } while (num);
+ }
+ // copy back the last processed vertex
+ c->vc.vBuffer[0] = *v0;
+ c->arrays.cull = v0->flags & vertex_t::CLIP_ALL;
+ } while (count);
+}
+
+void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count)
+{
+ if (ggl_unlikely(count < 2))
+ return;
+ drawPrimitivesLineStrip(c, first, count);
+ if (ggl_likely(count >= 3)) {
+ vertex_t* v0 = c->vc.vBuffer;
+ vertex_t* v1 = c->vc.vBuffer + 1;
+ c->arrays.compileElement(c, v1, first);
+ const uint32_t cc = v0->flags & v1->flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderLine(c, v0, v1);
+ }
+}
+
+void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count)
+{
+ if (ggl_unlikely(count < 2))
+ return;
+
+ // vertex cache size must be multiple of 2
+ const GLsizei vcs =
+ ((vertex_cache_t::VERTEX_BUFFER_SIZE +
+ vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
+ do {
+ vertex_t* v = c->vc.vBuffer;
+ GLsizei num = count > vcs ? vcs : count;
+ c->arrays.cull = vertex_t::CLIP_ALL;
+ c->arrays.compileElements(c, v, first, num);
+ first += num;
+ count -= num;
+ if (!c->arrays.cull) {
+ // quick/trivial reject of the whole batch
+ num -= 2;
+ do {
+ const uint32_t cc = v[0].flags & v[1].flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderLine(c, v, v+1);
+ v += 2;
+ num -= 2;
+ } while (num >= 0);
+ }
+ } while (count >= 2);
+}
+
+// ----------------------------------------------------------------------------
+
+static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
+ GLint first, GLsizei count, int winding)
+{
+ // winding == 2 : fan
+ // winding == 1 : strip
+
+ if (ggl_unlikely(count < 3))
+ return;
+
+ vertex_t *v, *v0, *v1, *v2;
+ c->arrays.cull = vertex_t::CLIP_ALL;
+ c->arrays.compileElements(c, c->vc.vBuffer, first, 2);
+ first += 2;
+ count -= 2;
+
+ // vertex cache size must be multiple of 2. This is extremely important
+ // because it allows us to preserve the same winding when the whole
+ // batch is culled. We also need 2 extra vertices in the array, because
+ // we always keep the two first ones.
+ const GLsizei vcs =
+ ((vertex_cache_t::VERTEX_BUFFER_SIZE +
+ vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
+ do {
+ v0 = c->vc.vBuffer + 0;
+ v1 = c->vc.vBuffer + 1;
+ v = c->vc.vBuffer + 2;
+ GLsizei num = count > vcs ? vcs : count;
+ c->arrays.compileElements(c, v, first, num);
+ first += num;
+ count -= num;
+ if (!c->arrays.cull) {
+ // quick/trivial reject of the whole batch
+ do {
+ v2 = v++;
+ const uint32_t cc = v0->flags & v1->flags & v2->flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderTriangle(c, v0, v1, v2);
+ swap(((winding^=1) ? v1 : v0), v2);
+ num--;
+ } while (num);
+ }
+ if (count) {
+ v0 = c->vc.vBuffer + 2 + num - 2;
+ v1 = c->vc.vBuffer + 2 + num - 1;
+ if ((winding&2) == 0) {
+ // for strips copy back the two last compiled vertices
+ c->vc.vBuffer[0] = *v0;
+ }
+ c->vc.vBuffer[1] = *v1;
+ c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL;
+ }
+ } while (count > 0);
+}
+
+void drawPrimitivesTriangleStrip(ogles_context_t* c,
+ GLint first, GLsizei count) {
+ drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
+}
+
+void drawPrimitivesTriangleFan(ogles_context_t* c,
+ GLint first, GLsizei count) {
+ drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
+}
+
+void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count)
+{
+ if (ggl_unlikely(count < 3))
+ return;
+
+ // vertex cache size must be multiple of 3
+ const GLsizei vcs =
+ ((vertex_cache_t::VERTEX_BUFFER_SIZE +
+ vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
+ do {
+ vertex_t* v = c->vc.vBuffer;
+ GLsizei num = count > vcs ? vcs : count;
+ c->arrays.cull = vertex_t::CLIP_ALL;
+ c->arrays.compileElements(c, v, first, num);
+ first += num;
+ count -= num;
+ if (!c->arrays.cull) {
+ // quick/trivial reject of the whole batch
+ num -= 3;
+ do {
+ const uint32_t cc = v[0].flags & v[1].flags & v[2].flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderTriangle(c, v, v+1, v+2);
+ v += 3;
+ num -= 3;
+ } while (num >= 0);
+ }
+ } while (count >= 3);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+// this looks goofy, but gcc does a great job with this...
+static inline unsigned int read_index(int type, const GLvoid*& p) {
+ unsigned int r;
+ if (type) {
+ r = *(const GLubyte*)p;
+ p = (const GLubyte*)p + 1;
+ } else {
+ r = *(const GLushort*)p;
+ p = (const GLushort*)p + 1;
+ }
+ return r;
+}
+
+// ----------------------------------------------------------------------------
+
+void drawIndexedPrimitivesPoints(ogles_context_t* c,
+ GLsizei count, const GLvoid *indices)
+{
+ if (ggl_unlikely(count < 1))
+ return;
+ const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
+ do {
+ vertex_t * v = fetch_vertex(c, read_index(type, indices));
+ if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL)))
+ c->prims.renderPoint(c, v);
+ v->locked = 0;
+ count--;
+ } while(count);
+}
+
+// ----------------------------------------------------------------------------
+
+void drawIndexedPrimitivesLineStrip(ogles_context_t* c,
+ GLsizei count, const GLvoid *indices)
+{
+ if (ggl_unlikely(count < 2))
+ return;
+
+ vertex_t * const v = c->vc.vBuffer;
+ vertex_t* v0 = v;
+ vertex_t* v1;
+
+ const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
+ c->arrays.compileElement(c, v0, read_index(type, indices));
+ count -= 1;
+ do {
+ v1 = fetch_vertex(c, read_index(type, indices));
+ const uint32_t cc = v0->flags & v1->flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderLine(c, v0, v1);
+ v0->locked = 0;
+ v0 = v1;
+ count--;
+ } while (count);
+ v1->locked = 0;
+}
+
+void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
+ GLsizei count, const GLvoid *indices)
+{
+ if (ggl_unlikely(count <= 2)) {
+ drawIndexedPrimitivesLines(c, count, indices);
+ return;
+ }
+
+ vertex_t * const v = c->vc.vBuffer;
+ vertex_t* v0 = v;
+ vertex_t* v1;
+
+ const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
+ c->arrays.compileElement(c, v0, read_index(type, indices));
+ count -= 1;
+ do {
+ v1 = fetch_vertex(c, read_index(type, indices));
+ const uint32_t cc = v0->flags & v1->flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderLine(c, v0, v1);
+ v0->locked = 0;
+ v0 = v1;
+ count--;
+ } while (count);
+ v1->locked = 0;
+
+ v1 = c->vc.vBuffer;
+ const uint32_t cc = v0->flags & v1->flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderLine(c, v0, v1);
+}
+
+void drawIndexedPrimitivesLines(ogles_context_t* c,
+ GLsizei count, const GLvoid *indices)
+{
+ if (ggl_unlikely(count < 2))
+ return;
+
+ count -= 2;
+ const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
+ do {
+ vertex_t* const v0 = fetch_vertex(c, read_index(type, indices));
+ vertex_t* const v1 = fetch_vertex(c, read_index(type, indices));
+ const uint32_t cc = v0->flags & v1->flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderLine(c, v0, v1);
+ v0->locked = 0;
+ v1->locked = 0;
+ count -= 2;
+ } while (count >= 0);
+}
+
+// ----------------------------------------------------------------------------
+
+static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c,
+ GLsizei count, const GLvoid *indices, int winding)
+{
+ // winding == 2 : fan
+ // winding == 1 : strip
+
+ if (ggl_unlikely(count < 3))
+ return;
+
+ vertex_t * const v = c->vc.vBuffer;
+ vertex_t* v0 = v;
+ vertex_t* v1 = v+1;
+ vertex_t* v2;
+
+ const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
+ c->arrays.compileElement(c, v0, read_index(type, indices));
+ c->arrays.compileElement(c, v1, read_index(type, indices));
+ count -= 2;
+
+ // note: GCC 4.1.1 here makes a prety interesting optimization
+ // where it duplicates the loop below based on c->arrays.indicesType
+
+ do {
+ v2 = fetch_vertex(c, read_index(type, indices));
+ const uint32_t cc = v0->flags & v1->flags & v2->flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderTriangle(c, v0, v1, v2);
+ vertex_t* & consumed = ((winding^=1) ? v1 : v0);
+ consumed->locked = 0;
+ consumed = v2;
+ count--;
+ } while (count);
+ v0->locked = v1->locked = 0;
+ v2->locked = 0;
+}
+
+void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c,
+ GLsizei count, const GLvoid *indices) {
+ drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1);
+}
+
+void drawIndexedPrimitivesTriangleFan(ogles_context_t* c,
+ GLsizei count, const GLvoid *indices) {
+ drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2);
+}
+
+void drawIndexedPrimitivesTriangles(ogles_context_t* c,
+ GLsizei count, const GLvoid *indices)
+{
+ if (ggl_unlikely(count < 3))
+ return;
+
+ count -= 3;
+ if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) {
+ // This case is probably our most common case...
+ uint16_t const * p = (uint16_t const *)indices;
+ do {
+ vertex_t* const v0 = fetch_vertex(c, *p++);
+ vertex_t* const v1 = fetch_vertex(c, *p++);
+ vertex_t* const v2 = fetch_vertex(c, *p++);
+ const uint32_t cc = v0->flags & v1->flags & v2->flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderTriangle(c, v0, v1, v2);
+ v0->locked = 0;
+ v1->locked = 0;
+ v2->locked = 0;
+ count -= 3;
+ } while (count >= 0);
+ } else {
+ uint8_t const * p = (uint8_t const *)indices;
+ do {
+ vertex_t* const v0 = fetch_vertex(c, *p++);
+ vertex_t* const v1 = fetch_vertex(c, *p++);
+ vertex_t* const v2 = fetch_vertex(c, *p++);
+ const uint32_t cc = v0->flags & v1->flags & v2->flags;
+ if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
+ c->prims.renderTriangle(c, v0, v1, v2);
+ v0->locked = 0;
+ v1->locked = 0;
+ v2->locked = 0;
+ count -= 3;
+ } while (count >= 0);
+ }
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Array compilers
+#endif
+
+void compileElement__generic(ogles_context_t* c,
+ vertex_t* v, GLint first)
+{
+ v->flags = 0;
+ v->index = first;
+ first &= vertex_cache_t::INDEX_MASK;
+ const GLubyte* vp = c->arrays.vertex.element(first);
+ c->arrays.vertex.fetch(c, v->obj.v, vp);
+ c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj);
+ c->arrays.perspective(c, v);
+}
+
+void compileElements__generic(ogles_context_t* c,
+ vertex_t* v, GLint first, GLsizei count)
+{
+ const GLubyte* vp = c->arrays.vertex.element(
+ first & vertex_cache_t::INDEX_MASK);
+ const size_t stride = c->arrays.vertex.stride;
+ transform_t const* const mvp = &c->transforms.mvp;
+ do {
+ v->flags = 0;
+ v->index = first++;
+ c->arrays.vertex.fetch(c, v->obj.v, vp);
+ c->arrays.mvp_transform(mvp, &v->clip, &v->obj);
+ c->arrays.perspective(c, v);
+ vp += stride;
+ v++;
+ } while (--count);
+}
+
+/*
+void compileElements__3x_full(ogles_context_t* c,
+ vertex_t* v, GLint first, GLsizei count)
+{
+ const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
+ const size_t stride = c->arrays.vertex.stride / 4;
+// const GLfixed* const& m = c->transforms.mvp.matrix.m;
+
+ GLfixed m[16];
+ memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
+
+ do {
+ const GLfixed rx = vp[0];
+ const GLfixed ry = vp[1];
+ const GLfixed rz = vp[2];
+ vp += stride;
+ v->index = first++;
+ v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
+ v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
+ v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
+ v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
+
+ const GLfixed w = v->clip.w;
+ uint32_t clip = 0;
+ if (v->clip.x < -w) clip |= vertex_t::CLIP_L;
+ if (v->clip.x > w) clip |= vertex_t::CLIP_R;
+ if (v->clip.y < -w) clip |= vertex_t::CLIP_B;
+ if (v->clip.y > w) clip |= vertex_t::CLIP_T;
+ if (v->clip.z < -w) clip |= vertex_t::CLIP_N;
+ if (v->clip.z > w) clip |= vertex_t::CLIP_F;
+ v->flags = clip;
+ c->arrays.cull &= clip;
+
+ //c->arrays.perspective(c, v);
+ v++;
+ } while (--count);
+}
+*/
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark clippers
+#endif
+
+static void clipVec4(vec4_t& nv,
+ GLfixed t, const vec4_t& s, const vec4_t& p)
+{
+ for (int i=0; i<4 ; i++)
+ nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28);
+}
+
+static void clipVertex(ogles_context_t* c, vertex_t* nv,
+ GLfixed t, const vertex_t* s, const vertex_t* p)
+{
+ clipVec4(nv->clip, t, s->clip, p->clip);
+ nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28);
+ ogles_vertex_project(c, nv);
+ nv->flags |= vertex_t::LIT | vertex_t::EYE | vertex_t::TT;
+ nv->flags &= ~vertex_t::CLIP_ALL;
+}
+
+static void clipVertexC(ogles_context_t* c, vertex_t* nv,
+ GLfixed t, const vertex_t* s, const vertex_t* p)
+{
+ clipVec4(nv->color, t, s->color, p->color);
+ clipVertex(c, nv, t, s, p);
+}
+
+static void clipVertexT(ogles_context_t* c, vertex_t* nv,
+ GLfixed t, const vertex_t* s, const vertex_t* p)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->rasterizer.state.texture[i].enable)
+ clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]);
+ }
+ clipVertex(c, nv, t, s, p);
+}
+
+static void clipVertexAll(ogles_context_t* c, vertex_t* nv,
+ GLfixed t, const vertex_t* s, const vertex_t* p)
+{
+ clipVec4(nv->color, t, s->color, p->color);
+ clipVertexT(c, nv, t, s, p);
+}
+
+static void clipEye(ogles_context_t* c, vertex_t* nv,
+ GLfixed t, const vertex_t* s, const vertex_t* p)
+{
+ nv->clear();
+ c->arrays.clipVertex(c, nv, t, p, s);
+ clipVec4(nv->eye, t, s->eye, p->eye);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void validate_arrays(ogles_context_t* c, GLenum mode)
+{
+ uint32_t enables = c->rasterizer.state.enables;
+
+ // Perspective correction is not need if Ortho transform, but
+ // the user can still provide the w coordinate manually, so we can't
+ // automatically turn it off (in fact we could when the 4th coordinate
+ // is not spcified in the vertex array).
+ // W interpolation is never needed for points.
+ GLboolean perspective =
+ c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
+ c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
+
+ // set anti-aliasing
+ GLboolean smooth = GL_FALSE;
+ switch (mode) {
+ case GL_POINTS:
+ smooth = c->point.smooth;
+ break;
+ case GL_LINES:
+ case GL_LINE_LOOP:
+ case GL_LINE_STRIP:
+ smooth = c->line.smooth;
+ break;
+ }
+ if (((enables & GGL_ENABLE_AA)?1:0) != smooth)
+ c->rasterizer.procs.enableDisable(c, GGL_AA, smooth);
+
+ // set the shade model for this primitive
+ c->rasterizer.procs.shadeModel(c,
+ (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel);
+
+ // compute all the matrices we'll need...
+ uint32_t want =
+ transform_state_t::MVP |
+ transform_state_t::VIEWPORT;
+ if (c->lighting.enable) { // needs normal transforms and eye coords
+ want |= transform_state_t::MVUI;
+ want |= transform_state_t::MODELVIEW;
+ }
+ if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
+ want |= transform_state_t::TEXTURE;
+ }
+ if (c->clipPlanes.enable) { // needs eye coords
+ want |= transform_state_t::MODELVIEW;
+ }
+ ogles_validate_transform(c, want);
+
+ // textures...
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_validate_texture(c);
+
+ // vertex compilers
+ c->arrays.compileElement = compileElement__generic;
+ c->arrays.compileElements = compileElements__generic;
+
+ // vertex transform
+ c->arrays.mvp_transform =
+ c->transforms.mvp.pointv[c->arrays.vertex.size - 2];
+
+ c->arrays.mv_transform =
+ c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
+
+ /*
+ * ***********************************************************************
+ * pick fetchers
+ * ***********************************************************************
+ */
+
+ array_machine_t& am = c->arrays;
+ am.vertex.fetch = fetchNop;
+ am.normal.fetch = currentNormal;
+ am.color.fetch = currentColor;
+
+ if (am.vertex.enable) {
+ am.vertex.resolve();
+ if (am.vertex.bo || am.vertex.pointer) {
+ am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF];
+ }
+ }
+
+ if (am.normal.enable) {
+ am.normal.resolve();
+ if (am.normal.bo || am.normal.pointer) {
+ am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF];
+ }
+ }
+
+ if (am.color.enable) {
+ am.color.resolve();
+ if (c->lighting.enable) {
+ if (am.color.bo || am.color.pointer) {
+ am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF];
+ }
+ } else {
+ if (am.color.bo || am.color.pointer) {
+ am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF];
+ }
+ }
+ }
+
+ int activeTmuCount = 0;
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ am.texture[i].fetch = currentTexCoord;
+ if (c->rasterizer.state.texture[i].enable) {
+
+ // texture fetchers...
+ if (am.texture[i].enable) {
+ am.texture[i].resolve();
+ if (am.texture[i].bo || am.texture[i].pointer) {
+ am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF];
+ }
+ }
+
+ // texture transform...
+ const int index = c->arrays.texture[i].size - 2;
+ c->arrays.tex_transform[i] =
+ c->transforms.texture[i].transform.pointv[index];
+
+ am.tmu = i;
+ activeTmuCount++;
+ }
+ }
+
+ // pick the vertex-clipper
+ uint32_t clipper = 0;
+ // we must reload 'enables' here
+ enables = c->rasterizer.state.enables;
+ if (enables & GGL_ENABLE_SMOOTH)
+ clipper |= 1; // we need to interpolate colors
+ if (enables & GGL_ENABLE_TMUS)
+ clipper |= 2; // we need to interpolate textures
+ switch (clipper) {
+ case 0: c->arrays.clipVertex = clipVertex; break;
+ case 1: c->arrays.clipVertex = clipVertexC; break;
+ case 2: c->arrays.clipVertex = clipVertexT; break;
+ case 3: c->arrays.clipVertex = clipVertexAll; break;
+ }
+ c->arrays.clipEye = clipEye;
+
+ // pick the primitive rasterizer
+ ogles_validate_primitives(c);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+#if 0
+#pragma mark -
+#pragma mark array API
+#endif
+
+void glVertexPointer(
+ GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (size<2 || size>4 || stride<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ switch (type) {
+ case GL_BYTE:
+ case GL_SHORT:
+ case GL_FIXED:
+ case GL_FLOAT:
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
+}
+
+void glColorPointer(
+ GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ // in theory ogles doesn't allow color arrays of size 3
+ // but it is very useful to 'visualize' the normal array.
+ if (size<3 || size>4 || stride<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ case GL_FIXED:
+ case GL_FLOAT:
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
+}
+
+void glNormalPointer(
+ GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (stride<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ switch (type) {
+ case GL_BYTE:
+ case GL_SHORT:
+ case GL_FIXED:
+ case GL_FLOAT:
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0);
+}
+
+void glTexCoordPointer(
+ GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (size<2 || size>4 || stride<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ switch (type) {
+ case GL_BYTE:
+ case GL_SHORT:
+ case GL_FIXED:
+ case GL_FLOAT:
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ const int tmu = c->arrays.activeTexture;
+ c->arrays.texture[tmu].init(size, type, stride, pointer,
+ c->arrays.array_buffer, 0);
+}
+
+
+void glEnableClientState(GLenum array) {
+ ogles_context_t* c = ogles_context_t::get();
+ enableDisableClientState(c, array, true);
+}
+
+void glDisableClientState(GLenum array) {
+ ogles_context_t* c = ogles_context_t::get();
+ enableDisableClientState(c, array, false);
+}
+
+void glClientActiveTexture(GLenum texture)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->arrays.activeTexture = texture - GL_TEXTURE0;
+}
+
+void glDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (count<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ switch (mode) {
+ case GL_POINTS:
+ case GL_LINE_STRIP:
+ case GL_LINE_LOOP:
+ case GL_LINES:
+ case GL_TRIANGLE_STRIP:
+ case GL_TRIANGLE_FAN:
+ case GL_TRIANGLES:
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ if (count == 0 || !c->arrays.vertex.enable)
+ return;
+ if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
+ return; // all triangles are culled
+
+ validate_arrays(c, mode);
+ drawArraysPrims[mode](c, first, count);
+
+#if VC_CACHE_STATISTICS
+ c->vc.total = count;
+ c->vc.dump_stats(mode);
+#endif
+}
+
+void glDrawElements(
+ GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (count<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ switch (mode) {
+ case GL_POINTS:
+ case GL_LINE_STRIP:
+ case GL_LINE_LOOP:
+ case GL_LINES:
+ case GL_TRIANGLE_STRIP:
+ case GL_TRIANGLE_FAN:
+ case GL_TRIANGLES:
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_SHORT:
+ c->arrays.indicesType = type;
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (count == 0 || !c->arrays.vertex.enable)
+ return;
+ if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
+ return; // all triangles are culled
+
+ // clear the vertex-cache
+ c->vc.clear();
+ validate_arrays(c, mode);
+
+ // if indices are in a buffer object, the pointer is treated as an
+ // offset in that buffer.
+ if (c->arrays.element_array_buffer) {
+ indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
+ }
+
+ drawElementsPrims[mode](c, count, indices);
+
+#if VC_CACHE_STATISTICS
+ c->vc.total = count;
+ c->vc.dump_stats(mode);
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// buffers
+// ----------------------------------------------------------------------------
+
+void glBindBuffer(GLenum target, GLuint buffer)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ // create a buffer object, or bind an existing one
+ buffer_t const* bo = 0;
+ if (buffer) {
+ bo = c->bufferObjectManager->bind(buffer);
+ if (!bo) {
+ ogles_error(c, GL_OUT_OF_MEMORY);
+ return;
+ }
+ }
+ ((target == GL_ARRAY_BUFFER) ?
+ c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
+}
+
+void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (size<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
+ c->arrays.array_buffer : c->arrays.element_array_buffer);
+
+ if (bo == 0) {
+ // can't modify buffer 0
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+
+ buffer_t* edit_bo = const_cast<buffer_t*>(bo);
+ if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) {
+ ogles_error(c, GL_OUT_OF_MEMORY);
+ return;
+ }
+ if (data) {
+ memcpy(bo->data, data, size);
+ }
+}
+
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (offset<0 || size<0 || data==0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
+ c->arrays.array_buffer : c->arrays.element_array_buffer);
+
+ if (bo == 0) {
+ // can't modify buffer 0
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+ if (offset+size > bo->size) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ memcpy(bo->data + offset, data, size);
+}
+
+void glDeleteBuffers(GLsizei n, const GLuint* buffers)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (n<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ for (int i=0 ; i<n ; i++) {
+ GLuint name = buffers[i];
+ if (name) {
+ // unbind bound deleted buffers...
+ if (c->arrays.element_array_buffer->name == name) {
+ c->arrays.element_array_buffer = 0;
+ }
+ if (c->arrays.array_buffer->name == name) {
+ c->arrays.array_buffer = 0;
+ }
+ if (c->arrays.vertex.bo->name == name) {
+ c->arrays.vertex.bo = 0;
+ }
+ if (c->arrays.normal.bo->name == name) {
+ c->arrays.normal.bo = 0;
+ }
+ if (c->arrays.color.bo->name == name) {
+ c->arrays.color.bo = 0;
+ }
+ for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
+ if (c->arrays.texture[t].bo->name == name) {
+ c->arrays.texture[t].bo = 0;
+ }
+ }
+ }
+ }
+ c->bufferObjectManager->deleteBuffers(n, buffers);
+ c->bufferObjectManager->recycleTokens(n, buffers);
+}
+
+void glGenBuffers(GLsizei n, GLuint* buffers)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (n<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ c->bufferObjectManager->getToken(n, buffers);
+}
diff --git a/opengl/libagl/array.h b/opengl/libagl/array.h
new file mode 100644
index 0000000..e156978
--- /dev/null
+++ b/opengl/libagl/array.h
@@ -0,0 +1,37 @@
+/* libs/opengles/array.h
+**
+** Copyright 2006, 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_OPENGLES_ARRAY_H
+#define ANDROID_OPENGLES_ARRAY_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+namespace android {
+
+namespace gl {
+struct ogles_context_t;
+};
+
+void ogles_init_array(ogles_context_t* c);
+void ogles_uninit_array(ogles_context_t* c);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_ARRAY_H
+
diff --git a/opengl/libagl/context.h b/opengl/libagl/context.h
new file mode 100644
index 0000000..ef36b56
--- /dev/null
+++ b/opengl/libagl/context.h
@@ -0,0 +1,20 @@
+/* libs/opengles/context.h
+**
+** Copyright 2006, 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.
+*/
+
+#include <private/opengles/gl_context.h>
+
+using namespace android::gl;
diff --git a/opengl/libagl/dxt.cpp b/opengl/libagl/dxt.cpp
new file mode 100644
index 0000000..238c81f
--- /dev/null
+++ b/opengl/libagl/dxt.cpp
@@ -0,0 +1,636 @@
+/* libs/opengles/dxt.cpp
+**
+** 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.
+*/
+
+#define TIMING 0
+
+#if TIMING
+#include <sys/time.h> // for optimization timing
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+#include <GLES/gl.h>
+#include <utils/Endian.h>
+
+#include "context.h"
+
+#define TIMING 0
+
+namespace android {
+
+static uint8_t avg23tab[64*64];
+static volatile int tables_initialized = 0;
+
+// Definitions below are equivalent to these over the valid range of arguments
+// #define div5(x) ((x)/5)
+// #define div7(x) ((x)/7)
+
+// Use fixed-point to divide by 5 and 7
+// 3277 = 2^14/5 + 1
+// 2341 = 2^14/7 + 1
+#define div5(x) (((x)*3277) >> 14)
+#define div7(x) (((x)*2341) >> 14)
+
+// Table with entry [a << 6 | b] = (2*a + b)/3 for 0 <= a,b < 64
+#define avg23(x0,x1) avg23tab[((x0) << 6) | (x1)]
+
+// Extract 5/6/5 RGB
+#define red(x) (((x) >> 11) & 0x1f)
+#define green(x) (((x) >> 5) & 0x3f)
+#define blue(x) ( (x) & 0x1f)
+
+/*
+ * Convert 5/6/5 RGB (as 3 ints) to 8/8/8
+ *
+ * Operation count: 8 <<, 0 &, 5 |
+ */
+inline static int rgb565SepTo888(int r, int g, int b)
+
+{
+ return ((((r << 3) | (r >> 2)) << 16) |
+ (((g << 2) | (g >> 4)) << 8) |
+ ((b << 3) | (b >> 2)));
+}
+
+/*
+ * Convert 5/6/5 RGB (as a single 16-bit word) to 8/8/8
+ *
+ * r4r3r2r1 r0g5g4g3 g2g1g0b4 b3b2b1b0 rgb
+ * r4r3r2 r1r0g5g4 g3g2g1g0 b4b3b2b1 b0 0 0 0 rgb << 3
+ * r4r3r2r1 r0r4r3r2 g5g4g3g2 g1g0g5g4 b4b3b2b1 b0b4b3b2 desired result
+ *
+ * Construct the 24-bit RGB word as:
+ *
+ * r4r3r2r1 r0------ -------- -------- -------- -------- (rgb << 8) & 0xf80000
+ * r4r3r2 -------- -------- -------- -------- (rgb << 3) & 0x070000
+ * g5g4g3g2 g1g0---- -------- -------- (rgb << 5) & 0x00fc00
+ * g5g4 -------- -------- (rgb >> 1) & 0x000300
+ * b4b3b2b1 b0------ (rgb << 3) & 0x0000f8
+ * b4b3b2 (rgb >> 2) & 0x000007
+ *
+ * Operation count: 5 <<, 6 &, 5 | (n.b. rgb >> 3 is used twice)
+ */
+inline static int rgb565To888(int rgb)
+
+{
+ int rgb3 = rgb >> 3;
+ return (((rgb << 8) & 0xf80000) |
+ ( rgb3 & 0x070000) |
+ ((rgb << 5) & 0x00fc00) |
+ ((rgb >> 1) & 0x000300) |
+ ( rgb3 & 0x0000f8) |
+ ((rgb >> 2) & 0x000007));
+}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static uint32_t swap(uint32_t x) {
+ int b0 = (x >> 24) & 0xff;
+ int b1 = (x >> 16) & 0xff;
+ int b2 = (x >> 8) & 0xff;
+ int b3 = (x ) & 0xff;
+
+ return (uint32_t)((b3 << 24) | (b2 << 16) | (b1 << 8) | b0);
+}
+#endif
+
+static void
+init_tables()
+{
+ if (tables_initialized) {
+ return;
+ }
+
+ for (int i = 0; i < 64; i++) {
+ for (int j = 0; j < 64; j++) {
+ int avg = (2*i + j)/3;
+ avg23tab[(i << 6) | j] = avg;
+ }
+ }
+
+ asm volatile ("" : : : "memory");
+ tables_initialized = 1;
+}
+
+/*
+ * Utility to scan a DXT1 compressed texture to determine whether it
+ * contains a transparent pixel (color0 < color1, code == 3). This
+ * may be useful if the application lacks information as to whether
+ * the true format is GL_COMPRESSED_RGB_S3TC_DXT1_EXT or
+ * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT.
+ */
+bool
+DXT1HasAlpha(const GLvoid *data, int width, int height) {
+#if TIMING
+ struct timeval start_t, end_t;
+ struct timezone tz;
+
+ gettimeofday(&start_t, &tz);
+#endif
+
+ bool hasAlpha = false;
+
+ int xblocks = (width + 3)/4;
+ int yblocks = (height + 3)/4;
+ int numblocks = xblocks*yblocks;
+
+ uint32_t const *d32 = (uint32_t *)data;
+ for (int b = 0; b < numblocks; b++) {
+ uint32_t colors = *d32++;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ colors = swap(colors);
+#endif
+
+ uint16_t color0 = colors & 0xffff;
+ uint16_t color1 = colors >> 16;
+
+ if (color0 < color1) {
+ // There's no need to endian-swap within 'bits'
+ // since we don't care which pixel is the transparent one
+ uint32_t bits = *d32++;
+
+ // Detect if any (odd, even) pair of bits are '11'
+ // bits: b31 b30 b29 ... b3 b2 b1 b0
+ // bits >> 1: b31 b31 b30 ... b4 b3 b2 b1
+ // &: b31 (b31 & b30) (b29 & b28) ... (b2 & b1) (b1 & b0)
+ // & 0x55..: 0 (b31 & b30) 0 ... 0 (b1 & b0)
+ if (((bits & (bits >> 1)) & 0x55555555) != 0) {
+ hasAlpha = true;
+ goto done;
+ }
+ } else {
+ // Skip 4 bytes
+ ++d32;
+ }
+ }
+
+ done:
+#if TIMING
+ gettimeofday(&end_t, &tz);
+ long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 +
+ (end_t.tv_usec - start_t.tv_usec);
+
+ printf("Scanned w=%d h=%d in %ld usec\n", width, height, usec);
+#endif
+
+ return hasAlpha;
+}
+
+static void
+decodeDXT1(const GLvoid *data, int width, int height,
+ void *surface, int stride,
+ bool hasAlpha)
+
+{
+ init_tables();
+
+ uint32_t const *d32 = (uint32_t *)data;
+
+ // Color table for the current block
+ uint16_t c[4];
+ c[0] = c[1] = c[2] = c[3] = 0;
+
+ // Specified colors from the previous block
+ uint16_t prev_color0 = 0x0000;
+ uint16_t prev_color1 = 0x0000;
+
+ uint16_t* rowPtr = (uint16_t*)surface;
+ for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
+ uint16_t *blockPtr = rowPtr;
+ for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
+ uint32_t colors = *d32++;
+ uint32_t bits = *d32++;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ colors = swap(colors);
+ bits = swap(bits);
+#endif
+
+ // Raw colors
+ uint16_t color0 = colors & 0xffff;
+ uint16_t color1 = colors >> 16;
+
+ // If the new block has the same base colors as the
+ // previous one, we don't need to recompute the color
+ // table c[]
+ if (color0 != prev_color0 || color1 != prev_color1) {
+ // Store raw colors for comparison with next block
+ prev_color0 = color0;
+ prev_color1 = color1;
+
+ int r0 = red(color0);
+ int g0 = green(color0);
+ int b0 = blue(color0);
+
+ int r1 = red(color1);
+ int g1 = green(color1);
+ int b1 = blue(color1);
+
+ if (hasAlpha) {
+ c[0] = (r0 << 11) | ((g0 >> 1) << 6) | (b0 << 1) | 0x1;
+ c[1] = (r1 << 11) | ((g1 >> 1) << 6) | (b1 << 1) | 0x1;
+ } else {
+ c[0] = color0;
+ c[1] = color1;
+ }
+
+ int r2, g2, b2, r3, g3, b3, a3;
+
+ int bbits = bits >> 1;
+ bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
+ bool has3 = ((bbits & bits) & 0x55555555) != 0;
+
+ if (has2 || has3) {
+ if (color0 > color1) {
+ r2 = avg23(r0, r1);
+ g2 = avg23(g0, g1);
+ b2 = avg23(b0, b1);
+
+ r3 = avg23(r1, r0);
+ g3 = avg23(g1, g0);
+ b3 = avg23(b1, b0);
+ a3 = 1;
+ } else {
+ r2 = (r0 + r1) >> 1;
+ g2 = (g0 + g1) >> 1;
+ b2 = (b0 + b1) >> 1;
+
+ r3 = g3 = b3 = a3 = 0;
+ }
+ if (hasAlpha) {
+ c[2] = (r2 << 11) | ((g2 >> 1) << 6) |
+ (b2 << 1) | 0x1;
+ c[3] = (r3 << 11) | ((g3 >> 1) << 6) |
+ (b3 << 1) | a3;
+ } else {
+ c[2] = (r2 << 11) | (g2 << 5) | b2;
+ c[3] = (r3 << 11) | (g3 << 5) | b3;
+ }
+ }
+ }
+
+ uint16_t* blockRowPtr = blockPtr;
+ for (int y = 0; y < 4; y++, blockRowPtr += stride) {
+ // Don't process rows past the botom
+ if (base_y + y >= height) {
+ break;
+ }
+
+ int w = min(width - base_x, 4);
+ for (int x = 0; x < w; x++) {
+ int code = bits & 0x3;
+ bits >>= 2;
+
+ blockRowPtr[x] = c[code];
+ }
+ }
+ }
+ }
+}
+
+// Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE
+static void
+decodeDXT3(const GLvoid *data, int width, int height,
+ void *surface, int stride)
+
+{
+ init_tables();
+
+ uint32_t const *d32 = (uint32_t *)data;
+
+ // Specified colors from the previous block
+ uint16_t prev_color0 = 0x0000;
+ uint16_t prev_color1 = 0x0000;
+
+ // Color table for the current block
+ uint32_t c[4];
+ c[0] = c[1] = c[2] = c[3] = 0;
+
+ uint32_t* rowPtr = (uint32_t*)surface;
+ for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
+ uint32_t *blockPtr = rowPtr;
+ for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ uint32_t alphahi = *d32++;
+ uint32_t alphalo = *d32++;
+ alphahi = swap(alphahi);
+ alphalo = swap(alphalo);
+#else
+ uint32_t alphalo = *d32++;
+ uint32_t alphahi = *d32++;
+#endif
+
+ uint32_t colors = *d32++;
+ uint32_t bits = *d32++;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ colors = swap(colors);
+ bits = swap(bits);
+#endif
+
+ uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo;
+
+ // Raw colors
+ uint16_t color0 = colors & 0xffff;
+ uint16_t color1 = colors >> 16;
+
+ // If the new block has the same base colors as the
+ // previous one, we don't need to recompute the color
+ // table c[]
+ if (color0 != prev_color0 || color1 != prev_color1) {
+ // Store raw colors for comparison with next block
+ prev_color0 = color0;
+ prev_color1 = color1;
+
+ int bbits = bits >> 1;
+ bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
+ bool has3 = ((bbits & bits) & 0x55555555) != 0;
+
+ if (has2 || has3) {
+ int r0 = red(color0);
+ int g0 = green(color0);
+ int b0 = blue(color0);
+
+ int r1 = red(color1);
+ int g1 = green(color1);
+ int b1 = blue(color1);
+
+ int r2 = avg23(r0, r1);
+ int g2 = avg23(g0, g1);
+ int b2 = avg23(b0, b1);
+
+ int r3 = avg23(r1, r0);
+ int g3 = avg23(g1, g0);
+ int b3 = avg23(b1, b0);
+
+ c[0] = rgb565SepTo888(r0, g0, b0);
+ c[1] = rgb565SepTo888(r1, g1, b1);
+ c[2] = rgb565SepTo888(r2, g2, b2);
+ c[3] = rgb565SepTo888(r3, g3, b3);
+ } else {
+ // Convert to 8 bits
+ c[0] = rgb565To888(color0);
+ c[1] = rgb565To888(color1);
+ }
+ }
+
+ uint32_t* blockRowPtr = blockPtr;
+ for (int y = 0; y < 4; y++, blockRowPtr += stride) {
+ // Don't process rows past the botom
+ if (base_y + y >= height) {
+ break;
+ }
+
+ int w = min(width - base_x, 4);
+ for (int x = 0; x < w; x++) {
+ int a = alpha & 0xf;
+ alpha >>= 4;
+
+ int code = bits & 0x3;
+ bits >>= 2;
+
+ blockRowPtr[x] = c[code] | (a << 28) | (a << 24);
+ }
+ }
+ }
+ }
+}
+
+// Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE
+static void
+decodeDXT5(const GLvoid *data, int width, int height,
+ void *surface, int stride)
+
+{
+ init_tables();
+
+ uint32_t const *d32 = (uint32_t *)data;
+
+ // Specified alphas from the previous block
+ uint8_t prev_alpha0 = 0x00;
+ uint8_t prev_alpha1 = 0x00;
+
+ // Specified colors from the previous block
+ uint16_t prev_color0 = 0x0000;
+ uint16_t prev_color1 = 0x0000;
+
+ // Alpha table for the current block
+ uint8_t a[8];
+ a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = 0;
+
+ // Color table for the current block
+ uint32_t c[4];
+ c[0] = c[1] = c[2] = c[3] = 0;
+
+ int good_a5 = 0;
+ int bad_a5 = 0;
+ int good_a6 = 0;
+ int bad_a6 = 0;
+ int good_a7 = 0;
+ int bad_a7 = 0;
+
+ uint32_t* rowPtr = (uint32_t*)surface;
+ for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
+ uint32_t *blockPtr = rowPtr;
+ for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ uint32_t alphahi = *d32++;
+ uint32_t alphalo = *d32++;
+ alphahi = swap(alphahi);
+ alphalo = swap(alphalo);
+#else
+ uint32_t alphalo = *d32++;
+ uint32_t alphahi = *d32++;
+#endif
+
+ uint32_t colors = *d32++;
+ uint32_t bits = *d32++;
+
+#if __BYTE_ORDER == __BIG_ENDIANx
+ colors = swap(colors);
+ bits = swap(bits);
+#endif
+
+ uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo;
+ uint64_t alpha0 = alpha & 0xff;
+ alpha >>= 8;
+ uint64_t alpha1 = alpha & 0xff;
+ alpha >>= 8;
+
+ if (alpha0 != prev_alpha0 || alpha1 != prev_alpha1) {
+ prev_alpha0 = alpha0;
+ prev_alpha1 = alpha1;
+
+ a[0] = alpha0;
+ a[1] = alpha1;
+ int a01 = alpha0 + alpha1 - 1;
+ if (alpha0 > alpha1) {
+ a[2] = div7(6*alpha0 + alpha1);
+ a[4] = div7(4*alpha0 + 3*alpha1);
+ a[6] = div7(2*alpha0 + 5*alpha1);
+
+ // Use symmetry to derive half of the values
+ // A few values will be off by 1 (~.5%)
+ // Alternate which values are computed directly
+ // and which are derived to try to reduce bias
+ a[3] = a01 - a[6];
+ a[5] = a01 - a[4];
+ a[7] = a01 - a[2];
+ } else {
+ a[2] = div5(4*alpha0 + alpha1);
+ a[4] = div5(2*alpha0 + 3*alpha1);
+ a[3] = a01 - a[4];
+ a[5] = a01 - a[2];
+ a[6] = 0x00;
+ a[7] = 0xff;
+ }
+ }
+
+ // Raw colors
+ uint16_t color0 = colors & 0xffff;
+ uint16_t color1 = colors >> 16;
+
+ // If the new block has the same base colors as the
+ // previous one, we don't need to recompute the color
+ // table c[]
+ if (color0 != prev_color0 || color1 != prev_color1) {
+ // Store raw colors for comparison with next block
+ prev_color0 = color0;
+ prev_color1 = color1;
+
+ int bbits = bits >> 1;
+ bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
+ bool has3 = ((bbits & bits) & 0x55555555) != 0;
+
+ if (has2 || has3) {
+ int r0 = red(color0);
+ int g0 = green(color0);
+ int b0 = blue(color0);
+
+ int r1 = red(color1);
+ int g1 = green(color1);
+ int b1 = blue(color1);
+
+ int r2 = avg23(r0, r1);
+ int g2 = avg23(g0, g1);
+ int b2 = avg23(b0, b1);
+
+ int r3 = avg23(r1, r0);
+ int g3 = avg23(g1, g0);
+ int b3 = avg23(b1, b0);
+
+ c[0] = rgb565SepTo888(r0, g0, b0);
+ c[1] = rgb565SepTo888(r1, g1, b1);
+ c[2] = rgb565SepTo888(r2, g2, b2);
+ c[3] = rgb565SepTo888(r3, g3, b3);
+ } else {
+ // Convert to 8 bits
+ c[0] = rgb565To888(color0);
+ c[1] = rgb565To888(color1);
+ }
+ }
+
+ uint32_t* blockRowPtr = blockPtr;
+ for (int y = 0; y < 4; y++, blockRowPtr += stride) {
+ // Don't process rows past the botom
+ if (base_y + y >= height) {
+ break;
+ }
+
+ int w = min(width - base_x, 4);
+ for (int x = 0; x < w; x++) {
+ int acode = alpha & 0x7;
+ alpha >>= 3;
+
+ int code = bits & 0x3;
+ bits >>= 2;
+
+ blockRowPtr[x] = c[code] | (a[acode] << 24);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Decode a DXT-compressed texture into memory. DXT textures consist of
+ * a series of 4x4 pixel blocks in left-to-right, top-down order.
+ * The number of blocks is given by ceil(width/4)*ceil(height/4).
+ *
+ * 'data' points to the texture data. 'width' and 'height' indicate the
+ * dimensions of the texture. We assume width and height are >= 0 but
+ * do not require them to be powers of 2 or divisible by any factor.
+ *
+ * The output is written to 'surface' with each scanline separated by
+ * 'stride' 2- or 4-byte words.
+ *
+ * 'format' indicates the type of compression and must be one of the following:
+ *
+ * GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ * The output is written as 5/6/5 opaque RGB (16 bit words).
+ * 8 bytes are read from 'data' for each block.
+ *
+ * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
+ * The output is written as 5/5/5/1 RGBA (16 bit words)
+ * 8 bytes are read from 'data' for each block.
+ *
+ * GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
+ * GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
+ * The output is written as 8/8/8/8 ARGB (32 bit words)
+ * 16 bytes are read from 'data' for each block.
+ */
+void
+decodeDXT(const GLvoid *data, int width, int height,
+ void *surface, int stride, int format)
+{
+#if TIMING
+ struct timeval start_t, end_t;
+ struct timezone tz;
+
+ gettimeofday(&start_t, &tz);
+#endif
+
+ switch (format) {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ decodeDXT1(data, width, height, surface, stride, false);
+ break;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ decodeDXT1(data, width, height, surface, stride, true);
+ break;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ decodeDXT3(data, width, height, surface, stride);
+ break;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ decodeDXT5(data, width, height, surface, stride);
+ break;
+ }
+
+#if TIMING
+ gettimeofday(&end_t, &tz);
+ long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 +
+ (end_t.tv_usec - start_t.tv_usec);
+
+ printf("Loaded w=%d h=%d in %ld usec\n", width, height, usec);
+#endif
+}
+
+} // namespace android
diff --git a/opengl/libagl/dxt.h b/opengl/libagl/dxt.h
new file mode 100644
index 0000000..d95a36c
--- /dev/null
+++ b/opengl/libagl/dxt.h
@@ -0,0 +1,33 @@
+/* libs/opengles/dxt.h
+**
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_TEXTURE_H
+#define ANDROID_OPENGLES_TEXTURE_H
+
+#include <stdlib.h>
+
+#include <GLES/gl.h>
+
+namespace android {
+
+ bool DXT1HasAlpha(const GLvoid *data, int width, int height);
+ void decodeDXT(const GLvoid *data, int width, int height,
+ void *surface, int stride, int format);
+
+} // namespace android
+
+#endif // ANDROID_OPENGLES_TEXTURE_H
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
new file mode 100644
index 0000000..854a49e
--- /dev/null
+++ b/opengl/libagl/egl.cpp
@@ -0,0 +1,1513 @@
+/*
+**
+** 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.
+*/
+
+#define LOG_TAG "EGL"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+
+#include <utils/threads.h>
+
+#include <GLES/egl.h>
+
+#include <pixelflinger/format.h>
+
+#include "context.h"
+#include "state.h"
+#include "texture.h"
+#include "matrix.h"
+
+#undef NELEM
+#define NELEM(x) (sizeof(x)/sizeof(*(x)))
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+const unsigned int NUM_DISPLAYS = 1;
+
+static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_key_t gEGLErrorKey = -1;
+#ifndef HAVE_ANDROID_OS
+namespace gl {
+pthread_key_t gGLKey = -1;
+}; // namspace gl
+#endif
+
+template<typename T>
+static T setError(GLint error, T returnValue) {
+ if (ggl_unlikely(gEGLErrorKey == -1)) {
+ pthread_mutex_lock(&gErrorKeyMutex);
+ if (gEGLErrorKey == -1)
+ pthread_key_create(&gEGLErrorKey, NULL);
+ pthread_mutex_unlock(&gErrorKeyMutex);
+ }
+ pthread_setspecific(gEGLErrorKey, (void*)error);
+ return returnValue;
+}
+
+static GLint getError() {
+ if (ggl_unlikely(gEGLErrorKey == -1))
+ return EGL_SUCCESS;
+ GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
+ pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
+ return error;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_display_t
+{
+ egl_display_t() : type(0), initialized(0) { }
+
+ static egl_display_t& get_display(EGLDisplay dpy);
+
+ static EGLBoolean is_valid(EGLDisplay dpy) {
+ return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
+ }
+
+ NativeDisplayType type;
+ volatile int32_t initialized;
+};
+
+static egl_display_t gDisplays[NUM_DISPLAYS];
+
+egl_display_t& egl_display_t::get_display(EGLDisplay dpy) {
+ return gDisplays[uintptr_t(dpy)-1U];
+}
+
+struct egl_context_t {
+ enum {
+ IS_CURRENT = 0x00010000,
+ NEVER_CURRENT = 0x00020000
+ };
+ uint32_t flags;
+ EGLDisplay dpy;
+ EGLConfig config;
+ EGLSurface read;
+ EGLSurface draw;
+
+ static inline egl_context_t* context(EGLContext ctx) {
+ ogles_context_t* const gl = static_cast<ogles_context_t*>(ctx);
+ return static_cast<egl_context_t*>(gl->rasterizer.base);
+ }
+};
+
+// ----------------------------------------------------------------------------
+
+struct egl_surface_t
+{
+ enum {
+ PAGE_FLIP = 0x00000001,
+ MAGIC = 0x31415265
+ };
+
+ uint32_t magic;
+ EGLDisplay dpy;
+ EGLConfig config;
+ EGLContext ctx;
+
+ egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
+ virtual ~egl_surface_t();
+ virtual bool isValid() const = 0;
+
+ virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0;
+ virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0;
+ virtual EGLint getWidth() const = 0;
+ virtual EGLint getHeight() const = 0;
+ virtual void* getBits() const = 0;
+
+ virtual EGLint getHorizontalResolution() const;
+ virtual EGLint getVerticalResolution() const;
+ virtual EGLint getRefreshRate() const;
+ virtual EGLint getSwapBehavior() const;
+ virtual EGLBoolean swapBuffers();
+ virtual EGLBoolean swapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+protected:
+ GGLSurface depth;
+};
+
+egl_surface_t::egl_surface_t(EGLDisplay dpy,
+ EGLConfig config,
+ int32_t depthFormat)
+ : magic(0x31415265), dpy(dpy), config(config), ctx(0)
+{
+ depth.version = sizeof(GGLSurface);
+ depth.data = 0;
+ depth.format = depthFormat;
+}
+egl_surface_t::~egl_surface_t()
+{
+ magic = 0;
+ free(depth.data);
+}
+EGLBoolean egl_surface_t::swapBuffers() {
+ return EGL_FALSE;
+}
+EGLBoolean egl_surface_t::swapRectangle(
+ EGLint l, EGLint t, EGLint w, EGLint h) {
+ return EGL_FALSE;
+}
+EGLint egl_surface_t::getHorizontalResolution() const {
+ return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_surface_t::getVerticalResolution() const {
+ return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_surface_t::getRefreshRate() const {
+ return (60 * EGL_DISPLAY_SCALING);
+}
+EGLint egl_surface_t::getSwapBehavior() const {
+ return EGL_BUFFER_PRESERVED;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_window_surface_t : public egl_surface_t
+{
+ egl_window_surface_t(
+ EGLDisplay dpy, EGLConfig config,
+ int32_t depthFormat,
+ egl_native_window_t* window);
+
+ ~egl_window_surface_t();
+
+ virtual bool isValid() const { return nativeWindow->magic == 0x600913; }
+ virtual EGLBoolean swapBuffers();
+ virtual EGLBoolean swapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+ virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
+ virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
+ virtual EGLint getWidth() const { return nativeWindow->width; }
+ virtual EGLint getHeight() const { return nativeWindow->height; }
+ virtual void* getBits() const;
+ virtual EGLint getHorizontalResolution() const;
+ virtual EGLint getVerticalResolution() const;
+ virtual EGLint getRefreshRate() const;
+ virtual EGLint getSwapBehavior() const;
+private:
+ egl_native_window_t* nativeWindow;
+};
+
+egl_window_surface_t::egl_window_surface_t(EGLDisplay dpy,
+ EGLConfig config,
+ int32_t depthFormat,
+ egl_native_window_t* window)
+ : egl_surface_t(dpy, config, depthFormat), nativeWindow(window)
+{
+ if (depthFormat) {
+ depth.width = window->width;
+ depth.height = window->height;
+ depth.stride = depth.width; // use the width here
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ return;
+ }
+ }
+ nativeWindow->incRef(nativeWindow);
+}
+egl_window_surface_t::~egl_window_surface_t() {
+ nativeWindow->decRef(nativeWindow);
+}
+
+EGLBoolean egl_window_surface_t::swapBuffers()
+{
+ uint32_t flags = nativeWindow->swapBuffers(nativeWindow);
+ if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
+ // TODO: we probaly should reset the swap rect here
+ // if the window size has changed
+ // window->setSwapRectangle(Rect(info.w, info.h));
+ if (depth.data) {
+ free(depth.data);
+ depth.width = nativeWindow->width;
+ depth.height = nativeWindow->height;
+ depth.stride = nativeWindow->stride;
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ return EGL_FALSE;
+ }
+ }
+ }
+ return EGL_TRUE;
+}
+
+EGLBoolean egl_window_surface_t::swapRectangle(
+ EGLint l, EGLint t, EGLint w, EGLint h)
+{
+ nativeWindow->setSwapRectangle(nativeWindow, l, t, w, h);
+ return EGL_TRUE;
+}
+EGLBoolean egl_window_surface_t::bindDrawSurface(ogles_context_t* gl)
+{
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = nativeWindow->width;
+ buffer.height = nativeWindow->height;
+ buffer.stride = nativeWindow->stride;
+ buffer.data = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
+ buffer.format = nativeWindow->format;
+ gl->rasterizer.procs.colorBuffer(gl, &buffer);
+ if (depth.data != gl->rasterizer.state.buffers.depth.data)
+ gl->rasterizer.procs.depthBuffer(gl, &depth);
+ return EGL_TRUE;
+}
+EGLBoolean egl_window_surface_t::bindReadSurface(ogles_context_t* gl)
+{
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = nativeWindow->width;
+ buffer.height = nativeWindow->height;
+ buffer.stride = nativeWindow->stride;
+ buffer.data = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
+ buffer.format = nativeWindow->format;
+ gl->rasterizer.procs.readBuffer(gl, &buffer);
+ return EGL_TRUE;
+}
+void* egl_window_surface_t::getBits() const {
+ return (GGLubyte*)nativeWindow->base + nativeWindow->offset;
+}
+EGLint egl_window_surface_t::getHorizontalResolution() const {
+ return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_window_surface_t::getVerticalResolution() const {
+ return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+}
+EGLint egl_window_surface_t::getRefreshRate() const {
+ return (nativeWindow->fps * EGL_DISPLAY_SCALING);
+}
+EGLint egl_window_surface_t::getSwapBehavior() const {
+ uint32_t flags = nativeWindow->flags;
+ if (flags & EGL_NATIVES_FLAG_DESTROY_BACKBUFFER)
+ return EGL_BUFFER_DESTROYED;
+ return EGL_BUFFER_PRESERVED;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_pixmap_surface_t : public egl_surface_t
+{
+ egl_pixmap_surface_t(
+ EGLDisplay dpy, EGLConfig config,
+ int32_t depthFormat,
+ egl_native_pixmap_t const * pixmap);
+
+ virtual ~egl_pixmap_surface_t() { }
+
+ virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
+ virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
+ virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
+ virtual EGLint getWidth() const { return nativePixmap.width; }
+ virtual EGLint getHeight() const { return nativePixmap.height; }
+ virtual void* getBits() const { return nativePixmap.data; }
+private:
+ egl_native_pixmap_t nativePixmap;
+};
+
+egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
+ EGLConfig config,
+ int32_t depthFormat,
+ egl_native_pixmap_t const * pixmap)
+ : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
+{
+ if (depthFormat) {
+ depth.width = pixmap->width;
+ depth.height = pixmap->height;
+ depth.stride = depth.width; // use the width here
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ return;
+ }
+ }
+}
+EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
+{
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = nativePixmap.width;
+ buffer.height = nativePixmap.height;
+ buffer.stride = nativePixmap.stride;
+ buffer.data = nativePixmap.data;
+ buffer.format = nativePixmap.format;
+
+ gl->rasterizer.procs.colorBuffer(gl, &buffer);
+ if (depth.data != gl->rasterizer.state.buffers.depth.data)
+ gl->rasterizer.procs.depthBuffer(gl, &depth);
+ return EGL_TRUE;
+}
+EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl)
+{
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = nativePixmap.width;
+ buffer.height = nativePixmap.height;
+ buffer.stride = nativePixmap.stride;
+ buffer.data = nativePixmap.data;
+ buffer.format = nativePixmap.format;
+ gl->rasterizer.procs.readBuffer(gl, &buffer);
+ return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+
+struct egl_pbuffer_surface_t : public egl_surface_t
+{
+ egl_pbuffer_surface_t(
+ EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
+ int32_t w, int32_t h, int32_t f);
+
+ virtual ~egl_pbuffer_surface_t();
+
+ virtual bool isValid() const { return pbuffer.data != 0; }
+ virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
+ virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
+ virtual EGLint getWidth() const { return pbuffer.width; }
+ virtual EGLint getHeight() const { return pbuffer.height; }
+ virtual void* getBits() const { return pbuffer.data; }
+private:
+ GGLSurface pbuffer;
+};
+
+egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
+ EGLConfig config, int32_t depthFormat,
+ int32_t w, int32_t h, int32_t f)
+ : egl_surface_t(dpy, config, depthFormat)
+{
+ size_t size = w*h;
+ switch (f) {
+ case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
+ case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
+ default:
+ LOGE("incompatible pixel format for pbuffer (format=%d)", f);
+ pbuffer.data = 0;
+ break;
+ }
+ pbuffer.version = sizeof(GGLSurface);
+ pbuffer.width = w;
+ pbuffer.height = h;
+ pbuffer.stride = w;
+ pbuffer.data = (GGLubyte*)malloc(size);
+ pbuffer.format = f;
+
+ if (depthFormat) {
+ depth.width = pbuffer.width;
+ depth.height = pbuffer.height;
+ depth.stride = depth.width; // use the width here
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ return;
+ }
+ }
+}
+egl_pbuffer_surface_t::~egl_pbuffer_surface_t() {
+ free(pbuffer.data);
+}
+EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl)
+{
+ gl->rasterizer.procs.colorBuffer(gl, &pbuffer);
+ if (depth.data != gl->rasterizer.state.buffers.depth.data)
+ gl->rasterizer.procs.depthBuffer(gl, &depth);
+ return EGL_TRUE;
+}
+EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl)
+{
+ gl->rasterizer.procs.readBuffer(gl, &pbuffer);
+ return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+
+struct config_pair_t {
+ GLint key;
+ GLint value;
+};
+
+struct configs_t {
+ const config_pair_t* array;
+ int size;
+};
+
+struct config_management_t {
+ GLint key;
+ bool (*match)(GLint reqValue, GLint confValue);
+ static bool atLeast(GLint reqValue, GLint confValue) {
+ return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
+ }
+ static bool exact(GLint reqValue, GLint confValue) {
+ return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
+ }
+ static bool mask(GLint reqValue, GLint confValue) {
+ return (confValue & reqValue) == reqValue;
+ }
+};
+
+// ----------------------------------------------------------------------------
+
+static char const * const gVendorString = "Google Inc.";
+static char const * const gVersionString = "1.2 Android Driver";
+static char const * const gClientApiString = "OpenGL ES";
+static char const * const gExtensionsString =
+ "EGL_ANDROID_swap_rectangle" " "
+ "EGL_ANDROID_copy_front_to_back" " "
+ "EGL_ANDROID_get_render_buffer_address"
+ ;
+
+// ----------------------------------------------------------------------------
+
+struct extention_map_t {
+ const char * const name;
+ void (*address)(void);
+};
+
+static const extention_map_t gExtentionMap[] = {
+ { "eglSwapRectangleANDROID", (void(*)())&eglSwapRectangleANDROID },
+ { "glDrawTexsOES", (void(*)())&glDrawTexsOES },
+ { "glDrawTexiOES", (void(*)())&glDrawTexiOES },
+ { "glDrawTexfOES", (void(*)())&glDrawTexfOES },
+ { "glDrawTexxOES", (void(*)())&glDrawTexxOES },
+ { "glDrawTexsvOES", (void(*)())&glDrawTexsvOES },
+ { "glDrawTexivOES", (void(*)())&glDrawTexivOES },
+ { "glDrawTexfvOES", (void(*)())&glDrawTexfvOES },
+ { "glDrawTexxvOES", (void(*)())&glDrawTexxvOES },
+ { "glQueryMatrixxOES", (void(*)())&glQueryMatrixxOES },
+ { "glClipPlanef", (void(*)())&glClipPlanef },
+ { "glClipPlanex", (void(*)())&glClipPlanex },
+ { "glBindBuffer", (void(*)())&glBindBuffer },
+ { "glBufferData", (void(*)())&glBufferData },
+ { "glBufferSubData", (void(*)())&glBufferSubData },
+ { "glDeleteBuffers", (void(*)())&glDeleteBuffers },
+ { "glGenBuffers", (void(*)())&glGenBuffers },
+};
+
+/*
+ * In the lists below, attributes names MUST be sorted.
+ * Additinnaly, all configs must be sorted according to
+ * the EGL specification.
+ */
+
+static config_pair_t const config_base_attribute_list[] = {
+ { EGL_STENCIL_SIZE, 0 },
+ { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
+ { EGL_LEVEL, 0 },
+ { EGL_MAX_PBUFFER_HEIGHT, 0 },
+ { EGL_MAX_PBUFFER_PIXELS, 0 },
+ { EGL_MAX_PBUFFER_WIDTH, 0 },
+ { EGL_NATIVE_RENDERABLE, EGL_TRUE },
+ { EGL_NATIVE_VISUAL_ID, 0 },
+ { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGB_565 },
+ { EGL_SAMPLES, 0 },
+ { EGL_SAMPLE_BUFFERS, 0 },
+ { EGL_TRANSPARENT_TYPE, EGL_NONE },
+ { EGL_TRANSPARENT_BLUE_VALUE, 0 },
+ { EGL_TRANSPARENT_GREEN_VALUE, 0 },
+ { EGL_TRANSPARENT_RED_VALUE, 0 },
+ { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE },
+ { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE },
+ { EGL_MIN_SWAP_INTERVAL, 1 },
+ { EGL_MAX_SWAP_INTERVAL, 4 },
+};
+
+// These configs can override the base attribute list
+
+static config_pair_t const config_0_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 16 },
+ { EGL_ALPHA_SIZE, 0 },
+ { EGL_BLUE_SIZE, 5 },
+ { EGL_GREEN_SIZE, 6 },
+ { EGL_RED_SIZE, 5 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 0 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_1_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 16 },
+ { EGL_ALPHA_SIZE, 0 },
+ { EGL_BLUE_SIZE, 5 },
+ { EGL_GREEN_SIZE, 6 },
+ { EGL_RED_SIZE, 5 },
+ { EGL_DEPTH_SIZE, 16 },
+ { EGL_CONFIG_ID, 1 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_2_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 2 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT },
+};
+
+static config_pair_t const config_3_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 16 },
+ { EGL_CONFIG_ID, 3 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT },
+};
+
+static configs_t const gConfigs[] = {
+ { config_0_attribute_list, NELEM(config_0_attribute_list) },
+ { config_1_attribute_list, NELEM(config_1_attribute_list) },
+ { config_2_attribute_list, NELEM(config_2_attribute_list) },
+ { config_3_attribute_list, NELEM(config_3_attribute_list) },
+};
+
+static config_management_t const gConfigManagement[] = {
+ { EGL_BUFFER_SIZE, config_management_t::atLeast },
+ { EGL_ALPHA_SIZE, config_management_t::atLeast },
+ { EGL_BLUE_SIZE, config_management_t::atLeast },
+ { EGL_GREEN_SIZE, config_management_t::atLeast },
+ { EGL_RED_SIZE, config_management_t::atLeast },
+ { EGL_DEPTH_SIZE, config_management_t::atLeast },
+ { EGL_STENCIL_SIZE, config_management_t::atLeast },
+ { EGL_CONFIG_CAVEAT, config_management_t::exact },
+ { EGL_CONFIG_ID, config_management_t::exact },
+ { EGL_LEVEL, config_management_t::exact },
+ { EGL_MAX_PBUFFER_HEIGHT, config_management_t::exact },
+ { EGL_MAX_PBUFFER_PIXELS, config_management_t::exact },
+ { EGL_MAX_PBUFFER_WIDTH, config_management_t::exact },
+ { EGL_NATIVE_RENDERABLE, config_management_t::exact },
+ { EGL_NATIVE_VISUAL_ID, config_management_t::exact },
+ { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact },
+ { EGL_SAMPLES, config_management_t::exact },
+ { EGL_SAMPLE_BUFFERS, config_management_t::exact },
+ { EGL_SURFACE_TYPE, config_management_t::mask },
+ { EGL_TRANSPARENT_TYPE, config_management_t::exact },
+ { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact },
+ { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact },
+ { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact },
+ { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact },
+ { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact },
+ { EGL_MIN_SWAP_INTERVAL, config_management_t::exact },
+ { EGL_MAX_SWAP_INTERVAL, config_management_t::exact },
+};
+
+static config_pair_t const config_defaults[] = {
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
+};
+
+// ----------------------------------------------------------------------------
+
+template<typename T>
+static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
+{
+ while (first <= last) {
+ int mid = (first + last) / 2;
+ if (key > sortedArray[mid].key) {
+ first = mid + 1;
+ } else if (key < sortedArray[mid].key) {
+ last = mid - 1;
+ } else {
+ return mid;
+ }
+ }
+ return -1;
+}
+
+static int isAttributeMatching(int i, EGLint attr, EGLint val)
+{
+ // look for the attribute in all of our configs
+ config_pair_t const* configFound = gConfigs[i].array;
+ int index = binarySearch<config_pair_t>(
+ gConfigs[i].array,
+ 0, gConfigs[i].size-1,
+ attr);
+ if (index < 0) {
+ configFound = config_base_attribute_list;
+ index = binarySearch<config_pair_t>(
+ config_base_attribute_list,
+ 0, NELEM(config_base_attribute_list)-1,
+ attr);
+ }
+ if (index >= 0) {
+ // attribute found, check if this config could match
+ int cfgMgtIndex = binarySearch<config_management_t>(
+ gConfigManagement,
+ 0, NELEM(gConfigManagement)-1,
+ attr);
+ if (index >= 0) {
+ bool match = gConfigManagement[cfgMgtIndex].match(
+ val, configFound[index].value);
+ if (match) {
+ // this config matches
+ return 1;
+ }
+ } else {
+ // attribute nont found. this should NEVER happen.
+ }
+ } else {
+ // error, this attribute doesn't exist
+ }
+ return 0;
+}
+
+static int makeCurrent(ogles_context_t* gl)
+{
+ ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
+ if (gl) {
+ egl_context_t* c = egl_context_t::context(gl);
+ if (c->flags & egl_context_t::IS_CURRENT) {
+ if (current != gl) {
+ // it is an error to set a context current, if it's already
+ // current to another thread
+ return -1;
+ }
+ } else {
+ if (current) {
+ // mark the current context as not current, and flush
+ glFlush();
+ egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
+ }
+ }
+ if (!(c->flags & egl_context_t::IS_CURRENT)) {
+ // The context is not current, make it current!
+ setGlThreadSpecific(gl);
+ c->flags |= egl_context_t::IS_CURRENT;
+ }
+ } else {
+ if (current) {
+ // mark the current context as not current, and flush
+ glFlush();
+ egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
+ }
+ // this thread has no context attached to it
+ setGlThreadSpecific(0);
+ }
+ return 0;
+}
+
+static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value)
+{
+ size_t numConfigs = NELEM(gConfigs);
+ int index = (int)config;
+ if (uint32_t(index) >= numConfigs)
+ return setError(EGL_BAD_CONFIG, EGL_FALSE);
+
+ int attrIndex;
+ attrIndex = binarySearch<config_pair_t>(
+ gConfigs[index].array,
+ 0, gConfigs[index].size-1,
+ attribute);
+ if (attrIndex>=0) {
+ *value = gConfigs[index].array[attrIndex].value;
+ return EGL_TRUE;
+ }
+
+ attrIndex = binarySearch<config_pair_t>(
+ config_base_attribute_list,
+ 0, NELEM(config_base_attribute_list)-1,
+ attribute);
+ if (attrIndex>=0) {
+ *value = config_base_attribute_list[attrIndex].value;
+ return EGL_TRUE;
+ }
+ return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+}
+
+static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
+ NativeWindowType window, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ if (window == 0)
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ EGLint surfaceType;
+ if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+ return EGL_FALSE;
+
+ if (!(surfaceType & EGL_WINDOW_BIT))
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ EGLint configID;
+ if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+ return EGL_FALSE;
+
+ int32_t depthFormat;
+ int32_t pixelFormat;
+ switch(configID) {
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = 0;
+ break;
+ case 1:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 2:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = 0;
+ break;
+ case 3:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ default:
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ // XXX: we don't have access to the pixelFormat here just yet.
+ // (it's possible that the surface is not fully initialized)
+ // maybe this should be done after the page-flip
+ //if (EGLint(info.format) != pixelFormat)
+ // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ egl_surface_t* surface =
+ new egl_window_surface_t(dpy, config, depthFormat,
+ static_cast<egl_native_window_t*>(window));
+
+ if (!surface->isValid()) {
+ // there was a problem in the ctor, the error
+ // flag has been set.
+ delete surface;
+ surface = 0;
+ }
+ return surface;
+}
+
+static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
+ NativePixmapType pixmap, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ if (pixmap == 0)
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ EGLint surfaceType;
+ if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+ return EGL_FALSE;
+
+ if (!(surfaceType & EGL_PIXMAP_BIT))
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ EGLint configID;
+ if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+ return EGL_FALSE;
+
+ int32_t depthFormat;
+ int32_t pixelFormat;
+ switch(configID) {
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = 0;
+ break;
+ case 1:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 2:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = 0;
+ break;
+ case 3:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ default:
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ if (pixmap->format != pixelFormat)
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ egl_surface_t* surface =
+ new egl_pixmap_surface_t(dpy, config, depthFormat,
+ static_cast<egl_native_pixmap_t*>(pixmap));
+
+ if (!surface->isValid()) {
+ // there was a problem in the ctor, the error
+ // flag has been set.
+ delete surface;
+ surface = 0;
+ }
+ return surface;
+}
+
+static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+
+ EGLint surfaceType;
+ if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+ return EGL_FALSE;
+
+ if (!(surfaceType & EGL_PBUFFER_BIT))
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+
+ EGLint configID;
+ if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+ return EGL_FALSE;
+
+ int32_t depthFormat;
+ int32_t pixelFormat;
+ switch(configID) {
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = 0;
+ break;
+ case 1:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ case 2:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = 0;
+ break;
+ case 3:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = GGL_PIXEL_FORMAT_Z_16;
+ break;
+ default:
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ int32_t w = 0;
+ int32_t h = 0;
+ while (attrib_list[0]) {
+ if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1];
+ if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
+ attrib_list+=2;
+ }
+
+ egl_surface_t* surface =
+ new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
+
+ if (!surface->isValid()) {
+ // there was a problem in the ctor, the error
+ // flag has been set.
+ delete surface;
+ surface = 0;
+ }
+ return surface;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// Initialization
+// ----------------------------------------------------------------------------
+
+EGLDisplay eglGetDisplay(NativeDisplayType display)
+{
+#ifndef HAVE_ANDROID_OS
+ // this just needs to be done once
+ if (gGLKey == -1) {
+ pthread_mutex_lock(&gInitMutex);
+ if (gGLKey == -1)
+ pthread_key_create(&gGLKey, NULL);
+ pthread_mutex_unlock(&gInitMutex);
+ }
+#endif
+ if (display == EGL_DEFAULT_DISPLAY) {
+ EGLDisplay dpy = (EGLDisplay)1;
+ egl_display_t& d = egl_display_t::get_display(dpy);
+ d.type = display;
+ return dpy;
+ }
+ return EGL_NO_DISPLAY;
+}
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ EGLBoolean res = EGL_TRUE;
+ egl_display_t& d = egl_display_t::get_display(dpy);
+
+ if (android_atomic_inc(&d.initialized) == 0) {
+ // initialize stuff here if needed
+ //pthread_mutex_lock(&gInitMutex);
+ //pthread_mutex_unlock(&gInitMutex);
+ }
+
+ if (res == EGL_TRUE) {
+ if (major != NULL) *major = 1;
+ if (minor != NULL) *minor = 2;
+ }
+ return res;
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ EGLBoolean res = EGL_TRUE;
+ egl_display_t& d = egl_display_t::get_display(dpy);
+ if (android_atomic_dec(&d.initialized) == 1) {
+ // TODO: destroy all resources (surfaces, contextes, etc...)
+ //pthread_mutex_lock(&gInitMutex);
+ //pthread_mutex_unlock(&gInitMutex);
+ }
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+// configuration
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglGetConfigs( EGLDisplay dpy,
+ EGLConfig *configs,
+ EGLint config_size, EGLint *num_config)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ GLint numConfigs = NELEM(gConfigs);
+ if (!configs) {
+ *num_config = numConfigs;
+ return EGL_TRUE;
+ }
+ GLint i;
+ for (i=0 ; i<numConfigs && i<config_size ; i++) {
+ *configs++ = (EGLConfig)i;
+ }
+ *num_config = i;
+ return EGL_TRUE;
+}
+
+EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ if (ggl_unlikely(configs==0 || attrib_list==0)) {
+ *num_config = 0;
+ return EGL_TRUE;
+ }
+
+ int numAttributes = 0;
+ int numConfigs = NELEM(gConfigs);
+ uint32_t possibleMatch = (1<<numConfigs)-1;
+ while(possibleMatch && *attrib_list != EGL_NONE) {
+ numAttributes++;
+ EGLint attr = *attrib_list++;
+ EGLint val = *attrib_list++;
+ for (int i=0 ; i<numConfigs ; i++) {
+ if (!(possibleMatch & (1<<i)))
+ continue;
+ if (isAttributeMatching(i, attr, val) == 0) {
+ possibleMatch &= ~(1<<i);
+ }
+ }
+ }
+
+ // now, handle the attributes which have a useful default value
+ for (size_t j=0 ; j<NELEM(config_defaults) ; j++) {
+ // see if this attribute was specified, if not apply its
+ // default value
+ if (binarySearch<config_pair_t>(
+ (config_pair_t const*)attrib_list,
+ 0, numAttributes,
+ config_defaults[j].key) < 0)
+ {
+ for (int i=0 ; i<numConfigs ; i++) {
+ if (!(possibleMatch & (1<<i)))
+ continue;
+ if (isAttributeMatching(i,
+ config_defaults[j].key,
+ config_defaults[j].value) == 0)
+ {
+ possibleMatch &= ~(1<<i);
+ }
+ }
+ }
+ }
+
+ // return the configurations found
+ int n=0;
+ if (possibleMatch) {
+ for (int i=0 ; config_size && i<numConfigs ; i++) {
+ if (possibleMatch & (1<<i)) {
+ *configs++ = (EGLConfig)i;
+ config_size--;
+ n++;
+ }
+ }
+ }
+ *num_config = n;
+ return EGL_TRUE;
+}
+
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ return getConfigAttrib(dpy, config, attribute, value);
+}
+
+// ----------------------------------------------------------------------------
+// surfaces
+// ----------------------------------------------------------------------------
+
+EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
+ NativeWindowType window,
+ const EGLint *attrib_list)
+{
+ return createWindowSurface(dpy, config, window, attrib_list);
+}
+
+EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
+ NativePixmapType pixmap,
+ const EGLint *attrib_list)
+{
+ return createPixmapSurface(dpy, config, pixmap, attrib_list);
+}
+
+EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list)
+{
+ // none of our configs support pbuffers
+ // (in fact it's working but since we can't use them as
+ // textures yet, it's not useful at all)
+ //createPbufferSurface(dpy, config, attrib_list);
+ return EGL_NO_SURFACE;
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (eglSurface != EGL_NO_SURFACE) {
+ egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
+ if (surface->magic != egl_surface_t::MAGIC)
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (surface->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ delete surface;
+ }
+ return EGL_TRUE;
+}
+
+EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
+ EGLint attribute, EGLint *value)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
+ if (surface->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ EGLBoolean ret = EGL_TRUE;
+ switch (attribute) {
+ case EGL_CONFIG_ID:
+ ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
+ break;
+ case EGL_WIDTH:
+ *value = surface->getWidth();
+ break;
+ case EGL_HEIGHT:
+ *value = surface->getHeight();
+ break;
+ case EGL_LARGEST_PBUFFER:
+ // not modified for a window or pixmap surface
+ break;
+ case EGL_TEXTURE_FORMAT:
+ *value = EGL_NO_TEXTURE;
+ break;
+ case EGL_TEXTURE_TARGET:
+ *value = EGL_NO_TEXTURE;
+ break;
+ case EGL_MIPMAP_TEXTURE:
+ *value = EGL_FALSE;
+ break;
+ case EGL_MIPMAP_LEVEL:
+ *value = 0;
+ break;
+ case EGL_RENDER_BUFFER:
+ // TODO: return the real RENDER_BUFFER here
+ *value = EGL_BACK_BUFFER;
+ break;
+ case EGL_HORIZONTAL_RESOLUTION:
+ // pixel/mm * EGL_DISPLAY_SCALING
+ *value = surface->getHorizontalResolution();
+ break;
+ case EGL_VERTICAL_RESOLUTION:
+ // pixel/mm * EGL_DISPLAY_SCALING
+ *value = surface->getVerticalResolution();
+ break;
+ case EGL_PIXEL_ASPECT_RATIO: {
+ // w/h * EGL_DISPLAY_SCALING
+ int wr = surface->getHorizontalResolution();
+ int hr = surface->getVerticalResolution();
+ *value = (wr * EGL_DISPLAY_SCALING) / hr;
+ } break;
+ case EGL_SWAP_BEHAVIOR:
+ *value = surface->getSwapBehavior();
+ break;
+ default:
+ ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+ return ret;
+}
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_list, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+
+ ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
+ if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+
+ egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
+ c->flags = egl_context_t::NEVER_CURRENT;
+ c->dpy = dpy;
+ c->config = config;
+ c->read = 0;
+ c->draw = 0;
+ return (EGLContext)gl;
+}
+
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_context_t* c = egl_context_t::context(ctx);
+ if (c->flags & egl_context_t::IS_CURRENT)
+ setGlThreadSpecific(0);
+ ogles_uninit((ogles_context_t*)ctx);
+ return EGL_TRUE;
+}
+
+EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (draw) {
+ egl_surface_t* s = (egl_surface_t*)draw;
+ if (s->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: check that draw and read are compatible with the context
+ }
+
+ EGLContext current_ctx = EGL_NO_CONTEXT;
+ if (ctx == EGL_NO_CONTEXT) {
+ // if we're detaching, we need the current context
+ current_ctx = (EGLContext)getGlThreadSpecific();
+ } else {
+ egl_context_t* c = egl_context_t::context(ctx);
+ egl_surface_t* d = (egl_surface_t*)draw;
+ egl_surface_t* r = (egl_surface_t*)read;
+ if ((d && d->ctx && d->ctx != ctx) ||
+ (r && r->ctx && r->ctx != ctx)) {
+ // once of the surface is bound to a context in another thread
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ }
+ }
+
+ ogles_context_t* gl = (ogles_context_t*)ctx;
+ if (makeCurrent(gl) == 0) {
+ if (ctx) {
+ egl_context_t* c = egl_context_t::context(ctx);
+ egl_surface_t* d = (egl_surface_t*)draw;
+ egl_surface_t* r = (egl_surface_t*)read;
+ c->read = read;
+ c->draw = draw;
+ if (c->flags & egl_context_t::NEVER_CURRENT) {
+ c->flags &= ~egl_context_t::NEVER_CURRENT;
+ GLint w = 0;
+ GLint h = 0;
+ if (draw) {
+ w = d->getWidth();
+ h = d->getHeight();
+ }
+ ogles_surfaceport(gl, 0, 0);
+ ogles_viewport(gl, 0, 0, w, h);
+ ogles_scissor(gl, 0, 0, w, h);
+ }
+ if (d) {
+ d->ctx = ctx;
+ d->bindDrawSurface(gl);
+ }
+ if (r) {
+ r->ctx = ctx;
+ r->bindReadSurface(gl);
+ }
+ } else {
+ // if surfaces were bound to the context bound to this thread
+ // mark then as unbound.
+ if (current_ctx) {
+ egl_context_t* c = egl_context_t::context(current_ctx);
+ egl_surface_t* d = (egl_surface_t*)c->draw;
+ egl_surface_t* r = (egl_surface_t*)c->read;
+ if (d) d->ctx = EGL_NO_CONTEXT;
+ if (r) r->ctx = EGL_NO_CONTEXT;
+ }
+ }
+ return EGL_TRUE;
+ }
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+}
+
+EGLContext eglGetCurrentContext(void)
+{
+ // eglGetCurrentContext returns the current EGL rendering context,
+ // as specified by eglMakeCurrent. If no context is current,
+ // EGL_NO_CONTEXT is returned.
+ return (EGLContext)getGlThreadSpecific();
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw)
+{
+ // eglGetCurrentSurface returns the read or draw surface attached
+ // to the current EGL rendering context, as specified by eglMakeCurrent.
+ // If no context is current, EGL_NO_SURFACE is returned.
+ EGLContext ctx = (EGLContext)getGlThreadSpecific();
+ if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
+ egl_context_t* c = egl_context_t::context(ctx);
+ if (readdraw == EGL_READ) {
+ return c->read;
+ } else if (readdraw == EGL_DRAW) {
+ return c->draw;
+ }
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+}
+
+EGLDisplay eglGetCurrentDisplay(void)
+{
+ // eglGetCurrentDisplay returns the current EGL display connection
+ // for the current EGL rendering context, as specified by eglMakeCurrent.
+ // If no context is current, EGL_NO_DISPLAY is returned.
+ EGLContext ctx = (EGLContext)getGlThreadSpecific();
+ if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
+ egl_context_t* c = egl_context_t::context(ctx);
+ return c->dpy;
+}
+
+EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
+ EGLint attribute, EGLint *value)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_context_t* c = egl_context_t::context(ctx);
+ switch (attribute) {
+ case EGL_CONFIG_ID:
+ // Returns the ID of the EGL frame buffer configuration with
+ // respect to which the context was created
+ return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
+ }
+ return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+}
+
+EGLBoolean eglWaitGL(void)
+{
+ return EGL_TRUE;
+}
+
+EGLBoolean eglWaitNative(EGLint engine)
+{
+ return EGL_TRUE;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (d->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ // post the surface
+ d->swapBuffers();
+
+ // if it's bound to a context, update the buffer
+ if (d->ctx != EGL_NO_CONTEXT) {
+ d->bindDrawSurface((ogles_context_t*)d->ctx);
+ // if this surface is also the read surface of the context
+ // it is bound to, make sure to update the read buffer as well.
+ // The EGL spec is a little unclear about this.
+ egl_context_t* c = egl_context_t::context(d->ctx);
+ if (c->read == draw) {
+ d->bindReadSurface((ogles_context_t*)d->ctx);
+ }
+ }
+
+ return EGL_TRUE;
+}
+
+EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
+ NativePixmapType target)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglCopyBuffers()
+ return EGL_FALSE;
+}
+
+EGLint eglGetError(void)
+{
+ return getError();
+}
+
+const char* eglQueryString(EGLDisplay dpy, EGLint name)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, (const char*)0);
+
+ switch (name) {
+ case EGL_VENDOR:
+ return gVendorString;
+ case EGL_VERSION:
+ return gVersionString;
+ case EGL_EXTENSIONS:
+ return gExtensionsString;
+ case EGL_CLIENT_APIS:
+ return gClientApiString;
+ }
+ return setError(EGL_BAD_PARAMETER, (const char *)0);
+}
+
+// ----------------------------------------------------------------------------
+// EGL 1.1
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSurfaceAttrib(
+ EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglSurfaceAttrib()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglBindTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglBindTexImage()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglReleaseTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglReleaseTexImage()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglSwapInterval()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+}
+
+// ----------------------------------------------------------------------------
+// EGL 1.2
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglBindAPI(EGLenum api)
+{
+ if (api != EGL_OPENGL_ES_API)
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return EGL_TRUE;
+}
+
+EGLenum eglQueryAPI(void)
+{
+ return EGL_OPENGL_ES_API;
+}
+
+EGLBoolean eglWaitClient(void)
+{
+ glFinish();
+ return EGL_TRUE;
+}
+
+EGLBoolean eglReleaseThread(void)
+{
+ // TODO: eglReleaseThread()
+ return EGL_TRUE;
+}
+
+EGLSurface eglCreatePbufferFromClientBuffer(
+ EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+ EGLConfig config, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ // TODO: eglCreatePbufferFromClientBuffer()
+ return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+}
+
+// ----------------------------------------------------------------------------
+// Android extentions
+// ----------------------------------------------------------------------------
+
+void (*eglGetProcAddress (const char *procname))()
+{
+ extention_map_t const * const map = gExtentionMap;
+ for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
+ if (!strcmp(procname, map[i].name)) {
+ return map[i].address;
+ }
+ }
+ return NULL;
+}
+
+EGLBoolean eglSwapRectangleANDROID(
+ EGLDisplay dpy, EGLSurface draw,
+ EGLint l, EGLint t, EGLint w, EGLint h)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_surface_t* surface = (egl_surface_t*)draw;
+ if (surface->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ return surface->swapRectangle(l, t, w, h);
+}
diff --git a/opengl/libagl/fixed_asm.S b/opengl/libagl/fixed_asm.S
new file mode 100644
index 0000000..6cbc56f
--- /dev/null
+++ b/opengl/libagl/fixed_asm.S
@@ -0,0 +1,65 @@
+/* libs/opengles/fixed_asm.S
+**
+** Copyright 2006, 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.
+*/
+
+
+ .text
+ .align
+
+ .global gglFloatToFixed
+ .global gglFloatToFixedFast
+
+
+/*
+ * Converts a float to a s15.16 fixed-point number.
+ * this doesn't handle floats out of the [-32768, +32768[ range
+ * and doesn't performs round-to-nearest.
+ * however, it's very fast :-)
+ */
+
+gglFloatToFixedFast:
+ movs r1, r0, lsl #1 /* remove bit sign */
+ mov r2, #0x8E /* 127 + 15 */
+ sub r1, r2, r1, lsr #24 /* compute shift */
+ mov r2, r0, lsl #8 /* mantissa<<8 */
+ orr r2, r2, #0x80000000 /* add the missing 1 */
+ mov r0, r2, lsr r1 /* scale to 16.16 */
+ rsbcs r0, r0, #0 /* negate if needed */
+ bx lr
+
+/*
+ * this version rounds-to-nearest and saturates numbers
+ * outside the range (but not NaNs).
+ */
+
+gglFloatToFixed:
+ mov r1, r0, lsl #1 /* remove bit sign */
+ mov r2, #0x8E /* 127 + 15 */
+ subs r1, r2, r1, lsr #24 /* compute shift */
+ bls 0f /* too big */
+ mov r2, r0, lsl #8 /* mantissa<<8 */
+ orr r2, r2, #0x80000000 /* add the missing 1 */
+ mov r3, r0
+ movs r0, r2, lsr r1 /* scale to 16.16 */
+ addcs r0, r0, #1 /* round-to-nearest */
+ tst r3, #0x80000000 /* negative? */
+ rsbne r0, r0, #0 /* negate if needed */
+ bx lr
+
+0: ands r0, r0, #0x80000000 /* keep only the sign bit */
+ moveq r0, #0x7fffffff /* positive, maximum value */
+ bx lr
+
diff --git a/opengl/libagl/fp.cpp b/opengl/libagl/fp.cpp
new file mode 100644
index 0000000..ae5f1fe
--- /dev/null
+++ b/opengl/libagl/fp.cpp
@@ -0,0 +1,87 @@
+/* libs/opengles/fp.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include "fp.h"
+
+// ----------------------------------------------------------------------------
+
+#if !defined(__arm__)
+GGLfixed gglFloatToFixed(float v) {
+ return GGLfixed(floorf(v * 65536.0f + 0.5f));
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+namespace gl {
+
+GLfloat fixedToFloat(GLfixed x)
+{
+#if DEBUG_USE_FLOATS
+ return x / 65536.0f;
+#else
+ if (!x) return 0;
+ const uint32_t s = x & 0x80000000;
+ union {
+ uint32_t i;
+ float f;
+ };
+ i = s ? -x : x;
+ const int c = gglClz(i) - 8;
+ i = (c>=0) ? (i<<c) : (i>>-c);
+ const uint32_t e = 134 - c;
+ i &= ~0x800000;
+ i |= e<<23;
+ i |= s;
+ return f;
+#endif
+}
+
+float sinef(float x)
+{
+ const float A = 1.0f / (2.0f*M_PI);
+ const float B = -16.0f;
+ const float C = 8.0f;
+
+ // scale angle for easy argument reduction
+ x *= A;
+
+ if (fabsf(x) >= 0.5f) {
+ // Argument reduction
+ x = x - ceilf(x + 0.5f) + 1.0f;
+ }
+
+ const float y = B*x*fabsf(x) + C*x;
+ return 0.2215f * (y*fabsf(y) - y) + y;
+}
+
+float cosinef(float x)
+{
+ return sinef(x + float(M_PI/2));
+}
+
+void sincosf(GLfloat angle, GLfloat* s, GLfloat* c) {
+ *s = sinef(angle);
+ *c = cosinef(angle);
+}
+
+}; // namespace fp_utils
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/opengl/libagl/fp.h b/opengl/libagl/fp.h
new file mode 100644
index 0000000..6d0c183
--- /dev/null
+++ b/opengl/libagl/fp.h
@@ -0,0 +1,243 @@
+/* libs/opengles/fp.h
+**
+** Copyright 2006, 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_OPENGLES_FP_H
+#define ANDROID_OPENGLES_FP_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <math.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#define DEBUG_USE_FLOATS 0
+
+// ----------------------------------------------------------------------------
+
+extern "C" GLfixed gglFloatToFixed(float f) __attribute__((const));
+
+// ----------------------------------------------------------------------------
+namespace android {
+
+namespace gl {
+
+ GLfloat fixedToFloat(GLfixed) CONST;
+
+ void sincosf(GLfloat angle, GLfloat* s, GLfloat* c);
+ float sinef(GLfloat x) CONST;
+ float cosinef(GLfloat x) CONST;
+
+inline bool cmpf(GLfloat a, GLfloat b) CONST;
+inline bool isZerof(GLfloat) CONST;
+inline bool isOnef(GLfloat) CONST;
+
+inline int isZeroOrNegativef(GLfloat) CONST;
+
+inline int exponent(GLfloat) CONST;
+inline int32_t mantissa(GLfloat) CONST;
+inline GLfloat clampToZerof(GLfloat) CONST;
+inline GLfloat reciprocalf(GLfloat) CONST;
+inline GLfloat rsqrtf(GLfloat) CONST;
+inline GLfloat sqrf(GLfloat) CONST;
+inline GLfloat addExpf(GLfloat v, int e) CONST;
+inline GLfloat mul2f(GLfloat v) CONST;
+inline GLfloat div2f(GLfloat v) CONST;
+inline GLfloat absf(GLfloat v) CONST;
+
+
+/*
+ * float fastexpf(float) : a fast approximation of expf(x)
+ * give somewhat accurate results for -88 <= x <= 88
+ *
+ * exp(x) = 2^(x/ln(2))
+ * we use the properties of float encoding
+ * to get a fast 2^ and linear interpolation
+ *
+ */
+
+inline float fastexpf(float y) __attribute__((const));
+
+inline float fastexpf(float y)
+{
+ union {
+ float r;
+ int32_t i;
+ } u;
+
+ // 127*ln(2) = 88
+ if (y < -88.0f) {
+ u.r = 0.0f;
+ } else if (y > 88.0f) {
+ u.r = INFINITY;
+ } else {
+ const float kOneOverLogTwo = (1L<<23) / M_LN2;
+ const int32_t kExponentBias = 127L<<23;
+ const int32_t e = int32_t(y*kOneOverLogTwo);
+ u.i = e + kExponentBias;
+ }
+
+ return u.r;
+}
+
+
+bool cmpf(GLfloat a, GLfloat b) {
+#if DEBUG_USE_FLOATS
+ return a == b;
+#else
+ union {
+ float f;
+ uint32_t i;
+ } ua, ub;
+ ua.f = a;
+ ub.f = b;
+ return ua.i == ub.i;
+#endif
+}
+
+bool isZerof(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v == 0;
+#else
+ union {
+ float f;
+ int32_t i;
+ };
+ f = v;
+ return (i<<1) == 0;
+#endif
+}
+
+bool isOnef(GLfloat v) {
+ return cmpf(v, 1.0f);
+}
+
+int isZeroOrNegativef(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v <= 0;
+#else
+ union {
+ float f;
+ int32_t i;
+ };
+ f = v;
+ return isZerof(v) | (i>>31);
+#endif
+}
+
+int exponent(GLfloat v) {
+ union {
+ float f;
+ uint32_t i;
+ };
+ f = v;
+ return ((i << 1) >> 24) - 127;
+}
+
+int32_t mantissa(GLfloat v) {
+ union {
+ float f;
+ uint32_t i;
+ };
+ f = v;
+ if (!(i&0x7F800000)) return 0;
+ const int s = i >> 31;
+ i |= (1L<<23);
+ i &= ~0xFF000000;
+ return s ? -i : i;
+}
+
+GLfloat clampToZerof(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v<0 ? 0 : (v>1 ? 1 : v);
+#else
+ union {
+ float f;
+ int32_t i;
+ };
+ f = v;
+ i &= ~(i>>31);
+ return f;
+#endif
+}
+
+GLfloat reciprocalf(GLfloat v) {
+ // XXX: do better
+ return 1.0f / v;
+}
+
+GLfloat rsqrtf(GLfloat v) {
+ // XXX: do better
+ return 1.0f / sqrtf(v);
+}
+
+GLfloat sqrf(GLfloat v) {
+ // XXX: do better
+ return v*v;
+}
+
+GLfloat addExpf(GLfloat v, int e) {
+ union {
+ float f;
+ int32_t i;
+ };
+ f = v;
+ if (i<<1) { // XXX: deal with over/underflow
+ i += int32_t(e)<<23;
+ }
+ return f;
+}
+
+GLfloat mul2f(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v*2;
+#else
+ return addExpf(v, 1);
+#endif
+}
+
+GLfloat div2f(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v*0.5f;
+#else
+ return addExpf(v, -1);
+#endif
+}
+
+GLfloat absf(GLfloat v) {
+#if DEBUG_USE_FLOATS
+ return v<0 ? -v : v;
+#else
+ union {
+ float f;
+ int32_t i;
+ };
+ f = v;
+ i &= ~0x80000000;
+ return f;
+#endif
+}
+
+}; // namespace gl
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_FP_H
+
diff --git a/opengl/libagl/iterators.S b/opengl/libagl/iterators.S
new file mode 100644
index 0000000..daf2937
--- /dev/null
+++ b/opengl/libagl/iterators.S
@@ -0,0 +1,88 @@
+/* libs/opengles/iterators.S
+**
+** Copyright 2006, 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.
+*/
+
+
+ .text
+ .align
+ .arm
+
+ .global iterators0032
+
+/*
+ * iterators0032
+ *
+ * MUST BE CALLED FROM ARM CODE
+ *
+ * r0: const compute_iterators_t* (this)
+ * r0 + 0: m_dx01
+ * r0 + 4: m_dy10
+ * r0 + 8: m_dx20
+ * r0 +12: m_dy02
+ * r0 +16: m_x0
+ * r0 +20: m_y0
+ * r0 +24: m_area
+ * r0 +28: m_scale
+ * r0 +29: m_area_scale;
+ * r1: int32_t* (out)
+ * r1 + 0: c
+ * r1 + 4: dcdx
+ * r1 + 8: dcdy
+ * r2: c0
+ * r3: c1
+ * [sp]: c2
+ */
+
+iterators0032:
+ stmfd sp!, {r4, r5, r6, r7, r8, lr}
+ ldr r4, [sp, #4*6]
+
+ ldrb r12, [r0, #29]
+ sub r3, r3, r2
+ sub r4, r4, r2
+ sub r12, r12, #16
+ mov r3, r3, asr r12
+ mov r4, r4, asr r12
+
+ ldr r5, [r0, #0]
+ ldr r12, [r0, #4]
+ smull r8, lr, r4, r5
+ ldr r5, [r0, #8]
+ smull r6, r7, r4, r12
+ ldr r12, [r0, #12]
+ smlal r8, lr, r3, r5
+ smlal r6, r7, r3, r12
+
+ ldr r3, [r0, #16] // m_x0
+ ldr r4, [r0, #20] // m_x1
+
+ str r6, [r1, #4]
+ str r8, [r1, #8]
+
+ umull r6, r5, r3, r6
+ umull r8, r0, r4, r8
+ mla r7, r3, r7, r5
+ mla lr, r4, lr, r0
+ adds r6, r6, r8
+ adc r7, r7, lr
+
+ movs r6, r6, lsr #4
+ adc r6, r6, r7, lsl #28
+ rsb r6, r6, r2, lsl #16
+ str r6, [r1, #0]
+
+ ldmfd sp!, {r4, r5, r6, r7, r8, pc}
+
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
new file mode 100644
index 0000000..87725cb
--- /dev/null
+++ b/opengl/libagl/light.cpp
@@ -0,0 +1,852 @@
+/* libs/opengles/light.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <stdio.h>
+#include "context.h"
+#include "fp.h"
+#include "light.h"
+#include "state.h"
+#include "matrix.h"
+
+
+#if defined(__arm__) && defined(__thumb__)
+#warning "light.cpp should not be compiled in thumb on ARM."
+#endif
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void invalidate_lighting(ogles_context_t* c);
+static void lightVertexValidate(ogles_context_t* c, vertex_t* v);
+static void lightVertexNop(ogles_context_t* c, vertex_t* v);
+static void lightVertex(ogles_context_t* c, vertex_t* v);
+static void lightVertexMaterial(ogles_context_t* c, vertex_t* v);
+
+static inline void vscale3(GLfixed* d, const GLfixed* m, GLfixed s);
+static inline void vsub3w(GLfixed* d, const GLfixed* a, const GLfixed* b);
+
+static __attribute__((noinline))
+void vnorm3(GLfixed* d, const GLfixed* a);
+
+static inline void vsa3(GLfixed* d,
+ const GLfixed* m, GLfixed s, const GLfixed* a);
+static inline void vmla3(GLfixed* d,
+ const GLfixed* m0, const GLfixed* m1, const GLfixed* a);
+static inline void vmul3(GLfixed* d,
+ const GLfixed* m0, const GLfixed* m1);
+
+static GLfixed fog_linear(ogles_context_t* c, GLfixed z);
+static GLfixed fog_exp(ogles_context_t* c, GLfixed z);
+static GLfixed fog_exp2(ogles_context_t* c, GLfixed z);
+
+
+// ----------------------------------------------------------------------------
+
+static void init_white(vec4_t& c) {
+ c.r = c.g = c.b = c.a = 0x10000;
+}
+
+void ogles_init_light(ogles_context_t* c)
+{
+ for (unsigned int i=0 ; i<OGLES_MAX_LIGHTS ; i++) {
+ c->lighting.lights[i].ambient.a = 0x10000;
+ c->lighting.lights[i].position.z = 0x10000;
+ c->lighting.lights[i].spotDir.z = -0x10000;
+ c->lighting.lights[i].spotCutoff = gglIntToFixed(180);
+ c->lighting.lights[i].attenuation[0] = 0x10000;
+ }
+ init_white(c->lighting.lights[0].diffuse);
+ init_white(c->lighting.lights[0].specular);
+
+ c->lighting.front.ambient.r =
+ c->lighting.front.ambient.g =
+ c->lighting.front.ambient.b = gglFloatToFixed(0.2f);
+ c->lighting.front.ambient.a = 0x10000;
+ c->lighting.front.diffuse.r =
+ c->lighting.front.diffuse.g =
+ c->lighting.front.diffuse.b = gglFloatToFixed(0.8f);
+ c->lighting.front.diffuse.a = 0x10000;
+ c->lighting.front.specular.a = 0x10000;
+ c->lighting.front.emission.a = 0x10000;
+
+ c->lighting.lightModel.ambient.r =
+ c->lighting.lightModel.ambient.g =
+ c->lighting.lightModel.ambient.b = gglFloatToFixed(0.2f);
+ c->lighting.lightModel.ambient.a = 0x10000;
+
+ c->lighting.colorMaterial.face = GL_FRONT_AND_BACK;
+ c->lighting.colorMaterial.mode = GL_AMBIENT_AND_DIFFUSE;
+
+ c->fog.mode = GL_EXP;
+ c->fog.fog = fog_exp;
+ c->fog.density = 0x10000;
+ c->fog.end = 0x10000;
+ c->fog.invEndMinusStart = 0x10000;
+
+ invalidate_lighting(c);
+
+ c->rasterizer.procs.shadeModel(c, GL_SMOOTH);
+ c->lighting.shadeModel = GL_SMOOTH;
+}
+
+void ogles_uninit_light(ogles_context_t* c)
+{
+}
+
+static inline int32_t clampF(GLfixed f) CONST;
+int32_t clampF(GLfixed f) {
+ f = (f & ~(f>>31));
+ if (f >= 0x10000)
+ f = 0x10000;
+ return f;
+}
+
+static GLfixed fog_linear(ogles_context_t* c, GLfixed z) {
+ return clampF(gglMulx((c->fog.end - z), c->fog.invEndMinusStart));
+}
+
+static GLfixed fog_exp(ogles_context_t* c, GLfixed z) {
+ const float e = fixedToFloat(gglMulx(c->fog.density, z));
+ return clampF(gglFloatToFixed(fastexpf(-e)));
+}
+
+static GLfixed fog_exp2(ogles_context_t* c, GLfixed z) {
+ const float e = fixedToFloat(gglMulx(c->fog.density, z));
+ return clampF(gglFloatToFixed(fastexpf(-e*e)));
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark math helpers
+#endif
+
+static inline
+void vscale3(GLfixed* d, const GLfixed* m, GLfixed s) {
+ d[0] = gglMulx(m[0], s);
+ d[1] = gglMulx(m[1], s);
+ d[2] = gglMulx(m[2], s);
+}
+
+static inline
+void vsa3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) {
+ d[0] = gglMulAddx(m[0], s, a[0]);
+ d[1] = gglMulAddx(m[1], s, a[1]);
+ d[2] = gglMulAddx(m[2], s, a[2]);
+}
+
+static inline
+void vsub3w(GLfixed* d, const GLfixed* a, const GLfixed* b) {
+ const GLfixed wa = a[3];
+ const GLfixed wb = b[3];
+ if (ggl_likely(wa == wb)) {
+ d[0] = a[0] - b[0];
+ d[1] = a[1] - b[1];
+ d[2] = a[2] - b[2];
+ } else {
+ d[0] = gglMulSubx(a[0], wb, gglMulx(b[0], wa));
+ d[1] = gglMulSubx(a[1], wb, gglMulx(b[1], wa));
+ d[2] = gglMulSubx(a[2], wb, gglMulx(b[2], wa));
+ }
+}
+
+static inline
+void vmla3(GLfixed* d,
+ const GLfixed* m0, const GLfixed* m1, const GLfixed* a)
+{
+ d[0] = gglMulAddx(m0[0], m1[0], a[0]);
+ d[1] = gglMulAddx(m0[1], m1[1], a[1]);
+ d[2] = gglMulAddx(m0[2], m1[2], a[2]);
+}
+
+static inline
+void vmul3(GLfixed* d, const GLfixed* m0, const GLfixed* m1) {
+ d[0] = gglMulx(m0[0], m1[0]);
+ d[1] = gglMulx(m0[1], m1[1]);
+ d[2] = gglMulx(m0[2], m1[2]);
+}
+
+void vnorm3(GLfixed* d, const GLfixed* a)
+{
+ // we must take care of overflows when normalizing a vector
+ GLfixed n;
+ int32_t x = a[0]; x = x>=0 ? x : -x;
+ int32_t y = a[1]; y = y>=0 ? y : -y;
+ int32_t z = a[2]; z = z>=0 ? z : -z;
+ if (ggl_likely(x<=0x6800 && y<=0x6800 && z<= 0x6800)) {
+ // in this case this will all fit on 32 bits
+ n = x*x + y*y + z*z;
+ n = gglSqrtRecipx(n);
+ n <<= 8;
+ } else {
+ // here norm^2 is at least 0x7EC00000 (>>32 == 0.495117)
+ n = vsquare3(x, y, z);
+ n = gglSqrtRecipx(n);
+ }
+ vscale3(d, a, n);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark lighting equations
+#endif
+
+static inline void light_picker(ogles_context_t* c)
+{
+ if (ggl_likely(!c->lighting.enable)) {
+ c->lighting.lightVertex = lightVertexNop;
+ return;
+ }
+ if (c->lighting.colorMaterial.enable) {
+ c->lighting.lightVertex = lightVertexMaterial;
+ } else {
+ c->lighting.lightVertex = lightVertex;
+ }
+}
+
+static inline void validate_light_mvi(ogles_context_t* c)
+{
+ uint32_t en = c->lighting.enabledLights;
+ while (en) {
+ const int i = 31 - gglClz(en);
+ en &= ~(1<<i);
+ light_t& l = c->lighting.lights[i];
+ c->transforms.mvui.point3(&c->transforms.mvui,
+ &l.objPosition, &l.position);
+ vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
+ }
+}
+
+static inline void validate_light(ogles_context_t* c)
+{
+ // if colorMaterial is enabled, we get the color from the vertex
+ if (!c->lighting.colorMaterial.enable) {
+ material_t& material = c->lighting.front;
+ uint32_t en = c->lighting.enabledLights;
+ while (en) {
+ const int i = 31 - gglClz(en);
+ en &= ~(1<<i);
+ light_t& l = c->lighting.lights[i];
+ vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v);
+ vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v);
+ vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
+
+ // this is just a flag to tell if we have a specular component
+ l.implicitSpecular.v[3] =
+ l.implicitSpecular.r |
+ l.implicitSpecular.g |
+ l.implicitSpecular.b;
+
+ l.rConstAttenuation = (l.attenuation[1] | l.attenuation[2])==0;
+ if (l.rConstAttenuation)
+ l.rConstAttenuation = gglRecipFast(l.attenuation[0]);
+ }
+ // emission and ambient for the whole scene
+ vmla3( c->lighting.implicitSceneEmissionAndAmbient.v,
+ c->lighting.lightModel.ambient.v,
+ material.ambient.v,
+ material.emission.v);
+ c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a;
+ }
+ validate_light_mvi(c);
+}
+
+void invalidate_lighting(ogles_context_t* c)
+{
+ // TODO: pick lightVertexValidate or lightVertexValidateMVI
+ // instead of systematically the heavier lightVertexValidate()
+ c->lighting.lightVertex = lightVertexValidate;
+}
+
+void ogles_invalidate_lighting_mvui(ogles_context_t* c)
+{
+ invalidate_lighting(c);
+}
+
+void lightVertexNop(ogles_context_t*, vertex_t* v)
+{
+ // we should never end-up here
+}
+
+void lightVertexValidateMVI(ogles_context_t* c, vertex_t* v)
+{
+ validate_light_mvi(c);
+ light_picker(c);
+ c->lighting.lightVertex(c, v);
+}
+
+void lightVertexValidate(ogles_context_t* c, vertex_t* v)
+{
+ validate_light(c);
+ light_picker(c);
+ c->lighting.lightVertex(c, v);
+}
+
+void lightVertexMaterial(ogles_context_t* c, vertex_t* v)
+{
+ // fetch the material color
+ const GLvoid* cp = c->arrays.color.element(
+ v->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v->color.v, cp);
+
+ // acquire the color-material from the vertex
+ material_t& material = c->lighting.front;
+ material.ambient =
+ material.diffuse = v->color;
+ // implicit arguments need to be computed per/vertex
+ uint32_t en = c->lighting.enabledLights;
+ while (en) {
+ const int i = 31 - gglClz(en);
+ en &= ~(1<<i);
+ light_t& l = c->lighting.lights[i];
+ vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v);
+ vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v);
+ vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
+ }
+ // emission and ambient for the whole scene
+ vmla3( c->lighting.implicitSceneEmissionAndAmbient.v,
+ c->lighting.lightModel.ambient.v,
+ material.ambient.v,
+ material.emission.v);
+ c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a;
+
+ // now we can light our vertex as usual
+ lightVertex(c, v);
+}
+
+void lightVertex(ogles_context_t* c, vertex_t* v)
+{
+ // emission and ambient for the whole scene
+ vec4_t r = c->lighting.implicitSceneEmissionAndAmbient;
+
+ uint32_t en = c->lighting.enabledLights;
+ if (ggl_likely(en)) {
+ // since we do the lighting in object-space, we don't need to
+ // transform each normal. However, we might still have to normalize
+ // it if GL_NORMALIZE is enabled.
+ vec4_t n;
+ c->arrays.normal.fetch(c, n.v,
+ c->arrays.normal.element(v->index & vertex_cache_t::INDEX_MASK));
+ if (c->transforms.rescaleNormals == GL_NORMALIZE)
+ vnorm3(n.v, n.v);
+
+ const material_t& material = c->lighting.front;
+ const int twoSide = c->lighting.lightModel.twoSide;
+
+ while (en) {
+ const int i = 31 - gglClz(en);
+ en &= ~(1<<i);
+ const light_t& l = c->lighting.lights[i];
+
+ vec4_t d, t;
+ GLfixed s;
+ GLfixed sqDist = 0x10000;
+
+ // compute vertex-to-light vector
+ if (ggl_unlikely(l.position.w)) {
+ vsub3w(d.v, l.objPosition.v, v->obj.v);
+ sqDist = dot3(d.v, d.v);
+ vscale3(d.v, d.v, gglSqrtRecipx(sqDist));
+ } else {
+ // TODO: avoid copy here
+ d = l.normalizedObjPosition;
+ }
+
+ // ambient & diffuse
+ s = dot3(n.v, d.v);
+ s = (s<0) ? (twoSide?(-s):0) : s;
+ vsa3(t.v, l.implicitDiffuse.v, s, l.implicitAmbient.v);
+
+ // specular
+ if (ggl_unlikely(s && l.implicitSpecular.v[3])) {
+ vec4_t h;
+ h.x = d.x;
+ h.y = d.y;
+ h.z = d.z + 0x10000;
+ vnorm3(h.v, h.v);
+ s = dot3(n.v, h.v);
+ s = (s<0) ? (twoSide?(-s):0) : s;
+ if (s > 0) {
+ s = gglPowx(s, material.shininess);
+ vsa3(t.v, l.implicitSpecular.v, s, t.v);
+ }
+ }
+
+ // spot
+ if (ggl_unlikely(l.spotCutoff != gglIntToFixed(180))) {
+ GLfixed spotAtt = -dot3(l.normalizedSpotDir.v, d.v);
+ if (spotAtt >= l.spotCutoffCosine) {
+ vscale3(t.v, t.v, gglPowx(spotAtt, l.spotExp));
+ }
+ }
+
+ // attenuation
+ if (ggl_unlikely(l.position.w)) {
+ if (l.rConstAttenuation) {
+ s = l.rConstAttenuation;
+ } else {
+ s = gglMulAddx(sqDist, l.attenuation[2], l.attenuation[0]);
+ if (l.attenuation[1])
+ s = gglMulAddx(gglSqrtx(sqDist), l.attenuation[1], s);
+ s = gglRecipFast(s);
+ }
+ vscale3(t.v, t.v, s);
+ }
+
+ r.r += t.r;
+ r.g += t.g;
+ r.b += t.b;
+ }
+ }
+ v->color.r = gglClampx(r.r);
+ v->color.g = gglClampx(r.g);
+ v->color.b = gglClampx(r.b);
+ v->color.a = gglClampx(r.a);
+ v->flags |= vertex_t::LIT;
+}
+
+static void lightModelx(GLenum pname, GLfixed param, ogles_context_t* c)
+{
+ if (ggl_unlikely(pname != GL_LIGHT_MODEL_TWO_SIDE)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->lighting.lightModel.twoSide = param ? GL_TRUE : GL_FALSE;
+ invalidate_lighting(c);
+}
+
+static void lightx(GLenum i, GLenum pname, GLfixed param, ogles_context_t* c)
+{
+ if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ light_t& light = c->lighting.lights[i-GL_LIGHT0];
+ const GLfixed kDegToRad = GLfixed((M_PI * gglIntToFixed(1)) / 180.0f);
+ switch (pname) {
+ case GL_SPOT_EXPONENT:
+ if (GGLfixed(param) >= gglIntToFixed(128)) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ light.spotExp = param;
+ break;
+ case GL_SPOT_CUTOFF:
+ if (param!=gglIntToFixed(180) && GGLfixed(param)>=gglIntToFixed(90)) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ light.spotCutoff = param;
+ light.spotCutoffCosine =
+ gglFloatToFixed(cosinef((M_PI/(180.0f*65536.0f))*param));
+ break;
+ case GL_CONSTANT_ATTENUATION:
+ if (param < 0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ light.attenuation[0] = param;
+ break;
+ case GL_LINEAR_ATTENUATION:
+ if (param < 0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ light.attenuation[1] = param;
+ break;
+ case GL_QUADRATIC_ATTENUATION:
+ if (param < 0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ light.attenuation[2] = param;
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ invalidate_lighting(c);
+}
+
+static void lightxv(GLenum i, GLenum pname, const GLfixed *params, ogles_context_t* c)
+{
+ if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ GLfixed* what;
+ light_t& light = c->lighting.lights[i-GL_LIGHT0];
+ switch (pname) {
+ case GL_AMBIENT:
+ what = light.ambient.v;
+ break;
+ case GL_DIFFUSE:
+ what = light.diffuse.v;
+ break;
+ case GL_SPECULAR:
+ what = light.specular.v;
+ break;
+ case GL_POSITION: {
+ ogles_validate_transform(c, transform_state_t::MODELVIEW);
+ transform_t& mv = c->transforms.modelview.transform;
+ memcpy(light.position.v, params, sizeof(light.position.v));
+ mv.point4(&mv, &light.position, &light.position);
+ invalidate_lighting(c);
+ return;
+ }
+ case GL_SPOT_DIRECTION: {
+ ogles_validate_transform(c, transform_state_t::MVUI);
+ transform_t& mvui = c->transforms.mvui;
+ mvui.point3(&mvui, &light.spotDir, (vec4_t*)params);
+ vnorm3(light.normalizedSpotDir.v, light.spotDir.v);
+ invalidate_lighting(c);
+ return;
+ }
+ default:
+ lightx(i, pname, params[0], c);
+ return;
+ }
+ what[0] = params[0];
+ what[1] = params[1];
+ what[2] = params[2];
+ what[3] = params[3];
+ invalidate_lighting(c);
+}
+
+static void materialx(GLenum face, GLenum pname, GLfixed param, ogles_context_t* c)
+{
+ if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (ggl_unlikely(pname != GL_SHININESS)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->lighting.front.shininess = param;
+ invalidate_lighting(c);
+}
+
+static void fogx(GLenum pname, GLfixed param, ogles_context_t* c)
+{
+ switch (pname) {
+ case GL_FOG_DENSITY:
+ if (param >= 0) {
+ c->fog.density = param;
+ break;
+ }
+ ogles_error(c, GL_INVALID_VALUE);
+ break;
+ case GL_FOG_START:
+ c->fog.start = gglClampx(param);
+ c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start);
+ break;
+ case GL_FOG_END:
+ c->fog.end = gglClampx(param);
+ c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start);
+ break;
+ case GL_FOG_MODE:
+ switch (param) {
+ case GL_LINEAR:
+ c->fog.mode = param;
+ c->fog.fog = fog_linear;
+ break;
+ case GL_EXP:
+ c->fog.mode = param;
+ c->fog.fog = fog_exp;
+ break;
+ case GL_EXP2:
+ c->fog.mode = param;
+ c->fog.fog = fog_exp2;
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ break;
+ }
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ break;
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+#if 0
+#pragma mark -
+#pragma mark lighting APIs
+#endif
+
+void glShadeModel(GLenum mode)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (ggl_unlikely(mode != GL_SMOOTH && mode != GL_FLAT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->lighting.shadeModel = mode;
+}
+
+void glLightModelf(GLenum pname, GLfloat param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ lightModelx(pname, gglFloatToFixed(param), c);
+}
+
+void glLightModelx(GLenum pname, GLfixed param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ lightModelx(pname, param, c);
+}
+
+void glLightModelfv(GLenum pname, const GLfloat *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (pname == GL_LIGHT_MODEL_TWO_SIDE) {
+ lightModelx(pname, gglFloatToFixed(params[0]), c);
+ return;
+ }
+
+ if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ c->lighting.lightModel.ambient.r = gglFloatToFixed(params[0]);
+ c->lighting.lightModel.ambient.g = gglFloatToFixed(params[1]);
+ c->lighting.lightModel.ambient.b = gglFloatToFixed(params[2]);
+ c->lighting.lightModel.ambient.a = gglFloatToFixed(params[3]);
+ invalidate_lighting(c);
+}
+
+void glLightModelxv(GLenum pname, const GLfixed *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (pname == GL_LIGHT_MODEL_TWO_SIDE) {
+ lightModelx(pname, params[0], c);
+ return;
+ }
+
+ if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ c->lighting.lightModel.ambient.r = params[0];
+ c->lighting.lightModel.ambient.g = params[1];
+ c->lighting.lightModel.ambient.b = params[2];
+ c->lighting.lightModel.ambient.a = params[3];
+ invalidate_lighting(c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void glLightf(GLenum i, GLenum pname, GLfloat param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ lightx(i, pname, gglFloatToFixed(param), c);
+}
+
+void glLightx(GLenum i, GLenum pname, GLfixed param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ lightx(i, pname, param, c);
+}
+
+void glLightfv(GLenum i, GLenum pname, const GLfloat *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ switch (pname) {
+ case GL_SPOT_EXPONENT:
+ case GL_SPOT_CUTOFF:
+ case GL_CONSTANT_ATTENUATION:
+ case GL_LINEAR_ATTENUATION:
+ case GL_QUADRATIC_ATTENUATION:
+ lightx(i, pname, gglFloatToFixed(params[0]), c);
+ return;
+ }
+
+ GLfixed paramsx[4];
+ paramsx[0] = gglFloatToFixed(params[0]);
+ paramsx[1] = gglFloatToFixed(params[1]);
+ paramsx[2] = gglFloatToFixed(params[2]);
+ if (pname != GL_SPOT_DIRECTION)
+ paramsx[3] = gglFloatToFixed(params[3]);
+
+ lightxv(i, pname, paramsx, c);
+}
+
+void glLightxv(GLenum i, GLenum pname, const GLfixed *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ lightxv(i, pname, params, c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void glMaterialf(GLenum face, GLenum pname, GLfloat param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ materialx(face, pname, gglFloatToFixed(param), c);
+}
+
+void glMaterialx(GLenum face, GLenum pname, GLfixed param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ materialx(face, pname, param, c);
+}
+
+void glMaterialfv(
+ GLenum face, GLenum pname, const GLfloat *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ GLfixed* what=0;
+ GLfixed* other=0;
+ switch (pname) {
+ case GL_AMBIENT: what = c->lighting.front.ambient.v; break;
+ case GL_DIFFUSE: what = c->lighting.front.diffuse.v; break;
+ case GL_SPECULAR: what = c->lighting.front.specular.v; break;
+ case GL_EMISSION: what = c->lighting.front.emission.v; break;
+ case GL_AMBIENT_AND_DIFFUSE:
+ what = c->lighting.front.ambient.v; break;
+ other = c->lighting.front.diffuse.v; break;
+ break;
+ case GL_SHININESS:
+ c->lighting.front.shininess = gglFloatToFixed(params[0]);
+ invalidate_lighting(c);
+ return;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ what[0] = gglFloatToFixed(params[0]);
+ what[1] = gglFloatToFixed(params[1]);
+ what[2] = gglFloatToFixed(params[2]);
+ what[3] = gglFloatToFixed(params[3]);
+ if (other) {
+ other[0] = what[0];
+ other[1] = what[1];
+ other[2] = what[2];
+ other[3] = what[3];
+ }
+ invalidate_lighting(c);
+}
+
+void glMaterialxv(
+ GLenum face, GLenum pname, const GLfixed *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ GLfixed* what=0;
+ GLfixed* other=0;
+ switch (pname) {
+ case GL_AMBIENT: what = c->lighting.front.ambient.v; break;
+ case GL_DIFFUSE: what = c->lighting.front.diffuse.v; break;
+ case GL_SPECULAR: what = c->lighting.front.specular.v; break;
+ case GL_EMISSION: what = c->lighting.front.emission.v; break;
+ case GL_AMBIENT_AND_DIFFUSE:
+ what = c->lighting.front.ambient.v; break;
+ other= c->lighting.front.diffuse.v; break;
+ break;
+ case GL_SHININESS:
+ c->lighting.front.shininess = gglFloatToFixed(params[0]);
+ invalidate_lighting(c);
+ return;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ what[0] = params[0];
+ what[1] = params[1];
+ what[2] = params[2];
+ what[3] = params[3];
+ if (other) {
+ other[0] = what[0];
+ other[1] = what[1];
+ other[2] = what[2];
+ other[3] = what[3];
+ }
+ invalidate_lighting(c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark fog
+#endif
+
+void glFogf(GLenum pname, GLfloat param) {
+ ogles_context_t* c = ogles_context_t::get();
+ GLfixed paramx = (GLfixed)param;
+ if (pname != GL_FOG_MODE)
+ paramx = gglFloatToFixed(param);
+ fogx(pname, paramx, c);
+}
+
+void glFogx(GLenum pname, GLfixed param) {
+ ogles_context_t* c = ogles_context_t::get();
+ fogx(pname, param, c);
+}
+
+void glFogfv(GLenum pname, const GLfloat *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (pname != GL_FOG_COLOR) {
+ GLfixed paramx = (GLfixed)params[0];
+ if (pname != GL_FOG_MODE)
+ paramx = gglFloatToFixed(params[0]);
+ fogx(pname, paramx, c);
+ return;
+ }
+ GLfixed paramsx[4];
+ paramsx[0] = gglFloatToFixed(params[0]);
+ paramsx[1] = gglFloatToFixed(params[1]);
+ paramsx[2] = gglFloatToFixed(params[2]);
+ paramsx[3] = gglFloatToFixed(params[3]);
+ c->rasterizer.procs.fogColor3xv(c, paramsx);
+}
+
+void glFogxv(GLenum pname, const GLfixed *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (pname != GL_FOG_COLOR) {
+ fogx(pname, params[0], c);
+ return;
+ }
+ c->rasterizer.procs.fogColor3xv(c, params);
+}
diff --git a/opengl/libagl/light.h b/opengl/libagl/light.h
new file mode 100644
index 0000000..6dae25f
--- /dev/null
+++ b/opengl/libagl/light.h
@@ -0,0 +1,38 @@
+/* libs/opengles/light.h
+**
+** Copyright 2006, 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_OPENGLES_LIGHT_H
+#define ANDROID_OPENGLES_LIGHT_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+namespace android {
+
+namespace gl {
+struct ogles_context_t;
+};
+
+void ogles_init_light(ogles_context_t* c);
+void ogles_uninit_light(ogles_context_t* c);
+void ogles_invalidate_lighting_mvui(ogles_context_t* c);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_LIGHT_H
+
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
new file mode 100644
index 0000000..441da38
--- /dev/null
+++ b/opengl/libagl/matrix.cpp
@@ -0,0 +1,1144 @@
+/* libs/opengles/matrix.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "light.h"
+
+#if defined(__arm__) && defined(__thumb__)
+#warning "matrix.cpp should not be compiled in thumb on ARM."
+#endif
+
+#define I(_i, _j) ((_j)+ 4*(_i))
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static const GLfloat gIdentityf[16] = { 1,0,0,0,
+ 0,1,0,0,
+ 0,0,1,0,
+ 0,0,0,1 };
+
+static const matrixx_t gIdentityx = {
+ { 0x10000,0,0,0,
+ 0,0x10000,0,0,
+ 0,0,0x10000,0,
+ 0,0,0,0x10000
+ }
+ };
+
+static void point2__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point3__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point4__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void normal__nop(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+static void normal__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void ogles_init_matrix(ogles_context_t* c)
+{
+ c->transforms.modelview.init(OGLES_MODELVIEW_STACK_DEPTH);
+ c->transforms.projection.init(OGLES_PROJECTION_STACK_DEPTH);
+ for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
+ c->transforms.texture[i].init(OGLES_TEXTURE_STACK_DEPTH);
+
+ c->transforms.current = &c->transforms.modelview;
+ c->transforms.matrixMode = GL_MODELVIEW;
+ c->transforms.dirty = transform_state_t::VIEWPORT |
+ transform_state_t::MVUI |
+ transform_state_t::MVIT |
+ transform_state_t::MVP;
+ c->transforms.mvp.loadIdentity();
+ c->transforms.mvp4.loadIdentity();
+ c->transforms.mvit4.loadIdentity();
+ c->transforms.mvui.loadIdentity();
+ c->transforms.vpt.loadIdentity();
+ c->transforms.vpt.zNear = 0.0f;
+ c->transforms.vpt.zFar = 1.0f;
+}
+
+void ogles_uninit_matrix(ogles_context_t* c)
+{
+ c->transforms.modelview.uninit();
+ c->transforms.projection.uninit();
+ for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
+ c->transforms.texture[i].uninit();
+}
+
+static void validate_perspective(ogles_context_t* c, vertex_t* v)
+{
+ const uint32_t enables = c->rasterizer.state.enables;
+ c->arrays.perspective = (c->clipPlanes.enable) ?
+ ogles_vertex_clipAllPerspective3D : ogles_vertex_perspective3D;
+ if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
+ c->arrays.perspective = (c->clipPlanes.enable) ?
+ ogles_vertex_clipAllPerspective3DZ : ogles_vertex_perspective3DZ;
+ }
+ if ((c->arrays.vertex.size != 4) &&
+ (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)) {
+ c->arrays.perspective = ogles_vertex_perspective2D;
+ }
+ c->arrays.perspective(c, v);
+}
+
+void ogles_invalidate_perspective(ogles_context_t* c)
+{
+ c->arrays.perspective = validate_perspective;
+}
+
+void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want)
+{
+ int dirty = c->transforms.dirty & want;
+
+ // Validate the modelview
+ if (dirty & transform_state_t::MODELVIEW) {
+ c->transforms.modelview.validate();
+ }
+
+ // Validate the projection stack (in fact, it's never needed)
+ if (dirty & transform_state_t::PROJECTION) {
+ c->transforms.projection.validate();
+ }
+
+ // Validate the viewport transformation
+ if (dirty & transform_state_t::VIEWPORT) {
+ vp_transform_t& vpt = c->transforms.vpt;
+ vpt.transform.matrix.load(vpt.matrix);
+ vpt.transform.picker();
+ }
+
+ // We need to update the mvp (used to transform each vertex)
+ if (dirty & transform_state_t::MVP) {
+ c->transforms.update_mvp();
+ // invalidate perspective (divide by W) and view volume clipping
+ ogles_invalidate_perspective(c);
+ }
+
+ // Validate the mvui (for normal transformation)
+ if (dirty & transform_state_t::MVUI) {
+ c->transforms.update_mvui();
+ ogles_invalidate_lighting_mvui(c);
+ }
+
+ // Validate the texture stack
+ if (dirty & transform_state_t::TEXTURE) {
+ for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
+ c->transforms.texture[i].validate();
+ }
+
+ // Validate the mvit4 (user-clip planes)
+ if (dirty & transform_state_t::MVIT) {
+ c->transforms.update_mvit();
+ }
+
+ c->transforms.dirty &= ~want;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark transform_t
+#endif
+
+void transform_t::loadIdentity() {
+ matrix = gIdentityx;
+ flags = 0;
+ ops = OP_IDENTITY;
+ point2 = point2__nop;
+ point3 = point3__nop;
+ point4 = point4__nop;
+}
+
+
+static inline
+int notZero(GLfixed v) {
+ return abs(v) & ~0x3;
+}
+
+static inline
+int notOne(GLfixed v) {
+ return notZero(v - 0x10000);
+}
+
+void transform_t::picker()
+{
+ const GLfixed* const m = matrix.m;
+
+ // XXX: picker needs to be smarter
+ flags = 0;
+ ops = OP_ALL;
+ point2 = point2__generic;
+ point3 = point3__generic;
+ point4 = point4__generic;
+
+ // find out if this is a 2D projection
+ if (!(notZero(m[3]) | notZero(m[7]) | notZero(m[11]) | notOne(m[15]))) {
+ flags |= FLAGS_2D_PROJECTION;
+ }
+}
+
+void mvui_transform_t::picker()
+{
+ flags = 0;
+ ops = OP_ALL;
+ point3 = normal__generic;
+}
+
+void transform_t::dump(const char* what)
+{
+ GLfixed const * const m = matrix.m;
+ LOGD("%s:", what);
+ for (int i=0 ; i<4 ; i++)
+ LOGD("[%08x %08x %08x %08x] [%f %f %f %f]\n",
+ m[I(0,i)], m[I(1,i)], m[I(2,i)], m[I(3,i)],
+ fixedToFloat(m[I(0,i)]),
+ fixedToFloat(m[I(1,i)]),
+ fixedToFloat(m[I(2,i)]),
+ fixedToFloat(m[I(3,i)]));
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrixx_t
+#endif
+
+void matrixx_t::load(const matrixf_t& rhs) {
+ GLfixed* xp = m;
+ GLfloat const* fp = rhs.elements();
+ unsigned int i = 16;
+ do {
+ const GLfloat f = *fp++;
+ *xp++ = isZerof(f) ? 0 : gglFloatToFixed(f);
+ } while (--i);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrixf_t
+#endif
+
+void matrixf_t::multiply(matrixf_t& r, const matrixf_t& lhs, const matrixf_t& rhs)
+{
+ GLfloat const* const m = lhs.m;
+ for (int i=0 ; i<4 ; i++) {
+ register const float rhs_i0 = rhs.m[ I(i,0) ];
+ register float ri0 = m[ I(0,0) ] * rhs_i0;
+ register float ri1 = m[ I(0,1) ] * rhs_i0;
+ register float ri2 = m[ I(0,2) ] * rhs_i0;
+ register float ri3 = m[ I(0,3) ] * rhs_i0;
+ for (int j=1 ; j<4 ; j++) {
+ register const float rhs_ij = rhs.m[ I(i,j) ];
+ ri0 += m[ I(j,0) ] * rhs_ij;
+ ri1 += m[ I(j,1) ] * rhs_ij;
+ ri2 += m[ I(j,2) ] * rhs_ij;
+ ri3 += m[ I(j,3) ] * rhs_ij;
+ }
+ r.m[ I(i,0) ] = ri0;
+ r.m[ I(i,1) ] = ri1;
+ r.m[ I(i,2) ] = ri2;
+ r.m[ I(i,3) ] = ri3;
+ }
+}
+
+void matrixf_t::dump(const char* what) {
+ LOGD("%s", what);
+ LOGD("[ %9f %9f %9f %9f ]", m[I(0,0)], m[I(1,0)], m[I(2,0)], m[I(3,0)]);
+ LOGD("[ %9f %9f %9f %9f ]", m[I(0,1)], m[I(1,1)], m[I(2,1)], m[I(3,1)]);
+ LOGD("[ %9f %9f %9f %9f ]", m[I(0,2)], m[I(1,2)], m[I(2,2)], m[I(3,2)]);
+ LOGD("[ %9f %9f %9f %9f ]", m[I(0,3)], m[I(1,3)], m[I(2,3)], m[I(3,3)]);
+}
+
+void matrixf_t::loadIdentity() {
+ memcpy(m, gIdentityf, sizeof(m));
+}
+
+void matrixf_t::set(const GLfixed* rhs) {
+ load(rhs);
+}
+
+void matrixf_t::set(const GLfloat* rhs) {
+ load(rhs);
+}
+
+void matrixf_t::load(const GLfixed* rhs) {
+ GLfloat* fp = m;
+ unsigned int i = 16;
+ do {
+ *fp++ = fixedToFloat(*rhs++);
+ } while (--i);
+}
+
+void matrixf_t::load(const GLfloat* rhs) {
+ memcpy(m, rhs, sizeof(m));
+}
+
+void matrixf_t::load(const matrixf_t& rhs) {
+ operator = (rhs);
+}
+
+void matrixf_t::multiply(const matrixf_t& rhs) {
+ matrixf_t r;
+ multiply(r, *this, rhs);
+ operator = (r);
+}
+
+void matrixf_t::translate(GLfloat x, GLfloat y, GLfloat z) {
+ for (int i=0 ; i<4 ; i++) {
+ m[12+i] += m[i]*x + m[4+i]*y + m[8+i]*z;
+ }
+}
+
+void matrixf_t::scale(GLfloat x, GLfloat y, GLfloat z) {
+ for (int i=0 ; i<4 ; i++) {
+ m[ i] *= x;
+ m[4+i] *= y;
+ m[8+i] *= z;
+ }
+}
+
+void matrixf_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
+{
+ matrixf_t rotation;
+ GLfloat* r = rotation.m;
+ GLfloat c, s;
+ r[3] = 0; r[7] = 0; r[11]= 0;
+ r[12]= 0; r[13]= 0; r[14]= 0; r[15]= 1;
+ a *= GLfloat(M_PI / 180.0f);
+ sincosf(a, &s, &c);
+ if (isOnef(x) && isZerof(y) && isZerof(z)) {
+ r[5] = c; r[10]= c;
+ r[6] = s; r[9] = -s;
+ r[1] = 0; r[2] = 0;
+ r[4] = 0; r[8] = 0;
+ r[0] = 1;
+ } else if (isZerof(x) && isOnef(y) && isZerof(z)) {
+ r[0] = c; r[10]= c;
+ r[8] = s; r[2] = -s;
+ r[1] = 0; r[4] = 0;
+ r[6] = 0; r[9] = 0;
+ r[5] = 1;
+ } else if (isZerof(x) && isZerof(y) && isOnef(z)) {
+ r[0] = c; r[5] = c;
+ r[1] = s; r[4] = -s;
+ r[2] = 0; r[6] = 0;
+ r[8] = 0; r[9] = 0;
+ r[10]= 1;
+ } else {
+ const GLfloat len = sqrtf(x*x + y*y + z*z);
+ if (!isOnef(len)) {
+ const GLfloat recipLen = reciprocalf(len);
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ const GLfloat nc = 1.0f - c;
+ const GLfloat xy = x * y;
+ const GLfloat yz = y * z;
+ const GLfloat zx = z * x;
+ const GLfloat xs = x * s;
+ const GLfloat ys = y * s;
+ const GLfloat zs = z * s;
+ r[ 0] = x*x*nc + c; r[ 4] = xy*nc - zs; r[ 8] = zx*nc + ys;
+ r[ 1] = xy*nc + zs; r[ 5] = y*y*nc + c; r[ 9] = yz*nc - xs;
+ r[ 2] = zx*nc - ys; r[ 6] = yz*nc + xs; r[10] = z*z*nc + c;
+ }
+ multiply(rotation);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrix_stack_t
+#endif
+
+void matrix_stack_t::init(int depth) {
+ stack = new matrixf_t[depth];
+ ops = new uint8_t[depth];
+ maxDepth = depth;
+ depth = 0;
+ dirty = 0;
+ loadIdentity();
+}
+
+void matrix_stack_t::uninit() {
+ delete [] stack;
+ delete [] ops;
+}
+
+void matrix_stack_t::loadIdentity() {
+ transform.loadIdentity();
+ stack[depth].loadIdentity();
+ ops[depth] = OP_IDENTITY;
+}
+
+void matrix_stack_t::load(const GLfixed* rhs)
+{
+ memcpy(transform.matrix.m, rhs, sizeof(transform.matrix.m));
+ stack[depth].load(rhs);
+ ops[depth] = OP_ALL; // TODO: we should look at the matrix
+}
+
+void matrix_stack_t::load(const GLfloat* rhs)
+{
+ stack[depth].load(rhs);
+ ops[depth] = OP_ALL; // TODO: we should look at the matrix
+}
+
+void matrix_stack_t::multiply(const matrixf_t& rhs)
+{
+ stack[depth].multiply(rhs);
+ ops[depth] = OP_ALL; // TODO: we should look at the matrix
+}
+
+void matrix_stack_t::translate(GLfloat x, GLfloat y, GLfloat z)
+{
+ stack[depth].translate(x,y,z);
+ ops[depth] |= OP_TRANSLATE;
+}
+
+void matrix_stack_t::scale(GLfloat x, GLfloat y, GLfloat z)
+{
+ stack[depth].scale(x,y,z);
+ if (x==y && y==z) {
+ ops[depth] |= OP_UNIFORM_SCALE;
+ } else {
+ ops[depth] |= OP_SCALE;
+ }
+}
+
+void matrix_stack_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
+{
+ stack[depth].rotate(a,x,y,z);
+ ops[depth] |= OP_ROTATE;
+}
+
+void matrix_stack_t::validate()
+{
+ if (dirty & DO_FLOAT_TO_FIXED) {
+ transform.matrix.load(top());
+ }
+ if (dirty & DO_PICKER) {
+ transform.picker();
+ }
+ dirty = 0;
+}
+
+GLint matrix_stack_t::push()
+{
+ if (depth >= (maxDepth-1)) {
+ return GL_STACK_OVERFLOW;
+ }
+ stack[depth+1] = stack[depth];
+ ops[depth+1] = ops[depth];
+ depth++;
+ return 0;
+}
+
+GLint matrix_stack_t::pop()
+{
+ if (depth == 0) {
+ return GL_STACK_UNDERFLOW;
+ }
+ depth--;
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark vp_transform_t
+#endif
+
+void vp_transform_t::loadIdentity() {
+ transform.loadIdentity();
+ matrix.loadIdentity();
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark transform_state_t
+#endif
+
+void transform_state_t::invalidate()
+{
+ switch (matrixMode) {
+ case GL_MODELVIEW: dirty |= MODELVIEW | MVP | MVUI | MVIT; break;
+ case GL_PROJECTION: dirty |= PROJECTION | MVP; break;
+ case GL_TEXTURE: dirty |= TEXTURE | MVP; break;
+ }
+ current->dirty = matrix_stack_t::DO_PICKER |
+ matrix_stack_t::DO_FLOAT_TO_FIXED;
+}
+
+void transform_state_t::update_mvp()
+{
+ matrixf_t temp_mvp;
+ matrixf_t::multiply(temp_mvp, projection.top(), modelview.top());
+ mvp4.matrix.load(temp_mvp);
+ mvp4.picker();
+
+ if (mvp4.flags & transform_t::FLAGS_2D_PROJECTION) {
+ // the mvp matrix doesn't transform W, in this case we can
+ // premultiply it with the viewport transformation. In addition to
+ // being more efficient, this is also much more accurate and in fact
+ // is needed for 2D drawing with a resulting 1:1 mapping.
+ matrixf_t mvpv;
+ matrixf_t::multiply(mvpv, vpt.matrix, temp_mvp);
+ mvp.matrix.load(mvpv);
+ mvp.picker();
+ } else {
+ mvp = mvp4;
+ }
+}
+
+static inline
+GLfloat det22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
+ return a*d - b*c;
+}
+
+static inline
+GLfloat ndet22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
+ return b*c - a*d;
+}
+
+static __attribute__((noinline))
+void invert(GLfloat* inverse, const GLfloat* src)
+{
+ double t;
+ int i, j, k, swap;
+ GLfloat tmp[4][4];
+
+ memcpy(inverse, gIdentityf, sizeof(gIdentityf));
+ memcpy(tmp, src, sizeof(GLfloat)*16);
+
+ for (i = 0; i < 4; i++) {
+ // look for largest element in column
+ swap = i;
+ for (j = i + 1; j < 4; j++) {
+ if (fabs(tmp[j][i]) > fabs(tmp[i][i])) {
+ swap = j;
+ }
+ }
+
+ if (swap != i) {
+ /* swap rows. */
+ for (k = 0; k < 4; k++) {
+ t = tmp[i][k];
+ tmp[i][k] = tmp[swap][k];
+ tmp[swap][k] = t;
+
+ t = inverse[i*4+k];
+ inverse[i*4+k] = inverse[swap*4+k];
+ inverse[swap*4+k] = t;
+ }
+ }
+
+ t = 1.0f / tmp[i][i];
+ for (k = 0; k < 4; k++) {
+ tmp[i][k] *= t;
+ inverse[i*4+k] *= t;
+ }
+ for (j = 0; j < 4; j++) {
+ if (j != i) {
+ t = tmp[j][i];
+ for (k = 0; k < 4; k++) {
+ tmp[j][k] -= tmp[i][k]*t;
+ inverse[j*4+k] -= inverse[i*4+k]*t;
+ }
+ }
+ }
+ }
+}
+
+void transform_state_t::update_mvit()
+{
+ GLfloat r[16];
+ const GLfloat* const mv = modelview.top().elements();
+ invert(r, mv);
+ // convert to fixed-point and transpose
+ GLfixed* const x = mvit4.matrix.m;
+ for (int i=0 ; i<4 ; i++)
+ for (int j=0 ; j<4 ; j++)
+ x[I(i,j)] = gglFloatToFixed(r[I(j,i)]);
+ mvit4.picker();
+}
+
+void transform_state_t::update_mvui()
+{
+ const GLfloat* const mv = modelview.top().elements();
+
+ /*
+ When transforming normals, we can use the upper 3x3 matrix, see:
+ http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node26.html
+ */
+
+ // Also note that:
+ // l(obj) = tr(M).l(eye) for infinite light
+ // l(obj) = inv(M).l(eye) for local light
+
+ const uint32_t ops = modelview.top_ops() & ~OP_TRANSLATE;
+ if (ggl_likely((!(ops & ~OP_ROTATE)) ||
+ (rescaleNormals && modelview.isRigidBody()))) {
+ // if the modelview matrix is a rigid body transformation
+ // (translation, rotation, uniform scaling), then we can bypass
+ // the inverse by transposing the matrix.
+ GLfloat rescale = 1.0f;
+ if (rescaleNormals == GL_RESCALE_NORMAL) {
+ if (!(ops & ~OP_UNIFORM_SCALE)) {
+ rescale = reciprocalf(mv[I(0,0)]);
+ } else {
+ rescale = rsqrtf(
+ sqrf(mv[I(2,0)]) + sqrf(mv[I(2,1)]) + sqrf(mv[I(2,2)]));
+ }
+ }
+ GLfixed* const x = mvui.matrix.m;
+ for (int i=0 ; i<3 ; i++) {
+ x[I(i,0)] = gglFloatToFixed(mv[I(0,i)] * rescale);
+ x[I(i,1)] = gglFloatToFixed(mv[I(1,i)] * rescale);
+ x[I(i,2)] = gglFloatToFixed(mv[I(2,i)] * rescale);
+ }
+ mvui.picker();
+ return;
+ }
+
+ GLfloat r[3][3];
+ r[0][0] = det22(mv[I(1,1)], mv[I(2,1)], mv[I(1,2)], mv[I(2,2)]);
+ r[0][1] =ndet22(mv[I(0,1)], mv[I(2,1)], mv[I(0,2)], mv[I(2,2)]);
+ r[0][2] = det22(mv[I(0,1)], mv[I(1,1)], mv[I(0,2)], mv[I(1,2)]);
+ r[1][0] =ndet22(mv[I(1,0)], mv[I(2,0)], mv[I(1,2)], mv[I(2,2)]);
+ r[1][1] = det22(mv[I(0,0)], mv[I(2,0)], mv[I(0,2)], mv[I(2,2)]);
+ r[1][2] =ndet22(mv[I(0,0)], mv[I(1,0)], mv[I(0,2)], mv[I(1,2)]);
+ r[2][0] = det22(mv[I(1,0)], mv[I(2,0)], mv[I(1,1)], mv[I(2,1)]);
+ r[2][1] =ndet22(mv[I(0,0)], mv[I(2,0)], mv[I(0,1)], mv[I(2,1)]);
+ r[2][2] = det22(mv[I(0,0)], mv[I(1,0)], mv[I(0,1)], mv[I(1,1)]);
+
+ GLfloat rdet;
+ if (rescaleNormals == GL_RESCALE_NORMAL) {
+ rdet = rsqrtf(sqrf(r[0][2]) + sqrf(r[1][2]) + sqrf(r[2][2]));
+ } else {
+ rdet = reciprocalf(
+ r[0][0]*mv[I(0,0)] + r[0][1]*mv[I(1,0)] + r[0][2]*mv[I(2,0)]);
+ }
+
+ GLfixed* const x = mvui.matrix.m;
+ for (int i=0 ; i<3 ; i++) {
+ x[I(i,0)] = gglFloatToFixed(r[i][0] * rdet);
+ x[I(i,1)] = gglFloatToFixed(r[i][1] * rdet);
+ x[I(i,2)] = gglFloatToFixed(r[i][2] * rdet);
+ }
+ mvui.picker();
+}
+
+
+// ----------------------------------------------------------------------------
+// transformation and matrices API
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark transformation and matrices API
+#endif
+
+int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y)
+{
+ c->viewport.surfaceport.x = x;
+ c->viewport.surfaceport.y = y;
+
+ ogles_viewport(c,
+ c->viewport.x,
+ c->viewport.y,
+ c->viewport.w,
+ c->viewport.h);
+
+ ogles_scissor(c,
+ c->viewport.scissor.x,
+ c->viewport.scissor.y,
+ c->viewport.scissor.w,
+ c->viewport.scissor.h);
+
+ return 0;
+}
+
+void ogles_scissor(ogles_context_t* c,
+ GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ if ((w|h) < 0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ c->viewport.scissor.x = x;
+ c->viewport.scissor.y = y;
+ c->viewport.scissor.w = w;
+ c->viewport.scissor.h = h;
+
+ x += c->viewport.surfaceport.x;
+ y += c->viewport.surfaceport.y;
+
+ y = c->rasterizer.state.buffers.color.height - (y + h);
+ c->rasterizer.procs.scissor(c, x, y, w, h);
+}
+
+void ogles_viewport(ogles_context_t* c,
+ GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ if ((w|h)<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ c->viewport.x = x;
+ c->viewport.y = y;
+ c->viewport.w = w;
+ c->viewport.h = h;
+
+ x += c->viewport.surfaceport.x;
+ y += c->viewport.surfaceport.y;
+
+ GLint H = c->rasterizer.state.buffers.color.height;
+ GLfloat sx = div2f(w);
+ GLfloat ox = sx + x;
+ GLfloat sy = div2f(h);
+ GLfloat oy = sy - y + (H - h);
+
+ GLfloat near = c->transforms.vpt.zNear;
+ GLfloat far = c->transforms.vpt.zFar;
+ GLfloat A = div2f(far - near);
+ GLfloat B = div2f(far + near);
+
+ // compute viewport matrix
+ GLfloat* const f = c->transforms.vpt.matrix.editElements();
+ f[0] = sx; f[4] = 0; f[ 8] = 0; f[12] = ox;
+ f[1] = 0; f[5] =-sy; f[ 9] = 0; f[13] = oy;
+ f[2] = 0; f[6] = 0; f[10] = A; f[14] = B;
+ f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1;
+ c->transforms.dirty |= transform_state_t::VIEWPORT;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark matrix * vertex
+#endif
+
+void point2__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+ const GLfixed* const m = mx->matrix.m;
+ const GLfixed rx = rhs->x;
+ const GLfixed ry = rhs->y;
+ lhs->x = mla2a(rx, m[ 0], ry, m[ 4], m[12]);
+ lhs->y = mla2a(rx, m[ 1], ry, m[ 5], m[13]);
+ lhs->z = mla2a(rx, m[ 2], ry, m[ 6], m[14]);
+ lhs->w = mla2a(rx, m[ 3], ry, m[ 7], m[15]);
+}
+
+void point3__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+ const GLfixed* const m = mx->matrix.m;
+ const GLfixed rx = rhs->x;
+ const GLfixed ry = rhs->y;
+ const GLfixed rz = rhs->z;
+ lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
+ lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
+ lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
+ lhs->w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
+}
+
+void point4__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+ const GLfixed* const m = mx->matrix.m;
+ const GLfixed rx = rhs->x;
+ const GLfixed ry = rhs->y;
+ const GLfixed rz = rhs->z;
+ const GLfixed rw = rhs->w;
+ lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]);
+ lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]);
+ lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]);
+ lhs->w = mla4(rx, m[ 3], ry, m[ 7], rz, m[11], rw, m[15]);
+}
+
+void normal__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+ const GLfixed* const m = mx->matrix.m;
+ const GLfixed rx = rhs->x;
+ const GLfixed ry = rhs->y;
+ const GLfixed rz = rhs->z;
+ lhs->x = mla3(rx, m[ 0], ry, m[ 4], rz, m[ 8]);
+ lhs->y = mla3(rx, m[ 1], ry, m[ 5], rz, m[ 9]);
+ lhs->z = mla3(rx, m[ 2], ry, m[ 6], rz, m[10]);
+}
+
+
+void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
+ lhs->z = 0;
+ lhs->w = 0x10000;
+ if (lhs != rhs) {
+ lhs->x = rhs->x;
+ lhs->y = rhs->y;
+ }
+}
+
+void point3__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
+ lhs->w = 0x10000;
+ if (lhs != rhs) {
+ lhs->x = rhs->x;
+ lhs->y = rhs->y;
+ lhs->z = rhs->z;
+ }
+}
+
+void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
+ if (lhs != rhs)
+ *lhs = *rhs;
+}
+
+
+static void frustumf(
+ GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar,
+ ogles_context_t* c)
+ {
+ if (cmpf(left,right) ||
+ cmpf(top, bottom) ||
+ cmpf(zNear, zFar) ||
+ isZeroOrNegativef(zNear) ||
+ isZeroOrNegativef(zFar))
+ {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ const GLfloat r_width = reciprocalf(right - left);
+ const GLfloat r_height = reciprocalf(top - bottom);
+ const GLfloat r_depth = reciprocalf(zNear - zFar);
+ const GLfloat x = mul2f(zNear * r_width);
+ const GLfloat y = mul2f(zNear * r_height);
+ const GLfloat A = mul2f((right + left) * r_width);
+ const GLfloat B = (top + bottom) * r_height;
+ const GLfloat C = (zFar + zNear) * r_depth;
+ const GLfloat D = mul2f(zFar * zNear * r_depth);
+ GLfloat f[16];
+ f[ 0] = x;
+ f[ 5] = y;
+ f[ 8] = A;
+ f[ 9] = B;
+ f[10] = C;
+ f[14] = D;
+ f[11] = -1.0f;
+ f[ 1] = f[ 2] = f[ 3] =
+ f[ 4] = f[ 6] = f[ 7] =
+ f[12] = f[13] = f[15] = 0.0f;
+
+ matrixf_t rhs;
+ rhs.set(f);
+ c->transforms.current->multiply(rhs);
+ c->transforms.invalidate();
+}
+
+static void orthof(
+ GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar,
+ ogles_context_t* c)
+{
+ if (cmpf(left,right) ||
+ cmpf(top, bottom) ||
+ cmpf(zNear, zFar))
+ {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ const GLfloat r_width = reciprocalf(right - left);
+ const GLfloat r_height = reciprocalf(top - bottom);
+ const GLfloat r_depth = reciprocalf(zFar - zNear);
+ const GLfloat x = mul2f(r_width);
+ const GLfloat y = mul2f(r_height);
+ const GLfloat z = -mul2f(r_depth);
+ const GLfloat tx = -(right + left) * r_width;
+ const GLfloat ty = -(top + bottom) * r_height;
+ const GLfloat tz = -(zFar + zNear) * r_depth;
+ GLfloat f[16];
+ f[ 0] = x;
+ f[ 5] = y;
+ f[10] = z;
+ f[12] = tx;
+ f[13] = ty;
+ f[14] = tz;
+ f[15] = 1.0f;
+ f[ 1] = f[ 2] = f[ 3] =
+ f[ 4] = f[ 6] = f[ 7] =
+ f[ 8] = f[ 9] = f[11] = 0.0f;
+ matrixf_t rhs;
+ rhs.set(f);
+ c->transforms.current->multiply(rhs);
+ c->transforms.invalidate();
+}
+
+static void depthRangef(GLclampf zNear, GLclampf zFar, ogles_context_t* c)
+{
+ zNear = clampToZerof(zNear > 1 ? 1 : zNear);
+ zFar = clampToZerof(zFar > 1 ? 1 : zFar);
+ GLfloat* const f = c->transforms.vpt.matrix.editElements();
+ f[10] = div2f(zFar - zNear);
+ f[14] = div2f(zFar + zNear);
+ c->transforms.dirty |= transform_state_t::VIEWPORT;
+ c->transforms.vpt.zNear = zNear;
+ c->transforms.vpt.zFar = zFar;
+}
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+using namespace android;
+
+void glMatrixMode(GLenum mode)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ matrix_stack_t* stack = 0;
+ switch (mode) {
+ case GL_MODELVIEW:
+ stack = &c->transforms.modelview;
+ break;
+ case GL_PROJECTION:
+ stack = &c->transforms.projection;
+ break;
+ case GL_TEXTURE:
+ stack = &c->transforms.texture[c->textures.active];
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->transforms.matrixMode = mode;
+ c->transforms.current = stack;
+}
+
+void glLoadIdentity()
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->loadIdentity(); // also loads the GLfixed transform
+ c->transforms.invalidate();
+ c->transforms.current->dirty = 0;
+}
+
+void glLoadMatrixf(const GLfloat* m)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->load(m);
+ c->transforms.invalidate();
+}
+
+void glLoadMatrixx(const GLfixed* m)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->load(m); // also loads the GLfixed transform
+ c->transforms.invalidate();
+ c->transforms.current->dirty &= ~matrix_stack_t::DO_FLOAT_TO_FIXED;
+}
+
+void glMultMatrixf(const GLfloat* m)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ matrixf_t rhs;
+ rhs.set(m);
+ c->transforms.current->multiply(rhs);
+ c->transforms.invalidate();
+}
+
+void glMultMatrixx(const GLfixed* m)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ matrixf_t rhs;
+ rhs.set(m);
+ c->transforms.current->multiply(rhs);
+ c->transforms.invalidate();
+}
+
+void glPopMatrix()
+{
+ ogles_context_t* c = ogles_context_t::get();
+ GLint err = c->transforms.current->pop();
+ if (ggl_unlikely(err)) {
+ ogles_error(c, err);
+ return;
+ }
+ c->transforms.invalidate();
+}
+
+void glPushMatrix()
+{
+ ogles_context_t* c = ogles_context_t::get();
+ GLint err = c->transforms.current->push();
+ if (ggl_unlikely(err)) {
+ ogles_error(c, err);
+ return;
+ }
+ c->transforms.invalidate();
+}
+
+void glFrustumf(
+ GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ frustumf(left, right, bottom, top, zNear, zFar, c);
+}
+
+void glFrustumx(
+ GLfixed left, GLfixed right,
+ GLfixed bottom, GLfixed top,
+ GLfixed zNear, GLfixed zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ frustumf( fixedToFloat(left), fixedToFloat(right),
+ fixedToFloat(bottom), fixedToFloat(top),
+ fixedToFloat(zNear), fixedToFloat(zFar),
+ c);
+}
+
+void glOrthof(
+ GLfloat left, GLfloat right,
+ GLfloat bottom, GLfloat top,
+ GLfloat zNear, GLfloat zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ orthof(left, right, bottom, top, zNear, zFar, c);
+}
+
+void glOrthox(
+ GLfixed left, GLfixed right,
+ GLfixed bottom, GLfixed top,
+ GLfixed zNear, GLfixed zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ orthof( fixedToFloat(left), fixedToFloat(right),
+ fixedToFloat(bottom), fixedToFloat(top),
+ fixedToFloat(zNear), fixedToFloat(zFar),
+ c);
+}
+
+void glRotatef(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->rotate(a, x, y, z);
+ c->transforms.invalidate();
+}
+
+void glRotatex(GLfixed a, GLfixed x, GLfixed y, GLfixed z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->rotate(
+ fixedToFloat(a), fixedToFloat(x),
+ fixedToFloat(y), fixedToFloat(z));
+ c->transforms.invalidate();
+}
+
+void glScalef(GLfloat x, GLfloat y, GLfloat z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->scale(x, y, z);
+ c->transforms.invalidate();
+}
+
+void glScalex(GLfixed x, GLfixed y, GLfixed z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->scale(
+ fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));
+ c->transforms.invalidate();
+}
+
+void glTranslatef(GLfloat x, GLfloat y, GLfloat z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->translate(x, y, z);
+ c->transforms.invalidate();
+}
+
+void glTranslatex(GLfixed x, GLfixed y, GLfixed z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->transforms.current->translate(
+ fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));
+ c->transforms.invalidate();
+}
+
+void glScissor(GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ ogles_scissor(c, x, y, w, h);
+}
+
+void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ ogles_viewport(c, x, y, w, h);
+}
+
+void glDepthRangef(GLclampf zNear, GLclampf zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ depthRangef(zNear, zFar, c);
+}
+
+void glDepthRangex(GLclampx zNear, GLclampx zFar)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c);
+}
+
+void glPolygonOffsetx(GLfixed factor, GLfixed units)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->polygonOffset.factor = factor;
+ c->polygonOffset.units = units;
+}
+
+void glPolygonOffset(GLfloat factor, GLfloat units)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->polygonOffset.factor = gglFloatToFixed(factor);
+ c->polygonOffset.units = gglFloatToFixed(units);
+}
+
+GLbitfield glQueryMatrixxOES(GLfixed* m, GLint* e)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ GLbitfield status = 0;
+ GLfloat const* f = c->transforms.current->top().elements();
+ for (int i=0 ; i<16 ; i++) {
+ if (isnan(f[i]) || isinf(f[i])) {
+ status |= 1<<i;
+ continue;
+ }
+ e[i] = exponent(f[i]) - 7;
+ m[i] = mantissa(f[i]);
+ }
+ return status;
+}
diff --git a/opengl/libagl/matrix.h b/opengl/libagl/matrix.h
new file mode 100644
index 0000000..c9a38a9
--- /dev/null
+++ b/opengl/libagl/matrix.h
@@ -0,0 +1,355 @@
+/* libs/opengles/matrix.h
+**
+** Copyright 2006, 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_OPENGLES_MATRIX_H
+#define ANDROID_OPENGLES_MATRIX_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+namespace android {
+
+const int OGLES_MODELVIEW_STACK_DEPTH = 16;
+const int OGLES_PROJECTION_STACK_DEPTH = 2;
+const int OGLES_TEXTURE_STACK_DEPTH = 2;
+
+void ogles_init_matrix(ogles_context_t*);
+void ogles_uninit_matrix(ogles_context_t*);
+void ogles_invalidate_perspective(ogles_context_t* c);
+void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want);
+
+int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y);
+
+void ogles_scissor(ogles_context_t* c,
+ GLint x, GLint y, GLsizei w, GLsizei h);
+
+void ogles_viewport(ogles_context_t* c,
+ GLint x, GLint y, GLsizei w, GLsizei h);
+
+inline void ogles_validate_transform(
+ ogles_context_t* c, uint32_t want)
+{
+ if (c->transforms.dirty & want)
+ ogles_validate_transform_impl(c, want);
+}
+
+// ----------------------------------------------------------------------------
+
+inline
+GLfixed vsquare3(GLfixed a, GLfixed b, GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ int32_t t;
+ asm(
+ "smull %0, %1, %2, %2 \n"
+ "smlal %0, %1, %3, %3 \n"
+ "smlal %0, %1, %4, %4 \n"
+ "movs %0, %0, lsr #16 \n"
+ "adc %0, %0, %1, lsl #16 \n"
+ : "=&r"(r), "=&r"(t)
+ : "%r"(a), "r"(b), "r"(c)
+ : "cc"
+ );
+ return r;
+
+#else
+
+ return (( int64_t(a)*a +
+ int64_t(b)*b +
+ int64_t(c)*c + 0x8000)>>16);
+
+#endif
+}
+
+static inline GLfixed mla2a( GLfixed a0, GLfixed b0,
+ GLfixed a1, GLfixed b1,
+ GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ int32_t t;
+ asm(
+ "smull %0, %1, %2, %3 \n"
+ "smlal %0, %1, %4, %5 \n"
+ "add %0, %6, %0, lsr #16 \n"
+ "add %0, %0, %1, lsl #16 \n"
+ : "=&r"(r), "=&r"(t)
+ : "%r"(a0), "r"(b0),
+ "%r"(a1), "r"(b1),
+ "r"(c)
+ :
+ );
+ return r;
+
+#else
+
+ return (( int64_t(a0)*b0 +
+ int64_t(a1)*b1)>>16) + c;
+
+#endif
+}
+
+static inline GLfixed mla3a( GLfixed a0, GLfixed b0,
+ GLfixed a1, GLfixed b1,
+ GLfixed a2, GLfixed b2,
+ GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ int32_t t;
+ asm(
+ "smull %0, %1, %2, %3 \n"
+ "smlal %0, %1, %4, %5 \n"
+ "smlal %0, %1, %6, %7 \n"
+ "add %0, %8, %0, lsr #16 \n"
+ "add %0, %0, %1, lsl #16 \n"
+ : "=&r"(r), "=&r"(t)
+ : "%r"(a0), "r"(b0),
+ "%r"(a1), "r"(b1),
+ "%r"(a2), "r"(b2),
+ "r"(c)
+ :
+ );
+ return r;
+
+#else
+
+ return (( int64_t(a0)*b0 +
+ int64_t(a1)*b1 +
+ int64_t(a2)*b2)>>16) + c;
+
+#endif
+}
+
+// b0, b1, b2 are signed 16-bit quanities
+// that have been shifted right by 'shift' bits relative to normal
+// S16.16 fixed point
+static inline GLfixed mla3a16( GLfixed a0, int32_t b1b0,
+ GLfixed a1,
+ GLfixed a2, int32_t b2,
+ GLint shift,
+ GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ asm(
+ "smulwb %0, %1, %2 \n"
+ "smlawt %0, %3, %2, %0 \n"
+ "smlawb %0, %4, %5, %0 \n"
+ "add %0, %7, %0, lsl %6 \n"
+ : "=&r"(r)
+ : "r"(a0), "r"(b1b0),
+ "r"(a1),
+ "r"(a2), "r"(b2),
+ "r"(shift),
+ "r"(c)
+ :
+ );
+ return r;
+
+#else
+
+ int32_t accum;
+ int16_t b0 = b1b0 & 0xffff;
+ int16_t b1 = (b1b0 >> 16) & 0xffff;
+ accum = int64_t(a0)*int16_t(b0) >> 16;
+ accum += int64_t(a1)*int16_t(b1) >> 16;
+ accum += int64_t(a2)*int16_t(b2) >> 16;
+ accum = (accum << shift) + c;
+ return accum;
+
+#endif
+}
+
+
+static inline GLfixed mla3a16_btb( GLfixed a0,
+ GLfixed a1,
+ GLfixed a2,
+ int32_t b1b0, int32_t xxb2,
+ GLint shift,
+ GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ asm(
+ "smulwb %0, %1, %4 \n"
+ "smlawt %0, %2, %4, %0 \n"
+ "smlawb %0, %3, %5, %0 \n"
+ "add %0, %7, %0, lsl %6 \n"
+ : "=&r"(r)
+ : "r"(a0),
+ "r"(a1),
+ "r"(a2),
+ "r"(b1b0), "r"(xxb2),
+ "r"(shift),
+ "r"(c)
+ :
+ );
+ return r;
+
+#else
+
+ int32_t accum;
+ int16_t b0 = b1b0 & 0xffff;
+ int16_t b1 = (b1b0 >> 16) & 0xffff;
+ int16_t b2 = xxb2 & 0xffff;
+ accum = int64_t(a0)*int16_t(b0) >> 16;
+ accum += int64_t(a1)*int16_t(b1) >> 16;
+ accum += int64_t(a2)*int16_t(b2) >> 16;
+ accum = (accum << shift) + c;
+ return accum;
+
+#endif
+}
+
+static inline GLfixed mla3a16_btt( GLfixed a0,
+ GLfixed a1,
+ GLfixed a2,
+ int32_t b1b0, int32_t b2xx,
+ GLint shift,
+ GLfixed c)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ asm(
+ "smulwb %0, %1, %4 \n"
+ "smlawt %0, %2, %4, %0 \n"
+ "smlawt %0, %3, %5, %0 \n"
+ "add %0, %7, %0, lsl %6 \n"
+ : "=&r"(r)
+ : "r"(a0),
+ "r"(a1),
+ "r"(a2),
+ "r"(b1b0), "r"(b2xx),
+ "r"(shift),
+ "r"(c)
+ :
+ );
+ return r;
+
+#else
+
+ int32_t accum;
+ int16_t b0 = b1b0 & 0xffff;
+ int16_t b1 = (b1b0 >> 16) & 0xffff;
+ int16_t b2 = (b2xx >> 16) & 0xffff;
+ accum = int64_t(a0)*int16_t(b0) >> 16;
+ accum += int64_t(a1)*int16_t(b1) >> 16;
+ accum += int64_t(a2)*int16_t(b2) >> 16;
+ accum = (accum << shift) + c;
+ return accum;
+
+#endif
+}
+
+static inline GLfixed mla3( GLfixed a0, GLfixed b0,
+ GLfixed a1, GLfixed b1,
+ GLfixed a2, GLfixed b2)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ int32_t t;
+ asm(
+ "smull %0, %1, %2, %3 \n"
+ "smlal %0, %1, %4, %5 \n"
+ "smlal %0, %1, %6, %7 \n"
+ "movs %0, %0, lsr #16 \n"
+ "adc %0, %0, %1, lsl #16 \n"
+ : "=&r"(r), "=&r"(t)
+ : "%r"(a0), "r"(b0),
+ "%r"(a1), "r"(b1),
+ "%r"(a2), "r"(b2)
+ : "cc"
+ );
+ return r;
+
+#else
+
+ return (( int64_t(a0)*b0 +
+ int64_t(a1)*b1 +
+ int64_t(a2)*b2 + 0x8000)>>16);
+
+#endif
+}
+
+static inline GLfixed mla4( GLfixed a0, GLfixed b0,
+ GLfixed a1, GLfixed b1,
+ GLfixed a2, GLfixed b2,
+ GLfixed a3, GLfixed b3)
+{
+#if defined(__arm__) && !defined(__thumb__)
+
+ GLfixed r;
+ int32_t t;
+ asm(
+ "smull %0, %1, %2, %3 \n"
+ "smlal %0, %1, %4, %5 \n"
+ "smlal %0, %1, %6, %7 \n"
+ "smlal %0, %1, %8, %9 \n"
+ "movs %0, %0, lsr #16 \n"
+ "adc %0, %0, %1, lsl #16 \n"
+ : "=&r"(r), "=&r"(t)
+ : "%r"(a0), "r"(b0),
+ "%r"(a1), "r"(b1),
+ "%r"(a2), "r"(b2),
+ "%r"(a3), "r"(b3)
+ : "cc"
+ );
+ return r;
+
+#else
+
+ return (( int64_t(a0)*b0 +
+ int64_t(a1)*b1 +
+ int64_t(a2)*b2 +
+ int64_t(a3)*b3 + 0x8000)>>16);
+
+#endif
+}
+
+inline
+GLfixed dot4(const GLfixed* a, const GLfixed* b)
+{
+ return mla4(a[0], b[0], a[1], b[1], a[2], b[2], a[3], b[3]);
+}
+
+
+inline
+GLfixed dot3(const GLfixed* a, const GLfixed* b)
+{
+ return mla3(a[0], b[0], a[1], b[1], a[2], b[2]);
+}
+
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_MATRIX_H
+
diff --git a/opengl/libagl/mipmap.cpp b/opengl/libagl/mipmap.cpp
new file mode 100644
index 0000000..ccd77b7
--- /dev/null
+++ b/opengl/libagl/mipmap.cpp
@@ -0,0 +1,192 @@
+/* libs/opengles/mipmap.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "context.h"
+#include "state.h"
+#include "texture.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex)
+{
+ int level = 0;
+ const GGLSurface* base = &tex->surface;
+ const GGLFormat& pixelFormat(c->rasterizer.formats[base->format]);
+
+ int w = base->width;
+ int h = base->height;
+ if ((w&h) == 1)
+ return NO_ERROR;
+
+ w = (w>>1) ? : 1;
+ h = (h>>1) ? : 1;
+
+ while(true) {
+ ++level;
+ const int bpr = w * pixelFormat.size;
+ if (tex->reallocate(level, w, h, w,
+ base->format, base->compressedFormat, bpr) != NO_ERROR) {
+ return NO_MEMORY;
+ }
+
+ int stride = w;
+ int bs = base->stride;
+ GGLSurface& cur = tex->editMip(level);
+
+ if (base->format == GGL_PIXEL_FORMAT_RGB_565)
+ {
+ uint16_t const * src = (uint16_t const *)base->data;
+ uint16_t* dst = (uint16_t*)cur.data;
+ const uint32_t mask = 0x07E0F81F;
+ for (int y=0 ; y<h ; y++) {
+ size_t offset = (y*2) * bs;
+ for (int x=0 ; x<w ; x++) {
+ uint32_t p00 = src[offset];
+ uint32_t p10 = src[offset+1];
+ uint32_t p01 = src[offset+bs];
+ uint32_t p11 = src[offset+bs+1];
+ p00 = (p00 | (p00 << 16)) & mask;
+ p01 = (p01 | (p01 << 16)) & mask;
+ p10 = (p10 | (p10 << 16)) & mask;
+ p11 = (p11 | (p11 << 16)) & mask;
+ uint32_t grb = ((p00 + p10 + p01 + p11) >> 2) & mask;
+ uint32_t rgb = (grb & 0xFFFF) | (grb >> 16);
+ dst[x + y*stride] = rgb;
+ offset += 2;
+ }
+ }
+ }
+ else if (base->format == GGL_PIXEL_FORMAT_RGBA_5551)
+ {
+ uint16_t const * src = (uint16_t const *)base->data;
+ uint16_t* dst = (uint16_t*)cur.data;
+ for (int y=0 ; y<h ; y++) {
+ size_t offset = (y*2) * bs;
+ for (int x=0 ; x<w ; x++) {
+ uint32_t p00 = src[offset];
+ uint32_t p10 = src[offset+1];
+ uint32_t p01 = src[offset+bs];
+ uint32_t p11 = src[offset+bs+1];
+ uint32_t r = ((p00>>11)+(p10>>11)+(p01>>11)+(p11>>11)+2)>>2;
+ uint32_t g = (((p00>>6)+(p10>>6)+(p01>>6)+(p11>>6)+2)>>2)&0x3F;
+ uint32_t b = ((p00&0x3E)+(p10&0x3E)+(p01&0x3E)+(p11&0x3E)+4)>>3;
+ uint32_t a = ((p00&1)+(p10&1)+(p01&1)+(p11&1)+2)>>2;
+ dst[x + y*stride] = (r<<11)|(g<<6)|(b<<1)|a;
+ offset += 2;
+ }
+ }
+ }
+ else if (base->format == GGL_PIXEL_FORMAT_RGBA_8888)
+ {
+ uint32_t const * src = (uint32_t const *)base->data;
+ uint32_t* dst = (uint32_t*)cur.data;
+ for (int y=0 ; y<h ; y++) {
+ size_t offset = (y*2) * bs;
+ for (int x=0 ; x<w ; x++) {
+ uint32_t p00 = src[offset];
+ uint32_t p10 = src[offset+1];
+ uint32_t p01 = src[offset+bs];
+ uint32_t p11 = src[offset+bs+1];
+ uint32_t rb00 = p00 & 0x00FF00FF;
+ uint32_t rb01 = p01 & 0x00FF00FF;
+ uint32_t rb10 = p10 & 0x00FF00FF;
+ uint32_t rb11 = p11 & 0x00FF00FF;
+ uint32_t ga00 = (p00 >> 8) & 0x00FF00FF;
+ uint32_t ga01 = (p01 >> 8) & 0x00FF00FF;
+ uint32_t ga10 = (p10 >> 8) & 0x00FF00FF;
+ uint32_t ga11 = (p11 >> 8) & 0x00FF00FF;
+ uint32_t rb = (rb00 + rb01 + rb10 + rb11)>>2;
+ uint32_t ga = (ga00 + ga01 + ga10 + ga11)>>2;
+ uint32_t rgba = (rb & 0x00FF00FF) | ((ga & 0x00FF00FF)<<8);
+ dst[x + y*stride] = rgba;
+ offset += 2;
+ }
+ }
+ }
+ else if ((base->format == GGL_PIXEL_FORMAT_RGB_888) ||
+ (base->format == GGL_PIXEL_FORMAT_LA_88) ||
+ (base->format == GGL_PIXEL_FORMAT_A_8) ||
+ (base->format == GGL_PIXEL_FORMAT_L_8))
+ {
+ int skip;
+ switch (base->format) {
+ case GGL_PIXEL_FORMAT_RGB_888: skip = 3; break;
+ case GGL_PIXEL_FORMAT_LA_88: skip = 2; break;
+ default: skip = 1; break;
+ }
+ uint8_t const * src = (uint8_t const *)base->data;
+ uint8_t* dst = (uint8_t*)cur.data;
+ bs *= skip;
+ stride *= skip;
+ for (int y=0 ; y<h ; y++) {
+ size_t offset = (y*2) * bs;
+ for (int x=0 ; x<w ; x++) {
+ for (int c=0 ; c<skip ; c++) {
+ uint32_t p00 = src[c+offset];
+ uint32_t p10 = src[c+offset+skip];
+ uint32_t p01 = src[c+offset+bs];
+ uint32_t p11 = src[c+offset+bs+skip];
+ dst[x + y*stride + c] = (p00 + p10 + p01 + p11) >> 2;
+ }
+ offset += 2*skip;
+ }
+ }
+ }
+ else if (base->format == GGL_PIXEL_FORMAT_RGBA_4444)
+ {
+ uint16_t const * src = (uint16_t const *)base->data;
+ uint16_t* dst = (uint16_t*)cur.data;
+ for (int y=0 ; y<h ; y++) {
+ size_t offset = (y*2) * bs;
+ for (int x=0 ; x<w ; x++) {
+ uint32_t p00 = src[offset];
+ uint32_t p10 = src[offset+1];
+ uint32_t p01 = src[offset+bs];
+ uint32_t p11 = src[offset+bs+1];
+ p00 = ((p00 << 12) & 0x0F0F0000) | (p00 & 0x0F0F);
+ p10 = ((p10 << 12) & 0x0F0F0000) | (p10 & 0x0F0F);
+ p01 = ((p01 << 12) & 0x0F0F0000) | (p01 & 0x0F0F);
+ p11 = ((p11 << 12) & 0x0F0F0000) | (p11 & 0x0F0F);
+ uint32_t rbga = (p00 + p10 + p01 + p11) >> 2;
+ uint32_t rgba = (rbga & 0x0F0F) | ((rbga>>12) & 0xF0F0);
+ dst[x + y*stride] = rgba;
+ offset += 2;
+ }
+ }
+ } else {
+ LOGE("Unsupported format (%d)", base->format);
+ return BAD_TYPE;
+ }
+
+ // exit condition: we just processed the 1x1 LODs
+ if ((w&h) == 1)
+ break;
+
+ base = &cur;
+ w = (w>>1) ? : 1;
+ h = (h>>1) ? : 1;
+ }
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp
new file mode 100644
index 0000000..20e8d37
--- /dev/null
+++ b/opengl/libagl/primitives.cpp
@@ -0,0 +1,1095 @@
+/* libs/opengles/primitives.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "context.h"
+#include "primitives.h"
+#include "light.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "fp.h"
+#include "TextureObjectManager.h"
+
+extern "C" void iterators0032(const void* that,
+ int32_t* it, int32_t c0, int32_t c1, int32_t c2);
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void primitive_point(ogles_context_t* c, vertex_t* v);
+static void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1);
+static void primitive_clip_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void primitive_nop_point(ogles_context_t* c, vertex_t* v);
+static void primitive_nop_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1);
+static void primitive_nop_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static inline bool cull_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void lerp_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void lerp_texcoords(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void lerp_texcoords_w(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static void clip_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+
+static unsigned int clip_line(ogles_context_t* c,
+ vertex_t* s, vertex_t* p);
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+static void lightTriangleDarkSmooth(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ if (!(v0->flags & vertex_t::LIT)) {
+ v0->flags |= vertex_t::LIT;
+ const GLvoid* cp = c->arrays.color.element(
+ v0->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v0->color.v, cp);
+ }
+ if (!(v1->flags & vertex_t::LIT)) {
+ v1->flags |= vertex_t::LIT;
+ const GLvoid* cp = c->arrays.color.element(
+ v1->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v1->color.v, cp);
+ }
+ if(!(v2->flags & vertex_t::LIT)) {
+ v2->flags |= vertex_t::LIT;
+ const GLvoid* cp = c->arrays.color.element(
+ v2->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v2->color.v, cp);
+ }
+}
+
+static void lightTriangleDarkFlat(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ if (!(v2->flags & vertex_t::LIT)) {
+ v2->flags |= vertex_t::LIT;
+ const GLvoid* cp = c->arrays.color.element(
+ v2->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v2->color.v, cp);
+ }
+ // configure the rasterizer here, before we clip
+ c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+static void lightTriangleSmooth(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ if (!(v0->flags & vertex_t::LIT))
+ c->lighting.lightVertex(c, v0);
+ if (!(v1->flags & vertex_t::LIT))
+ c->lighting.lightVertex(c, v1);
+ if(!(v2->flags & vertex_t::LIT))
+ c->lighting.lightVertex(c, v2);
+}
+
+static void lightTriangleFlat(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ if (!(v2->flags & vertex_t::LIT))
+ c->lighting.lightVertex(c, v2);
+ // configure the rasterizer here, before we clip
+ c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+// The fog versions...
+
+static inline
+void lightVertexDarkSmoothFog(ogles_context_t* c, vertex_t* v)
+{
+ if (!(v->flags & vertex_t::LIT)) {
+ v->flags |= vertex_t::LIT;
+ v->fog = c->fog.fog(c, v->window.z);
+ const GLvoid* cp = c->arrays.color.element(
+ v->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v->color.v, cp);
+ }
+}
+static inline
+void lightVertexDarkFlatFog(ogles_context_t* c, vertex_t* v)
+{
+ if (!(v->flags & vertex_t::LIT)) {
+ v->flags |= vertex_t::LIT;
+ v->fog = c->fog.fog(c, v->window.z);
+ }
+}
+static inline
+void lightVertexSmoothFog(ogles_context_t* c, vertex_t* v)
+{
+ if (!(v->flags & vertex_t::LIT)) {
+ v->fog = c->fog.fog(c, v->window.z);
+ c->lighting.lightVertex(c, v);
+ }
+}
+
+static void lightTriangleDarkSmoothFog(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ lightVertexDarkSmoothFog(c, v0);
+ lightVertexDarkSmoothFog(c, v1);
+ lightVertexDarkSmoothFog(c, v2);
+}
+
+static void lightTriangleDarkFlatFog(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ lightVertexDarkFlatFog(c, v0);
+ lightVertexDarkFlatFog(c, v1);
+ lightVertexDarkSmoothFog(c, v2);
+ // configure the rasterizer here, before we clip
+ c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+static void lightTriangleSmoothFog(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ lightVertexSmoothFog(c, v0);
+ lightVertexSmoothFog(c, v1);
+ lightVertexSmoothFog(c, v2);
+}
+
+static void lightTriangleFlatFog(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ lightVertexDarkFlatFog(c, v0);
+ lightVertexDarkFlatFog(c, v1);
+ lightVertexSmoothFog(c, v2);
+ // configure the rasterizer here, before we clip
+ c->rasterizer.procs.color4xv(c, v2->color.v);
+}
+
+
+
+typedef void (*light_primitive_t)(ogles_context_t*,
+ vertex_t*, vertex_t*, vertex_t*);
+
+// fog 0x4, light 0x2, smooth 0x1
+static const light_primitive_t lightPrimitive[8] = {
+ lightTriangleDarkFlat, // no fog | dark | flat
+ lightTriangleDarkSmooth, // no fog | dark | smooth
+ lightTriangleFlat, // no fog | light | flat
+ lightTriangleSmooth, // no fog | light | smooth
+ lightTriangleDarkFlatFog, // fog | dark | flat
+ lightTriangleDarkSmoothFog, // fog | dark | smooth
+ lightTriangleFlatFog, // fog | light | flat
+ lightTriangleSmoothFog // fog | light | smooth
+};
+
+void ogles_validate_primitives(ogles_context_t* c)
+{
+ const uint32_t enables = c->rasterizer.state.enables;
+
+ // set up the lighting/shading/smoothing/fogging function
+ int index = enables & GGL_ENABLE_SMOOTH ? 0x1 : 0;
+ index |= c->lighting.enable ? 0x2 : 0;
+ index |= enables & GGL_ENABLE_FOG ? 0x4 : 0;
+ c->lighting.lightTriangle = lightPrimitive[index];
+
+ // set up the primitive renderers
+ if (ggl_likely(c->arrays.vertex.enable)) {
+ c->prims.renderPoint = primitive_point;
+ c->prims.renderLine = primitive_line;
+ c->prims.renderTriangle = primitive_clip_triangle;
+ } else {
+ c->prims.renderPoint = primitive_nop_point;
+ c->prims.renderLine = primitive_nop_line;
+ c->prims.renderTriangle = primitive_nop_triangle;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void compute_iterators_t::initTriangle(
+ vertex_t const* v0, vertex_t const* v1, vertex_t const* v2)
+{
+ m_dx01 = v1->window.x - v0->window.x;
+ m_dy10 = v0->window.y - v1->window.y;
+ m_dx20 = v0->window.x - v2->window.x;
+ m_dy02 = v2->window.y - v0->window.y;
+ m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
+}
+
+void compute_iterators_t::initLerp(vertex_t const* v0, uint32_t enables)
+{
+ m_x0 = v0->window.x;
+ m_y0 = v0->window.y;
+ const GGLcoord area = (m_area + TRI_HALF) >> TRI_FRACTION_BITS;
+ const GGLcoord minArea = 2; // cannot be inversed
+ // triangles with an area smaller than 1.0 are not smooth-shaded
+
+ int q=0, s=0, d=0;
+ if (abs(area) >= minArea) {
+ // Here we do some voodoo magic, to compute a suitable scale
+ // factor for deltas/area:
+
+ // First compute the 1/area with full 32-bits precision,
+ // gglRecipQNormalized returns a number [-0.5, 0.5[ and an exponent.
+ d = gglRecipQNormalized(area, &q);
+
+ // Then compute the minimum left-shift to not overflow the muls
+ // below.
+ s = 32 - gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20));
+
+ // We'll keep 16-bits of precision for deltas/area. So we need
+ // to shift everything left an extra 15 bits.
+ s += 15;
+
+ // make sure all final shifts are not > 32, because gglMulx
+ // can't handle it.
+ if (s < q) s = q;
+ if (s > 32) {
+ d >>= 32-s;
+ s = 32;
+ }
+ }
+
+ m_dx01 = gglMulx(m_dx01, d, s);
+ m_dy10 = gglMulx(m_dy10, d, s);
+ m_dx20 = gglMulx(m_dx20, d, s);
+ m_dy02 = gglMulx(m_dy02, d, s);
+ m_area_scale = 32 + q - s;
+ m_scale = 0;
+
+ if (enables & GGL_ENABLE_TMUS) {
+ const int A = gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20));
+ const int B = gglClz(abs(m_x0)|abs(m_y0));
+ m_scale = max(0, 32 - (A + 16)) +
+ max(0, 32 - (B + TRI_FRACTION_BITS)) + 1;
+ }
+}
+
+int compute_iterators_t::iteratorsScale(GGLfixed* it,
+ int32_t c0, int32_t c1, int32_t c2) const
+{
+ int32_t dc01 = c1 - c0;
+ int32_t dc02 = c2 - c0;
+ const int A = gglClz(abs(c0));
+ const int B = gglClz(abs(dc01)|abs(dc02));
+ const int scale = min(A, B - m_scale) - 2;
+ if (scale >= 0) {
+ c0 <<= scale;
+ dc01 <<= scale;
+ dc02 <<= scale;
+ } else {
+ c0 >>= -scale;
+ dc01 >>= -scale;
+ dc02 >>= -scale;
+ }
+ const int s = m_area_scale;
+ int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s);
+ int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s);
+ int32_t c = c0 - (gglMulAddx(dcdx, m_x0,
+ gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS));
+ it[0] = c;
+ it[1] = dcdx;
+ it[2] = dcdy;
+ return scale;
+}
+
+void compute_iterators_t::iterators1616(GGLfixed* it,
+ GGLfixed c0, GGLfixed c1, GGLfixed c2) const
+{
+ const GGLfixed dc01 = c1 - c0;
+ const GGLfixed dc02 = c2 - c0;
+ // 16.16 x 16.16 == 32.32 --> 16.16
+ const int s = m_area_scale;
+ int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s);
+ int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s);
+ int32_t c = c0 - (gglMulAddx(dcdx, m_x0,
+ gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS));
+ it[0] = c;
+ it[1] = dcdx;
+ it[2] = dcdy;
+}
+
+#if defined(__arm__) && !defined(__thumb__)
+inline void compute_iterators_t::iterators0032(int32_t* it,
+ int32_t c0, int32_t c1, int32_t c2) const
+{
+ ::iterators0032(this, it, c0, c1, c2);
+}
+#else
+void compute_iterators_t::iterators0032(int32_t* it,
+ int32_t c0, int32_t c1, int32_t c2) const
+{
+ const int s = m_area_scale - 16;
+ int32_t dc01 = (c1 - c0)>>s;
+ int32_t dc02 = (c2 - c0)>>s;
+ // 16.16 x 16.16 == 32.32
+ int64_t dcdx = gglMulii(dc01, m_dy02) + gglMulii(dc02, m_dy10);
+ int64_t dcdy = gglMulii(dc02, m_dx01) + gglMulii(dc01, m_dx20);
+ int32_t c = (c0<<16) - ((dcdx*m_x0 + dcdy*m_y0)>>4);
+ it[ 0] = c;
+ it[ 1] = dcdx;
+ it[ 2] = dcdy;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+static inline int32_t clampZ(GLfixed z) CONST;
+int32_t clampZ(GLfixed z) {
+ z = (z & ~(z>>31));
+ if (z >= 0x10000)
+ z = 0xFFFF;
+ return z;
+}
+
+static __attribute__((noinline))
+void fetch_texcoord_impl(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ vertex_t* const vtx[3] = { v0, v1, v2 };
+ array_t const * const texcoordArray = c->arrays.texture;
+
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (!(c->rasterizer.state.texture[i].enable))
+ continue;
+
+ for (int j=0 ; j<3 ; j++) {
+ vertex_t* const v = vtx[j];
+ if (v->flags & vertex_t::TT)
+ continue;
+
+ // NOTE: here we could compute automatic texgen
+ // such as sphere/cube maps, instead of fetching them
+ // from the textcoord array.
+
+ vec4_t& coords = v->texture[i];
+ const GLubyte* tp = texcoordArray[i].element(
+ v->index & vertex_cache_t::INDEX_MASK);
+ texcoordArray[i].fetch(c, coords.v, tp);
+
+ // transform texture coordinates...
+ coords.Q = 0x10000;
+ const transform_t& tr = c->transforms.texture[i].transform;
+ if (ggl_unlikely(tr.ops)) {
+ c->arrays.tex_transform[i](&tr, &coords, &coords);
+ }
+
+ // divide by Q
+ const GGLfixed q = coords.Q;
+ if (ggl_unlikely(q != 0x10000)) {
+ const int32_t qinv = gglRecip28(q);
+ coords.S = gglMulx(coords.S, qinv, 28);
+ coords.T = gglMulx(coords.T, qinv, 28);
+ }
+ }
+ }
+ v0->flags |= vertex_t::TT;
+ v1->flags |= vertex_t::TT;
+ v2->flags |= vertex_t::TT;
+}
+
+inline void fetch_texcoord(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (!(enables & GGL_ENABLE_TMUS))
+ return;
+
+ // Fetch & transform texture coordinates...
+ if (ggl_likely(v0->flags & v1->flags & v2->flags & vertex_t::TT)) {
+ // already done for all three vertices, bail...
+ return;
+ }
+ fetch_texcoord_impl(c, v0, v1, v2);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Point
+#endif
+
+void primitive_nop_point(ogles_context_t*, vertex_t*) {
+}
+
+void primitive_point(ogles_context_t* c, vertex_t* v)
+{
+ // lighting & clamping...
+ const uint32_t enables = c->rasterizer.state.enables;
+
+ if (ggl_unlikely(!(v->flags & vertex_t::LIT))) {
+ if (c->lighting.enable) {
+ c->lighting.lightVertex(c, v);
+ } else {
+ v->flags |= vertex_t::LIT;
+ const GLvoid* cp = c->arrays.color.element(
+ v->index & vertex_cache_t::INDEX_MASK);
+ c->arrays.color.fetch(c, v->color.v, cp);
+ }
+ if (enables & GGL_ENABLE_FOG) {
+ v->fog = c->fog.fog(c, v->window.z);
+ }
+ }
+
+ // XXX: we don't need to do that each-time
+ // if color array and lighting not enabled
+ c->rasterizer.procs.color4xv(c, v->color.v);
+
+ // XXX: look into ES point-sprite extension
+ if (enables & GGL_ENABLE_TMUS) {
+ fetch_texcoord(c, v,v,v);
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (!c->rasterizer.state.texture[i].enable)
+ continue;
+ int32_t itt[8];
+ itt[1] = itt[2] = itt[4] = itt[5] = 0;
+ itt[6] = itt[7] = 16; // XXX: check that
+ if (c->rasterizer.state.texture[i].s_wrap == GGL_CLAMP) {
+ int width = c->textures.tmu[i].texture->surface.width;
+ itt[0] = v->texture[i].S * width;
+ itt[6] = 0;
+ }
+ if (c->rasterizer.state.texture[i].t_wrap == GGL_CLAMP) {
+ int height = c->textures.tmu[i].texture->surface.height;
+ itt[3] = v->texture[i].T * height;
+ itt[7] = 0;
+ }
+ c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
+ }
+ }
+
+ if (enables & GGL_ENABLE_DEPTH_TEST) {
+ int32_t itz[3];
+ itz[0] = clampZ(v->window.z) * 0x00010001;
+ itz[1] = itz[2] = 0;
+ c->rasterizer.procs.zGrad3xv(c, itz);
+ }
+
+ if (enables & GGL_ENABLE_FOG) {
+ GLfixed itf[3];
+ itf[0] = v->fog;
+ itf[1] = itf[2] = 0;
+ c->rasterizer.procs.fogGrad3xv(c, itf);
+ }
+
+ // Render our point...
+ c->rasterizer.procs.pointx(c, v->window.v, c->point.size);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Line
+#endif
+
+void primitive_nop_line(ogles_context_t*, vertex_t*, vertex_t*) {
+}
+
+void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1)
+{
+ // This is a cheezy implementation of line drawing that
+ // uses 2 triangles per line.
+ // That said, how often line drawing is used?
+
+ // get texture coordinates
+ fetch_texcoord(c, v0, v1, v1);
+
+ // light/shade the vertices first (they're copied below)
+ c->lighting.lightTriangle(c, v0, v1, v1);
+
+ vertex_t v[4];
+ v[0] = *v0;
+ v[1] = *v1;
+ v0 = &v[0];
+ v1 = &v[1];
+
+ // clip the line if needed
+ if (ggl_unlikely((v0->flags | v1->flags) & vertex_t::CLIP_ALL)) {
+ unsigned int count = clip_line(c, v0, v1);
+ if (ggl_unlikely(count == 0))
+ return;
+ }
+
+ // compute iterators...
+ const uint32_t enables = c->rasterizer.state.enables;
+ const uint32_t mask = GGL_ENABLE_TMUS |
+ GGL_ENABLE_SMOOTH |
+ GGL_ENABLE_W |
+ GGL_ENABLE_FOG |
+ GGL_ENABLE_DEPTH_TEST;
+
+ if (ggl_unlikely(enables & mask)) {
+ c->lerp.initTriangle(v0, v1, v1);
+ lerp_triangle(c, v0, v1, v1);
+ }
+
+ // render our line
+ c->rasterizer.procs.linex(c, v0->window.v, v1->window.v, c->line.width);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Triangle
+#endif
+
+void primitive_nop_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2) {
+}
+
+void primitive_clip_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ uint32_t cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL;
+ if (ggl_likely(!cc)) {
+ // code below must be as optimized as possible, this is the
+ // common code path.
+
+ // This triangle is not clipped, test if it's culled
+ // unclipped triangle...
+ c->lerp.initTriangle(v0, v1, v2);
+ if (cull_triangle(c, v0, v1, v2))
+ return; // culled!
+
+ // Fetch all texture coordinates if needed
+ fetch_texcoord(c, v0, v1, v2);
+
+ // light (or shade) our triangle!
+ c->lighting.lightTriangle(c, v0, v1, v2);
+
+ triangle(c, v0, v1, v2);
+ return;
+ }
+
+ // The assumption here is that we're not going to clip very often,
+ // and even more rarely will we clip a triangle that ends up
+ // being culled out. So it's okay to light the vertices here, even though
+ // in a few cases we won't render the triangle (if culled).
+
+ // Fetch texture coordinates...
+ fetch_texcoord(c, v0, v1, v2);
+
+ // light (or shade) our triangle!
+ c->lighting.lightTriangle(c, v0, v1, v2);
+
+ clip_triangle(c, v0, v1, v2);
+}
+
+// -----------------------------------------------------------------------
+
+void triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ // compute iterators...
+ const uint32_t enables = c->rasterizer.state.enables;
+ const uint32_t mask = GGL_ENABLE_TMUS |
+ GGL_ENABLE_SMOOTH |
+ GGL_ENABLE_W |
+ GGL_ENABLE_FOG |
+ GGL_ENABLE_DEPTH_TEST;
+
+ if (ggl_likely(enables & mask))
+ lerp_triangle(c, v0, v1, v2);
+
+ c->rasterizer.procs.trianglex(c, v0->window.v, v1->window.v, v2->window.v);
+}
+
+void lerp_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ const uint32_t enables = c->rasterizer.state.enables;
+ c->lerp.initLerp(v0, enables);
+
+ // set up texture iterators
+ if (enables & GGL_ENABLE_TMUS) {
+ if (enables & GGL_ENABLE_W) {
+ lerp_texcoords_w(c, v0, v1, v2);
+ } else {
+ lerp_texcoords(c, v0, v1, v2);
+ }
+ }
+
+ // set up the color iterators
+ const compute_iterators_t& lerp = c->lerp;
+ if (enables & GGL_ENABLE_SMOOTH) {
+ GLfixed itc[12];
+ for (int i=0 ; i<4 ; i++) {
+ const GGLcolor c0 = v0->color.v[i] * 255;
+ const GGLcolor c1 = v1->color.v[i] * 255;
+ const GGLcolor c2 = v2->color.v[i] * 255;
+ lerp.iterators1616(&itc[i*3], c0, c1, c2);
+ }
+ c->rasterizer.procs.colorGrad12xv(c, itc);
+ }
+
+ if (enables & GGL_ENABLE_DEPTH_TEST) {
+ int32_t itz[3];
+ const int32_t v0z = clampZ(v0->window.z);
+ const int32_t v1z = clampZ(v1->window.z);
+ const int32_t v2z = clampZ(v2->window.z);
+ lerp.iterators0032(itz, v0z, v1z, v2z);
+ if (ggl_unlikely(c->polygonOffset.enable)) {
+ const GLfixed factor = c->polygonOffset.factor;
+ const GLfixed units = c->polygonOffset.units;
+ int32_t maxDepthSlope = max(abs(itz[1]), abs(itz[2]));
+ int32_t offset = (int64_t(maxDepthSlope)*factor +
+ (int64_t(units) << 16)) >> 16;
+ itz[0] += offset; // XXX: this can cause overflows
+ }
+ c->rasterizer.procs.zGrad3xv(c, itz);
+ }
+
+ if (ggl_unlikely(enables & GGL_ENABLE_FOG)) {
+ GLfixed itf[3];
+ lerp.iterators1616(itf, v0->fog, v1->fog, v2->fog);
+ c->rasterizer.procs.fogGrad3xv(c, itf);
+ }
+}
+
+
+static inline
+int compute_lod(ogles_context_t* c, int i,
+ int32_t s0, int32_t t0, int32_t s1, int32_t t1, int32_t s2, int32_t t2)
+{
+ // Compute mipmap level / primitive
+ // rho = sqrt( texelArea / area )
+ // lod = log2( rho )
+ // lod = log2( texelArea / area ) / 2
+ // lod = (log2( texelArea ) - log2( area )) / 2
+ const compute_iterators_t& lerp = c->lerp;
+ const GGLcoord area = abs(lerp.area());
+ const int w = c->textures.tmu[i].texture->surface.width;
+ const int h = c->textures.tmu[i].texture->surface.height;
+ const int shift = 16 + (16 - TRI_FRACTION_BITS);
+ int32_t texelArea = abs( gglMulx(s1-s0, t2-t0, shift) -
+ gglMulx(s2-s0, t1-t0, shift) )*w*h;
+ int log2TArea = (32-TRI_FRACTION_BITS -1) - gglClz(texelArea);
+ int log2Area = (32-TRI_FRACTION_BITS*2-1) - gglClz(area);
+ int lod = (log2TArea - log2Area + 1) >> 1;
+ return lod;
+}
+
+void lerp_texcoords(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ const compute_iterators_t& lerp = c->lerp;
+ int32_t itt[8] __attribute__((aligned(16)));
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ const texture_t& tmu = c->rasterizer.state.texture[i];
+ if (!tmu.enable)
+ continue;
+
+ // compute the jacobians using block floating-point
+ int32_t s0 = v0->texture[i].S;
+ int32_t t0 = v0->texture[i].T;
+ int32_t s1 = v1->texture[i].S;
+ int32_t t1 = v1->texture[i].T;
+ int32_t s2 = v2->texture[i].S;
+ int32_t t2 = v2->texture[i].T;
+
+ const GLenum min_filter = c->textures.tmu[i].texture->min_filter;
+ if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) {
+ int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2);
+ c->rasterizer.procs.bindTextureLod(c, i,
+ &c->textures.tmu[i].texture->mip(lod));
+ }
+
+ // premultiply (s,t) when clampling
+ if (tmu.s_wrap == GGL_CLAMP) {
+ const int width = tmu.surface.width;
+ s0 *= width;
+ s1 *= width;
+ s2 *= width;
+ }
+ if (tmu.t_wrap == GGL_CLAMP) {
+ const int height = tmu.surface.height;
+ t0 *= height;
+ t1 *= height;
+ t2 *= height;
+ }
+ itt[6] = -lerp.iteratorsScale(itt+0, s0, s1, s2);
+ itt[7] = -lerp.iteratorsScale(itt+3, t0, t1, t2);
+ c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
+ }
+}
+
+void lerp_texcoords_w(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ const compute_iterators_t& lerp = c->lerp;
+ int32_t itt[8] __attribute__((aligned(16)));
+ int32_t itw[3];
+
+ // compute W's scale to 2.30
+ int32_t w0 = v0->window.w;
+ int32_t w1 = v1->window.w;
+ int32_t w2 = v2->window.w;
+ int wscale = 32 - gglClz(w0|w1|w2);
+
+ // compute the jacobian using block floating-point
+ int sc = lerp.iteratorsScale(itw, w0, w1, w2);
+ sc += wscale - 16;
+ c->rasterizer.procs.wGrad3xv(c, itw);
+
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ const texture_t& tmu = c->rasterizer.state.texture[i];
+ if (!tmu.enable)
+ continue;
+
+ // compute the jacobians using block floating-point
+ int32_t s0 = v0->texture[i].S;
+ int32_t t0 = v0->texture[i].T;
+ int32_t s1 = v1->texture[i].S;
+ int32_t t1 = v1->texture[i].T;
+ int32_t s2 = v2->texture[i].S;
+ int32_t t2 = v2->texture[i].T;
+
+ const GLenum min_filter = c->textures.tmu[i].texture->min_filter;
+ if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) {
+ int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2);
+ c->rasterizer.procs.bindTextureLod(c, i,
+ &c->textures.tmu[i].texture->mip(lod));
+ }
+
+ // premultiply (s,t) when clampling
+ if (tmu.s_wrap == GGL_CLAMP) {
+ const int width = tmu.surface.width;
+ s0 *= width;
+ s1 *= width;
+ s2 *= width;
+ }
+ if (tmu.t_wrap == GGL_CLAMP) {
+ const int height = tmu.surface.height;
+ t0 *= height;
+ t1 *= height;
+ t2 *= height;
+ }
+
+ s0 = gglMulx(s0, w0, wscale);
+ t0 = gglMulx(t0, w0, wscale);
+ s1 = gglMulx(s1, w1, wscale);
+ t1 = gglMulx(t1, w1, wscale);
+ s2 = gglMulx(s2, w2, wscale);
+ t2 = gglMulx(t2, w2, wscale);
+
+ itt[6] = sc - lerp.iteratorsScale(itt+0, s0, s1, s2);
+ itt[7] = sc - lerp.iteratorsScale(itt+3, t0, t1, t2);
+ c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
+ }
+}
+
+
+static inline
+bool cull_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ if (ggl_likely(c->cull.enable)) {
+ const GLenum winding = (c->lerp.area() > 0) ? GL_CW : GL_CCW;
+ const GLenum face = (winding == c->cull.frontFace) ? GL_FRONT : GL_BACK;
+ if (face == c->cull.cullFace)
+ return true; // culled!
+ }
+ return false;
+}
+
+static inline
+GLfixed frustumPlaneDist(int plane, const vec4_t& s)
+{
+ const GLfixed d = s.v[ plane >> 1 ];
+ return ((plane & 1) ? (s.w - d) : (s.w + d));
+}
+
+static inline
+int32_t clipDivide(GLfixed a, GLfixed b) {
+ // returns a 4.28 fixed-point
+ return gglMulDivi(1LU<<28, a, b);
+}
+
+void clip_triangle(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2)
+{
+ uint32_t all_cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL;
+
+ vertex_t *p0, *p1, *p2;
+ const int MAX_CLIPPING_PLANES = 6 + OGLES_MAX_CLIP_PLANES;
+ const int MAX_VERTICES = 3;
+
+ // Temporary buffer to hold the new vertices. Each plane can add up to
+ // two new vertices (because the polygon is convex).
+ // We need one extra element, to handle an overflow case when
+ // the polygon degenerates into something non convex.
+ vertex_t buffer[MAX_CLIPPING_PLANES * 2 + 1]; // ~3KB
+ vertex_t* buf = buffer;
+
+ // original list of vertices (polygon to clip, in fact this
+ // function works with an arbitrary polygon).
+ vertex_t* in[3] = { v0, v1, v2 };
+
+ // output lists (we need 2, which we use back and forth)
+ // (maximum outpout list's size is MAX_CLIPPING_PLANES + MAX_VERTICES)
+ // 2 more elements for overflow when non convex polygons.
+ vertex_t* out[2][MAX_CLIPPING_PLANES + MAX_VERTICES + 2];
+ unsigned int outi = 0;
+
+ // current input list
+ vertex_t** ivl = in;
+
+ // 3 input vertices, 0 in the output list, first plane
+ unsigned int ic = 3;
+
+ // User clip-planes first, the clipping is always done in eye-coordinate
+ // this is basically the same algorithm than for the view-volume
+ // clipping, except for the computation of the distance (vertex, plane)
+ // and the fact that we need to compute the eye-coordinates of each
+ // new vertex we create.
+
+ if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL))
+ {
+ unsigned int plane = 0;
+ uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8;
+ do {
+ if (cc & 1) {
+ // pointers to our output list (head and current)
+ vertex_t** const ovl = &out[outi][0];
+ vertex_t** output = ovl;
+ unsigned int oc = 0;
+ unsigned int sentinel = 0;
+ // previous vertice, compute distance to the plane
+ vertex_t* s = ivl[ic-1];
+ const vec4_t& equation = c->clipPlanes.plane[plane].equation;
+ GLfixed sd = dot4(equation.v, s->eye.v);
+ // clip each vertice against this plane...
+ for (unsigned int i=0 ; i<ic ; i++) {
+ vertex_t* p = ivl[i];
+ const GLfixed pd = dot4(equation.v, p->eye.v);
+ if (sd >= 0) {
+ if (pd >= 0) {
+ // both inside
+ *output++ = p;
+ oc++;
+ } else {
+ // s inside, p outside (exiting)
+ const GLfixed t = clipDivide(sd, sd-pd);
+ c->arrays.clipEye(c, buf, t, p, s);
+ *output++ = buf++;
+ oc++;
+ if (++sentinel >= 3)
+ return; // non-convex polygon!
+ }
+ } else {
+ if (pd >= 0) {
+ // s outside (entering)
+ if (pd) {
+ const GLfixed t = clipDivide(pd, pd-sd);
+ c->arrays.clipEye(c, buf, t, s, p);
+ *output++ = buf++;
+ oc++;
+ if (++sentinel >= 3)
+ return; // non-convex polygon!
+ }
+ *output++ = p;
+ oc++;
+ } else {
+ // both outside
+ }
+ }
+ s = p;
+ sd = pd;
+ }
+ // output list become the new input list
+ if (oc<3)
+ return; // less than 3 vertices left? we're done!
+ ivl = ovl;
+ ic = oc;
+ outi = 1-outi;
+ }
+ cc >>= 1;
+ plane++;
+ } while (cc);
+ }
+
+ // frustum clip-planes
+ if (all_cc & vertex_t::FRUSTUM_CLIP_ALL)
+ {
+ unsigned int plane = 0;
+ uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL;
+ do {
+ if (cc & 1) {
+ // pointers to our output list (head and current)
+ vertex_t** const ovl = &out[outi][0];
+ vertex_t** output = ovl;
+ unsigned int oc = 0;
+ unsigned int sentinel = 0;
+ // previous vertice, compute distance to the plane
+ vertex_t* s = ivl[ic-1];
+ GLfixed sd = frustumPlaneDist(plane, s->clip);
+ // clip each vertice against this plane...
+ for (unsigned int i=0 ; i<ic ; i++) {
+ vertex_t* p = ivl[i];
+ const GLfixed pd = frustumPlaneDist(plane, p->clip);
+ if (sd >= 0) {
+ if (pd >= 0) {
+ // both inside
+ *output++ = p;
+ oc++;
+ } else {
+ // s inside, p outside (exiting)
+ const GLfixed t = clipDivide(sd, sd-pd);
+ c->arrays.clipVertex(c, buf, t, p, s);
+ *output++ = buf++;
+ oc++;
+ if (++sentinel >= 3)
+ return; // non-convex polygon!
+ }
+ } else {
+ if (pd >= 0) {
+ // s outside (entering)
+ if (pd) {
+ const GLfixed t = clipDivide(pd, pd-sd);
+ c->arrays.clipVertex(c, buf, t, s, p);
+ *output++ = buf++;
+ oc++;
+ if (++sentinel >= 3)
+ return; // non-convex polygon!
+ }
+ *output++ = p;
+ oc++;
+ } else {
+ // both outside
+ }
+ }
+ s = p;
+ sd = pd;
+ }
+ // output list become the new input list
+ if (oc<3)
+ return; // less than 3 vertices left? we're done!
+ ivl = ovl;
+ ic = oc;
+ outi = 1-outi;
+ }
+ cc >>= 1;
+ plane++;
+ } while (cc);
+ }
+
+ // finally we can render our triangles...
+ p0 = ivl[0];
+ p1 = ivl[1];
+ for (unsigned int i=2 ; i<ic ; i++) {
+ p2 = ivl[i];
+ c->lerp.initTriangle(p0, p1, p2);
+ if (cull_triangle(c, p0, p1, p2)) {
+ p1 = p2;
+ continue; // culled!
+ }
+ triangle(c, p0, p1, p2);
+ p1 = p2;
+ }
+}
+
+unsigned int clip_line(ogles_context_t* c, vertex_t* s, vertex_t* p)
+{
+ const uint32_t all_cc = (s->flags | p->flags) & vertex_t::CLIP_ALL;
+
+ if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL))
+ {
+ unsigned int plane = 0;
+ uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8;
+ do {
+ if (cc & 1) {
+ const vec4_t& equation = c->clipPlanes.plane[plane].equation;
+ const GLfixed sd = dot4(equation.v, s->eye.v);
+ const GLfixed pd = dot4(equation.v, p->eye.v);
+ if (sd >= 0) {
+ if (pd >= 0) {
+ // both inside
+ } else {
+ // s inside, p outside (exiting)
+ const GLfixed t = clipDivide(sd, sd-pd);
+ c->arrays.clipEye(c, p, t, p, s);
+ }
+ } else {
+ if (pd >= 0) {
+ // s outside (entering)
+ if (pd) {
+ const GLfixed t = clipDivide(pd, pd-sd);
+ c->arrays.clipEye(c, s, t, s, p);
+ }
+ } else {
+ // both outside
+ return 0;
+ }
+ }
+ }
+ cc >>= 1;
+ plane++;
+ } while (cc);
+ }
+
+ // frustum clip-planes
+ if (all_cc & vertex_t::FRUSTUM_CLIP_ALL)
+ {
+ unsigned int plane = 0;
+ uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL;
+ do {
+ if (cc & 1) {
+ const GLfixed sd = frustumPlaneDist(plane, s->clip);
+ const GLfixed pd = frustumPlaneDist(plane, p->clip);
+ if (sd >= 0) {
+ if (pd >= 0) {
+ // both inside
+ } else {
+ // s inside, p outside (exiting)
+ const GLfixed t = clipDivide(sd, sd-pd);
+ c->arrays.clipVertex(c, p, t, p, s);
+ }
+ } else {
+ if (pd >= 0) {
+ // s outside (entering)
+ if (pd) {
+ const GLfixed t = clipDivide(pd, pd-sd);
+ c->arrays.clipVertex(c, s, t, s, p);
+ }
+ } else {
+ // both outside
+ return 0;
+ }
+ }
+ }
+ cc >>= 1;
+ plane++;
+ } while (cc);
+ }
+
+ return 2;
+}
+
+
+}; // namespace android
diff --git a/opengl/libagl/primitives.h b/opengl/libagl/primitives.h
new file mode 100644
index 0000000..1bef604
--- /dev/null
+++ b/opengl/libagl/primitives.h
@@ -0,0 +1,37 @@
+/* libs/opengles/primitives.h
+**
+** Copyright 2006, 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_OPENGLES_PRIMITIVES_H
+#define ANDROID_OPENGLES_PRIMITIVES_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+
+namespace android {
+
+namespace gl {
+struct ogles_context_t;
+};
+
+void ogles_validate_primitives(ogles_context_t* c);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_PRIMITIVES_H
+
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
new file mode 100644
index 0000000..c2f9f12
--- /dev/null
+++ b/opengl/libagl/state.cpp
@@ -0,0 +1,592 @@
+/* libs/opengles/state.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <stdlib.h>
+
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "array.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "light.h"
+#include "texture.h"
+#include "BufferObjectManager.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static char const * const gVendorString = "Android";
+static char const * const gRendererString = "Android PixelFlinger 1.0";
+static char const * const gVersionString = "OpenGL ES-CM 1.0";
+static char const * const gExtensionsString =
+ "GL_OES_byte_coordinates " // OK
+ "GL_OES_fixed_point " // OK
+ "GL_OES_single_precision " // OK
+ "GL_OES_read_format " // OK
+ "GL_OES_compressed_paletted_texture " // OK
+ "GL_OES_draw_texture " // OK
+ "GL_OES_matrix_get " // OK
+ "GL_OES_query_matrix " // OK
+ // "GL_OES_point_size_array " // TODO
+ // "GL_OES_point_sprite " // TODO
+ "GL_ARB_texture_compression " // OK
+ "GL_ARB_texture_non_power_of_two " // OK
+ "GL_ANDROID_direct_texture " // OK
+ "GL_ANDROID_user_clip_plane " // OK
+ "GL_ANDROID_vertex_buffer_object " // OK
+ "GL_ANDROID_generate_mipmap " // OK
+ ;
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+ogles_context_t *ogles_init(size_t extra)
+{
+ void* const base = malloc(extra + sizeof(ogles_context_t) + 32);
+ if (!base) return 0;
+
+ ogles_context_t *c =
+ (ogles_context_t *)((ptrdiff_t(base) + extra + 31) & ~0x1FL);
+ memset(c, 0, sizeof(ogles_context_t));
+ ggl_init_context(&(c->rasterizer));
+
+ // XXX: this should be passed as an argument
+ sp<EGLSurfaceManager> smgr(new EGLSurfaceManager());
+ c->surfaceManager = smgr.get();
+ c->surfaceManager->incStrong(c);
+
+ sp<EGLBufferObjectManager> bomgr(new EGLBufferObjectManager());
+ c->bufferObjectManager = bomgr.get();
+ c->bufferObjectManager->incStrong(c);
+
+ ogles_init_array(c);
+ ogles_init_matrix(c);
+ ogles_init_vertex(c);
+ ogles_init_light(c);
+ ogles_init_texture(c);
+
+ c->rasterizer.base = base;
+ c->point.size = TRI_ONE;
+ c->line.width = TRI_ONE;
+
+ // in OpenGL, writing to the depth buffer is enabled by default.
+ c->rasterizer.procs.depthMask(c, 1);
+
+ // OpenGL enables dithering by default
+ c->rasterizer.procs.enable(c, GL_DITHER);
+
+ return c;
+}
+
+void ogles_uninit(ogles_context_t* c)
+{
+ ogles_uninit_array(c);
+ ogles_uninit_matrix(c);
+ ogles_uninit_vertex(c);
+ ogles_uninit_light(c);
+ ogles_uninit_texture(c);
+ c->surfaceManager->decStrong(c);
+ c->bufferObjectManager->decStrong(c);
+ ggl_uninit_context(&(c->rasterizer));
+ free(c->rasterizer.base);
+}
+
+void _ogles_error(ogles_context_t* c, GLenum error)
+{
+ if (c->error == GL_NO_ERROR)
+ c->error = error;
+}
+
+static bool stencilop_valid(GLenum op) {
+ switch (op) {
+ case GL_KEEP:
+ case GL_ZERO:
+ case GL_REPLACE:
+ case GL_INCR:
+ case GL_DECR:
+ case GL_INVERT:
+ return true;
+ }
+ return false;
+}
+
+static void enable_disable(ogles_context_t* c, GLenum cap, int enabled)
+{
+ if ((cap >= GL_LIGHT0) && (cap<GL_LIGHT0+OGLES_MAX_LIGHTS)) {
+ c->lighting.lights[cap-GL_LIGHT0].enable = enabled;
+ c->lighting.enabledLights &= ~(1<<(cap-GL_LIGHT0));
+ c->lighting.enabledLights |= (enabled<<(cap-GL_LIGHT0));
+ return;
+ }
+
+ switch (cap) {
+ case GL_POINT_SMOOTH:
+ c->point.smooth = enabled;
+ break;
+ case GL_LINE_SMOOTH:
+ c->line.smooth = enabled;
+ break;
+ case GL_POLYGON_OFFSET_FILL:
+ c->polygonOffset.enable = enabled;
+ break;
+ case GL_CULL_FACE:
+ c->cull.enable = enabled;
+ break;
+ case GL_LIGHTING:
+ c->lighting.enable = enabled;
+ break;
+ case GL_COLOR_MATERIAL:
+ c->lighting.colorMaterial.enable = enabled;
+ break;
+ case GL_NORMALIZE:
+ case GL_RESCALE_NORMAL:
+ c->transforms.rescaleNormals = enabled ? cap : 0;
+ // XXX: invalidate mvit
+ break;
+
+ case GL_CLIP_PLANE0:
+ case GL_CLIP_PLANE1:
+ case GL_CLIP_PLANE2:
+ case GL_CLIP_PLANE3:
+ case GL_CLIP_PLANE4:
+ case GL_CLIP_PLANE5:
+ c->clipPlanes.enable &= ~(1<<(cap-GL_CLIP_PLANE0));
+ c->clipPlanes.enable |= (enabled<<(cap-GL_CLIP_PLANE0));
+ ogles_invalidate_perspective(c);
+ break;
+
+ case GL_FOG:
+ case GL_DEPTH_TEST:
+ ogles_invalidate_perspective(c);
+ // fall-through...
+ case GL_BLEND:
+ case GL_SCISSOR_TEST:
+ case GL_ALPHA_TEST:
+ case GL_COLOR_LOGIC_OP:
+ case GL_DITHER:
+ case GL_STENCIL_TEST:
+ case GL_TEXTURE_2D:
+ // these need to fall through into the rasterizer
+ c->rasterizer.procs.enableDisable(c, cap, enabled);
+ break;
+
+ case GL_MULTISAMPLE:
+ case GL_SAMPLE_ALPHA_TO_COVERAGE:
+ case GL_SAMPLE_ALPHA_TO_ONE:
+ case GL_SAMPLE_COVERAGE:
+ // not supported in this implementation
+ break;
+
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+using namespace android;
+
+#if 0
+#pragma mark -
+#endif
+
+// These ones are super-easy, we're not supporting those features!
+void glSampleCoverage(GLclampf value, GLboolean invert) {
+}
+void glSampleCoveragex(GLclampx value, GLboolean invert) {
+}
+void glStencilFunc(GLenum func, GLint ref, GLuint mask) {
+ ogles_context_t* c = ogles_context_t::get();
+ if (func < GL_NEVER || func > GL_ALWAYS) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ // from OpenGL|ES 1.0 sepcification:
+ // If there is no stencil buffer, no stencil modification can occur
+ // and it is as if the stencil test always passes.
+}
+
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
+ ogles_context_t* c = ogles_context_t::get();
+ if ((stencilop_valid(fail) &
+ stencilop_valid(zfail) &
+ stencilop_valid(zpass)) == 0) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void glAlphaFunc(GLenum func, GLclampf ref)
+{
+ glAlphaFuncx(func, gglFloatToFixed(ref));
+}
+
+void glCullFace(GLenum mode)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ switch (mode) {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ }
+ c->cull.cullFace = mode;
+}
+
+void glFrontFace(GLenum mode)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ switch (mode) {
+ case GL_CW:
+ case GL_CCW:
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->cull.frontFace = mode;
+}
+
+void glHint(GLenum target, GLenum mode)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ switch (target) {
+ case GL_FOG_HINT:
+ case GL_GENERATE_MIPMAP_HINT:
+ case GL_LINE_SMOOTH_HINT:
+ break;
+ case GL_POINT_SMOOTH_HINT:
+ c->rasterizer.procs.enableDisable(c,
+ GGL_POINT_SMOOTH_NICE, mode==GL_NICEST);
+ break;
+ case GL_PERSPECTIVE_CORRECTION_HINT:
+ c->perspective = (mode == GL_NICEST) ? 1 : 0;
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ }
+}
+
+void glEnable(GLenum cap) {
+ ogles_context_t* c = ogles_context_t::get();
+ enable_disable(c, cap, 1);
+}
+void glDisable(GLenum cap) {
+ ogles_context_t* c = ogles_context_t::get();
+ enable_disable(c, cap, 0);
+}
+
+void glFinish()
+{ // nothing to do for our software implementation
+}
+
+void glFlush()
+{ // nothing to do for our software implementation
+}
+
+GLenum glGetError()
+{
+ // From OpenGL|ES 1.0 specification:
+ // If more than one flag has recorded an error, glGetError returns
+ // and clears an arbitrary error flag value. Thus, glGetError should
+ // always be called in a loop, until it returns GL_NO_ERROR,
+ // if all error flags are to be reset.
+
+ ogles_context_t* c = ogles_context_t::get();
+ if (c->error) {
+ const GLenum ret(c->error);
+ c->error = 0;
+ return ret;
+ }
+
+ if (c->rasterizer.error) {
+ const GLenum ret(c->rasterizer.error);
+ c->rasterizer.error = 0;
+ return ret;
+ }
+
+ return GL_NO_ERROR;
+}
+
+const GLubyte* glGetString(GLenum string)
+{
+ switch (string) {
+ case GL_VENDOR: return (const GLubyte*)gVendorString;
+ case GL_RENDERER: return (const GLubyte*)gRendererString;
+ case GL_VERSION: return (const GLubyte*)gVersionString;
+ case GL_EXTENSIONS: return (const GLubyte*)gExtensionsString;
+ }
+ ogles_context_t* c = ogles_context_t::get();
+ ogles_error(c, GL_INVALID_ENUM);
+ return 0;
+}
+
+void glGetIntegerv(GLenum pname, GLint *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ switch (pname) {
+ case GL_ALIASED_POINT_SIZE_RANGE:
+ params[0] = 0;
+ params[1] = GGL_MAX_ALIASED_POINT_SIZE;
+ break;
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+ params[0] = 0;
+ params[1] = GGL_MAX_ALIASED_POINT_SIZE;
+ break;
+ case GL_ALPHA_BITS: {
+ int index = c->rasterizer.state.buffers.color.format;
+ GGLFormat const * formats = gglGetPixelFormatTable();
+ params[0] = formats[index].ah - formats[index].al;
+ break;
+ }
+ case GL_RED_BITS: {
+ int index = c->rasterizer.state.buffers.color.format;
+ GGLFormat const * formats = gglGetPixelFormatTable();
+ params[0] = formats[index].rh - formats[index].rl;
+ break;
+ }
+ case GL_GREEN_BITS: {
+ int index = c->rasterizer.state.buffers.color.format;
+ GGLFormat const * formats = gglGetPixelFormatTable();
+ params[0] = formats[index].gh - formats[index].gl;
+ break;
+ }
+ case GL_BLUE_BITS: {
+ int index = c->rasterizer.state.buffers.color.format;
+ GGLFormat const * formats = gglGetPixelFormatTable();
+ params[0] = formats[index].bh - formats[index].bl;
+ break;
+ }
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ params[ 0] = GL_PALETTE4_RGB8_OES;
+ params[ 1] = GL_PALETTE4_RGBA8_OES;
+ params[ 2] = GL_PALETTE4_R5_G6_B5_OES;
+ params[ 3] = GL_PALETTE4_RGBA4_OES;
+ params[ 4] = GL_PALETTE4_RGB5_A1_OES;
+ params[ 5] = GL_PALETTE8_RGB8_OES;
+ params[ 6] = GL_PALETTE8_RGBA8_OES;
+ params[ 7] = GL_PALETTE8_R5_G6_B5_OES;
+ params[ 8] = GL_PALETTE8_RGBA4_OES;
+ params[ 9] = GL_PALETTE8_RGB5_A1_OES;
+ break;
+ case GL_DEPTH_BITS:
+ params[0] = c->rasterizer.state.buffers.depth.format ? 0 : 16;
+ break;
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
+ params[0] = GL_RGB;
+ break;
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
+ params[0] = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case GL_MAX_ELEMENTS_INDICES:
+ params[0] = 65536;
+ break;
+ case GL_MAX_ELEMENTS_VERTICES:
+ params[0] = 0x7FFFFFFF;
+ break;
+ case GL_MAX_LIGHTS:
+ params[0] = OGLES_MAX_LIGHTS;
+ break;
+ case GL_MAX_CLIP_PLANES:
+ params[0] = OGLES_MAX_CLIP_PLANES;
+ break;
+ case GL_MAX_MODELVIEW_STACK_DEPTH:
+ params[0] = OGLES_MODELVIEW_STACK_DEPTH;
+ break;
+ case GL_MAX_PROJECTION_STACK_DEPTH:
+ params[0] = OGLES_PROJECTION_STACK_DEPTH;
+ break;
+ case GL_MAX_TEXTURE_STACK_DEPTH:
+ params[0] = OGLES_TEXTURE_STACK_DEPTH;
+ break;
+ case GL_MAX_TEXTURE_SIZE:
+ params[0] = GGL_MAX_TEXTURE_SIZE;
+ break;
+ case GL_MAX_TEXTURE_UNITS:
+ params[0] = GGL_TEXTURE_UNIT_COUNT;
+ break;
+ case GL_MAX_VIEWPORT_DIMS:
+ params[0] = GGL_MAX_VIEWPORT_DIMS;
+ params[1] = GGL_MAX_VIEWPORT_DIMS;
+ break;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ params[0] = OGLES_NUM_COMPRESSED_TEXTURE_FORMATS;
+ break;
+ case GL_SMOOTH_LINE_WIDTH_RANGE:
+ params[0] = 0;
+ params[1] = GGL_MAX_SMOOTH_LINE_WIDTH;
+ break;
+ case GL_SMOOTH_POINT_SIZE_RANGE:
+ params[0] = 0;
+ params[1] = GGL_MAX_SMOOTH_POINT_SIZE;
+ break;
+ case GL_STENCIL_BITS:
+ params[0] = 0;
+ break;
+ case GL_SUBPIXEL_BITS:
+ params[0] = GGL_SUBPIXEL_BITS;
+ break;
+
+ case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES:
+ memcpy( params,
+ c->transforms.modelview.top().elements(),
+ 16*sizeof(GLint));
+ break;
+ case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES:
+ memcpy( params,
+ c->transforms.projection.top().elements(),
+ 16*sizeof(GLint));
+ break;
+ case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES:
+ memcpy( params,
+ c->transforms.texture[c->textures.active].top().elements(),
+ 16*sizeof(GLint));
+ break;
+
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ break;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void glPointSize(GLfloat size)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (size <= 0) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->point.size = TRI_FROM_FIXED(gglFloatToFixed(size));
+}
+
+void glPointSizex(GLfixed size)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (size <= 0) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->point.size = TRI_FROM_FIXED(size);
+}
+
+// ----------------------------------------------------------------------------
+
+void glLineWidth(GLfloat width)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (width <= 0) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->line.width = TRI_FROM_FIXED(gglFloatToFixed(width));
+}
+
+void glLineWidthx(GLfixed width)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (width <= 0) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->line.width = TRI_FROM_FIXED(width);
+}
+
+// ----------------------------------------------------------------------------
+
+void glColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.colorMask(c, r, g, b, a);
+}
+
+void glDepthMask(GLboolean flag) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.depthMask(c, flag);
+}
+
+void glStencilMask(GLuint mask) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.stencilMask(c, mask);
+}
+
+void glDepthFunc(GLenum func) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.depthFunc(c, func);
+}
+
+void glLogicOp(GLenum opcode) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.logicOp(c, opcode);
+}
+
+void glAlphaFuncx(GLenum func, GLclampx ref) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.alphaFuncx(c, func, ref);
+}
+
+void glBlendFunc(GLenum sfactor, GLenum dfactor) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.blendFunc(c, sfactor, dfactor);
+}
+
+void glClear(GLbitfield mask) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clear(c, mask);
+}
+
+void glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clearColorx(c, red, green, blue, alpha);
+}
+
+void glClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clearColorx(c,
+ gglFloatToFixed(r),
+ gglFloatToFixed(g),
+ gglFloatToFixed(b),
+ gglFloatToFixed(a));
+}
+
+void glClearDepthx(GLclampx depth) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clearDepthx(c, depth);
+}
+
+void glClearDepthf(GLclampf depth)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clearDepthx(c, gglFloatToFixed(depth));
+}
+
+void glClearStencil(GLint s) {
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.clearStencil(c, s);
+}
diff --git a/opengl/libagl/state.h b/opengl/libagl/state.h
new file mode 100644
index 0000000..55a5ccb
--- /dev/null
+++ b/opengl/libagl/state.h
@@ -0,0 +1,54 @@
+/* libs/opengles/state.h
+**
+** Copyright 2006, 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_OPENGLES_STATE_H
+#define ANDROID_OPENGLES_STATE_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#include <stdio.h>
+
+namespace android {
+
+ogles_context_t *ogles_init(size_t extra);
+void ogles_uninit(ogles_context_t* c);
+void _ogles_error(ogles_context_t* c, GLenum error);
+
+#ifndef TRACE_GL_ERRORS
+#define TRACE_GL_ERRORS 0
+#endif
+
+#if TRACE_GL_ERRORS
+#define ogles_error(c, error) \
+do { \
+ printf("ogles_error at file %s line %d\n", __FILE__, __LINE__); \
+ _ogles_error(c, error); \
+} while (0)
+#else /* !TRACE_GL_ERRORS */
+#define ogles_error(c, error) _ogles_error((c), (error))
+#endif
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_STATE_H
+
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
new file mode 100644
index 0000000..6b2640a
--- /dev/null
+++ b/opengl/libagl/texture.cpp
@@ -0,0 +1,1423 @@
+/* libs/opengles/texture.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "texture.h"
+#include "TextureObjectManager.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void bindTextureTmu(
+ ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex);
+
+static __attribute__((noinline))
+void generateMipmap(ogles_context_t* c, GLint level);
+
+// ----------------------------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Init
+#endif
+
+void ogles_init_texture(ogles_context_t* c)
+{
+ c->textures.packAlignment = 4;
+ c->textures.unpackAlignment = 4;
+
+ // each context has a default named (0) texture (not shared)
+ c->textures.defaultTexture = new EGLTextureObject();
+ c->textures.defaultTexture->incStrong(c);
+
+ // bind the default texture to each texture unit
+ for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ bindTextureTmu(c, i, 0, c->textures.defaultTexture);
+ memset(c->current.texture[i].v, 0, sizeof(vec4_t));
+ c->current.texture[i].Q = 0x10000;
+ }
+}
+
+void ogles_uninit_texture(ogles_context_t* c)
+{
+ if (c->textures.ggl)
+ gglUninit(c->textures.ggl);
+ c->textures.defaultTexture->decStrong(c);
+ for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->textures.tmu[i].texture)
+ c->textures.tmu[i].texture->decStrong(c);
+ }
+}
+
+static __attribute__((noinline))
+void validate_tmu(ogles_context_t* c, int i)
+{
+ texture_unit_t& u(c->textures.tmu[i]);
+ if (u.dirty) {
+ u.dirty = 0;
+ c->rasterizer.procs.activeTexture(c, i);
+ c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+ c->rasterizer.procs.texGeni(c, GGL_S,
+ GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
+ c->rasterizer.procs.texGeni(c, GGL_T,
+ GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_WRAP_S, u.texture->wraps);
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_WRAP_T, u.texture->wrapt);
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
+
+ // disable this texture unit if it's not complete
+ if (!u.texture->isComplete()) {
+ c->rasterizer.procs.disable(c, GGL_TEXTURE_2D);
+ }
+ }
+}
+
+void ogles_validate_texture_impl(ogles_context_t* c)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->rasterizer.state.texture[i].enable)
+ validate_tmu(c, i);
+ }
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+}
+
+static
+void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
+ c->textures.tmu[tmu].dirty = flags;
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Format conversion
+#endif
+
+static uint32_t gl2format_table[6][4] = {
+ // BYTE, 565, 4444, 5551
+ { GGL_PIXEL_FORMAT_A_8,
+ 0, 0, 0 }, // GL_ALPHA
+ { GGL_PIXEL_FORMAT_RGB_888,
+ GGL_PIXEL_FORMAT_RGB_565,
+ 0, 0 }, // GL_RGB
+ { GGL_PIXEL_FORMAT_RGBA_8888,
+ 0,
+ GGL_PIXEL_FORMAT_RGBA_4444,
+ GGL_PIXEL_FORMAT_RGBA_5551 }, // GL_RGBA
+ { GGL_PIXEL_FORMAT_L_8,
+ 0, 0, 0 }, // GL_LUMINANCE
+ { GGL_PIXEL_FORMAT_LA_88,
+ 0, 0, 0 }, // GL_LUMINANCE_ALPHA
+};
+
+static int32_t convertGLPixelFormat(GLint format, GLenum type)
+{
+ int32_t fi = -1;
+ int32_t ti = -1;
+ switch (format) {
+ case GL_ALPHA: fi = 0; break;
+ case GL_RGB: fi = 1; break;
+ case GL_RGBA: fi = 2; break;
+ case GL_LUMINANCE: fi = 3; break;
+ case GL_LUMINANCE_ALPHA: fi = 4; break;
+ }
+ switch (type) {
+ case GL_UNSIGNED_BYTE: ti = 0; break;
+ case GL_UNSIGNED_SHORT_5_6_5: ti = 1; break;
+ case GL_UNSIGNED_SHORT_4_4_4_4: ti = 2; break;
+ case GL_UNSIGNED_SHORT_5_5_5_1: ti = 3; break;
+ }
+ if (fi==-1 || ti==-1)
+ return 0;
+ return gl2format_table[fi][ti];
+}
+
+// ----------------------------------------------------------------------------
+
+static GLenum validFormatType(ogles_context_t* c, GLenum format, GLenum type)
+{
+ GLenum error = 0;
+ if (format<GL_ALPHA || format>GL_LUMINANCE_ALPHA) {
+ error = GL_INVALID_ENUM;
+ }
+ if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT_4_4_4_4 &&
+ type != GL_UNSIGNED_SHORT_5_5_5_1 && type != GL_UNSIGNED_SHORT_5_6_5) {
+ error = GL_INVALID_ENUM;
+ }
+ if (type == GL_UNSIGNED_SHORT_5_6_5 && format != GL_RGB) {
+ error = GL_INVALID_OPERATION;
+ }
+ if ((type == GL_UNSIGNED_SHORT_4_4_4_4 ||
+ type == GL_UNSIGNED_SHORT_5_5_5_1) && format != GL_RGBA) {
+ error = GL_INVALID_OPERATION;
+ }
+ if (error) {
+ ogles_error(c, error);
+ }
+ return error;
+}
+
+// ----------------------------------------------------------------------------
+
+GGLContext* getRasterizer(ogles_context_t* c)
+{
+ GGLContext* ggl = c->textures.ggl;
+ if (ggl_unlikely(!ggl)) {
+ // this is quite heavy the first time...
+ gglInit(&ggl);
+ if (!ggl) {
+ return 0;
+ }
+ GGLfixed colors[4] = { 0, 0, 0, 0x10000 };
+ c->textures.ggl = ggl;
+ ggl->activeTexture(ggl, 0);
+ ggl->enable(ggl, GGL_TEXTURE_2D);
+ ggl->texEnvi(ggl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
+ ggl->disable(ggl, GGL_DITHER);
+ ggl->shadeModel(ggl, GGL_FLAT);
+ ggl->color4xv(ggl, colors);
+ }
+ return ggl;
+}
+
+static __attribute__((noinline))
+int copyPixels(
+ ogles_context_t* c,
+ const GGLSurface& dst,
+ GLint xoffset, GLint yoffset,
+ const GGLSurface& src,
+ GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ if ((dst.format == src.format) &&
+ (dst.stride == src.stride) &&
+ (dst.width == src.width) &&
+ (dst.height == src.height) &&
+ (dst.stride > 0) &&
+ ((x|y) == 0) &&
+ ((xoffset|yoffset) == 0))
+ {
+ // this is a common case...
+ const GGLFormat& pixelFormat(c->rasterizer.formats[src.format]);
+ const size_t size = src.height * src.stride * pixelFormat.size;
+ memcpy(dst.data, src.data, size);
+ return 0;
+ }
+
+ // use pixel-flinger to handle all the conversions
+ GGLContext* ggl = getRasterizer(c);
+ if (!ggl) {
+ // the only reason this would fail is because we ran out of memory
+ return GL_OUT_OF_MEMORY;
+ }
+
+ ggl->colorBuffer(ggl, &dst);
+ ggl->bindTexture(ggl, &src);
+ ggl->texCoord2i(ggl, x-xoffset, y-yoffset);
+ ggl->recti(ggl, xoffset, yoffset, xoffset+w, yoffset+h);
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+
+static __attribute__((noinline))
+sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
+{
+ sp<EGLTextureObject> tex;
+ const int active = c->textures.active;
+ const GLuint name = c->textures.tmu[active].name;
+
+ // free the reference to the previously bound object
+ texture_unit_t& u(c->textures.tmu[active]);
+ if (u.texture)
+ u.texture->decStrong(c);
+
+ if (name == 0) {
+ // 0 is our local texture object, not shared with anyone.
+ // But it affects all bound TMUs immediately.
+ // (we need to invalidate all units bound to this texture object)
+ tex = c->textures.defaultTexture;
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->textures.tmu[i].texture == tex.get())
+ invalidate_texture(c, i);
+ }
+ } else {
+ // get a new texture object for that name
+ tex = c->surfaceManager->replaceTexture(name);
+ }
+
+ // bind this texture to the current active texture unit
+ // and add a reference to this texture object
+ u.texture = tex.get();
+ u.texture->incStrong(c);
+ u.name = name;
+ invalidate_texture(c, active);
+ return tex;
+}
+
+void bindTextureTmu(
+ ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex)
+{
+ if (tex.get() == c->textures.tmu[tmu].texture)
+ return;
+
+ // free the reference to the previously bound object
+ texture_unit_t& u(c->textures.tmu[tmu]);
+ if (u.texture)
+ u.texture->decStrong(c);
+
+ // bind this texture to the current active texture unit
+ // and add a reference to this texture object
+ u.texture = tex.get();
+ u.texture->incStrong(c);
+ u.name = texture;
+ invalidate_texture(c, tmu);
+}
+
+int createTextureSurface(ogles_context_t* c,
+ GGLSurface** outSurface, int32_t* outSize, GLint level,
+ GLenum format, GLenum type, GLsizei width, GLsizei height,
+ GLenum compressedFormat = 0)
+{
+ // find out which texture is bound to the current unit
+ const int active = c->textures.active;
+ const GLuint name = c->textures.tmu[active].name;
+
+ // convert the pixelformat to one we can handle
+ const int32_t formatIdx = convertGLPixelFormat(format, type);
+ if (formatIdx == 0) { // we don't know what to do with this
+ return GL_INVALID_OPERATION;
+ }
+
+ // figure out the size we need as well as the stride
+ const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+ const int32_t align = c->textures.unpackAlignment-1;
+ const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+ const size_t size = bpr * height;
+ const int32_t stride = bpr / pixelFormat.size;
+
+ if (level > 0) {
+ const int active = c->textures.active;
+ EGLTextureObject* tex = c->textures.tmu[active].texture;
+ status_t err = tex->reallocate(level,
+ width, height, stride, formatIdx, compressedFormat, bpr);
+ if (err != NO_ERROR)
+ return GL_OUT_OF_MEMORY;
+ GGLSurface& surface = tex->editMip(level);
+ *outSurface = &surface;
+ *outSize = size;
+ return 0;
+ }
+
+ sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
+ status_t err = tex->reallocate(level,
+ width, height, stride, formatIdx, compressedFormat, bpr);
+ if (err != NO_ERROR)
+ return GL_OUT_OF_MEMORY;
+
+ tex->internalformat = format;
+ *outSurface = &tex->surface;
+ *outSize = size;
+ return 0;
+}
+
+static void decodePalette4(const GLvoid *data, int level, int width, int height,
+ void *surface, int stride, int format)
+
+{
+ int indexBits = 8;
+ int entrySize = 0;
+ switch (format) {
+ case GL_PALETTE4_RGB8_OES:
+ indexBits = 4;
+ /* FALLTHROUGH */
+ case GL_PALETTE8_RGB8_OES:
+ entrySize = 3;
+ break;
+
+ case GL_PALETTE4_RGBA8_OES:
+ indexBits = 4;
+ /* FALLTHROUGH */
+ case GL_PALETTE8_RGBA8_OES:
+ entrySize = 4;
+ break;
+
+ case GL_PALETTE4_R5_G6_B5_OES:
+ case GL_PALETTE4_RGBA4_OES:
+ case GL_PALETTE4_RGB5_A1_OES:
+ indexBits = 4;
+ /* FALLTHROUGH */
+ case GL_PALETTE8_R5_G6_B5_OES:
+ case GL_PALETTE8_RGBA4_OES:
+ case GL_PALETTE8_RGB5_A1_OES:
+ entrySize = 2;
+ break;
+ }
+
+ const int paletteSize = (1 << indexBits) * entrySize;
+ uint8_t const* pixels = (uint8_t *)data + paletteSize;
+ for (int i=0 ; i<level ; i++) {
+ int w = (width >> i) ? : 1;
+ int h = (height >> i) ? : 1;
+ pixels += h * ((w * indexBits) / 8);
+ }
+ width = (width >> level) ? : 1;
+ height = (height >> level) ? : 1;
+
+ if (entrySize == 2) {
+ uint8_t const* const palette = (uint8_t*)data;
+ for (int y=0 ; y<height ; y++) {
+ uint8_t* p = (uint8_t*)surface + y*stride*2;
+ if (indexBits == 8) {
+ for (int x=0 ; x<width ; x++) {
+ int index = 2 * (*pixels++);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ }
+ } else {
+ for (int x=0 ; x<width ; x+=2) {
+ int v = *pixels++;
+ int index = 2 * (v >> 4);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ if (x+1 < width) {
+ index = 2 * (v & 0xF);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ }
+ }
+ }
+ }
+ } else if (entrySize == 3) {
+ uint8_t const* const palette = (uint8_t*)data;
+ for (int y=0 ; y<height ; y++) {
+ uint8_t* p = (uint8_t*)surface + y*stride*3;
+ if (indexBits == 8) {
+ for (int x=0 ; x<width ; x++) {
+ int index = 3 * (*pixels++);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ }
+ } else {
+ for (int x=0 ; x<width ; x+=2) {
+ int v = *pixels++;
+ int index = 3 * (v >> 4);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ if (x+1 < width) {
+ index = 3 * (v & 0xF);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ }
+ }
+ }
+ }
+ } else if (entrySize == 4) {
+ uint8_t const* const palette = (uint8_t*)data;
+ for (int y=0 ; y<height ; y++) {
+ uint8_t* p = (uint8_t*)surface + y*stride*4;
+ if (indexBits == 8) {
+ for (int x=0 ; x<width ; x++) {
+ int index = 4 * (*pixels++);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ *p++ = palette[index + 3];
+ }
+ } else {
+ for (int x=0 ; x<width ; x+=2) {
+ int v = *pixels++;
+ int index = 4 * (v >> 4);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ *p++ = palette[index + 3];
+ if (x+1 < width) {
+ index = 4 * (v & 0xF);
+ *p++ = palette[index + 0];
+ *p++ = palette[index + 1];
+ *p++ = palette[index + 2];
+ *p++ = palette[index + 3];
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+static __attribute__((noinline))
+void set_depth_and_fog(ogles_context_t* c, GLint z)
+{
+ const uint32_t enables = c->rasterizer.state.enables;
+ // we need to compute Zw
+ int32_t iterators[3];
+ iterators[1] = iterators[2] = 0;
+ GGLfixed Zw;
+ GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear);
+ GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar);
+ if (z<=0) Zw = n;
+ else if (z>=1) Zw = f;
+ else Zw = gglMulAddx(z, (f-n), n);
+ if (enables & GGL_ENABLE_FOG) {
+ // set up fog if needed...
+ iterators[0] = c->fog.fog(c, Zw);
+ c->rasterizer.procs.fogGrad3xv(c, iterators);
+ }
+ if (enables & GGL_ENABLE_DEPTH_TEST) {
+ // set up z-test if needed...
+ int32_t z = (Zw & ~(Zw>>31));
+ if (z >= 0x10000)
+ z = 0xFFFF;
+ iterators[0] = (z << 16) | z;
+ c->rasterizer.procs.zGrad3xv(c, iterators);
+ }
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark Generate mimaps
+#endif
+
+extern status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex);
+
+void generateMipmap(ogles_context_t* c, GLint level)
+{
+ if (level == 0) {
+ const int active = c->textures.active;
+ EGLTextureObject* tex = c->textures.tmu[active].texture;
+ if (tex->generate_mipmap) {
+ if (buildAPyramid(c, tex) != NO_ERROR) {
+ ogles_error(c, GL_OUT_OF_MEMORY);
+ return;
+ }
+ }
+ }
+}
+
+
+static void texParameterx(
+ GLenum target, GLenum pname, GLfixed param, ogles_context_t* c)
+{
+ if (target != GGL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
+ switch (pname) {
+ case GL_TEXTURE_WRAP_S:
+ if ((param == GL_CLAMP) ||
+ (param == GL_REPEAT) ||
+ (param == GL_CLAMP_TO_EDGE)) {
+ textureObject->wraps = param;
+ } else {
+ goto invalid_enum;
+ }
+ break;
+ case GL_TEXTURE_WRAP_T:
+ if ((param == GGL_CLAMP) ||
+ (param == GGL_REPEAT) ||
+ (param == GGL_CLAMP_TO_EDGE)) {
+ textureObject->wrapt = param;
+ } else {
+ goto invalid_enum;
+ }
+ break;
+ case GL_TEXTURE_MIN_FILTER:
+ if ((param == GL_NEAREST) ||
+ (param == GL_LINEAR) ||
+ (param == GL_NEAREST_MIPMAP_NEAREST) ||
+ (param == GL_LINEAR_MIPMAP_NEAREST) ||
+ (param == GL_NEAREST_MIPMAP_LINEAR) ||
+ (param == GL_LINEAR_MIPMAP_LINEAR)) {
+ textureObject->min_filter = param;
+ } else {
+ goto invalid_enum;
+ }
+ break;
+ case GL_TEXTURE_MAG_FILTER:
+ if ((param == GL_NEAREST) ||
+ (param == GL_LINEAR)) {
+ textureObject->mag_filter = param;
+ } else {
+ goto invalid_enum;
+ }
+ break;
+ case GL_GENERATE_MIPMAP:
+ textureObject->generate_mipmap = param;
+ break;
+ default:
+invalid_enum:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ invalidate_texture(c, c->textures.active);
+}
+
+
+static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
+ ogles_context_t* c)
+{
+ // quickly reject empty rects
+ if ((w|h) <= 0)
+ return;
+
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ y = gglIntToFixed(cbSurface.height) - (y + h);
+ w >>= FIXED_BITS;
+ h >>= FIXED_BITS;
+
+ // set up all texture units
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (!c->rasterizer.state.texture[i].enable)
+ continue;
+
+ int32_t texcoords[8];
+ texture_unit_t& u(c->textures.tmu[i]);
+
+ // validate this tmu (bind, wrap, filter)
+ validate_tmu(c, i);
+ // we CLAMP here, which works with premultiplied (s,t)
+ c->rasterizer.procs.texParameteri(c,
+ GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
+ c->rasterizer.procs.texParameteri(c,
+ GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
+ u.dirty = 0xFF; // XXX: should be more subtle
+
+ EGLTextureObject* textureObject = u.texture;
+ const GLint Ucr = textureObject->crop_rect[0] << 16;
+ const GLint Vcr = textureObject->crop_rect[1] << 16;
+ const GLint Wcr = textureObject->crop_rect[2] << 16;
+ const GLint Hcr = textureObject->crop_rect[3] << 16;
+
+ // computes texture coordinates (pre-multiplied)
+ int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt
+ int32_t dtdy =-Hcr / h; // dtdy = -((Hcr/h)/Ht)*Ht
+ int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
+ int32_t t0 = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy
+ texcoords[0] = s0;
+ texcoords[1] = dsdx;
+ texcoords[2] = 0;
+ texcoords[3] = t0;
+ texcoords[4] = 0;
+ texcoords[5] = dtdy;
+ texcoords[6] = 0;
+ texcoords[7] = 0;
+ c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords);
+ }
+
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
+ set_depth_and_fog(c, z);
+
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+ c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
+ c->rasterizer.procs.disable(c, GGL_W_LERP);
+ c->rasterizer.procs.disable(c, GGL_AA);
+ c->rasterizer.procs.shadeModel(c, GL_FLAT);
+ c->rasterizer.procs.recti(c,
+ gglFixedToIntRound(x),
+ gglFixedToIntRound(y),
+ gglFixedToIntRound(x)+w,
+ gglFixedToIntRound(y)+h);
+}
+
+static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
+{
+ // All coordinates are integer, so if we have only one
+ // texture unit active and no scaling is required
+ // THEN, we can use our special 1:1 mapping
+ // which is a lot faster.
+
+ if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
+ const int tmu = 0;
+ texture_unit_t& u(c->textures.tmu[tmu]);
+ EGLTextureObject* textureObject = u.texture;
+ const GLint Wcr = textureObject->crop_rect[2];
+ const GLint Hcr = textureObject->crop_rect[3];
+
+ if ((w == Wcr) && (h == -Hcr)) {
+ if ((w|h) <= 0) return; // quickly reject empty rects
+
+ if (u.dirty) {
+ c->rasterizer.procs.activeTexture(c, tmu);
+ c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
+ c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
+ GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
+ }
+ c->rasterizer.procs.texGeni(c, GGL_S,
+ GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+ c->rasterizer.procs.texGeni(c, GGL_T,
+ GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
+ u.dirty = 0xFF; // XXX: should be more subtle
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ y = cbSurface.height - (y + h);
+ const GLint Ucr = textureObject->crop_rect[0];
+ const GLint Vcr = textureObject->crop_rect[1];
+ const GLint s0 = Ucr - x;
+ const GLint t0 = (Vcr + Hcr) - y;
+
+ const GLuint tw = textureObject->surface.width;
+ const GLuint th = textureObject->surface.height;
+ if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
+ // The GL spec is unclear about what should happen
+ // in this case, so we just use the slow case, which
+ // at least won't crash
+ goto slow_case;
+ }
+
+ c->rasterizer.procs.texCoord2i(c, s0, t0);
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
+ set_depth_and_fog(c, z);
+
+ c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
+ c->rasterizer.procs.disable(c, GGL_W_LERP);
+ c->rasterizer.procs.disable(c, GGL_AA);
+ c->rasterizer.procs.shadeModel(c, GL_FLAT);
+ c->rasterizer.procs.recti(c, x, y, x+w, y+h);
+ return;
+ }
+ }
+
+slow_case:
+ drawTexxOES(
+ gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
+ gglIntToFixed(w), gglIntToFixed(h),
+ c);
+}
+
+
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+
+#if 0
+#pragma mark -
+#pragma mark Texture API
+#endif
+
+void glActiveTexture(GLenum texture)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ c->textures.active = texture - GL_TEXTURE0;
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+}
+
+void glBindTexture(GLenum target, GLuint texture)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ // Bind or create a texture
+ sp<EGLTextureObject> tex;
+ if (texture == 0) {
+ // 0 is our local texture object
+ tex = c->textures.defaultTexture;
+ } else {
+ tex = c->surfaceManager->texture(texture);
+ if (ggl_unlikely(tex == 0)) {
+ tex = c->surfaceManager->createTexture(texture);
+ if (tex == 0) {
+ ogles_error(c, GL_OUT_OF_MEMORY);
+ return;
+ }
+ }
+ }
+ bindTextureTmu(c, c->textures.active, texture, tex);
+}
+
+void glGenTextures(GLsizei n, GLuint *textures)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (n<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ // generate unique (shared) texture names
+ c->surfaceManager->getToken(n, textures);
+}
+
+void glDeleteTextures(GLsizei n, const GLuint *textures)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (n<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ // If deleting a bound texture, bind this unit to 0
+ for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
+ if (c->textures.tmu[t].name == 0)
+ continue;
+ for (int i=0 ; i<n ; i++) {
+ if (textures[i] && (textures[i] == c->textures.tmu[t].name)) {
+ // bind this tmu to texture 0
+ sp<EGLTextureObject> tex(c->textures.defaultTexture);
+ bindTextureTmu(c, t, 0, tex);
+ }
+ }
+ }
+ c->surfaceManager->deleteTextures(n, textures);
+ c->surfaceManager->recycleTokens(n, textures);
+}
+
+void glMultiTexCoord4f(
+ GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ const int tmu = target-GL_TEXTURE0;
+ c->current.texture[tmu].S = gglFloatToFixed(s);
+ c->current.texture[tmu].T = gglFloatToFixed(t);
+ c->current.texture[tmu].R = gglFloatToFixed(r);
+ c->current.texture[tmu].Q = gglFloatToFixed(q);
+}
+
+void glMultiTexCoord4x(
+ GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ const int tmu = target-GL_TEXTURE0;
+ c->current.texture[tmu].S = s;
+ c->current.texture[tmu].T = t;
+ c->current.texture[tmu].R = r;
+ c->current.texture[tmu].Q = q;
+}
+
+void glPixelStorei(GLenum pname, GLint param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if ((param<=0 || param>8) || (param & (param-1))) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (pname == GL_PACK_ALIGNMENT)
+ c->textures.packAlignment = param;
+ if (pname == GL_UNPACK_ALIGNMENT)
+ c->textures.unpackAlignment = param;
+}
+
+void glTexEnvf(GLenum target, GLenum pname, GLfloat param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.texEnvi(c, target, pname, GLint(param));
+}
+
+void glTexEnvfv(
+ GLenum target, GLenum pname, const GLfloat *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (pname == GL_TEXTURE_ENV_MODE) {
+ c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params));
+ return;
+ }
+ if (pname == GL_TEXTURE_ENV_COLOR) {
+ GGLfixed fixed[4];
+ for (int i=0 ; i<4 ; i++)
+ fixed[i] = gglFloatToFixed(params[i]);
+ c->rasterizer.procs.texEnvxv(c, target, pname, fixed);
+ return;
+ }
+ ogles_error(c, GL_INVALID_ENUM);
+}
+
+void glTexEnvx(GLenum target, GLenum pname, GLfixed param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.texEnvi(c, target, pname, param);
+}
+
+void glTexEnvxv(
+ GLenum target, GLenum pname, const GLfixed *params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->rasterizer.procs.texEnvxv(c, target, pname, params);
+}
+
+void glTexParameteriv(
+ GLenum target, GLenum pname, const GLint* params)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GGL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
+ switch (pname) {
+ case GL_TEXTURE_CROP_RECT_OES:
+ memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+}
+
+void glTexParameterf(
+ GLenum target, GLenum pname, GLfloat param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ texParameterx(target, pname, GLfixed(param), c);
+}
+
+void glTexParameterx(
+ GLenum target, GLenum pname, GLfixed param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ texParameterx(target, pname, param, c);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#endif
+
+void glCompressedTexImage2D(
+ GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLsizei imageSize, const GLvoid *data)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if ((internalformat < GL_PALETTE4_RGB8_OES ||
+ internalformat > GL_PALETTE8_RGB5_A1_OES)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (width<0 || height<0 || border!=0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ // "uncompress" the texture since pixelflinger doesn't support
+ // any compressed texture format natively.
+ GLenum format;
+ GLenum type;
+ switch (internalformat) {
+ case GL_PALETTE8_RGB8_OES:
+ case GL_PALETTE4_RGB8_OES:
+ format = GL_RGB;
+ type = GL_UNSIGNED_BYTE;
+ break;
+ case GL_PALETTE8_RGBA8_OES:
+ case GL_PALETTE4_RGBA8_OES:
+ format = GL_RGBA;
+ type = GL_UNSIGNED_BYTE;
+ break;
+ case GL_PALETTE8_R5_G6_B5_OES:
+ case GL_PALETTE4_R5_G6_B5_OES:
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case GL_PALETTE8_RGBA4_OES:
+ case GL_PALETTE4_RGBA4_OES:
+ format = GL_RGBA;
+ type = GL_UNSIGNED_SHORT_4_4_4_4;
+ break;
+ case GL_PALETTE8_RGB5_A1_OES:
+ case GL_PALETTE4_RGB5_A1_OES:
+ format = GL_RGBA;
+ type = GL_UNSIGNED_SHORT_5_5_5_1;
+ break;
+ default:
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ if (!data || !width || !height) {
+ // unclear if this is an error or not...
+ return;
+ }
+
+ int32_t size;
+ GGLSurface* surface;
+ // all mipmap levels are specified at once.
+ const int numLevels = level<0 ? -level : 1;
+ for (int i=0 ; i<numLevels ; i++) {
+ int lod_w = (width >> i) ? : 1;
+ int lod_h = (height >> i) ? : 1;
+ int error = createTextureSurface(c, &surface, &size,
+ i, format, type, lod_w, lod_h);
+ if (error) {
+ ogles_error(c, error);
+ return;
+ }
+ decodePalette4(data, i, width, height,
+ surface->data, surface->stride, internalformat);
+ }
+}
+
+
+void glTexImage2D(
+ GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLenum format, GLenum type, const GLvoid *pixels)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D && target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (width<0 || height<0 || border!=0 || level < 0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (format != internalformat) {
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+ if (validFormatType(c, format, type)) {
+ return;
+ }
+
+ int32_t size = 0;
+ GGLSurface* surface = 0;
+ if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+ int error = createTextureSurface(c, &surface, &size,
+ level, format, type, width, height);
+ if (error) {
+ ogles_error(c, error);
+ return;
+ }
+ } else if (pixels == 0 || level != 0) {
+ // pixel can't be null for direct texture
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+
+ if (pixels) {
+ const int32_t formatIdx = convertGLPixelFormat(format, type);
+ const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+ const int32_t align = c->textures.unpackAlignment-1;
+ const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+ const size_t size = bpr * height;
+ const int32_t stride = bpr / pixelFormat.size;
+
+ GGLSurface userSurface;
+ userSurface.version = sizeof(userSurface);
+ userSurface.width = width;
+ userSurface.height = height;
+ userSurface.stride = stride;
+ userSurface.format = formatIdx;
+ userSurface.compressedFormat = 0;
+ userSurface.data = (GLubyte*)pixels;
+
+ if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+ int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
+ if (err) {
+ ogles_error(c, err);
+ return;
+ }
+ generateMipmap(c, level);
+ } else {
+ // bind it to the texture unit
+ sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
+ tex->setSurface(&userSurface);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void glCompressedTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize,
+ const GLvoid *data)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ ogles_error(c, GL_INVALID_ENUM);
+}
+
+void glTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid *pixels)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (validFormatType(c, format, type)) {
+ return;
+ }
+
+ // find out which texture is bound to the current unit
+ const int active = c->textures.active;
+ EGLTextureObject* tex = c->textures.tmu[active].texture;
+ const GGLSurface& surface(tex->mip(level));
+
+ if (!tex->internalformat || tex->direct) {
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+ if ((xoffset + width > GLsizei(surface.width)) ||
+ (yoffset + height > GLsizei(surface.height))) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (!width || !height) {
+ return; // okay, but no-op.
+ }
+
+ // figure out the size we need as well as the stride
+ const int32_t formatIdx = convertGLPixelFormat(format, type);
+ if (formatIdx == 0) { // we don't know what to do with this
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+
+ const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+ const int32_t align = c->textures.unpackAlignment-1;
+ const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+ const size_t size = bpr * height;
+ const int32_t stride = bpr / pixelFormat.size;
+ GGLSurface userSurface;
+ userSurface.version = sizeof(userSurface);
+ userSurface.width = width;
+ userSurface.height = height;
+ userSurface.stride = stride;
+ userSurface.format = formatIdx;
+ userSurface.compressedFormat = 0;
+ userSurface.data = (GLubyte*)pixels;
+
+ int err = copyPixels(c,
+ surface, xoffset, yoffset,
+ userSurface, 0, 0, width, height);
+ if (err) {
+ ogles_error(c, err);
+ return;
+ }
+
+ generateMipmap(c, level);
+
+ // since we only changed the content of the texture, we don't need
+ // to call bindTexture on the main rasterizer.
+}
+
+// ----------------------------------------------------------------------------
+
+void glCopyTexImage2D(
+ GLenum target, GLint level, GLenum internalformat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (width<0 || height<0 || border!=0 || level<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ GLenum format = 0;
+ GLenum type = GL_UNSIGNED_BYTE;
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ const int cbFormatIdx = cbSurface.format;
+ switch (cbFormatIdx) {
+ case GGL_PIXEL_FORMAT_RGB_565:
+ type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case GGL_PIXEL_FORMAT_RGBA_5551:
+ type = GL_UNSIGNED_SHORT_5_5_5_1;
+ break;
+ case GGL_PIXEL_FORMAT_RGBA_4444:
+ type = GL_UNSIGNED_SHORT_4_4_4_4;
+ break;
+ }
+ switch (internalformat) {
+ case GL_ALPHA:
+ case GL_LUMINANCE_ALPHA:
+ case GL_LUMINANCE:
+ type = GL_UNSIGNED_BYTE;
+ break;
+ }
+
+ // figure out the format to use for the new texture
+ switch (cbFormatIdx) {
+ case GGL_PIXEL_FORMAT_RGBA_8888:
+ case GGL_PIXEL_FORMAT_A_8:
+ case GGL_PIXEL_FORMAT_RGBA_5551:
+ case GGL_PIXEL_FORMAT_RGBA_4444:
+ format = internalformat;
+ break;
+ case GGL_PIXEL_FORMAT_RGBX_8888:
+ case GGL_PIXEL_FORMAT_RGB_888:
+ case GGL_PIXEL_FORMAT_RGB_565:
+ case GGL_PIXEL_FORMAT_L_8:
+ switch (internalformat) {
+ case GL_LUMINANCE:
+ case GL_RGB:
+ format = internalformat;
+ break;
+ }
+ break;
+ }
+
+ if (format == 0) {
+ // invalid combination
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ // create the new texture...
+ int32_t size;
+ GGLSurface* surface;
+ int error = createTextureSurface(c, &surface, &size,
+ level, format, type, width, height);
+ if (error) {
+ ogles_error(c, error);
+ return;
+ }
+
+ // The bottom row is stored first in textures
+ GGLSurface txSurface(*surface);
+ txSurface.stride = -txSurface.stride;
+
+ // (x,y) is the lower-left corner of colorBuffer
+ y = cbSurface.height - (y + height);
+
+ int err = copyPixels(c,
+ txSurface, 0, 0,
+ cbSurface, x, y, cbSurface.width, cbSurface.height);
+ if (err) {
+ ogles_error(c, err);
+ }
+
+ generateMipmap(c, level);
+}
+
+void glCopyTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (!width || !height) {
+ return; // okay, but no-op.
+ }
+
+ // find out which texture is bound to the current unit
+ const int active = c->textures.active;
+ EGLTextureObject* tex = c->textures.tmu[active].texture;
+ const GGLSurface& surface(tex->mip(level));
+
+ if (!tex->internalformat) {
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+ if ((xoffset + width > GLsizei(surface.width)) ||
+ (yoffset + height > GLsizei(surface.height))) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ // The bottom row is stored first in textures
+ GGLSurface txSurface(surface);
+ txSurface.stride = -txSurface.stride;
+
+ // (x,y) is the lower-left corner of colorBuffer
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ y = cbSurface.height - (y + height);
+
+ int err = copyPixels(c,
+ surface, xoffset, yoffset,
+ cbSurface, x, y, width, height);
+ if (err) {
+ ogles_error(c, err);
+ return;
+ }
+
+ generateMipmap(c, level);
+}
+
+void glReadPixels(
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid *pixels)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if ((format != GL_RGBA) && (format != GL_RGB)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+ if (width<0 || height<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (x<0 || x<0) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
+ if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
+ formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
+ } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
+ formatIdx = GGL_PIXEL_FORMAT_RGB_565;
+ } else {
+ ogles_error(c, GL_INVALID_OPERATION);
+ return;
+ }
+
+ const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
+ if ((x+width > GLint(readSurface.width)) ||
+ (y+height > GLint(readSurface.height))) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
+ const int32_t align = c->textures.packAlignment-1;
+ const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
+ const int32_t stride = bpr / pixelFormat.size;
+
+ GGLSurface userSurface;
+ userSurface.version = sizeof(userSurface);
+ userSurface.width = width;
+ userSurface.height = height;
+ userSurface.stride = -stride; // bottom row is transfered first
+ userSurface.format = formatIdx;
+ userSurface.compressedFormat = 0;
+ userSurface.data = (GLubyte*)pixels;
+
+ // use pixel-flinger to handle all the conversions
+ GGLContext* ggl = getRasterizer(c);
+ if (!ggl) {
+ // the only reason this would fail is because we ran out of memory
+ ogles_error(c, GL_OUT_OF_MEMORY);
+ return;
+ }
+
+ ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
+ ggl->bindTexture(ggl, &readSurface); // source is read-buffer
+ ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
+ ggl->recti(ggl, 0, 0, width, height);
+}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark DrawTexture Extension
+#endif
+
+void glDrawTexsvOES(const GLshort* coords) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
+}
+void glDrawTexivOES(const GLint* coords) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
+}
+void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexiOES(x, y, z, w, h, c);
+}
+void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexiOES(x, y, z, w, h, c);
+}
+
+void glDrawTexfvOES(const GLfloat* coords) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexxOES(
+ gglFloatToFixed(coords[0]),
+ gglFloatToFixed(coords[1]),
+ gglFloatToFixed(coords[2]),
+ gglFloatToFixed(coords[3]),
+ gglFloatToFixed(coords[4]),
+ c);
+}
+void glDrawTexxvOES(const GLfixed* coords) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
+}
+void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexxOES(
+ gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
+ gglFloatToFixed(w), gglFloatToFixed(h),
+ c);
+}
+void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
+ ogles_context_t* c = ogles_context_t::get();
+ drawTexxOES(x, y, z, w, h, c);
+}
diff --git a/opengl/libagl/texture.h b/opengl/libagl/texture.h
new file mode 100644
index 0000000..5c57948
--- /dev/null
+++ b/opengl/libagl/texture.h
@@ -0,0 +1,45 @@
+/* libs/opengles/texture.h
+**
+** Copyright 2006, 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_OPENGLES_TEXTURE_H
+#define ANDROID_OPENGLES_TEXTURE_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+
+#include "context.h"
+
+namespace android {
+
+void ogles_init_texture(ogles_context_t* c);
+void ogles_uninit_texture(ogles_context_t* c);
+void ogles_validate_texture_impl(ogles_context_t* c);
+
+inline void ogles_validate_texture(ogles_context_t* c) {
+ if (c->rasterizer.state.enables & GGL_ENABLE_TMUS)
+ ogles_validate_texture_impl(c);
+}
+
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_TEXTURE_H
diff --git a/opengl/libagl/vertex.cpp b/opengl/libagl/vertex.cpp
new file mode 100644
index 0000000..5bcc9dc
--- /dev/null
+++ b/opengl/libagl/vertex.cpp
@@ -0,0 +1,247 @@
+/* libs/opengles/vertex.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "context.h"
+#include "fp.h"
+#include "vertex.h"
+#include "state.h"
+#include "matrix.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+void ogles_init_vertex(ogles_context_t* c)
+{
+ c->cull.enable = GL_FALSE;
+ c->cull.cullFace = GL_BACK;
+ c->cull.frontFace = GL_CCW;
+
+ c->current.color.r = 0x10000;
+ c->current.color.g = 0x10000;
+ c->current.color.b = 0x10000;
+ c->current.color.a = 0x10000;
+
+ c->currentNormal.z = 0x10000;
+}
+
+void ogles_uninit_vertex(ogles_context_t* c)
+{
+}
+
+// ----------------------------------------------------------------------------
+// vertex processing
+// ----------------------------------------------------------------------------
+
+// Divides a vertex clip coordinates by W
+static inline
+void perspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
+{
+ // [x,y,z]window = vpt * ([x,y,z]clip / clip.w)
+ // [w]window = 1/w
+
+ // With a regular projection generated by glFrustum(),
+ // we have w=-z, therefore, w is in [zNear, zFar].
+ // Also, zNear and zFar are stricly positive,
+ // and 1/w (window.w) is in [1/zFar, 1/zNear], usually this
+ // means ]0, +inf[ -- however, it is always recommended
+ // to use as large values as possible for zNear.
+ // All in all, w is usually smaller than 1.0 (assuming
+ // zNear is at least 1.0); and even if zNear is smaller than 1.0
+ // values of w won't be too big.
+
+ const int32_t rw = gglRecip28(v->clip.w);
+ const GLfixed* const m = c->transforms.vpt.transform.matrix.m;
+ v->window.w = rw;
+ v->window.x = gglMulAddx(gglMulx(v->clip.x, rw, 16), m[ 0], m[12], 28);
+ v->window.y = gglMulAddx(gglMulx(v->clip.y, rw, 16), m[ 5], m[13], 28);
+ v->window.x = TRI_FROM_FIXED(v->window.x);
+ v->window.y = TRI_FROM_FIXED(v->window.y);
+ if (enables & GGL_ENABLE_DEPTH_TEST) {
+ v->window.z = gglMulAddx(gglMulx(v->clip.z, rw, 16), m[10], m[14], 28);
+ }
+}
+
+// frustum clipping and W-divide
+static inline
+void clipFrustumPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
+{
+ // ndc = clip / W
+ // window = ncd * viewport
+
+ // clip to the view-volume
+ uint32_t clip = v->flags & vertex_t::CLIP_ALL;
+ const GLfixed w = v->clip.w;
+ if (v->clip.x < -w) clip |= vertex_t::CLIP_L;
+ if (v->clip.x > w) clip |= vertex_t::CLIP_R;
+ if (v->clip.y < -w) clip |= vertex_t::CLIP_B;
+ if (v->clip.y > w) clip |= vertex_t::CLIP_T;
+ if (v->clip.z < -w) clip |= vertex_t::CLIP_N;
+ if (v->clip.z > w) clip |= vertex_t::CLIP_F;
+
+ v->flags |= clip;
+ c->arrays.cull &= clip;
+
+ if (ggl_likely(!clip)) {
+ // if the vertice is clipped, we don't do the perspective
+ // divide, since we don't need its window coordinates.
+ perspective(c, v, enables);
+ }
+}
+
+// frustum clipping, user clipping and W-divide
+static inline
+void clipAllPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
+{
+ // compute eye coordinates
+ c->arrays.mv_transform(
+ &c->transforms.modelview.transform, &v->eye, &v->obj);
+ v->flags |= vertex_t::EYE;
+
+ // clip this vertex against each user clip plane
+ uint32_t clip = 0;
+ int planes = c->clipPlanes.enable;
+ while (planes) {
+ const int i = 31 - gglClz(planes);
+ planes &= ~(1<<i);
+ // XXX: we should have a special dot() for 2,3,4 coords vertices
+ GLfixed d = dot4(c->clipPlanes.plane[i].equation.v, v->eye.v);
+ if (d < 0) {
+ clip |= 0x100<<i;
+ }
+ }
+ v->flags |= clip;
+
+ clipFrustumPerspective(c, v, enables);
+}
+
+// ----------------------------------------------------------------------------
+
+void ogles_vertex_project(ogles_context_t* c, vertex_t* v) {
+ perspective(c, v, c->rasterizer.state.enables);
+}
+
+void ogles_vertex_perspective2D(ogles_context_t* c, vertex_t* v)
+{
+ // here we assume w=1.0 and the viewport transformation
+ // has been applied already.
+ c->arrays.cull = 0;
+ v->window.x = TRI_FROM_FIXED(v->clip.x);
+ v->window.y = TRI_FROM_FIXED(v->clip.y);
+ v->window.z = v->clip.z;
+ v->window.w = v->clip.w << 12;
+}
+
+void ogles_vertex_perspective3DZ(ogles_context_t* c, vertex_t* v) {
+ clipFrustumPerspective(c, v, GGL_ENABLE_DEPTH_TEST);
+}
+void ogles_vertex_perspective3D(ogles_context_t* c, vertex_t* v) {
+ clipFrustumPerspective(c, v, 0);
+}
+void ogles_vertex_clipAllPerspective3DZ(ogles_context_t* c, vertex_t* v) {
+ clipAllPerspective(c, v, GGL_ENABLE_DEPTH_TEST);
+}
+void ogles_vertex_clipAllPerspective3D(ogles_context_t* c, vertex_t* v) {
+ clipAllPerspective(c, v, 0);
+}
+
+static void clipPlanex(GLenum plane, const GLfixed* equ, ogles_context_t* c)
+{
+ const int p = plane - GL_CLIP_PLANE0;
+ if (ggl_unlikely(uint32_t(p) > (GL_CLIP_PLANE5 - GL_CLIP_PLANE0))) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ vec4_t& equation = c->clipPlanes.plane[p].equation;
+ memcpy(equation.v, equ, sizeof(vec4_t));
+
+ ogles_validate_transform(c, transform_state_t::MVIT);
+ transform_t& mvit = c->transforms.mvit4;
+ mvit.point4(&mvit, &equation, &equation);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+
+void glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->current.color.r = gglFloatToFixed(r);
+ c->currentColorClamped.r = gglClampx(c->current.color.r);
+ c->current.color.g = gglFloatToFixed(g);
+ c->currentColorClamped.g = gglClampx(c->current.color.g);
+ c->current.color.b = gglFloatToFixed(b);
+ c->currentColorClamped.b = gglClampx(c->current.color.b);
+ c->current.color.a = gglFloatToFixed(a);
+ c->currentColorClamped.a = gglClampx(c->current.color.a);
+}
+
+void glColor4x(GLfixed r, GLfixed g, GLfixed b, GLfixed a)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->current.color.r = r;
+ c->current.color.g = g;
+ c->current.color.b = b;
+ c->current.color.a = a;
+ c->currentColorClamped.r = gglClampx(r);
+ c->currentColorClamped.g = gglClampx(g);
+ c->currentColorClamped.b = gglClampx(b);
+ c->currentColorClamped.a = gglClampx(a);
+}
+
+void glNormal3f(GLfloat x, GLfloat y, GLfloat z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->currentNormal.x = gglFloatToFixed(x);
+ c->currentNormal.y = gglFloatToFixed(y);
+ c->currentNormal.z = gglFloatToFixed(z);
+}
+
+void glNormal3x(GLfixed x, GLfixed y, GLfixed z)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ c->currentNormal.x = x;
+ c->currentNormal.y = y;
+ c->currentNormal.z = z;
+}
+
+// ----------------------------------------------------------------------------
+
+void glClipPlanef(GLenum plane, const GLfloat* equ)
+{
+ const GLfixed equx[4] = {
+ gglFloatToFixed(equ[0]),
+ gglFloatToFixed(equ[1]),
+ gglFloatToFixed(equ[2]),
+ gglFloatToFixed(equ[3])
+ };
+ ogles_context_t* c = ogles_context_t::get();
+ clipPlanex(plane, equx, c);
+}
+
+void glClipPlanex(GLenum plane, const GLfixed* equ)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ clipPlanex(plane, equ, c);
+}
diff --git a/opengl/libagl/vertex.h b/opengl/libagl/vertex.h
new file mode 100644
index 0000000..55e6213
--- /dev/null
+++ b/opengl/libagl/vertex.h
@@ -0,0 +1,48 @@
+/* libs/opengles/vertex.h
+**
+** Copyright 2006, 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_OPENGLES_VERTEX_H
+#define ANDROID_OPENGLES_VERTEX_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+namespace android {
+
+namespace gl {
+struct vertex_t;
+struct ogles_context_t;
+};
+
+void ogles_init_vertex(ogles_context_t* c);
+void ogles_uninit_vertex(ogles_context_t* c);
+
+void ogles_vertex_perspective2D(ogles_context_t*, vertex_t*);
+
+void ogles_vertex_perspective3D(ogles_context_t*, vertex_t*);
+void ogles_vertex_perspective3DZ(ogles_context_t*, vertex_t*);
+void ogles_vertex_clipAllPerspective3D(ogles_context_t*, vertex_t*);
+void ogles_vertex_clipAllPerspective3DZ(ogles_context_t*, vertex_t*);
+
+
+void ogles_vertex_project(ogles_context_t* c, vertex_t*);
+
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_VERTEX_H
+
diff --git a/services/Android.mk b/services/Android.mk
new file mode 100644
index 0000000..5e912d6
--- /dev/null
+++ b/services/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+
+# the library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ $(call all-subdir-java-files)
+
+LOCAL_MODULE:= services
+
+LOCAL_JAVA_LIBRARIES := android.policy
+
+include $(BUILD_JAVA_LIBRARY)
+
+include $(BUILD_DROIDDOC)
+