1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-11 23:54:18 +00:00

More graphics updates, including fixes for CoreGraphics on PPC macs. Fix for keypress recursion in AU plugins, and fix for tabs in the CodeEditorComponent

This commit is contained in:
Julian Storer 2009-11-30 19:21:25 +00:00
parent 01f109e857
commit 95fcc168d8
7 changed files with 271 additions and 594 deletions

View file

@ -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;

View file

@ -730,7 +730,7 @@ public:
the rest of the codebase.
*/
#define USE_COREGRAPHICS_RENDERING 0
#define USE_COREGRAPHICS_RENDERING 1
#if JUCE_IPHONE
#import <Foundation/Foundation.h>
@ -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 <const CoreGraphicsImage*> (&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 <const CoreGraphicsImage*> (&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 <const CoreGraphicsImage*> (&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 <const CoreGraphicsImage*> (&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

View file

@ -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)
{

View file

@ -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

View file

@ -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 <const CoreGraphicsImage*> (&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 <const CoreGraphicsImage*> (&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)

View file

@ -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];

View file

@ -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;
}
//==============================================================================