gfx/2d/QuartzSupport.mm

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "QuartzSupport.h"
     8 #include "nsDebug.h"
     9 #include "MacIOSurface.h"
    11 #import <QuartzCore/QuartzCore.h>
    12 #import <AppKit/NSOpenGL.h>
    13 #include <dlfcn.h>
    14 #include "GLDefs.h"
    16 #define IOSURFACE_FRAMEWORK_PATH \
    17   "/System/Library/Frameworks/IOSurface.framework/IOSurface"
    18 #define OPENGL_FRAMEWORK_PATH \
    19   "/System/Library/Frameworks/OpenGL.framework/OpenGL"
    20 #define COREGRAPHICS_FRAMEWORK_PATH \
    21   "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/CoreGraphics"
    23 @interface CALayer (ContentsScale)
    24 - (double)contentsScale;
    25 - (void)setContentsScale:(double)scale;
    26 @end
    28 using mozilla::RefPtr;
    29 using mozilla::TemporaryRef;
    31 CGColorSpaceRef CreateSystemColorSpace() {
    32   CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID());
    33   if (!cspace) {
    34     cspace = ::CGColorSpaceCreateDeviceRGB();
    35   }
    36   return cspace;
    37 }
    39 nsCARenderer::~nsCARenderer() {
    40   Destroy();
    41 }
    43 void cgdata_release_callback(void *aCGData, const void *data, size_t size) {
    44   if (aCGData) {
    45     free(aCGData);
    46   }
    47 }
    49 void nsCARenderer::Destroy() {
    50   if (mCARenderer) {
    51     CARenderer* caRenderer = (CARenderer*)mCARenderer;
    52     // Bug 556453:
    53     // Explicitly remove the layer from the renderer
    54     // otherwise it does not always happen right away.
    55     caRenderer.layer = nullptr;
    56     [caRenderer release];
    57   }
    58   if (mWrapperCALayer) {
    59     CALayer* wrapperLayer = (CALayer*)mWrapperCALayer;
    60     [wrapperLayer release];
    61   }
    62   if (mOpenGLContext) {
    63     if (mFBO || mIOTexture || mFBOTexture) {
    64       // Release these resources with the context that allocated them
    65       CGLContextObj oldContext = ::CGLGetCurrentContext();
    66       ::CGLSetCurrentContext(mOpenGLContext);
    68       if (mFBOTexture) {
    69         ::glDeleteTextures(1, &mFBOTexture);
    70       }
    71       if (mIOTexture) {
    72         ::glDeleteTextures(1, &mIOTexture);
    73       }
    74       if (mFBO) {
    75         ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    76         ::glDeleteFramebuffersEXT(1, &mFBO);
    77       }
    79       if (oldContext)
    80         ::CGLSetCurrentContext(oldContext);
    81     }
    82     ::CGLDestroyContext((CGLContextObj)mOpenGLContext);
    83   }
    84   if (mCGImage) {
    85     ::CGImageRelease(mCGImage);
    86   }
    87   // mCGData is deallocated by cgdata_release_callback
    89   mCARenderer = nil;
    90   mWrapperCALayer = nil;
    91   mFBOTexture = 0;
    92   mOpenGLContext = nullptr;
    93   mCGImage = nullptr;
    94   mIOSurface = nullptr;
    95   mFBO = 0;
    96   mIOTexture = 0;
    97 }
    99 nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight,
   100                                      double aContentsScaleFactor,
   101                                      AllowOfflineRendererEnum aAllowOfflineRenderer) {
   102   mAllowOfflineRenderer = aAllowOfflineRenderer;
   104   if (aWidth == 0 || aHeight == 0 || aContentsScaleFactor <= 0)
   105     return NS_ERROR_FAILURE;
   107   if (aWidth == mUnsupportedWidth &&
   108       aHeight == mUnsupportedHeight) {
   109     return NS_ERROR_FAILURE;
   110   }
   112   CGLPixelFormatAttribute attributes[] = {
   113     kCGLPFAAccelerated,
   114     kCGLPFADepthSize, (CGLPixelFormatAttribute)24,
   115     kCGLPFAAllowOfflineRenderers,
   116     (CGLPixelFormatAttribute)0
   117   };
   119   if (mAllowOfflineRenderer == DISALLOW_OFFLINE_RENDERER) {
   120     attributes[3] = (CGLPixelFormatAttribute)0;
   121   }
   123   GLint screen;
   124   CGLPixelFormatObj format;
   125   if (::CGLChoosePixelFormat(attributes, &format, &screen) != kCGLNoError) {
   126     mUnsupportedWidth = aWidth;
   127     mUnsupportedHeight = aHeight;
   128     Destroy();
   129     return NS_ERROR_FAILURE;
   130   }
   132   if (::CGLCreateContext(format, nullptr, &mOpenGLContext) != kCGLNoError) {
   133     mUnsupportedWidth = aWidth;
   134     mUnsupportedHeight = aHeight;
   135     Destroy();
   136     return NS_ERROR_FAILURE;
   137   }
   138   ::CGLDestroyPixelFormat(format);
   140   CARenderer* caRenderer = [[CARenderer rendererWithCGLContext:mOpenGLContext 
   141                                                        options:nil] retain];
   142   if (caRenderer == nil) {
   143     mUnsupportedWidth = aWidth;
   144     mUnsupportedHeight = aHeight;
   145     Destroy();
   146     return NS_ERROR_FAILURE;
   147   }
   148   CALayer* wrapperCALayer = [[CALayer layer] retain];
   149   if (wrapperCALayer == nil) {
   150     [caRenderer release];
   151     mUnsupportedWidth = aWidth;
   152     mUnsupportedHeight = aHeight;
   153     Destroy();
   154     return NS_ERROR_FAILURE;
   155   }
   157   mCARenderer = caRenderer;
   158   mWrapperCALayer = wrapperCALayer;
   159   caRenderer.layer = wrapperCALayer;
   160   [wrapperCALayer addSublayer:(CALayer*)aCALayer];
   161   mContentsScaleFactor = aContentsScaleFactor;
   162   size_t intScaleFactor = ceil(mContentsScaleFactor);
   163   SetBounds(aWidth, aHeight);
   165   // We target rendering to a CGImage if no shared IOSurface are given.
   166   if (!mIOSurface) {
   167     mCGData = malloc(aWidth*intScaleFactor*aHeight*4*intScaleFactor);
   168     if (!mCGData) {
   169       mUnsupportedWidth = aWidth;
   170       mUnsupportedHeight = aHeight;
   171       Destroy();
   172       return NS_ERROR_FAILURE;
   173     }
   174     memset(mCGData, 0, aWidth*intScaleFactor*aHeight*4*intScaleFactor);
   176     CGDataProviderRef dataProvider = nullptr;
   177     dataProvider = ::CGDataProviderCreateWithData(mCGData,
   178                                         mCGData, aHeight*intScaleFactor*aWidth*4*intScaleFactor,
   179                                         cgdata_release_callback);
   180     if (!dataProvider) {
   181       cgdata_release_callback(mCGData, mCGData,
   182                               aHeight*intScaleFactor*aWidth*4*intScaleFactor);
   183       mUnsupportedWidth = aWidth;
   184       mUnsupportedHeight = aHeight;
   185       Destroy();
   186       return NS_ERROR_FAILURE;
   187     }
   189     CGColorSpaceRef colorSpace = CreateSystemColorSpace();
   191     mCGImage = ::CGImageCreate(aWidth * intScaleFactor, aHeight * intScaleFactor,
   192                 8, 32, aWidth * intScaleFactor * 4, colorSpace,
   193                 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
   194                 dataProvider, nullptr, true, kCGRenderingIntentDefault);
   196     ::CGDataProviderRelease(dataProvider);
   197     ::CGColorSpaceRelease(colorSpace);
   198     if (!mCGImage) {
   199       mUnsupportedWidth = aWidth;
   200       mUnsupportedHeight = aHeight;
   201       Destroy();
   202       return NS_ERROR_FAILURE;
   203     }
   204   }
   206   CGLContextObj oldContext = ::CGLGetCurrentContext();
   207   ::CGLSetCurrentContext(mOpenGLContext);
   209   if (mIOSurface) {
   210     // Create the IOSurface mapped texture.
   211     ::glGenTextures(1, &mIOTexture);
   212     ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mIOTexture);
   213     ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   214     ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   215     MacIOSurfaceLib::CGLTexImageIOSurface2D(mOpenGLContext, GL_TEXTURE_RECTANGLE_ARB,
   216                                            GL_RGBA, aWidth * intScaleFactor,
   217                                            aHeight * intScaleFactor,
   218                                            GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
   219                                            mIOSurface->mIOSurfacePtr, 0);
   220     ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
   221   } else {
   222     ::glGenTextures(1, &mFBOTexture);
   223     ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mFBOTexture);
   224     ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   225     ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   226     ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
   227   }
   229   // Create the fbo
   230   ::glGenFramebuffersEXT(1, &mFBO);
   231   ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
   232   if (mIOSurface) {
   233    ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
   234                                 GL_TEXTURE_RECTANGLE_ARB, mIOTexture, 0);
   235   } else {
   236     ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
   237                                 GL_TEXTURE_RECTANGLE_ARB, mFBOTexture, 0);
   238   }
   241   // Make sure that the Framebuffer configuration is supported on the client machine
   242   GLenum fboStatus;
   243   fboStatus = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
   244   if (fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT) {
   245     NS_ERROR("FBO not supported");
   246     if (oldContext)
   247       ::CGLSetCurrentContext(oldContext);
   248     mUnsupportedWidth = aWidth;
   249     mUnsupportedHeight = aHeight;
   250     Destroy();
   251     return NS_ERROR_FAILURE;
   252   }
   254   SetViewport(aWidth, aHeight);
   256   GLenum result = ::glGetError();
   257   if (result != GL_NO_ERROR) {
   258     NS_ERROR("Unexpected OpenGL Error");
   259     mUnsupportedWidth = aWidth;
   260     mUnsupportedHeight = aHeight;
   261     Destroy();
   262     if (oldContext)
   263       ::CGLSetCurrentContext(oldContext);
   264     return NS_ERROR_FAILURE;
   265   }
   267   if (oldContext)
   268     ::CGLSetCurrentContext(oldContext);
   270   return NS_OK;
   271 }
   273 void nsCARenderer::SetBounds(int aWidth, int aHeight) {
   274   CARenderer* caRenderer = (CARenderer*)mCARenderer;
   275   CALayer* wrapperLayer = (CALayer*)mWrapperCALayer;
   276   NSArray* sublayers = [wrapperLayer sublayers];
   277   CALayer* pluginLayer = (CALayer*) [sublayers objectAtIndex:0];
   279   // Create a transaction and disable animations
   280   // to make the position update instant.
   281   [CATransaction begin];
   282   NSMutableDictionary *newActions =
   283     [[NSMutableDictionary alloc] initWithObjectsAndKeys:
   284       [NSNull null], @"onOrderIn",
   285       [NSNull null], @"onOrderOut",
   286       [NSNull null], @"sublayers",
   287       [NSNull null], @"contents",
   288       [NSNull null], @"position",
   289       [NSNull null], @"bounds",
   290       nil];
   291   wrapperLayer.actions = newActions;
   292   [newActions release];
   294   // If we're in HiDPI mode, mContentsScaleFactor will (presumably) be 2.0.
   295   // For some reason, to make things work properly in HiDPI mode we need to
   296   // make caRenderer's 'bounds' and 'layer' different sizes -- to set 'bounds'
   297   // to the size of 'layer's backing store.  And to avoid this possibly
   298   // confusing the plugin, we need to hide it's effects from the plugin by
   299   // making pluginLayer (usually the CALayer* provided by the plugin) a
   300   // sublayer of our own wrapperLayer (see bug 829284).
   301   size_t intScaleFactor = ceil(mContentsScaleFactor);
   302   [CATransaction setValue: [NSNumber numberWithFloat:0.0f] forKey: kCATransactionAnimationDuration];
   303   [CATransaction setValue: (id) kCFBooleanTrue forKey: kCATransactionDisableActions];
   304   [wrapperLayer setBounds:CGRectMake(0, 0, aWidth, aHeight)];
   305   [wrapperLayer setPosition:CGPointMake(aWidth/2.0, aHeight/2.0)];
   306   [pluginLayer setBounds:CGRectMake(0, 0, aWidth, aHeight)];
   307   [pluginLayer setFrame:CGRectMake(0, 0, aWidth, aHeight)];
   308   caRenderer.bounds = CGRectMake(0, 0, aWidth * intScaleFactor, aHeight * intScaleFactor);
   309   if (mContentsScaleFactor != 1.0) {
   310     CGAffineTransform affineTransform = [wrapperLayer affineTransform];
   311     affineTransform.a = mContentsScaleFactor;
   312     affineTransform.d = mContentsScaleFactor;
   313     affineTransform.tx = ((double)aWidth)/mContentsScaleFactor;
   314     affineTransform.ty = ((double)aHeight)/mContentsScaleFactor;
   315     [wrapperLayer setAffineTransform:affineTransform];
   316   } else {
   317     // These settings are the default values.  But they might have been
   318     // changed as above if we were previously running in a HiDPI mode
   319     // (i.e. if we just switched from that to a non-HiDPI mode).
   320     [wrapperLayer setAffineTransform:CGAffineTransformIdentity];
   321   }
   322   [CATransaction commit];
   323 }
   325 void nsCARenderer::SetViewport(int aWidth, int aHeight) {
   326   size_t intScaleFactor = ceil(mContentsScaleFactor);
   327   aWidth *= intScaleFactor;
   328   aHeight *= intScaleFactor;
   330   ::glViewport(0.0, 0.0, aWidth, aHeight);
   331   ::glMatrixMode(GL_PROJECTION);
   332   ::glLoadIdentity();
   333   ::glOrtho (0.0, aWidth, 0.0, aHeight, -1, 1);
   335   // Render upside down to speed up CGContextDrawImage
   336   ::glTranslatef(0.0f, aHeight, 0.0);
   337   ::glScalef(1.0, -1.0, 1.0);
   338 }
   340 void nsCARenderer::AttachIOSurface(RefPtr<MacIOSurface> aSurface) {
   341   if (mIOSurface &&
   342       aSurface->GetIOSurfaceID() == mIOSurface->GetIOSurfaceID()) {
   343     // This object isn't needed since we already have a
   344     // handle to the same io surface.
   345     aSurface = nullptr;
   346     return;
   347   }
   349   mIOSurface = aSurface;
   351   // Update the framebuffer and viewport
   352   if (mCARenderer) {
   353     CARenderer* caRenderer = (CARenderer*)mCARenderer;
   354     size_t intScaleFactor = ceil(mContentsScaleFactor);
   355     int width = caRenderer.bounds.size.width / intScaleFactor;
   356     int height = caRenderer.bounds.size.height / intScaleFactor;
   358     CGLContextObj oldContext = ::CGLGetCurrentContext();
   359     ::CGLSetCurrentContext(mOpenGLContext);
   360     ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mIOTexture);
   361     MacIOSurfaceLib::CGLTexImageIOSurface2D(mOpenGLContext, GL_TEXTURE_RECTANGLE_ARB,
   362                                            GL_RGBA, mIOSurface->GetDevicePixelWidth(),
   363                                            mIOSurface->GetDevicePixelHeight(),
   364                                            GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
   365                                            mIOSurface->mIOSurfacePtr, 0);
   366     ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
   368     // Rebind the FBO to make it live
   369     ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
   371     if (static_cast<int>(mIOSurface->GetWidth()) != width ||
   372         static_cast<int>(mIOSurface->GetHeight()) != height) {
   373       width = mIOSurface->GetWidth();
   374       height = mIOSurface->GetHeight();
   375       SetBounds(width, height);
   376       SetViewport(width, height);
   377     }
   379     if (oldContext) {
   380       ::CGLSetCurrentContext(oldContext);
   381     }
   382   }
   383 }
   385 IOSurfaceID nsCARenderer::GetIOSurfaceID() {
   386   if (!mIOSurface) {
   387     return 0;
   388   }
   390   return mIOSurface->GetIOSurfaceID();
   391 }
   393 nsresult nsCARenderer::Render(int aWidth, int aHeight, 
   394                               double aContentsScaleFactor,
   395                               CGImageRef *aOutCGImage) {
   396   if (!aOutCGImage && !mIOSurface) {
   397     NS_ERROR("No target destination for rendering");
   398   } else if (aOutCGImage) {
   399     // We are expected to return a CGImageRef, we will set
   400     // it to nullptr in case we fail before the image is ready.
   401     *aOutCGImage = nullptr;
   402   }
   404   if (aWidth == 0 || aHeight == 0 || aContentsScaleFactor <= 0)
   405     return NS_OK;
   407   if (!mCARenderer || !mWrapperCALayer) {
   408     return NS_ERROR_FAILURE;
   409   }
   411   CARenderer* caRenderer = (CARenderer*)mCARenderer;
   412   CALayer* wrapperLayer = (CALayer*)mWrapperCALayer;
   413   size_t intScaleFactor = ceil(aContentsScaleFactor);
   414   int renderer_width = caRenderer.bounds.size.width / intScaleFactor;
   415   int renderer_height = caRenderer.bounds.size.height / intScaleFactor;
   417   if (renderer_width != aWidth || renderer_height != aHeight ||
   418       mContentsScaleFactor != aContentsScaleFactor) {
   419     // XXX: This should be optimized to not rescale the buffer
   420     //      if we are resizing down.
   421     // caLayer may be the CALayer* provided by the plugin, so we need to
   422     // preserve it across the call to Destroy().
   423     NSArray* sublayers = [wrapperLayer sublayers];
   424     CALayer* caLayer = (CALayer*) [sublayers objectAtIndex:0];
   425     // mIOSurface is set by AttachIOSurface(), not by SetupRenderer().  So
   426     // since it may have been set by a prior call to AttachIOSurface(), we
   427     // need to preserve it across the call to Destroy().
   428     mozilla::RefPtr<MacIOSurface> ioSurface = mIOSurface;
   429     Destroy();
   430     mIOSurface = ioSurface;
   431     if (SetupRenderer(caLayer, aWidth, aHeight, aContentsScaleFactor,
   432                       mAllowOfflineRenderer) != NS_OK) {
   433       return NS_ERROR_FAILURE;
   434     }
   436     caRenderer = (CARenderer*)mCARenderer;
   437   }
   439   CGLContextObj oldContext = ::CGLGetCurrentContext();
   440   ::CGLSetCurrentContext(mOpenGLContext);
   441   if (!mIOSurface) {
   442     // If no shared IOSurface is given render to our own
   443     // texture for readback.
   444     ::glGenTextures(1, &mFBOTexture);
   445   }
   447   GLenum result = ::glGetError();
   448   if (result != GL_NO_ERROR) {
   449     NS_ERROR("Unexpected OpenGL Error");
   450     Destroy();
   451     if (oldContext)
   452       ::CGLSetCurrentContext(oldContext);
   453     return NS_ERROR_FAILURE;
   454   }
   456   ::glClearColor(0.0, 0.0, 0.0, 0.0);
   457   ::glClear(GL_COLOR_BUFFER_BIT);
   459   [CATransaction commit];
   460   double caTime = ::CACurrentMediaTime();
   461   [caRenderer beginFrameAtTime:caTime timeStamp:nullptr];
   462   [caRenderer addUpdateRect:CGRectMake(0,0, aWidth * intScaleFactor,
   463                                        aHeight * intScaleFactor)];
   464   [caRenderer render];
   465   [caRenderer endFrame];
   467   // Read the data back either to the IOSurface or mCGImage.
   468   if (mIOSurface) {
   469     ::glFlush();
   470   } else {
   471     ::glPixelStorei(GL_PACK_ALIGNMENT, 4);
   472     ::glPixelStorei(GL_PACK_ROW_LENGTH, 0);
   473     ::glPixelStorei(GL_PACK_SKIP_ROWS, 0);
   474     ::glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
   476     ::glReadPixels(0.0f, 0.0f, aWidth * intScaleFactor,
   477                         aHeight * intScaleFactor,
   478                         GL_BGRA, GL_UNSIGNED_BYTE,
   479                         mCGData);
   481     *aOutCGImage = mCGImage;
   482   }
   484   if (oldContext) {
   485     ::CGLSetCurrentContext(oldContext);
   486   }
   488   return NS_OK;
   489 }
   491 nsresult nsCARenderer::DrawSurfaceToCGContext(CGContextRef aContext, 
   492                                               MacIOSurface *surf, 
   493                                               CGColorSpaceRef aColorSpace,
   494                                               int aX, int aY,
   495                                               size_t aWidth, size_t aHeight) {
   496   surf->Lock();
   497   size_t bytesPerRow = surf->GetBytesPerRow();
   498   size_t ioWidth = surf->GetWidth();
   499   size_t ioHeight = surf->GetHeight();
   501   // We get rendering glitches if we use a width/height that falls
   502   // outside of the IOSurface.
   503   if (aWidth + aX > ioWidth) 
   504     aWidth = ioWidth - aX;
   505   if (aHeight + aY > ioHeight) 
   506     aHeight = ioHeight - aY;
   508   if (aX < 0 || static_cast<size_t>(aX) >= ioWidth ||
   509       aY < 0 || static_cast<size_t>(aY) >= ioHeight) {
   510     surf->Unlock();
   511     return NS_ERROR_FAILURE;
   512   }
   514   void* ioData = surf->GetBaseAddress();
   515   double scaleFactor = surf->GetContentsScaleFactor();
   516   size_t intScaleFactor = ceil(surf->GetContentsScaleFactor());
   517   CGDataProviderRef dataProvider = ::CGDataProviderCreateWithData(ioData,
   518                                       ioData, ioHeight*intScaleFactor*(bytesPerRow)*4, 
   519                                       nullptr); //No release callback 
   520   if (!dataProvider) {
   521     surf->Unlock();
   522     return NS_ERROR_FAILURE;
   523   }
   525   CGImageRef cgImage = ::CGImageCreate(ioWidth * intScaleFactor,
   526               ioHeight * intScaleFactor, 8, 32, bytesPerRow, aColorSpace,
   527               kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
   528               dataProvider, nullptr, true, kCGRenderingIntentDefault);
   529   ::CGDataProviderRelease(dataProvider);
   530   if (!cgImage) {
   531     surf->Unlock();
   532     return NS_ERROR_FAILURE;
   533   }
   534   CGImageRef subImage = ::CGImageCreateWithImageInRect(cgImage,
   535                                        ::CGRectMake(aX * scaleFactor,
   536                                                     aY * scaleFactor,
   537                                                     aWidth * scaleFactor,
   538                                                     aHeight * scaleFactor));
   539   if (!subImage) {
   540     ::CGImageRelease(cgImage);
   541     surf->Unlock();
   542     return NS_ERROR_FAILURE;
   543   }
   545   ::CGContextScaleCTM(aContext, 1.0f, -1.0f);
   546   ::CGContextDrawImage(aContext, 
   547                        CGRectMake(aX * scaleFactor,
   548                                   (-(CGFloat)aY - (CGFloat)aHeight) * scaleFactor, 
   549                                   aWidth * scaleFactor,
   550                                   aHeight * scaleFactor), 
   551                        subImage);
   553   ::CGImageRelease(subImage);
   554   ::CGImageRelease(cgImage);
   555   surf->Unlock();
   556   return NS_OK;
   557 }
   559 void nsCARenderer::DetachCALayer() {
   560   CALayer* wrapperLayer = (CALayer*)mWrapperCALayer;
   561   NSArray* sublayers = [wrapperLayer sublayers];
   562   CALayer* oldLayer = (CALayer*) [sublayers objectAtIndex:0];
   563   [oldLayer removeFromSuperlayer];
   564 }
   566 void nsCARenderer::AttachCALayer(void *aCALayer) {
   567   CALayer* wrapperLayer = (CALayer*)mWrapperCALayer;
   568   NSArray* sublayers = [wrapperLayer sublayers];
   569   CALayer* oldLayer = (CALayer*) [sublayers objectAtIndex:0];
   570   [oldLayer removeFromSuperlayer];
   571   [wrapperLayer addSublayer:(CALayer*)aCALayer];
   572 }
   574 #ifdef DEBUG
   576 int sSaveToDiskSequence = 0;
   577 void nsCARenderer::SaveToDisk(MacIOSurface *surf) {
   578   surf->Lock();
   579   size_t bytesPerRow = surf->GetBytesPerRow();
   580   size_t ioWidth = surf->GetWidth();
   581   size_t ioHeight = surf->GetHeight();
   582   void* ioData = surf->GetBaseAddress();
   583   CGDataProviderRef dataProvider = ::CGDataProviderCreateWithData(ioData,
   584                                       ioData, ioHeight*(bytesPerRow)*4, 
   585                                       nullptr); //No release callback 
   586   if (!dataProvider) {
   587     surf->Unlock();
   588     return;
   589   }
   591   CGColorSpaceRef colorSpace = CreateSystemColorSpace();
   592   CGImageRef cgImage = ::CGImageCreate(ioWidth, ioHeight, 8, 32, bytesPerRow,
   593               colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
   594               dataProvider, nullptr, true, kCGRenderingIntentDefault);
   595   ::CGDataProviderRelease(dataProvider);
   596   ::CGColorSpaceRelease(colorSpace);
   597   if (!cgImage) {
   598     surf->Unlock();
   599     return;
   600   }
   602   char cstr[1000];
   604   sprintf(cstr, "file:///Users/benoitgirard/debug/iosurface_%i.png", ++sSaveToDiskSequence);
   606   CFStringRef cfStr = ::CFStringCreateWithCString(kCFAllocatorDefault, cstr, kCFStringEncodingMacRoman);
   608   printf("Exporting: %s\n", cstr);
   609   CFURLRef url = ::CFURLCreateWithString( nullptr, cfStr, nullptr);
   610   ::CFRelease(cfStr);
   612   CFStringRef type = kUTTypePNG;
   613   size_t count = 1;
   614   CFDictionaryRef options = nullptr;
   615   CGImageDestinationRef dest = ::CGImageDestinationCreateWithURL(url, type, count, options);
   616   ::CFRelease(url);
   618   ::CGImageDestinationAddImage(dest, cgImage, nullptr);
   620   ::CGImageDestinationFinalize(dest);
   621   ::CFRelease(dest);
   622   ::CGImageRelease(cgImage);
   624   surf->Unlock();
   626   return;
   628 }
   630 #endif

mercurial