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
authorTimothy Nikkel <tnikkel@gmail.com>
Tue, 25 Aug 2009 12:07:57 -0700
changeset 31954 d023a0300d0f0f8a583c083082d8a10920b9dcbf
parent 31953 4919c19abb16c44928ad87b026cce86e2fae30b2
child 31955 38f64aaaa56542ebf30fb6139f5677e30e59e256
push id8749
push userrocallahan@mozilla.com
push dateTue, 25 Aug 2009 19:23:03 +0000
treeherdermozilla-central@c5a789064023 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs511323
milestone1.9.3a1pre
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
layout/forms/nsListControlFrame.cpp
layout/forms/nsListControlFrame.h
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -228,16 +228,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);
 }
 
@@ -1726,23 +1736,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
@@ -438,21 +438,25 @@ protected:
   // pass.  This only happens for auto heights.
   PRPackedBool mMightNeedSecondPass: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
 
 private:
   // for incremental typing navigation
   static nsAString& GetIncrementalString ();
   static DOMTimeStamp gLastKeyTime;