bug 806059 - make gfxQuartzNativeDrawing aware of backing scale factor when rendering native widgets. r=smichaud
authorJonathan Kew <jkew@mozilla.com>
Mon, 29 Oct 2012 09:22:30 +0000
changeset 111922 8147196deeb8551cfb139ffd9477c1c65538960c
parent 111921 8e03750d5434c1f60cbb918b6f8527e3d36665e6
child 111923 d25ef46858dc52aa0f95b4b217e5f828c7d44bb2
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewerssmichaud
bugs806059
milestone19.0a1
bug 806059 - make gfxQuartzNativeDrawing aware of backing scale factor when rendering native widgets. r=smichaud
gfx/thebes/gfxQuartzNativeDrawing.cpp
gfx/thebes/gfxQuartzNativeDrawing.h
widget/cocoa/nsNativeThemeCocoa.mm
--- a/gfx/thebes/gfxQuartzNativeDrawing.cpp
+++ b/gfx/thebes/gfxQuartzNativeDrawing.cpp
@@ -14,18 +14,19 @@ enum {
 };
 
 // private Quartz routine needed here
 extern "C" {
     CG_EXTERN void CGContextSetCompositeOperation(CGContextRef, int);
 }
 
 gfxQuartzNativeDrawing::gfxQuartzNativeDrawing(gfxContext* ctx,
-                                               const gfxRect& nativeRect)
-    : mContext(ctx), mNativeRect(nativeRect)
+                                               const gfxRect& nativeRect,
+                                               gfxFloat aBackingScale)
+    : mContext(ctx), mNativeRect(nativeRect), mBackingScale(aBackingScale)
 {
     mNativeRect.RoundOut();
 }
 
 CGContextRef
 gfxQuartzNativeDrawing::BeginNativeDrawing()
 {
     NS_ASSERTION(!mQuartzSurface, "BeginNativeDrawing called when drawing already in progress");
@@ -70,24 +71,27 @@ gfxQuartzNativeDrawing::BeginNativeDrawi
 
         CGContextConcatCTM(mCGContext, CGAffineTransformMake(m.xx, m.yx,
                                                              m.xy, m.yy,
                                                              x0, y0));
 
         // bug 382049 - need to explicity set the composite operation to sourceOver
         CGContextSetCompositeOperation(mCGContext, kPrivateCGCompositeSourceOver);
     } else {
-        mQuartzSurface = new gfxQuartzSurface(mNativeRect.Size(),
+        nsIntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
+                              NSToIntFloor(mNativeRect.height * mBackingScale));
+        mQuartzSurface = new gfxQuartzSurface(backingSize,
                                               gfxASurface::ImageFormatARGB32);
         if (mQuartzSurface->CairoStatus())
             return nullptr;
         mSurfaceContext = new gfxContext(mQuartzSurface);
 
         // grab the CGContextRef
         mCGContext = cairo_quartz_get_cg_context_with_clip(mSurfaceContext->GetCairo());
+        CGContextScaleCTM(mCGContext, mBackingScale, mBackingScale);
         CGContextTranslateCTM(mCGContext, -mNativeRect.X(), -mNativeRect.Y());
     }
 
     return mCGContext;
 }
 
 void
 gfxQuartzNativeDrawing::EndNativeDrawing()
@@ -96,11 +100,12 @@ gfxQuartzNativeDrawing::EndNativeDrawing
 
     cairo_quartz_finish_cg_context_with_clip(mSurfaceContext->GetCairo());
     mQuartzSurface->MarkDirty();
     if (mSurfaceContext != mContext) {
         gfxContextMatrixAutoSaveRestore save(mContext);
 
         // Copy back to destination
         mContext->Translate(mNativeRect.TopLeft());
-        mContext->DrawSurface(mQuartzSurface, mNativeRect.Size());
+        mContext->Scale(1.0f / mBackingScale, 1.0f / mBackingScale);
+        mContext->DrawSurface(mQuartzSurface, mQuartzSurface->GetSize());
     }
 }
--- a/gfx/thebes/gfxQuartzNativeDrawing.h
+++ b/gfx/thebes/gfxQuartzNativeDrawing.h
@@ -22,19 +22,31 @@ public:
      *   gfxQuartzNativeDrawing nativeDraw(ctx, nativeRect);
      *   CGContextRef cgContext = nativeDraw.BeginNativeDrawing();
      *   if (!cgContext)
      *     return NS_ERROR_FAILURE;
      *
      *     ... call Quartz operations on CGContextRef to draw to nativeRect ...
      *
      *   nativeDraw.EndNativeDrawing();
+     *
+     * aNativeRect is the size of the surface (in Quartz/Cocoa points) that
+     * will be created _if_ the gfxQuartzNativeDrawing decides to create a new
+     * surface and CGContext for its drawing operations, which it then
+     * composites into the target gfxContext.
+     *
+     * (Note that aNativeRect will be ignored if the gfxQuartzNativeDrawing
+     * uses the target gfxContext directly.)
+     *
+     * The optional aBackingScale parameter is a scaling factor that will be
+     * applied when creating and rendering into such a temporary surface.
      */
     gfxQuartzNativeDrawing(gfxContext *ctx,
-                           const gfxRect& nativeRect);
+                           const gfxRect& aNativeRect,
+                           gfxFloat aBackingScale = 1.0f);
 
     /* Returns a CGContextRef which may be used for native drawing.  This
      * CGContextRef is valid until EndNativeDrawing is called; if it is used
      * for drawing after that time, the result is undefined. */
     CGContextRef BeginNativeDrawing();
 
     /* Marks the end of native drawing */
     void EndNativeDrawing();
@@ -45,15 +57,16 @@ private:
     const gfxQuartzNativeDrawing& operator=(const gfxQuartzNativeDrawing&) MOZ_DELETE;
 
     // Final destination context
     nsRefPtr<gfxContext> mContext;
     // context that draws to mQuartzSurface; can be different from mContext
     // if mContext is not drawing to Quartz
     nsRefPtr<gfxContext> mSurfaceContext;
     gfxRect mNativeRect;
+    gfxFloat mBackingScale;
 
     // saved state
     nsRefPtr<gfxQuartzSurface> mQuartzSurface;
     CGContextRef mCGContext;
 };
 
 #endif
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -1926,24 +1926,26 @@ nsNativeThemeCocoa::DrawWidgetBackground
     return NS_OK; // Don't attempt to draw invisible widgets.
 
   gfxContext* thebesCtx = aContext->ThebesContext();
   if (!thebesCtx)
     return NS_ERROR_FAILURE;
 
   gfxContextMatrixAutoSaveRestore save(thebesCtx);
 
-  if (IsHiDPIContext(aContext->DeviceContext())) {
+  bool hidpi = IsHiDPIContext(aContext->DeviceContext());
+  if (hidpi) {
     // Use high-resolution drawing.
     nativeWidgetRect.ScaleInverse(2.0f);
     nativeDirtyRect.ScaleInverse(2.0f);
     thebesCtx->Scale(2.0f, 2.0f);
   }
 
-  gfxQuartzNativeDrawing nativeDrawing(thebesCtx, nativeDirtyRect);
+  gfxQuartzNativeDrawing nativeDrawing(thebesCtx, nativeDirtyRect,
+                                       hidpi ? 2.0f : 1.0f);
 
   CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
   if (cgContext == nullptr) {
     // The Quartz surface handles 0x0 surfaces by internally
     // making all operations no-ops; there's no cgcontext created for them.
     // Unfortunately, this means that callers that want to render
     // directly to the CGContext need to be aware of this quirk.
     return NS_OK;