Commit a67e645c authored by Markus Stange's avatar Markus Stange
Browse files

bug 674373 pt 1 - Mac OS X native theme rendering support for HiDPI display. r=smichaud

parent efcb97d8
Loading
Loading
Loading
Loading
+53 −7
Original line number Diff line number Diff line
@@ -460,6 +460,16 @@ nsNativeThemeCocoa::~nsNativeThemeCocoa()
// different amounts of RAM.
#define BITMAP_MAX_AREA 500000

static int
GetBackingScaleFactorForRendering(CGContextRef cgContext)
{
  CGAffineTransform ctm = CGContextGetUserSpaceToDeviceSpaceTransform(cgContext);
  CGRect transformedUserSpacePixel = CGRectApplyAffineTransform(CGRectMake(0, 0, 1, 1), ctm);
  float maxScale = NS_MAX(fabs(transformedUserSpacePixel.size.width),
                          fabs(transformedUserSpacePixel.size.height));
  return maxScale > 1.0 ? 2 : 1;  
}

/*
 * Draw the given NSCell into the given cgContext.
 *
@@ -542,10 +552,11 @@ static void DrawCellWithScaling(NSCell *cell,
    w += MAX_FOCUS_RING_WIDTH * 2.0;
    h += MAX_FOCUS_RING_WIDTH * 2.0;

    int backingScaleFactor = GetBackingScaleFactorForRendering(cgContext);
    CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
    CGContextRef ctx = CGBitmapContextCreate(NULL,
                                             (int) w, (int) h,
                                             8, (int) w * 4,
                                             (int) w * backingScaleFactor, (int) h * backingScaleFactor,
                                             8, (int) w * backingScaleFactor * 4,
                                             rgb, kCGImageAlphaPremultipliedFirst);
    CGColorSpaceRelease(rgb);

@@ -561,6 +572,8 @@ static void DrawCellWithScaling(NSCell *cell,
    NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
    [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:YES]];

    CGContextScaleCTM(ctx, backingScaleFactor, backingScaleFactor);

    // This is the second flip transform, applied to ctx.
    CGContextScaleCTM(ctx, 1.0f, -1.0f);
    CGContextTranslateCTM(ctx, 0.0f, -(2.0 * tmpRect.origin.y + tmpRect.size.height));
@@ -967,12 +980,18 @@ RenderTransformedHIThemeControl(CGContextRef aCGContext, const HIRect& aRect,
    int w = ceil(drawRect.size.width) + 2 * MAX_FOCUS_RING_WIDTH;
    int h = ceil(drawRect.size.height) + 2 * MAX_FOCUS_RING_WIDTH;

    int backingScaleFactor = GetBackingScaleFactorForRendering(aCGContext);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef bitmapctx = CGBitmapContextCreate(NULL, w, h, 8, w * 4,
    CGContextRef bitmapctx = CGBitmapContextCreate(NULL,
                                                   w * backingScaleFactor,
                                                   h * backingScaleFactor,
                                                   8,
                                                   w * backingScaleFactor * 4,
                                                   colorSpace,
                                                   kCGImageAlphaPremultipliedFirst);
    CGColorSpaceRelease(colorSpace);

    CGContextScaleCTM(bitmapctx, backingScaleFactor, backingScaleFactor);
    CGContextTranslateCTM(bitmapctx, MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH);

    // HITheme always wants to draw into a flipped context, or things
@@ -1774,10 +1793,12 @@ ToolbarCanBeUnified(CGContextRef cgContext, const HIRect& inBoxRect, NSWindow* a
    return false;

  float unifiedToolbarHeight = [(ToolbarWindow*)aWindow unifiedToolbarHeight];
  CGAffineTransform ctm = CGContextGetUserSpaceToDeviceSpaceTransform(cgContext);
  CGRect deviceRect = CGRectApplyAffineTransform(inBoxRect, ctm);
  return inBoxRect.origin.x == 0 &&
         inBoxRect.size.width >= [aWindow frame].size.width &&
         deviceRect.size.width >= [aWindow frame].size.width &&
         inBoxRect.origin.y <= 0.0 &&
         inBoxRect.origin.y + inBoxRect.size.height <= unifiedToolbarHeight;
         floor(inBoxRect.origin.y + inBoxRect.size.height) <= unifiedToolbarHeight;
}

void
@@ -1876,6 +1897,14 @@ nsNativeThemeCocoa::DrawResizer(CGContextRef cgContext, const HIRect& aRect,
  NS_OBJC_END_TRY_ABORT_BLOCK;
}

static bool
IsContextZoomedToHighResolution(nsDeviceContext* aContext)
{
  const float devPixelsPerCSSPixel = 1.0f *
    nsPresContext::AppUnitsPerCSSPixel() / aContext->AppUnitsPerDevPixel();
  return devPixelsPerCSSPixel > 1.5f;
}

NS_IMETHODIMP
nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
                                         nsIFrame* aFrame,
@@ -1901,6 +1930,15 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
  if (!thebesCtx)
    return NS_ERROR_FAILURE;

  gfxContextMatrixAutoSaveRestore save(thebesCtx);

  if (IsContextZoomedToHighResolution(aContext->DeviceContext())) {
    // Use high-resolution drawing.
    nativeWidgetRect.ScaleInverse(2.0f);
    nativeDirtyRect.ScaleInverse(2.0f);
    thebesCtx->Scale(2.0f, 2.0f);
  }

  gfxQuartzNativeDrawing nativeDrawing(thebesCtx, nativeDirtyRect);

  CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
@@ -2298,8 +2336,8 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
      CGContextFillRect(cgContext, macRect);

      // #8E8E8E for the top border, #BEBEBE for the rest.
      int x = macRect.origin.x, y = macRect.origin.y;
      int w = macRect.size.width, h = macRect.size.height;
      float x = macRect.origin.x, y = macRect.origin.y;
      float w = macRect.size.width, h = macRect.size.height;
      CGContextSetRGBFillColor(cgContext, 0.557, 0.557, 0.557, 1.0);
      CGContextFillRect(cgContext, CGRectMake(x, y, w, 1));
      CGContextSetRGBFillColor(cgContext, 0.745, 0.745, 0.745, 1.0);
@@ -2449,6 +2487,10 @@ nsNativeThemeCocoa::GetWidgetBorder(nsDeviceContext* aContext,
      break;
  }

  if (IsContextZoomedToHighResolution(aContext)) {
    *aResult = *aResult + *aResult; // doubled
  }

  return NS_OK;

  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
@@ -2718,6 +2760,10 @@ nsNativeThemeCocoa::GetMinimumWidgetSize(nsRenderingContext* aContext,
    }
  }

  if (IsContextZoomedToHighResolution(aContext->DeviceContext())) {
    *aResult = *aResult * 2;
  }

  return NS_OK;

  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;