From ed49149b6d84e1fbad5d15aa1363a686743d3c3a Mon Sep 17 00:00:00 2001
From: Kathleen Brade <brade@pearlcrescent.com>
Date: Wed, 28 Nov 2012 15:08:40 -0500
Subject: [PATCH 22/41] Do not expose system colors to CSS or canvas.

This patch also contains a hack to use properly contrasting colors if the
desktop theme specifies white on black for text colors (see
https://trac.torproject.org/projects/tor/ticket/7920). These color choices are
also not exposed to content.
---
 content/canvas/src/nsCanvasRenderingContext2D.cpp  |  28 ++-
 .../canvas/src/nsCanvasRenderingContext2DAzure.cpp |  34 +++-
 .../canvas/src/nsCanvasRenderingContext2DAzure.h   |   5 +-
 layout/base/nsLayoutUtils.cpp                      |  51 +++++
 layout/base/nsLayoutUtils.h                        |   4 +
 layout/generic/nsFrame.cpp                         |   6 +-
 layout/style/nsRuleNode.cpp                        |   5 +-
 widget/LookAndFeel.h                               |  12 ++
 widget/xpwidgets/nsXPLookAndFeel.cpp               | 214 ++++++++++++++++++++-
 widget/xpwidgets/nsXPLookAndFeel.h                 |   5 +-
 10 files changed, 343 insertions(+), 21 deletions(-)

diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp
index 0dec654..7132e4f 100644
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -32,6 +32,7 @@
 #include "nsCSSParser.h"
 #include "mozilla/css/StyleRule.h"
 #include "mozilla/css/Declaration.h"
+#include "mozilla/css/Loader.h"
 #include "nsComputedDOMStyle.h"
 #include "nsStyleSet.h"
 
@@ -159,8 +160,9 @@ class nsCanvasGradient MOZ_FINAL : public nsIDOMCanvasGradient
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENT_PRIVATE_IID)
 
-    nsCanvasGradient(gfxPattern* pat)
-        : mPattern(pat)
+    nsCanvasGradient(mozilla::css::Loader* aLoader, gfxPattern* pat)
+        : mCSSLoader(aLoader)
+        , mPattern(pat)
     {
     }
 
@@ -181,8 +183,17 @@ public:
             return NS_ERROR_DOM_SYNTAX_ERR;
         }
 
+        nsIPresShell* presShell = nullptr;
+        if (mCSSLoader) {
+          nsIDocument *doc = mCSSLoader->GetDocument();
+          if (doc)
+            presShell = doc->GetShell();
+        }
+
         nscolor color;
-        if (!nsRuleNode::ComputeColor(value, nullptr, nullptr, color)) {
+        if (!nsRuleNode::ComputeColor(value,
+                           presShell ? presShell->GetPresContext() : nullptr,
+                           nullptr, color)) {
             return NS_ERROR_DOM_SYNTAX_ERR;
         }
 
@@ -194,6 +205,7 @@ public:
     NS_DECL_ISUPPORTS
 
 protected:
+    mozilla::css::Loader* mCSSLoader; // not ref counted, it owns us
     nsRefPtr<gfxPattern> mPattern;
 };
 
@@ -1814,7 +1826,10 @@ nsCanvasRenderingContext2D::CreateLinearGradient(float x0, float y0, float x1, f
     if (!gradpat)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat);
+    nsIDocument* doc = mCanvasElement ? mCanvasElement->OwnerDoc() : nullptr;
+    mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nullptr;
+    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(cssLoader,
+                                                               gradpat);
     if (!grad)
         return NS_ERROR_OUT_OF_MEMORY;
 
@@ -1836,7 +1851,10 @@ nsCanvasRenderingContext2D::CreateRadialGradient(float x0, float y0, float r0, f
     if (!gradpat)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat);
+    nsIDocument* doc = mCanvasElement ? mCanvasElement->OwnerDoc() : nullptr;
+    mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nullptr;
+    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(cssLoader,
+                                                               gradpat);
     if (!grad)
         return NS_ERROR_OUT_OF_MEMORY;
 
diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
index d86ba32..84c1927 100644
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -31,6 +31,7 @@
 #include "nsCSSParser.h"
 #include "mozilla/css/StyleRule.h"
 #include "mozilla/css/Declaration.h"
+#include "mozilla/css/Loader.h"
 #include "nsComputedDOMStyle.h"
 #include "nsStyleSet.h"
 
