Bug 574778 - Fix win widget's ConstrainPosition so that it supports full screen windo...
[mozilla-central.git] / gfx / thebes / nsCoreAnimationSupport.mm
blob426122aba8cbe58786fbf48309925746aa1d4319
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:set ts=2 sts=2 sw=2 et cin:
3 /* ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is Mozilla.org code.
17  *
18  * The Initial Developer of the Original Code is
19  * Mozilla Corporation.
20  * Portions created by the Initial Developer are Copyright (C) 2008
21  * the Initial Developer. All Rights Reserved.
22  *
23  * Contributor(s):
24  *   Benoit Girard <b56girard@gmail.com>
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either of the GNU General Public License Version 2 or later (the "GPL"),
28  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
40 #include "nsCoreAnimationSupport.h"
41 #include "nsDebug.h"
43 #import <QuartzCore/QuartzCore.h>
44 #include <dlfcn.h>
46 #define IOSURFACE_FRAMEWORK_PATH \
47   "/System/Library/Frameworks/IOSurface.framework/IOSurface"
48 #define OPENGL_FRAMEWORK_PATH \
49   "/System/Library/Frameworks/OpenGL.framework/OpenGL"
52 // IOSurface signatures
53 typedef CFTypeRef IOSurfacePtr;
54 typedef IOSurfacePtr (*IOSurfaceCreateFunc) (CFDictionaryRef properties);
55 typedef IOSurfacePtr (*IOSurfaceLookupFunc) (uint32_t io_surface_id);
56 typedef IOSurfaceID (*IOSurfaceGetIDFunc) (CFTypeRef io_surface);
57 typedef IOReturn (*IOSurfaceLockFunc) (CFTypeRef io_surface, 
58                                        uint32_t options, 
59                                        uint32_t *seed);
60 typedef IOReturn (*IOSurfaceUnlockFunc) (CFTypeRef io_surface, 
61                                          uint32_t options, 
62                                          uint32_t *seed);
63 typedef void* (*IOSurfaceGetBaseAddressFunc) (CFTypeRef io_surface);
64 typedef size_t (*IOSurfaceGetWidthFunc) (IOSurfacePtr io_surface);
65 typedef size_t (*IOSurfaceGetHeightFunc) (IOSurfacePtr io_surface);
66 typedef size_t (*IOSurfaceGetBytesPerRowFunc) (IOSurfacePtr io_surface);
67 typedef CGLError (*CGLTexImageIOSurface2DFunc) (CGLContextObj ctxt,
68                              GLenum target, GLenum internalFormat,
69                              GLsizei width, GLsizei height,
70                              GLenum format, GLenum type,
71                              IOSurfacePtr ioSurface, GLuint plane);
73 #define GET_CONST(const_name) \
74   ((CFStringRef*) dlsym(sIOSurfaceFramework, const_name))
75 #define GET_IOSYM(dest,sym_name) \
76   (typeof(dest)) dlsym(sIOSurfaceFramework, sym_name)
77 #define GET_CGLSYM(dest,sym_name) \
78   (typeof(dest)) dlsym(sOpenGLFramework, sym_name)
80 class nsIOSurfaceLib: public nsIOSurface {
81 public:
82   static void                        *sIOSurfaceFramework;
83   static void                        *sOpenGLFramework;
84   static bool                         isLoaded;
85   static IOSurfaceCreateFunc          sCreate;
86   static IOSurfaceGetIDFunc           sGetID;
87   static IOSurfaceLookupFunc          sLookup;
88   static IOSurfaceGetBaseAddressFunc  sGetBaseAddress;
89   static IOSurfaceLockFunc            sLock;
90   static IOSurfaceUnlockFunc          sUnlock;
91   static IOSurfaceGetWidthFunc        sWidth;
92   static IOSurfaceGetHeightFunc       sHeight;
93   static IOSurfaceGetBytesPerRowFunc  sBytesPerRow;
94   static CGLTexImageIOSurface2DFunc   sTexImage;
95   static CFStringRef                  kPropWidth;
96   static CFStringRef                  kPropHeight;
97   static CFStringRef                  kPropBytesPerElem;
98   static CFStringRef                  kPropBytesPerRow;
99   static CFStringRef                  kPropIsGlobal;
101   static bool isInit();
102   static CFStringRef GetIOConst(const char* symbole);
103   static IOSurfacePtr IOSurfaceCreate(CFDictionaryRef properties);
104   static IOSurfacePtr IOSurfaceLookup(IOSurfaceID aIOSurfaceID);
105   static IOSurfaceID  IOSurfaceGetID(IOSurfacePtr aIOSurfacePtr);
106   static void        *IOSurfaceGetBaseAddress(IOSurfacePtr aIOSurfacePtr);
107   static size_t       IOSurfaceGetWidth(IOSurfacePtr aIOSurfacePtr);
108   static size_t       IOSurfaceGetHeight(IOSurfacePtr aIOSurfacePtr);
109   static size_t       IOSurfaceGetBytesPerRow(IOSurfacePtr aIOSurfacePtr);
110   static IOReturn     IOSurfaceLock(IOSurfacePtr aIOSurfacePtr, 
111                                     uint32_t options, uint32_t *seed);
112   static IOReturn     IOSurfaceUnlock(IOSurfacePtr aIOSurfacePtr, 
113                                       uint32_t options, uint32_t *seed);
114   static CGLError     CGLTexImageIOSurface2D(CGLContextObj ctxt,
115                              GLenum target, GLenum internalFormat,
116                              GLsizei width, GLsizei height,
117                              GLenum format, GLenum type,
118                              IOSurfacePtr ioSurface, GLuint plane);
119   static void LoadLibrary();
120   static void CloseLibrary();
122   // Static deconstructor
123   static class LibraryUnloader {
124   public:
125     ~LibraryUnloader() {
126       CloseLibrary();
127     }
128   } sLibraryUnloader;
131 nsIOSurfaceLib::LibraryUnloader nsIOSurfaceLib::sLibraryUnloader;
132 bool                          nsIOSurfaceLib::isLoaded = false;
133 void*                         nsIOSurfaceLib::sIOSurfaceFramework;
134 void*                         nsIOSurfaceLib::sOpenGLFramework;
135 IOSurfaceCreateFunc           nsIOSurfaceLib::sCreate;
136 IOSurfaceGetIDFunc            nsIOSurfaceLib::sGetID;
137 IOSurfaceLookupFunc           nsIOSurfaceLib::sLookup;
138 IOSurfaceGetBaseAddressFunc   nsIOSurfaceLib::sGetBaseAddress;
139 IOSurfaceGetHeightFunc        nsIOSurfaceLib::sWidth;
140 IOSurfaceGetWidthFunc         nsIOSurfaceLib::sHeight;
141 IOSurfaceGetBytesPerRowFunc   nsIOSurfaceLib::sBytesPerRow;
142 IOSurfaceLockFunc             nsIOSurfaceLib::sLock;
143 IOSurfaceUnlockFunc           nsIOSurfaceLib::sUnlock;
144 CGLTexImageIOSurface2DFunc    nsIOSurfaceLib::sTexImage;
145 CFStringRef                   nsIOSurfaceLib::kPropWidth;
146 CFStringRef                   nsIOSurfaceLib::kPropHeight;
147 CFStringRef                   nsIOSurfaceLib::kPropBytesPerElem;
148 CFStringRef                   nsIOSurfaceLib::kPropBytesPerRow;
149 CFStringRef                   nsIOSurfaceLib::kPropIsGlobal;
151 bool nsIOSurfaceLib::isInit() {
152   // Guard against trying to reload the library
153   // if it is not available.
154   if (!isLoaded)
155     LoadLibrary();
156   if (!sIOSurfaceFramework) {
157     NS_ERROR("nsIOSurfaceLib failed to initialize");
158   }
159   return sIOSurfaceFramework;
162 IOSurfacePtr nsIOSurfaceLib::IOSurfaceCreate(CFDictionaryRef properties) {
163   return sCreate(properties);
166 IOSurfacePtr nsIOSurfaceLib::IOSurfaceLookup(IOSurfaceID aIOSurfaceID) {
167   return sLookup(aIOSurfaceID);
170 IOSurfaceID nsIOSurfaceLib::IOSurfaceGetID(IOSurfacePtr aIOSurfacePtr) {
171   return sGetID(aIOSurfacePtr);
174 void* nsIOSurfaceLib::IOSurfaceGetBaseAddress(IOSurfacePtr aIOSurfacePtr) {
175   return sGetBaseAddress(aIOSurfacePtr);
178 size_t nsIOSurfaceLib::IOSurfaceGetWidth(IOSurfacePtr aIOSurfacePtr) {
179   return sWidth(aIOSurfacePtr);
182 size_t nsIOSurfaceLib::IOSurfaceGetHeight(IOSurfacePtr aIOSurfacePtr) {
183   return sHeight(aIOSurfacePtr);
186 size_t nsIOSurfaceLib::IOSurfaceGetBytesPerRow(IOSurfacePtr aIOSurfacePtr) {
187   return sBytesPerRow(aIOSurfacePtr);
190 IOReturn nsIOSurfaceLib::IOSurfaceLock(IOSurfacePtr aIOSurfacePtr, 
191                                        uint32_t options, uint32_t *seed) {
192   return sLock(aIOSurfacePtr, options, seed);
195 IOReturn nsIOSurfaceLib::IOSurfaceUnlock(IOSurfacePtr aIOSurfacePtr, 
196                                          uint32_t options, uint32_t *seed) {
197   return sUnlock(aIOSurfacePtr, options, seed);
200 CGLError nsIOSurfaceLib::CGLTexImageIOSurface2D(CGLContextObj ctxt,
201                              GLenum target, GLenum internalFormat,
202                              GLsizei width, GLsizei height,
203                              GLenum format, GLenum type,
204                              IOSurfacePtr ioSurface, GLuint plane) {
205   return sTexImage(ctxt, target, internalFormat, width, height, 
206                    format, type, ioSurface, plane);
209 CFStringRef nsIOSurfaceLib::GetIOConst(const char* symbole) {
210   CFStringRef *address = (CFStringRef*)dlsym(sIOSurfaceFramework, symbole);
211   if (!address)
212     return nsnull;
214   return *address;
217 void nsIOSurfaceLib::LoadLibrary() {
218   if (isLoaded) {
219     return;
220   } 
221   isLoaded = true;
222   sIOSurfaceFramework = dlopen(IOSURFACE_FRAMEWORK_PATH, 
223                             RTLD_LAZY | RTLD_LOCAL);
224   sOpenGLFramework = dlopen(OPENGL_FRAMEWORK_PATH, 
225                             RTLD_LAZY | RTLD_LOCAL);
226   if (!sIOSurfaceFramework) {
227     return;
228   }
229   if (!sOpenGLFramework) {
230     dlclose(sIOSurfaceFramework);
231     sIOSurfaceFramework = nsnull;
232     return;
233   }
235   kPropWidth = GetIOConst("kIOSurfaceWidth");
236   kPropHeight = GetIOConst("kIOSurfaceHeight");
237   kPropBytesPerElem = GetIOConst("kIOSurfaceBytesPerElement");
238   kPropBytesPerRow = GetIOConst("kIOSurfaceBytesPerRow");
239   kPropIsGlobal = GetIOConst("kIOSurfaceIsGlobal");
240   sCreate = GET_IOSYM(sCreate, "IOSurfaceCreate");
241   sGetID  = GET_IOSYM(sGetID,  "IOSurfaceGetID");
242   sWidth = GET_IOSYM(sWidth, "IOSurfaceGetWidth");
243   sHeight = GET_IOSYM(sHeight, "IOSurfaceGetHeight");
244   sBytesPerRow = GET_IOSYM(sBytesPerRow, "IOSurfaceGetBytesPerRow");
245   sLookup = GET_IOSYM(sLookup, "IOSurfaceLookup");
246   sLock = GET_IOSYM(sLock, "IOSurfaceLock");
247   sUnlock = GET_IOSYM(sUnlock, "IOSurfaceUnlock");
248   sGetBaseAddress = GET_IOSYM(sGetBaseAddress, "IOSurfaceGetBaseAddress");
249   sTexImage = GET_CGLSYM(sTexImage, "CGLTexImageIOSurface2D");
251   if (!sCreate || !sGetID || !sLookup || !sTexImage || !sGetBaseAddress ||
252       !kPropWidth || !kPropHeight || !kPropBytesPerElem || !kPropIsGlobal ||
253       !sLock || !sUnlock || !sWidth || !sHeight || !kPropBytesPerRow ||
254       !sBytesPerRow) {
255     CloseLibrary();
256   }
259 void nsIOSurfaceLib::CloseLibrary() {
260   if (sIOSurfaceFramework) {
261     dlclose(sIOSurfaceFramework);
262   }
263   if (sOpenGLFramework) {
264     dlclose(sOpenGLFramework);
265   }
266   sIOSurfaceFramework = nsnull;
267   sOpenGLFramework = nsnull;
270 nsIOSurface* nsIOSurface::CreateIOSurface(int aWidth, int aHeight) { 
271   if (!nsIOSurfaceLib::isInit())
272     return nsnull;
274   CFMutableDictionaryRef props = ::CFDictionaryCreateMutable(
275                       kCFAllocatorDefault, 4,
276                       &kCFTypeDictionaryKeyCallBacks,
277                       &kCFTypeDictionaryValueCallBacks);
278   if (!props)
279     return nsnull;
281   int32_t bytesPerElem = 4;
282   CFNumberRef cfWidth = ::CFNumberCreate(NULL, kCFNumberSInt32Type, &aWidth);
283   CFNumberRef cfHeight = ::CFNumberCreate(NULL, kCFNumberSInt32Type, &aHeight);
284   CFNumberRef cfBytesPerElem = ::CFNumberCreate(NULL, kCFNumberSInt32Type, &bytesPerElem);
285   ::CFDictionaryAddValue(props, nsIOSurfaceLib::kPropWidth,
286                                 cfWidth);
287   ::CFRelease(cfWidth);
288   ::CFDictionaryAddValue(props, nsIOSurfaceLib::kPropHeight,
289                                 cfHeight);
290   ::CFRelease(cfHeight);
291   ::CFDictionaryAddValue(props, nsIOSurfaceLib::kPropBytesPerElem, 
292                                 cfBytesPerElem);
293   ::CFRelease(cfBytesPerElem);
294   ::CFDictionaryAddValue(props, nsIOSurfaceLib::kPropIsGlobal, 
295                                 kCFBooleanTrue);
297   IOSurfacePtr surfaceRef = nsIOSurfaceLib::IOSurfaceCreate(props);
298   ::CFRelease(props);
300   if (!surfaceRef)
301     return nsnull;
303   nsIOSurface* ioSurface = new nsIOSurface(surfaceRef);
304   if (!ioSurface) {
305     ::CFRelease(surfaceRef);
306     return nsnull;
307   }
309   return ioSurface;
312 nsIOSurface* nsIOSurface::LookupSurface(IOSurfaceID aIOSurfaceID) { 
313   if (!nsIOSurfaceLib::isInit())
314     return nsnull;
316   IOSurfacePtr surfaceRef = nsIOSurfaceLib::IOSurfaceLookup(aIOSurfaceID);
317   if (!surfaceRef)
318     return nsnull;
319   // IOSurfaceLookup does not retain the object for us,
320   // we want IOSurfacePtr to remain for the lifetime of
321   // nsIOSurface.
322   CFRetain(surfaceRef);
324   nsIOSurface* ioSurface = new nsIOSurface(surfaceRef);
325   if (!ioSurface) {
326     ::CFRelease(ioSurface);
327     return nsnull;
328   }
329   return ioSurface;
332 IOSurfaceID nsIOSurface::GetIOSurfaceID() { 
333   return nsIOSurfaceLib::IOSurfaceGetID(mIOSurfacePtr);
336 void* nsIOSurface::GetBaseAddress() { 
337   return nsIOSurfaceLib::IOSurfaceGetBaseAddress(mIOSurfacePtr);
340 size_t nsIOSurface::GetWidth() { 
341   return nsIOSurfaceLib::IOSurfaceGetWidth(mIOSurfacePtr);
344 size_t nsIOSurface::GetHeight() { 
345   return nsIOSurfaceLib::IOSurfaceGetHeight(mIOSurfacePtr);
348 size_t nsIOSurface::GetBytesPerRow() { 
349   return nsIOSurfaceLib::IOSurfaceGetBytesPerRow(mIOSurfacePtr);
352 #define READ_ONLY 0x1
353 void nsIOSurface::Lock() {
354   nsIOSurfaceLib::IOSurfaceLock(mIOSurfacePtr, READ_ONLY, NULL);
357 void nsIOSurface::Unlock() {
358   nsIOSurfaceLib::IOSurfaceUnlock(mIOSurfacePtr, READ_ONLY, NULL);
361 nsCARenderer::~nsCARenderer() {
362   Destroy();
365 CGColorSpaceRef CreateSystemColorSpace() {
366     CMProfileRef system_profile = nsnull;
367     CGColorSpaceRef cspace = nsnull;
369     if (::CMGetSystemProfile(&system_profile) == noErr) {
370       // Create a colorspace with the systems profile
371       cspace = ::CGColorSpaceCreateWithPlatformColorSpace(system_profile);
372       ::CMCloseProfile(system_profile);
373     } else {
374       // Default to generic
375       cspace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
376     }
378     return cspace;
381 void cgdata_release_callback(void *aCGData, const void *data, size_t size) {
382   if (aCGData) {
383     free(aCGData);
384   }
387 void nsCARenderer::Destroy() {
388   if (mCARenderer) {
389     CARenderer* caRenderer = (CARenderer*)mCARenderer;
390     // Bug 556453:
391     // Explicitly remove the layer from the renderer
392     // otherwise it does not always happen right away.
393     caRenderer.layer = nsnull;
394     [caRenderer release];
395   }
396   if (mPixelBuffer) {
397     ::CGLDestroyPBuffer((CGLPBufferObj)mPixelBuffer);
398   }
399   if (mOpenGLContext) {
400     if (mFBO || mIOTexture) {
401       // Release these resources with the context that allocated them
402       CGLContextObj oldContext = ::CGLGetCurrentContext();
403       ::CGLSetCurrentContext(mOpenGLContext);
405       if (mIOTexture) {
406         ::glDeleteTextures(1, &mIOTexture);
407       }
408       if (mFBO) {
409         ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
410         ::glDeleteFramebuffersEXT(1, &mFBO);
411       }
413       if (oldContext)
414         ::CGLSetCurrentContext(oldContext);
415     }
416     ::CGLDestroyContext((CGLContextObj)mOpenGLContext);
417   }
418   if (mCGImage) {
419     ::CGImageRelease(mCGImage);
420   }
421   if (mIOSurface) {
422     delete mIOSurface;
423   }
424   // mCGData is deallocated by cgdata_release_callback
426   mCARenderer = nil;
427   mPixelBuffer = nsnull;
428   mOpenGLContext = nsnull;
429   mCGImage = nsnull;
430   mIOSurface = nsnull;
431   mFBO = nsnull;
432   mIOTexture = nsnull;
435 nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) {
436   if (aWidth == 0 || aHeight == 0)
437     return NS_ERROR_FAILURE;
439   CALayer* layer = (CALayer*)aCALayer;
440   CARenderer* caRenderer = nsnull;
442   CGLPixelFormatAttribute attributes[] = {
443     kCGLPFANoRecovery,
444     kCGLPFAAccelerated,
445     kCGLPFAPBuffer,
446     kCGLPFADepthSize, (CGLPixelFormatAttribute)24,
447     (CGLPixelFormatAttribute)0
448   };
450   if (!mIOSurface) {
451     CGLError result = ::CGLCreatePBuffer(aWidth, aHeight,
452                          GL_TEXTURE_2D, GL_RGBA, 0, &mPixelBuffer);
453     if (result != kCGLNoError) {
454       Destroy();
455       return NS_ERROR_FAILURE;
456     }
457   }
459   GLint screen;
460   CGLPixelFormatObj format;
461   if (::CGLChoosePixelFormat(attributes, &format, &screen) != kCGLNoError) {
462     Destroy();
463     return NS_ERROR_FAILURE;
464   }
466   if (::CGLCreateContext(format, nsnull, &mOpenGLContext) != kCGLNoError) {
467     Destroy();
468     return NS_ERROR_FAILURE;
469   }
470   ::CGLDestroyPixelFormat(format);
472   caRenderer = [[CARenderer rendererWithCGLContext:mOpenGLContext 
473                             options:nil] retain];
474   mCARenderer = caRenderer;
475   if (caRenderer == nil) {
476     Destroy();
477     return NS_ERROR_FAILURE;
478   }
479   [layer setBounds:CGRectMake(0, 0, aWidth, aHeight)];
480   [layer setPosition:CGPointMake(aWidth/2.0, aHeight/2.0)];
481   caRenderer.layer = layer;
482   caRenderer.bounds = CGRectMake(0, 0, aWidth, aHeight);
484   // We either target rendering to a CGImage or IOSurface.
485   if (!mIOSurface) {
486     mCGData = malloc(aWidth*aHeight*4);
487     if (!mCGData) {
488       Destroy();
489     }
490     memset(mCGData, 0, aWidth*aHeight*4);
492     CGDataProviderRef dataProvider = nsnull;
493     dataProvider = ::CGDataProviderCreateWithData(mCGData,
494                                         mCGData, aHeight*aWidth*4, 
495                                         cgdata_release_callback);
496     if (!dataProvider) {
497       cgdata_release_callback(mCGData, mCGData, aHeight*aWidth*4);
498       Destroy();
499       return NS_ERROR_FAILURE;
500     }
502     CGColorSpaceRef colorSpace = CreateSystemColorSpace();
504     mCGImage = ::CGImageCreate(aWidth, aHeight, 8, 32, aWidth * 4, colorSpace, 
505                 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
506                 dataProvider, NULL, true, kCGRenderingIntentDefault);
508     ::CGDataProviderRelease(dataProvider);
509     if (colorSpace) {
510       ::CGColorSpaceRelease(colorSpace);
511     }
512     if (!mCGImage) {
513       Destroy();
514       return NS_ERROR_FAILURE;
515     }
516   } else {
517     CGLContextObj oldContext = ::CGLGetCurrentContext();
518     ::CGLSetCurrentContext(mOpenGLContext);
520     // Create the IOSurface mapped texture.
521     ::glGenTextures(1, &mIOTexture);
522     ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mIOTexture);
523     ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
524     ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
525     nsIOSurfaceLib::CGLTexImageIOSurface2D(mOpenGLContext, GL_TEXTURE_RECTANGLE_ARB,
526                                            GL_RGBA, aWidth, aHeight,
527                                            GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 
528                                            mIOSurface->mIOSurfacePtr, 0);
529     ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
531     // Create the fbo
532     ::glGenFramebuffersEXT(1, &mFBO);
533     ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
534     ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
535                                 GL_TEXTURE_RECTANGLE_ARB, mIOTexture, 0);
537     // Make sure that the Framebuffer configuration is supported on the client machine
538     GLenum fboStatus;
539     fboStatus = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
540     if (fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT) {
541       NS_ERROR("FBO not supported");
542       if (oldContext)
543         ::CGLSetCurrentContext(oldContext);
544       Destroy();
545       return NS_ERROR_FAILURE; 
546     }
548     if (oldContext)
549       ::CGLSetCurrentContext(oldContext);
550   }
552   CGLContextObj oldContext = ::CGLGetCurrentContext();
553   ::CGLSetCurrentContext(mOpenGLContext);
555   ::glViewport(0.0, 0.0, aWidth, aHeight);
556   ::glMatrixMode(GL_PROJECTION);
557   ::glLoadIdentity();
558   ::glOrtho (0.0, aWidth, 0.0, aHeight, -1, 1);
560   // Render upside down to speed up CGContextDrawImage
561   ::glTranslatef(0.0f, aHeight, 0.0);
562   ::glScalef(1.0, -1.0, 1.0);
564   GLenum result = ::glGetError();
565   if (result != GL_NO_ERROR) {
566     NS_ERROR("Unexpected OpenGL Error");
567     Destroy();
568     if (oldContext)
569       ::CGLSetCurrentContext(oldContext);
570     return NS_ERROR_FAILURE;
571   }
573   if (oldContext)
574     ::CGLSetCurrentContext(oldContext);
576   return NS_OK;
579 void nsCARenderer::AttachIOSurface(nsIOSurface *aSurface) {
580   if (mIOSurface && 
581       aSurface->GetIOSurfaceID() == mIOSurface->GetIOSurfaceID()) {
582     delete aSurface; 
583     return;
584   }
585   if (mCARenderer) {
586     // We are attaching a larger IOSurface, we need to
587     // resize our elements.
588     Destroy(); 
589   }
590   if (mIOSurface)
591     delete mIOSurface;
593   mIOSurface = aSurface;
596 nsresult nsCARenderer::Render(int aWidth, int aHeight, 
597                               CGImageRef *aOutCGImage) {
598   if (!aOutCGImage && !mIOSurface) {
599     NS_ERROR("No target destination for rendering");
600   } else if (aOutCGImage) {
601     // We are expected to return a CGImageRef, we will set
602     // it to NULL in case we fail before the image is ready.
603     *aOutCGImage = NULL;
604   }
606   if (aWidth == 0 || aHeight == 0)
607     return NS_OK;
609   if (!mCARenderer) {
610     return NS_ERROR_FAILURE;
611   }
613   CARenderer* caRenderer = (CARenderer*)mCARenderer;
614   int renderer_width = caRenderer.bounds.size.width;
615   int renderer_height = caRenderer.bounds.size.height;
617   if (renderer_width != aWidth || renderer_height != aHeight) {
618     // XXX: This should be optimized to not rescale the buffer
619     //      if we are resizing down.
620     CALayer* caLayer = [caRenderer layer];
621     Destroy();
622     if (SetupRenderer(caLayer, aWidth, aHeight) != NS_OK) {
623       return NS_ERROR_FAILURE;
624     }
625     caRenderer = (CARenderer*)mCARenderer;
626   }
628   CGLContextObj oldContext = ::CGLGetCurrentContext();
629   ::CGLSetCurrentContext(mOpenGLContext);
630   if (!mIOSurface) {
631     ::CGLSetPBuffer(mOpenGLContext, mPixelBuffer, 0, 0, 0);
632   }
634   GLenum result = ::glGetError();
635   if (result != GL_NO_ERROR) {
636     NS_ERROR("Unexpected OpenGL Error");
637     Destroy();
638     if (oldContext)
639       ::CGLSetCurrentContext(oldContext);
640     return NS_ERROR_FAILURE;
641   }
643   ::glClearColor(0.0, 0.0, 0.0, 0.0);
644   ::glClear(GL_COLOR_BUFFER_BIT);
646   double caTime = ::CACurrentMediaTime();
647   [caRenderer beginFrameAtTime:caTime timeStamp:NULL];
648   [caRenderer addUpdateRect:CGRectMake(0,0, aWidth, aHeight)];
649   [caRenderer render];
650   [caRenderer endFrame];
652   // Read the data back either to the IOSurface or mCGImage.
653   if (mIOSurface) {
654     ::glFlush();
655   } else {
656     ::glPixelStorei(GL_PACK_ALIGNMENT, 4);
657     ::glPixelStorei(GL_PACK_ROW_LENGTH, 0);
658     ::glPixelStorei(GL_PACK_SKIP_ROWS, 0);
659     ::glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
661     ::glReadPixels(0.0f, 0.0f, aWidth, aHeight,
662                         GL_BGRA, GL_UNSIGNED_BYTE,
663                         mCGData);
665     *aOutCGImage = mCGImage;
666   }
668   if (oldContext) {
669     ::CGLSetCurrentContext(oldContext);
670   }
672   return NS_OK;
675 nsresult nsCARenderer::DrawSurfaceToCGContext(CGContextRef aContext, 
676                                               nsIOSurface *surf, 
677                                               CGColorSpaceRef aColorSpace,
678                                               int aX, int aY,
679                                               int aWidth, int aHeight) {
680   surf->Lock();
681   size_t bytesPerRow = surf->GetBytesPerRow();
682   size_t ioWidth = surf->GetWidth();
683   size_t ioHeight = surf->GetHeight();
684   void* ioData = surf->GetBaseAddress();
685   CGDataProviderRef dataProvider = ::CGDataProviderCreateWithData(ioData,
686                                       ioData, ioHeight*(bytesPerRow)*4, 
687                                       NULL); //No release callback 
688   if (!dataProvider) {
689     surf->Unlock();
690     return NS_ERROR_FAILURE;
691   }
693   // We get rendering glitches if we use a width/height that falls
694   // outside of the IOSurface.
695   if (aWidth > ioWidth - aX) 
696     aWidth = ioWidth - aX;
697   if (aHeight > ioHeight - aY) 
698     aHeight = ioHeight - aY;
700   CGImageRef cgImage = ::CGImageCreate(ioWidth, ioHeight, 8, 32, bytesPerRow,
701               aColorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
702               dataProvider, NULL, true, kCGRenderingIntentDefault);
703   ::CGDataProviderRelease(dataProvider);
704   if (!cgImage) {
705     surf->Unlock();
706     return NS_ERROR_FAILURE;
707   }
708   CGImageRef subImage = ::CGImageCreateWithImageInRect(cgImage,
709                                        ::CGRectMake(aX, aY, aWidth, aHeight));
710   if (!subImage) {
711     ::CGImageRelease(cgImage);
712     surf->Unlock();
713     return NS_ERROR_FAILURE;
714   }
716   ::CGContextScaleCTM(aContext, 1.0f, -1.0f);
717   ::CGContextDrawImage(aContext, CGRectMake(aX, -aY-aHeight, aWidth, aHeight), subImage);
719   ::CGImageRelease(subImage);
720   ::CGImageRelease(cgImage);
721   surf->Unlock();
722   return NS_OK;