Bug 475535 - don't go through PaintBackgroundWithSC to draw non-native radio buttons and checkboxes; remove special UA pseudo-elements for styling these. r+sr=roc

This commit is contained in:
Zack Weinberg 2009-04-02 09:57:13 +02:00
Родитель 726accf85c
Коммит 26daaa1428
15 изменённых файлов: 64 добавлений и 246 удалений

Просмотреть файл

@ -89,7 +89,8 @@ PaintIndeterminateMark(nsIRenderingContext& aRenderingContext,
//------------------------------------------------------------
nsIFrame*
NS_NewGfxCheckboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
NS_NewGfxCheckboxControlFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext)
{
return new (aPresShell) nsGfxCheckboxControlFrame(aContext);
}
@ -111,63 +112,22 @@ NS_QUERYFRAME_HEAD(nsGfxCheckboxControlFrame)
NS_QUERYFRAME_ENTRY(nsICheckboxControlFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsFormControlFrame)
NS_IMETHODIMP
nsGfxCheckboxControlFrame::Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow)
{
nsresult rv = nsFormControlFrame::Init(aContent, aParent, aPrevInFlow);
if (NS_SUCCEEDED(rv)) {
mCheckButtonFaceStyle =
PresContext()->PresShell()->StyleSet()->
ResolvePseudoStyleFor(aContent, nsCSSAnonBoxes::check,
GetStyleContext());
}
return rv;
}
#ifdef ACCESSIBILITY
NS_IMETHODIMP nsGfxCheckboxControlFrame::GetAccessible(nsIAccessible** aAccessible)
NS_IMETHODIMP
nsGfxCheckboxControlFrame::GetAccessible(nsIAccessible** aAccessible)
{
nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
nsCOMPtr<nsIAccessibilityService> accService
= do_GetService("@mozilla.org/accessibilityService;1");
if (accService) {
return accService->CreateHTMLCheckboxAccessible(static_cast<nsIFrame*>(this), aAccessible);
return accService->CreateHTMLCheckboxAccessible(
static_cast<nsIFrame*>(this), aAccessible);
}
return NS_ERROR_FAILURE;
}
#endif
//--------------------------------------------------------------
nsStyleContext*
nsGfxCheckboxControlFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
{
switch (aIndex) {
case NS_GFX_CHECKBOX_CONTROL_FRAME_FACE_CONTEXT_INDEX:
return mCheckButtonFaceStyle;
break;
default:
return nsnull;
}
}
//--------------------------------------------------------------
void
nsGfxCheckboxControlFrame::SetAdditionalStyleContext(PRInt32 aIndex,
nsStyleContext* aStyleContext)
{
switch (aIndex) {
case NS_GFX_CHECKBOX_CONTROL_FRAME_FACE_CONTEXT_INDEX:
mCheckButtonFaceStyle = aStyleContext;
break;
}
}
//------------------------------------------------------------
NS_IMETHODIMP
nsGfxCheckboxControlFrame::OnChecked(nsPresContext* aPresContext,
@ -177,12 +137,6 @@ nsGfxCheckboxControlFrame::OnChecked(nsPresContext* aPresContext,
return NS_OK;
}
static void PaintCheckMarkFromStyle(nsIFrame* aFrame,
nsIRenderingContext* aCtx, const nsRect& aDirtyRect, nsPoint aPt) {
static_cast<nsGfxCheckboxControlFrame*>(aFrame)
->PaintCheckBoxFromStyle(*aCtx, aPt, aDirtyRect);
}
class nsDisplayCheckMark : public nsDisplayItem {
public:
nsDisplayCheckMark(nsGfxCheckboxControlFrame* aFrame)
@ -244,45 +198,8 @@ nsGfxCheckboxControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (IsThemed())
return NS_OK; // No need to paint the checkmark. The theme will do it.
// Paint the checkmark
if (mCheckButtonFaceStyle) {
// This code actually works now; not sure how useful it'll be
// (The purpose is to allow the UA stylesheet to substitute its own
// checkmark for the default one)
// XXXbz maybe we should just remove this, together with the
// attendant complexity
const nsStyleBackground* myBackground = mCheckButtonFaceStyle->GetStyleBackground();
if (!myBackground->IsTransparent())
return aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayGeneric(this, PaintCheckMarkFromStyle, "CheckMarkFromStyle"));
}
return aLists.Content()->AppendNewToTop(new (aBuilder) nsDisplayCheckMark(this));
}
void
nsGfxCheckboxControlFrame::PaintCheckBoxFromStyle(
nsIRenderingContext& aRenderingContext, nsPoint aPt, const nsRect& aDirtyRect) {
const nsStylePosition* myPosition = mCheckButtonFaceStyle->GetStylePosition();
const nsStyleBorder* myBorder = mCheckButtonFaceStyle->GetStyleBorder();
const nsStyleBackground* myBackground = mCheckButtonFaceStyle->GetStyleBackground();
NS_ASSERTION(myPosition->mWidth.GetUnit() == eStyleUnit_Coord &&
myPosition->mHeight.GetUnit() == eStyleUnit_Coord,
"styles for :-moz-checkbox are incorrect or author-accessible");
nscoord width = myPosition->mWidth.GetCoordValue();
nscoord height = myPosition->mHeight.GetCoordValue();
// Position the button centered within the control's rectangle.
nscoord x = (mRect.width - width) / 2;
nscoord y = (mRect.height - height) / 2;
nsRect rect(aPt.x + x, aPt.y + y, width, height);
nsCSSRendering::PaintBackgroundWithSC(PresContext(), aRenderingContext,
this, aDirtyRect, rect, *myBackground,
*myBorder, PR_FALSE);
nsCSSRendering::PaintBorder(PresContext(), aRenderingContext, this,
aDirtyRect, rect, *myBorder,
mCheckButtonFaceStyle);
return aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayCheckMark(this));
}
//------------------------------------------------------------

