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
authorZack Weinberg <zweinberg@mozilla.com>
Fri, 03 Apr 2009 10:45:17 +0200
changeset 26885 f3d729b22f94d01cc90db5a9e8e80af6640bca11
parent 26884 5a4343f645ba6afe3f32bb90ccd4099667903c35
child 26886 8277119139f61a9c89648bb926b5a80fdc6e6e17
push idunknown
push userunknown
push dateunknown
bugs475535
milestone1.9.2a1pre
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
layout/forms/nsGfxCheckboxControlFrame.cpp
layout/forms/nsGfxCheckboxControlFrame.h
layout/forms/nsGfxRadioControlFrame.cpp
layout/forms/nsGfxRadioControlFrame.h
layout/reftests/bugs/373381-1-ref.html
layout/reftests/bugs/373381-1.html
layout/reftests/bugs/373381-2-ref.html
layout/reftests/bugs/373381-2.html
layout/reftests/bugs/373381-3-ref.html
layout/reftests/bugs/373381-3.html
layout/reftests/bugs/373381-4-ref.html
layout/reftests/bugs/373381-4.html
layout/reftests/bugs/reftest.list
layout/reftests/forms/checkbox-checked-native-notref.html
layout/reftests/forms/checkbox-checked-native.html
layout/reftests/forms/checkbox-checked-notref.html
layout/reftests/forms/checkbox-checked.html
layout/reftests/forms/radio-checked-native-notref.html
layout/reftests/forms/radio-checked-native.html
layout/reftests/forms/radio-checked-notref.html
layout/reftests/forms/radio-checked.html
layout/reftests/forms/reftest.list
layout/style/forms.css
layout/style/nsCSSAnonBoxList.h
--- a/layout/forms/nsGfxCheckboxControlFrame.cpp
+++ b/layout/forms/nsGfxCheckboxControlFrame.cpp
@@ -44,57 +44,68 @@
 #endif
 #include "nsIServiceManager.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsDisplayList.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsIDOMNSHTMLInputElement.h"
 
 static void
-PaintCheckMark(nsIRenderingContext& aRenderingContext,
-               const nsRect& aRect)
+PaintCheckMark(nsIFrame* aFrame,
+               nsIRenderingContext* aCtx,
+               const nsRect& aDirtyRect,
+               nsPoint aPt)
 {
+  nsRect rect(aPt, aFrame->GetSize());
+  rect.Deflate(aFrame->GetUsedBorderAndPadding());
+
   // Points come from the coordinates on a 7X7 unit box centered at 0,0
   const PRInt32 checkPolygonX[] = { -3, -1,  3,  3, -1, -3 };
   const PRInt32 checkPolygonY[] = { -1,  1, -3, -1,  3,  1 };
   const PRInt32 checkNumPoints = sizeof(checkPolygonX) / sizeof(PRInt32);
-  const PRInt32 checkSize      = 9; // This is value is determined by adding 2
-                                    // units to pad the 7x7 unit checkmark
+  const PRInt32 checkSize      = 9; // 2 units of padding on either side
+                                    // of the 7x7 unit checkmark
 
   // Scale the checkmark based on the smallest dimension
-  nscoord paintScale = PR_MIN(aRect.width, aRect.height) / checkSize;
-  nsPoint paintCenter(aRect.x + aRect.width  / 2,
-                      aRect.y + aRect.height / 2);
+  nscoord paintScale = PR_MIN(rect.width, rect.height) / checkSize;
+  nsPoint paintCenter(rect.x + rect.width  / 2,
+                      rect.y + rect.height / 2);
 
   nsPoint paintPolygon[checkNumPoints];
   // Convert checkmark for screen rendering
   for (PRInt32 polyIndex = 0; polyIndex < checkNumPoints; polyIndex++) {
     paintPolygon[polyIndex] = paintCenter +
                               nsPoint(checkPolygonX[polyIndex] * paintScale,
                                       checkPolygonY[polyIndex] * paintScale);
   }
 
-  aRenderingContext.FillPolygon(paintPolygon, checkNumPoints);
+  aCtx->SetColor(aFrame->GetStyleColor()->mColor);
+  aCtx->FillPolygon(paintPolygon, checkNumPoints);
 }
 
 static void
