Bug 373266 - win support for rendering two layer themes on widgets. r=joe,bbondy
authorJim Mathies <jmathies@mozilla.com>
Wed, 07 Mar 2012 09:29:42 -0600
changeset 89958 9b80fa3e587d3ad93e357f0c21a3667a45dd08c7
parent 89957 5d43b850791530388064dee8cfe82b8d0edf753b
child 89959 c4d338502df015d225a4d062d5ed815ff12fa766
push id975
push userffxbld
push dateTue, 13 Mar 2012 21:39:16 +0000
treeherdermozilla-aurora@99faebf9dc36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoe, bbondy
bugs373266
milestone13.0a1
Bug 373266 - win support for rendering two layer themes on widgets. r=joe,bbondy
gfx/thebes/gfxWindowsNativeDrawing.cpp
gfx/thebes/gfxWindowsNativeDrawing.h
widget/windows/WinUtils.cpp
widget/windows/WinUtils.h
widget/windows/nsNativeThemeWin.cpp
widget/windows/nsNativeThemeWin.h
widget/xpwidgets/nsNativeTheme.h
--- a/gfx/thebes/gfxWindowsNativeDrawing.cpp
+++ b/gfx/thebes/gfxWindowsNativeDrawing.cpp
@@ -228,16 +228,49 @@ gfxWindowsNativeDrawing::IsDoublePass()
     if ((surf->GetContentType() != gfxASurface::CONTENT_COLOR ||
          (surf->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA &&
           !(mNativeDrawFlags & CAN_DRAW_TO_COLOR_ALPHA))))
         return true;
     return false;
 }
 
 bool