Просмотреть файл

@ -73,22 +73,11 @@ public:
//nsICheckboxControlFrame methods
NS_IMETHOD OnChecked(nsPresContext* aPresContext, PRBool aChecked);
virtual nsStyleContext* GetAdditionalStyleContext(PRInt32 aIndex) const;
virtual void SetAdditionalStyleContext(PRInt32 aIndex,
nsStyleContext* aStyleContext);
NS_DECL_QUERYFRAME
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* asPrevInFlow);
void PaintCheckBox(nsIRenderingContext& aRenderingContext,
nsPoint aPt, const nsRect& aDirtyRect);
void PaintCheckBoxFromStyle(nsIRenderingContext& aRenderingContext,
nsPoint aPt, const nsRect& aDirtyRect);
protected:
PRBool IsChecked();

Просмотреть файл

@ -66,29 +66,16 @@ NS_QUERYFRAME_HEAD(nsGfxRadioControlFrame)
NS_QUERYFRAME_ENTRY(nsIRadioControlFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsFormControlFrame)
NS_IMETHODIMP
nsGfxRadioControlFrame::Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow)
{
nsresult rv = nsFormControlFrame::Init(aContent, aParent, aPrevInFlow);
if (NS_SUCCEEDED(rv)) {
mRadioButtonFaceStyle =
PresContext()->PresShell()->StyleSet()->
ResolvePseudoStyleFor(aContent, nsCSSAnonBoxes::radio,
GetStyleContext());
}
return rv;
}
#ifdef ACCESSIBILITY
NS_IMETHODIMP nsGfxRadioControlFrame::GetAccessible(nsIAccessible** aAccessible)
NS_IMETHODIMP
nsGfxRadioControlFrame::GetAccessible(nsIAccessible** aAccessible)
{
nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
nsCOMPtr<nsIAccessibilityService> accService
= do_GetService("@mozilla.org/accessibilityService;1");
if (accService) {
return accService->CreateHTMLRadioButtonAccessible(static_cast<nsIFrame*>(this), aAccessible);
return accService->CreateHTMLRadioButtonAccessible(
static_cast<nsIFrame*>(this), aAccessible);
}
return NS_ERROR_FAILURE;
@ -96,120 +83,45 @@ NS_IMETHODIMP nsGfxRadioControlFrame::GetAccessible(nsIAccessible** aAccessible)
#endif
//--------------------------------------------------------------
nsStyleContext*
nsGfxRadioControlFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
// Draw the dot for a non-native radio button in the checked state.
static void
PaintCheckedRadioButton(nsIFrame* aFrame,
nsIRenderingContext* aCtx,
const nsRect& aDirtyRect,
nsPoint aPt)
{
switch (aIndex) {
case NS_GFX_RADIO_CONTROL_FRAME_FACE_CONTEXT_INDEX:
return mRadioButtonFaceStyle;
break;
default:
return nsnull;
}
// The dot is an ellipse precisely filling the content-box, drawn in
// the foreground color.
nsRect rect(aPt, aFrame->GetSize());
rect.Deflate(aFrame->GetUsedBorderAndPadding());
aCtx->SetColor(aFrame->GetStyleColor()->mColor);
aCtx->FillEllipse(rect);
}
//--------------------------------------------------------------
void
nsGfxRadioControlFrame::SetAdditionalStyleContext(PRInt32 aIndex,
nsStyleContext* aStyleContext)
{
switch (aIndex) {
case NS_GFX_RADIO_CONTROL_FRAME_FACE_CONTEXT_INDEX:
mRadioButtonFaceStyle = aStyleContext;
break;
}
}
//--------------------------------------------------------------
void
nsGfxRadioControlFrame::PaintRadioButtonFromStyle(
nsIRenderingContext& aRenderingContext, nsPoint aPt, const nsRect& aDirtyRect)
{
const nsStyleBorder* myBorder = mRadioButtonFaceStyle->GetStyleBorder();
// Paint the button for the radio button using CSS background rendering code
const nsStyleBackground* myColor = mRadioButtonFaceStyle->GetStyleBackground();
const nsStyleColor* color = mRadioButtonFaceStyle->GetStyleColor();
const nsStylePosition* myPosition = mRadioButtonFaceStyle->GetStylePosition();
NS_ASSERTION(myPosition->mWidth.GetUnit() == eStyleUnit_Coord &&
myPosition->mHeight.GetUnit() == eStyleUnit_Coord,
"styles for :-moz-radio are incorrect or author-accessible");
nscoord width = myPosition->mWidth.GetCoordValue();
nscoord height = myPosition->mHeight.GetCoordValue();
// Position the button centered within the radio control's rectangle.
nscoord x = (mRect.width - width) / 2;
nscoord y = (mRect.height - height) / 2;
nsRect rect = nsRect(x, y, width, height) + aPt;
// So we will use PaintBackgroundWithSC to paint the dot,
// but it uses the mBackgroundColor for painting and we need to use the mColor
// so create a temporary style color struct and set it up appropriately
// XXXldb It would make more sense to use
// |aRenderingContext.FillEllipse| here, but on at least GTK that
// doesn't draw a round enough circle.
nsStyleBackground tmpColor = *myColor;
tmpColor.mBackgroundColor = color->mColor;
nsPresContext* pc = PresContext();
nsCSSRendering::PaintBackgroundWithSC(pc, aRenderingContext,
this, aDirtyRect, rect,
tmpColor, *myBorder, PR_FALSE);
nsCSSRendering::PaintBorder(pc, aRenderingContext, this,
aDirtyRect, rect, *myBorder, mRadioButtonFaceStyle, 0);
}
class nsDisplayRadioButtonFromStyle : public nsDisplayItem {
public:
nsDisplayRadioButtonFromStyle(nsGfxRadioControlFrame* aFrame)
: nsDisplayItem(aFrame) {
MOZ_COUNT_CTOR(nsDisplayRadioButtonFromStyle);
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayRadioButtonFromStyle() {
MOZ_COUNT_DTOR(nsDisplayRadioButtonFromStyle);
}
#endif
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
const nsRect& aDirtyRect);
NS_DISPLAY_DECL_NAME("RadioButton")
};
void
nsDisplayRadioButtonFromStyle::Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx, const nsRect& aDirtyRect) {
static_cast<nsGfxRadioControlFrame*>(mFrame)->
PaintRadioButtonFromStyle(*aCtx, aBuilder->ToReferenceFrame(mFrame), aDirtyRect);
}
//--------------------------------------------------------------
NS_IMETHODIMP
nsGfxRadioControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
nsresult rv = nsFormControlFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
nsresult rv = nsFormControlFrame::BuildDisplayList(aBuilder, aDirtyRect,
aLists);
NS_ENSURE_SUCCESS(rv, rv);
if (!IsVisibleForPainting(aBuilder))
return NS_OK;
if (IsThemed())
return NS_OK; // No need to paint the radio button. The theme will do it.
return NS_OK; // The theme will paint the check, if any.
if (!mRadioButtonFaceStyle)
return NS_OK;
PRBool checked = PR_TRUE;
GetCurrentCheckState(&checked); // Get check state from the content model
if (!checked)
return NS_OK;
return aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayRadioButtonFromStyle(this));
nsDisplayGeneric(this, PaintCheckedRadioButton, "CheckedRadioButton"));
}
//--------------------------------------------------------------
NS_IMETHODIMP
nsGfxRadioControlFrame::OnChecked(nsPresContext* aPresContext,
PRBool aChecked)
@ -217,4 +129,3 @@ nsGfxRadioControlFrame::OnChecked(nsPresContext* aPresContext,
InvalidateOverflowRect();
return NS_OK;
}