-PaintIndeterminateMark(nsIRenderingContext& aRenderingContext,
-                       const nsRect& aRect)
+PaintIndeterminateMark(nsIFrame* aFrame,
+                       nsIRenderingContext* aCtx,
+                       const nsRect& aDirtyRect,
+                       nsPoint aPt)
 {
-  // Drawing a thin horizontal line in the middle of the rect.
-  nsRect fillRect = aRect;
-  fillRect.height /= 4;
-  fillRect.y += (aRect.height - fillRect.height) / 2;
+  nsRect rect(aPt, aFrame->GetSize());
+  rect.Deflate(aFrame->GetUsedBorderAndPadding());
 
-  aRenderingContext.FillRect(fillRect);
+  rect.y += (rect.height - rect.height/4) / 2;
+  rect.height /= 4;
+
+  aCtx->SetColor(aFrame->GetStyleColor()->mColor);
+  aCtx->FillRect(rect);
 }
 
 //------------------------------------------------------------
 nsIFrame*
-NS_NewGfxCheckboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
+NS_NewGfxCheckboxControlFrame(nsIPresShell* aPresShell,
+                              nsStyleContext* aContext)
 {
   return new (aPresShell) nsGfxCheckboxControlFrame(aContext);
 }
 
 
 //------------------------------------------------------------
 // Initialize GFX-rendered state
 nsGfxCheckboxControlFrame::nsGfxCheckboxControlFrame(nsStyleContext* aContext)
@@ -106,188 +117,63 @@ nsGfxCheckboxControlFrame::~nsGfxCheckbo
 {
 }
 
 
 NS_QUERYFRAME_HEAD(nsGfxCheckboxControlFrame)
   NS_QUERYFRAME_ENTRY(nsICheckboxControlFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsFormControlFrame)
 
+#ifdef ACCESSIBILITY
 NS_IMETHODIMP
-nsGfxCheckboxControlFrame::Init(nsIContent* aContent,
-                                nsIFrame* aParent,
-                                nsIFrame* aPrevInFlow)
+nsGfxCheckboxControlFrame::GetAccessible(nsIAccessible** aAccessible)
 {
-  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)
-{
-  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,
                                      PRBool aChecked)
 {
   InvalidateOverflowRect();
   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)
-    : nsDisplayItem(aFrame) {
-    MOZ_COUNT_CTOR(nsDisplayCheckMark);
-  }
-#ifdef NS_BUILD_REFCNT_LOGGING
-  virtual ~nsDisplayCheckMark() {
-    MOZ_COUNT_DTOR(nsDisplayCheckMark);
-  }
-#endif
-
-  virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
-     const nsRect& aDirtyRect);
-  NS_DISPLAY_DECL_NAME("CheckMark")
-};
-
-void
-nsDisplayCheckMark::Paint(nsDisplayListBuilder* aBuilder,
-     nsIRenderingContext* aCtx, const nsRect& aDirtyRect) {
-  static_cast<nsGfxCheckboxControlFrame*>(mFrame)->
-    PaintCheckBox(*aCtx, aBuilder->ToReferenceFrame(mFrame), aDirtyRect);
-}
-
-
-//------------------------------------------------------------
-void
-nsGfxCheckboxControlFrame::PaintCheckBox(nsIRenderingContext& aRenderingContext,
-                                         nsPoint aPt,
-                                         const nsRect& aDirtyRect)
-{
-  // REVIEW: moved the mAppearance test out so we avoid constructing
-  // a display item if it's not needed
-  nsRect checkRect(aPt, mRect.Size());
-  checkRect.Deflate(GetUsedBorderAndPadding());
-
-  const nsStyleColor* color = GetStyleColor();
-  aRenderingContext.SetColor(color->mColor);
-
-  if (IsIndeterminate())
-    PaintIndeterminateMark(aRenderingContext, checkRect);
-  else
-    PaintCheckMark(aRenderingContext, checkRect);
-}
-
 //------------------------------------------------------------
 NS_IMETHODIMP
 nsGfxCheckboxControlFrame::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);
   
   // Get current checked state through content model.
   if ((!IsChecked() && !IsIndeterminate()) || !IsVisibleForPainting(aBuilder))
     return NS_OK;   // we're not checked or not visible, nothing to paint.
     
   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)
