Bug 588664. Cache DPI in nsCocoaWindow. r=joshmoz,a=blocking
authorRobert O'Callahan <robert@ocallahan.org>
Thu, 19 Aug 2010 21:35:08 +1200
changeset 50873 5a3b5dbd2929769d338e97eef8903591e21f999f
parent 50872 3ec65c47a51a24a353b8c3b08f0209046732dd66
child 50874 91427ac7438e0441de66dec9b603d7cbc63561e1
push id15186
push userrocallahan@mozilla.com
push dateThu, 19 Aug 2010 09:50:34 +0000
treeherderautoland@4af78db27055 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoshmoz, blocking
bugs588664
milestone2.0b5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 588664. Cache DPI in nsCocoaWindow. r=joshmoz,a=blocking
widget/src/cocoa/nsChildView.mm
widget/src/cocoa/nsCocoaWindow.h
widget/src/cocoa/nsCocoaWindow.mm
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -964,32 +964,21 @@ nsChildView::GetParent()
 {
   return mParentWidget;
 }
 
 float
 nsChildView::GetDPI()
 {
   NSWindow* window = [mView window];
-  NSScreen* screen = [window screen];
-  if (!screen)
-    return 96.0f;
-
-  CGDirectDisplayID displayID =
-    [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] intValue];
-  CGFloat heightMM = CGDisplayScreenSize(displayID).height;
-  size_t heightPx = CGDisplayPixelsHigh(displayID);
-  CGFloat scaleFactor = [window userSpaceScaleFactor];
-
-  // Currently we don't do our own scaling to take account
-  // of userSpaceScaleFactor, so every "pixel" we draw is actually
-  // userSpaceScaleFactor screen pixels. So divide the screen height
-  // by userSpaceScaleFactor to get the number of "device pixels"
-  // available.
-  return (heightPx / scaleFactor) / (heightMM / MM_PER_INCH_FLOAT);
+  if (window && [window isKindOfClass:[BaseWindow class]]) {
+    return [(BaseWindow*)window getDPI];
+  }
+
+  return 96.0;
 }
 
 LayerManager*
 nsChildView::GetLayerManager()
 {
   nsCocoaWindow* window = GetXULWindowWidget();
   if (window && window->GetAcceleratedRendering() != mUseAcceleratedRendering) {
     mLayerManager = NULL;
--- a/widget/src/cocoa/nsCocoaWindow.h
+++ b/widget/src/cocoa/nsCocoaWindow.h
@@ -71,27 +71,33 @@ typedef struct _nsCocoaWindowList {
   // Data Storage
   NSMutableDictionary* mState;
   BOOL mDrawsIntoWindowFrame;
   NSColor* mActiveTitlebarColor;
   NSColor* mInactiveTitlebarColor;
 
   // Shadow
   BOOL mScheduledShadowInvalidation;
+
+  // DPI cache. Getting the physical screen size (CGDisplayScreenSize)
+  // is ridiculously slow, so we cache it in the toplevel window for all
+  // descendants to use.
+  float mDPI;
 }
 
 - (void)importState:(NSDictionary*)aState;
 - (NSMutableDictionary*)exportState;
 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
 - (BOOL)drawsContentsIntoWindowFrame;
 - (void)setTitlebarColor:(NSColor*)aColor forActiveWindow:(BOOL)aActive;
 - (NSColor*)titlebarColorForActiveWindow:(BOOL)aActive;
 
 - (void)deferredInvalidateShadow;
 - (void)invalidateShadow;
+- (float)getDPI;
 
 @end
 
 @interface NSWindow (Undocumented)
 
 // If a window has been explicitly removed from the "window cache" (to
 // deactivate it), it's sometimes necessary to "reset" it to reactivate it
 // (and put it back in the "window cache").  One way to do this, which Apple
--- a/widget/src/cocoa/nsCocoaWindow.mm
+++ b/widget/src/cocoa/nsCocoaWindow.mm
@@ -1932,26 +1932,53 @@ void nsCocoaWindow::SetPopupWindowLevel(
   if (mToplevelActiveState) {
     [self sendFocusEvent:NS_DEACTIVATE];
     mToplevelActiveState = PR_FALSE;
   }
 }
 
 @end
 
+static float
+GetDPI(NSWindow* aWindow)
+{
+  NSScreen* screen = [aWindow screen];
+  if (!screen)
+    return 96.0f;
+
+  CGDirectDisplayID displayID =
+    [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] intValue];
+  CGFloat heightMM = ::CGDisplayScreenSize(displayID).height;
+  size_t heightPx = ::CGDisplayPixelsHigh(displayID);
+  CGFloat scaleFactor = [aWindow userSpaceScaleFactor];
+  if (scaleFactor < 0.01 || heightMM < 1 || heightPx < 1) {
+    // Something extremely bogus is going on
+    return 96.0f;
+  }
+
+  // Currently we don't do our own scaling to take account
+  // of userSpaceScaleFactor, so every "pixel" we draw is actually
+  // userSpaceScaleFactor screen pixels. So divide the screen height
+  // by userSpaceScaleFactor to get the number of "device pixels"
+  // available.
+  return (heightPx / scaleFactor) / (heightMM / MM_PER_INCH_FLOAT);
+}
+
 @implementation BaseWindow
 
 - (id)initWithContentRect:(NSRect)aContentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)aBufferingType defer:(BOOL)aFlag
 {
   [super initWithContentRect:aContentRect styleMask:aStyle backing:aBufferingType defer:aFlag];
   mState = nil;
   mDrawsIntoWindowFrame = NO;
   mActiveTitlebarColor = nil;
   mInactiveTitlebarColor = nil;
   mScheduledShadowInvalidation = NO;
+  mDPI = GetDPI(self);
+
   return self;
 }
 
 - (void)dealloc
 {
   [mActiveTitlebarColor release];
   [mInactiveTitlebarColor release];
   [super dealloc];
@@ -2029,16 +2056,21 @@ static const NSString* kStateShowsToolba
 }
 
 - (void)invalidateShadow
 {
   [super invalidateShadow];
   mScheduledShadowInvalidation = NO;
 }
 
+- (float)getDPI
+{
+  return mDPI;
+}
+
 - (void) doCommandBySelector:(SEL)aSelector
 {
   // We override this so that it won't beep if it can't act.
   // We want to control the beeping for missing or disabled
   // commands ourselves.
   [self tryToPerform:aSelector with:nil];
 }