@@ -140,9 +141,10 @@ NS_MEMORY_REPORTER_IMPLEMENT(CanvasAzureMemory,
 class nsCanvasRadialGradientAzure : public nsCanvasGradientAzure
 {
 public:
-  nsCanvasRadialGradientAzure(const Point &aBeginOrigin, Float aBeginRadius,
+  nsCanvasRadialGradientAzure(mozilla::css::Loader* aLoader,
+                              const Point &aBeginOrigin, Float aBeginRadius,
                               const Point &aEndOrigin, Float aEndRadius)
-    : nsCanvasGradientAzure(RADIAL)
+    : nsCanvasGradientAzure(aLoader, RADIAL)
     , mCenter1(aBeginOrigin)
     , mCenter2(aEndOrigin)
     , mRadius1(aBeginRadius)
@@ -159,8 +161,9 @@ public:
 class nsCanvasLinearGradientAzure : public nsCanvasGradientAzure
 {
 public:
-  nsCanvasLinearGradientAzure(const Point &aBegin, const Point &aEnd)
-    : nsCanvasGradientAzure(LINEAR)
+  nsCanvasLinearGradientAzure(mozilla::css::Loader* aLoader,
+                              const Point &aBegin, const Point &aEnd)
+    : nsCanvasGradientAzure(aLoader, LINEAR)
     , mBegin(aBegin)
     , mEnd(aEnd)
   {
@@ -363,8 +366,17 @@ nsCanvasGradientAzure::AddColorStop(float offset, const nsAString& colorstr)
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
+  nsIPresShell* presShell = nullptr;
+  if (mCSSLoader) {
+    nsIDocument *doc = mCSSLoader->GetDocument();
+    if (doc)
+      presShell = doc->GetShell();
+  }
+
   nscolor color;
-  if (!nsRuleNode::ComputeColor(value, nullptr, nullptr, color)) {
+  if (!nsRuleNode::ComputeColor(value,
+                          presShell ? presShell->GetPresContext() : nullptr,
+                          nullptr, color)) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
@@ -1788,8 +1800,10 @@ nsCanvasRenderingContext2DAzure::CreateLinearGradient(double x0, double y0, doub
     return nullptr;
   }
 
-  nsRefPtr<nsIDOMCanvasGradient> grad =
-    new nsCanvasLinearGradientAzure(Point(x0, y0), Point(x1, y1));
+  nsIDocument* doc = mCanvasElement ? mCanvasElement->OwnerDoc() : nullptr;
+  mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nullptr;
+  nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasLinearGradientAzure(
+                                     cssLoader, Point(x0, y0), Point(x1, y1));
 
   return grad.forget();
 }
@@ -1818,8 +1832,10 @@ nsCanvasRenderingContext2DAzure::CreateRadialGradient(double x0, double y0, doub
     return nullptr;
   }
 
-  nsRefPtr<nsIDOMCanvasGradient> grad =
-    new nsCanvasRadialGradientAzure(Point(x0, y0), r0, Point(x1, y1), r1);
+  nsIDocument* doc = mCanvasElement ? mCanvasElement->OwnerDoc() : nullptr;
+  mozilla::css::Loader* cssLoader = doc ? doc->CSSLoader() : nullptr;
+  nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasRadialGradientAzure(
+                            cssLoader, Point(x0, y0), r0, Point(x1, y1), r1);
 
   return grad.forget();
 }
diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.h b/content/canvas/src/nsCanvasRenderingContext2DAzure.h
index 05ccf61..629d78a 100644
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.h
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.h
@@ -71,11 +71,14 @@ public:
   NS_IMETHOD AddColorStop(float offset, const nsAString& colorstr);
 
 protected:
-  nsCanvasGradientAzure(Type aType) : mType(aType)
+  nsCanvasGradientAzure(mozilla::css::Loader* aLoader, Type aType)
+      : mCSSLoader(aLoader)
+      , mType(aType)
   {}
 
   nsTArray<mozilla::gfx::GradientStop> mRawStops;
   mozilla::RefPtr<mozilla::gfx::GradientStops> mStops;
+  mozilla::css::Loader* mCSSLoader; // not ref counted, it owns us
   Type mType;
   virtual ~nsCanvasGradientAzure() {}
 };
diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
index 87b0d34..00a4994 100644
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -76,6 +76,7 @@
 #include "nsSVGForeignObjectFrame.h"
 #include "nsSVGOuterSVGFrame.h"
 #include "nsStyleStructInlines.h"
+#include "mozilla/LookAndFeel.h"
 
 #include "mozilla/Preferences.h"
 
@@ -3134,13 +3135,63 @@ ShouldDarkenColors(nsPresContext* aPresContext)
 nscolor
 nsLayoutUtils::GetColor(nsIFrame* aFrame, nsCSSProperty aProperty)
 {
+  if (aProperty == eCSSProperty_color)
+  {
+    nscolor nativeColor = NS_RGB(0, 0, 0);
+    if (GetNativeTextColor(aFrame, nativeColor))
+      return nativeColor;
+  }
+
   nscolor color = aFrame->GetVisitedDependentColor(aProperty);
   if (ShouldDarkenColors(aFrame->PresContext())) {
     color = DarkenColor(color);
   }
+
   return color;
 }
 
+bool
+nsLayoutUtils::GetNativeTextColor(nsIFrame* aFrame, nscolor& aColor)
+{
+  nsPresContext *presContext = aFrame->PresContext();
+  if (!presContext->IsChrome()) {
+    // If native appearance was used to draw the background of the containing
+    // frame, return a contrasting native foreground color instead of the
+    // color from the element's style.  This avoids a problem where black
+    // text was displayed on a black background when a Windows theme such as
+    // "High Contrast Black" was used.  The background is drawn inside
+    // nsNativeThemeWin::ClassicDrawWidgetBackground().
+    //
+    // Because both the background color and this foreground color are used
+    // directly without exposing the colors via CSS computed styles, the
+    // native colors are not leaked to content.
+    nsIFrame* bgFrame =
+                    nsCSSRendering::FindNonTransparentBackgroundFrame(aFrame);
+    if (bgFrame) {
+      const nsStyleDisplay* displayData = bgFrame->GetStyleDisplay();
+      uint8_t widgetType = displayData->mAppearance;
+      nsITheme *theme = presContext->GetTheme();
+      if (theme && widgetType && theme->ThemeSupportsWidget(presContext,
+                                                            bgFrame,
+                                                            widgetType)) {
+        bool isDisabled = false;
+        nsIContent* frameContent = bgFrame->GetContent();
+        if (frameContent && frameContent->IsElement()) {
+          nsEventStates es = frameContent->AsElement()->State();
+          isDisabled = es.HasState(NS_EVENT_STATE_DISABLED); 
+        } 
+
+        if (NS_SUCCEEDED(LookAndFeel::GetColorForNativeAppearance(widgetType,
+                                                       isDisabled, &aColor))) {
+            return true;
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
 gfxFloat
 nsLayoutUtils::GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
                                    nscoord aY, nscoord aAscent)
diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h
index 4fb1f93..6552f04 100644
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -989,6 +989,10 @@ public:
   // Get a suitable foreground color for painting aProperty for aFrame.
   static nscolor GetColor(nsIFrame* aFrame, nsCSSProperty aProperty);
 
+  // Get the native text color if appropriate.  If false is returned, callers
+  // should fallback to the CSS color.
+  static bool GetNativeTextColor(nsIFrame* aFrame, nscolor& aColor);
+
   // Get a baseline y position in app units that is snapped to device pixels.
   static gfxFloat GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
                                       nscoord aY, nscoord aAscent);
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
index 75a2bb9..d684a62 100644
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1446,7 +1446,11 @@ nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
 nscolor
 nsIFrame::GetCaretColorAt(int32_t aOffset)
 {
-  // Use text color.
+  nscolor color = NS_RGB(0, 0, 0);
+  if (nsLayoutUtils::GetNativeTextColor(this, color))
+    return color;
+
+  // Use CSS text color.
   return GetStyleColor()->mColor;
 }
 
diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp
index 86eff1f..732b1fe 100644
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -747,7 +747,10 @@ static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
     int32_t intValue = aValue.GetIntValue();
     if (0 <= intValue) {
       LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue;
-      if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID, &aResult))) {
+      bool useStandinsForNativeColors = aPresContext &&
+                                        !aPresContext->IsChrome();
+      if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID,
+                                    useStandinsForNativeColors, &aResult))) {
         result = true;
       }
     }
diff --git a/widget/LookAndFeel.h b/widget/LookAndFeel.h
index e46bb13..f947084 100644
--- a/widget/LookAndFeel.h
+++ b/widget/LookAndFeel.h
@@ -446,6 +446,18 @@ public:
   static nsresult GetColor(ColorID aID, nscolor* aResult);
 
   /**
+   * This variant of GetColor() take an extra Boolean parameter that allows
+   * the caller to ask that hard-coded color values be substituted for
+   * native colors (used when it is desireable to hide system colors to
+   * avoid system fingerprinting).
+   */
+  static nsresult GetColor(ColorID aID, bool aUseStandinsForNativeColors,
+                           nscolor* aResult);
+
+  static nsresult GetColorForNativeAppearance(uint8_t aWidgetType,
+                                          bool aIsDisabled, nscolor* aResult);
+
+  /**
    * GetInt() and GetFloat() return a int or float value for aID.  The result
    * might be distance, time, some flags or a int value which has particular
    * meaning.  See each document at definition of each ID for the detail.
diff --git a/widget/xpwidgets/nsXPLookAndFeel.cpp b/widget/xpwidgets/nsXPLookAndFeel.cpp
index 50c2c86..704963a 100644
--- a/widget/xpwidgets/nsXPLookAndFeel.cpp
+++ b/widget/xpwidgets/nsXPLookAndFeel.cpp
@@ -11,6 +11,7 @@
 #include "nsLookAndFeel.h"
 #include "nsCRT.h"
 #include "nsFont.h"
+#include "nsThemeConstants.h"
 #include "mozilla/Preferences.h"
 
 #include "gfxPlatform.h"
@@ -476,6 +477,155 @@ nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor &aColor)
   return false;
 }
 
+bool
+nsXPLookAndFeel::ColorIsNotCSSAccessible(ColorID aID)
+{
+  bool result = false;
+
+  switch (aID) {
+    case eColorID_WindowBackground:
+    case eColorID_WindowForeground:
+    case eColorID_WidgetBackground:
+    case eColorID_WidgetForeground:
+    case eColorID_WidgetSelectBackground:
+    case eColorID_WidgetSelectForeground:
+    case eColorID_Widget3DHighlight:
+    case eColorID_Widget3DShadow:
+    case eColorID_TextBackground:
+    case eColorID_TextForeground:
+    case eColorID_TextSelectBackground:
+    case eColorID_TextSelectForeground:
+    case eColorID_TextSelectBackgroundDisabled:
+    case eColorID_TextSelectBackgroundAttention:
+    case eColorID_TextHighlightBackground:
+    case eColorID_TextHighlightForeground:
+    case eColorID_IMERawInputBackground:
+    case eColorID_IMERawInputForeground:
+    case eColorID_IMERawInputUnderline:
+    case eColorID_IMESelectedRawTextBackground:
+    case eColorID_IMESelectedRawTextForeground:
+    case eColorID_IMESelectedRawTextUnderline:
+    case eColorID_IMEConvertedTextBackground:
+    case eColorID_IMEConvertedTextForeground:
+    case eColorID_IMEConvertedTextUnderline:
+    case eColorID_IMESelectedConvertedTextBackground:
+    case eColorID_IMESelectedConvertedTextForeground:
+    case eColorID_IMESelectedConvertedTextUnderline:
+    case eColorID_SpellCheckerUnderline:
+      result = true;
+      break;
+    default:
+      break;
+  }
+
+  return result;
+}
+
+nscolor
+nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID)
+{
+  nscolor result = NS_RGB(0xFF, 0xFF, 0xFF);
+
+  // The stand-in colors are taken from the Windows 7 Aero theme
+  // except Mac-specific colors which are taken from Mac OS 10.7.
+  switch (aID) {
+    // CSS 2 colors:
+    case eColorID_activeborder:      result = NS_RGB(0xB4, 0xB4, 0xB4); break;
+    case eColorID_activecaption:     result = NS_RGB(0x99, 0xB4, 0xD1); break;
+    case eColorID_appworkspace:      result = NS_RGB(0xAB, 0xAB, 0xAB); break;
+    case eColorID_background:        result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID_buttonface:        result = NS_RGB(0xF0, 0xF0, 0xF0); break;
+    case eColorID_buttonhighlight:   result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID_buttonshadow:      result = NS_RGB(0xA0, 0xA0, 0xA0); break;
+    case eColorID_buttontext:        result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID_captiontext:       result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID_graytext:          result = NS_RGB(0x6D, 0x6D, 0x6D); break;
+    case eColorID_highlight:         result = NS_RGB(0x33, 0x99, 0xFF); break;
+    case eColorID_highlighttext:     result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID_inactiveborder:    result = NS_RGB(0xF4, 0xF7, 0xFC); break;
+    case eColorID_inactivecaption:   result = NS_RGB(0xBF, 0xCD, 0xDB); break;
+    case eColorID_inactivecaptiontext:
+      result = NS_RGB(0x43, 0x4E, 0x54); break;
+    case eColorID_infobackground:    result = NS_RGB(0xFF, 0xFF, 0xE1); break;
+    case eColorID_infotext:          result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID_menu:              result = NS_RGB(0xF0, 0xF0, 0xF0); break;
+    case eColorID_menutext:          result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID_scrollbar:         result = NS_RGB(0xC8, 0xC8, 0xC8); break;
+    case eColorID_threeddarkshadow:  result = NS_RGB(0x69, 0x69, 0x69); break;
+    case eColorID_threedface:        result = NS_RGB(0xF0, 0xF0, 0xF0); break;
+    case eColorID_threedhighlight:   result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID_threedlightshadow: result = NS_RGB(0xE3, 0xE3, 0xE3); break;
+    case eColorID_threedshadow:      result = NS_RGB(0xA0, 0xA0, 0xA0); break;
+    case eColorID_window:            result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID_windowframe:       result = NS_RGB(0x64, 0x64, 0x64); break;
+    case eColorID_windowtext:        result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID__moz_buttondefault:
+      result = NS_RGB(0x69, 0x69, 0x69); break;
+    case eColorID__moz_field:        result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID__moz_fieldtext:    result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID__moz_dialog:       result = NS_RGB(0xF0, 0xF0, 0xF0); break;
+    case eColorID__moz_dialogtext:   result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID__moz_dragtargetzone:
+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID__moz_cellhighlight:
+      result = NS_RGB(0xF0, 0xF0, 0xF0); break;
+    case eColorID__moz_cellhighlighttext:
+      result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID__moz_html_cellhighlight:
+      result = NS_RGB(0x33, 0x99, 0xFF); break;
+    case eColorID__moz_html_cellhighlighttext:
+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID__moz_buttonhoverface:
+      result = NS_RGB(0xF0, 0xF0, 0xF0); break;
+    case eColorID__moz_buttonhovertext:
+      result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID__moz_menuhover:
+      result = NS_RGB(0x33, 0x99, 0xFF); break;
+    case eColorID__moz_menuhovertext:
+      result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID__moz_menubartext:
+      result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID__moz_menubarhovertext:
+      result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID__moz_oddtreerow:
+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID__moz_mac_chrome_active:
+      result = NS_RGB(0xB2, 0xB2, 0xB2); break;
+    case eColorID__moz_mac_chrome_inactive:
+      result = NS_RGB(0xE1, 0xE1, 0xE1); break;
+    case eColorID__moz_mac_focusring:
+      result = NS_RGB(0x60, 0x9D, 0xD7); break;
+    case eColorID__moz_mac_menuselect:
+      result = NS_RGB(0x38, 0x75, 0xD7); break;
+    case eColorID__moz_mac_menushadow:
+      result = NS_RGB(0xA3, 0xA3, 0xA3); break;
+    case eColorID__moz_mac_menutextdisable:
+      result = NS_RGB(0x88, 0x88, 0x88); break;
+    case eColorID__moz_mac_menutextselect:
+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID__moz_mac_disabledtoolbartext:
+      result = NS_RGB(0x3F, 0x3F, 0x3F); break;
+    case eColorID__moz_mac_alternateprimaryhighlight:
+      result = NS_RGB(0x38, 0x75, 0xD7); break;
+    case eColorID__moz_mac_secondaryhighlight:
+      result = NS_RGB(0xD4, 0xD4, 0xD4); break;
+    case eColorID__moz_win_mediatext:
+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID__moz_win_communicationstext:
+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    case eColorID__moz_nativehyperlinktext:
+      result = NS_RGB(0x00, 0x66, 0xCC); break;
+    case eColorID__moz_comboboxtext:
+      result = NS_RGB(0x00, 0x00, 0x00); break;
+    case eColorID__moz_combobox:
+      result = NS_RGB(0xFF, 0xFF, 0xFF); break;
+    default:
+      break;
+  }
+
+  return result;
+}
+
 //
 // All these routines will return NS_OK if they have a value,
 // in which case the nsLookAndFeel should use that value;
@@ -483,7 +633,8 @@ nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor &aColor)
 // platform-specific nsLookAndFeel should use its own values instead.
 //
 nsresult
-nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
+nsXPLookAndFeel::GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors,
+                              nscolor &aResult)
 {
   if (!sInitialized)
     Init();
@@ -569,7 +720,10 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
   }
 #endif // DEBUG_SYSTEM_COLOR_USE
 
-  if (IS_COLOR_CACHED(aID)) {
+  if (aUseStandinsForNativeColors && ColorIsNotCSSAccessible(aID))
+    aUseStandinsForNativeColors = false;
+
+  if (!aUseStandinsForNativeColors && IS_COLOR_CACHED(aID)) {
     aResult = sCachedColors[aID];
     return NS_OK;
   }
@@ -603,6 +757,12 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult)
     return NS_OK;
   }
 
+  if (sUseNativeColors && aUseStandinsForNativeColors)
+  {
+    aResult = GetStandinForNativeColor(aID);
+    return NS_OK;
+  }
+
   if (sUseNativeColors && NS_SUCCEEDED(NativeGetColor(aID, aResult))) {
     if ((gfxPlatform::GetCMSMode() == eCMSMode_All) &&
          !IsSpecialColor(aID, aResult)) {
@@ -693,7 +853,55 @@ namespace mozilla {
 nsresult
 LookAndFeel::GetColor(ColorID aID, nscolor* aResult)
 {
-  return nsLookAndFeel::GetInstance()->GetColorImpl(aID, *aResult);
+  return nsLookAndFeel::GetInstance()->GetColorImpl(aID, false, *aResult);
+}
+
+nsresult
+LookAndFeel::GetColor(ColorID aID, bool aUseStandinsForNativeColors,
+                      nscolor* aResult)
+{
+  return nsLookAndFeel::GetInstance()->GetColorImpl(aID,
+                                       aUseStandinsForNativeColors, *aResult);
+}
+
+// static
+nsresult
+LookAndFeel::GetColorForNativeAppearance(uint8_t aWidgetType, bool aIsDisabled,
+                                         nscolor* aResult)
+{
+  NS_ENSURE_ARG_POINTER(aResult);
+
+  ColorID colorID = eColorID_LAST_COLOR;
+  switch (aWidgetType) {
+    case NS_THEME_TEXTFIELD:
+    case NS_THEME_TEXTFIELD_MULTILINE:
+    case NS_THEME_LISTBOX:
+    case NS_THEME_DROPDOWN:
+    case NS_THEME_DROPDOWN_TEXTFIELD:
+    case NS_THEME_TREEVIEW:
+      colorID = (aIsDisabled) ? eColorID_graytext : eColorID__moz_fieldtext;
+      break;
+
+    case NS_THEME_TOOLTIP:
+      colorID = eColorID_infotext;
+      break;
+
+    case NS_THEME_BUTTON:
+    case NS_THEME_GROUPBOX:
+    case NS_THEME_PROGRESSBAR:
+    case NS_THEME_PROGRESSBAR_VERTICAL:
+    case NS_THEME_TAB_PANEL:
+    case NS_THEME_STATUSBAR:
+    case NS_THEME_STATUSBAR_RESIZER_PANEL:
+      colorID = (aIsDisabled) ? eColorID_graytext : eColorID_buttontext;
+      break;
+  }
+
+  if (LookAndFeel::eColorID_LAST_COLOR == colorID)
+    return NS_ERROR_FAILURE;
+
+  *aResult = NS_RGB(0, 0, 0);
+  return nsLookAndFeel::GetInstance()->NativeGetColor(colorID, *aResult);
 }
 
 // static
diff --git a/widget/xpwidgets/nsXPLookAndFeel.h b/widget/xpwidgets/nsXPLookAndFeel.h
index 69627d2..2729803 100644
--- a/widget/xpwidgets/nsXPLookAndFeel.h
+++ b/widget/xpwidgets/nsXPLookAndFeel.h
@@ -52,7 +52,8 @@ public:
   // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
   // platform-specific nsLookAndFeel should use its own values instead.
   //
-  nsresult GetColorImpl(ColorID aID, nscolor &aResult);
+  nsresult GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors,
+                        nscolor &aResult);
   virtual nsresult GetIntImpl(IntID aID, int32_t &aResult);
   virtual nsresult GetFloatImpl(FloatID aID, float &aResult);
 
@@ -89,6 +90,8 @@ protected:
   void InitColorFromPref(int32_t aIndex);
   virtual nsresult NativeGetColor(ColorID aID, nscolor &aResult) = 0;
   bool IsSpecialColor(ColorID aID, nscolor &aColor);
+  bool ColorIsNotCSSAccessible(ColorID aID);
+  nscolor GetStandinForNativeColor(ColorID aID);
 
   static int OnPrefChanged(const char* aPref, void* aClosure);
 
-- 
1.8.1.2

