Bug 511323. If a dropdown combobox (select) is given a translucent background color make sure to draw an opaque color on the dropdown's opaque widget so we don't get garbage painted. r=roc a=roc
authorTimothy Nikkel <tnikkel@gmail.com>
Sun, 20 Sep 2009 20:22:38 -0500
changeset 31833 d4a76980bee41a3bde3d5d4528c854e117c0a551
parent 31832 5c81af01b5077e3e881d24222a80b67bbf0912fc
child 31834 c0975a14cc92aa225637bb4b3f6689234608ce0d
push id197
push usertnikkel@gmail.com
push dateMon, 21 Sep 2009 22:05:45 +0000
reviewersroc, roc
bugs511323
milestone1.9.2a2pre
Bug 511323. If a dropdown combobox (select) is given a translucent background color make sure to draw an opaque color on the dropdown's opaque widget so we don't get garbage painted. r=roc a=roc
layout/forms/nsListControlFrame.cpp
layout/forms/nsListControlFrame.h
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -229,16 +229,26 @@ nsListControlFrame::BuildDisplayList(nsD
   // Don't allow painting of list controls when painting is suppressed.
   // XXX why do we need this here? we should never reach this. Maybe
   // because these can have widgets? Hmm
   if (aBuilder->IsBackgroundOnly())
     return NS_OK;
 
   DO_GLOBAL_REFLOW_COUNT_DSP("nsListControlFrame");
 
+  if (IsInDropDownMode()) {
+    // XXX Because we have an opaque widget and we get called to paint with
+    // this frame as the root of a stacking context we need make sure to draw
+    // some opaque color over the whole widget. (Bug 511323)
+    aLists.BorderBackground()->AppendNewToBottom(
+      new (aBuilder) nsDisplaySolidColor(
+        this, nsRect(aBuilder->ToReferenceFrame(this), GetSize()),
+        mLastDropdownBackstopColor));
+  }
+
   // REVIEW: The selection visibility code that used to be here is what
   // we already do by default.
   // REVIEW: There was code here to paint the theme background. But as far
   // as I can tell, we'd just paint the theme background twice because
   // it was redundant with nsCSSRendering::PaintBackground
   return nsHTMLScrollFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
 }
 
@@ -1730,23 +1740,48 @@ nsListControlFrame::SyncViewWithFrame()
   mComboboxFrame->AbsolutelyPositionDropDown();
 
   nsContainerFrame::PositionFrameView(this);
 }
 
 void
 nsListControlFrame::AboutToDropDown()
 {
+  NS_ASSERTION(IsInDropDownMode(),
+    "AboutToDropDown called without being in dropdown mode");
+
   if (mIsAllContentHere && mIsAllFramesHere && mHasBeenInitialized) {
     ScrollToIndex(GetSelectedIndex());
 #ifdef ACCESSIBILITY
     FireMenuItemActiveEvent(); // Inform assistive tech what got focus
 #endif
   }
   mItemSelectionStarted = PR_FALSE;
+
+  // Our widget doesn't get invalidated on changes to the rest of the document,
+  // so compute and store this color at the start of a dropdown so we don't
+  // get weird painting behaviour.
+  // We start looking for backgrounds above the combobox frame to avoid
+  // duplicating the combobox frame's background and compose each background
+  // color we find underneath until we have an opaque color, or run out of
+  // backgrounds. We compose with the PresContext default background color,
+  // which is always opaque, in case we don't end up with an opaque color.
+  // This gives us a very poor approximation of translucency.
+  nsIFrame* comboboxFrame = do_QueryFrame(mComboboxFrame);
+  nsStyleContext* context = comboboxFrame->GetStyleContext()->GetParent();
+  mLastDropdownBackstopColor = NS_RGBA(0,0,0,0);
+  while (NS_GET_A(mLastDropdownBackstopColor) < 255 && context) {
+    mLastDropdownBackstopColor =
+      NS_ComposeColors(context->GetStyleBackground()->mBackgroundColor,
+                       mLastDropdownBackstopColor);
+    context = context->GetParent();
+  }
+  mLastDropdownBackstopColor =
+    NS_ComposeColors(PresContext()->DefaultBackgroundColor(),
+                     mLastDropdownBackstopColor);
 }
 
 // We are about to be rolledup from the outside (ComboboxFrame)
 void
 nsListControlFrame::AboutToRollup()
 {
   // We've been updating the combobox with the keyboard up until now, but not
   // with the mouse.  The problem is, even with mouse selection, we are
--- a/layout/forms/nsListControlFrame.h
+++ b/layout/forms/nsListControlFrame.h
@@ -445,16 +445,20 @@ protected:
    */
   PRPackedBool mHasPendingInterruptAtStartOfReflow:1;
 
   // The last computed height we reflowed at if we're a combobox dropdown.
   // XXXbz should we be using a subclass here?  Or just not worry
   // about the extra member on listboxes?
   nscoord mLastDropdownComputedHeight;
 
+  // At the time of our last dropdown, the backstop color to draw in case we
+  // are translucent.
+  nscolor mLastDropdownBackstopColor;
+
   nsRefPtr<nsListEventListener> mEventListener;
 
   static nsListControlFrame * mFocused;
   static nsString * sIncrementalString;
   
 #ifdef DO_REFLOW_COUNTER
   PRInt32 mReflowId;
 #endif