Bug 662870 - Use a native rendering for meter elements on MacOS X. r=bgirard

This commit is contained in:
Mounir Lamouri 2012-06-06 09:56:28 +02:00
parent 8aee8c7ad2
commit 20983000a7
5 changed files with 144 additions and 1 deletions

View File

@ -79,6 +79,8 @@ protected:
void DrawProgress(CGContextRef context, const HIRect& inBoxRect,
bool inIsIndeterminate, bool inIsHorizontal,
double inValue, double inMaxValue, nsIFrame* aFrame);
void DrawMeter(CGContextRef context, const HIRect& inBoxRect,
nsIFrame* aFrame);
void DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
nsEventStates inState, nsIFrame* aFrame,
const SegmentedControlRenderSettings& aSettings);
@ -126,6 +128,7 @@ private:
NSPopUpButtonCell* mDropdownCell;
NSComboBoxCell* mComboBoxCell;
NSProgressBarCell* mProgressBarCell;
NSLevelIndicatorCell* mMeterBarCell;
CellDrawView* mCellDrawView;
};

View File

@ -24,6 +24,8 @@
#include "nsNativeThemeColors.h"
#include "nsIScrollableFrame.h"
#include "nsIDOMHTMLProgressElement.h"
#include "nsIDOMHTMLMeterElement.h"
#include "mozilla/dom/Element.h"
#include "gfxContext.h"
#include "gfxQuartzSurface.h"
@ -422,6 +424,9 @@ nsNativeThemeCocoa::nsNativeThemeCocoa()
mProgressBarCell = [[NSProgressBarCell alloc] init];
mMeterBarCell = [[NSLevelIndicatorCell alloc]
initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle];
mCellDrawView = [[CellDrawView alloc] init];
NS_OBJC_END_TRY_ABORT_BLOCK;
@ -431,6 +436,7 @@ nsNativeThemeCocoa::~nsNativeThemeCocoa()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
[mMeterBarCell release];
[mProgressBarCell release];
[mPushButtonCell release];
[mRadioButtonCell release];
@ -1335,6 +1341,92 @@ nsNativeThemeCocoa::DrawProgress(CGContextRef cgContext, const HIRect& inBoxRect
NS_OBJC_END_TRY_ABORT_BLOCK;
}
static const CellRenderSettings meterSetting = {
{
NSMakeSize(0, 16), // mini
NSMakeSize(0, 16), // small
NSMakeSize(0, 16) // regular
},
{
NSZeroSize, NSZeroSize, NSZeroSize
},
{
{ // Leopard
{1, 1, 1, 1}, // mini
{1, 1, 1, 1}, // small
{1, 1, 1, 1} // regular
}
}
};
void
nsNativeThemeCocoa::DrawMeter(CGContextRef cgContext, const HIRect& inBoxRect,
nsIFrame* aFrame)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK
NS_PRECONDITION(aFrame, "aFrame should not be null here!");
nsCOMPtr<nsIDOMHTMLMeterElement> meterElement =
do_QueryInterface(aFrame->GetContent());
// When using -moz-meterbar on an non meter element, we will not be able to
// get all the needed information so we just draw an empty meter.
if (!meterElement) {
DrawCellWithSnapping(mMeterBarCell, cgContext, inBoxRect,
meterSetting, VerticalAlignFactor(aFrame),
mCellDrawView, IsFrameRTL(aFrame));
return;
}
double value;
double min;
double max;
double low;
double high;
double optimum;
// NOTE: if we were allowed to static_cast to nsHTMLMeterElement we would be
// able to use nicer getters...
meterElement->GetValue(&value);
meterElement->GetMin(&min);
meterElement->GetMax(&max);
meterElement->GetLow(&low);
meterElement->GetHigh(&high);
meterElement->GetOptimum(&optimum);
NSLevelIndicatorCell* cell = mMeterBarCell;
[cell setMinValue:min];
[cell setMaxValue:max];
[cell setDoubleValue:value];
/**
* The way HTML and Cocoa defines the meter/indicator widget are different.
* So, we are going to use a trick to get the Cocoa widget showing what we
* are expecting: we set the warningValue or criticalValue to the current
* value when we want to have the widget to be in the warning or critical
* state.
*/
nsEventStates states = aFrame->GetContent()->AsElement()->State();
// Reset previously set warning and critical values.
[cell setWarningValue:max+1];
[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,
meterSetting, VerticalAlignFactor(aFrame),
mCellDrawView, IsFrameRTL(aFrame));
NS_OBJC_END_TRY_ABORT_BLOCK
}
void
nsNativeThemeCocoa::DrawTabPanel(CGContextRef cgContext, const HIRect& inBoxRect,
nsIFrame* aFrame)
@ -2028,9 +2120,14 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
GetProgressMaxValue(aFrame), aFrame);
break;
case NS_THEME_METERBAR:
DrawMeter(cgContext, macRect, aFrame);
break;
case NS_THEME_PROGRESSBAR_CHUNK:
case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
// do nothing, covered by the progress bar cases above
case NS_THEME_METERBAR_CHUNK:
// Do nothing: progress and meter bars cases will draw chunks.
break;
case NS_THEME_TREEVIEW_TWISTY:
@ -2614,6 +2711,8 @@ nsNativeThemeCocoa::WidgetStateChanged(nsIFrame* aFrame, PRUint8 aWidgetType,
case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
case NS_THEME_PROGRESSBAR:
case NS_THEME_PROGRESSBAR_VERTICAL:
case NS_THEME_METERBAR:
case NS_THEME_METERBAR_CHUNK:
*aShouldRepaint = false;
return NS_OK;
}
@ -2698,6 +2797,8 @@ nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* a
case NS_THEME_PROGRESSBAR_VERTICAL:
case NS_THEME_PROGRESSBAR_CHUNK:
case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
case NS_THEME_METERBAR:
case NS_THEME_METERBAR_CHUNK:
case NS_THEME_TOOLBAR_SEPARATOR:
case NS_THEME_TAB_PANELS:
@ -2764,6 +2865,7 @@ nsNativeThemeCocoa::WidgetIsContainer(PRUint8 aWidgetType)
case NS_THEME_RADIO:
case NS_THEME_CHECKBOX:
case NS_THEME_PROGRESSBAR:
case NS_THEME_METERBAR:
return false;
break;
}

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<body>
<!-- Empty meter, no bar. -->
<meter></meter>
<!-- Full meter green colored. -->
<meter min=0 low=0 high=1 optimum=2 max=10 value=10></meter>
<!-- Full meter orange colored. -->
<meter min=0 low=0 high=1 optimum=1 max=10 value=10></meter>
<!-- Full meter red colored. -->
<meter min=0 low=1 high=2 optimum=0 max=10 value=10></meter>
<!-- Half-empty orange colored. -->
<meter min=0 low=0 high=1 optimum=0 max=10 value=5></meter>
<!-- Half-empty orange colored. -->
<meter min=0 low=0 high=1 optimum=0 max=10 value=5></meter>
<!-- With RTL, the bar should begin on the right. -->
<meter style="-moz-transform: scale(-1, 1);" value=0.5></meter>
</body>
</html>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<body>
<meter vaue=0></meter>
<!-- Should be green. -->
<meter min=0 low=0 high=10 optimum=10 max=10 value=10></meter>
<!-- Should be orange. -->
<meter min=0 low=9 high=10 optimum=8 max=10 value=10></meter>
<!-- Should be red. -->
<meter min=0 low=8 high=9 optimum=0 max=10 value=10></meter>
<!-- Half-full orange. -->
<meter min=0 low=3 high=4 optimum=4 max=10 value=5></meter>
<!-- Half-full orange. -->
<meter min=0 low=9 high=10 optimum=10 max=10 value=5></meter>
<!-- Test RTL -->
<meter dir='rtl' value=0.5></meter>
</body>
</html>

View File

@ -1,4 +1,5 @@
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
== meter-fallback-default-style.html meter-fallback-default-style-ref.html
load 664925.xhtml