+    nsDisplayGeneric(this,
+                     IsIndeterminate()
+                     ? PaintIndeterminateMark : PaintCheckMark,
+                     "CheckedCheckbox"));
 }
 
 //------------------------------------------------------------
 PRBool
 nsGfxCheckboxControlFrame::IsChecked()
 {
   nsCOMPtr<nsIDOMHTMLInputElement> elem(do_QueryInterface(mContent));
   PRBool retval = PR_FALSE;
--- a/layout/forms/nsGfxCheckboxControlFrame.h
+++ b/layout/forms/nsGfxCheckboxControlFrame.h
@@ -39,20 +39,16 @@
 
 #include "nsFormControlFrame.h"
 #include "nsICheckboxControlFrame.h"
 
 #ifdef ACCESSIBILITY
 class nsIAccessible;
 #endif
 
-
-#define NS_GFX_CHECKBOX_CONTROL_FRAME_FACE_CONTEXT_INDEX   0 // for additional style contexts
-#define NS_GFX_CHECKBOX_CONTROL_FRAME_LAST_CONTEXT_INDEX   0
-
 class nsGfxCheckboxControlFrame : public nsFormControlFrame,
                                   public nsICheckboxControlFrame
 {
 public:
   nsGfxCheckboxControlFrame(nsStyleContext* aContext);
   virtual ~nsGfxCheckboxControlFrame();
   
 #ifdef DEBUG
@@ -64,38 +60,21 @@ public:
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists);
 
 #ifdef ACCESSIBILITY
   NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
 #endif
 
-
   //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();
   PRBool IsIndeterminate();
-
-  nsRefPtr<nsStyleContext> mCheckButtonFaceStyle;
 };
 
 #endif
 
--- a/layout/forms/nsGfxRadioControlFrame.cpp
+++ b/layout/forms/nsGfxRadioControlFrame.cpp
@@ -61,160 +61,74 @@ nsGfxRadioControlFrame::nsGfxRadioContro
 nsGfxRadioControlFrame::~nsGfxRadioControlFrame()
 {
 }
 
 NS_QUERYFRAME_HEAD(nsGfxRadioControlFrame)
   NS_QUERYFRAME_ENTRY(nsIRadioControlFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsFormControlFrame)
 
+#ifdef ACCESSIBILITY
 NS_IMETHODIMP
-nsGfxRadioControlFrame::Init(nsIContent* aContent,
-                             nsIFrame* aParent,
-                             nsIFrame* aPrevInFlow)
+nsGfxRadioControlFrame::GetAccessible(nsIAccessible** aAccessible)
 {
-  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)
-{
-  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;
 }
 #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 2px on all sides smaller than the content-box,
+  // drawn in the foreground color.
+  nsRect rect(aPt, aFrame->GetSize());
+  rect.Deflate(aFrame->GetUsedBorderAndPadding());
+  rect.Deflate(nsPresContext::CSSPixelsToAppUnits(2),
+               nsPresContext::CSSPixelsToAppUnits(2));
 
-//--------------------------------------------------------------
-void
-nsGfxRadioControlFrame::SetAdditionalStyleContext(PRInt32 aIndex, 
-                                                  nsStyleContext* aStyleContext)
-{
-  switch (aIndex) {
-  case NS_GFX_RADIO_CONTROL_FRAME_FACE_CONTEXT_INDEX:
-    mRadioButtonFaceStyle = aStyleContext;
-    break;
-  }
+  aCtx->SetColor(aFrame->GetStyleColor()->mColor);
+  aCtx->FillEllipse(rect);
 }
 
