From 33dc8a610ce2bb4474fe93c26b5635f5130fb2ff Mon Sep 17 00:00:00 2001 From: Mounir Lamouri Date: Wed, 4 May 2011 16:57:48 +0200 Subject: [PATCH] Bug 641905 - Use native rendering for indeterminate progress bar on Windows. r=jimm --- widget/src/windows/nsNativeThemeWin.cpp | 99 ++++++++++++++++++------- 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/widget/src/windows/nsNativeThemeWin.cpp b/widget/src/windows/nsNativeThemeWin.cpp index 5d1b52bf1ea5..9ebdd49a833a 100644 --- a/widget/src/windows/nsNativeThemeWin.cpp +++ b/widget/src/windows/nsNativeThemeWin.cpp @@ -354,10 +354,19 @@ static CaptionButtonPadding buttonData[3] = { 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) { @@ -674,7 +683,12 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType, 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; } @@ -1306,9 +1320,13 @@ RENDER_AGAIN: 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 @@ -1543,30 +1561,55 @@ RENDER_AGAIN: 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(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(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(animationWidth * ratio) - overlayWidth; - - RECT overlayRect = widgetRect; - overlayRect.left += dx; - overlayRect.right = overlayRect.left + overlayWidth; - nsUXThemeData::drawThemeBG(theme, hdc, PP_MOVEOVERLAY, state, &overlayRect, - &clipRect); }