Bug 656909 - Use a native rendering for vertical progress bar on Windows. r=jimm

This commit is contained in:
Mounir Lamouri 2011-05-17 18:39:22 +02:00
parent b4edcad58f
commit 6c39859dae
4 changed files with 76 additions and 23 deletions

View File

@ -349,10 +349,14 @@ 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.
*/
// The width of the overlay used to animate the progress bar (Vista and later).
static const PRInt32 kProgressVistaOverlayWidth = 120;
// The width of the overlay used to for indeterminate progress bars on XP.
static const PRInt32 kProgressXPOverlayWidth = 55;
// The width of the overlay used to animate the horizontal progress bar (Vista and later).
static const PRInt32 kProgressHorizontalVistaOverlaySize = 120;
// The width of the overlay used for the horizontal indeterminate progress bars on XP.
static const PRInt32 kProgressHorizontalXPOverlaySize = 55;
// The height of the overlay used to animate the vertical progress bar (Vista and later).
static const PRInt32 kProgressVerticalOverlaySize = 45;
// The height of the overlay used for the vertical indeterminate progress bar (Vista and later).
static const PRInt32 kProgressVerticalIndeterminateOverlaySize = 60;
// Speed (px per ms) of the animation for determined Vista and later progress bars.
static const double kProgressDeterminedVistaSpeed = 0.225;
// Speed (px per ms) of the animation for indeterminate progress bars.
@ -672,17 +676,24 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType,
return NS_OK;
}
case NS_THEME_PROGRESSBAR: {
aPart = PP_BAR;
aPart = IsVerticalProgress(aFrame) ? PP_BARVERT : PP_BAR;
aState = TS_NORMAL;
return NS_OK;
}
case NS_THEME_PROGRESSBAR_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;
if (IsIndeterminateProgress(stateFrame, eventStates)) {
// If the element is indeterminate, we are going to render it ourself so
// we have to return aPart = -1.
aPart = -1;
} else if (IsVerticalProgress(stateFrame)) {
aPart = nsUXThemeData::sIsVistaOrLater ? PP_FILLVERT : PP_CHUNKVERT;
} else {
aPart = nsUXThemeData::sIsVistaOrLater ? PP_FILL : PP_CHUNK;
}
aState = TS_NORMAL;
return NS_OK;
}
@ -1567,43 +1578,75 @@ RENDER_AGAIN:
nsIFrame* stateFrame = aFrame->GetParent();
nsEventStates eventStates = GetContentState(stateFrame, aWidgetType);
bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates);
bool vertical = IsVerticalProgress(stateFrame);
if (indeterminate || nsUXThemeData::sIsVistaOrLater) {
if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 60)) {
NS_WARNING("unable to animate progress widget!");
}
const PRInt32 overlayWidth = nsUXThemeData::sIsVistaOrLater
? kProgressVistaOverlayWidth
: kProgressXPOverlayWidth;
/**
* Unfortunately, vertical progress bar support on Windows seems weak and
* PP_MOVEOVERLAYRECT looks really different from PP_MOVEOVERLAY.
* Thus, we have to change the size and even don't use it for vertical
* indeterminate progress bars.
*/
PRInt32 overlaySize;
if (nsUXThemeData::sIsVistaOrLater) {
if (vertical) {
overlaySize = indeterminate ? kProgressVerticalIndeterminateOverlaySize
: kProgressVerticalOverlaySize;
} else {
overlaySize = kProgressHorizontalVistaOverlaySize;
}
} else {
overlaySize = kProgressHorizontalXPOverlaySize;
}
const double pixelsPerMillisecond = indeterminate
? kProgressIndeterminateSpeed
: kProgressDeterminedVistaSpeed;
const PRInt32 delay = indeterminate ? kProgressIndeterminateDelay
: kProgressDeterminedVistaDelay;
const PRInt32 frameWidth = widgetRect.right - widgetRect.left;
const PRInt32 animationWidth = frameWidth + overlayWidth +
const PRInt32 frameSize = vertical ? widgetRect.bottom - widgetRect.top
: widgetRect.right - widgetRect.left;
const PRInt32 animationSize = frameSize + overlaySize +
static_cast<PRInt32>(pixelsPerMillisecond * delay);
const double interval = animationWidth / pixelsPerMillisecond;
const double interval = animationSize / 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);
// If the frame direction is RTL, we want to have the animation going RTL.
// ratio is in [0.0; 1.0[ range, inverting it reverse the animation.
if (IsFrameRTL(aFrame)) {
if (!vertical && IsFrameRTL(aFrame)) {
ratio = 1.0 - ratio;
}
PRInt32 dx = static_cast<PRInt32>(animationWidth * ratio) - overlayWidth;
PRInt32 dx = static_cast<PRInt32>(animationSize * ratio) - overlaySize;
RECT overlayRect = widgetRect;
overlayRect.left += dx;
overlayRect.right = overlayRect.left + overlayWidth;
nsUXThemeData::drawThemeBG(theme, hdc,
nsUXThemeData::sIsVistaOrLater ? PP_MOVEOVERLAY
: PP_CHUNK,
state, &overlayRect, &clipRect);
if (vertical) {
overlayRect.bottom -= dx;
overlayRect.top = overlayRect.bottom - overlaySize;
} else {
overlayRect.left += dx;
overlayRect.right = overlayRect.left + overlaySize;
}
PRInt32 overlayPart;
if (vertical) {
if (nsUXThemeData::sIsVistaOrLater) {
overlayPart = indeterminate ? PP_MOVEOVERLAY : PP_MOVEOVERLAYVERT;
} else {
overlayPart = PP_CHUNKVERT;
}
} else {
overlayPart = nsUXThemeData::sIsVistaOrLater ? PP_MOVEOVERLAY : PP_CHUNK;
}
nsUXThemeData::drawThemeBG(theme, hdc, overlayPart, state, &overlayRect,
&clipRect);
}
}

View File

@ -117,7 +117,9 @@
#define PP_CHUNK 3
#define PP_CHUNKVERT 4
#define PP_FILL 5
#define PP_FILLVERT 6
#define PP_MOVEOVERLAY 8
#define PP_MOVEOVERLAYVERT 9
// Tab constants
#define TABP_TAB 4

View File

@ -472,6 +472,13 @@ nsNativeTheme::IsIndeterminateProgress(nsIFrame* aFrame,
eCaseMatters);
}
PRBool
nsNativeTheme::IsVerticalProgress(nsIFrame* aFrame)
{
return aFrame &&
aFrame->GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL;
}
// menupopup:
PRBool
nsNativeTheme::IsSubmenu(nsIFrame* aFrame, PRBool* aLeftOfParent)

View File

@ -161,6 +161,7 @@ class nsNativeTheme : public nsITimerCallback
// progressbar:
PRBool IsIndeterminateProgress(nsIFrame* aFrame, nsEventStates aEventStates);
PRBool IsVerticalProgress(nsIFrame* aFrame);
// textfield:
PRBool IsReadOnly(nsIFrame* aFrame) {