-//--------------------------------------------------------------
-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)
 {
   InvalidateOverflowRect();
   return NS_OK;
 }
-
--- a/layout/forms/nsGfxRadioControlFrame.h
+++ b/layout/forms/nsGfxRadioControlFrame.h
@@ -42,50 +42,29 @@
 #include "nsIRadioControlFrame.h"
 
 #ifdef ACCESSIBILITY
 class nsIAccessible;
 #endif
 
 // 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
-
--- a/layout/reftests/bugs/373381-1-ref.html
+++ b/layout/reftests/bugs/373381-1-ref.html
@@ -1,4 +1,3 @@
-<meta http-equiv="msthemecompatible" content="no">
-<input type="radio">
-<input type="radio">
-<input type="radio">
+<input type="radio">
+<input type="radio">
+<input type="radio">
--- a/layout/reftests/bugs/373381-1.html
+++ b/layout/reftests/bugs/373381-1.html
@@ -1,4 +1,3 @@
-<meta http-equiv="msthemecompatible" content="no">
-<input type="radio" style="width: auto">
-<input type="radio" style="height: auto">
-<input type="radio" style="height: auto; width: auto">
+<input type="radio" style="width: auto">
+<input type="radio" style="height: auto">
+<input type="radio" style="height: auto; width: auto">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/373381-2-ref.html
@@ -0,0 +1,3 @@
+<input type="radio" style="-moz-appearance:none">
+<input type="radio" style="-moz-appearance:none">
+<input type="radio" style="-moz-appearance:none">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/373381-2.html
@@ -0,0 +1,3 @@
+<input type="radio" style="width: auto; -moz-appearance: none">
+<input type="radio" style="height: auto; -moz-appearance: none">
+<input type="radio" style="height: auto; width: auto; -moz-appearance: none">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/373381-3-ref.html
@@ -0,0 +1,3 @@
+<input type="checkbox">
+<input type="checkbox">
+<input type="checkbox">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/373381-3.html
@@ -0,0 +1,3 @@
+<input type="checkbox" style="width: auto">
+<input type="checkbox" style="height: auto">
+<input type="checkbox" style="height: auto; width: auto">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/373381-4-ref.html
@@ -0,0 +1,3 @@
+<input type="checkbox" style="-moz-appearance:none">
+<input type="checkbox" style="-moz-appearance:none">
+<input type="checkbox" style="-moz-appearance:none">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/373381-4.html
@@ -0,0 +1,3 @@
+<input type="checkbox" style="width: auto; -moz-appearance: none">
+<input type="checkbox" style="height: auto; -moz-appearance: none">
+<input type="checkbox" style="height: auto; width: auto; -moz-appearance: none">
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -573,16 +573,19 @@ random-if(MOZ_WIDGET_TOOLKIT=="gtk2") ==
 == 372037-1.html 372037-1-ref.html
 == 372063-1.html 372063-1-ref.html
 == 372323-1.xhtml 372323-1-ref.xhtml
 == 372553-1.html 372553-1-ref.html
 == 372632-1.html 372632-1-ref.html
 == 373295-1.html 373295-1-ref.html
 == 373298-1.html 373298-1-ref.html
 == 373381-1.html 373381-1-ref.html
