From 95fcc168d8965d6d482fa1e2d87fdddf83e39487 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Mon, 30 Nov 2009 19:21:25 +0000 Subject: [PATCH] More graphics updates, including fixes for CoreGraphics on PPC macs. Fix for keypress recursion in AU plugins, and fix for tabs in the CodeEditorComponent --- .../wrapper/AU/juce_AU_Wrapper.mm | 10 +- juce_amalgamated.cpp | 489 ++++++------------ .../code_editor/juce_CodeEditorComponent.cpp | 5 +- src/native/mac/juce_mac_CameraDevice.mm | 67 +-- .../mac/juce_mac_CoreGraphicsContext.mm | 95 ++-- src/native/mac/juce_mac_MouseCursor.mm | 31 +- .../mac/juce_mac_NSViewComponentPeer.mm | 168 +----- 7 files changed, 271 insertions(+), 594 deletions(-) diff --git a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm index c33e746bc5..e573993159 100644 --- a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm +++ b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm @@ -1359,8 +1359,14 @@ private: { // If we have an unused keypress, move the key-focus to a host window // and re-inject the event.. - [[hostWindow parentWindow] makeKeyWindow]; - [NSApp postEvent: [NSApp currentEvent] atStart: YES]; + static NSTimeInterval lastEventTime = 0; // check we're not recursively sending the same event + + if (lastEventTime != [[NSApp currentEvent] timestamp]) + { + lastEventTime = [[NSApp currentEvent] timestamp]; + [[hostWindow parentWindow] makeKeyWindow]; + [NSApp postEvent: [NSApp currentEvent] atStart: YES]; + } } return false; diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 6791f3c1f9..ff4bcf304c 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -730,7 +730,7 @@ public: the rest of the codebase. */ -#define USE_COREGRAPHICS_RENDERING 0 +#define USE_COREGRAPHICS_RENDERING 1 #if JUCE_IPHONE #import @@ -44829,8 +44829,11 @@ void CodeEditorComponent::insertTextAtCaret (const String& newText) void CodeEditorComponent::insertTabAtCaret() { - if (CharacterFunctions::isWhitespace (caretPos.getCharacter())) + if (CharacterFunctions::isWhitespace (caretPos.getCharacter()) + && caretPos.getLineNumber() == caretPos.movedBy (1).getLineNumber()) + { moveCaretTo (document.findWordBreakAfter (caretPos), false); + } if (useSpacesForTabs) { @@ -261310,6 +261313,7 @@ void Font::getPlatformDefaultFontNames (String& defaultSans, String& defaultSeri class CoreGraphicsImage : public Image { public: + CoreGraphicsImage (const PixelFormat format, const int imageWidth, const int imageHeight, @@ -261320,9 +261324,7 @@ public: : CGColorSpaceCreateDeviceRGB(); context = CGBitmapContextCreate (imageData, imageWidth, imageHeight, 8, lineStride, - colourSpace, - format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) - : kCGBitmapByteOrderDefault); + colourSpace, getCGImageFlags (*this)); CGColorSpaceRelease (colourSpace); } @@ -261334,7 +261336,62 @@ public: LowLevelGraphicsContext* createLowLevelContext(); + static CGImageRef createImage (const Image& juceImage, const bool forAlpha, CGColorSpaceRef colourSpace) throw() + { + const CoreGraphicsImage* nativeImage = dynamic_cast (&juceImage); + + if (nativeImage != 0 && (juceImage.getFormat() == Image::SingleChannel || ! forAlpha)) + { + return CGBitmapContextCreateImage (nativeImage->context); + } + else + { + const Image::BitmapData srcData (juceImage, 0, 0, juceImage.getWidth(), juceImage.getHeight()); + + CGDataProviderRef provider = CGDataProviderCreateWithData (0, srcData.data, srcData.lineStride * srcData.pixelStride, 0); + + CGImageRef imageRef = CGImageCreate (srcData.width, srcData.height, + 8, srcData.pixelStride * 8, srcData.lineStride, + colourSpace, getCGImageFlags (juceImage), provider, + 0, true, kCGRenderingIntentDefault); + + CGDataProviderRelease (provider); + return imageRef; + } + } + + static NSImage* createNSImage (const Image& image) + { + const ScopedAutoReleasePool pool; + + NSImage* im = [[NSImage alloc] init]; + [im setSize: NSMakeSize (image.getWidth(), image.getHeight())]; + [im lockFocus]; + + CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); + CGImageRef imageRef = createImage (image, false, colourSpace); + CGColorSpaceRelease (colourSpace); + + CGContextRef cg = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; + CGContextDrawImage (cg, CGRectMake (0, 0, image.getWidth(), image.getHeight()), imageRef); + + CGImageRelease (imageRef); + [im unlockFocus]; + + return im; + } + CGContextRef context; + +private: + static CGBitmapInfo getCGImageFlags (const Image& image) throw() + { +#if JUCE_BIG_ENDIAN + return image.getFormat() == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) : kCGBitmapByteOrderDefault; +#else + return image.getFormat() == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) : kCGBitmapByteOrderDefault; +#endif + } }; Image* Image::createNativeImage (const PixelFormat format, const int imageWidth, const int imageHeight, const bool clearImage) @@ -261423,7 +261480,7 @@ public: if (! transform.isSingularity()) { Image* singleChannelImage = createAlphaChannelImage (sourceImage); - CGImageRef image = createImage (*singleChannelImage, true); + CGImageRef image = CoreGraphicsImage::createImage (*singleChannelImage, true, greyColourSpace); flip(); AffineTransform t (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); @@ -261589,7 +261646,7 @@ public: void drawImage (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform, const bool fillEntireClipAsTiles) { - CGImageRef fullImage = createImage (sourceImage, false); + CGImageRef fullImage = CoreGraphicsImage::createImage (sourceImage, false, rgbColourSpace); CGImageRef image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), sourceImage.getHeight() - srcClip.getBottom(), srcClip.getWidth(), srcClip.getHeight())); CGImageRelease (fullImage); @@ -261887,35 +261944,6 @@ private: } } - CGImageRef createImage (const Image& juceImage, const bool forAlpha) const throw() - { - const CoreGraphicsImage* nativeImage = dynamic_cast (&juceImage); - - if (nativeImage != 0 && (juceImage.getFormat() == Image::SingleChannel || ! forAlpha)) - { - return CGBitmapContextCreateImage (nativeImage->context); - } - else - { - const Image::BitmapData srcData (juceImage, 0, 0, juceImage.getWidth(), juceImage.getHeight()); - - CGDataProviderRef provider = CGDataProviderCreateWithData (0, srcData.data, srcData.lineStride * srcData.pixelStride, 0); - CGColorSpaceRef colourSpace = forAlpha ? greyColourSpace : rgbColourSpace; - - CGImageRef imageRef = CGImageCreate (srcData.width, srcData.height, - 8, srcData.pixelStride * 8, srcData.lineStride, - colourSpace, - (juceImage.hasAlphaChannel() && ! forAlpha) - ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) - : kCGBitmapByteOrderDefault, - provider, - 0, true, kCGRenderingIntentDefault); - - CGDataProviderRelease (provider); - return imageRef; - } - } - static Image* createAlphaChannelImage (const Image& im) throw() { if (im.getFormat() == Image::SingleChannel) @@ -263519,38 +263547,9 @@ void juce_glViewport (const int w, const int h) #if JUCE_MAC -static NSImage* juceImageToNSImage (const Image& image) -{ - const ScopedAutoReleasePool pool; - - const Image::BitmapData srcData (image, 0, 0, image.getWidth(), image.getHeight()); - - NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: NULL - pixelsWide: srcData.width - pixelsHigh: srcData.height - bitsPerSample: 8 - samplesPerPixel: image.hasAlphaChannel() ? 4 : 3 - hasAlpha: image.hasAlphaChannel() - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bitmapFormat: (NSBitmapFormat) 0 - bytesPerRow: srcData.lineStride - bitsPerPixel: srcData.pixelStride * 8]; - - unsigned char* newData = [rep bitmapData]; - memcpy (newData, srcData.data, srcData.lineStride * srcData.height); - - NSImage* im = [[NSImage alloc] init]; - [im addRepresentation: rep]; - [rep release]; - - return im; -} - void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hotspotY) throw() { - NSImage* im = juceImageToNSImage (image); + NSImage* im = CoreGraphicsImage::createNSImage (image); NSCursor* c = [[NSCursor alloc] initWithImage: im hotSpot: NSMakePoint (hotspotX, hotspotY)]; [im release]; @@ -265759,6 +265758,7 @@ void Font::getPlatformDefaultFontNames (String& defaultSans, String& defaultSeri class CoreGraphicsImage : public Image { public: + CoreGraphicsImage (const PixelFormat format, const int imageWidth, const int imageHeight, @@ -265769,9 +265769,7 @@ public: : CGColorSpaceCreateDeviceRGB(); context = CGBitmapContextCreate (imageData, imageWidth, imageHeight, 8, lineStride, - colourSpace, - format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) - : kCGBitmapByteOrderDefault); + colourSpace, getCGImageFlags (*this)); CGColorSpaceRelease (colourSpace); } @@ -265783,7 +265781,62 @@ public: LowLevelGraphicsContext* createLowLevelContext(); + static CGImageRef createImage (const Image& juceImage, const bool forAlpha, CGColorSpaceRef colourSpace) throw() + { + const CoreGraphicsImage* nativeImage = dynamic_cast (&juceImage); + + if (nativeImage != 0 && (juceImage.getFormat() == Image::SingleChannel || ! forAlpha)) + { + return CGBitmapContextCreateImage (nativeImage->context); + } + else + { + const Image::BitmapData srcData (juceImage, 0, 0, juceImage.getWidth(), juceImage.getHeight()); + + CGDataProviderRef provider = CGDataProviderCreateWithData (0, srcData.data, srcData.lineStride * srcData.pixelStride, 0); + + CGImageRef imageRef = CGImageCreate (srcData.width, srcData.height, + 8, srcData.pixelStride * 8, srcData.lineStride, + colourSpace, getCGImageFlags (juceImage), provider, + 0, true, kCGRenderingIntentDefault); + + CGDataProviderRelease (provider); + return imageRef; + } + } + + static NSImage* createNSImage (const Image& image) + { + const ScopedAutoReleasePool pool; + + NSImage* im = [[NSImage alloc] init]; + [im setSize: NSMakeSize (image.getWidth(), image.getHeight())]; + [im lockFocus]; + + CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); + CGImageRef imageRef = createImage (image, false, colourSpace); + CGColorSpaceRelease (colourSpace); + + CGContextRef cg = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; + CGContextDrawImage (cg, CGRectMake (0, 0, image.getWidth(), image.getHeight()), imageRef); + + CGImageRelease (imageRef); + [im unlockFocus]; + + return im; + } + CGContextRef context; + +private: + static CGBitmapInfo getCGImageFlags (const Image& image) throw() + { +#if JUCE_BIG_ENDIAN + return image.getFormat() == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) : kCGBitmapByteOrderDefault; +#else + return image.getFormat() == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) : kCGBitmapByteOrderDefault; +#endif + } }; Image* Image::createNativeImage (const PixelFormat format, const int imageWidth, const int imageHeight, const bool clearImage) @@ -265872,7 +265925,7 @@ public: if (! transform.isSingularity()) { Image* singleChannelImage = createAlphaChannelImage (sourceImage); - CGImageRef image = createImage (*singleChannelImage, true); + CGImageRef image = CoreGraphicsImage::createImage (*singleChannelImage, true, greyColourSpace); flip(); AffineTransform t (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); @@ -266038,7 +266091,7 @@ public: void drawImage (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform, const bool fillEntireClipAsTiles) { - CGImageRef fullImage = createImage (sourceImage, false); + CGImageRef fullImage = CoreGraphicsImage::createImage (sourceImage, false, rgbColourSpace); CGImageRef image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), sourceImage.getHeight() - srcClip.getBottom(), srcClip.getWidth(), srcClip.getHeight())); CGImageRelease (fullImage); @@ -266336,35 +266389,6 @@ private: } } - CGImageRef createImage (const Image& juceImage, const bool forAlpha) const throw() - { - const CoreGraphicsImage* nativeImage = dynamic_cast (&juceImage); - - if (nativeImage != 0 && (juceImage.getFormat() == Image::SingleChannel || ! forAlpha)) - { - return CGBitmapContextCreateImage (nativeImage->context); - } - else - { - const Image::BitmapData srcData (juceImage, 0, 0, juceImage.getWidth(), juceImage.getHeight()); - - CGDataProviderRef provider = CGDataProviderCreateWithData (0, srcData.data, srcData.lineStride * srcData.pixelStride, 0); - CGColorSpaceRef colourSpace = forAlpha ? greyColourSpace : rgbColourSpace; - - CGImageRef imageRef = CGImageCreate (srcData.width, srcData.height, - 8, srcData.pixelStride * 8, srcData.lineStride, - colourSpace, - (juceImage.hasAlphaChannel() && ! forAlpha) - ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) - : kCGBitmapByteOrderDefault, - provider, - 0, true, kCGRenderingIntentDefault); - - CGDataProviderRelease (provider); - return imageRef; - } - } - static Image* createAlphaChannelImage (const Image& im) throw() { if (im.getFormat() == Image::SingleChannel) @@ -266928,122 +266952,6 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE -class JuceNSImage -{ -public: - JuceNSImage (const int width, const int height, const bool hasAlpha) - : juceImage (hasAlpha ? Image::ARGB : Image::RGB, - width, height, hasAlpha), - srcData (juceImage, 0, 0, width, height) - { - imageRep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: (unsigned char**) &(srcData.data) - pixelsWide: width - pixelsHigh: height - bitsPerSample: 8 - samplesPerPixel: srcData.pixelStride - hasAlpha: hasAlpha - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bitmapFormat: /*NSAlphaFirstBitmapFormat*/ (NSBitmapFormat) 0 - bytesPerRow: srcData.lineStride - bitsPerPixel: 8 * srcData.pixelStride ]; - } - - ~JuceNSImage() - { - [imageRep release]; - } - - Image& getJuceImage() throw() { return juceImage; } - - void draw (const float x, const float y, - const RectangleList& clip, - const int originX, const int originY) const - { - // Our data is BGRA and the damned image rep only takes RGBA, so - // we need to byte-swap the active areas if there's an alpha channel... - if (juceImage.hasAlphaChannel()) - { - RectangleList::Iterator iter (clip); - while (iter.next()) - { - const Rectangle* const r = iter.getRectangle(); - - swapRGBOrder (r->getX() + originX, - r->getY() + originY, - r->getWidth(), - r->getHeight()); - } - } - - NSPoint p; - p.x = x; - p.y = y; - [imageRep drawAtPoint: p]; - } - - void drawNSImage (NSImage* imageToDraw) - { - const ScopedAutoReleasePool pool; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext: - [NSGraphicsContext graphicsContextWithBitmapImageRep: imageRep]]; - - [imageToDraw drawAtPoint: NSZeroPoint - fromRect: NSMakeRect (0, 0, [imageToDraw size].width, [imageToDraw size].height) - operation: NSCompositeSourceOver - fraction: 1.0f]; - - [[NSGraphicsContext currentContext] flushGraphics]; - [NSGraphicsContext restoreGraphicsState]; - - if (juceImage.hasAlphaChannel()) - swapRGBOrder (0, 0, juceImage.getWidth(), juceImage.getHeight()); - } - -private: - Image juceImage; - NSBitmapImageRep* imageRep; - const Image::BitmapData srcData; - - void swapRGBOrder (const int x, const int y, const int w, int h) const - { -#if JUCE_BIG_ENDIAN - jassert (srcData.pixelStride == 4); -#endif - jassert (Rectangle (0, 0, juceImage.getWidth(), juceImage.getHeight()) - .contains (Rectangle (x, y, w, h))); - - uint8* start = srcData.getPixelPointer (x, y); - - while (--h >= 0) - { - uint8* p = start; - start += srcData.lineStride; - - for (int i = w; --i >= 0;) - { -#if JUCE_BIG_ENDIAN - const uint8 oldp3 = p[3]; - const uint8 oldp1 = p[1]; - p[3] = p[0]; - p[0] = oldp1; - p[1] = p[2]; - p[2] = oldp3; -#else - const uint8 oldp0 = p[0]; - p[0] = p[2]; - p[2] = oldp0; -#endif - - p += srcData.pixelStride; - } - } - } -}; - static ComponentPeer* currentlyFocusedPeer = 0; static VoidArray keysCurrentlyDown; @@ -267801,28 +267709,26 @@ void NSViewComponentPeer::drawRect (NSRect r) if (r.size.width < 1.0f || r.size.height < 1.0f) return; -#if USE_COREGRAPHICS_RENDERING CGContextRef cg = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; if (! component->isOpaque()) CGContextClearRect (cg, CGContextGetClipBoundingBox (cg)); +#if USE_COREGRAPHICS_RENDERING CoreGraphicsContext context (cg, [view frame].size.height); insideDrawRect = true; handlePaint (context); insideDrawRect = false; #else - const float y = [view frame].size.height - (r.origin.y + r.size.height); + Image temp (getComponent()->isOpaque() ? Image::RGB : Image::ARGB, + (int) (r.size.width + 0.5f), + (int) (r.size.height + 0.5f), + ! getComponent()->isOpaque()); - JuceNSImage temp ((int) (r.size.width + 0.5f), - (int) (r.size.height + 0.5f), - ! getComponent()->isOpaque()); - - LowLevelGraphicsSoftwareRenderer context (temp.getJuceImage()); - const int originX = -roundFloatToInt (r.origin.x); - const int originY = -roundFloatToInt (y); - context.setOrigin (originX, originY); + LowLevelGraphicsSoftwareRenderer context (temp); + context.setOrigin (-roundFloatToInt (r.origin.x), + -roundFloatToInt ([view frame].size.height - (r.origin.y + r.size.height))); const NSRect* rects = 0; NSInteger numRects = 0; @@ -267843,7 +267749,11 @@ void NSViewComponentPeer::drawRect (NSRect r) handlePaint (context); insideDrawRect = false; - temp.draw (r.origin.x, r.origin.y, clip, originX, originY); + CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); + CGImageRef image = CoreGraphicsImage::createImage (temp, false, colourSpace); + CGColorSpaceRelease (colourSpace); + CGContextDrawImage (cg, CGRectMake (r.origin.x, r.origin.y, temp.getWidth(), temp.getHeight()), image); + CGImageRelease (image); } #endif } @@ -267930,22 +267840,25 @@ ComponentPeer* Component::createNewPeer (int styleFlags, void* windowToAttachTo) return new NSViewComponentPeer (this, styleFlags, (NSView*) windowToAttachTo); } -static Image* NSImageToJuceImage (NSImage* image) -{ - JuceNSImage juceIm ((int) [image size].width, - (int) [image size].height, - true); - - juceIm.drawNSImage (image); - return juceIm.getJuceImage().createCopy(); -} - Image* juce_createIconForFile (const File& file) { const ScopedAutoReleasePool pool; - NSImage* im = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())]; - return NSImageToJuceImage (im); + NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())]; + + CoreGraphicsImage* result = new CoreGraphicsImage (Image::ARGB, (int) [image size].width, (int) [image size].height, true); + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: result->context flipped: false]]; + + [image drawAtPoint: NSMakePoint (0, 0) + fromRect: NSMakeRect (0, 0, [image size].width, [image size].height) + operation: NSCompositeSourceOver fraction: 1.0f]; + + [[NSGraphicsContext currentContext] flushGraphics]; + [NSGraphicsContext restoreGraphicsState]; + + return result; } const int KeyPress::spaceKey = ' '; @@ -268012,38 +267925,9 @@ const int KeyPress::rewindKey = 0x30003; #if JUCE_MAC -static NSImage* juceImageToNSImage (const Image& image) -{ - const ScopedAutoReleasePool pool; - - const Image::BitmapData srcData (image, 0, 0, image.getWidth(), image.getHeight()); - - NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: NULL - pixelsWide: srcData.width - pixelsHigh: srcData.height - bitsPerSample: 8 - samplesPerPixel: image.hasAlphaChannel() ? 4 : 3 - hasAlpha: image.hasAlphaChannel() - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bitmapFormat: (NSBitmapFormat) 0 - bytesPerRow: srcData.lineStride - bitsPerPixel: srcData.pixelStride * 8]; - - unsigned char* newData = [rep bitmapData]; - memcpy (newData, srcData.data, srcData.lineStride * srcData.height); - - NSImage* im = [[NSImage alloc] init]; - [im addRepresentation: rep]; - [rep release]; - - return im; -} - void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hotspotY) throw() { - NSImage* im = juceImageToNSImage (image); + NSImage* im = CoreGraphicsImage::createNSImage (image); NSCursor* c = [[NSCursor alloc] initWithImage: im hotSpot: NSMakePoint (hotspotX, hotspotY)]; [im release]; @@ -273104,63 +272988,12 @@ public: [session removeOutput: imageOutput]; } - static void drawNSBitmapIntoJuceImage (Image& dest, NSBitmapImageRep* source) + void callListeners (CIImage* frame, int w, int h) { - const ScopedAutoReleasePool pool; - - const Image::BitmapData destData (dest, 0, 0, dest.getWidth(), dest.getHeight(), true); - - NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: (unsigned char**) &(destData.data) - pixelsWide: destData.width - pixelsHigh: destData.height - bitsPerSample: 8 - samplesPerPixel: destData.pixelStride - hasAlpha: dest.hasAlphaChannel() - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bitmapFormat: (NSBitmapFormat) 0 - bytesPerRow: destData.lineStride - bitsPerPixel: destData.pixelStride * 8]; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithBitmapImageRep: rep]]; - - [source drawAtPoint: NSZeroPoint]; - - [[NSGraphicsContext currentContext] flushGraphics]; - [NSGraphicsContext restoreGraphicsState]; - - uint8* start = destData.data; - for (int h = dest.getHeight(); --h >= 0;) - { - uint8* p = start; - start += destData.lineStride; - - for (int i = dest.getWidth(); --i >= 0;) - { -#if JUCE_BIG_ENDIAN - const uint8 oldp3 = p[3]; - const uint8 oldp1 = p[1]; - p[3] = p[0]; - p[0] = oldp1; - p[1] = p[2]; - p[2] = oldp3; -#else - const uint8 oldp0 = p[0]; - p[0] = p[2]; - p[2] = oldp0; -#endif - - p += destData.pixelStride; - } - } - } - - void callListeners (NSBitmapImageRep* bitmap) - { - Image image (Image::ARGB, [bitmap size].width, [bitmap size].height, false); - drawNSBitmapIntoJuceImage (image, bitmap); + CoreGraphicsImage image (Image::ARGB, w, h, false); + CIContext* cic = [CIContext contextWithCGContext: image.context options: nil]; + [cic drawImage: frame inRect: CGRectMake (0, 0, w, h) fromRect: CGRectMake (0, 0, w, h)]; + CGContextFlush (image.context); const ScopedLock sl (listenerLock); @@ -273210,10 +273043,10 @@ END_JUCE_NAMESPACE fromConnection: (QTCaptureConnection*) connection { const ScopedAutoReleasePool pool; - CIImage* image = [CIImage imageWithCVImageBuffer: videoFrame]; - NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc] initWithCIImage: image] autorelease]; - internal->callListeners (bitmap); + internal->callListeners ([CIImage imageWithCVImageBuffer: videoFrame], + CVPixelBufferGetWidth (videoFrame), + CVPixelBufferGetHeight (videoFrame)); } - (void) captureOutput: (QTCaptureFileOutput*) captureOutput diff --git a/src/gui/components/code_editor/juce_CodeEditorComponent.cpp b/src/gui/components/code_editor/juce_CodeEditorComponent.cpp index bdbe1b2803..b04bc05924 100644 --- a/src/gui/components/code_editor/juce_CodeEditorComponent.cpp +++ b/src/gui/components/code_editor/juce_CodeEditorComponent.cpp @@ -618,8 +618,11 @@ void CodeEditorComponent::insertTextAtCaret (const String& newText) void CodeEditorComponent::insertTabAtCaret() { - if (CharacterFunctions::isWhitespace (caretPos.getCharacter())) + if (CharacterFunctions::isWhitespace (caretPos.getCharacter()) + && caretPos.getLineNumber() == caretPos.movedBy (1).getLineNumber()) + { moveCaretTo (document.findWordBreakAfter (caretPos), false); + } if (useSpacesForTabs) { diff --git a/src/native/mac/juce_mac_CameraDevice.mm b/src/native/mac/juce_mac_CameraDevice.mm index ec9e8c38cc..2ef59760e0 100644 --- a/src/native/mac/juce_mac_CameraDevice.mm +++ b/src/native/mac/juce_mac_CameraDevice.mm @@ -145,63 +145,12 @@ public: [session removeOutput: imageOutput]; } - static void drawNSBitmapIntoJuceImage (Image& dest, NSBitmapImageRep* source) + void callListeners (CIImage* frame, int w, int h) { - const ScopedAutoReleasePool pool; - - const Image::BitmapData destData (dest, 0, 0, dest.getWidth(), dest.getHeight(), true); - - NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: (unsigned char**) &(destData.data) - pixelsWide: destData.width - pixelsHigh: destData.height - bitsPerSample: 8 - samplesPerPixel: destData.pixelStride - hasAlpha: dest.hasAlphaChannel() - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bitmapFormat: (NSBitmapFormat) 0 - bytesPerRow: destData.lineStride - bitsPerPixel: destData.pixelStride * 8]; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithBitmapImageRep: rep]]; - - [source drawAtPoint: NSZeroPoint]; - - [[NSGraphicsContext currentContext] flushGraphics]; - [NSGraphicsContext restoreGraphicsState]; - - uint8* start = destData.data; - for (int h = dest.getHeight(); --h >= 0;) - { - uint8* p = start; - start += destData.lineStride; - - for (int i = dest.getWidth(); --i >= 0;) - { -#if JUCE_BIG_ENDIAN - const uint8 oldp3 = p[3]; - const uint8 oldp1 = p[1]; - p[3] = p[0]; - p[0] = oldp1; - p[1] = p[2]; - p[2] = oldp3; -#else - const uint8 oldp0 = p[0]; - p[0] = p[2]; - p[2] = oldp0; -#endif - - p += destData.pixelStride; - } - } - } - - void callListeners (NSBitmapImageRep* bitmap) - { - Image image (Image::ARGB, [bitmap size].width, [bitmap size].height, false); - drawNSBitmapIntoJuceImage (image, bitmap); + CoreGraphicsImage image (Image::ARGB, w, h, false); + CIContext* cic = [CIContext contextWithCGContext: image.context options: nil]; + [cic drawImage: frame inRect: CGRectMake (0, 0, w, h) fromRect: CGRectMake (0, 0, w, h)]; + CGContextFlush (image.context); const ScopedLock sl (listenerLock); @@ -251,10 +200,10 @@ END_JUCE_NAMESPACE fromConnection: (QTCaptureConnection*) connection { const ScopedAutoReleasePool pool; - CIImage* image = [CIImage imageWithCVImageBuffer: videoFrame]; - NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc] initWithCIImage: image] autorelease]; - internal->callListeners (bitmap); + internal->callListeners ([CIImage imageWithCVImageBuffer: videoFrame], + CVPixelBufferGetWidth (videoFrame), + CVPixelBufferGetHeight (videoFrame)); } - (void) captureOutput: (QTCaptureFileOutput*) captureOutput diff --git a/src/native/mac/juce_mac_CoreGraphicsContext.mm b/src/native/mac/juce_mac_CoreGraphicsContext.mm index 4c172fbf84..555b202d87 100644 --- a/src/native/mac/juce_mac_CoreGraphicsContext.mm +++ b/src/native/mac/juce_mac_CoreGraphicsContext.mm @@ -31,6 +31,7 @@ class CoreGraphicsImage : public Image { public: + //============================================================================== CoreGraphicsImage (const PixelFormat format, const int imageWidth, const int imageHeight, @@ -41,9 +42,7 @@ public: : CGColorSpaceCreateDeviceRGB(); context = CGBitmapContextCreate (imageData, imageWidth, imageHeight, 8, lineStride, - colourSpace, - format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) - : kCGBitmapByteOrderDefault); + colourSpace, getCGImageFlags (*this)); CGColorSpaceRelease (colourSpace); } @@ -55,7 +54,64 @@ public: LowLevelGraphicsContext* createLowLevelContext(); + //============================================================================== + static CGImageRef createImage (const Image& juceImage, const bool forAlpha, CGColorSpaceRef colourSpace) throw() + { + const CoreGraphicsImage* nativeImage = dynamic_cast (&juceImage); + + if (nativeImage != 0 && (juceImage.getFormat() == Image::SingleChannel || ! forAlpha)) + { + return CGBitmapContextCreateImage (nativeImage->context); + } + else + { + const Image::BitmapData srcData (juceImage, 0, 0, juceImage.getWidth(), juceImage.getHeight()); + + CGDataProviderRef provider = CGDataProviderCreateWithData (0, srcData.data, srcData.lineStride * srcData.pixelStride, 0); + + CGImageRef imageRef = CGImageCreate (srcData.width, srcData.height, + 8, srcData.pixelStride * 8, srcData.lineStride, + colourSpace, getCGImageFlags (juceImage), provider, + 0, true, kCGRenderingIntentDefault); + + CGDataProviderRelease (provider); + return imageRef; + } + } + + static NSImage* createNSImage (const Image& image) + { + const ScopedAutoReleasePool pool; + + NSImage* im = [[NSImage alloc] init]; + [im setSize: NSMakeSize (image.getWidth(), image.getHeight())]; + [im lockFocus]; + + CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); + CGImageRef imageRef = createImage (image, false, colourSpace); + CGColorSpaceRelease (colourSpace); + + CGContextRef cg = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; + CGContextDrawImage (cg, CGRectMake (0, 0, image.getWidth(), image.getHeight()), imageRef); + + CGImageRelease (imageRef); + [im unlockFocus]; + + return im; + } + + //============================================================================== CGContextRef context; + +private: + static CGBitmapInfo getCGImageFlags (const Image& image) throw() + { +#if JUCE_BIG_ENDIAN + return image.getFormat() == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) : kCGBitmapByteOrderDefault; +#else + return image.getFormat() == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) : kCGBitmapByteOrderDefault; +#endif + } }; Image* Image::createNativeImage (const PixelFormat format, const int imageWidth, const int imageHeight, const bool clearImage) @@ -146,7 +202,7 @@ public: if (! transform.isSingularity()) { Image* singleChannelImage = createAlphaChannelImage (sourceImage); - CGImageRef image = createImage (*singleChannelImage, true); + CGImageRef image = CoreGraphicsImage::createImage (*singleChannelImage, true, greyColourSpace); flip(); AffineTransform t (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); @@ -315,7 +371,7 @@ public: void drawImage (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform, const bool fillEntireClipAsTiles) { - CGImageRef fullImage = createImage (sourceImage, false); + CGImageRef fullImage = CoreGraphicsImage::createImage (sourceImage, false, rgbColourSpace); CGImageRef image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), sourceImage.getHeight() - srcClip.getBottom(), srcClip.getWidth(), srcClip.getHeight())); CGImageRelease (fullImage); @@ -614,35 +670,6 @@ private: } } - CGImageRef createImage (const Image& juceImage, const bool forAlpha) const throw() - { - const CoreGraphicsImage* nativeImage = dynamic_cast (&juceImage); - - if (nativeImage != 0 && (juceImage.getFormat() == Image::SingleChannel || ! forAlpha)) - { - return CGBitmapContextCreateImage (nativeImage->context); - } - else - { - const Image::BitmapData srcData (juceImage, 0, 0, juceImage.getWidth(), juceImage.getHeight()); - - CGDataProviderRef provider = CGDataProviderCreateWithData (0, srcData.data, srcData.lineStride * srcData.pixelStride, 0); - CGColorSpaceRef colourSpace = forAlpha ? greyColourSpace : rgbColourSpace; - - CGImageRef imageRef = CGImageCreate (srcData.width, srcData.height, - 8, srcData.pixelStride * 8, srcData.lineStride, - colourSpace, - (juceImage.hasAlphaChannel() && ! forAlpha) - ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) - : kCGBitmapByteOrderDefault, - provider, - 0, true, kCGRenderingIntentDefault); - - CGDataProviderRelease (provider); - return imageRef; - } - } - static Image* createAlphaChannelImage (const Image& im) throw() { if (im.getFormat() == Image::SingleChannel) diff --git a/src/native/mac/juce_mac_MouseCursor.mm b/src/native/mac/juce_mac_MouseCursor.mm index ab493bbe19..ea5f0e9690 100644 --- a/src/native/mac/juce_mac_MouseCursor.mm +++ b/src/native/mac/juce_mac_MouseCursor.mm @@ -29,40 +29,11 @@ #if JUCE_MAC -//============================================================================== -static NSImage* juceImageToNSImage (const Image& image) -{ - const ScopedAutoReleasePool pool; - - const Image::BitmapData srcData (image, 0, 0, image.getWidth(), image.getHeight()); - - NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: NULL - pixelsWide: srcData.width - pixelsHigh: srcData.height - bitsPerSample: 8 - samplesPerPixel: image.hasAlphaChannel() ? 4 : 3 - hasAlpha: image.hasAlphaChannel() - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bitmapFormat: (NSBitmapFormat) 0 - bytesPerRow: srcData.lineStride - bitsPerPixel: srcData.pixelStride * 8]; - - unsigned char* newData = [rep bitmapData]; - memcpy (newData, srcData.data, srcData.lineStride * srcData.height); - - NSImage* im = [[NSImage alloc] init]; - [im addRepresentation: rep]; - [rep release]; - - return im; -} //============================================================================== void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hotspotY) throw() { - NSImage* im = juceImageToNSImage (image); + NSImage* im = CoreGraphicsImage::createNSImage (image); NSCursor* c = [[NSCursor alloc] initWithImage: im hotSpot: NSMakePoint (hotspotX, hotspotY)]; [im release]; diff --git a/src/native/mac/juce_mac_NSViewComponentPeer.mm b/src/native/mac/juce_mac_NSViewComponentPeer.mm index f84c186771..cf500b6fb1 100644 --- a/src/native/mac/juce_mac_NSViewComponentPeer.mm +++ b/src/native/mac/juce_mac_NSViewComponentPeer.mm @@ -555,123 +555,6 @@ END_JUCE_NAMESPACE //============================================================================== BEGIN_JUCE_NAMESPACE -//============================================================================== -class JuceNSImage -{ -public: - JuceNSImage (const int width, const int height, const bool hasAlpha) - : juceImage (hasAlpha ? Image::ARGB : Image::RGB, - width, height, hasAlpha), - srcData (juceImage, 0, 0, width, height) - { - imageRep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: (unsigned char**) &(srcData.data) - pixelsWide: width - pixelsHigh: height - bitsPerSample: 8 - samplesPerPixel: srcData.pixelStride - hasAlpha: hasAlpha - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bitmapFormat: /*NSAlphaFirstBitmapFormat*/ (NSBitmapFormat) 0 - bytesPerRow: srcData.lineStride - bitsPerPixel: 8 * srcData.pixelStride ]; - } - - ~JuceNSImage() - { - [imageRep release]; - } - - Image& getJuceImage() throw() { return juceImage; } - - void draw (const float x, const float y, - const RectangleList& clip, - const int originX, const int originY) const - { - // Our data is BGRA and the damned image rep only takes RGBA, so - // we need to byte-swap the active areas if there's an alpha channel... - if (juceImage.hasAlphaChannel()) - { - RectangleList::Iterator iter (clip); - while (iter.next()) - { - const Rectangle* const r = iter.getRectangle(); - - swapRGBOrder (r->getX() + originX, - r->getY() + originY, - r->getWidth(), - r->getHeight()); - } - } - - NSPoint p; - p.x = x; - p.y = y; - [imageRep drawAtPoint: p]; - } - - void drawNSImage (NSImage* imageToDraw) - { - const ScopedAutoReleasePool pool; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext: - [NSGraphicsContext graphicsContextWithBitmapImageRep: imageRep]]; - - [imageToDraw drawAtPoint: NSZeroPoint - fromRect: NSMakeRect (0, 0, [imageToDraw size].width, [imageToDraw size].height) - operation: NSCompositeSourceOver - fraction: 1.0f]; - - [[NSGraphicsContext currentContext] flushGraphics]; - [NSGraphicsContext restoreGraphicsState]; - - if (juceImage.hasAlphaChannel()) - swapRGBOrder (0, 0, juceImage.getWidth(), juceImage.getHeight()); - } - -private: - Image juceImage; - NSBitmapImageRep* imageRep; - const Image::BitmapData srcData; - - void swapRGBOrder (const int x, const int y, const int w, int h) const - { -#if JUCE_BIG_ENDIAN - jassert (srcData.pixelStride == 4); -#endif - jassert (Rectangle (0, 0, juceImage.getWidth(), juceImage.getHeight()) - .contains (Rectangle (x, y, w, h))); - - uint8* start = srcData.getPixelPointer (x, y); - - while (--h >= 0) - { - uint8* p = start; - start += srcData.lineStride; - - for (int i = w; --i >= 0;) - { -#if JUCE_BIG_ENDIAN - const uint8 oldp3 = p[3]; - const uint8 oldp1 = p[1]; - p[3] = p[0]; - p[0] = oldp1; - p[1] = p[2]; - p[2] = oldp3; -#else - const uint8 oldp0 = p[0]; - p[0] = p[2]; - p[2] = oldp0; -#endif - - p += srcData.pixelStride; - } - } - } -}; - //============================================================================== static ComponentPeer* currentlyFocusedPeer = 0; static VoidArray keysCurrentlyDown; @@ -1435,28 +1318,26 @@ void NSViewComponentPeer::drawRect (NSRect r) if (r.size.width < 1.0f || r.size.height < 1.0f) return; -#if USE_COREGRAPHICS_RENDERING CGContextRef cg = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; if (! component->isOpaque()) CGContextClearRect (cg, CGContextGetClipBoundingBox (cg)); +#if USE_COREGRAPHICS_RENDERING CoreGraphicsContext context (cg, [view frame].size.height); insideDrawRect = true; handlePaint (context); insideDrawRect = false; #else - const float y = [view frame].size.height - (r.origin.y + r.size.height); + Image temp (getComponent()->isOpaque() ? Image::RGB : Image::ARGB, + (int) (r.size.width + 0.5f), + (int) (r.size.height + 0.5f), + ! getComponent()->isOpaque()); - JuceNSImage temp ((int) (r.size.width + 0.5f), - (int) (r.size.height + 0.5f), - ! getComponent()->isOpaque()); - - LowLevelGraphicsSoftwareRenderer context (temp.getJuceImage()); - const int originX = -roundFloatToInt (r.origin.x); - const int originY = -roundFloatToInt (y); - context.setOrigin (originX, originY); + LowLevelGraphicsSoftwareRenderer context (temp); + context.setOrigin (-roundFloatToInt (r.origin.x), + -roundFloatToInt ([view frame].size.height - (r.origin.y + r.size.height))); const NSRect* rects = 0; NSInteger numRects = 0; @@ -1477,7 +1358,11 @@ void NSViewComponentPeer::drawRect (NSRect r) handlePaint (context); insideDrawRect = false; - temp.draw (r.origin.x, r.origin.y, clip, originX, originY); + CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); + CGImageRef image = CoreGraphicsImage::createImage (temp, false, colourSpace); + CGColorSpaceRelease (colourSpace); + CGContextDrawImage (cg, CGRectMake (r.origin.x, r.origin.y, temp.getWidth(), temp.getHeight()), image); + CGImageRelease (image); } #endif } @@ -1567,22 +1452,25 @@ ComponentPeer* Component::createNewPeer (int styleFlags, void* windowToAttachTo) } //============================================================================== -static Image* NSImageToJuceImage (NSImage* image) -{ - JuceNSImage juceIm ((int) [image size].width, - (int) [image size].height, - true); - - juceIm.drawNSImage (image); - return juceIm.getJuceImage().createCopy(); -} - Image* juce_createIconForFile (const File& file) { const ScopedAutoReleasePool pool; - NSImage* im = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())]; - return NSImageToJuceImage (im); + NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())]; + + CoreGraphicsImage* result = new CoreGraphicsImage (Image::ARGB, (int) [image size].width, (int) [image size].height, true); + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: result->context flipped: false]]; + + [image drawAtPoint: NSMakePoint (0, 0) + fromRect: NSMakeRect (0, 0, [image size].width, [image size].height) + operation: NSCompositeSourceOver fraction: 1.0f]; + + [[NSGraphicsContext currentContext] flushGraphics]; + [NSGraphicsContext restoreGraphicsState]; + + return result; } //==============================================================================