Bug 641905 - Use native rendering for indeterminate progress bar on Windows. r=jimm
authorMounir Lamouri <mounir.lamouri@gmail.com>
Wed, 04 May 2011 16:57:48 +0200
changeset 69397 ddfa8bef5859dbf31966d19c61020a3c9c9c9acb
parent 69396 4a7b8019b83f46156bbe070baf99a565d2276d1d
child 69398 f645c31242541e12d22597b0c8af9a1ed9a21eae
push id76
push userbzbarsky@mozilla.com
push dateTue, 05 Jul 2011 17:00:57 +0000
treeherdermozilla-beta@d3a2732c35f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs641905
milestone6.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 641905 - Use native rendering for indeterminate progress bar on Windows. r=jimm
widget/src/windows/nsNativeThemeWin.cpp
--- a/widget/src/windows/nsNativeThemeWin.cpp
+++ b/widget/src/windows/nsNativeThemeWin.cpp
@@ -349,20 +349,29 @@ static CaptionButtonPadding buttonData[3
  * These values are found by experimenting and comparing against native widgets
  * used by the system. They are very unlikely exact but try to not be too wrong.
  */
 // PP_CHUNK is overflowing on the bottom for no appearant reasons.
 // This is a fix around this issue.
 static const PRInt32 kProgressDeterminedXPOverflow = 11;
 // Same thing but for PP_FILL.
 static const PRInt32 kProgressDeterminedVistaOverflow = 4;
+// Same thing but for indeterminate progress bar.
+// The value is the same for PP_CHUNK and PP_MOVEOVERLAY in that case.
+static const PRInt32 kProgressIndeterminateOverflow = 2;
 // The width of the overlay used to animate the progress bar (Vista and later).
 static const PRInt32 kProgressVistaOverlayWidth = 120;
-// Speed of the animation for determined Vista and later progress bars.
+// The width of the overlay used to for indeterminate progress bars on XP.
+static const PRInt32 kProgressXPOverlayWidth = 55;
+// Speed (px per ms) of the animation for determined Vista and later progress bars.
 static const double kProgressDeterminedVistaSpeed = 0.3;
+// Speed (px per ms) of the animation for indeterminate progress bars.
+static const double kProgressIndeterminateSpeed = 0.175;
+// Delay between two indeterminate progress bar cycle (in ms).
+static const PRInt32 kProgressIndeterminateDelay = 500;
 
 // Adds "hot" caption button padding to minimum widget size.
 static void AddPaddingRect(nsIntSize* aSize, CaptionButton button) {
   if (!aSize)
     return;
   RECT offset;
   if (!nsUXThemeData::IsAppThemed())
     offset = buttonData[CAPTION_CLASSIC].hotPadding[button];
@@ -669,17 +678,22 @@ nsNativeThemeWin::GetThemePartAndState(n
       return NS_OK;
     }
     case NS_THEME_PROGRESSBAR: {
       aPart = PP_BAR;
       aState = TS_NORMAL;
       return NS_OK;
     }
     case NS_THEME_PROGRESSBAR_CHUNK: {
-      aPart = nsUXThemeData::sIsVistaOrLater ? PP_FILL : PP_CHUNK;
+      nsIFrame* stateFrame = aFrame->GetParent();
+      nsEventStates eventStates = GetContentState(stateFrame, aWidgetType);
+      // If the element is indeterminate, we are going to render it ourself so
+      // we have to return aPart = -1.
+      aPart = IsIndeterminateProgress(stateFrame, eventStates)
+                ? -1 : nsUXThemeData::sIsVistaOrLater ? PP_FILL : PP_CHUNK;
       aState = TS_NORMAL;
       return NS_OK;
     }
     case NS_THEME_PROGRESSBAR_VERTICAL: {
       aPart = PP_BARVERT;
       aState = TS_NORMAL;
       return NS_OK;
     }
@@ -1301,19 +1315,23 @@ RENDER_AGAIN:
   }
   else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE ||
            aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) {
     OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_RESTORE);
   }
   else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) {
     OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_CLOSE);
   } else if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK) {
-    widgetRect.bottom -= nsUXThemeData::sIsVistaOrLater
-                           ? kProgressDeterminedVistaOverflow
-                           : kProgressDeterminedXPOverflow;
+    nsIFrame* stateFrame = aFrame->GetParent();
+    nsEventStates eventStates = GetContentState(stateFrame, aWidgetType);
+    widgetRect.bottom -= IsIndeterminateProgress(stateFrame, eventStates)
+                           ? kProgressIndeterminateOverflow
+                           : nsUXThemeData::sIsVistaOrLater
+                             ? kProgressDeterminedVistaOverflow
+                             : kProgressDeterminedXPOverflow;
   }
 
   // widgetRect is the bounding box for a widget, yet the scale track is only
   // a small portion of this size, so the edges of the scale need to be
   // adjusted to the real size of the track.
   if (aWidgetType == NS_THEME_SCALE_HORIZONTAL ||
       aWidgetType == NS_THEME_SCALE_VERTICAL) {
     RECT contentRect;
@@ -1538,40 +1556,65 @@ RENDER_AGAIN:
     ctx->Fill();
 
     ctx->NewPath();
     ctx->Rectangle(buttonbox3, PR_TRUE);
     ctx->Fill();
 
     ctx->Restore();
     ctx->SetOperator(currentOp);
-  } else if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK &&
-             nsUXThemeData::sIsVistaOrLater) {
-    if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 60)) {
-      NS_WARNING("unable to animate progress widget!");
+  } else if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK) {
+    /**
+     * Here, we draw the animated part of the progress bar.
+     * A progress bar has always an animated part on Windows Vista and later.
+     * On Windows XP, a progress bar has an animated part when in an
+     * indeterminated state.
+     * When the progress bar is indeterminated, no background is painted so we
+     * only see the animated part.
+     * When the progress bar is determinated, the animated part is a glow draw
+     * on top of the background (PP_FILL).
+     */
+    nsIFrame* stateFrame = aFrame->GetParent();
+    nsEventStates eventStates = GetContentState(stateFrame, aWidgetType);
+    bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates);
+
+    if (indeterminate || nsUXThemeData::sIsVistaOrLater) {
+      if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 60)) {
+        NS_WARNING("unable to animate progress widget!");
+      }
+
+      const PRInt32 overlayWidth = nsUXThemeData::sIsVistaOrLater
+                                     ? kProgressVistaOverlayWidth
+                                     : kProgressXPOverlayWidth;
+      const double pixelsPerMillisecond = indeterminate
+                                            ? kProgressIndeterminateSpeed
+                                            : kProgressDeterminedVistaSpeed;
+
+      const PRInt32 frameWidth = widgetRect.right - widgetRect.left;
+      PRInt32 animationWidth = frameWidth + overlayWidth;
+      // When indeterminated, we add a delay of one second between two cycles.
+      if (indeterminate) {
+        animationWidth += static_cast<PRInt32>(pixelsPerMillisecond *
+                          kProgressIndeterminateDelay);
+      }
+      const double interval = animationWidth / pixelsPerMillisecond;
+      // We have to pass a double* to modf and we can't pass NULL.
+      double tempValue;
+      double ratio = modf(PR_IntervalToMilliseconds(PR_IntervalNow())/interval,
+                          &tempValue);
+      PRInt32 dx = static_cast<PRInt32>(animationWidth * ratio) - overlayWidth;
+
+      RECT overlayRect = widgetRect;
+      overlayRect.left += dx;
+      overlayRect.right = overlayRect.left + overlayWidth;
+      nsUXThemeData::drawThemeBG(theme, hdc,
+                                 nsUXThemeData::sIsVistaOrLater ? PP_MOVEOVERLAY
+                                                                : PP_CHUNK,
+                                 state, &overlayRect, &clipRect);
     }
-
-    // Add the animated glow.
-    const PRInt32 frameWidth = widgetRect.right - widgetRect.left;
-    static const PRInt32 overlayWidth = kProgressVistaOverlayWidth;
-    static const double pixelsPerMillisecond = kProgressDeterminedVistaSpeed;
-
-    PRInt32 animationWidth = frameWidth + overlayWidth;
-    double interval = animationWidth / pixelsPerMillisecond;
-    // We have to pass a double* to modf and we can't pass NULL.
-    double tempValue;
-    double ratio = modf(PR_IntervalToMilliseconds(PR_IntervalNow())/interval,
-                        &tempValue);
-    PRInt32 dx = static_cast<PRInt32>(animationWidth * ratio) - overlayWidth;
-
-    RECT overlayRect = widgetRect;
-    overlayRect.left += dx;
-    overlayRect.right = overlayRect.left + overlayWidth;
-    nsUXThemeData::drawThemeBG(theme, hdc, PP_MOVEOVERLAY, state, &overlayRect,
-                               &clipRect);
   }
 
 
   nativeDrawing.EndNativeDrawing();
 
   if (nativeDrawing.ShouldRenderAgain())
     goto RENDER_AGAIN;