diff --git a/extras/JuceDemo/Source/demos/OpenGLDemo.cpp b/extras/JuceDemo/Source/demos/OpenGLDemo.cpp index ed839103cb..b9abd54864 100644 --- a/extras/JuceDemo/Source/demos/OpenGLDemo.cpp +++ b/extras/JuceDemo/Source/demos/OpenGLDemo.cpp @@ -128,7 +128,7 @@ public: glPixelStorei (GL_UNPACK_ALIGNMENT, 4); - Image::BitmapData srcData (image, false); + Image::BitmapData srcData (image, Image::BitmapData::readOnly); glTexImage2D (GL_TEXTURE_2D, 0, 4, image.getWidth(), image.getHeight(), 0, GL_RGB, diff --git a/extras/audio plugins/demo/Source/PluginProcessor.cpp b/extras/audio plugins/demo/Source/PluginProcessor.cpp index 690e8d3a0c..50356489ca 100644 --- a/extras/audio plugins/demo/Source/PluginProcessor.cpp +++ b/extras/audio plugins/demo/Source/PluginProcessor.cpp @@ -222,6 +222,13 @@ void JuceDemoPluginAudioProcessor::releaseResources() keyboardState.reset(); } +void JuceDemoPluginAudioProcessor::reset() +{ + // Use this method as the place to clear any delay lines, buffers, etc, as it + // means there's been a break in the audio's continuity. + delayBuffer.clear(); +} + void JuceDemoPluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) { const int numSamples = buffer.getNumSamples(); diff --git a/extras/audio plugins/demo/Source/PluginProcessor.h b/extras/audio plugins/demo/Source/PluginProcessor.h index 07f2291116..46d7d6bb20 100644 --- a/extras/audio plugins/demo/Source/PluginProcessor.h +++ b/extras/audio plugins/demo/Source/PluginProcessor.h @@ -28,8 +28,8 @@ public: //============================================================================== void prepareToPlay (double sampleRate, int samplesPerBlock); void releaseResources(); - void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + void reset(); //============================================================================== bool hasEditor() const { return true; } diff --git a/juce.h b/juce.h index 84ae097254..5fda86bc02 100644 --- a/juce.h +++ b/juce.h @@ -73,11 +73,6 @@ BEGIN_JUCE_NAMESPACE #pragma pack (pop) #endif -#if defined (JUCE_DLL) && ! (JUCE_AMALGAMATED_TEMPLATE || defined (JUCE_DLL_BUILD)) - #undef JUCE_LEAK_DETECTOR - #define JUCE_LEAK_DETECTOR(OwnerClass) -#endif - END_JUCE_NAMESPACE diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 7f070e2bef..549963c9dd 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -2351,7 +2351,9 @@ public: a.memoryBarrier(); a -= (Type) 5; test.expect (a.get() == (Type) 20); - ++a; ++a; --a; + test.expect (++a == (Type) 21); + ++a; + test.expect (--a == (Type) 21); test.expect (a.get() == (Type) 21); a.memoryBarrier(); @@ -22592,7 +22594,7 @@ public: startSampleInFile += samplesReceived; numSamples -= samplesReceived; - if ((outFlags & kQTMovieAudioExtractionComplete) != 0 && numSamples > 0) + if (((outFlags & kQTMovieAudioExtractionComplete) != 0 || samplesReceived == 0) && numSamples > 0) { for (int j = numDestChannels; --j >= 0;) if (destSamples[j] != 0) @@ -31251,6 +31253,8 @@ public: void setStateInformation (const void* data, int sizeInBytes); void setCurrentProgramStateInformation (const void* data, int sizeInBytes); + void refreshParameterListFromPlugin(); + private: friend class AudioUnitPluginWindowCarbon; @@ -31272,7 +31276,6 @@ private: bool getComponentDescFromFile (const String& fileOrIdentifier); void setPluginCallbacks(); - void getParameterListFromPlugin(); OSStatus renderGetInput (AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, @@ -31515,7 +31518,7 @@ bool AudioUnitPluginInstance::getComponentDescFromFile (const String& fileOrIden void AudioUnitPluginInstance::initialise() { - getParameterListFromPlugin(); + refreshParameterListFromPlugin(); setPluginCallbacks(); int numIns, numOuts; @@ -31524,7 +31527,7 @@ void AudioUnitPluginInstance::initialise() setLatencySamples (0); } -void AudioUnitPluginInstance::getParameterListFromPlugin() +void AudioUnitPluginInstance::refreshParameterListFromPlugin() { parameterIds.clear(); @@ -31539,7 +31542,7 @@ void AudioUnitPluginInstance::getParameterListFromPlugin() parameterIds.insertMultiple (0, 0, paramListSize / sizeof (int)); AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, - 0, ¶meterIds.getReference(0), ¶mListSize); + 0, parameterIds.getRawDataPointer(), ¶mListSize); } } } @@ -38774,7 +38777,7 @@ void MessageManager::deliverMessage (Message* const message) JUCE_CATCH_EXCEPTION } -#if ! (JUCE_MAC || JUCE_IOS) +#if ! (JUCE_MAC || JUCE_IOS || JUCE_ANDROID) void MessageManager::runDispatchLoop() { jassert (isThisTheMessageThread()); // must only be called by the message thread @@ -73914,7 +73917,7 @@ public: const int height = getHeight() / 2; colours = Image (Image::RGB, width, height, false); - Image::BitmapData pixels (colours, true); + Image::BitmapData pixels (colours, Image::BitmapData::writeOnly); for (int y = 0; y < height; ++y) { @@ -84560,7 +84563,7 @@ public: const Ptr clipToImageAlpha (const Image& image, const AffineTransform& transform, const bool betterQuality) { - const Image::BitmapData srcData (image, false); + const Image::BitmapData srcData (image, Image::BitmapData::readOnly); if (transform.isOnlyTranslation()) { @@ -85291,7 +85294,7 @@ public: { if (fillType.isColour()) { - Image::BitmapData destData (image, true); + Image::BitmapData destData (image, Image::BitmapData::readWrite); clip->fillRectWithColour (destData, r.translated (xOffset, yOffset), fillType.colour.getPixelARGB(), replaceContents); } else @@ -85320,7 +85323,7 @@ public: { if (fillType.isColour()) { - Image::BitmapData destData (image, true); + Image::BitmapData destData (image, Image::BitmapData::readWrite); clip->fillRectWithColour (destData, r.translated ((float) xOffset, (float) yOffset), fillType.colour.getPixelARGB()); } else @@ -85368,7 +85371,7 @@ public: if (shapeToFill != 0) { - Image::BitmapData destData (image, true); + Image::BitmapData destData (image, Image::BitmapData::readWrite); if (fillType.isGradient()) { @@ -85405,8 +85408,8 @@ public: { const AffineTransform transform (getTransformWith (t)); - const Image::BitmapData destData (image, true); - const Image::BitmapData srcData (sourceImage, false); + const Image::BitmapData destData (image, Image::BitmapData::readWrite); + const Image::BitmapData srcData (sourceImage, Image::BitmapData::readOnly); const int alpha = fillType.colour.getAlpha(); const bool betterQuality = (interpolationQuality != Graphics::lowResamplingQuality); @@ -89437,38 +89440,40 @@ void DropShadowEffect::applyEffect (Image& image, Graphics& g, float alpha) Image shadowImage (Image::SingleChannel, w, h, false); - const Image::BitmapData srcData (image, false); - const Image::BitmapData destData (shadowImage, true); - - const int filter = roundToInt (63.0f / radius); - const int radiusMinus1 = roundToInt ((radius - 1.0f) * 63.0f); - - for (int x = w; --x >= 0;) { - int shadowAlpha = 0; + const Image::BitmapData srcData (image, Image::BitmapData::readOnly); + const Image::BitmapData destData (shadowImage, Image::BitmapData::readWrite); - const PixelARGB* src = ((const PixelARGB*) srcData.data) + x; - uint8* shadowPix = destData.data + x; - - for (int y = h; --y >= 0;) - { - shadowAlpha = ((shadowAlpha * radiusMinus1 + (src->getAlpha() << 6)) * filter) >> 12; - - *shadowPix = (uint8) shadowAlpha; - src = (const PixelARGB*) (((const uint8*) src) + srcData.lineStride); - shadowPix += destData.lineStride; - } - } - - for (int y = h; --y >= 0;) - { - int shadowAlpha = 0; - uint8* shadowPix = destData.getLinePointer (y); + const int filter = roundToInt (63.0f / radius); + const int radiusMinus1 = roundToInt ((radius - 1.0f) * 63.0f); for (int x = w; --x >= 0;) { - shadowAlpha = ((shadowAlpha * radiusMinus1 + (*shadowPix << 6)) * filter) >> 12; - *shadowPix++ = (uint8) shadowAlpha; + int shadowAlpha = 0; + + const PixelARGB* src = ((const PixelARGB*) srcData.data) + x; + uint8* shadowPix = destData.data + x; + + for (int y = h; --y >= 0;) + { + shadowAlpha = ((shadowAlpha * radiusMinus1 + (src->getAlpha() << 6)) * filter) >> 12; + + *shadowPix = (uint8) shadowAlpha; + src = addBytesToPointer (src, srcData.lineStride); + shadowPix += destData.lineStride; + } + } + + for (int y = h; --y >= 0;) + { + int shadowAlpha = 0; + uint8* shadowPix = destData.getLinePointer (y); + + for (int x = w; --x >= 0;) + { + shadowAlpha = ((shadowAlpha * radiusMinus1 + (*shadowPix << 6)) * filter) >> 12; + *shadowPix++ = (uint8) shadowAlpha; + } } } @@ -94762,22 +94767,15 @@ Image::SharedImage::~SharedImage() { } -inline uint8* Image::SharedImage::getPixelData (const int x, const int y) const throw() -{ - return imageData + lineStride * y + pixelStride * x; -} - class SoftwareSharedImage : public Image::SharedImage { public: SoftwareSharedImage (const Image::PixelFormat format_, const int width_, const int height_, const bool clearImage) - : Image::SharedImage (format_, width_, height_) + : Image::SharedImage (format_, width_, height_), + pixelStride (format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1)), + lineStride ((pixelStride * jmax (1, width_) + 3) & ~3) { - pixelStride = format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1); - lineStride = (pixelStride * jmax (1, width) + 3) & ~3; - - imageDataAllocated.allocate (lineStride * jmax (1, height), clearImage); - imageData = imageDataAllocated; + imageData.allocate (lineStride * jmax (1, height_), clearImage); } Image::ImageType getType() const @@ -94790,6 +94788,14 @@ public: return new LowLevelGraphicsSoftwareRenderer (Image (this)); } + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) + { + bitmap.data = imageData + x * pixelStride + y * lineStride; + bitmap.pixelFormat = format; + bitmap.lineStride = lineStride; + bitmap.pixelStride = pixelStride; + } + Image::SharedImage* clone() { SoftwareSharedImage* s = new SoftwareSharedImage (format, width, height, false); @@ -94798,7 +94804,8 @@ public: } private: - HeapBlock imageDataAllocated; + HeapBlock imageData; + const int pixelStride, lineStride; JUCE_LEAK_DETECTOR (SoftwareSharedImage); }; @@ -94815,9 +94822,6 @@ public: : Image::SharedImage (image_->getPixelFormat(), area_.getWidth(), area_.getHeight()), image (image_), area (area_) { - pixelStride = image_->getPixelStride(); - lineStride = image_->getLineStride(); - imageData = image_->getPixelData (area_.getX(), area_.getY()); } Image::ImageType getType() const @@ -94833,6 +94837,11 @@ public: return g; } + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) + { + image->initialiseBitmapData (bitmap, x + area.getX(), y + area.getY(), mode); + } + Image::SharedImage* clone() { return new SubsectionSharedImage (image->clone(), area); @@ -94932,7 +94941,7 @@ const Image Image::convertedToFormat (PixelFormat newFormat) const } else { - const BitmapData destData (newImage, 0, 0, w, h, true); + const BitmapData destData (newImage, 0, 0, w, h, BitmapData::writeOnly); const BitmapData srcData (*this, 0, 0, w, h); for (int y = 0; y < h; ++y) @@ -94965,37 +94974,39 @@ NamedValueSet* Image::getProperties() const return image == 0 ? 0 : &(image->userData); } -Image::BitmapData::BitmapData (Image& image, const int x, const int y, const int w, const int h, const bool /*makeWritable*/) - : data (image.image == 0 ? 0 : image.image->getPixelData (x, y)), - pixelFormat (image.getFormat()), - lineStride (image.image == 0 ? 0 : image.image->lineStride), - pixelStride (image.image == 0 ? 0 : image.image->pixelStride), - width (w), +Image::BitmapData::BitmapData (Image& image, const int x, const int y, const int w, const int h, BitmapData::ReadWriteMode mode) + : width (w), height (h) { - jassert (data != 0); + // The BitmapData class must be given a valid image, and a valid rectangle within it! + jassert (image.image != 0); jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= image.getWidth() && y + h <= image.getHeight()); + + image.image->initialiseBitmapData (*this, x, y, mode); + jassert (data != 0 && pixelStride > 0 && lineStride != 0); } Image::BitmapData::BitmapData (const Image& image, const int x, const int y, const int w, const int h) - : data (image.image == 0 ? 0 : image.image->getPixelData (x, y)), - pixelFormat (image.getFormat()), - lineStride (image.image == 0 ? 0 : image.image->lineStride), - pixelStride (image.image == 0 ? 0 : image.image->pixelStride), - width (w), + : width (w), height (h) { + // The BitmapData class must be given a valid image, and a valid rectangle within it! + jassert (image.image != 0); jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= image.getWidth() && y + h <= image.getHeight()); + + image.image->initialiseBitmapData (*this, x, y, readOnly); + jassert (data != 0 && pixelStride > 0 && lineStride != 0); } -Image::BitmapData::BitmapData (const Image& image, bool /*needsToBeWritable*/) - : data (image.image == 0 ? 0 : image.image->imageData), - pixelFormat (image.getFormat()), - lineStride (image.image == 0 ? 0 : image.image->lineStride), - pixelStride (image.image == 0 ? 0 : image.image->pixelStride), - width (image.getWidth()), +Image::BitmapData::BitmapData (const Image& image, BitmapData::ReadWriteMode mode) + : width (image.getWidth()), height (image.getHeight()) { + // The BitmapData class must be given a valid image! + jassert (image.image != 0); + + image.image->initialiseBitmapData (*this, 0, 0, mode); + jassert (data != 0 && pixelStride > 0 && lineStride != 0); } Image::BitmapData::~BitmapData() @@ -95010,21 +95021,10 @@ const Colour Image::BitmapData::getPixelColour (const int x, const int y) const switch (pixelFormat) { - case Image::ARGB: - { - PixelARGB p (*(const PixelARGB*) pixel); - p.unpremultiply(); - return Colour (p.getARGB()); - } - case Image::RGB: - return Colour (((const PixelRGB*) pixel)->getARGB()); - - case Image::SingleChannel: - return Colour ((uint8) 0, (uint8) 0, (uint8) 0, *pixel); - - default: - jassertfalse; - break; + case Image::ARGB: return Colour (((const PixelARGB*) pixel)->getUnpremultipliedARGB()); + case Image::RGB: return Colour (((const PixelRGB*) pixel)->getUnpremultipliedARGB()); + case Image::SingleChannel: return Colour (((const PixelAlpha*) pixel)->getUnpremultipliedARGB()); + default: jassertfalse; break; } return Colour(); @@ -95053,7 +95053,7 @@ void Image::setPixelData (int x, int y, int w, int h, if (Rectangle::intersectRectangles (x, y, w, h, 0, 0, getWidth(), getHeight())) { - const BitmapData dest (*this, x, y, w, h, true); + const BitmapData dest (*this, x, y, w, h, BitmapData::writeOnly); for (int i = 0; i < h; ++i) { @@ -95072,7 +95072,7 @@ void Image::clear (const Rectangle& area, const Colour& colourToClearTo) { const PixelARGB col (colourToClearTo.getPixelARGB()); - const BitmapData destData (*this, clipped.getX(), clipped.getY(), clipped.getWidth(), clipped.getHeight(), true); + const BitmapData destData (*this, clipped.getX(), clipped.getY(), clipped.getWidth(), clipped.getHeight(), BitmapData::writeOnly); uint8* dest = destData.data; int dh = clipped.getHeight(); @@ -95124,7 +95124,7 @@ void Image::setPixelAt (const int x, const int y, const Colour& colour) { if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight())) { - const BitmapData destData (*this, x, y, 1, 1, true); + const BitmapData destData (*this, x, y, 1, 1, BitmapData::writeOnly); destData.setPixelColour (0, 0, colour); } } @@ -95134,7 +95134,7 @@ void Image::multiplyAlphaAt (const int x, const int y, const float multiplier) if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight()) && hasAlphaChannel()) { - const BitmapData destData (*this, x, y, 1, 1, true); + const BitmapData destData (*this, x, y, 1, 1, BitmapData::readWrite); if (isARGB()) ((PixelARGB*) destData.data)->multiplyAlpha (multiplier); @@ -95147,7 +95147,7 @@ void Image::multiplyAllAlphas (const float amountToMultiplyBy) { if (hasAlphaChannel()) { - const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), true); + const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite); if (isARGB()) { @@ -95186,7 +95186,7 @@ void Image::desaturate() { if (isARGB() || isRGB()) { - const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), true); + const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite); if (isARGB()) { @@ -95310,7 +95310,7 @@ void Image::moveImageSection (int dx, int dy, const int maxX = jmax (dx, sx) + w; const int maxY = jmax (dy, sy) + h; - const BitmapData destData (*this, minX, minY, maxX - minX, maxY - minY, true); + const BitmapData destData (*this, minX, minY, maxX - minX, maxY - minY, BitmapData::readWrite); uint8* dst = destData.getPixelPointer (dx - minX, dy - minY); const uint8* src = destData.getPixelPointer (sx - minX, sy - minY); @@ -95588,10 +95588,11 @@ void ImageConvolutionKernel::applyToImage (Image& destImage, const int right = area.getRight(); const int bottom = area.getBottom(); - const Image::BitmapData destData (destImage, area.getX(), area.getY(), area.getWidth(), area.getHeight(), true); + const Image::BitmapData destData (destImage, area.getX(), area.getY(), area.getWidth(), area.getHeight(), + Image::BitmapData::writeOnly); uint8* line = destData.data; - const Image::BitmapData srcData (sourceImage, false); + const Image::BitmapData srcData (sourceImage, Image::BitmapData::readOnly); if (destData.pixelStride == 4) { @@ -96145,7 +96146,7 @@ private: int index; int xpos = 0, ypos = 0, pass = 0; - const Image::BitmapData destData (image, true); + const Image::BitmapData destData (image, Image::BitmapData::writeOnly); uint8* p = destData.data; const bool hasAlpha = image.hasAlphaChannel(); @@ -211337,7 +211338,7 @@ const Image JPEGImageFormat::decodeImage (InputStream& in) image.getProperties()->set ("originalImageHadAlpha", false); const bool hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect) - const Image::BitmapData destData (image, true); + const Image::BitmapData destData (image, Image::BitmapData::writeOnly); for (int y = 0; y < height; ++y) { @@ -211441,7 +211442,7 @@ bool JPEGImageFormat::writeImageToStream (const Image& image, OutputStream& out) JSAMPARRAY buffer = (*jpegCompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegCompStruct, JPOOL_IMAGE, strideBytes, 1); - const Image::BitmapData srcData (image, false); + const Image::BitmapData srcData (image, Image::BitmapData::readOnly); while (jpegCompStruct.next_scanline < jpegCompStruct.image_height) { @@ -237048,7 +237049,7 @@ const Image PNGImageFormat::decodeImage (InputStream& in) image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel()); hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect) - const Image::BitmapData destData (image, true); + const Image::BitmapData destData (image, Image::BitmapData::writeOnly); uint8* srcRow = tempBuffer; uint8* destRow = destData.data; @@ -237127,7 +237128,7 @@ bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out) png_set_shift (pngWriteStruct, &sig_bit); png_set_packing (pngWriteStruct); - const Image::BitmapData srcData (image, false); + const Image::BitmapData srcData (image, Image::BitmapData::readOnly); for (int y = 0; y < height; ++y) { @@ -240489,7 +240490,7 @@ public: D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); Image img (image.convertedToFormat (Image::ARGB)); - Image::BitmapData bd (img, false); + Image::BitmapData bd (img, Image::BitmapData::readOnly); bp.pixelFormat = renderingTarget->GetPixelFormat(); bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; @@ -240724,7 +240725,7 @@ public: D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); maskImage = image.convertedToFormat (Image::ARGB); - Image::BitmapData bd (this->image, false); // xxx should be maskImage? + Image::BitmapData bd (this->image, Image::BitmapData::readOnly); // xxx should be maskImage? bp.pixelFormat = owner.renderingTarget->GetPixelFormat(); bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; @@ -240903,7 +240904,7 @@ public: D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); this->image = image.convertedToFormat (Image::ARGB); - Image::BitmapData bd (this->image, false); + Image::BitmapData bd (this->image, Image::BitmapData::readOnly); bp.pixelFormat = owner.renderingTarget->GetPixelFormat(); bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; @@ -241277,12 +241278,6 @@ class WindowsBitmapImage : public Image::SharedImage { public: - HBITMAP hBitmap; - HGDIOBJ previousBitmap; - BITMAPV4HEADER bitmapInfo; - HDC hdc; - unsigned char* bitmapData; - WindowsBitmapImage (const Image::PixelFormat format_, const int w, const int h, const bool clearImage) : Image::SharedImage (format_, w, h) @@ -241290,6 +241285,7 @@ public: jassert (format_ == Image::RGB || format_ == Image::ARGB); pixelStride = (format_ == Image::RGB) ? 3 : 4; + lineStride = -((w * pixelStride + 3) & ~3); zerostruct (bitmapInfo); bitmapInfo.bV4Size = sizeof (BITMAPV4HEADER); @@ -241312,19 +241308,14 @@ public: bitmapInfo.bV4V4Compression = BI_RGB; } - lineStride = -((w * pixelStride + 3) & ~3); - HDC dc = GetDC (0); hdc = CreateCompatibleDC (dc); ReleaseDC (0, dc); SetMapMode (hdc, MM_TEXT); - hBitmap = CreateDIBSection (hdc, - (BITMAPINFO*) &(bitmapInfo), - DIB_RGB_COLORS, - (void**) &bitmapData, - 0, 0); + hBitmap = CreateDIBSection (hdc, (BITMAPINFO*) &(bitmapInfo), DIB_RGB_COLORS, + (void**) &bitmapData, 0, 0); previousBitmap = SelectObject (hdc, hBitmap); @@ -241348,6 +241339,14 @@ public: return new LowLevelGraphicsSoftwareRenderer (Image (this)); } + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) + { + bitmap.data = imageData + x * pixelStride + y * lineStride; + bitmap.pixelFormat = format; + bitmap.lineStride = lineStride; + bitmap.pixelStride = pixelStride; + } + Image::SharedImage* clone() { WindowsBitmapImage* im = new WindowsBitmapImage (format, width, height, false); @@ -241448,6 +241447,14 @@ public: } } + HBITMAP hBitmap; + HGDIOBJ previousBitmap; + BITMAPV4HEADER bitmapInfo; + HDC hdc; + uint8* bitmapData; + int pixelStride, lineStride; + uint8* imageData; + private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsBitmapImage); }; @@ -241472,7 +241479,7 @@ namespace IconConverters SelectObject (dc, bitmap); im = Image (Image::ARGB, bm.bmWidth, bm.bmHeight, true); - Image::BitmapData imageData (im, true); + Image::BitmapData imageData (im, Image::BitmapData::writeOnly); for (int y = bm.bmHeight; --y >= 0;) { @@ -252633,7 +252640,7 @@ public: const ScopedLock sl (imageSwapLock); { - const Image::BitmapData destData (loadingImage, 0, 0, width, height, true); + const Image::BitmapData destData (loadingImage, 0, 0, width, height, Image::BitmapData::writeOnly); for (int i = 0; i < height; ++i) memcpy (destData.getLinePointer ((height - 1) - i), @@ -257100,6 +257107,14 @@ public: return new LowLevelGraphicsSoftwareRenderer (Image (this)); } + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) + { + bitmap.data = imageData + x * pixelStride + y * lineStride; + bitmap.pixelFormat = format; + bitmap.lineStride = lineStride; + bitmap.pixelStride = pixelStride; + } + SharedImage* clone() { jassertfalse; @@ -257137,7 +257152,7 @@ public: const uint32 bShiftL = jmax (0, getShiftNeeded (bMask)); const uint32 bShiftR = jmax (0, -getShiftNeeded (bMask)); - const Image::BitmapData srcData (Image (this), false); + const Image::BitmapData srcData (Image (this), Image::BitmapData::readOnly); for (int y = sy; y < sy + dh; ++y) { @@ -257170,6 +257185,8 @@ private: const int imageDepth; HeapBlock imageDataAllocated; HeapBlock imageData16Bit; + int pixelStride, lineStride; + uint8* imageData; GC gc; @@ -265453,8 +265470,7 @@ public: pixelStride = format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1); lineStride = (pixelStride * jmax (1, width) + 3) & ~3; - imageDataAllocated.allocate (lineStride * jmax (1, height), clearImage); - imageData = imageDataAllocated; + imageData.allocate (lineStride * jmax (1, height), clearImage); CGColorSpaceRef colourSpace = (format == Image::SingleChannel) ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); @@ -265473,6 +265489,14 @@ public: Image::ImageType getType() const { return Image::NativeImage; } LowLevelGraphicsContext* createLowLevelContext(); + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) + { + bitmap.data = imageData + x * pixelStride + y * lineStride; + bitmap.pixelFormat = format; + bitmap.lineStride = lineStride; + bitmap.pixelStride = pixelStride; + } + SharedImage* clone() { CoreGraphicsImage* im = new CoreGraphicsImage (format, width, height, false); @@ -265491,7 +265515,7 @@ public: } else { - const Image::BitmapData srcData (juceImage, false); + const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly); CGDataProviderRef provider; if (mustOutliveSource) @@ -265539,7 +265563,8 @@ public: #endif CGContextRef context; - HeapBlock imageDataAllocated; + HeapBlock imageData; + int pixelStride, lineStride; private: static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) @@ -270172,8 +270197,7 @@ public: pixelStride = format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1); lineStride = (pixelStride * jmax (1, width) + 3) & ~3; - imageDataAllocated.allocate (lineStride * jmax (1, height), clearImage); - imageData = imageDataAllocated; + imageData.allocate (lineStride * jmax (1, height), clearImage); CGColorSpaceRef colourSpace = (format == Image::SingleChannel) ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); @@ -270192,6 +270216,14 @@ public: Image::ImageType getType() const { return Image::NativeImage; } LowLevelGraphicsContext* createLowLevelContext(); + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) + { + bitmap.data = imageData + x * pixelStride + y * lineStride; + bitmap.pixelFormat = format; + bitmap.lineStride = lineStride; + bitmap.pixelStride = pixelStride; + } + SharedImage* clone() { CoreGraphicsImage* im = new CoreGraphicsImage (format, width, height, false); @@ -270210,7 +270242,7 @@ public: } else { - const Image::BitmapData srcData (juceImage, false); + const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly); CGDataProviderRef provider; if (mustOutliveSource) @@ -270258,7 +270290,8 @@ public: #endif CGContextRef context; - HeapBlock imageDataAllocated; + HeapBlock imageData; + int pixelStride, lineStride; private: static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) @@ -278662,6 +278695,8 @@ BEGIN_JUCE_NAMESPACE JAVACLASS (canvasClass, "android/graphics/Canvas") \ JAVACLASS (paintClass, "android/graphics/Paint") \ JAVACLASS (pathClass, "android/graphics/Path") \ + JAVACLASS (bitmapClass, "android/graphics/Bitmap") \ + JAVACLASS (bitmapConfigClass, "android/graphics/Bitmap$Config") \ JAVACLASS (matrixClass, "android/graphics/Matrix") \ JAVACLASS (rectClass, "android/graphics/Rect") \ JAVACLASS (regionClass, "android/graphics/Region") \ @@ -278674,11 +278709,14 @@ BEGIN_JUCE_NAMESPACE #define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ \ STATICMETHOD (activityClass, printToConsole, "printToConsole", "(Ljava/lang/String;)V") \ - METHOD (activityClass, createNewView, "createNewView", "()Lcom/juce/ComponentPeerView;") \ + METHOD (activityClass, createNewView, "createNewView", "(Z)Lcom/juce/ComponentPeerView;") \ METHOD (activityClass, deleteView, "deleteView", "(Lcom/juce/ComponentPeerView;)V") \ METHOD (activityClass, postMessage, "postMessage", "(J)V") \ + METHOD (activityClass, finish, "finish", "()V") \ METHOD (activityClass, getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \ METHOD (activityClass, setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \ + METHOD (activityClass, excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \ + METHOD (activityClass, createPathForGlyph, "createPathForGlyph", "(Landroid/graphics/Paint;C)Ljava/lang/String;") \ \ METHOD (fileClass, fileExists, "exists", "()Z") \ \ @@ -278695,7 +278733,9 @@ BEGIN_JUCE_NAMESPACE METHOD (componentPeerViewClass, isVisible, "isVisible", "()Z") \ METHOD (componentPeerViewClass, hasFocus, "hasFocus", "()Z") \ METHOD (componentPeerViewClass, invalidate, "invalidate", "(IIII)V") \ + METHOD (componentPeerViewClass, containsPoint, "containsPoint", "(II)Z") \ \ + METHOD (canvasClass, canvasBitmapConstructor, "", "(Landroid/graphics/Bitmap;)V") \ METHOD (canvasClass, drawRect, "drawRect", "(FFFFLandroid/graphics/Paint;)V") \ METHOD (canvasClass, translate, "translate", "(FF)V") \ METHOD (canvasClass, clipPath, "clipPath", "(Landroid/graphics/Path;)Z") \ @@ -278703,6 +278743,7 @@ BEGIN_JUCE_NAMESPACE METHOD (canvasClass, clipRegion, "clipRegion", "(Landroid/graphics/Region;)Z") \ METHOD (canvasClass, concat, "concat", "(Landroid/graphics/Matrix;)V") \ METHOD (canvasClass, drawBitmap, "drawBitmap", "(Landroid/graphics/Bitmap;Landroid/graphics/Matrix;Landroid/graphics/Paint;)V") \ + METHOD (canvasClass, drawMemoryBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \ METHOD (canvasClass, drawLine, "drawLine", "(FFFFLandroid/graphics/Paint;)V") \ METHOD (canvasClass, drawPath, "drawPath", "(Landroid/graphics/Path;Landroid/graphics/Paint;)V") \ METHOD (canvasClass, drawText, "drawText", "(Ljava/lang/String;FFLandroid/graphics/Paint;)V") \ @@ -278715,13 +278756,13 @@ BEGIN_JUCE_NAMESPACE \ METHOD (paintClass, paintClassConstructor, "", "(I)V") \ METHOD (paintClass, setColor, "setColor", "(I)V") \ + METHOD (paintClass, setAlpha, "setAlpha", "(I)V") \ METHOD (paintClass, setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \ METHOD (paintClass, setTypeface, "setTypeface", "(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;") \ METHOD (paintClass, ascent, "ascent", "()F") \ METHOD (paintClass, descent, "descent", "()F") \ METHOD (paintClass, setTextSize, "setTextSize", "(F)V") \ METHOD (paintClass, getTextWidths, "getTextWidths", "(Ljava/lang/String;[F)I") \ - METHOD (paintClass, getTextPath, "getTextPath", "(Ljava/lang/String;IIFFLandroid/graphics/Path;)V") \ \ METHOD (shaderClass, setLocalMatrix, "setLocalMatrix", "(Landroid/graphics/Matrix;)V") \ STATICFIELD (shaderTileModeClass, clampMode, "CLAMP", "Landroid/graphics/Shader$TileMode;") \ @@ -278732,6 +278773,13 @@ BEGIN_JUCE_NAMESPACE METHOD (pathClass, quadTo, "quadTo", "(FFFF)V") \ METHOD (pathClass, cubicTo, "cubicTo", "(FFFFFF)V") \ METHOD (pathClass, closePath, "close", "()V") \ +\ + STATICMETHOD (bitmapClass, createBitmap, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;") \ + STATICFIELD (bitmapConfigClass, ARGB_8888, "ARGB_8888", "Landroid/graphics/Bitmap$Config;") \ + METHOD (bitmapClass, bitmapCopy, "copy", "(Landroid/graphics/Bitmap$Config;Z)Landroid/graphics/Bitmap;") \ + METHOD (bitmapClass, getPixels, "getPixels", "([IIIIIII)V") \ + METHOD (bitmapClass, setPixels, "setPixels", "([IIIIIII)V") \ + METHOD (bitmapClass, recycle, "recycle", "()V") \ \ METHOD (matrixClass, matrixClassConstructor, "", "()V") \ METHOD (matrixClass, setValues, "setValues", "([F)V") \ @@ -278869,7 +278917,10 @@ public: inline void clear() { if (obj != 0) + { getEnv()->DeleteGlobalRef (obj); + obj = 0; + } } inline GlobalRef& operator= (const GlobalRef& other) @@ -280618,43 +280669,29 @@ InputStream* URL::createNativeStream (const String& address, bool isPost, const // compiled on its own). #if JUCE_INCLUDED_FILE -void MessageManager::doPlatformSpecificInitialisation() -{ - -} - -void MessageManager::doPlatformSpecificShutdown() -{ - -} +void MessageManager::doPlatformSpecificInitialisation() {} +void MessageManager::doPlatformSpecificShutdown() {} bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages) { - // TODO - - /* - The idea here is that this will check the system message queue, pull off a - message if there is one, deliver it, and return true if a message was delivered. - If the queue's empty, return false. - - If the message is one of our special ones (i.e. a Message object being delivered, - this must call MessageManager::getInstance()->deliverMessage() to deliver it - - */ + Logger::outputDebugString ("*** Modal loops are not possible in Android!! Exiting..."); + exit (1); return true; } bool juce_postMessageToSystemQueue (Message* message) { + message->incReferenceCount(); getEnv()->CallVoidMethod (android.activity, android.postMessage, (jlong) (pointer_sized_uint) message); return true; } JUCE_JNI_CALLBACK (JuceAppActivity, deliverMessage, void, (jobject activity, jlong value)) { - Message* m = (Message*) (pointer_sized_uint) value; - MessageManager::getInstance()->deliverMessage ((Message*) (pointer_sized_uint) value); + Message* const message = (Message*) (pointer_sized_uint) value; + MessageManager::getInstance()->deliverMessage (message); + message->decReferenceCount(); } class AsyncFunctionCaller : public AsyncUpdater @@ -280699,6 +280736,33 @@ void MessageManager::broadcastMessage (const String&) { } +void MessageManager::runDispatchLoop() +{ +} + +class QuitCallback : public CallbackMessage +{ +public: + QuitCallback() {} + + void messageCallback() + { + android.activity.callVoidMethod (android.finish); + } +}; + +void MessageManager::stopDispatchLoop() +{ + (new QuitCallback())->post(); + quitMessagePosted = true; +} + +bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) +{ + juce_dispatchNextMessageOnSystemQueue (false); + return false; +} + #endif /*** End of inlined file: juce_android_Messaging.cpp ***/ @@ -280805,8 +280869,14 @@ public: bool getOutlineForGlyph (int glyphNumber, Path& destPath) { - // TODO - return false; + LocalRef s ((jstring) android.activity.callObjectMethod (android.createPathForGlyph, paint.get(), (jchar) glyphNumber)); + + if (s == 0) + return false; + + const String ourString (juceString (s)); + destPath.restoreFromString (ourString); + return ourString.isNotEmpty(); } GlobalRef typeface, paint; @@ -280830,20 +280900,138 @@ const Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) // compiled on its own). #if JUCE_INCLUDED_FILE +class AndroidImage : public Image::SharedImage +{ +public: + + AndroidImage (const int width_, const int height_, const bool clearImage) + : Image::SharedImage (Image::ARGB, width_, height_) + { + JNIEnv* env = getEnv(); + jobject mode = env->GetStaticObjectField (android.bitmapConfigClass, android.ARGB_8888); + bitmap = GlobalRef (env->CallStaticObjectMethod (android.bitmapClass, android.createBitmap, width_, height_, mode)); + env->DeleteLocalRef (mode); + } + + AndroidImage (const int width_, const int height_, const GlobalRef& bitmap_) + : Image::SharedImage (Image::ARGB, width_, height_), + bitmap (bitmap_) + { + } + + ~AndroidImage() + { + bitmap.callVoidMethod (android.recycle); + } + + Image::ImageType getType() const { return Image::NativeImage; } + LowLevelGraphicsContext* createLowLevelContext(); + + void initialiseBitmapData (Image::BitmapData& bm, int x, int y, Image::BitmapData::ReadWriteMode mode) + { + bm.lineStride = width * sizeof (jint); + bm.pixelStride = sizeof (jint); + bm.pixelFormat = Image::ARGB; + bm.dataReleaser = new CopyHandler (*this, bm, x, y, mode); + } + + SharedImage* clone() + { + JNIEnv* env = getEnv(); + jobject mode = env->GetStaticObjectField (android.bitmapConfigClass, android.ARGB_8888); + GlobalRef newCopy (bitmap.callObjectMethod (android.bitmapCopy, mode, true)); + env->DeleteLocalRef (mode); + + return new AndroidImage (width, height, newCopy); + } + + GlobalRef bitmap; + +private: + class CopyHandler : public Image::BitmapData::BitmapDataReleaser + { + public: + CopyHandler (AndroidImage& owner_, Image::BitmapData& bitmapData_, + const int x_, const int y_, const Image::BitmapData::ReadWriteMode mode_) + : owner (owner_), bitmapData (bitmapData_), mode (mode_), x (x_), y (y_) + { + JNIEnv* env = getEnv(); + + intArray = env->NewIntArray (bitmapData.width * bitmapData.height); + + if (mode != Image::BitmapData::writeOnly) + owner_.bitmap.callVoidMethod (android.getPixels, intArray, 0, bitmapData.width, x_, y_, + bitmapData.width, bitmapData.height); + + bitmapData.data = (uint8*) env->GetIntArrayElements (intArray, 0); + + if (mode != Image::BitmapData::writeOnly) + { + for (int yy = 0; yy < bitmapData.height; ++yy) + { + PixelARGB* p = (PixelARGB*) bitmapData.getLinePointer (yy); + + for (int xx = 0; xx < bitmapData.width; ++xx) + p[xx].premultiply(); + } + } + } + + ~CopyHandler() + { + JNIEnv* env = getEnv(); + + if (mode != Image::BitmapData::readOnly) + { + for (int yy = 0; yy < bitmapData.height; ++yy) + { + PixelARGB* p = (PixelARGB*) bitmapData.getLinePointer (yy); + + for (int xx = 0; xx < bitmapData.width; ++xx) + p[xx].unpremultiply(); + } + } + + env->ReleaseIntArrayElements (intArray, (jint*) bitmapData.data, 0); + + if (mode != Image::BitmapData::readOnly) + owner.bitmap.callVoidMethod (android.setPixels, intArray, 0, bitmapData.width, x, y, + bitmapData.width, bitmapData.height); + + env->DeleteLocalRef (intArray); + } + + private: + AndroidImage& owner; + Image::BitmapData& bitmapData; + jintArray intArray; + const Image::BitmapData::ReadWriteMode mode; + const int x, y; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CopyHandler); + }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidImage); +}; + +Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage) +{ + if (format == Image::SingleChannel) + return createSoftwareImage (format, width, height, clearImage); + else + return new AndroidImage (width, height, clearImage); +} + class AndroidLowLevelGraphicsContext : public LowLevelGraphicsContext { public: - AndroidLowLevelGraphicsContext (const GlobalRef& canvas_) + AndroidLowLevelGraphicsContext (jobject canvas_) : canvas (canvas_), currentState (new SavedState()) { setFill (Colours::black); } - ~AndroidLowLevelGraphicsContext() - { - } - bool isVectorDevice() const { return false; } void setOrigin (int x, int y) @@ -280868,11 +281056,19 @@ public: bool clipToRectangleList (const RectangleList& clipRegion) { - return canvas.callBooleanMethod (android.clipRegion, createRegion (getEnv(), clipRegion).get()); + RectangleList excluded (getClipBounds()); + excluded.subtract (clipRegion); + + const int numRects = excluded.getNumRectangles(); + + for (int i = 0; i < numRects; ++i) + excludeClipRectangle (excluded.getRectangle(i)); } void excludeClipRectangle (const Rectangle& r) { + android.activity.callVoidMethod (android.excludeClipRegion, canvas.get(), + (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); } void clipToPath (const Path& path, const AffineTransform& transform) @@ -280882,6 +281078,7 @@ public: void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) { + // TODO xxx } bool clipRegionIntersects (const Rectangle& r) @@ -280916,10 +281113,12 @@ public: void setOpacity (float newOpacity) { + currentState->setAlpha (newOpacity); } void setInterpolationQuality (Graphics::ResamplingQuality quality) { + // TODO xxx } void fillRect (const Rectangle& r, bool replaceExistingContents) @@ -280937,6 +281136,60 @@ public: void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles) { + AndroidImage* androidImage = dynamic_cast (sourceImage.getSharedImage()); + + if (androidImage != 0) + { + JNIEnv* env = getEnv(); + canvas.callVoidMethod (android.drawBitmap, androidImage->bitmap.get(), + createMatrix (env, transform).get(), getImagePaint()); + } + else + { + if (transform.isOnlyTranslation()) + { + JNIEnv* env = getEnv(); + + Image::BitmapData bm (sourceImage, Image::BitmapData::readOnly); + + jintArray imageData = env->NewIntArray (bm.width * bm.height); + jint* dest = env->GetIntArrayElements (imageData, 0); + + if (dest != 0) + { + const uint8* srcLine = bm.getLinePointer (0); + jint* dstLine = dest; + + for (int y = 0; y < bm.height; ++y) + { + switch (bm.pixelFormat) + { + case Image::ARGB: copyPixels (dstLine, (PixelARGB*) srcLine, bm.width, bm.pixelStride); break; + case Image::RGB: copyPixels (dstLine, (PixelRGB*) srcLine, bm.width, bm.pixelStride); break; + case Image::SingleChannel: copyPixels (dstLine, (PixelAlpha*) srcLine, bm.width, bm.pixelStride); break; + default: jassertfalse; break; + } + + srcLine += bm.lineStride; + dstLine += bm.width; + } + + canvas.callVoidMethod (android.drawMemoryBitmap, imageData, 0, bm.width, + transform.getTranslationX(), transform.getTranslationY(), + bm.width, bm.height, true, getImagePaint()); + + env->ReleaseIntArrayElements (imageData, dest, 0); + env->DeleteLocalRef (imageData); + } + } + else + { + saveState(); + addTransform (transform); + drawImage (sourceImage, AffineTransform::identity, fillEntireClipAsTiles); + restoreState(); + } + } } void drawLine (const Line & line) @@ -281012,10 +281265,12 @@ public: void beginTransparencyLayer (float opacity) { + // TODO xxx } void endTransparencyLayer() { + // TODO xxx } class SavedState @@ -281037,6 +281292,12 @@ public: fillType = newType; } + void setAlpha (float alpha) + { + fillNeedsUpdate = true; + fillType.colour = fillType.colour.withAlpha (alpha); + } + jobject getPaint() { if (fillNeedsUpdate) @@ -281096,6 +281357,7 @@ public: tileMode); } + env->DeleteLocalRef (tileMode); env->DeleteLocalRef (coloursArray); env->DeleteLocalRef (positionsArray); @@ -281106,6 +281368,7 @@ public: } else { + } } @@ -281127,11 +281390,22 @@ public: paint.callObjectMethod (android.setTypeface, atf->typeface.get()); paint.callVoidMethod (android.setTextSize, font.getHeight()); } + + fillNeedsUpdate = true; + paint.callVoidMethod (android.setAlpha, (jint) fillType.colour.getAlpha()); } return p; } + jobject getImagePaint() + { + jobject p = getPaint(); + paint.callVoidMethod (android.setAlpha, (jint) fillType.colour.getAlpha()); + fillNeedsUpdate = true; + return p; + } + FillType fillType; Font font; GlobalRef paint; @@ -281144,10 +281418,8 @@ private: ScopedPointer currentState; OwnedArray stateStack; - jobject getCurrentPaint() const - { - return currentState->getPaint(); - } + jobject getCurrentPaint() const { return currentState->getPaint(); } + jobject getImagePaint() const { return currentState->getImagePaint(); } static const LocalRef createPath (JNIEnv* env, const Path& path) { @@ -281221,9 +281493,25 @@ private: return col.getARGB(); } + template + static void copyPixels (jint* const dest, const PixelType* src, const int width, const int pixelStride) throw() + { + for (int x = 0; x < width; ++x) + { + dest[x] = src->getUnpremultipliedARGB(); + src = addBytesToPointer (src, pixelStride); + } + } + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidLowLevelGraphicsContext); }; +LowLevelGraphicsContext* AndroidImage::createLowLevelContext() +{ + jobject canvas = getEnv()->NewObject (android.canvasClass, android.canvasBitmapConstructor, bitmap.get()); + return new AndroidLowLevelGraphicsContext (canvas); +} + #endif /*** End of inlined file: juce_android_GraphicsContext.cpp ***/ @@ -281233,16 +281521,16 @@ private: // compiled on its own). #if JUCE_INCLUDED_FILE -static ModifierKeys currentModifiers; - class AndroidComponentPeer : public ComponentPeer { public: AndroidComponentPeer (Component* const component, const int windowStyleFlags) : ComponentPeer (component, windowStyleFlags), - view (android.activity.callObjectMethod (android.createNewView)) + view (android.activity.callObjectMethod (android.createNewView, component->isOpaque())) { + if (isFocused()) + handleFocusGain(); } ~AndroidComponentPeer() @@ -281293,7 +281581,7 @@ public: const Point getScreenPosition() const { - JNIEnv* const env = getEnv(); + /*JNIEnv* const env = getEnv(); jintArray pos = env->NewIntArray (2); view.callVoidMethod (android.getLocationOnScreen, pos); @@ -281302,7 +281590,10 @@ public: env->GetIntArrayRegion (pos, 0, 2, coords); env->DeleteLocalRef (pos); - return Point (coords[0], coords[1]); + return Point (coords[0], coords[1]);*/ + + return Point (view.callIntMethod (android.getLeft), + view.callIntMethod (android.getTop)); } const Point localToGlobal (const Point& relativePosition) @@ -281343,10 +281634,9 @@ public: bool contains (const Point& position, bool trueIfInAChildWindow) const { - // TODO - return isPositiveAndBelow (position.getX(), component->getWidth()) - && isPositiveAndBelow (position.getY(), component->getHeight()); + && isPositiveAndBelow (position.getY(), component->getHeight()) + && ((! trueIfInAChildWindow) || view.callBooleanMethod (android.containsPoint, position.getX(), position.getY())); } const BorderSize getFrameSize() const @@ -281367,6 +281657,8 @@ public: if (makeActive) grabFocus(); + + handleBroughtToFront(); } void toBehind (ComponentPeer* other) @@ -281376,21 +281668,24 @@ public: void handleMouseDownCallback (float x, float y, int64 time) { + lastMousePos.setXY ((int) x, (int) y); currentModifiers = currentModifiers.withoutMouseButtons(); - handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + handleMouseEvent (0, lastMousePos, currentModifiers, time); currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); - handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + handleMouseEvent (0, lastMousePos, currentModifiers, time); } void handleMouseDragCallback (float x, float y, int64 time) { - handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + lastMousePos.setXY ((int) x, (int) y); + handleMouseEvent (0, lastMousePos, currentModifiers, time); } void handleMouseUpCallback (float x, float y, int64 time) { + lastMousePos.setXY ((int) x, (int) y); currentModifiers = currentModifiers.withoutMouseButtons(); - handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + handleMouseEvent (0, lastMousePos, currentModifiers, time); } bool isFocused() const @@ -281400,7 +281695,15 @@ public: void grabFocus() { - (void) view.callBooleanMethod (android.requestFocus); + view.callBooleanMethod (android.requestFocus); + } + + void handleFocusChangeCallback (bool hasFocus) + { + if (hasFocus) + handleFocusGain(); + else + handleFocusLoss(); } void textInputRequired (const Point& position) @@ -281410,8 +281713,7 @@ public: void handlePaintCallback (JNIEnv* env, jobject canvas) { - GlobalRef canvasRef (canvas); - AndroidLowLevelGraphicsContext g (canvasRef); + AndroidLowLevelGraphicsContext g (canvas); handlePaint (g); } @@ -281444,6 +281746,9 @@ public: return 0; } + static ModifierKeys currentModifiers; + static Point lastMousePos; + private: GlobalRef view; @@ -281451,6 +281756,9 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidComponentPeer); }; +ModifierKeys AndroidComponentPeer::currentModifiers = 0; +Point AndroidComponentPeer::lastMousePos; + #define JUCE_VIEW_CALLBACK(returnType, javaMethodName, params, juceMethodInvocation) \ JUCE_JNI_CALLBACK (ComponentPeerView, javaMethodName, returnType, params) \ { \ @@ -281469,6 +281777,12 @@ JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv*, jobject view, jfloat x, jfl JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), handleMouseUpCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, viewSizeChanged, (JNIEnv*, jobject view), + handleMovedOrResized()) + +JUCE_VIEW_CALLBACK (void, focusChanged, (JNIEnv*, jobject view, jboolean hasFocus), + handleFocusChangeCallback (hasFocus)) + ComponentPeer* Component::createNewPeer (int styleFlags, void*) { return new AndroidComponentPeer (this, styleFlags); @@ -281495,8 +281809,7 @@ void Desktop::createMouseInputSources() const Point MouseInputSource::getCurrentMousePosition() { - // TODO - return Point(); + return AndroidComponentPeer::lastMousePos; } void Desktop::setMousePosition (const Point& newPosition) @@ -281512,12 +281825,12 @@ bool KeyPress::isKeyCurrentlyDown (const int keyCode) void ModifierKeys::updateCurrentModifiers() throw() { - // not needed + currentModifiers = AndroidComponentPeer::currentModifiers; } const ModifierKeys ModifierKeys::getCurrentModifiersRealtime() throw() { - return currentModifiers; + return AndroidComponentPeer::currentModifiers; } bool Process::isForegroundProcess() @@ -281533,11 +281846,6 @@ bool AlertWindow::showNativeDialogBox (const String& title, } -Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage) -{ - return createSoftwareImage (format, width, height, clearImage); -} - void Desktop::setScreenSaverEnabled (const bool isEnabled) { // TODO diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 6a9609a296..5b3edb26b3 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 28 +#define JUCE_BUILDNUMBER 29 /** Current Juce version number. @@ -2371,7 +2371,7 @@ inline Type Atomic::operator++() throw() return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value) : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value); #elif JUCE_ATOMICS_ANDROID - return (Type) __atomic_inc ((volatile int*) &value); + return (Type) (__atomic_inc ((volatile int*) &value) + 1); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, 1); #endif @@ -2387,7 +2387,7 @@ inline Type Atomic::operator--() throw() return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value) : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value); #elif JUCE_ATOMICS_ANDROID - return (Type) __atomic_dec ((volatile int*) &value); + return (Type) (__atomic_dec ((volatile int*) &value) - 1); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, -1); #endif @@ -26479,7 +26479,9 @@ public: { } - forcedinline uint32 getARGB() const throw() { return argb; } + forcedinline uint32 getARGB() const throw() { return argb; } + forcedinline uint32 getUnpremultipliedARGB() const throw() { PixelARGB p (argb); p.unpremultiply(); return p.getARGB(); } + forcedinline uint32 getRB() const throw() { return 0x00ff00ff & argb; } forcedinline uint32 getAG() const throw() { return 0x00ff00ff & (argb >> 8); } @@ -26710,7 +26712,9 @@ public: b = (uint8) (argb); } - forcedinline uint32 getARGB() const throw() { return 0xff000000 | b | (g << 8) | (r << 16); } + forcedinline uint32 getARGB() const throw() { return 0xff000000 | b | (g << 8) | (r << 16); } + forcedinline uint32 getUnpremultipliedARGB() const throw() { return getARGB(); } + forcedinline uint32 getRB() const throw() { return b | (uint32) (r << 16); } forcedinline uint32 getAG() const throw() { return 0xff0000 | g; } @@ -26872,7 +26876,9 @@ public: a = (uint8) (argb >> 24); } - forcedinline uint32 getARGB() const throw() { return (((uint32) a) << 24) | (((uint32) a) << 16) | (((uint32) a) << 8) | a; } + forcedinline uint32 getARGB() const throw() { return (((uint32) a) << 24) | (((uint32) a) << 16) | (((uint32) a) << 8) | a; } + forcedinline uint32 getUnpremultipliedARGB() const throw() { return (((uint32) a) << 24) | 0xffffff; } + forcedinline uint32 getRB() const throw() { return (((uint32) a) << 16) | a; } forcedinline uint32 getAG() const throw() { return (((uint32) a) << 16) | a; } @@ -28625,9 +28631,16 @@ public: class BitmapData { public: - BitmapData (Image& image, int x, int y, int w, int h, bool needsToBeWritable); + enum ReadWriteMode + { + readOnly, + writeOnly, + readWrite + }; + + BitmapData (Image& image, int x, int y, int w, int h, ReadWriteMode mode); BitmapData (const Image& image, int x, int y, int w, int h); - BitmapData (const Image& image, bool needsToBeWritable); + BitmapData (const Image& image, ReadWriteMode mode); ~BitmapData(); /** Returns a pointer to the start of a line in the image. @@ -28655,9 +28668,20 @@ public: void setPixelColour (int x, int y, const Colour& colour) const throw(); uint8* data; - const PixelFormat pixelFormat; + PixelFormat pixelFormat; int lineStride, pixelStride, width, height; + /** Used internally by custom image types to manage pixel data lifetime. */ + class BitmapDataReleaser + { + protected: + BitmapDataReleaser() {} + public: + virtual ~BitmapDataReleaser() {} + }; + + ScopedPointer dataReleaser; + private: JUCE_DECLARE_NON_COPYABLE (BitmapData); }; @@ -28717,6 +28741,7 @@ public: virtual LowLevelGraphicsContext* createLowLevelContext() = 0; virtual SharedImage* clone() = 0; virtual ImageType getType() const = 0; + virtual void initialiseBitmapData (BitmapData& bitmapData, int x, int y, BitmapData::ReadWriteMode mode) = 0; static SharedImage* createNativeImage (PixelFormat format, int width, int height, bool clearImage); static SharedImage* createSoftwareImage (PixelFormat format, int width, int height, bool clearImage); @@ -28724,17 +28749,12 @@ public: const PixelFormat getPixelFormat() const throw() { return format; } int getWidth() const throw() { return width; } int getHeight() const throw() { return height; } - int getPixelStride() const throw() { return pixelStride; } - int getLineStride() const throw() { return lineStride; } - uint8* getPixelData (int x, int y) const throw(); protected: friend class Image; friend class BitmapData; const PixelFormat format; const int width, height; - int pixelStride, lineStride; - uint8* imageData; NamedValueSet userData; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedImage); @@ -28938,7 +28958,7 @@ public: const Path toPath() const; /** An iterator for accessing all the rectangles in a RectangleList. */ - class Iterator + class JUCE_API Iterator { public: @@ -38944,7 +38964,7 @@ public: @see MidiBuffer */ - class Iterator + class JUCE_API Iterator { public: @@ -50326,7 +50346,7 @@ public: @see CodeDocument, SyntaxAnalyser */ - class Iterator + class JUCE_API Iterator { public: Iterator (CodeDocument* document); @@ -66216,11 +66236,6 @@ private: #pragma pack (pop) #endif -#if defined (JUCE_DLL) && ! (JUCE_AMALGAMATED_TEMPLATE || defined (JUCE_DLL_BUILD)) - #undef JUCE_LEAK_DETECTOR - #define JUCE_LEAK_DETECTOR(OwnerClass) -#endif - END_JUCE_NAMESPACE #ifndef DONT_SET_USING_JUCE_NAMESPACE diff --git a/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp b/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp index 0d03636574..f3cb02dffe 100644 --- a/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp +++ b/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp @@ -291,7 +291,7 @@ public: startSampleInFile += samplesReceived; numSamples -= samplesReceived; - if ((outFlags & kQTMovieAudioExtractionComplete) != 0 && numSamples > 0) + if (((outFlags & kQTMovieAudioExtractionComplete) != 0 || samplesReceived == 0) && numSamples > 0) { for (int j = numDestChannels; --j >= 0;) if (destSamples[j] != 0) diff --git a/src/audio/midi/juce_MidiBuffer.h b/src/audio/midi/juce_MidiBuffer.h index be0158925e..a683659b16 100644 --- a/src/audio/midi/juce_MidiBuffer.h +++ b/src/audio/midi/juce_MidiBuffer.h @@ -170,7 +170,7 @@ public: @see MidiBuffer */ - class Iterator + class JUCE_API Iterator { public: //============================================================================== diff --git a/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm b/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm index 755f29a8c2..73c72e139e 100644 --- a/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm +++ b/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm @@ -265,6 +265,8 @@ public: void setStateInformation (const void* data, int sizeInBytes); void setCurrentProgramStateInformation (const void* data, int sizeInBytes); + void refreshParameterListFromPlugin(); + private: //============================================================================== friend class AudioUnitPluginWindowCarbon; @@ -287,7 +289,6 @@ private: //============================================================================== bool getComponentDescFromFile (const String& fileOrIdentifier); void setPluginCallbacks(); - void getParameterListFromPlugin(); //============================================================================== OSStatus renderGetInput (AudioUnitRenderActionFlags* ioActionFlags, @@ -535,7 +536,7 @@ bool AudioUnitPluginInstance::getComponentDescFromFile (const String& fileOrIden //============================================================================== void AudioUnitPluginInstance::initialise() { - getParameterListFromPlugin(); + refreshParameterListFromPlugin(); setPluginCallbacks(); int numIns, numOuts; @@ -544,7 +545,7 @@ void AudioUnitPluginInstance::initialise() setLatencySamples (0); } -void AudioUnitPluginInstance::getParameterListFromPlugin() +void AudioUnitPluginInstance::refreshParameterListFromPlugin() { parameterIds.clear(); @@ -559,7 +560,7 @@ void AudioUnitPluginInstance::getParameterListFromPlugin() parameterIds.insertMultiple (0, 0, paramListSize / sizeof (int)); AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, - 0, ¶meterIds.getReference(0), ¶mListSize); + 0, parameterIds.getRawDataPointer(), ¶mListSize); } } } diff --git a/src/core/juce_Initialisation.cpp b/src/core/juce_Initialisation.cpp index 6e7ec7d890..dd0949f736 100644 --- a/src/core/juce_Initialisation.cpp +++ b/src/core/juce_Initialisation.cpp @@ -231,7 +231,9 @@ public: a.memoryBarrier(); a -= (Type) 5; test.expect (a.get() == (Type) 20); - ++a; ++a; --a; + test.expect (++a == (Type) 21); + ++a; + test.expect (--a == (Type) 21); test.expect (a.get() == (Type) 21); a.memoryBarrier(); diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index 9cfe808816..bd6c9f52a3 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 28 +#define JUCE_BUILDNUMBER 29 /** Current Juce version number. diff --git a/src/events/juce_MessageManager.cpp b/src/events/juce_MessageManager.cpp index 9f2798806f..3ee06c1434 100644 --- a/src/events/juce_MessageManager.cpp +++ b/src/events/juce_MessageManager.cpp @@ -127,7 +127,7 @@ void MessageManager::deliverMessage (Message* const message) } //============================================================================== -#if ! (JUCE_MAC || JUCE_IOS) +#if ! (JUCE_MAC || JUCE_IOS || JUCE_ANDROID) void MessageManager::runDispatchLoop() { jassert (isThisTheMessageThread()); // must only be called by the message thread diff --git a/src/gui/components/code_editor/juce_CodeDocument.h b/src/gui/components/code_editor/juce_CodeDocument.h index 3d502433da..14ff23d8e5 100644 --- a/src/gui/components/code_editor/juce_CodeDocument.h +++ b/src/gui/components/code_editor/juce_CodeDocument.h @@ -336,7 +336,7 @@ public: @see CodeDocument, SyntaxAnalyser */ - class Iterator + class JUCE_API Iterator { public: Iterator (CodeDocument* document); diff --git a/src/gui/components/special/juce_ColourSelector.cpp b/src/gui/components/special/juce_ColourSelector.cpp index 24bd770211..f1b73921e1 100644 --- a/src/gui/components/special/juce_ColourSelector.cpp +++ b/src/gui/components/special/juce_ColourSelector.cpp @@ -103,7 +103,7 @@ public: const int height = getHeight() / 2; colours = Image (Image::RGB, width, height, false); - Image::BitmapData pixels (colours, true); + Image::BitmapData pixels (colours, Image::BitmapData::writeOnly); for (int y = 0; y < height; ++y) { diff --git a/src/gui/graphics/colour/juce_PixelFormats.h b/src/gui/graphics/colour/juce_PixelFormats.h index 089646ff09..fe8df5b048 100644 --- a/src/gui/graphics/colour/juce_PixelFormats.h +++ b/src/gui/graphics/colour/juce_PixelFormats.h @@ -42,6 +42,7 @@ class PixelRGB; class PixelAlpha; +//============================================================================== /** Represents a 32-bit ARGB pixel with premultiplied alpha, and can perform compositing operations with it. @@ -64,7 +65,9 @@ public: { } - forcedinline uint32 getARGB() const throw() { return argb; } + forcedinline uint32 getARGB() const throw() { return argb; } + forcedinline uint32 getUnpremultipliedARGB() const throw() { PixelARGB p (argb); p.unpremultiply(); return p.getARGB(); } + forcedinline uint32 getRB() const throw() { return 0x00ff00ff & argb; } forcedinline uint32 getAG() const throw() { return 0x00ff00ff & (argb >> 8); } @@ -300,7 +303,9 @@ public: b = (uint8) (argb); } - forcedinline uint32 getARGB() const throw() { return 0xff000000 | b | (g << 8) | (r << 16); } + forcedinline uint32 getARGB() const throw() { return 0xff000000 | b | (g << 8) | (r << 16); } + forcedinline uint32 getUnpremultipliedARGB() const throw() { return getARGB(); } + forcedinline uint32 getRB() const throw() { return b | (uint32) (r << 16); } forcedinline uint32 getAG() const throw() { return 0xff0000 | g; } @@ -464,7 +469,9 @@ public: a = (uint8) (argb >> 24); } - forcedinline uint32 getARGB() const throw() { return (((uint32) a) << 24) | (((uint32) a) << 16) | (((uint32) a) << 8) | a; } + forcedinline uint32 getARGB() const throw() { return (((uint32) a) << 24) | (((uint32) a) << 16) | (((uint32) a) << 8) | a; } + forcedinline uint32 getUnpremultipliedARGB() const throw() { return (((uint32) a) << 24) | 0xffffff; } + forcedinline uint32 getRB() const throw() { return (((uint32) a) << 16) | a; } forcedinline uint32 getAG() const throw() { return (((uint32) a) << 16) | a; } diff --git a/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp b/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp index a8b6a1b25e..38e5a88598 100644 --- a/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp +++ b/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp @@ -1273,7 +1273,7 @@ public: const Ptr clipToImageAlpha (const Image& image, const AffineTransform& transform, const bool betterQuality) { - const Image::BitmapData srcData (image, false); + const Image::BitmapData srcData (image, Image::BitmapData::readOnly); if (transform.isOnlyTranslation()) { @@ -2010,7 +2010,7 @@ public: { if (fillType.isColour()) { - Image::BitmapData destData (image, true); + Image::BitmapData destData (image, Image::BitmapData::readWrite); clip->fillRectWithColour (destData, r.translated (xOffset, yOffset), fillType.colour.getPixelARGB(), replaceContents); } else @@ -2039,7 +2039,7 @@ public: { if (fillType.isColour()) { - Image::BitmapData destData (image, true); + Image::BitmapData destData (image, Image::BitmapData::readWrite); clip->fillRectWithColour (destData, r.translated ((float) xOffset, (float) yOffset), fillType.colour.getPixelARGB()); } else @@ -2087,7 +2087,7 @@ public: if (shapeToFill != 0) { - Image::BitmapData destData (image, true); + Image::BitmapData destData (image, Image::BitmapData::readWrite); if (fillType.isGradient()) { @@ -2125,8 +2125,8 @@ public: { const AffineTransform transform (getTransformWith (t)); - const Image::BitmapData destData (image, true); - const Image::BitmapData srcData (sourceImage, false); + const Image::BitmapData destData (image, Image::BitmapData::readWrite); + const Image::BitmapData srcData (sourceImage, Image::BitmapData::readOnly); const int alpha = fillType.colour.getAlpha(); const bool betterQuality = (interpolationQuality != Graphics::lowResamplingQuality); diff --git a/src/gui/graphics/effects/juce_DropShadowEffect.cpp b/src/gui/graphics/effects/juce_DropShadowEffect.cpp index eade3aa1c2..c16da1d4b8 100644 --- a/src/gui/graphics/effects/juce_DropShadowEffect.cpp +++ b/src/gui/graphics/effects/juce_DropShadowEffect.cpp @@ -66,38 +66,40 @@ void DropShadowEffect::applyEffect (Image& image, Graphics& g, float alpha) Image shadowImage (Image::SingleChannel, w, h, false); - const Image::BitmapData srcData (image, false); - const Image::BitmapData destData (shadowImage, true); - - const int filter = roundToInt (63.0f / radius); - const int radiusMinus1 = roundToInt ((radius - 1.0f) * 63.0f); - - for (int x = w; --x >= 0;) { - int shadowAlpha = 0; + const Image::BitmapData srcData (image, Image::BitmapData::readOnly); + const Image::BitmapData destData (shadowImage, Image::BitmapData::readWrite); - const PixelARGB* src = ((const PixelARGB*) srcData.data) + x; - uint8* shadowPix = destData.data + x; - - for (int y = h; --y >= 0;) - { - shadowAlpha = ((shadowAlpha * radiusMinus1 + (src->getAlpha() << 6)) * filter) >> 12; - - *shadowPix = (uint8) shadowAlpha; - src = (const PixelARGB*) (((const uint8*) src) + srcData.lineStride); - shadowPix += destData.lineStride; - } - } - - for (int y = h; --y >= 0;) - { - int shadowAlpha = 0; - uint8* shadowPix = destData.getLinePointer (y); + const int filter = roundToInt (63.0f / radius); + const int radiusMinus1 = roundToInt ((radius - 1.0f) * 63.0f); for (int x = w; --x >= 0;) { - shadowAlpha = ((shadowAlpha * radiusMinus1 + (*shadowPix << 6)) * filter) >> 12; - *shadowPix++ = (uint8) shadowAlpha; + int shadowAlpha = 0; + + const PixelARGB* src = ((const PixelARGB*) srcData.data) + x; + uint8* shadowPix = destData.data + x; + + for (int y = h; --y >= 0;) + { + shadowAlpha = ((shadowAlpha * radiusMinus1 + (src->getAlpha() << 6)) * filter) >> 12; + + *shadowPix = (uint8) shadowAlpha; + src = addBytesToPointer (src, srcData.lineStride); + shadowPix += destData.lineStride; + } + } + + for (int y = h; --y >= 0;) + { + int shadowAlpha = 0; + uint8* shadowPix = destData.getLinePointer (y); + + for (int x = w; --x >= 0;) + { + shadowAlpha = ((shadowAlpha * radiusMinus1 + (*shadowPix << 6)) * filter) >> 12; + *shadowPix++ = (uint8) shadowAlpha; + } } } diff --git a/src/gui/graphics/geometry/juce_RectangleList.h b/src/gui/graphics/geometry/juce_RectangleList.h index b61bb785af..a2b304e4b7 100644 --- a/src/gui/graphics/geometry/juce_RectangleList.h +++ b/src/gui/graphics/geometry/juce_RectangleList.h @@ -214,7 +214,7 @@ public: //============================================================================== /** An iterator for accessing all the rectangles in a RectangleList. */ - class Iterator + class JUCE_API Iterator { public: //============================================================================== diff --git a/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp b/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp index 6d70b9f9bd..35d13a22a1 100644 --- a/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp +++ b/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp @@ -400,7 +400,7 @@ private: int index; int xpos = 0, ypos = 0, pass = 0; - const Image::BitmapData destData (image, true); + const Image::BitmapData destData (image, Image::BitmapData::writeOnly); uint8* p = destData.data; const bool hasAlpha = image.hasAlphaChannel(); diff --git a/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp b/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp index 96b0eb82ce..ec2eb8406f 100644 --- a/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp +++ b/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp @@ -307,7 +307,7 @@ const Image JPEGImageFormat::decodeImage (InputStream& in) image.getProperties()->set ("originalImageHadAlpha", false); const bool hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect) - const Image::BitmapData destData (image, true); + const Image::BitmapData destData (image, Image::BitmapData::writeOnly); for (int y = 0; y < height; ++y) { @@ -411,7 +411,7 @@ bool JPEGImageFormat::writeImageToStream (const Image& image, OutputStream& out) JSAMPARRAY buffer = (*jpegCompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegCompStruct, JPOOL_IMAGE, strideBytes, 1); - const Image::BitmapData srcData (image, false); + const Image::BitmapData srcData (image, Image::BitmapData::readOnly); while (jpegCompStruct.next_scanline < jpegCompStruct.image_height) { diff --git a/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp b/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp index 18c1955d4e..7cfec979dc 100644 --- a/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp +++ b/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp @@ -234,7 +234,7 @@ const Image PNGImageFormat::decodeImage (InputStream& in) image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel()); hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect) - const Image::BitmapData destData (image, true); + const Image::BitmapData destData (image, Image::BitmapData::writeOnly); uint8* srcRow = tempBuffer; uint8* destRow = destData.data; @@ -313,7 +313,7 @@ bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out) png_set_shift (pngWriteStruct, &sig_bit); png_set_packing (pngWriteStruct); - const Image::BitmapData srcData (image, false); + const Image::BitmapData srcData (image, Image::BitmapData::readOnly); for (int y = 0; y < height; ++y) { diff --git a/src/gui/graphics/imaging/juce_Image.cpp b/src/gui/graphics/imaging/juce_Image.cpp index b6e82e2a33..8fbdf2fccb 100644 --- a/src/gui/graphics/imaging/juce_Image.cpp +++ b/src/gui/graphics/imaging/juce_Image.cpp @@ -46,23 +46,16 @@ Image::SharedImage::~SharedImage() { } -inline uint8* Image::SharedImage::getPixelData (const int x, const int y) const throw() -{ - return imageData + lineStride * y + pixelStride * x; -} - //============================================================================== class SoftwareSharedImage : public Image::SharedImage { public: SoftwareSharedImage (const Image::PixelFormat format_, const int width_, const int height_, const bool clearImage) - : Image::SharedImage (format_, width_, height_) + : Image::SharedImage (format_, width_, height_), + pixelStride (format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1)), + lineStride ((pixelStride * jmax (1, width_) + 3) & ~3) { - pixelStride = format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1); - lineStride = (pixelStride * jmax (1, width) + 3) & ~3; - - imageDataAllocated.allocate (lineStride * jmax (1, height), clearImage); - imageData = imageDataAllocated; + imageData.allocate (lineStride * jmax (1, height_), clearImage); } Image::ImageType getType() const @@ -75,6 +68,14 @@ public: return new LowLevelGraphicsSoftwareRenderer (Image (this)); } + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) + { + bitmap.data = imageData + x * pixelStride + y * lineStride; + bitmap.pixelFormat = format; + bitmap.lineStride = lineStride; + bitmap.pixelStride = pixelStride; + } + Image::SharedImage* clone() { SoftwareSharedImage* s = new SoftwareSharedImage (format, width, height, false); @@ -83,7 +84,8 @@ public: } private: - HeapBlock imageDataAllocated; + HeapBlock imageData; + const int pixelStride, lineStride; JUCE_LEAK_DETECTOR (SoftwareSharedImage); }; @@ -101,9 +103,6 @@ public: : Image::SharedImage (image_->getPixelFormat(), area_.getWidth(), area_.getHeight()), image (image_), area (area_) { - pixelStride = image_->getPixelStride(); - lineStride = image_->getLineStride(); - imageData = image_->getPixelData (area_.getX(), area_.getY()); } Image::ImageType getType() const @@ -119,6 +118,11 @@ public: return g; } + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) + { + image->initialiseBitmapData (bitmap, x + area.getX(), y + area.getY(), mode); + } + Image::SharedImage* clone() { return new SubsectionSharedImage (image->clone(), area); @@ -220,7 +224,7 @@ const Image Image::convertedToFormat (PixelFormat newFormat) const } else { - const BitmapData destData (newImage, 0, 0, w, h, true); + const BitmapData destData (newImage, 0, 0, w, h, BitmapData::writeOnly); const BitmapData srcData (*this, 0, 0, w, h); for (int y = 0; y < h; ++y) @@ -254,37 +258,39 @@ NamedValueSet* Image::getProperties() const } //============================================================================== -Image::BitmapData::BitmapData (Image& image, const int x, const int y, const int w, const int h, const bool /*makeWritable*/) - : data (image.image == 0 ? 0 : image.image->getPixelData (x, y)), - pixelFormat (image.getFormat()), - lineStride (image.image == 0 ? 0 : image.image->lineStride), - pixelStride (image.image == 0 ? 0 : image.image->pixelStride), - width (w), +Image::BitmapData::BitmapData (Image& image, const int x, const int y, const int w, const int h, BitmapData::ReadWriteMode mode) + : width (w), height (h) { - jassert (data != 0); + // The BitmapData class must be given a valid image, and a valid rectangle within it! + jassert (image.image != 0); jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= image.getWidth() && y + h <= image.getHeight()); + + image.image->initialiseBitmapData (*this, x, y, mode); + jassert (data != 0 && pixelStride > 0 && lineStride != 0); } Image::BitmapData::BitmapData (const Image& image, const int x, const int y, const int w, const int h) - : data (image.image == 0 ? 0 : image.image->getPixelData (x, y)), - pixelFormat (image.getFormat()), - lineStride (image.image == 0 ? 0 : image.image->lineStride), - pixelStride (image.image == 0 ? 0 : image.image->pixelStride), - width (w), + : width (w), height (h) { + // The BitmapData class must be given a valid image, and a valid rectangle within it! + jassert (image.image != 0); jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= image.getWidth() && y + h <= image.getHeight()); + + image.image->initialiseBitmapData (*this, x, y, readOnly); + jassert (data != 0 && pixelStride > 0 && lineStride != 0); } -Image::BitmapData::BitmapData (const Image& image, bool /*needsToBeWritable*/) - : data (image.image == 0 ? 0 : image.image->imageData), - pixelFormat (image.getFormat()), - lineStride (image.image == 0 ? 0 : image.image->lineStride), - pixelStride (image.image == 0 ? 0 : image.image->pixelStride), - width (image.getWidth()), +Image::BitmapData::BitmapData (const Image& image, BitmapData::ReadWriteMode mode) + : width (image.getWidth()), height (image.getHeight()) { + // The BitmapData class must be given a valid image! + jassert (image.image != 0); + + image.image->initialiseBitmapData (*this, 0, 0, mode); + jassert (data != 0 && pixelStride > 0 && lineStride != 0); } Image::BitmapData::~BitmapData() @@ -299,21 +305,10 @@ const Colour Image::BitmapData::getPixelColour (const int x, const int y) const switch (pixelFormat) { - case Image::ARGB: - { - PixelARGB p (*(const PixelARGB*) pixel); - p.unpremultiply(); - return Colour (p.getARGB()); - } - case Image::RGB: - return Colour (((const PixelRGB*) pixel)->getARGB()); - - case Image::SingleChannel: - return Colour ((uint8) 0, (uint8) 0, (uint8) 0, *pixel); - - default: - jassertfalse; - break; + case Image::ARGB: return Colour (((const PixelARGB*) pixel)->getUnpremultipliedARGB()); + case Image::RGB: return Colour (((const PixelRGB*) pixel)->getUnpremultipliedARGB()); + case Image::SingleChannel: return Colour (((const PixelAlpha*) pixel)->getUnpremultipliedARGB()); + default: jassertfalse; break; } return Colour(); @@ -342,7 +337,7 @@ void Image::setPixelData (int x, int y, int w, int h, if (Rectangle::intersectRectangles (x, y, w, h, 0, 0, getWidth(), getHeight())) { - const BitmapData dest (*this, x, y, w, h, true); + const BitmapData dest (*this, x, y, w, h, BitmapData::writeOnly); for (int i = 0; i < h; ++i) { @@ -362,7 +357,7 @@ void Image::clear (const Rectangle& area, const Colour& colourToClearTo) { const PixelARGB col (colourToClearTo.getPixelARGB()); - const BitmapData destData (*this, clipped.getX(), clipped.getY(), clipped.getWidth(), clipped.getHeight(), true); + const BitmapData destData (*this, clipped.getX(), clipped.getY(), clipped.getWidth(), clipped.getHeight(), BitmapData::writeOnly); uint8* dest = destData.data; int dh = clipped.getHeight(); @@ -415,7 +410,7 @@ void Image::setPixelAt (const int x, const int y, const Colour& colour) { if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight())) { - const BitmapData destData (*this, x, y, 1, 1, true); + const BitmapData destData (*this, x, y, 1, 1, BitmapData::writeOnly); destData.setPixelColour (0, 0, colour); } } @@ -425,7 +420,7 @@ void Image::multiplyAlphaAt (const int x, const int y, const float multiplier) if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight()) && hasAlphaChannel()) { - const BitmapData destData (*this, x, y, 1, 1, true); + const BitmapData destData (*this, x, y, 1, 1, BitmapData::readWrite); if (isARGB()) ((PixelARGB*) destData.data)->multiplyAlpha (multiplier); @@ -438,7 +433,7 @@ void Image::multiplyAllAlphas (const float amountToMultiplyBy) { if (hasAlphaChannel()) { - const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), true); + const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite); if (isARGB()) { @@ -477,7 +472,7 @@ void Image::desaturate() { if (isARGB() || isRGB()) { - const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), true); + const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite); if (isARGB()) { @@ -601,7 +596,7 @@ void Image::moveImageSection (int dx, int dy, const int maxX = jmax (dx, sx) + w; const int maxY = jmax (dy, sy) + h; - const BitmapData destData (*this, minX, minY, maxX - minX, maxY - minY, true); + const BitmapData destData (*this, minX, minY, maxX - minX, maxY - minY, BitmapData::readWrite); uint8* dst = destData.getPixelPointer (dx - minX, dy - minY); const uint8* src = destData.getPixelPointer (sx - minX, sy - minY); diff --git a/src/gui/graphics/imaging/juce_Image.h b/src/gui/graphics/imaging/juce_Image.h index c11f0be85b..cb2592224d 100644 --- a/src/gui/graphics/imaging/juce_Image.h +++ b/src/gui/graphics/imaging/juce_Image.h @@ -292,9 +292,16 @@ public: class BitmapData { public: - BitmapData (Image& image, int x, int y, int w, int h, bool needsToBeWritable); + enum ReadWriteMode + { + readOnly, + writeOnly, + readWrite + }; + + BitmapData (Image& image, int x, int y, int w, int h, ReadWriteMode mode); BitmapData (const Image& image, int x, int y, int w, int h); - BitmapData (const Image& image, bool needsToBeWritable); + BitmapData (const Image& image, ReadWriteMode mode); ~BitmapData(); /** Returns a pointer to the start of a line in the image. @@ -322,9 +329,21 @@ public: void setPixelColour (int x, int y, const Colour& colour) const throw(); uint8* data; - const PixelFormat pixelFormat; + PixelFormat pixelFormat; int lineStride, pixelStride, width, height; + //============================================================================== + /** Used internally by custom image types to manage pixel data lifetime. */ + class BitmapDataReleaser + { + protected: + BitmapDataReleaser() {} + public: + virtual ~BitmapDataReleaser() {} + }; + + ScopedPointer dataReleaser; + private: JUCE_DECLARE_NON_COPYABLE (BitmapData); }; @@ -387,6 +406,7 @@ public: virtual LowLevelGraphicsContext* createLowLevelContext() = 0; virtual SharedImage* clone() = 0; virtual ImageType getType() const = 0; + virtual void initialiseBitmapData (BitmapData& bitmapData, int x, int y, BitmapData::ReadWriteMode mode) = 0; static SharedImage* createNativeImage (PixelFormat format, int width, int height, bool clearImage); static SharedImage* createSoftwareImage (PixelFormat format, int width, int height, bool clearImage); @@ -394,17 +414,12 @@ public: const PixelFormat getPixelFormat() const throw() { return format; } int getWidth() const throw() { return width; } int getHeight() const throw() { return height; } - int getPixelStride() const throw() { return pixelStride; } - int getLineStride() const throw() { return lineStride; } - uint8* getPixelData (int x, int y) const throw(); protected: friend class Image; friend class BitmapData; const PixelFormat format; const int width, height; - int pixelStride, lineStride; - uint8* imageData; NamedValueSet userData; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedImage); diff --git a/src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp b/src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp index 3ac7267d5b..efa9608fc1 100644 --- a/src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp +++ b/src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp @@ -134,10 +134,11 @@ void ImageConvolutionKernel::applyToImage (Image& destImage, const int right = area.getRight(); const int bottom = area.getBottom(); - const Image::BitmapData destData (destImage, area.getX(), area.getY(), area.getWidth(), area.getHeight(), true); + const Image::BitmapData destData (destImage, area.getX(), area.getY(), area.getWidth(), area.getHeight(), + Image::BitmapData::writeOnly); uint8* line = destData.data; - const Image::BitmapData srcData (sourceImage, false); + const Image::BitmapData srcData (sourceImage, Image::BitmapData::readOnly); if (destData.pixelStride == 4) { diff --git a/src/memory/juce_Atomic.h b/src/memory/juce_Atomic.h index bb927c2bbb..654a48c6ff 100644 --- a/src/memory/juce_Atomic.h +++ b/src/memory/juce_Atomic.h @@ -310,7 +310,7 @@ inline Type Atomic::operator++() throw() return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value) : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value); #elif JUCE_ATOMICS_ANDROID - return (Type) __atomic_inc ((volatile int*) &value); + return (Type) (__atomic_inc ((volatile int*) &value) + 1); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, 1); #endif @@ -326,7 +326,7 @@ inline Type Atomic::operator--() throw() return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value) : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value); #elif JUCE_ATOMICS_ANDROID - return (Type) __atomic_dec ((volatile int*) &value); + return (Type) (__atomic_dec ((volatile int*) &value) - 1); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, -1); #endif diff --git a/src/native/android/java/ComponentPeerView.java b/src/native/android/java/ComponentPeerView.java index 10ee4e4a8c..edd982e869 100644 --- a/src/native/android/java/ComponentPeerView.java +++ b/src/native/android/java/ComponentPeerView.java @@ -31,10 +31,16 @@ import android.graphics.*; //============================================================================== public class ComponentPeerView extends View + implements View.OnFocusChangeListener { - public ComponentPeerView (Context context) + public ComponentPeerView (Context context, boolean opaque_) { super (context); + opaque = opaque_; + setFocusable (true); + setFocusableInTouchMode (true); + setOnFocusChangeListener (this); + requestFocus(); } //============================================================================== @@ -46,6 +52,14 @@ public class ComponentPeerView extends View handlePaint (canvas); } + @Override + public boolean isOpaque() + { + return opaque; + } + + private boolean opaque; + //============================================================================== private native void handleMouseDown (float x, float y, long time); private native void handleMouseDrag (float x, float y, long time); @@ -70,6 +84,7 @@ public class ComponentPeerView extends View @Override protected void onSizeChanged (int w, int h, int oldw, int oldh) { + viewSizeChanged(); } @Override @@ -77,16 +92,33 @@ public class ComponentPeerView extends View { } + private native void viewSizeChanged(); + + @Override + public void onFocusChange (View v, boolean hasFocus) + { + if (v == this) + focusChanged (hasFocus); + } + + private native void focusChanged (boolean hasFocus); + public void setViewName (String newName) { } public boolean isVisible() { - return true; + return getVisibility() == VISIBLE; } public void setVisible (boolean b) { + setVisibility (b ? VISIBLE : INVISIBLE); + } + + public boolean containsPoint (int x, int y) + { + return true; //xxx needs to check overlapping views } } diff --git a/src/native/android/java/JuceAppActivity.java b/src/native/android/java/JuceAppActivity.java index ebd2d033b5..781be9fc49 100644 --- a/src/native/android/java/JuceAppActivity.java +++ b/src/native/android/java/JuceAppActivity.java @@ -27,11 +27,16 @@ package com.juce; import android.app.Activity; import android.os.Bundle; -import android.content.*; -import android.view.*; +import android.content.Context; +import android.view.ViewGroup; +import android.view.Display; +import android.view.WindowManager; +import android.graphics.Paint; +import android.graphics.Path; import android.text.ClipboardManager; import com.juce.ComponentPeerView; + //============================================================================== public class JuceAppActivity extends Activity { @@ -106,9 +111,9 @@ public class JuceAppActivity extends Activity //============================================================================== private ViewHolder viewHolder; - public ComponentPeerView createNewView() + public ComponentPeerView createNewView (boolean opaque) { - ComponentPeerView v = new ComponentPeerView (this); + ComponentPeerView v = new ComponentPeerView (this, opaque); viewHolder.addView (v); return v; } @@ -123,6 +128,8 @@ public class JuceAppActivity extends Activity public ViewHolder (Context context) { super (context); + setDescendantFocusability (ViewGroup.FOCUS_AFTER_DESCENDANTS); + setFocusable (false); } protected void onLayout (boolean changed, int left, int top, int right, int bottom) @@ -130,6 +137,11 @@ public class JuceAppActivity extends Activity } } + public void excludeClipRegion (android.graphics.Canvas canvas, float left, float top, float right, float bottom) + { + canvas.clipRect (left, top, right, bottom, android.graphics.Region.Op.DIFFERENCE); + } + //============================================================================== public String getClipboardContent() { @@ -142,4 +154,97 @@ public class JuceAppActivity extends Activity ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE); clipboard.setText (newText); } + + //============================================================================== + /*class PathGrabber extends Path + { + public PathGrabber() + { + pathString = new StringBuilder(); + } + + @Override + public void addPath (Path src) + { + } + + @Override + public void addPath (Path src, float dx, float dy) + { + } + + @Override + public void close() + { + pathString.append ('c'); + } + + @Override + public void moveTo (float x, float y) + { + pathString.append ('m'); + pathString.append (String.valueOf (x)); + pathString.append (String.valueOf (y)); + } + + @Override + public void lineTo (float x, float y) + { + pathString.append ('l'); + pathString.append (String.valueOf (x)); + pathString.append (String.valueOf (y)); + } + + @Override + public void quadTo (float x1, float y1, float x2, float y2) + { + pathString.append ('q'); + pathString.append (String.valueOf (x1)); + pathString.append (String.valueOf (y1)); + pathString.append (String.valueOf (x2)); + pathString.append (String.valueOf (y2)); + } + + @Override + public void cubicTo (float x1, float y1, float x2, float y2, float x3, float y3) + { + pathString.append ('b'); + pathString.append (String.valueOf (x1)); + pathString.append (String.valueOf (y1)); + pathString.append (String.valueOf (x2)); + pathString.append (String.valueOf (y2)); + pathString.append (String.valueOf (x3)); + pathString.append (String.valueOf (y3)); + } + + @Override + public void reset() + { + rewind(); + } + + @Override + public void rewind() + { + pathString.setLength (0); + } + + public String getJucePath() + { + if (getFillType() == FillType.EVEN_ODD) + return "z" + pathString.toString(); + else + return "n" + pathString.toString(); + } + + private StringBuilder pathString; + }*/ + + public String createPathForGlyph (Paint paint, char c) + { + /*PathGrabber pg = new PathGrabber(); + paint.getTextPath (String.valueOf (c), 0, 1, 0, 0, pg); + return pg.getJucePath();*/ + return ""; + } } diff --git a/src/native/android/juce_android_Fonts.cpp b/src/native/android/juce_android_Fonts.cpp index 6928de215f..f6a167ce7f 100644 --- a/src/native/android/juce_android_Fonts.cpp +++ b/src/native/android/juce_android_Fonts.cpp @@ -127,8 +127,14 @@ public: bool getOutlineForGlyph (int glyphNumber, Path& destPath) { - // TODO - return false; + LocalRef s ((jstring) android.activity.callObjectMethod (android.createPathForGlyph, paint.get(), (jchar) glyphNumber)); + + if (s == 0) + return false; + + const String ourString (juceString (s)); + destPath.restoreFromString (ourString); + return ourString.isNotEmpty(); } GlobalRef typeface, paint; diff --git a/src/native/android/juce_android_GraphicsContext.cpp b/src/native/android/juce_android_GraphicsContext.cpp index 55988fe18b..3cdf4cf18a 100644 --- a/src/native/android/juce_android_GraphicsContext.cpp +++ b/src/native/android/juce_android_GraphicsContext.cpp @@ -27,22 +27,141 @@ // compiled on its own). #if JUCE_INCLUDED_FILE +//============================================================================== +class AndroidImage : public Image::SharedImage +{ +public: + //============================================================================== + AndroidImage (const int width_, const int height_, const bool clearImage) + : Image::SharedImage (Image::ARGB, width_, height_) + { + JNIEnv* env = getEnv(); + jobject mode = env->GetStaticObjectField (android.bitmapConfigClass, android.ARGB_8888); + bitmap = GlobalRef (env->CallStaticObjectMethod (android.bitmapClass, android.createBitmap, width_, height_, mode)); + env->DeleteLocalRef (mode); + } + + AndroidImage (const int width_, const int height_, const GlobalRef& bitmap_) + : Image::SharedImage (Image::ARGB, width_, height_), + bitmap (bitmap_) + { + } + + ~AndroidImage() + { + bitmap.callVoidMethod (android.recycle); + } + + Image::ImageType getType() const { return Image::NativeImage; } + LowLevelGraphicsContext* createLowLevelContext(); + + void initialiseBitmapData (Image::BitmapData& bm, int x, int y, Image::BitmapData::ReadWriteMode mode) + { + bm.lineStride = width * sizeof (jint); + bm.pixelStride = sizeof (jint); + bm.pixelFormat = Image::ARGB; + bm.dataReleaser = new CopyHandler (*this, bm, x, y, mode); + } + + SharedImage* clone() + { + JNIEnv* env = getEnv(); + jobject mode = env->GetStaticObjectField (android.bitmapConfigClass, android.ARGB_8888); + GlobalRef newCopy (bitmap.callObjectMethod (android.bitmapCopy, mode, true)); + env->DeleteLocalRef (mode); + + return new AndroidImage (width, height, newCopy); + } + + //============================================================================== + GlobalRef bitmap; + +private: + class CopyHandler : public Image::BitmapData::BitmapDataReleaser + { + public: + CopyHandler (AndroidImage& owner_, Image::BitmapData& bitmapData_, + const int x_, const int y_, const Image::BitmapData::ReadWriteMode mode_) + : owner (owner_), bitmapData (bitmapData_), mode (mode_), x (x_), y (y_) + { + JNIEnv* env = getEnv(); + + intArray = env->NewIntArray (bitmapData.width * bitmapData.height); + + if (mode != Image::BitmapData::writeOnly) + owner_.bitmap.callVoidMethod (android.getPixels, intArray, 0, bitmapData.width, x_, y_, + bitmapData.width, bitmapData.height); + + bitmapData.data = (uint8*) env->GetIntArrayElements (intArray, 0); + + if (mode != Image::BitmapData::writeOnly) + { + for (int yy = 0; yy < bitmapData.height; ++yy) + { + PixelARGB* p = (PixelARGB*) bitmapData.getLinePointer (yy); + + for (int xx = 0; xx < bitmapData.width; ++xx) + p[xx].premultiply(); + } + } + } + + ~CopyHandler() + { + JNIEnv* env = getEnv(); + + if (mode != Image::BitmapData::readOnly) + { + for (int yy = 0; yy < bitmapData.height; ++yy) + { + PixelARGB* p = (PixelARGB*) bitmapData.getLinePointer (yy); + + for (int xx = 0; xx < bitmapData.width; ++xx) + p[xx].unpremultiply(); + } + } + + env->ReleaseIntArrayElements (intArray, (jint*) bitmapData.data, 0); + + if (mode != Image::BitmapData::readOnly) + owner.bitmap.callVoidMethod (android.setPixels, intArray, 0, bitmapData.width, x, y, + bitmapData.width, bitmapData.height); + + env->DeleteLocalRef (intArray); + } + + private: + AndroidImage& owner; + Image::BitmapData& bitmapData; + jintArray intArray; + const Image::BitmapData::ReadWriteMode mode; + const int x, y; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CopyHandler); + }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidImage); +}; + +Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage) +{ + if (format == Image::SingleChannel) + return createSoftwareImage (format, width, height, clearImage); + else + return new AndroidImage (width, height, clearImage); +} //============================================================================== class AndroidLowLevelGraphicsContext : public LowLevelGraphicsContext { public: - AndroidLowLevelGraphicsContext (const GlobalRef& canvas_) + AndroidLowLevelGraphicsContext (jobject canvas_) : canvas (canvas_), currentState (new SavedState()) { setFill (Colours::black); } - ~AndroidLowLevelGraphicsContext() - { - } - bool isVectorDevice() const { return false; } //============================================================================== @@ -68,11 +187,19 @@ public: bool clipToRectangleList (const RectangleList& clipRegion) { - return canvas.callBooleanMethod (android.clipRegion, createRegion (getEnv(), clipRegion).get()); + RectangleList excluded (getClipBounds()); + excluded.subtract (clipRegion); + + const int numRects = excluded.getNumRectangles(); + + for (int i = 0; i < numRects; ++i) + excludeClipRectangle (excluded.getRectangle(i)); } void excludeClipRectangle (const Rectangle& r) { + android.activity.callVoidMethod (android.excludeClipRegion, canvas.get(), + (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); } void clipToPath (const Path& path, const AffineTransform& transform) @@ -82,6 +209,7 @@ public: void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) { + // TODO xxx } bool clipRegionIntersects (const Rectangle& r) @@ -117,10 +245,12 @@ public: void setOpacity (float newOpacity) { + currentState->setAlpha (newOpacity); } void setInterpolationQuality (Graphics::ResamplingQuality quality) { + // TODO xxx } //============================================================================== @@ -139,6 +269,60 @@ public: void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles) { + AndroidImage* androidImage = dynamic_cast (sourceImage.getSharedImage()); + + if (androidImage != 0) + { + JNIEnv* env = getEnv(); + canvas.callVoidMethod (android.drawBitmap, androidImage->bitmap.get(), + createMatrix (env, transform).get(), getImagePaint()); + } + else + { + if (transform.isOnlyTranslation()) + { + JNIEnv* env = getEnv(); + + Image::BitmapData bm (sourceImage, Image::BitmapData::readOnly); + + jintArray imageData = env->NewIntArray (bm.width * bm.height); + jint* dest = env->GetIntArrayElements (imageData, 0); + + if (dest != 0) + { + const uint8* srcLine = bm.getLinePointer (0); + jint* dstLine = dest; + + for (int y = 0; y < bm.height; ++y) + { + switch (bm.pixelFormat) + { + case Image::ARGB: copyPixels (dstLine, (PixelARGB*) srcLine, bm.width, bm.pixelStride); break; + case Image::RGB: copyPixels (dstLine, (PixelRGB*) srcLine, bm.width, bm.pixelStride); break; + case Image::SingleChannel: copyPixels (dstLine, (PixelAlpha*) srcLine, bm.width, bm.pixelStride); break; + default: jassertfalse; break; + } + + srcLine += bm.lineStride; + dstLine += bm.width; + } + + canvas.callVoidMethod (android.drawMemoryBitmap, imageData, 0, bm.width, + transform.getTranslationX(), transform.getTranslationY(), + bm.width, bm.height, true, getImagePaint()); + + env->ReleaseIntArrayElements (imageData, dest, 0); + env->DeleteLocalRef (imageData); + } + } + else + { + saveState(); + addTransform (transform); + drawImage (sourceImage, AffineTransform::identity, fillEntireClipAsTiles); + restoreState(); + } + } } void drawLine (const Line & line) @@ -215,10 +399,12 @@ public: void beginTransparencyLayer (float opacity) { + // TODO xxx } void endTransparencyLayer() { + // TODO xxx } class SavedState @@ -240,6 +426,12 @@ public: fillType = newType; } + void setAlpha (float alpha) + { + fillNeedsUpdate = true; + fillType.colour = fillType.colour.withAlpha (alpha); + } + jobject getPaint() { if (fillNeedsUpdate) @@ -299,6 +491,7 @@ public: tileMode); } + env->DeleteLocalRef (tileMode); env->DeleteLocalRef (coloursArray); env->DeleteLocalRef (positionsArray); @@ -309,6 +502,7 @@ public: } else { + } } @@ -330,11 +524,22 @@ public: paint.callObjectMethod (android.setTypeface, atf->typeface.get()); paint.callVoidMethod (android.setTextSize, font.getHeight()); } + + fillNeedsUpdate = true; + paint.callVoidMethod (android.setAlpha, (jint) fillType.colour.getAlpha()); } return p; } + jobject getImagePaint() + { + jobject p = getPaint(); + paint.callVoidMethod (android.setAlpha, (jint) fillType.colour.getAlpha()); + fillNeedsUpdate = true; + return p; + } + FillType fillType; Font font; GlobalRef paint; @@ -347,10 +552,8 @@ private: ScopedPointer currentState; OwnedArray stateStack; - jobject getCurrentPaint() const - { - return currentState->getPaint(); - } + jobject getCurrentPaint() const { return currentState->getPaint(); } + jobject getImagePaint() const { return currentState->getImagePaint(); } static const LocalRef createPath (JNIEnv* env, const Path& path) { @@ -424,8 +627,24 @@ private: return col.getARGB(); } + template + static void copyPixels (jint* const dest, const PixelType* src, const int width, const int pixelStride) throw() + { + for (int x = 0; x < width; ++x) + { + dest[x] = src->getUnpremultipliedARGB(); + src = addBytesToPointer (src, pixelStride); + } + } + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidLowLevelGraphicsContext); }; +LowLevelGraphicsContext* AndroidImage::createLowLevelContext() +{ + jobject canvas = getEnv()->NewObject (android.canvasClass, android.canvasBitmapConstructor, bitmap.get()); + return new AndroidLowLevelGraphicsContext (canvas); +} + #endif diff --git a/src/native/android/juce_android_Messaging.cpp b/src/native/android/juce_android_Messaging.cpp index c6e643fd86..faa22cbd55 100644 --- a/src/native/android/juce_android_Messaging.cpp +++ b/src/native/android/juce_android_Messaging.cpp @@ -29,31 +29,14 @@ //============================================================================== -void MessageManager::doPlatformSpecificInitialisation() -{ - -} - -void MessageManager::doPlatformSpecificShutdown() -{ - -} +void MessageManager::doPlatformSpecificInitialisation() {} +void MessageManager::doPlatformSpecificShutdown() {} //============================================================================== bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages) { - // TODO - - /* - The idea here is that this will check the system message queue, pull off a - message if there is one, deliver it, and return true if a message was delivered. - If the queue's empty, return false. - - If the message is one of our special ones (i.e. a Message object being delivered, - this must call MessageManager::getInstance()->deliverMessage() to deliver it - - - */ + Logger::outputDebugString ("*** Modal loops are not possible in Android!! Exiting..."); + exit (1); return true; } @@ -61,14 +44,16 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages //============================================================================== bool juce_postMessageToSystemQueue (Message* message) { + message->incReferenceCount(); getEnv()->CallVoidMethod (android.activity, android.postMessage, (jlong) (pointer_sized_uint) message); return true; } JUCE_JNI_CALLBACK (JuceAppActivity, deliverMessage, void, (jobject activity, jlong value)) { - Message* m = (Message*) (pointer_sized_uint) value; - MessageManager::getInstance()->deliverMessage ((Message*) (pointer_sized_uint) value); + Message* const message = (Message*) (pointer_sized_uint) value; + MessageManager::getInstance()->deliverMessage (message); + message->decReferenceCount(); } //============================================================================== @@ -115,4 +100,31 @@ void MessageManager::broadcastMessage (const String&) { } +void MessageManager::runDispatchLoop() +{ +} + +class QuitCallback : public CallbackMessage +{ +public: + QuitCallback() {} + + void messageCallback() + { + android.activity.callVoidMethod (android.finish); + } +}; + +void MessageManager::stopDispatchLoop() +{ + (new QuitCallback())->post(); + quitMessagePosted = true; +} + +bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) +{ + juce_dispatchNextMessageOnSystemQueue (false); + return false; +} + #endif diff --git a/src/native/android/juce_android_NativeCode.cpp b/src/native/android/juce_android_NativeCode.cpp index 69e062c635..a6dff0bb33 100644 --- a/src/native/android/juce_android_NativeCode.cpp +++ b/src/native/android/juce_android_NativeCode.cpp @@ -103,6 +103,8 @@ BEGIN_JUCE_NAMESPACE JAVACLASS (canvasClass, "android/graphics/Canvas") \ JAVACLASS (paintClass, "android/graphics/Paint") \ JAVACLASS (pathClass, "android/graphics/Path") \ + JAVACLASS (bitmapClass, "android/graphics/Bitmap") \ + JAVACLASS (bitmapConfigClass, "android/graphics/Bitmap$Config") \ JAVACLASS (matrixClass, "android/graphics/Matrix") \ JAVACLASS (rectClass, "android/graphics/Rect") \ JAVACLASS (regionClass, "android/graphics/Region") \ @@ -116,11 +118,14 @@ BEGIN_JUCE_NAMESPACE #define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ \ STATICMETHOD (activityClass, printToConsole, "printToConsole", "(Ljava/lang/String;)V") \ - METHOD (activityClass, createNewView, "createNewView", "()Lcom/juce/ComponentPeerView;") \ + METHOD (activityClass, createNewView, "createNewView", "(Z)Lcom/juce/ComponentPeerView;") \ METHOD (activityClass, deleteView, "deleteView", "(Lcom/juce/ComponentPeerView;)V") \ METHOD (activityClass, postMessage, "postMessage", "(J)V") \ + METHOD (activityClass, finish, "finish", "()V") \ METHOD (activityClass, getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \ METHOD (activityClass, setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \ + METHOD (activityClass, excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \ + METHOD (activityClass, createPathForGlyph, "createPathForGlyph", "(Landroid/graphics/Paint;C)Ljava/lang/String;") \ \ METHOD (fileClass, fileExists, "exists", "()Z") \ \ @@ -137,7 +142,9 @@ BEGIN_JUCE_NAMESPACE METHOD (componentPeerViewClass, isVisible, "isVisible", "()Z") \ METHOD (componentPeerViewClass, hasFocus, "hasFocus", "()Z") \ METHOD (componentPeerViewClass, invalidate, "invalidate", "(IIII)V") \ + METHOD (componentPeerViewClass, containsPoint, "containsPoint", "(II)Z") \ \ + METHOD (canvasClass, canvasBitmapConstructor, "", "(Landroid/graphics/Bitmap;)V") \ METHOD (canvasClass, drawRect, "drawRect", "(FFFFLandroid/graphics/Paint;)V") \ METHOD (canvasClass, translate, "translate", "(FF)V") \ METHOD (canvasClass, clipPath, "clipPath", "(Landroid/graphics/Path;)Z") \ @@ -145,6 +152,7 @@ BEGIN_JUCE_NAMESPACE METHOD (canvasClass, clipRegion, "clipRegion", "(Landroid/graphics/Region;)Z") \ METHOD (canvasClass, concat, "concat", "(Landroid/graphics/Matrix;)V") \ METHOD (canvasClass, drawBitmap, "drawBitmap", "(Landroid/graphics/Bitmap;Landroid/graphics/Matrix;Landroid/graphics/Paint;)V") \ + METHOD (canvasClass, drawMemoryBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \ METHOD (canvasClass, drawLine, "drawLine", "(FFFFLandroid/graphics/Paint;)V") \ METHOD (canvasClass, drawPath, "drawPath", "(Landroid/graphics/Path;Landroid/graphics/Paint;)V") \ METHOD (canvasClass, drawText, "drawText", "(Ljava/lang/String;FFLandroid/graphics/Paint;)V") \ @@ -157,13 +165,13 @@ BEGIN_JUCE_NAMESPACE \ METHOD (paintClass, paintClassConstructor, "", "(I)V") \ METHOD (paintClass, setColor, "setColor", "(I)V") \ + METHOD (paintClass, setAlpha, "setAlpha", "(I)V") \ METHOD (paintClass, setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \ METHOD (paintClass, setTypeface, "setTypeface", "(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;") \ METHOD (paintClass, ascent, "ascent", "()F") \ METHOD (paintClass, descent, "descent", "()F") \ METHOD (paintClass, setTextSize, "setTextSize", "(F)V") \ METHOD (paintClass, getTextWidths, "getTextWidths", "(Ljava/lang/String;[F)I") \ - METHOD (paintClass, getTextPath, "getTextPath", "(Ljava/lang/String;IIFFLandroid/graphics/Path;)V") \ \ METHOD (shaderClass, setLocalMatrix, "setLocalMatrix", "(Landroid/graphics/Matrix;)V") \ STATICFIELD (shaderTileModeClass, clampMode, "CLAMP", "Landroid/graphics/Shader$TileMode;") \ @@ -174,6 +182,13 @@ BEGIN_JUCE_NAMESPACE METHOD (pathClass, quadTo, "quadTo", "(FFFF)V") \ METHOD (pathClass, cubicTo, "cubicTo", "(FFFFFF)V") \ METHOD (pathClass, closePath, "close", "()V") \ +\ + STATICMETHOD (bitmapClass, createBitmap, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;") \ + STATICFIELD (bitmapConfigClass, ARGB_8888, "ARGB_8888", "Landroid/graphics/Bitmap$Config;") \ + METHOD (bitmapClass, bitmapCopy, "copy", "(Landroid/graphics/Bitmap$Config;Z)Landroid/graphics/Bitmap;") \ + METHOD (bitmapClass, getPixels, "getPixels", "([IIIIIII)V") \ + METHOD (bitmapClass, setPixels, "setPixels", "([IIIIIII)V") \ + METHOD (bitmapClass, recycle, "recycle", "()V") \ \ METHOD (matrixClass, matrixClassConstructor, "", "()V") \ METHOD (matrixClass, setValues, "setValues", "([F)V") \ @@ -315,7 +330,10 @@ public: inline void clear() { if (obj != 0) + { getEnv()->DeleteGlobalRef (obj); + obj = 0; + } } inline GlobalRef& operator= (const GlobalRef& other) diff --git a/src/native/android/juce_android_Windowing.cpp b/src/native/android/juce_android_Windowing.cpp index 483809afc1..4d50059b20 100644 --- a/src/native/android/juce_android_Windowing.cpp +++ b/src/native/android/juce_android_Windowing.cpp @@ -27,7 +27,6 @@ // compiled on its own). #if JUCE_INCLUDED_FILE -static ModifierKeys currentModifiers; //============================================================================== class AndroidComponentPeer : public ComponentPeer @@ -36,8 +35,10 @@ public: //============================================================================== AndroidComponentPeer (Component* const component, const int windowStyleFlags) : ComponentPeer (component, windowStyleFlags), - view (android.activity.callObjectMethod (android.createNewView)) + view (android.activity.callObjectMethod (android.createNewView, component->isOpaque())) { + if (isFocused()) + handleFocusGain(); } ~AndroidComponentPeer() @@ -88,7 +89,7 @@ public: const Point getScreenPosition() const { - JNIEnv* const env = getEnv(); + /*JNIEnv* const env = getEnv(); jintArray pos = env->NewIntArray (2); view.callVoidMethod (android.getLocationOnScreen, pos); @@ -97,7 +98,10 @@ public: env->GetIntArrayRegion (pos, 0, 2, coords); env->DeleteLocalRef (pos); - return Point (coords[0], coords[1]); + return Point (coords[0], coords[1]);*/ + + return Point (view.callIntMethod (android.getLeft), + view.callIntMethod (android.getTop)); } const Point localToGlobal (const Point& relativePosition) @@ -138,10 +142,9 @@ public: bool contains (const Point& position, bool trueIfInAChildWindow) const { - // TODO - return isPositiveAndBelow (position.getX(), component->getWidth()) - && isPositiveAndBelow (position.getY(), component->getHeight()); + && isPositiveAndBelow (position.getY(), component->getHeight()) + && ((! trueIfInAChildWindow) || view.callBooleanMethod (android.containsPoint, position.getX(), position.getY())); } const BorderSize getFrameSize() const @@ -162,6 +165,8 @@ public: if (makeActive) grabFocus(); + + handleBroughtToFront(); } void toBehind (ComponentPeer* other) @@ -172,21 +177,24 @@ public: //============================================================================== void handleMouseDownCallback (float x, float y, int64 time) { + lastMousePos.setXY ((int) x, (int) y); currentModifiers = currentModifiers.withoutMouseButtons(); - handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + handleMouseEvent (0, lastMousePos, currentModifiers, time); currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); - handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + handleMouseEvent (0, lastMousePos, currentModifiers, time); } void handleMouseDragCallback (float x, float y, int64 time) { - handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + lastMousePos.setXY ((int) x, (int) y); + handleMouseEvent (0, lastMousePos, currentModifiers, time); } void handleMouseUpCallback (float x, float y, int64 time) { + lastMousePos.setXY ((int) x, (int) y); currentModifiers = currentModifiers.withoutMouseButtons(); - handleMouseEvent (0, Point ((int) x, (int) y), currentModifiers, time); + handleMouseEvent (0, lastMousePos, currentModifiers, time); } //============================================================================== @@ -197,7 +205,15 @@ public: void grabFocus() { - (void) view.callBooleanMethod (android.requestFocus); + view.callBooleanMethod (android.requestFocus); + } + + void handleFocusChangeCallback (bool hasFocus) + { + if (hasFocus) + handleFocusGain(); + else + handleFocusLoss(); } void textInputRequired (const Point& position) @@ -208,8 +224,7 @@ public: //============================================================================== void handlePaintCallback (JNIEnv* env, jobject canvas) { - GlobalRef canvasRef (canvas); - AndroidLowLevelGraphicsContext g (canvasRef); + AndroidLowLevelGraphicsContext g (canvas); handlePaint (g); } @@ -243,6 +258,9 @@ public: return 0; } + static ModifierKeys currentModifiers; + static Point lastMousePos; + private: //============================================================================== GlobalRef view; @@ -250,6 +268,9 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidComponentPeer); }; +ModifierKeys AndroidComponentPeer::currentModifiers = 0; +Point AndroidComponentPeer::lastMousePos; + //============================================================================== #define JUCE_VIEW_CALLBACK(returnType, javaMethodName, params, juceMethodInvocation) \ JUCE_JNI_CALLBACK (ComponentPeerView, javaMethodName, returnType, params) \ @@ -269,6 +290,12 @@ JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv*, jobject view, jfloat x, jfl JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), handleMouseUpCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, viewSizeChanged, (JNIEnv*, jobject view), + handleMovedOrResized()) + +JUCE_VIEW_CALLBACK (void, focusChanged, (JNIEnv*, jobject view, jboolean hasFocus), + handleFocusChangeCallback (hasFocus)) + //============================================================================== ComponentPeer* Component::createNewPeer (int styleFlags, void*) { @@ -298,8 +325,7 @@ void Desktop::createMouseInputSources() const Point MouseInputSource::getCurrentMousePosition() { - // TODO - return Point(); + return AndroidComponentPeer::lastMousePos; } void Desktop::setMousePosition (const Point& newPosition) @@ -316,12 +342,12 @@ bool KeyPress::isKeyCurrentlyDown (const int keyCode) void ModifierKeys::updateCurrentModifiers() throw() { - // not needed + currentModifiers = AndroidComponentPeer::currentModifiers; } const ModifierKeys ModifierKeys::getCurrentModifiersRealtime() throw() { - return currentModifiers; + return AndroidComponentPeer::currentModifiers; } //============================================================================== @@ -340,11 +366,6 @@ bool AlertWindow::showNativeDialogBox (const String& title, } //============================================================================== -Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage) -{ - return createSoftwareImage (format, width, height, clearImage); -} - void Desktop::setScreenSaverEnabled (const bool isEnabled) { // TODO diff --git a/src/native/linux/juce_linux_Windowing.cpp b/src/native/linux/juce_linux_Windowing.cpp index 3203d75604..191d15cabd 100644 --- a/src/native/linux/juce_linux_Windowing.cpp +++ b/src/native/linux/juce_linux_Windowing.cpp @@ -585,6 +585,14 @@ public: return new LowLevelGraphicsSoftwareRenderer (Image (this)); } + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) + { + bitmap.data = imageData + x * pixelStride + y * lineStride; + bitmap.pixelFormat = format; + bitmap.lineStride = lineStride; + bitmap.pixelStride = pixelStride; + } + SharedImage* clone() { jassertfalse; @@ -622,7 +630,7 @@ public: const uint32 bShiftL = jmax (0, getShiftNeeded (bMask)); const uint32 bShiftR = jmax (0, -getShiftNeeded (bMask)); - const Image::BitmapData srcData (Image (this), false); + const Image::BitmapData srcData (Image (this), Image::BitmapData::readOnly); for (int y = sy; y < sy + dh; ++y) { @@ -656,6 +664,8 @@ private: const int imageDepth; HeapBlock imageDataAllocated; HeapBlock imageData16Bit; + int pixelStride, lineStride; + uint8* imageData; GC gc; diff --git a/src/native/mac/juce_mac_CoreGraphicsContext.mm b/src/native/mac/juce_mac_CoreGraphicsContext.mm index 2d887f6386..7bf645206a 100644 --- a/src/native/mac/juce_mac_CoreGraphicsContext.mm +++ b/src/native/mac/juce_mac_CoreGraphicsContext.mm @@ -38,8 +38,7 @@ public: pixelStride = format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1); lineStride = (pixelStride * jmax (1, width) + 3) & ~3; - imageDataAllocated.allocate (lineStride * jmax (1, height), clearImage); - imageData = imageDataAllocated; + imageData.allocate (lineStride * jmax (1, height), clearImage); CGColorSpaceRef colourSpace = (format == Image::SingleChannel) ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); @@ -58,6 +57,14 @@ public: Image::ImageType getType() const { return Image::NativeImage; } LowLevelGraphicsContext* createLowLevelContext(); + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) + { + bitmap.data = imageData + x * pixelStride + y * lineStride; + bitmap.pixelFormat = format; + bitmap.lineStride = lineStride; + bitmap.pixelStride = pixelStride; + } + SharedImage* clone() { CoreGraphicsImage* im = new CoreGraphicsImage (format, width, height, false); @@ -77,7 +84,7 @@ public: } else { - const Image::BitmapData srcData (juceImage, false); + const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly); CGDataProviderRef provider; if (mustOutliveSource) @@ -126,7 +133,8 @@ public: //============================================================================== CGContextRef context; - HeapBlock imageDataAllocated; + HeapBlock imageData; + int pixelStride, lineStride; private: static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) diff --git a/src/native/windows/juce_win32_CameraDevice.cpp b/src/native/windows/juce_win32_CameraDevice.cpp index ea3433b666..055aeb5cb9 100644 --- a/src/native/windows/juce_win32_CameraDevice.cpp +++ b/src/native/windows/juce_win32_CameraDevice.cpp @@ -212,7 +212,7 @@ public: const ScopedLock sl (imageSwapLock); { - const Image::BitmapData destData (loadingImage, 0, 0, width, height, true); + const Image::BitmapData destData (loadingImage, 0, 0, width, height, Image::BitmapData::writeOnly); for (int i = 0; i < height; ++i) memcpy (destData.getLinePointer ((height - 1) - i), diff --git a/src/native/windows/juce_win32_Direct2DGraphicsContext.cpp b/src/native/windows/juce_win32_Direct2DGraphicsContext.cpp index 175d32c0f2..8301bfc31f 100644 --- a/src/native/windows/juce_win32_Direct2DGraphicsContext.cpp +++ b/src/native/windows/juce_win32_Direct2DGraphicsContext.cpp @@ -243,7 +243,7 @@ public: D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); Image img (image.convertedToFormat (Image::ARGB)); - Image::BitmapData bd (img, false); + Image::BitmapData bd (img, Image::BitmapData::readOnly); bp.pixelFormat = renderingTarget->GetPixelFormat(); bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; @@ -479,7 +479,7 @@ public: D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); maskImage = image.convertedToFormat (Image::ARGB); - Image::BitmapData bd (this->image, false); // xxx should be maskImage? + Image::BitmapData bd (this->image, Image::BitmapData::readOnly); // xxx should be maskImage? bp.pixelFormat = owner.renderingTarget->GetPixelFormat(); bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; @@ -658,7 +658,7 @@ public: D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); this->image = image.convertedToFormat (Image::ARGB); - Image::BitmapData bd (this->image, false); + Image::BitmapData bd (this->image, Image::BitmapData::readOnly); bp.pixelFormat = owner.renderingTarget->GetPixelFormat(); bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; diff --git a/src/native/windows/juce_win32_Windowing.cpp b/src/native/windows/juce_win32_Windowing.cpp index 95cb724eee..cc4b2b994a 100644 --- a/src/native/windows/juce_win32_Windowing.cpp +++ b/src/native/windows/juce_win32_Windowing.cpp @@ -145,13 +145,6 @@ const int KeyPress::rewindKey = 0x30003; class WindowsBitmapImage : public Image::SharedImage { public: - //============================================================================== - HBITMAP hBitmap; - HGDIOBJ previousBitmap; - BITMAPV4HEADER bitmapInfo; - HDC hdc; - unsigned char* bitmapData; - //============================================================================== WindowsBitmapImage (const Image::PixelFormat format_, const int w, const int h, const bool clearImage) @@ -160,6 +153,7 @@ public: jassert (format_ == Image::RGB || format_ == Image::ARGB); pixelStride = (format_ == Image::RGB) ? 3 : 4; + lineStride = -((w * pixelStride + 3) & ~3); zerostruct (bitmapInfo); bitmapInfo.bV4Size = sizeof (BITMAPV4HEADER); @@ -182,19 +176,14 @@ public: bitmapInfo.bV4V4Compression = BI_RGB; } - lineStride = -((w * pixelStride + 3) & ~3); - HDC dc = GetDC (0); hdc = CreateCompatibleDC (dc); ReleaseDC (0, dc); SetMapMode (hdc, MM_TEXT); - hBitmap = CreateDIBSection (hdc, - (BITMAPINFO*) &(bitmapInfo), - DIB_RGB_COLORS, - (void**) &bitmapData, - 0, 0); + hBitmap = CreateDIBSection (hdc, (BITMAPINFO*) &(bitmapInfo), DIB_RGB_COLORS, + (void**) &bitmapData, 0, 0); previousBitmap = SelectObject (hdc, hBitmap); @@ -218,6 +207,14 @@ public: return new LowLevelGraphicsSoftwareRenderer (Image (this)); } + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) + { + bitmap.data = imageData + x * pixelStride + y * lineStride; + bitmap.pixelFormat = format; + bitmap.lineStride = lineStride; + bitmap.pixelStride = pixelStride; + } + Image::SharedImage* clone() { WindowsBitmapImage* im = new WindowsBitmapImage (format, width, height, false); @@ -318,6 +315,15 @@ public: } } + //============================================================================== + HBITMAP hBitmap; + HGDIOBJ previousBitmap; + BITMAPV4HEADER bitmapInfo; + HDC hdc; + uint8* bitmapData; + int pixelStride, lineStride; + uint8* imageData; + private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsBitmapImage); }; @@ -342,7 +348,7 @@ namespace IconConverters SelectObject (dc, bitmap); im = Image (Image::ARGB, bm.bmWidth, bm.bmHeight, true); - Image::BitmapData imageData (im, true); + Image::BitmapData imageData (im, Image::BitmapData::writeOnly); for (int y = bm.bmHeight; --y >= 0;) {