Bug 663119 - Implement native vertical meters for MacOS X. r=bgirard
authorMounir Lamouri <mounir.lamouri@gmail.com>
Wed, 06 Jun 2012 09:58:00 +0200
changeset 100751 0f2b9a6e36c7f48b40c2f0c1b734fe4c27724791
parent 100750 cd74e9324088d2e8985eba3c8f93bca6f6de28c9
child 100752 3df1de4c95927e43bb2fd4ee688fe74bbdbb4be2
push id1316
push userakeybl@mozilla.com
push dateMon, 27 Aug 2012 22:37:00 +0000
treeherdermozilla-beta@db4b09302ee2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbgirard
bugs663119
milestone16.0a1
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 663119 - Implement native vertical meters for MacOS X. r=bgirard
widget/cocoa/nsNativeThemeCocoa.mm
widget/reftests/meter-vertical-native-style-ref.html
widget/reftests/meter-vertical-native-style.html
widget/reftests/reftest.list
widget/xpwidgets/nsNativeTheme.cpp
widget/xpwidgets/nsNativeTheme.h
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -1415,19 +1415,48 @@ nsNativeThemeCocoa::DrawMeter(CGContextR
   [cell setCriticalValue:max+1];
 
   if (states.HasState(NS_EVENT_STATE_SUB_OPTIMUM)) {
     [cell setWarningValue:value];
   } else if (states.HasState(NS_EVENT_STATE_SUB_SUB_OPTIMUM)) {
     [cell setCriticalValue:value];
   }
 
-  DrawCellWithSnapping(cell, cgContext, inBoxRect,
+  HIRect rect = CGRectStandardize(inBoxRect);
+  BOOL vertical = IsVerticalMeter(aFrame);
+
+  CGContextSaveGState(cgContext);
+
+  if (vertical) {
+    /**
+     * Cocoa doesn't provide a vertical meter bar so to show one, we have to
+     * show a rotated horizontal meter bar.
+     * Given that we want to show a vertical meter bar, we assume that the rect
+     * has vertical dimensions but we can't correctly draw a meter widget inside
+     * such a rectangle so we need to inverse width and height (and re-position)
+     * to get a rectangle with horizontal dimensions.
+     * Finally, we want to show a vertical meter so we want to rotate the result
+     * so it is vertical. We do that by changing the context.
+     */
+    CGFloat tmp = rect.size.width;
+    rect.size.width = rect.size.height;
+    rect.size.height = tmp;
+    rect.origin.x += rect.size.height / 2.f - rect.size.width / 2.f;
+    rect.origin.y += rect.size.width / 2.f - rect.size.height / 2.f;
+
+    CGContextTranslateCTM(cgContext, CGRectGetMidX(rect), CGRectGetMidY(rect));
+    CGContextRotateCTM(cgContext, -M_PI / 2.f);
+    CGContextTranslateCTM(cgContext, -CGRectGetMidX(rect), -CGRectGetMidY(rect));
+  }
+
+  DrawCellWithSnapping(cell, cgContext, rect,
                        meterSetting, VerticalAlignFactor(aFrame),
-                       mCellDrawView, IsFrameRTL(aFrame));
+                       mCellDrawView, !vertical && IsFrameRTL(aFrame));
+
+  CGContextRestoreGState(cgContext);
 
   NS_OBJC_END_TRY_ABORT_BLOCK
 }
 
 void
 nsNativeThemeCocoa::DrawTabPanel(CGContextRef cgContext, const HIRect& inBoxRect,
                                  nsIFrame* aFrame)
 {
new file mode 100644
--- /dev/null
+++ b/widget/reftests/meter-vertical-native-style-ref.html
@@ -0,0 +1,14 @@
+<html>
+  <style>
+    meter:nth-child(1) { -moz-transform: rotate(-90deg) translate(-2em, -2em); }
+    meter:nth-child(2) { -moz-transform: rotate(-90deg) translate(-2em, -6em); }
+    meter:nth-child(3) { -moz-transform: rotate(-90deg) translate(-2em, -10em); }
+    meter:nth-child(4) { -moz-transform: rotate(-90deg) translate(-2em, -14em); }
+    meter:nth-child(5) { -moz-transform: rotate(-90deg) translate(-2em, -18em); }
+    meter:nth-child(6) { -moz-transform: rotate(-90deg) translate(-2em, -22em); }
+    meter:nth-child(7) { -moz-transform: rotate(-90deg) translate(-2em, -26em); }
+  </style>
+<body>
+<meter></meter><meter min=0 low=0 high=1 optimum=2 max=10 value=10></meter><meter min=0 low=0 high=1 optimum=1 max=10 value=10></meter><meter min=0 low=1 high=2 optimum=0 max=10 value=10></meter><meter min=0 low=0 high=1 optimum=0 max=10 value=5></meter><meter min=0 low=0 high=1 optimum=0 max=10 value=5></meter><meter value=0.5></meter>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/widget/reftests/meter-vertical-native-style.html
@@ -0,0 +1,13 @@
+<html>
+  <style>
+    meter { -moz-orient: vertical; }
+  </style>
+  <body>
+<!-- For some reasons, the ref has a small offset when there are spaces between meters.
+     Given that we don't want to test -moz-transform and even a perfect match but just
+     the general rendering, we are going to keep this dirty test.
+     It's very similar to the non-vertical test with a difference, for the RTL: RTL
+     does not apply for vertical meters. -->
+<meter vaue=0></meter><meter min=0 low=0 high=10 optimum=10 max=10 value=10></meter><meter min=0 low=9 high=10 optimum=8 max=10 value=10></meter><meter min=0 low=8 high=9 optimum=0 max=10 value=10></meter><meter min=0 low=3 high=4 optimum=4 max=10 value=5></meter><meter min=0 low=9 high=10 optimum=10 max=10 value=5></meter><meter value=0.5 dir=rtl></meter>
+  </body>
+</html>
--- a/widget/reftests/reftest.list
+++ b/widget/reftests/reftest.list
@@ -1,5 +1,6 @@
 skip-if(!cocoaWidget) != 507947.html about:blank
 == progressbar-fallback-default-style.html progressbar-fallback-default-style-ref.html
 == meter-native-style.html meter-native-style-ref.html
+skip-if(!cocoaWidget) == meter-vertical-native-style.html meter-vertical-native-style-ref.html
 == meter-fallback-default-style.html meter-fallback-default-style-ref.html
 load 664925.xhtml
--- a/widget/xpwidgets/nsNativeTheme.cpp
+++ b/widget/xpwidgets/nsNativeTheme.cpp
@@ -457,16 +457,23 @@ nsNativeTheme::IsIndeterminateProgress(n
 
 bool
 nsNativeTheme::IsVerticalProgress(nsIFrame* aFrame)
 {
   return aFrame &&
          aFrame->GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL;
 }
 
+bool
+nsNativeTheme::IsVerticalMeter(nsIFrame* aFrame)
+{
+  NS_PRECONDITION(aFrame, "You have to pass a non-null aFrame");
+  return aFrame->GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL;
+}
+
 // menupopup:
 bool
 nsNativeTheme::IsSubmenu(nsIFrame* aFrame, bool* aLeftOfParent)
 {
   if (!aFrame)
     return false;
 
   nsIContent* parentContent = aFrame->GetContent()->GetParent();
--- a/widget/xpwidgets/nsNativeTheme.h
+++ b/widget/xpwidgets/nsNativeTheme.h
@@ -131,16 +131,19 @@ class nsNativeTheme : public nsITimerCal
   bool IsFirstTab(nsIFrame* aFrame);
   
   bool IsHorizontal(nsIFrame* aFrame);
 
   // progressbar:
   bool IsIndeterminateProgress(nsIFrame* aFrame, nsEventStates aEventStates);
   bool IsVerticalProgress(nsIFrame* aFrame);
 
+  // meter:
+  bool IsVerticalMeter(nsIFrame* aFrame);
+
   // textfield:
   bool IsReadOnly(nsIFrame* aFrame) {
       return CheckBooleanAttr(aFrame, nsGkAtoms::readonly);
   }
 
   // menupopup:
   bool IsSubmenu(nsIFrame* aFrame, bool* aLeftOfParent);