+gfxWindowsNativeDrawing::IsSecondPass()
+{
+    return (mRenderState == RENDER_STATE_ALPHA_RECOVERY_WHITE ||
+            mRenderState == RENDER_STATE_ALPHA_RECOVERY_WHITE_DONE);
+}
+
+gfxWindowsSurface*
+gfxWindowsNativeDrawing::GetCurrentSurface()
+{
+    switch (mRenderState) {
+        case RENDER_STATE_NATIVE_DRAWING:
+        case RENDER_STATE_ALPHA_RECOVERY_WHITE:
+        case RENDER_STATE_ALPHA_RECOVERY_BLACK:
+            return mWinSurface;
+
+        case RENDER_STATE_NATIVE_DRAWING_DONE:
+        case RENDER_STATE_ALPHA_RECOVERY_BLACK_DONE:
+        case RENDER_STATE_ALPHA_RECOVERY_WHITE_DONE:
+        case RENDER_STATE_DONE:
+            NS_WARNING("GetCurrentSurface() called after "
+                       "rendering operation complete. Returning nsnull.");
+            return nsnull;
+
+        default:
+            NS_ERROR("Invalid RenderState in"
+                     "gfxWindowsNativeDrawing::GetCurrentSurface");
+            break;
+    }
+
+    return nsnull;
+}
+
+bool
 gfxWindowsNativeDrawing::ShouldRenderAgain()
 {
     switch (mRenderState) {
         case RENDER_STATE_NATIVE_DRAWING_DONE:
             return false;
 
         case RENDER_STATE_ALPHA_RECOVERY_BLACK_DONE:
             mRenderState = RENDER_STATE_ALPHA_RECOVERY_WHITE;
@@ -246,17 +279,17 @@ gfxWindowsNativeDrawing::ShouldRenderAga
         case RENDER_STATE_ALPHA_RECOVERY_WHITE_DONE:
             return false;
 
         default:
             NS_ERROR("Invalid RenderState in gfxWindowsNativeDrawing::ShouldRenderAgain");
             break;
     }
 
-    return false;
+    return nsnull;
 }
 
 void
 gfxWindowsNativeDrawing::EndNativeDrawing()
 {
     if (mRenderState == RENDER_STATE_NATIVE_DRAWING) {
         // we drew directly to the HDC in the context; undo our changes
         SetViewportOrgEx(mDC, mOrigViewportOrigin.x, mOrigViewportOrigin.y, NULL);
--- a/gfx/thebes/gfxWindowsNativeDrawing.h
+++ b/gfx/thebes/gfxWindowsNativeDrawing.h
@@ -109,16 +109,23 @@ public:
     void EndNativeDrawing();
 
     /* Returns true if the native drawing should be executed again */
     bool ShouldRenderAgain();
 
     /* Returns true if double pass alpha extraction is taking place. */
     bool IsDoublePass();
 
+    /* Returns true if double pass alpha extraction is taking place
+     * and this is the second pass in the operation. */
+    bool IsSecondPass();
+
+    /* Returns the current surface in use for rendering. */
+    gfxWindowsSurface* GetCurrentSurface();
+
     /* Places the result to the context, if necessary */
     void PaintToContext();
 
 private:
 
     nsRefPtr<gfxContext> mContext;
     gfxRect mNativeRect;
     PRUint32 mNativeDrawFlags;
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -57,16 +57,28 @@
 
 #include "WinUtils.h"
 #include "nsWindow.h"
 #include "nsWindowDefs.h"
 #include "nsGUIEvent.h"
 #include "nsIDOMMouseEvent.h"
 #include "mozilla/Preferences.h"
 
+#ifdef DEBUG
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#include <gdiplus.h>
+#endif
+
 namespace mozilla {
 namespace widget {
 
 // SHCreateItemFromParsingName is only available on vista and up.
 WinUtils::SHCreateItemFromParsingNamePtr WinUtils::sCreateItemFromParsingName = nsnull;
 
 /* static */ 
 WinUtils::WinVersion
@@ -427,10 +439,119 @@ WinUtils::GetShellItemPath(IShellItem* a
   LPWSTR str = NULL;
   if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str)))
     return false;
   aResultString.Assign(str);
   CoTaskMemFree(str);
   return !aResultString.IsEmpty();
 }
 
+#ifdef DEBUG
+
+// Win xp and up
+#pragma comment(lib, "gdiplus.lib")
+
+static bool
+GetEncoderClsid(const WCHAR* aFormat, CLSID* aClsid)
+{
+  using namespace Gdiplus;
+
+  UINT num = 0;
+  UINT size = 0;
+
+  ImageCodecInfo* pImageCodecInfo = NULL;
+
+  GetImageEncodersSize(&num, &size);
+  if(size == 0)
+    return false;
+
+  pImageCodecInfo = (ImageCodecInfo*)(moz_malloc(size));
+
+  if (GetImageEncoders(num, size, pImageCodecInfo) != Ok)
+    return false;
+
+  for(UINT j = 0; j < num; ++j) {
+    if(!wcscmp(pImageCodecInfo[j].MimeType, aFormat)) {
+      *aClsid = pImageCodecInfo[j].Clsid;
+      moz_free(pImageCodecInfo);
+      return true;
+    }    
+  }
+
+  moz_free(pImageCodecInfo);
+  return false;
+}
+
+/* static */
+void
+WinUtils::SaveDCToPng(HDC aHdc, const WCHAR* aFilePath, int aXPos, int aYPos,
+                      int aWidth, int aHeight)
+{
+  using namespace Gdiplus;
+  
+  static ULONG_PTR sGiplusToken;
+
+  nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
+  if (!file || NS_FAILED(file->InitWithPath(nsDependentString(aFilePath)))) {
+    NS_WARNING("bad file path.");
+    return;
+  }
+
+  GdiplusStartupInput gdiplusStartupInput;
+  if (!sGiplusToken)
+    GdiplusStartup(&sGiplusToken, &gdiplusStartupInput, NULL);
+
+  HDC memdc;
+  HBITMAP membit;
+  memdc = CreateCompatibleDC(aHdc);
+  NS_WARN_IF_FALSE(memdc, "CreateCompatibleDC failed");
+  if (!memdc)
+    return;
+  membit = CreateCompatibleBitmap(aHdc, aWidth, aHeight);
+  NS_WARN_IF_FALSE(membit, "CreateCompatibleBitmap failed");
+  if (!membit) {
+    DeleteObject(memdc);
+    return;
+  }
+  HBITMAP hOldBitmap =(HBITMAP) SelectObject(memdc, membit);
+  if (!hOldBitmap || hOldBitmap == HGDI_ERROR) {
+    DeleteObject(memdc);
+    DeleteObject(membit);
+    return;
+  }
+  BitBlt(memdc, 0, 0, aWidth, aHeight, aHdc, aXPos, aYPos, SRCCOPY);
+
+  Gdiplus::Bitmap bitmap(membit, NULL);
+
+  CLSID clsid;
+  if (!GetEncoderClsid(L"image/png", &clsid)) {
+    NS_WARNING("GetEncoderClsid failed");
+    return;
+  }
+
+  file->Remove(false);
+  if (bitmap.Save(aFilePath, &clsid) != Ok) {
+    NS_WARNING("bitmap.Save faled.");
+  }
+
+  SelectObject(memdc, hOldBitmap);
+  DeleteObject(memdc);
+  DeleteObject(membit);
+}
+
+/* static */
+void
+WinUtils::SaveDCToPngIndexed(HDC aHdc, const WCHAR* aDirectory, const WCHAR* aAnnotation,
+                             int aXPos, int aYPos, int aWidth, int aHeight)
+{
+  static int sPngFileIndex;
+  WCHAR filename[512];
+  filename[0] = 0;
+  wsprintf(filename, L"%s\\%s_image-%d.png", aDirectory, aAnnotation,
+           sPngFileIndex);
+  sPngFileIndex++;
+  WinUtils::SaveDCToPng(aHdc, filename, aXPos, aYPos, aWidth, aHeight);
+}
+
+#endif // DEBUG
+
 } // namespace widget
 } // namespace mozilla