+== 373381-2.html 373381-2-ref.html
+== 373381-3.html 373381-3-ref.html
+== 373381-4.html 373381-4-ref.html
 == 375508-1.html 375508-1-ref.html
 == 373433-1.html 373433-1-ref.html
 == 372062-1.html 372062-1-ref.html
 == 372768-1.html 372768-1-ref.html
 == 373383-1.html 373383-1-ref.html
 == 374038-1.xul 374038-1-ref.xul
 == 374719-1.xul 374719-1-ref.xul
 == 374038-2.xul 374038-2-ref.xul
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/checkbox-checked-native-notref.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<input type="checkbox">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/checkbox-checked-native.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<input type="checkbox" checked>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/checkbox-checked-notref.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<input type="checkbox" style="-moz-appearance:none">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/checkbox-checked.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<input type="checkbox" style="-moz-appearance:none" checked>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/radio-checked-native-notref.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<input type="radio">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/radio-checked-native.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<input type="radio" checked>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/radio-checked-notref.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<input type="radio" style="-moz-appearance:none">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/radio-checked.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<input type="radio" style="-moz-appearance:none" checked>
--- a/layout/reftests/forms/reftest.list
+++ b/layout/reftests/forms/reftest.list
@@ -1,12 +1,27 @@
+
 == 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
 == input-text-size-1.html input-text-size-1-ref.html
 == input-text-size-2.html input-text-size-2-ref.html
 == radio-label-dynamic.html radio-label-dynamic-ref.html
 == out-of-bounds-selectedindex.html out-of-bounds-selectedindex-ref.html # bug 471741
 != indeterminate-checked.html indeterminate-checked-notref.html
 != indeterminate-unchecked.html indeterminate-unchecked-notref.html
 != 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
--- a/layout/style/forms.css
+++ b/layout/style/forms.css
@@ -400,45 +400,43 @@ input[type="file"] > input[type="button"
   height: inherit;
   font-size: inherit;
   letter-spacing: inherit;
 }
 
 /* radio buttons */
 input[type="radio"] {
   -moz-appearance: radio;
-  width: 13px;
-  height: 13px;
   margin: 3px 3px 0px 5px;
-  padding: 0 !important;
-  cursor: default;
-  -moz-binding: none;
-
   -moz-border-radius: 100% !important;
 }
 
 /* check boxes */
 input[type="checkbox"] {
   -moz-appearance: checkbox;
-  width: 13px;
-  height: 13px;
   margin: 3px 3px 3px 4px;
-  padding: 0 !important;
-  cursor: default;
-  -moz-binding: none;
-
   -moz-border-radius: 0 !important;
 }
 
 /* common features of radio buttons and check boxes */
 
+/* NOTE: The width, height, border-width, and padding here must all
+   add up the way nsFormControlFrame::GetIntrinsic(Width|Height)
+   expects them to, or they will not come out with total width equal
+   to total height on sites that set their 'width' or 'height' to 'auto'.
+   (Should we maybe set !important on width and height, then?)  */
 input[type="radio"],
 input[type="checkbox"] {
+  -moz-box-sizing: border-box;
+  width: 13px;
+  height: 13px;
+  cursor: default;
+  padding: 0 !important;
+  -moz-binding: none;
   /* same colors as |input| rule, but |!important| this time. */
-  -moz-box-sizing: border-box;
   background-color: -moz-Field ! important;
   color: -moz-FieldText ! important;
   border: 2px inset ThreeDFace ! important;
 }
 
 input[type="radio"][disabled],
 input[type="radio"][disabled]:active,
 input[type="radio"][disabled]:hover,
@@ -461,23 +459,16 @@ input[type="radio"]:focus {
 }
 
 input[type="checkbox"]:hover:active,
 input[type="radio"]:hover:active {
   background-color: ThreeDFace ! important;
   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 
    need to match button background/border values here */
 
 button, 
 input[type="reset"],
 input[type="button"],
--- a/layout/style/nsCSSAnonBoxList.h
+++ b/layout/style/nsCSSAnonBoxList.h
@@ -62,18 +62,16 @@ CSS_ANON_BOX(mozXULAnonymousBlock, ":-mo
 CSS_ANON_BOX(mozLineFrame, ":-moz-line-frame")
 
 CSS_ANON_BOX(buttonContent, ":-moz-button-content")
 CSS_ANON_BOX(mozButtonLabel, ":-moz-buttonlabel")
 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")
 CSS_ANON_BOX(table, ":-moz-table")
 CSS_ANON_BOX(tableCell, ":-moz-table-cell")
 CSS_ANON_BOX(tableColGroup, ":-moz-table-column-group")
 CSS_ANON_BOX(tableCol, ":-moz-table-column")
 CSS_ANON_BOX(tableOuter, ":-moz-table-outer")