Просмотреть файл

@ -47,45 +47,24 @@ class nsIAccessible;
// nsGfxRadioControlFrame
#define NS_GFX_RADIO_CONTROL_FRAME_FACE_CONTEXT_INDEX 0 // for additional style contexts
#define NS_GFX_RADIO_CONTROL_FRAME_LAST_CONTEXT_INDEX 0
class nsGfxRadioControlFrame : public nsFormControlFrame,
public nsIRadioControlFrame
{
private:
public:
nsGfxRadioControlFrame(nsStyleContext* aContext);
~nsGfxRadioControlFrame();
NS_DECL_QUERYFRAME
//nsIRadioControlFrame methods
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* asPrevInFlow);
#ifdef ACCESSIBILITY
NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
#endif
NS_IMETHOD OnChecked(nsPresContext* aPresContext, PRBool aChecked);
virtual nsStyleContext* GetAdditionalStyleContext(PRInt32 aIndex) const;
virtual void SetAdditionalStyleContext(PRInt32 aIndex,
nsStyleContext* aStyleContext);
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
void PaintRadioButtonFromStyle(nsIRenderingContext& aRenderingContext, nsPoint aPt,
const nsRect& aDirtyRect);
protected:
nsRefPtr<nsStyleContext> mRadioButtonFaceStyle;
};
#endif