--- a/widget/windows/WinUtils.h
+++ b/widget/windows/WinUtils.h
@@ -226,16 +226,54 @@ public:
    *
    * aItem  the shell item containing the path.
    * aResultString  the resulting string path.
    * returns  true if a path was retreived.
    */
   static bool GetShellItemPath(IShellItem* aItem,
                                nsString& aResultString);
 
+#ifdef DEBUG
+  /**
+   * (DEBUG ONLY)
+   * SaveDCToPng - Save the contents of an HDC to a local png image. Deletes
+   * the target before creating.
+   *
+   * aHdc        HDC to save
+   * aFilePath   file path to save to.
+   * aXPos       X origin within the HDC.
+   * aYPos       Y origin within the HDC.
+   * aWidth      Width of the section to capture.
+   * aHeight     height of the section to capture.
+   */
+  static void SaveDCToPng(HDC hdc, const WCHAR* aFilePath,
+                          int aXPos, int aYPos,
+                          int aWidth, int aHeight);
+
+  /**
+   * (DEBUG ONLY)
+   * SaveDCToPngIndexed - Save the contents of an HDC to a local png image.
+   * Filenames are of the format:
+   *  (dir)\\(annotation)_image-(index).png
+   * where index equals the call count. Calls SaveDCToPng.
+   *
+   * aHdc        HDC to save
+   * aDirectory  location to store mutliple images.
+   * aAnnotation filename safe annotation for the png.
+   * aXPos       X origin within the HDC.
+   * aYPos       Y origin within the HDC.
+   * aWidth      Width of the section to capture.
+   * aHeight     height of the section to capture.
+   */
+  static void SaveDCToPngIndexed(HDC aHdc, const WCHAR* aDirectory,
+                                 const WCHAR* aAnnotation,
+                                 int aXPos, int aYPos,
+                                 int aWidth, int aHeight);
+#endif
+
 private:
   typedef HRESULT (WINAPI * SHCreateItemFromParsingNamePtr)(PCWSTR pszPath,
                                                             IBindCtx *pbc,
                                                             REFIID riid,
                                                             void **ppv);
   static SHCreateItemFromParsingNamePtr sCreateItemFromParsingName;
 
   /**
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -73,16 +73,19 @@
 #include "nsUXThemeConstants.h"
 
 using namespace mozilla::widget;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gWindowsLog;
 #endif
 
+// Default fps when animating themed widgets.
+#define DEFAULT_ANIMATION_FPS 30
+
 NS_IMPL_ISUPPORTS_INHERITED1(nsNativeThemeWin, nsNativeTheme, nsITheme)
 
 static inline bool IsHTMLContent(nsIFrame *frame)
 {
   nsIContent* content = frame->GetContent();
   return content && content->IsHTML();
 }
 
@@ -220,16 +223,203 @@ static SIZE GetGutterSize(HANDLE theme, 
     int width = NS_MAX(itemSize.cx, checkboxBGSize.cx + gutterSize.cx);
     int height = NS_MAX(itemSize.cy, checkboxBGSize.cy);
     SIZE ret;
     ret.cx = width;
     ret.cy = height;
     return ret;
 }
 
+/*
+ * RenderThemedAnimationFrame - renders a frame of widget animation
+ * for fadable widgets.
+ *
+ * aCtx         gfxContext of the target composition surface.
+ * aNative      gfxWindowsNativeDrawing associated with the rendering
+ *              operation initiated in DrawWidgetBackground.
+ * aTheme       An open theme handle used in rendering.
+ * aHdc         HDC associated with the DIB we'll be rendering the final
+ *              frame to.
+ * aPartsList   The Win theme part(s) to render.
+ * aPartCount   The number of parts listed in aPartsList.
+ * aBaseState   Theme state that will act as the background graphic of
+ *              the frame.
+ * aAlphaState  The overlay theme graphic that is layered on top of
+ *              aBaseState.
+ * aAlpha       Alpha (0.0-1.0) value for the aAlphaState overlay.
+ * aDRect,
+ * aDDirtyRect  Device rects 
+ * aWRect,
+ * aWDirtyRect  Native rects 
+ * returns      true on success, false if the default theme was rendered
+ *              without a fade or serious error. Callers should not
+ *              queue animations for false results.
+ */
+static bool
+RenderThemedAnimationFrame(gfxContext* aCtx,
+                           gfxWindowsNativeDrawing* aNative,
+                           HANDLE aTheme, HDC aHdc,
+                           int aPartsList[], int aPartCount,
+                           int aBaseState, int aAlphaState,
+                           double aAlpha,
+                           const gfxRect& aDRect, const gfxRect& aDDirtyRect,
+                           const RECT& aWRect, const RECT& aWDirtyRect)
+{
+  NS_ASSERTION(aPartCount > 0, "Bad parts array.");
+  NS_ASSERTION(aCtx, "Bad context.");
+  NS_ASSERTION(aNative, "Bad native pointer.");
+
+#if 0
+  printf("rect:(%d %d %d %d) dirty:(%d %d %d %d) alpha=%f\n",
+  aWRect.left, aWRect.top, aWRect.right, aWRect.bottom,
+  aWDirtyRect.left, aWDirtyRect.top, aWDirtyRect.right, aWDirtyRect.bottom,
+  aAlpha);
+#endif
+
+  // If false, we are rendering to the target surface, so use origin offsets.
+  // If true, we are rendering to back buffers with an origin of 0,0.
+  bool backBufferInUse = aNative->IsDoublePass();
+
+  nsRefPtr<gfxContext> paintCtx;
+  if (backBufferInUse) {
+    // In the case of alpha recovery, gfxWindowsNativeDrawing creates internal
+    // backing DIBs we render to, so get the current surface we are working
+    // with. (aHdc is already associated with the correct buffer.)
+    nsRefPtr<gfxASurface> currentSurf = aNative->GetCurrentSurface();
+    NS_ENSURE_TRUE(currentSurf, false);
+
+    // Wrap this in a gfxContext so we can work with it
+    paintCtx = new gfxContext(currentSurf);
+    NS_ENSURE_TRUE(paintCtx, false);
+  } else {
+    // Use the passed in context
+    paintCtx = aCtx;
+  }
+
+  int width = aWDirtyRect.right - aWDirtyRect.left;
+  int height = aWDirtyRect.bottom - aWDirtyRect.top;
+
+  RECT surfaceDrawRect = { 0, 0, width, height }; // left, top, right, bottom
+
+  // Create a temp base theme background surface
+  nsRefPtr<gfxWindowsSurface> surfBase =
+    new gfxWindowsSurface(gfxIntSize(width, height),
+                          gfxASurface::ImageFormatRGB24);
+  NS_ENSURE_TRUE(surfBase, false);
+
+  // Copy the destination context over to our temporary surface. We'll render
+  // on top of what we copy.
+  if (backBufferInUse) {
+    // FillRect is about 35% faster than BitBlt
+    if (!aNative->IsSecondPass()) {
+      FillRect(surfBase->GetDC(), &surfaceDrawRect,
+               (HBRUSH)GetStockObject(BLACK_BRUSH));
+    } else {
+      FillRect(surfBase->GetDC(), &surfaceDrawRect,
+               (HBRUSH)GetStockObject(WHITE_BRUSH));
+    }
+  } else {
+    // XXX we might not need this?
+    BitBlt(surfBase->GetDC(), 0, 0, width, height, aHdc, aWDirtyRect.left,
+           aWDirtyRect.top, SRCCOPY);
+  }
+
+  // Render the theme's base graphic
+  for (int idx = 0; idx < aPartCount; idx++) {
+    DrawThemeBackground(aTheme, surfBase->GetDC(), aPartsList[idx],
+                        aBaseState, &surfaceDrawRect, &surfaceDrawRect);
+  }
+
+  // Create a new highlight theme background surface
+  nsRefPtr<gfxWindowsSurface> surfAlpha =
+    new gfxWindowsSurface(gfxIntSize(width, height),
+                          gfxASurface::ImageFormatRGB24);
+  NS_ENSURE_TRUE(surfAlpha, false);
+
+  if (backBufferInUse) {
+    if (!aNative->IsSecondPass()) {
+      FillRect(surfAlpha->GetDC(), &surfaceDrawRect,
+               (HBRUSH)GetStockObject(BLACK_BRUSH));
+    } else {
+      FillRect(surfAlpha->GetDC(), &surfaceDrawRect,
+               (HBRUSH)GetStockObject(WHITE_BRUSH));
+    }
+  } else {
+    BitBlt(surfAlpha->GetDC(), 0, 0, width, height, aHdc, aWDirtyRect.left,
+           aWDirtyRect.top, SRCCOPY);
+  }
+
+  // Render the theme's highlight graphic
+  for (int idx = 0; idx < aPartCount; idx++) {
+    DrawThemeBackground(aTheme, surfAlpha->GetDC(), aPartsList[idx],
+                        aAlphaState, &surfaceDrawRect, &surfaceDrawRect);
+ }
+
+  // Blend the two images together using aAlpha for surfAlpha.
+  nsRefPtr<gfxImageSurface> imageBase = surfBase->GetAsImageSurface();
+  nsRefPtr<gfxImageSurface> imageAlpha = surfAlpha->GetAsImageSurface();
+  NS_ENSURE_TRUE(imageBase, false);
+  NS_ENSURE_TRUE(imageAlpha, false);
+
+  gfxContext::GraphicsOperator currentOp = paintCtx->CurrentOperator();
+  paintCtx->Save();
+  paintCtx->ResetClip();
+  if (!backBufferInUse) {
+    // In cairo we want to fall through and use BitBlt or AlphaBlend but
+    // won't unless we're aligned on pixel boundaries. Since our hdc rects
+    // are already snapped, round off the Translate parameter as well so
+    // they match.
+    gfxRect roundedRect = aDDirtyRect;
+    roundedRect.Round();
+    paintCtx->Clip(roundedRect);
+    paintCtx->Translate(roundedRect.TopLeft());
+  }
+  paintCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
+  paintCtx->SetSource(imageBase);
+  paintCtx->Paint();
+  paintCtx->SetOperator(gfxContext::OPERATOR_OVER);
+  paintCtx->SetSource(imageAlpha);
+  paintCtx->Paint(aAlpha);
+  paintCtx->Restore();
+  paintCtx->SetOperator(currentOp);
+
+  return true;
+}
+
+/*
+ * QueueAnimation - helper for queuing up a render callback via
+ * QueueAnimatedContentRefreshForFade.
+ *
+ * aNative    gfxWindowsNativeDrawing associated with the rendering operation
+ *            initiated in DrawWidgetBackground.
+ * aContent   The element that will be invalidated.
+ * aDirection The FadeState direction of the fade. FADE_IN & FADE_OUT are
+ *            valid values.
+ * aDuration  The total duration of one phase (in/out) of the fade.
+ * aUserData  User data passed to QueueAnimatedContentRefreshForFade.
+ */
+void
+nsNativeThemeWin::QueueAnimation(gfxWindowsNativeDrawing* aNativeDrawing,
+                                 nsIContent* aContent, FadeState aDirection,
+                                 DWORD aDuration, PRUint32 aUserValue)
+{
+  NS_ASSERTION(aNativeDrawing, "bad draw pointer");
+  NS_ASSERTION(aContent, "bad content pointer");
+  NS_ASSERTION((aDirection == FADE_IN ||
+                aDirection == FADE_OUT), "bad direction");
+  // Often content is rendered using alpha recovery which requires two passes,
+  // so only queue up another refresh if we are on the final (or single) pass
+  // of a render operation. This way QueueAnimatedContentRefreshForFade won't
+  // cancel our fade resulting in the second pass passing through fState ==
+  // FADE_NOTACTIVE rendering, which would screw up recovery.
+  if (!aNativeDrawing->IsDoublePass() || aNativeDrawing->IsSecondPass())
+    QueueAnimatedContentRefreshForFade(aContent, aDirection,
+      DEFAULT_ANIMATION_FPS, aDuration, aUserValue);
+}
+
 static HRESULT DrawThemeBGRTLAware(HANDLE theme, HDC hdc, int part, int state,
                                    const RECT *widgetRect, const RECT *clipRect,
                                    bool isRTL)
 {
   /* Some widgets are not direction-neutral and need to be drawn reversed for
    * RTL.  Windows provides a way to do this with SetLayout, but this reverses
    * the entire drawing area of a given device context, which means that its
    * use will also affect the positioning of the widget.  There are two ways
--- a/widget/windows/nsNativeThemeWin.h
+++ b/widget/windows/nsNativeThemeWin.h
@@ -36,16 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsITheme.h"
 #include "nsCOMPtr.h"
 #include "nsIAtom.h"
 #include "nsNativeTheme.h"
+#include "gfxWindowsNativeDrawing.h"
 #include <windows.h>
 
 struct nsIntRect;
 struct nsIntSize;
 
 class nsNativeThemeWin : private nsNativeTheme,
                          public nsITheme {
 public:
@@ -98,45 +99,41 @@ public:
   nsNativeThemeWin();
   virtual ~nsNativeThemeWin();
 
 protected:
   HANDLE GetTheme(PRUint8 aWidgetType);
   nsresult GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType,
                                 PRInt32& aPart, PRInt32& aState);
   nsresult ClassicGetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType,
-                                   PRInt32& aPart, PRInt32& aState, bool& aFocused);
+                                       PRInt32& aPart, PRInt32& aState, bool& aFocused);
   nsresult ClassicDrawWidgetBackground(nsRenderingContext* aContext,
+                                       nsIFrame* aFrame,
+                                       PRUint8 aWidgetType,
+                                       const nsRect& aRect,
+                                       const nsRect& aClipRect);
+  nsresult ClassicGetWidgetBorder(nsDeviceContext* aContext, 
                                   nsIFrame* aFrame,
                                   PRUint8 aWidgetType,
-                                  const nsRect& aRect,
-                                  const nsRect& aClipRect);
-  nsresult ClassicGetWidgetBorder(nsDeviceContext* aContext, 
-                             nsIFrame* aFrame,
-                             PRUint8 aWidgetType,
-                             nsIntMargin* aResult);
-
+                                  nsIntMargin* aResult);
   bool ClassicGetWidgetPadding(nsDeviceContext* aContext,
-                            nsIFrame* aFrame,
-                            PRUint8 aWidgetType,
-                            nsIntMargin* aResult);
-
+                               nsIFrame* aFrame,
+                               PRUint8 aWidgetType,
+                               nsIntMargin* aResult);
   nsresult ClassicGetMinimumWidgetSize(nsRenderingContext* aContext, nsIFrame* aFrame,
-                                  PRUint8 aWidgetType,
-                                  nsIntSize* aResult,
-                                  bool* aIsOverridable);
-
+                                       PRUint8 aWidgetType,
+                                       nsIntSize* aResult,
+                                       bool* aIsOverridable);
   bool ClassicThemeSupportsWidget(nsPresContext* aPresContext, 
-                             nsIFrame* aFrame,
-                             PRUint8 aWidgetType);
-
+                                  nsIFrame* aFrame,
+                                  PRUint8 aWidgetType);
   void DrawCheckedRect(HDC hdc, const RECT& rc, PRInt32 fore, PRInt32 back,
                        HBRUSH defaultBack);
-
   PRUint32 GetWidgetNativeDrawingFlags(PRUint8 aWidgetType);
-
   PRInt32 StandardGetState(nsIFrame* aFrame, PRUint8 aWidgetType, bool wantFocused);
-
   bool IsMenuActive(nsIFrame* aFrame, PRUint8 aWidgetType);
+  void QueueAnimation(gfxWindowsNativeDrawing* aNativeDrawing,
+                      nsIContent* aContent, FadeState aDirection,
+                      DWORD aDuration, PRUint32 aUserValue = 0);
 };
 
 // Creator function
 extern NS_METHOD NS_NewNativeThemeWin(nsISupports *aOuter, REFNSIID aIID, void **aResult);
--- a/widget/xpwidgets/nsNativeTheme.h
+++ b/widget/xpwidgets/nsNativeTheme.h
@@ -57,21 +57,20 @@ class nsIContent;
 class nsIFrame;
 class nsIPresShell;
 class nsPresContext;
 
 class nsNativeTheme :
   public nsITimerCallback,
   public nsIObserver
 {
+ protected:
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
 
- protected:
-
   NS_DECL_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
   NS_DECL_NSIOBSERVER
 
   enum ScrollbarButtonType {
     eScrollbarButton_UpTop   = 0,
     eScrollbarButton_Down    = 1 << 0,
     eScrollbarButton_Bottom  = 1 << 1