Просмотреть файл

@ -0,0 +1,2 @@
<!doctype html>
<input type="checkbox">

Просмотреть файл

@ -0,0 +1,2 @@
<!doctype html>
<input type="checkbox" checked>

Просмотреть файл

@ -0,0 +1,2 @@
<!doctype html>
<input type="checkbox" style="-moz-appearance:none">

Просмотреть файл

@ -0,0 +1,2 @@
<!doctype html>
<input type="checkbox" style="-moz-appearance:none" checked>

Просмотреть файл

@ -0,0 +1,2 @@
<!doctype html>
<input type="radio">

Просмотреть файл

@ -0,0 +1,2 @@
<!doctype html>
<input type="radio" checked>

Просмотреть файл

@ -0,0 +1,2 @@
<!doctype html>
<input type="radio" style="-moz-appearance:none">

Просмотреть файл

@ -0,0 +1,2 @@
<!doctype html>
<input type="radio" style="-moz-appearance:none" checked>

Просмотреть файл

@ -1,3 +1,4 @@
== checkbox-label-dynamic.html checkbox-label-dynamic-ref.html
== checkbox-radio-stretched.html checkbox-radio-stretched-ref.html # bug 464589
== input-file-width-clip-1.html input-file-width-clip-ref.html # bug 409587
@ -10,3 +11,17 @@
!= indeterminate-native-checked.html indeterminate-native-checked-notref.html
!= indeterminate-native-unchecked.html indeterminate-native-unchecked-notref.html
== indeterminate-selector.html indeterminate-selector-ref.html
!= checkbox-checked.html checkbox-checked-notref.html
!= checkbox-checked-native.html checkbox-checked-native-notref.html
!= radio-checked.html radio-checked-notref.html
!= radio-checked-native.html radio-checked-native-notref.html
!= checkbox-checked.html about:blank
!= checkbox-checked-notref.html about:blank
!= radio-checked.html about:blank
!= radio-checked-notref.html about:blank
!= checkbox-checked-native.html about:blank
!= checkbox-checked-native-notref.html about:blank
!= radio-checked-native.html about:blank
!= radio-checked-native-notref.html about:blank

Просмотреть файл

@ -408,7 +408,7 @@ input[type="radio"] {
width: 13px;
height: 13px;
margin: 3px 3px 0px 5px;
padding: 0 !important;
padding: 2px !important; /* padding controls size of dot in checked state */
cursor: default;
-moz-binding: none;
@ -466,13 +466,6 @@ input[type="radio"]:hover:active {
border-style: inset !important;
}
*|*::-moz-radio {
width: 4px;
height: 4px;
background-color: -moz-FieldText ! important;
-moz-border-radius: 3px;
}
/* buttons */
/* Note: Values in nsNativeTheme IsWidgetStyled function

Просмотреть файл

@ -67,8 +67,6 @@ CSS_ANON_BOX(cellContent, ":-moz-cell-content")
CSS_ANON_BOX(dropDownList, ":-moz-dropdown-list")
CSS_ANON_BOX(fieldsetContent, ":-moz-fieldset-content")
CSS_ANON_BOX(framesetBlank, ":-moz-frameset-blank")
CSS_ANON_BOX(radio, ":-moz-radio")
CSS_ANON_BOX(check, ":-moz-checkbox")
CSS_ANON_BOX(mozDisplayComboboxControlFrame, ":-moz-display-comboboxcontrol-frame")
CSS_ANON_BOX(inlineTable, ":-moz-inline-table")