michael@0: /* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsNativeThemeWin.h" michael@0: #include "mozilla/EventStates.h" michael@0: #include "mozilla/WindowsVersion.h" michael@0: #include "nsRenderingContext.h" michael@0: #include "nsRect.h" michael@0: #include "nsSize.h" michael@0: #include "nsTransform2D.h" michael@0: #include "nsThemeConstants.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIFrame.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsIDOMHTMLInputElement.h" michael@0: #include "nsLookAndFeel.h" michael@0: #include "nsMenuFrame.h" michael@0: #include "nsGkAtoms.h" michael@0: #include michael@0: #include "nsWindow.h" michael@0: #include "nsIComboboxControlFrame.h" michael@0: #include "prinrval.h" michael@0: #include "WinUtils.h" michael@0: michael@0: #include "gfxPlatform.h" michael@0: #include "gfxContext.h" michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "gfxWindowsSurface.h" michael@0: #include "gfxWindowsNativeDrawing.h" michael@0: michael@0: #include "nsUXThemeData.h" michael@0: #include "nsUXThemeConstants.h" michael@0: #include michael@0: michael@0: using mozilla::IsVistaOrLater; michael@0: using namespace mozilla; michael@0: using namespace mozilla::widget; michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gWindowsLog; michael@0: #endif michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeWin, nsNativeTheme, nsITheme) michael@0: michael@0: nsNativeThemeWin::nsNativeThemeWin() : michael@0: mProgressDeterminateTimeStamp(TimeStamp::Now()), michael@0: mProgressIndeterminateTimeStamp(TimeStamp::Now()) michael@0: { michael@0: // If there is a relevant change in forms.css for windows platform, michael@0: // static widget style variables (e.g. sButtonBorderSize) should be michael@0: // reinitialized here. michael@0: } michael@0: michael@0: nsNativeThemeWin::~nsNativeThemeWin() michael@0: { michael@0: nsUXThemeData::Invalidate(); michael@0: } michael@0: michael@0: static int32_t michael@0: GetTopLevelWindowActiveState(nsIFrame *aFrame) michael@0: { michael@0: // Get the widget. nsIFrame's GetNearestWidget walks up the view chain michael@0: // until it finds a real window. michael@0: nsIWidget* widget = aFrame->GetNearestWidget(); michael@0: nsWindowBase * window = static_cast(widget); michael@0: if (!window) michael@0: return mozilla::widget::themeconst::FS_INACTIVE; michael@0: if (widget && !window->IsTopLevelWidget() && michael@0: !(window = window->GetParentWindowBase(false))) michael@0: return mozilla::widget::themeconst::FS_INACTIVE; michael@0: michael@0: if (window->GetWindowHandle() == ::GetActiveWindow()) michael@0: return mozilla::widget::themeconst::FS_ACTIVE; michael@0: return mozilla::widget::themeconst::FS_INACTIVE; michael@0: } michael@0: michael@0: static int32_t michael@0: GetWindowFrameButtonState(nsIFrame* aFrame, EventStates eventState) michael@0: { michael@0: if (GetTopLevelWindowActiveState(aFrame) == michael@0: mozilla::widget::themeconst::FS_INACTIVE) { michael@0: if (eventState.HasState(NS_EVENT_STATE_HOVER)) michael@0: return mozilla::widget::themeconst::BS_HOT; michael@0: return mozilla::widget::themeconst::BS_INACTIVE; michael@0: } michael@0: michael@0: if (eventState.HasState(NS_EVENT_STATE_HOVER)) { michael@0: if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) michael@0: return mozilla::widget::themeconst::BS_PUSHED; michael@0: return mozilla::widget::themeconst::BS_HOT; michael@0: } michael@0: return mozilla::widget::themeconst::BS_NORMAL; michael@0: } michael@0: michael@0: static int32_t michael@0: GetClassicWindowFrameButtonState(EventStates eventState) michael@0: { michael@0: if (eventState.HasState(NS_EVENT_STATE_ACTIVE) && michael@0: eventState.HasState(NS_EVENT_STATE_HOVER)) michael@0: return DFCS_BUTTONPUSH|DFCS_PUSHED; michael@0: return DFCS_BUTTONPUSH; michael@0: } michael@0: michael@0: static bool michael@0: IsTopLevelMenu(nsIFrame *aFrame) michael@0: { michael@0: bool isTopLevel(false); michael@0: nsMenuFrame *menuFrame = do_QueryFrame(aFrame); michael@0: if (menuFrame) { michael@0: isTopLevel = menuFrame->IsOnMenuBar(); michael@0: } michael@0: return isTopLevel; michael@0: } michael@0: michael@0: static MARGINS michael@0: GetCheckboxMargins(HANDLE theme, HDC hdc) michael@0: { michael@0: MARGINS checkboxContent = {0}; michael@0: GetThemeMargins(theme, hdc, MENU_POPUPCHECK, MCB_NORMAL, michael@0: TMT_CONTENTMARGINS, nullptr, &checkboxContent); michael@0: return checkboxContent; michael@0: } michael@0: michael@0: static SIZE michael@0: GetCheckboxBGSize(HANDLE theme, HDC hdc) michael@0: { michael@0: SIZE checkboxSize; michael@0: GetThemePartSize(theme, hdc, MENU_POPUPCHECK, MC_CHECKMARKNORMAL, michael@0: nullptr, TS_TRUE, &checkboxSize); michael@0: michael@0: MARGINS checkboxMargins = GetCheckboxMargins(theme, hdc); michael@0: michael@0: int leftMargin = checkboxMargins.cxLeftWidth; michael@0: int rightMargin = checkboxMargins.cxRightWidth; michael@0: int topMargin = checkboxMargins.cyTopHeight; michael@0: int bottomMargin = checkboxMargins.cyBottomHeight; michael@0: michael@0: int width = leftMargin + checkboxSize.cx + rightMargin; michael@0: int height = topMargin + checkboxSize.cy + bottomMargin; michael@0: SIZE ret; michael@0: ret.cx = width; michael@0: ret.cy = height; michael@0: return ret; michael@0: } michael@0: michael@0: static SIZE michael@0: GetCheckboxBGBounds(HANDLE theme, HDC hdc) michael@0: { michael@0: MARGINS checkboxBGSizing = {0}; michael@0: MARGINS checkboxBGContent = {0}; michael@0: GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, michael@0: TMT_SIZINGMARGINS, nullptr, &checkboxBGSizing); michael@0: GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, michael@0: TMT_CONTENTMARGINS, nullptr, &checkboxBGContent); michael@0: michael@0: #define posdx(d) ((d) > 0 ? d : 0) michael@0: michael@0: int dx = posdx(checkboxBGContent.cxRightWidth - michael@0: checkboxBGSizing.cxRightWidth) + michael@0: posdx(checkboxBGContent.cxLeftWidth - michael@0: checkboxBGSizing.cxLeftWidth); michael@0: int dy = posdx(checkboxBGContent.cyTopHeight - michael@0: checkboxBGSizing.cyTopHeight) + michael@0: posdx(checkboxBGContent.cyBottomHeight - michael@0: checkboxBGSizing.cyBottomHeight); michael@0: michael@0: #undef posdx michael@0: michael@0: SIZE ret(GetCheckboxBGSize(theme, hdc)); michael@0: ret.cx += dx; michael@0: ret.cy += dy; michael@0: return ret; michael@0: } michael@0: michael@0: static SIZE michael@0: GetGutterSize(HANDLE theme, HDC hdc) michael@0: { michael@0: SIZE gutterSize; michael@0: GetThemePartSize(theme, hdc, MENU_POPUPGUTTER, 0, nullptr, TS_TRUE, &gutterSize); michael@0: michael@0: SIZE checkboxBGSize(GetCheckboxBGBounds(theme, hdc)); michael@0: michael@0: SIZE itemSize; michael@0: GetThemePartSize(theme, hdc, MENU_POPUPITEM, MPI_NORMAL, nullptr, TS_TRUE, &itemSize); michael@0: michael@0: // Figure out how big the menuitem's icon will be (if present) at current DPI michael@0: double scaleFactor = nsIWidget::DefaultScaleOverride(); michael@0: if (scaleFactor <= 0.0) { michael@0: scaleFactor = gfxWindowsPlatform::GetPlatform()->GetDPIScale(); michael@0: } michael@0: int iconDevicePixels = NSToIntRound(16 * scaleFactor); michael@0: SIZE iconSize = { michael@0: iconDevicePixels, iconDevicePixels michael@0: }; michael@0: // Not really sure what margins should be used here, but this seems to work in practice... michael@0: MARGINS margins = {0}; michael@0: GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, michael@0: TMT_CONTENTMARGINS, nullptr, &margins); michael@0: iconSize.cx += margins.cxLeftWidth + margins.cxRightWidth; michael@0: iconSize.cy += margins.cyTopHeight + margins.cyBottomHeight; michael@0: michael@0: int width = std::max(itemSize.cx, std::max(iconSize.cx, checkboxBGSize.cx) + gutterSize.cx); michael@0: int height = std::max(itemSize.cy, std::max(iconSize.cy, checkboxBGSize.cy)); michael@0: michael@0: SIZE ret; michael@0: ret.cx = width; michael@0: ret.cy = height; michael@0: return ret; michael@0: } michael@0: michael@0: /* DrawThemeBGRTLAware - render a theme part based on rtl state. michael@0: * Some widgets are not direction-neutral and need to be drawn reversed for michael@0: * RTL. Windows provides a way to do this with SetLayout, but this reverses michael@0: * the entire drawing area of a given device context, which means that its michael@0: * use will also affect the positioning of the widget. There are two ways michael@0: * to work around this: michael@0: * michael@0: * Option 1: Alter the position of the rect that we send so that we cancel michael@0: * out the positioning effects of SetLayout michael@0: * Option 2: Create a memory DC with the widgetRect's dimensions, draw onto michael@0: * that, and then transfer the results back to our DC michael@0: * michael@0: * This function tries to implement option 1, under the assumption that the michael@0: * correct way to reverse the effects of SetLayout is to translate the rect michael@0: * such that the offset from the DC bitmap's left edge to the old rect's michael@0: * left edge is equal to the offset from the DC bitmap's right edge to the michael@0: * new rect's right edge. In other words, michael@0: * (oldRect.left + vpOrg.x) == ((dcBMP.width - vpOrg.x) - newRect.right) michael@0: */ michael@0: static HRESULT michael@0: DrawThemeBGRTLAware(HANDLE aTheme, HDC aHdc, int aPart, int aState, michael@0: const RECT *aWidgetRect, const RECT *aClipRect, michael@0: bool aIsRtl) michael@0: { michael@0: NS_ASSERTION(aTheme, "Bad theme handle."); michael@0: NS_ASSERTION(aHdc, "Bad hdc."); michael@0: NS_ASSERTION(aWidgetRect, "Bad rect."); michael@0: NS_ASSERTION(aClipRect, "Bad clip rect."); michael@0: michael@0: if (!aIsRtl) { michael@0: return DrawThemeBackground(aTheme, aHdc, aPart, aState, michael@0: aWidgetRect, aClipRect); michael@0: } michael@0: michael@0: HGDIOBJ hObj = GetCurrentObject(aHdc, OBJ_BITMAP); michael@0: BITMAP bitmap; michael@0: POINT vpOrg; michael@0: michael@0: if (hObj && GetObject(hObj, sizeof(bitmap), &bitmap) && michael@0: GetViewportOrgEx(aHdc, &vpOrg)) { michael@0: RECT newWRect(*aWidgetRect); michael@0: newWRect.left = bitmap.bmWidth - (aWidgetRect->right + 2*vpOrg.x); michael@0: newWRect.right = bitmap.bmWidth - (aWidgetRect->left + 2*vpOrg.x); michael@0: michael@0: RECT newCRect; michael@0: RECT *newCRectPtr = nullptr; michael@0: michael@0: if (aClipRect) { michael@0: newCRect.top = aClipRect->top; michael@0: newCRect.bottom = aClipRect->bottom; michael@0: newCRect.left = bitmap.bmWidth - (aClipRect->right + 2*vpOrg.x); michael@0: newCRect.right = bitmap.bmWidth - (aClipRect->left + 2*vpOrg.x); michael@0: newCRectPtr = &newCRect; michael@0: } michael@0: michael@0: SetLayout(aHdc, LAYOUT_RTL); michael@0: HRESULT hr = DrawThemeBackground(aTheme, aHdc, aPart, aState, &newWRect, michael@0: newCRectPtr); michael@0: SetLayout(aHdc, 0); michael@0: if (SUCCEEDED(hr)) { michael@0: return hr; michael@0: } michael@0: } michael@0: return DrawThemeBackground(aTheme, aHdc, aPart, aState, michael@0: aWidgetRect, aClipRect); michael@0: } michael@0: michael@0: /* michael@0: * Caption button padding data - 'hot' button padding. michael@0: * These areas are considered hot, in that they activate michael@0: * a button when hovered or clicked. The button graphic michael@0: * is drawn inside the padding border. Unrecognized themes michael@0: * are treated as their recognized counterparts for now. michael@0: * left top right bottom michael@0: * classic min 1 2 0 1 michael@0: * classic max 0 2 1 1 michael@0: * classic close 1 2 2 1 michael@0: * michael@0: * aero basic min 1 2 0 2 michael@0: * aero basic max 0 2 1 2 michael@0: * aero basic close 1 2 1 2 michael@0: * michael@0: * xp theme min 0 2 0 2 michael@0: * xp theme max 0 2 1 2 michael@0: * xp theme close 1 2 2 2 michael@0: * michael@0: * 'cold' button padding - generic button padding, should michael@0: * be handled in css. michael@0: * left top right bottom michael@0: * classic min 0 0 0 0 michael@0: * classic max 0 0 0 0 michael@0: * classic close 0 0 0 0 michael@0: * michael@0: * aero basic min 0 0 1 0 michael@0: * aero basic max 1 0 0 0 michael@0: * aero basic close 0 0 0 0 michael@0: * michael@0: * xp theme min 0 0 1 0 michael@0: * xp theme max 1 0 0 0 michael@0: * xp theme close 0 0 0 0 michael@0: */ michael@0: michael@0: enum CaptionDesktopTheme { michael@0: CAPTION_CLASSIC = 0, michael@0: CAPTION_BASIC, michael@0: CAPTION_XPTHEME, michael@0: }; michael@0: michael@0: enum CaptionButton { michael@0: CAPTIONBUTTON_MINIMIZE = 0, michael@0: CAPTIONBUTTON_RESTORE, michael@0: CAPTIONBUTTON_CLOSE, michael@0: }; michael@0: michael@0: struct CaptionButtonPadding { michael@0: RECT hotPadding[3]; michael@0: }; michael@0: michael@0: // RECT: left, top, right, bottom michael@0: static CaptionButtonPadding buttonData[3] = { michael@0: { michael@0: { { 1, 2, 0, 1 }, { 0, 2, 1, 1 }, { 1, 2, 2, 1 } } michael@0: }, michael@0: { michael@0: { { 1, 2, 0, 2 }, { 0, 2, 1, 2 }, { 1, 2, 2, 2 } } michael@0: }, michael@0: { michael@0: { { 0, 2, 0, 2 }, { 0, 2, 1, 2 }, { 1, 2, 2, 2 } } michael@0: } michael@0: }; michael@0: michael@0: // Adds "hot" caption button padding to minimum widget size. michael@0: static void michael@0: AddPaddingRect(nsIntSize* aSize, CaptionButton button) { michael@0: if (!aSize) michael@0: return; michael@0: RECT offset; michael@0: if (!IsAppThemed()) michael@0: offset = buttonData[CAPTION_CLASSIC].hotPadding[button]; michael@0: else if (!IsVistaOrLater()) michael@0: offset = buttonData[CAPTION_XPTHEME].hotPadding[button]; michael@0: else michael@0: offset = buttonData[CAPTION_BASIC].hotPadding[button]; michael@0: aSize->width += offset.left + offset.right; michael@0: aSize->height += offset.top + offset.bottom; michael@0: } michael@0: michael@0: // If we've added padding to the minimum widget size, offset michael@0: // the area we draw into to compensate. michael@0: static void michael@0: OffsetBackgroundRect(RECT& rect, CaptionButton button) { michael@0: RECT offset; michael@0: if (!IsAppThemed()) michael@0: offset = buttonData[CAPTION_CLASSIC].hotPadding[button]; michael@0: else if (!IsVistaOrLater()) michael@0: offset = buttonData[CAPTION_XPTHEME].hotPadding[button]; michael@0: else michael@0: offset = buttonData[CAPTION_BASIC].hotPadding[button]; michael@0: rect.left += offset.left; michael@0: rect.top += offset.top; michael@0: rect.right -= offset.right; michael@0: rect.bottom -= offset.bottom; michael@0: } michael@0: michael@0: /* michael@0: * Notes on progress track and meter part constants: michael@0: * xp and up: michael@0: * PP_BAR(_VERT) - base progress track michael@0: * PP_TRANSPARENTBAR(_VERT) - transparent progress track. this only works if michael@0: * the underlying surface supports alpha. otherwise michael@0: * theme lib's DrawThemeBackground falls back on michael@0: * opaque PP_BAR. we currently don't use this. michael@0: * PP_CHUNK(_VERT) - xp progress meter. this does not draw an xp style michael@0: * progress w/chunks, it draws fill using the chunk michael@0: * graphic. michael@0: * vista and up: michael@0: * PP_FILL(_VERT) - progress meter. these have four states/colors. michael@0: * PP_PULSEOVERLAY(_VERT) - white reflection - an overlay, not sure what this michael@0: * is used for. michael@0: * PP_MOVEOVERLAY(_VERT) - green pulse - the pulse effect overlay on michael@0: * determined progress bars. we also use this for michael@0: * indeterminate chunk. michael@0: * michael@0: * Notes on state constants: michael@0: * PBBS_NORMAL - green progress michael@0: * PBBVS_PARTIAL/PBFVS_ERROR - red error progress michael@0: * PBFS_PAUSED - yellow paused progress michael@0: * michael@0: * There is no common controls style indeterminate part on vista and up. michael@0: */ michael@0: michael@0: /* michael@0: * Progress bar related constants. These values are found by experimenting and michael@0: * comparing against native widgets used by the system. They are very unlikely michael@0: * exact but try to not be too wrong. michael@0: */ michael@0: // The amount of time we animate progress meters parts across the frame. michael@0: static const double kProgressDeterminateTimeSpan = 3.0; michael@0: static const double kProgressIndeterminateTimeSpan = 5.0; michael@0: // The width of the overlay used to animate the horizontal progress bar (Vista and later). michael@0: static const int32_t kProgressHorizontalVistaOverlaySize = 120; michael@0: // The width of the overlay used for the horizontal indeterminate progress bars on XP. michael@0: static const int32_t kProgressHorizontalXPOverlaySize = 55; michael@0: // The height of the overlay used to animate the vertical progress bar (Vista and later). michael@0: static const int32_t kProgressVerticalOverlaySize = 45; michael@0: // The height of the overlay used for the vertical indeterminate progress bar (Vista and later). michael@0: static const int32_t kProgressVerticalIndeterminateOverlaySize = 60; michael@0: // The width of the overlay used to animate the indeterminate progress bar (Windows Classic). michael@0: static const int32_t kProgressClassicOverlaySize = 40; michael@0: michael@0: /* michael@0: * GetProgressOverlayStyle - returns the proper overlay part for themed michael@0: * progress bars based on os and orientation. michael@0: */ michael@0: static int32_t michael@0: GetProgressOverlayStyle(bool aIsVertical) michael@0: { michael@0: if (aIsVertical) { michael@0: if (IsVistaOrLater()) { michael@0: return PP_MOVEOVERLAYVERT; michael@0: } michael@0: return PP_CHUNKVERT; michael@0: } else { michael@0: if (IsVistaOrLater()) { michael@0: return PP_MOVEOVERLAY; michael@0: } michael@0: return PP_CHUNK; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * GetProgressOverlaySize - returns the minimum width or height for themed michael@0: * progress bar overlays. This includes the width of indeterminate chunks michael@0: * and vista pulse overlays. michael@0: */ michael@0: static int32_t michael@0: GetProgressOverlaySize(bool aIsVertical, bool aIsIndeterminate) michael@0: { michael@0: if (IsVistaOrLater()) { michael@0: if (aIsVertical) { michael@0: return aIsIndeterminate ? kProgressVerticalIndeterminateOverlaySize michael@0: : kProgressVerticalOverlaySize; michael@0: } michael@0: return kProgressHorizontalVistaOverlaySize; michael@0: } michael@0: return kProgressHorizontalXPOverlaySize; michael@0: } michael@0: michael@0: /* michael@0: * IsProgressMeterFilled - Determines if a progress meter is at 100% fill based michael@0: * on a comparison of the current value and maximum. michael@0: */ michael@0: static bool michael@0: IsProgressMeterFilled(nsIFrame* aFrame) michael@0: { michael@0: NS_ENSURE_TRUE(aFrame, false); michael@0: nsIFrame* parentFrame = aFrame->GetParent(); michael@0: NS_ENSURE_TRUE(parentFrame, false); michael@0: return nsNativeTheme::GetProgressValue(parentFrame) == michael@0: nsNativeTheme::GetProgressMaxValue(parentFrame); michael@0: } michael@0: michael@0: /* michael@0: * CalculateProgressOverlayRect - returns the padded overlay animation rect michael@0: * used in rendering progress bars. Resulting rects are used in rendering michael@0: * vista+ pulse overlays and indeterminate progress meters. Graphics should michael@0: * be rendered at the origin. michael@0: */ michael@0: RECT michael@0: nsNativeThemeWin::CalculateProgressOverlayRect(nsIFrame* aFrame, michael@0: RECT* aWidgetRect, michael@0: bool aIsVertical, michael@0: bool aIsIndeterminate, michael@0: bool aIsClassic) michael@0: { michael@0: NS_ASSERTION(aFrame, "bad frame pointer"); michael@0: NS_ASSERTION(aWidgetRect, "bad rect pointer"); michael@0: michael@0: int32_t frameSize = aIsVertical ? aWidgetRect->bottom - aWidgetRect->top michael@0: : aWidgetRect->right - aWidgetRect->left; michael@0: michael@0: // Recycle a set of progress pulse timers - these timers control the position michael@0: // of all progress overlays and indeterminate chunks that get rendered. michael@0: double span = aIsIndeterminate ? kProgressIndeterminateTimeSpan michael@0: : kProgressDeterminateTimeSpan; michael@0: TimeDuration period; michael@0: if (!aIsIndeterminate) { michael@0: if (TimeStamp::Now() > (mProgressDeterminateTimeStamp + michael@0: TimeDuration::FromSeconds(span))) { michael@0: mProgressDeterminateTimeStamp = TimeStamp::Now(); michael@0: } michael@0: period = TimeStamp::Now() - mProgressDeterminateTimeStamp; michael@0: } else { michael@0: if (TimeStamp::Now() > (mProgressIndeterminateTimeStamp + michael@0: TimeDuration::FromSeconds(span))) { michael@0: mProgressIndeterminateTimeStamp = TimeStamp::Now(); michael@0: } michael@0: period = TimeStamp::Now() - mProgressIndeterminateTimeStamp; michael@0: } michael@0: michael@0: double percent = period / TimeDuration::FromSeconds(span); michael@0: michael@0: if (!aIsVertical && IsFrameRTL(aFrame)) michael@0: percent = 1 - percent; michael@0: michael@0: RECT overlayRect = *aWidgetRect; michael@0: int32_t overlaySize; michael@0: if (!aIsClassic) { michael@0: overlaySize = GetProgressOverlaySize(aIsVertical, aIsIndeterminate); michael@0: } else { michael@0: overlaySize = kProgressClassicOverlaySize; michael@0: } michael@0: michael@0: // Calculate a bounds that is larger than the meters frame such that the michael@0: // overlay starts and ends completely off the edge of the frame: michael@0: // [overlay][frame][overlay] michael@0: // This also yields a nice delay on rotation. Use overlaySize as the minimum michael@0: // size for [overlay] based on the graphics dims. If [frame] is larger, use michael@0: // the frame size instead. michael@0: int trackWidth = frameSize > overlaySize ? frameSize : overlaySize; michael@0: if (!aIsVertical) { michael@0: int xPos = aWidgetRect->left - trackWidth; michael@0: xPos += (int)ceil(((double)(trackWidth*2) * percent)); michael@0: overlayRect.left = xPos; michael@0: overlayRect.right = xPos + overlaySize; michael@0: } else { michael@0: int yPos = aWidgetRect->bottom + trackWidth; michael@0: yPos -= (int)ceil(((double)(trackWidth*2) * percent)); michael@0: overlayRect.bottom = yPos; michael@0: overlayRect.top = yPos - overlaySize; michael@0: } michael@0: return overlayRect; michael@0: } michael@0: michael@0: /* michael@0: * DrawChunkProgressMeter - renders an xp style chunked progress meter. Called michael@0: * by DrawProgressMeter. michael@0: * michael@0: * @param aTheme progress theme handle michael@0: * @param aHdc hdc returned by gfxWindowsNativeDrawing michael@0: * @param aPart the PP_X progress part michael@0: * @param aState the theme state michael@0: * @param aFrame the elements frame michael@0: * @param aWidgetRect bounding rect for the widget michael@0: * @param aClipRect dirty rect that needs drawing. michael@0: * @param aAppUnits app units per device pixel michael@0: * @param aIsIndeterm is an indeterminate progress? michael@0: * @param aIsVertical render a vertical progress? michael@0: * @param aIsRtl direction is rtl michael@0: */ michael@0: static void michael@0: DrawChunkProgressMeter(HTHEME aTheme, HDC aHdc, int aPart, michael@0: int aState, nsIFrame* aFrame, RECT* aWidgetRect, michael@0: RECT* aClipRect, gfxFloat aAppUnits, bool aIsIndeterm, michael@0: bool aIsVertical, bool aIsRtl) michael@0: { michael@0: NS_ASSERTION(aTheme, "Bad theme."); michael@0: NS_ASSERTION(aHdc, "Bad hdc."); michael@0: NS_ASSERTION(aWidgetRect, "Bad rect."); michael@0: NS_ASSERTION(aClipRect, "Bad clip rect."); michael@0: NS_ASSERTION(aFrame, "Bad frame."); michael@0: michael@0: // For horizontal meters, the theme lib paints the right graphic but doesn't michael@0: // paint the chunks, so we do that manually. For vertical meters, the theme michael@0: // library draws everything correctly. michael@0: if (aIsVertical) { michael@0: DrawThemeBackground(aTheme, aHdc, aPart, aState, aWidgetRect, aClipRect); michael@0: return; michael@0: } michael@0: michael@0: // query for the proper chunk metrics michael@0: int chunkSize, spaceSize; michael@0: if (FAILED(GetThemeMetric(aTheme, aHdc, aPart, aState, michael@0: TMT_PROGRESSCHUNKSIZE, &chunkSize)) || michael@0: FAILED(GetThemeMetric(aTheme, aHdc, aPart, aState, michael@0: TMT_PROGRESSSPACESIZE, &spaceSize))) { michael@0: DrawThemeBackground(aTheme, aHdc, aPart, aState, aWidgetRect, aClipRect); michael@0: return; michael@0: } michael@0: michael@0: // render chunks michael@0: if (!aIsRtl || aIsIndeterm) { michael@0: for (int chunk = aWidgetRect->left; chunk <= aWidgetRect->right; michael@0: chunk += (chunkSize+spaceSize)) { michael@0: if (!aIsIndeterm && ((chunk + chunkSize) > aWidgetRect->right)) { michael@0: // aWidgetRect->right represents the end of the meter. Partial blocks michael@0: // don't get rendered with one exception, so exit here if we don't have michael@0: // a full chunk to draw. michael@0: // The above is true *except* when the meter is at 100% fill, in which michael@0: // case Windows renders any remaining partial block. Query the parent michael@0: // frame to find out if we're at 100%. michael@0: if (!IsProgressMeterFilled(aFrame)) { michael@0: break; michael@0: } michael@0: } michael@0: RECT bounds = michael@0: { chunk, aWidgetRect->top, chunk + chunkSize, aWidgetRect->bottom }; michael@0: DrawThemeBackground(aTheme, aHdc, aPart, aState, &bounds, aClipRect); michael@0: } michael@0: } else { michael@0: // rtl needs to grow in the opposite direction to look right. michael@0: for (int chunk = aWidgetRect->right; chunk >= aWidgetRect->left; michael@0: chunk -= (chunkSize+spaceSize)) { michael@0: if ((chunk - chunkSize) < aWidgetRect->left) { michael@0: if (!IsProgressMeterFilled(aFrame)) { michael@0: break; michael@0: } michael@0: } michael@0: RECT bounds = michael@0: { chunk - chunkSize, aWidgetRect->top, chunk, aWidgetRect->bottom }; michael@0: DrawThemeBackground(aTheme, aHdc, aPart, aState, &bounds, aClipRect); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * DrawProgressMeter - render an appropriate progress meter based on progress michael@0: * meter style, orientation, and os. Note, this does not render the underlying michael@0: * progress track. michael@0: * michael@0: * @param aFrame the widget frame michael@0: * @param aWidgetType type of widget michael@0: * @param aTheme progress theme handle michael@0: * @param aHdc hdc returned by gfxWindowsNativeDrawing michael@0: * @param aPart the PP_X progress part michael@0: * @param aState the theme state michael@0: * @param aWidgetRect bounding rect for the widget michael@0: * @param aClipRect dirty rect that needs drawing. michael@0: * @param aAppUnits app units per device pixel michael@0: */ michael@0: void michael@0: nsNativeThemeWin::DrawThemedProgressMeter(nsIFrame* aFrame, int aWidgetType, michael@0: HANDLE aTheme, HDC aHdc, michael@0: int aPart, int aState, michael@0: RECT* aWidgetRect, RECT* aClipRect, michael@0: gfxFloat aAppUnits) michael@0: { michael@0: if (!aFrame || !aTheme || !aHdc) michael@0: return; michael@0: michael@0: NS_ASSERTION(aWidgetRect, "bad rect pointer"); michael@0: NS_ASSERTION(aClipRect, "bad clip rect pointer"); michael@0: michael@0: RECT adjWidgetRect, adjClipRect; michael@0: adjWidgetRect = *aWidgetRect; michael@0: adjClipRect = *aClipRect; michael@0: if (!IsVistaOrLater()) { michael@0: // Adjust clipping out by one pixel. XP progress meters are inset, michael@0: // Vista+ are not. michael@0: InflateRect(&adjWidgetRect, 1, 1); michael@0: InflateRect(&adjClipRect, 1, 1); michael@0: } michael@0: michael@0: nsIFrame* parentFrame = aFrame->GetParent(); michael@0: if (!parentFrame) { michael@0: // We have no parent to work with, just bail. michael@0: NS_WARNING("No parent frame for progress rendering. Can't paint."); michael@0: return; michael@0: } michael@0: michael@0: EventStates eventStates = GetContentState(parentFrame, aWidgetType); michael@0: bool vertical = IsVerticalProgress(parentFrame) || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL; michael@0: bool indeterminate = IsIndeterminateProgress(parentFrame, eventStates); michael@0: bool animate = indeterminate; michael@0: michael@0: if (IsVistaOrLater()) { michael@0: // Vista and up progress meter is fill style, rendered here. We render michael@0: // the pulse overlay in the follow up section below. michael@0: DrawThemeBackground(aTheme, aHdc, aPart, aState, michael@0: &adjWidgetRect, &adjClipRect); michael@0: if (!IsProgressMeterFilled(aFrame)) { michael@0: animate = true; michael@0: } michael@0: } else if (!indeterminate) { michael@0: // XP progress meters are 'chunk' style. michael@0: DrawChunkProgressMeter(aTheme, aHdc, aPart, aState, aFrame, michael@0: &adjWidgetRect, &adjClipRect, aAppUnits, michael@0: indeterminate, vertical, IsFrameRTL(aFrame)); michael@0: } michael@0: michael@0: if (animate) { michael@0: // Indeterminate rendering michael@0: int32_t overlayPart = GetProgressOverlayStyle(vertical); michael@0: RECT overlayRect = michael@0: CalculateProgressOverlayRect(aFrame, &adjWidgetRect, vertical, michael@0: indeterminate, false); michael@0: if (IsVistaOrLater()) { michael@0: DrawThemeBackground(aTheme, aHdc, overlayPart, aState, &overlayRect, michael@0: &adjClipRect); michael@0: } else { michael@0: DrawChunkProgressMeter(aTheme, aHdc, overlayPart, aState, aFrame, michael@0: &overlayRect, &adjClipRect, aAppUnits, michael@0: indeterminate, vertical, IsFrameRTL(aFrame)); michael@0: } michael@0: michael@0: if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 60)) { michael@0: NS_WARNING("unable to animate progress widget!"); michael@0: } michael@0: } michael@0: } michael@0: michael@0: HANDLE michael@0: nsNativeThemeWin::GetTheme(uint8_t aWidgetType) michael@0: { michael@0: if (!IsVistaOrLater()) { michael@0: // On XP or earlier, render dropdowns as textfields; michael@0: // doing it the right way works fine with the MS themes, michael@0: // but breaks on a lot of custom themes (presumably because MS michael@0: // apps do the textfield border business as well). michael@0: if (aWidgetType == NS_THEME_DROPDOWN) michael@0: aWidgetType = NS_THEME_TEXTFIELD; michael@0: } michael@0: michael@0: switch (aWidgetType) { michael@0: case NS_THEME_BUTTON: michael@0: case NS_THEME_RADIO: michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_GROUPBOX: michael@0: return nsUXThemeData::GetTheme(eUXButton); michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TEXTFIELD_MULTILINE: michael@0: return nsUXThemeData::GetTheme(eUXEdit); michael@0: case NS_THEME_TOOLTIP: michael@0: // XP/2K3 should force a classic treatment of tooltips michael@0: return !IsVistaOrLater() ? michael@0: nullptr : nsUXThemeData::GetTheme(eUXTooltip); michael@0: case NS_THEME_TOOLBOX: michael@0: return nsUXThemeData::GetTheme(eUXRebar); michael@0: case NS_THEME_WIN_MEDIA_TOOLBOX: michael@0: return nsUXThemeData::GetTheme(eUXMediaRebar); michael@0: case NS_THEME_WIN_COMMUNICATIONS_TOOLBOX: michael@0: return nsUXThemeData::GetTheme(eUXCommunicationsRebar); michael@0: case NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX: michael@0: return nsUXThemeData::GetTheme(eUXBrowserTabBarRebar); michael@0: case NS_THEME_TOOLBAR: michael@0: case NS_THEME_TOOLBAR_BUTTON: michael@0: case NS_THEME_TOOLBAR_SEPARATOR: michael@0: return nsUXThemeData::GetTheme(eUXToolbar); michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: case NS_THEME_PROGRESSBAR_CHUNK: michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: michael@0: return nsUXThemeData::GetTheme(eUXProgress); michael@0: case NS_THEME_TAB: michael@0: case NS_THEME_TAB_PANEL: michael@0: case NS_THEME_TAB_PANELS: michael@0: return nsUXThemeData::GetTheme(eUXTab); michael@0: case NS_THEME_SCROLLBAR: michael@0: case NS_THEME_SCROLLBAR_SMALL: michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: return nsUXThemeData::GetTheme(eUXScrollbar); michael@0: case NS_THEME_RANGE: michael@0: case NS_THEME_RANGE_THUMB: michael@0: case NS_THEME_SCALE_HORIZONTAL: michael@0: case NS_THEME_SCALE_VERTICAL: michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: michael@0: return nsUXThemeData::GetTheme(eUXTrackbar); michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: michael@0: return nsUXThemeData::GetTheme(eUXSpin); michael@0: case NS_THEME_STATUSBAR: michael@0: case NS_THEME_STATUSBAR_PANEL: michael@0: case NS_THEME_STATUSBAR_RESIZER_PANEL: michael@0: case NS_THEME_RESIZER: michael@0: return nsUXThemeData::GetTheme(eUXStatus); michael@0: case NS_THEME_DROPDOWN: michael@0: case NS_THEME_DROPDOWN_BUTTON: michael@0: return nsUXThemeData::GetTheme(eUXCombobox); michael@0: case NS_THEME_TREEVIEW_HEADER_CELL: michael@0: case NS_THEME_TREEVIEW_HEADER_SORTARROW: michael@0: return nsUXThemeData::GetTheme(eUXHeader); michael@0: case NS_THEME_LISTBOX: michael@0: case NS_THEME_LISTBOX_LISTITEM: michael@0: case NS_THEME_TREEVIEW: michael@0: case NS_THEME_TREEVIEW_TWISTY_OPEN: michael@0: case NS_THEME_TREEVIEW_TREEITEM: michael@0: return nsUXThemeData::GetTheme(eUXListview); michael@0: case NS_THEME_MENUBAR: michael@0: case NS_THEME_MENUPOPUP: michael@0: case NS_THEME_MENUITEM: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: michael@0: case NS_THEME_MENUCHECKBOX: michael@0: case NS_THEME_MENURADIO: michael@0: case NS_THEME_MENUSEPARATOR: michael@0: case NS_THEME_MENUARROW: michael@0: case NS_THEME_MENUIMAGE: michael@0: case NS_THEME_MENUITEMTEXT: michael@0: return nsUXThemeData::GetTheme(eUXMenu); michael@0: case NS_THEME_WINDOW_TITLEBAR: michael@0: case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: michael@0: case NS_THEME_WINDOW_FRAME_LEFT: michael@0: case NS_THEME_WINDOW_FRAME_RIGHT: michael@0: case NS_THEME_WINDOW_FRAME_BOTTOM: michael@0: case NS_THEME_WINDOW_BUTTON_CLOSE: michael@0: case NS_THEME_WINDOW_BUTTON_MINIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_MAXIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_RESTORE: michael@0: case NS_THEME_WINDOW_BUTTON_BOX: michael@0: case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: michael@0: case NS_THEME_WIN_GLASS: michael@0: case NS_THEME_WIN_BORDERLESS_GLASS: michael@0: return nsUXThemeData::GetTheme(eUXWindowFrame); michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: int32_t michael@0: nsNativeThemeWin::StandardGetState(nsIFrame* aFrame, uint8_t aWidgetType, michael@0: bool wantFocused) michael@0: { michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) michael@0: return TS_ACTIVE; michael@0: if (eventState.HasState(NS_EVENT_STATE_HOVER)) michael@0: return TS_HOVER; michael@0: if (wantFocused && eventState.HasState(NS_EVENT_STATE_FOCUS)) michael@0: return TS_FOCUSED; michael@0: michael@0: return TS_NORMAL; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeWin::IsMenuActive(nsIFrame *aFrame, uint8_t aWidgetType) michael@0: { michael@0: nsIContent* content = aFrame->GetContent(); michael@0: if (content->IsXUL() && michael@0: content->NodeInfo()->Equals(nsGkAtoms::richlistitem)) michael@0: return CheckBooleanAttr(aFrame, nsGkAtoms::selected); michael@0: michael@0: return CheckBooleanAttr(aFrame, nsGkAtoms::menuactive); michael@0: } michael@0: michael@0: /** michael@0: * aPart is filled in with the UXTheme part code. On return, values > 0 michael@0: * are the actual UXTheme part code; -1 means the widget will be drawn by michael@0: * us; 0 means that we should use part code 0, which isn't a real part code michael@0: * but elicits some kind of default behaviour from UXTheme when drawing michael@0: * (but isThemeBackgroundPartiallyTransparent may not work). michael@0: */ michael@0: nsresult michael@0: nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType, michael@0: int32_t& aPart, int32_t& aState) michael@0: { michael@0: if (!IsVistaOrLater()) { michael@0: // See GetTheme michael@0: if (aWidgetType == NS_THEME_DROPDOWN) michael@0: aWidgetType = NS_THEME_TEXTFIELD; michael@0: } michael@0: michael@0: switch (aWidgetType) { michael@0: case NS_THEME_BUTTON: { michael@0: aPart = BP_BUTTON; michael@0: if (!aFrame) { michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: if (IsDisabled(aFrame, eventState)) { michael@0: aState = TS_DISABLED; michael@0: return NS_OK; michael@0: } else if (IsOpenButton(aFrame) || michael@0: IsCheckedButton(aFrame)) { michael@0: aState = TS_ACTIVE; michael@0: return NS_OK; michael@0: } michael@0: michael@0: aState = StandardGetState(aFrame, aWidgetType, true); michael@0: michael@0: // Check for default dialog buttons. These buttons should always look michael@0: // focused. michael@0: if (aState == TS_NORMAL && IsDefaultButton(aFrame)) michael@0: aState = TS_FOCUSED; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_RADIO: { michael@0: bool isCheckbox = (aWidgetType == NS_THEME_CHECKBOX); michael@0: aPart = isCheckbox ? BP_CHECKBOX : BP_RADIO; michael@0: michael@0: enum InputState { michael@0: UNCHECKED = 0, CHECKED, INDETERMINATE michael@0: }; michael@0: InputState inputState = UNCHECKED; michael@0: bool isXULCheckboxRadio = false; michael@0: michael@0: if (!aFrame) { michael@0: aState = TS_NORMAL; michael@0: } else { michael@0: if (GetCheckedOrSelected(aFrame, !isCheckbox)) { michael@0: inputState = CHECKED; michael@0: } if (isCheckbox && GetIndeterminate(aFrame)) { michael@0: inputState = INDETERMINATE; michael@0: } michael@0: michael@0: EventStates eventState = michael@0: GetContentState(isXULCheckboxRadio ? aFrame->GetParent() : aFrame, michael@0: aWidgetType); michael@0: if (IsDisabled(aFrame, eventState)) { michael@0: aState = TS_DISABLED; michael@0: } else { michael@0: aState = StandardGetState(aFrame, aWidgetType, false); michael@0: } michael@0: } michael@0: michael@0: // 4 unchecked states, 4 checked states, 4 indeterminate states. michael@0: aState += inputState * 4; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_GROUPBOX: { michael@0: aPart = BP_GROUPBOX; michael@0: aState = TS_NORMAL; michael@0: // Since we don't support groupbox disabled and GBS_DISABLED looks the michael@0: // same as GBS_NORMAL don't bother supporting GBS_DISABLED. michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TEXTFIELD_MULTILINE: { michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: if (IsVistaOrLater()) { michael@0: /* Note: the NOSCROLL type has a rounded corner in each michael@0: * corner. The more specific HSCROLL, VSCROLL, HVSCROLL types michael@0: * have side and/or top/bottom edges rendered as straight michael@0: * horizontal lines with sharp corners to accommodate a michael@0: * scrollbar. However, the scrollbar gets rendered on top of michael@0: * this for us, so we don't care, and can just use NOSCROLL michael@0: * here. michael@0: */ michael@0: aPart = TFP_EDITBORDER_NOSCROLL; michael@0: michael@0: if (!aFrame) { michael@0: aState = TFS_EDITBORDER_NORMAL; michael@0: } else if (IsDisabled(aFrame, eventState)) { michael@0: aState = TFS_EDITBORDER_DISABLED; michael@0: } else if (IsReadOnly(aFrame)) { michael@0: /* no special read-only state */ michael@0: aState = TFS_EDITBORDER_NORMAL; michael@0: } else { michael@0: nsIContent* content = aFrame->GetContent(); michael@0: michael@0: /* XUL textboxes don't get focused themselves, because they have child michael@0: * html:input.. but we can check the XUL focused attributes on them michael@0: */ michael@0: if (content && content->IsXUL() && IsFocused(aFrame)) michael@0: aState = TFS_EDITBORDER_FOCUSED; michael@0: else if (eventState.HasAtLeastOneOfStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS)) michael@0: aState = TFS_EDITBORDER_FOCUSED; michael@0: else if (eventState.HasState(NS_EVENT_STATE_HOVER)) michael@0: aState = TFS_EDITBORDER_HOVER; michael@0: else michael@0: aState = TFS_EDITBORDER_NORMAL; michael@0: } michael@0: } else { michael@0: aPart = TFP_TEXTFIELD; michael@0: michael@0: if (!aFrame) michael@0: aState = TS_NORMAL; michael@0: else if (IsDisabled(aFrame, eventState)) michael@0: aState = TS_DISABLED; michael@0: else if (IsReadOnly(aFrame)) michael@0: aState = TFS_READONLY; michael@0: else michael@0: aState = StandardGetState(aFrame, aWidgetType, true); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TOOLTIP: { michael@0: aPart = TTP_STANDARD; michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: { michael@0: // Note IsVerticalProgress only tests for orient css attrribute, michael@0: // NS_THEME_PROGRESSBAR_VERTICAL is dedicated to -moz-appearance: michael@0: // progressbar-vertical. michael@0: bool vertical = IsVerticalProgress(aFrame) || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL; michael@0: aPart = vertical ? PP_BARVERT : PP_BAR; michael@0: aState = PBBS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_PROGRESSBAR_CHUNK: michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: { michael@0: nsIFrame* parentFrame = aFrame->GetParent(); michael@0: EventStates eventStates = GetContentState(parentFrame, aWidgetType); michael@0: if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL || michael@0: IsVerticalProgress(parentFrame)) { michael@0: aPart = IsVistaOrLater() ? michael@0: PP_FILLVERT : PP_CHUNKVERT; michael@0: } else { michael@0: aPart = IsVistaOrLater() ? michael@0: PP_FILL : PP_CHUNK; michael@0: } michael@0: michael@0: aState = PBBVS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TOOLBAR_BUTTON: { michael@0: aPart = BP_BUTTON; michael@0: if (!aFrame) { michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: if (IsDisabled(aFrame, eventState)) { michael@0: aState = TS_DISABLED; michael@0: return NS_OK; michael@0: } michael@0: if (IsOpenButton(aFrame)) { michael@0: aState = TS_ACTIVE; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) michael@0: aState = TS_ACTIVE; michael@0: else if (eventState.HasState(NS_EVENT_STATE_HOVER)) { michael@0: if (IsCheckedButton(aFrame)) michael@0: aState = TB_HOVER_CHECKED; michael@0: else michael@0: aState = TS_HOVER; michael@0: } michael@0: else { michael@0: if (IsCheckedButton(aFrame)) michael@0: aState = TB_CHECKED; michael@0: else michael@0: aState = TS_NORMAL; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TOOLBAR_SEPARATOR: { michael@0: aPart = TP_SEPARATOR; michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: { michael@0: aPart = SP_BUTTON; michael@0: aState = (aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP)*4; michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: if (!aFrame) michael@0: aState += TS_NORMAL; michael@0: else if (IsDisabled(aFrame, eventState)) michael@0: aState += TS_DISABLED; michael@0: else { michael@0: nsIFrame *parent = aFrame->GetParent(); michael@0: EventStates parentState = michael@0: GetContentState(parent, parent->StyleDisplay()->mAppearance); michael@0: if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) michael@0: aState += TS_ACTIVE; michael@0: else if (eventState.HasState(NS_EVENT_STATE_HOVER)) michael@0: aState += TS_HOVER; michael@0: else if (IsVistaOrLater() && michael@0: parentState.HasState(NS_EVENT_STATE_HOVER)) michael@0: aState = (aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP) + SP_BUTTON_IMPLICIT_HOVER_BASE; michael@0: else michael@0: aState += TS_NORMAL; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: { michael@0: aPart = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL) ? michael@0: SP_TRACKSTARTHOR : SP_TRACKSTARTVERT; michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: { michael@0: aPart = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL) ? michael@0: SP_THUMBHOR : SP_THUMBVERT; michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: if (!aFrame) michael@0: aState = TS_NORMAL; michael@0: else if (IsDisabled(aFrame, eventState)) michael@0: aState = TS_DISABLED; michael@0: else { michael@0: if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) // Hover is not also a requirement for michael@0: // the thumb, since the drag is not canceled michael@0: // when you move outside the thumb. michael@0: aState = TS_ACTIVE; michael@0: else if (eventState.HasState(NS_EVENT_STATE_HOVER)) michael@0: aState = TS_HOVER; michael@0: else michael@0: aState = TS_NORMAL; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_RANGE: michael@0: case NS_THEME_SCALE_HORIZONTAL: michael@0: case NS_THEME_SCALE_VERTICAL: { michael@0: if (aWidgetType == NS_THEME_SCALE_HORIZONTAL || michael@0: (aWidgetType == NS_THEME_RANGE && michael@0: IsRangeHorizontal(aFrame))) { michael@0: aPart = TKP_TRACK; michael@0: aState = TRS_NORMAL; michael@0: } else { michael@0: aPart = TKP_TRACKVERT; michael@0: aState = TRVS_NORMAL; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_RANGE_THUMB: michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: { michael@0: if (aWidgetType == NS_THEME_RANGE_THUMB) { michael@0: if (IsRangeHorizontal(aFrame)) { michael@0: aPart = TKP_THUMBBOTTOM; michael@0: } else { michael@0: aPart = IsFrameRTL(aFrame) ? TKP_THUMBLEFT : TKP_THUMBRIGHT; michael@0: } michael@0: } else { michael@0: aPart = (aWidgetType == NS_THEME_SCALE_THUMB_HORIZONTAL) ? michael@0: TKP_THUMB : TKP_THUMBVERT; michael@0: } michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: if (!aFrame) michael@0: aState = TS_NORMAL; michael@0: else if (IsDisabled(aFrame, eventState)) { michael@0: aState = TKP_DISABLED; michael@0: } michael@0: else { michael@0: if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) // Hover is not also a requirement for michael@0: // the thumb, since the drag is not canceled michael@0: // when you move outside the thumb. michael@0: aState = TS_ACTIVE; michael@0: else if (eventState.HasState(NS_EVENT_STATE_FOCUS)) michael@0: aState = TKP_FOCUSED; michael@0: else if (eventState.HasState(NS_EVENT_STATE_HOVER)) michael@0: aState = TS_HOVER; michael@0: else michael@0: aState = TS_NORMAL; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: { michael@0: aPart = (aWidgetType == NS_THEME_SPINNER_UP_BUTTON) ? michael@0: SPNP_UP : SPNP_DOWN; michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: if (!aFrame) michael@0: aState = TS_NORMAL; michael@0: else if (IsDisabled(aFrame, eventState)) michael@0: aState = TS_DISABLED; michael@0: else michael@0: aState = StandardGetState(aFrame, aWidgetType, false); michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TOOLBOX: michael@0: case NS_THEME_WIN_MEDIA_TOOLBOX: michael@0: case NS_THEME_WIN_COMMUNICATIONS_TOOLBOX: michael@0: case NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX: michael@0: case NS_THEME_STATUSBAR: michael@0: case NS_THEME_SCROLLBAR: michael@0: case NS_THEME_SCROLLBAR_SMALL: { michael@0: aState = 0; michael@0: if (IsVistaOrLater()) { michael@0: // On vista, they have a part michael@0: aPart = RP_BACKGROUND; michael@0: } else { michael@0: // Otherwise, they don't. (But I bet michael@0: // RP_BACKGROUND would work here, too); michael@0: aPart = 0; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TOOLBAR: { michael@0: // Use -1 to indicate we don't wish to have the theme background drawn michael@0: // for this item. We will pass any nessessary information via aState, michael@0: // and will render the item using separate code. michael@0: aPart = -1; michael@0: aState = 0; michael@0: if (aFrame) { michael@0: nsIContent* content = aFrame->GetContent(); michael@0: nsIContent* parent = content->GetParent(); michael@0: // XXXzeniko hiding the first toolbar will result in an unwanted margin michael@0: if (parent && parent->GetFirstChild() == content) { michael@0: aState = 1; michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_STATUSBAR_PANEL: michael@0: case NS_THEME_STATUSBAR_RESIZER_PANEL: michael@0: case NS_THEME_RESIZER: { michael@0: aPart = (aWidgetType - NS_THEME_STATUSBAR_PANEL) + 1; michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TREEVIEW: michael@0: case NS_THEME_LISTBOX: { michael@0: aPart = TREEVIEW_BODY; michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TAB_PANELS: { michael@0: aPart = TABP_PANELS; michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TAB_PANEL: { michael@0: aPart = TABP_PANEL; michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TAB: { michael@0: aPart = TABP_TAB; michael@0: if (!aFrame) { michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: if (IsDisabled(aFrame, eventState)) { michael@0: aState = TS_DISABLED; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (IsSelectedTab(aFrame)) { michael@0: aPart = TABP_TAB_SELECTED; michael@0: aState = TS_ACTIVE; // The selected tab is always "pressed". michael@0: } michael@0: else michael@0: aState = StandardGetState(aFrame, aWidgetType, true); michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TREEVIEW_HEADER_SORTARROW: { michael@0: // XXX Probably will never work due to a bug in the Luna theme. michael@0: aPart = 4; michael@0: aState = 1; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_TREEVIEW_HEADER_CELL: { michael@0: aPart = 1; michael@0: if (!aFrame) { michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: michael@0: aState = StandardGetState(aFrame, aWidgetType, true); michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_DROPDOWN: { michael@0: nsIContent* content = aFrame->GetContent(); michael@0: bool isHTML = content && content->IsHTML(); michael@0: bool useDropBorder = isHTML || IsMenuListEditable(aFrame); michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: /* On Vista/Win7, we use CBP_DROPBORDER instead of DROPFRAME for HTML michael@0: * content or for editable menulists; this gives us the thin outline, michael@0: * instead of the gradient-filled background */ michael@0: if (useDropBorder) michael@0: aPart = CBP_DROPBORDER; michael@0: else michael@0: aPart = CBP_DROPFRAME; michael@0: michael@0: if (IsDisabled(aFrame, eventState)) { michael@0: aState = TS_DISABLED; michael@0: } else if (IsReadOnly(aFrame)) { michael@0: aState = TS_NORMAL; michael@0: } else if (IsOpenButton(aFrame)) { michael@0: aState = TS_ACTIVE; michael@0: } else { michael@0: if (useDropBorder && (eventState.HasState(NS_EVENT_STATE_FOCUS) || IsFocused(aFrame))) michael@0: aState = TS_ACTIVE; michael@0: else if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) michael@0: aState = TS_ACTIVE; michael@0: else if (eventState.HasState(NS_EVENT_STATE_HOVER)) michael@0: aState = TS_HOVER; michael@0: else michael@0: aState = TS_NORMAL; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_DROPDOWN_BUTTON: { michael@0: bool isHTML = IsHTMLContent(aFrame); michael@0: nsIFrame* parentFrame = aFrame->GetParent(); michael@0: bool isMenulist = !isHTML && parentFrame->GetType() == nsGkAtoms::menuFrame; michael@0: bool isOpen = false; michael@0: michael@0: // HTML select and XUL menulist dropdown buttons get state from the parent. michael@0: if (isHTML || isMenulist) michael@0: aFrame = parentFrame; michael@0: michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: aPart = IsVistaOrLater() ? michael@0: CBP_DROPMARKER_VISTA : CBP_DROPMARKER; michael@0: michael@0: // For HTML controls with author styling, we should fall michael@0: // back to the old dropmarker style to avoid clashes with michael@0: // author-specified backgrounds and borders (bug #441034) michael@0: if (isHTML && IsWidgetStyled(aFrame->PresContext(), aFrame, NS_THEME_DROPDOWN)) michael@0: aPart = CBP_DROPMARKER; michael@0: michael@0: if (IsDisabled(aFrame, eventState)) { michael@0: aState = TS_DISABLED; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (isHTML) { michael@0: nsIComboboxControlFrame* ccf = do_QueryFrame(aFrame); michael@0: isOpen = (ccf && ccf->IsDroppedDown()); michael@0: } michael@0: else michael@0: isOpen = IsOpenButton(aFrame); michael@0: michael@0: if (IsVistaOrLater()) { michael@0: if (isHTML || IsMenuListEditable(aFrame)) { michael@0: if (isOpen) { michael@0: /* Hover is propagated, but we need to know whether we're michael@0: * hovering just the combobox frame, not the dropdown frame. michael@0: * But, we can't get that information, since hover is on the michael@0: * content node, and they share the same content node. So, michael@0: * instead, we cheat -- if the dropdown is open, we always michael@0: * show the hover state. This looks fine in practice. michael@0: */ michael@0: aState = TS_HOVER; michael@0: return NS_OK; michael@0: } michael@0: } else { michael@0: /* On Vista, the dropdown indicator on a menulist button in michael@0: * chrome is not given a hover effect. When the frame isn't michael@0: * isn't HTML content, we cheat and force the dropdown state michael@0: * to be normal. (Bug 430434) michael@0: */ michael@0: aState = TS_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: aState = TS_NORMAL; michael@0: michael@0: // Dropdown button active state doesn't need :hover. michael@0: if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) { michael@0: if (isOpen && (isHTML || isMenulist)) { michael@0: // XXX Button should look active until the mouse is released, but michael@0: // without making it look active when the popup is clicked. michael@0: return NS_OK; michael@0: } michael@0: aState = TS_ACTIVE; michael@0: } michael@0: else if (eventState.HasState(NS_EVENT_STATE_HOVER)) { michael@0: // No hover effect for XUL menulists and autocomplete dropdown buttons michael@0: // while the dropdown menu is open. michael@0: if (isOpen) { michael@0: // XXX HTML select dropdown buttons should have the hover effect when michael@0: // hovering the combobox frame, but not the popup frame. michael@0: return NS_OK; michael@0: } michael@0: aState = TS_HOVER; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_MENUPOPUP: { michael@0: aPart = MENU_POPUPBACKGROUND; michael@0: aState = MB_ACTIVE; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_MENUITEM: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: { michael@0: bool isTopLevel = false; michael@0: bool isOpen = false; michael@0: bool isHover = false; michael@0: nsMenuFrame *menuFrame = do_QueryFrame(aFrame); michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: isTopLevel = IsTopLevelMenu(aFrame); michael@0: michael@0: if (menuFrame) michael@0: isOpen = menuFrame->IsOpen(); michael@0: michael@0: isHover = IsMenuActive(aFrame, aWidgetType); michael@0: michael@0: if (isTopLevel) { michael@0: aPart = MENU_BARITEM; michael@0: michael@0: if (isOpen) michael@0: aState = MBI_PUSHED; michael@0: else if (isHover) michael@0: aState = MBI_HOT; michael@0: else michael@0: aState = MBI_NORMAL; michael@0: michael@0: // the disabled states are offset by 3 michael@0: if (IsDisabled(aFrame, eventState)) michael@0: aState += 3; michael@0: } else { michael@0: aPart = MENU_POPUPITEM; michael@0: michael@0: if (isHover) michael@0: aState = MPI_HOT; michael@0: else michael@0: aState = MPI_NORMAL; michael@0: michael@0: // the disabled states are offset by 2 michael@0: if (IsDisabled(aFrame, eventState)) michael@0: aState += 2; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_MENUSEPARATOR: michael@0: aPart = MENU_POPUPSEPARATOR; michael@0: aState = 0; michael@0: return NS_OK; michael@0: case NS_THEME_MENUARROW: michael@0: { michael@0: aPart = MENU_POPUPSUBMENU; michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: aState = IsDisabled(aFrame, eventState) ? MSM_DISABLED : MSM_NORMAL; michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_MENUCHECKBOX: michael@0: case NS_THEME_MENURADIO: michael@0: { michael@0: bool isChecked; michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: // NOTE: we can probably use NS_EVENT_STATE_CHECKED michael@0: isChecked = CheckBooleanAttr(aFrame, nsGkAtoms::checked); michael@0: michael@0: aPart = MENU_POPUPCHECK; michael@0: aState = MC_CHECKMARKNORMAL; michael@0: michael@0: // Radio states are offset by 2 michael@0: if (aWidgetType == NS_THEME_MENURADIO) michael@0: aState += 2; michael@0: michael@0: // the disabled states are offset by 1 michael@0: if (IsDisabled(aFrame, eventState)) michael@0: aState += 1; michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_MENUITEMTEXT: michael@0: case NS_THEME_MENUIMAGE: michael@0: aPart = -1; michael@0: aState = 0; michael@0: return NS_OK; michael@0: michael@0: case NS_THEME_WINDOW_TITLEBAR: michael@0: aPart = mozilla::widget::themeconst::WP_CAPTION; michael@0: aState = GetTopLevelWindowActiveState(aFrame); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: michael@0: aPart = mozilla::widget::themeconst::WP_MAXCAPTION; michael@0: aState = GetTopLevelWindowActiveState(aFrame); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_FRAME_LEFT: michael@0: aPart = mozilla::widget::themeconst::WP_FRAMELEFT; michael@0: aState = GetTopLevelWindowActiveState(aFrame); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_FRAME_RIGHT: michael@0: aPart = mozilla::widget::themeconst::WP_FRAMERIGHT; michael@0: aState = GetTopLevelWindowActiveState(aFrame); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_FRAME_BOTTOM: michael@0: aPart = mozilla::widget::themeconst::WP_FRAMEBOTTOM; michael@0: aState = GetTopLevelWindowActiveState(aFrame); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_BUTTON_CLOSE: michael@0: aPart = mozilla::widget::themeconst::WP_CLOSEBUTTON; michael@0: aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_BUTTON_MINIMIZE: michael@0: aPart = mozilla::widget::themeconst::WP_MINBUTTON; michael@0: aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_BUTTON_MAXIMIZE: michael@0: aPart = mozilla::widget::themeconst::WP_MAXBUTTON; michael@0: aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_BUTTON_RESTORE: michael@0: aPart = mozilla::widget::themeconst::WP_RESTOREBUTTON; michael@0: aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_BUTTON_BOX: michael@0: case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: michael@0: case NS_THEME_WIN_GLASS: michael@0: case NS_THEME_WIN_BORDERLESS_GLASS: michael@0: aPart = -1; michael@0: aState = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: aPart = 0; michael@0: aState = 0; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: static bool michael@0: AssumeThemePartAndStateAreTransparent(int32_t aPart, int32_t aState) michael@0: { michael@0: if (aPart == MENU_POPUPITEM && aState == MBI_NORMAL) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeWin::DrawWidgetBackground(nsRenderingContext* aContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aWidgetType, michael@0: const nsRect& aRect, michael@0: const nsRect& aDirtyRect) michael@0: { michael@0: HANDLE theme = GetTheme(aWidgetType); michael@0: if (!theme) michael@0: return ClassicDrawWidgetBackground(aContext, aFrame, aWidgetType, aRect, aDirtyRect); michael@0: michael@0: // ^^ without the right sdk, assume xp theming and fall through. michael@0: if (nsUXThemeData::CheckForCompositor()) { michael@0: switch (aWidgetType) { michael@0: case NS_THEME_WINDOW_TITLEBAR: michael@0: case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: michael@0: case NS_THEME_WINDOW_FRAME_LEFT: michael@0: case NS_THEME_WINDOW_FRAME_RIGHT: michael@0: case NS_THEME_WINDOW_FRAME_BOTTOM: michael@0: // Nothing to draw, these areas are glass. Minimum dimensions michael@0: // should be set, so xul content should be layed out correctly. michael@0: return NS_OK; michael@0: break; michael@0: case NS_THEME_WINDOW_BUTTON_CLOSE: michael@0: case NS_THEME_WINDOW_BUTTON_MINIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_MAXIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_RESTORE: michael@0: // Not conventional bitmaps, can't be retrieved. If we fall michael@0: // through here and call the theme library we'll get aero michael@0: // basic bitmaps. michael@0: return NS_OK; michael@0: break; michael@0: case NS_THEME_WIN_GLASS: michael@0: case NS_THEME_WIN_BORDERLESS_GLASS: michael@0: // Nothing to draw, this is the glass background. michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_BUTTON_BOX: michael@0: case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: michael@0: // We handle these through nsIWidget::UpdateThemeGeometries michael@0: return NS_OK; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: int32_t part, state; michael@0: nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (AssumeThemePartAndStateAreTransparent(part, state)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: gfxFloat p2a = gfxFloat(aContext->AppUnitsPerDevPixel()); michael@0: RECT widgetRect; michael@0: RECT clipRect; michael@0: gfxRect tr(aRect.x, aRect.y, aRect.width, aRect.height), michael@0: dr(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); michael@0: michael@0: tr.ScaleInverse(p2a); michael@0: dr.ScaleInverse(p2a); michael@0: michael@0: nsRefPtr ctx = aContext->ThebesContext(); michael@0: michael@0: gfxWindowsNativeDrawing nativeDrawing(ctx, dr, GetWidgetNativeDrawingFlags(aWidgetType)); michael@0: michael@0: RENDER_AGAIN: michael@0: michael@0: HDC hdc = nativeDrawing.BeginNativeDrawing(); michael@0: if (!hdc) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nativeDrawing.TransformToNativeRect(tr, widgetRect); michael@0: nativeDrawing.TransformToNativeRect(dr, clipRect); michael@0: michael@0: #if 0 michael@0: { michael@0: PR_LOG(gWindowsLog, PR_LOG_ERROR, michael@0: (stderr, "xform: %f %f %f %f [%f %f]\n", m.xx, m.yx, m.xy, m.yy, michael@0: m.x0, m.y0)); michael@0: PR_LOG(gWindowsLog, PR_LOG_ERROR, michael@0: (stderr, "tr: [%d %d %d %d]\ndr: [%d %d %d %d]\noff: [%f %f]\n", michael@0: tr.x, tr.y, tr.width, tr.height, dr.x, dr.y, dr.width, dr.height, michael@0: offset.x, offset.y)); michael@0: } michael@0: #endif michael@0: michael@0: if (aWidgetType == NS_THEME_WINDOW_TITLEBAR) { michael@0: // Clip out the left and right corners of the frame, all we want in michael@0: // is the middle section. michael@0: widgetRect.left -= GetSystemMetrics(SM_CXFRAME); michael@0: widgetRect.right += GetSystemMetrics(SM_CXFRAME); michael@0: } else if (aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) { michael@0: // The origin of the window is off screen when maximized and windows michael@0: // doesn't compensate for this in rendering the background. Push the michael@0: // top of the bitmap down by SM_CYFRAME so we get the full graphic. michael@0: widgetRect.top += GetSystemMetrics(SM_CYFRAME); michael@0: } else if (aWidgetType == NS_THEME_TAB) { michael@0: // For left edge and right edge tabs, we need to adjust the widget michael@0: // rects and clip rects so that the edges don't get drawn. michael@0: bool isLeft = IsLeftToSelectedTab(aFrame); michael@0: bool isRight = !isLeft && IsRightToSelectedTab(aFrame); michael@0: michael@0: if (isLeft || isRight) { michael@0: // HACK ALERT: There appears to be no way to really obtain this value, so we're forced michael@0: // to just use the default value for Luna (which also happens to be correct for michael@0: // all the other skins I've tried). michael@0: int32_t edgeSize = 2; michael@0: michael@0: // Armed with the size of the edge, we now need to either shift to the left or to the michael@0: // right. The clip rect won't include this extra area, so we know that we're michael@0: // effectively shifting the edge out of view (such that it won't be painted). michael@0: if (isLeft) michael@0: // The right edge should not be drawn. Extend our rect by the edge size. michael@0: widgetRect.right += edgeSize; michael@0: else michael@0: // The left edge should not be drawn. Move the widget rect's left coord back. michael@0: widgetRect.left -= edgeSize; michael@0: } michael@0: } michael@0: else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) { michael@0: OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_MINIMIZE); michael@0: } michael@0: else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE || michael@0: aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { michael@0: OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_RESTORE); michael@0: } michael@0: else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) { michael@0: OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_CLOSE); michael@0: } michael@0: michael@0: // widgetRect is the bounding box for a widget, yet the scale track is only michael@0: // a small portion of this size, so the edges of the scale need to be michael@0: // adjusted to the real size of the track. michael@0: if (aWidgetType == NS_THEME_RANGE || michael@0: aWidgetType == NS_THEME_SCALE_HORIZONTAL || michael@0: aWidgetType == NS_THEME_SCALE_VERTICAL) { michael@0: RECT contentRect; michael@0: GetThemeBackgroundContentRect(theme, hdc, part, state, &widgetRect, &contentRect); michael@0: michael@0: SIZE siz; michael@0: GetThemePartSize(theme, hdc, part, state, &widgetRect, TS_TRUE, &siz); michael@0: michael@0: // When rounding is necessary, we round the position of the track michael@0: // away from the chevron of the thumb to make it look better. michael@0: if (aWidgetType == NS_THEME_SCALE_HORIZONTAL || michael@0: (aWidgetType == NS_THEME_RANGE && IsRangeHorizontal(aFrame))) { michael@0: contentRect.top += (contentRect.bottom - contentRect.top - siz.cy) / 2; michael@0: contentRect.bottom = contentRect.top + siz.cy; michael@0: } michael@0: else { michael@0: if (!IsFrameRTL(aFrame)) { michael@0: contentRect.left += (contentRect.right - contentRect.left - siz.cx) / 2; michael@0: contentRect.right = contentRect.left + siz.cx; michael@0: } else { michael@0: contentRect.right -= (contentRect.right - contentRect.left - siz.cx) / 2; michael@0: contentRect.left = contentRect.right - siz.cx; michael@0: } michael@0: } michael@0: michael@0: DrawThemeBackground(theme, hdc, part, state, &contentRect, &clipRect); michael@0: } michael@0: else if (aWidgetType == NS_THEME_MENUCHECKBOX || aWidgetType == NS_THEME_MENURADIO) michael@0: { michael@0: bool isChecked = false; michael@0: isChecked = CheckBooleanAttr(aFrame, nsGkAtoms::checked); michael@0: michael@0: if (isChecked) michael@0: { michael@0: int bgState = MCB_NORMAL; michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: // the disabled states are offset by 1 michael@0: if (IsDisabled(aFrame, eventState)) michael@0: bgState += 1; michael@0: michael@0: SIZE checkboxBGSize(GetCheckboxBGSize(theme, hdc)); michael@0: michael@0: RECT checkBGRect = widgetRect; michael@0: if (IsFrameRTL(aFrame)) { michael@0: checkBGRect.left = checkBGRect.right-checkboxBGSize.cx; michael@0: } else { michael@0: checkBGRect.right = checkBGRect.left+checkboxBGSize.cx; michael@0: } michael@0: michael@0: // Center the checkbox background vertically in the menuitem michael@0: checkBGRect.top += (checkBGRect.bottom - checkBGRect.top)/2 - checkboxBGSize.cy/2; michael@0: checkBGRect.bottom = checkBGRect.top + checkboxBGSize.cy; michael@0: michael@0: DrawThemeBackground(theme, hdc, MENU_POPUPCHECKBACKGROUND, bgState, &checkBGRect, &clipRect); michael@0: michael@0: MARGINS checkMargins = GetCheckboxMargins(theme, hdc); michael@0: RECT checkRect = checkBGRect; michael@0: checkRect.left += checkMargins.cxLeftWidth; michael@0: checkRect.right -= checkMargins.cxRightWidth; michael@0: checkRect.top += checkMargins.cyTopHeight; michael@0: checkRect.bottom -= checkMargins.cyBottomHeight; michael@0: DrawThemeBackground(theme, hdc, MENU_POPUPCHECK, state, &checkRect, &clipRect); michael@0: } michael@0: } michael@0: else if (aWidgetType == NS_THEME_MENUPOPUP) michael@0: { michael@0: DrawThemeBackground(theme, hdc, MENU_POPUPBORDERS, /* state */ 0, &widgetRect, &clipRect); michael@0: SIZE borderSize; michael@0: GetThemePartSize(theme, hdc, MENU_POPUPBORDERS, 0, nullptr, TS_TRUE, &borderSize); michael@0: michael@0: RECT bgRect = widgetRect; michael@0: bgRect.top += borderSize.cy; michael@0: bgRect.bottom -= borderSize.cy; michael@0: bgRect.left += borderSize.cx; michael@0: bgRect.right -= borderSize.cx; michael@0: michael@0: DrawThemeBackground(theme, hdc, MENU_POPUPBACKGROUND, /* state */ 0, &bgRect, &clipRect); michael@0: michael@0: SIZE gutterSize(GetGutterSize(theme, hdc)); michael@0: michael@0: RECT gutterRect; michael@0: gutterRect.top = bgRect.top; michael@0: gutterRect.bottom = bgRect.bottom; michael@0: if (IsFrameRTL(aFrame)) { michael@0: gutterRect.right = bgRect.right; michael@0: gutterRect.left = gutterRect.right-gutterSize.cx; michael@0: } else { michael@0: gutterRect.left = bgRect.left; michael@0: gutterRect.right = gutterRect.left+gutterSize.cx; michael@0: } michael@0: michael@0: DrawThemeBGRTLAware(theme, hdc, MENU_POPUPGUTTER, /* state */ 0, michael@0: &gutterRect, &clipRect, IsFrameRTL(aFrame)); michael@0: } michael@0: else if (aWidgetType == NS_THEME_MENUSEPARATOR) michael@0: { michael@0: SIZE gutterSize(GetGutterSize(theme,hdc)); michael@0: michael@0: RECT sepRect = widgetRect; michael@0: if (IsFrameRTL(aFrame)) michael@0: sepRect.right -= gutterSize.cx; michael@0: else michael@0: sepRect.left += gutterSize.cx; michael@0: michael@0: DrawThemeBackground(theme, hdc, MENU_POPUPSEPARATOR, /* state */ 0, &sepRect, &clipRect); michael@0: } michael@0: else if (aWidgetType == NS_THEME_MENUARROW) michael@0: { michael@0: // We're dpi aware and as such on systems that have dpi > 96 set, the michael@0: // theme library expects us to do proper positioning and scaling of glyphs. michael@0: // For NS_THEME_MENUARROW, layout may hand us a widget rect larger than the michael@0: // glyph rect we request in GetMinimumWidgetSize. To prevent distortion we michael@0: // have to position and scale what we draw. michael@0: michael@0: SIZE glyphSize; michael@0: GetThemePartSize(theme, hdc, part, state, nullptr, TS_TRUE, &glyphSize); michael@0: michael@0: int32_t widgetHeight = widgetRect.bottom - widgetRect.top; michael@0: michael@0: RECT renderRect = widgetRect; michael@0: michael@0: // We request (glyph width * 2, glyph height) in GetMinimumWidgetSize. In michael@0: // Firefox some menu items provide the full height of the item to us, in michael@0: // others our widget rect is the exact dims of our arrow glyph. Adjust the michael@0: // vertical position by the added space, if any exists. michael@0: renderRect.top += ((widgetHeight - glyphSize.cy) / 2); michael@0: renderRect.bottom = renderRect.top + glyphSize.cy; michael@0: // I'm using the width of the arrow glyph for the arrow-side padding. michael@0: // AFAICT there doesn't appear to be a theme constant we can query michael@0: // for this value. Generally this looks correct, and has the added michael@0: // benefit of being a dpi adjusted value. michael@0: if (!IsFrameRTL(aFrame)) { michael@0: renderRect.right = widgetRect.right - glyphSize.cx; michael@0: renderRect.left = renderRect.right - glyphSize.cx; michael@0: } else { michael@0: renderRect.left = glyphSize.cx; michael@0: renderRect.right = renderRect.left + glyphSize.cx; michael@0: } michael@0: DrawThemeBGRTLAware(theme, hdc, part, state, &renderRect, &clipRect, michael@0: IsFrameRTL(aFrame)); michael@0: } michael@0: // The following widgets need to be RTL-aware michael@0: else if (aWidgetType == NS_THEME_RESIZER || michael@0: aWidgetType == NS_THEME_DROPDOWN_BUTTON) michael@0: { michael@0: DrawThemeBGRTLAware(theme, hdc, part, state, michael@0: &widgetRect, &clipRect, IsFrameRTL(aFrame)); michael@0: } michael@0: else if (aWidgetType == NS_THEME_PROGRESSBAR || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL) { michael@0: // DrawThemeBackground renders each corner with a solid white pixel. michael@0: // Restore these pixels to the underlying color. Tracks are rendered michael@0: // using alpha recovery, so this makes the corners transparent. michael@0: COLORREF color; michael@0: color = GetPixel(hdc, widgetRect.left, widgetRect.top); michael@0: DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect); michael@0: SetPixel(hdc, widgetRect.left, widgetRect.top, color); michael@0: SetPixel(hdc, widgetRect.right-1, widgetRect.top, color); michael@0: SetPixel(hdc, widgetRect.right-1, widgetRect.bottom-1, color); michael@0: SetPixel(hdc, widgetRect.left, widgetRect.bottom-1, color); michael@0: } michael@0: else if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL) { michael@0: DrawThemedProgressMeter(aFrame, aWidgetType, theme, hdc, part, state, michael@0: &widgetRect, &clipRect, p2a); michael@0: } michael@0: // If part is negative, the element wishes us to not render a themed michael@0: // background, instead opting to be drawn specially below. michael@0: else if (part >= 0) { michael@0: DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect); michael@0: } michael@0: michael@0: // Draw focus rectangles for XP HTML checkboxes and radio buttons michael@0: // XXX it'd be nice to draw these outside of the frame michael@0: if (((aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO) && michael@0: aFrame->GetContent()->IsHTML()) || michael@0: aWidgetType == NS_THEME_RANGE || michael@0: aWidgetType == NS_THEME_SCALE_HORIZONTAL || michael@0: aWidgetType == NS_THEME_SCALE_VERTICAL) { michael@0: EventStates contentState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: if (contentState.HasState(NS_EVENT_STATE_FOCUS)) { michael@0: POINT vpOrg; michael@0: HPEN hPen = nullptr; michael@0: michael@0: uint8_t id = SaveDC(hdc); michael@0: michael@0: ::SelectClipRgn(hdc, nullptr); michael@0: ::GetViewportOrgEx(hdc, &vpOrg); michael@0: ::SetBrushOrgEx(hdc, vpOrg.x + widgetRect.left, vpOrg.y + widgetRect.top, nullptr); michael@0: michael@0: // On vista, choose our own colors and draw an XP style half focus rect michael@0: // for focused checkboxes and a full rect when active. michael@0: if (IsVistaOrLater() && michael@0: aWidgetType == NS_THEME_CHECKBOX) { michael@0: LOGBRUSH lb; michael@0: lb.lbStyle = BS_SOLID; michael@0: lb.lbColor = RGB(255,255,255); michael@0: lb.lbHatch = 0; michael@0: michael@0: hPen = ::ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, nullptr); michael@0: ::SelectObject(hdc, hPen); michael@0: michael@0: // If pressed, draw the upper left corner of the dotted rect. michael@0: if (contentState.HasState(NS_EVENT_STATE_ACTIVE)) { michael@0: ::MoveToEx(hdc, widgetRect.left, widgetRect.bottom-1, nullptr); michael@0: ::LineTo(hdc, widgetRect.left, widgetRect.top); michael@0: ::LineTo(hdc, widgetRect.right-1, widgetRect.top); michael@0: } michael@0: michael@0: // Draw the lower right corner of the dotted rect. michael@0: ::MoveToEx(hdc, widgetRect.right-1, widgetRect.top, nullptr); michael@0: ::LineTo(hdc, widgetRect.right-1, widgetRect.bottom-1); michael@0: ::LineTo(hdc, widgetRect.left, widgetRect.bottom-1); michael@0: } else { michael@0: ::SetTextColor(hdc, 0); michael@0: ::DrawFocusRect(hdc, &widgetRect); michael@0: } michael@0: ::RestoreDC(hdc, id); michael@0: if (hPen) { michael@0: ::DeleteObject(hPen); michael@0: } michael@0: } michael@0: } michael@0: else if (aWidgetType == NS_THEME_TOOLBAR && state == 0) { michael@0: // Draw toolbar separator lines above all toolbars except the first one. michael@0: // The lines are part of the Rebar theme, which is loaded for NS_THEME_TOOLBOX. michael@0: theme = GetTheme(NS_THEME_TOOLBOX); michael@0: if (!theme) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: widgetRect.bottom = widgetRect.top + TB_SEPARATOR_HEIGHT; michael@0: DrawThemeEdge(theme, hdc, RP_BAND, 0, &widgetRect, EDGE_ETCHED, BF_TOP, nullptr); michael@0: } michael@0: else if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL || michael@0: aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL) michael@0: { michael@0: // Draw the decorative gripper for the scrollbar thumb button, if it fits michael@0: michael@0: SIZE gripSize; michael@0: MARGINS thumbMgns; michael@0: int gripPart = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL) ? michael@0: SP_GRIPPERHOR : SP_GRIPPERVERT; michael@0: michael@0: if (GetThemePartSize(theme, hdc, gripPart, state, nullptr, TS_TRUE, &gripSize) == S_OK && michael@0: GetThemeMargins(theme, hdc, part, state, TMT_CONTENTMARGINS, nullptr, &thumbMgns) == S_OK && michael@0: gripSize.cx + thumbMgns.cxLeftWidth + thumbMgns.cxRightWidth <= widgetRect.right - widgetRect.left && michael@0: gripSize.cy + thumbMgns.cyTopHeight + thumbMgns.cyBottomHeight <= widgetRect.bottom - widgetRect.top) michael@0: { michael@0: DrawThemeBackground(theme, hdc, gripPart, state, &widgetRect, &clipRect); michael@0: } michael@0: } michael@0: michael@0: nativeDrawing.EndNativeDrawing(); michael@0: michael@0: if (nativeDrawing.ShouldRenderAgain()) michael@0: goto RENDER_AGAIN; michael@0: michael@0: nativeDrawing.PaintToContext(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeWin::GetWidgetBorder(nsDeviceContext* aContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aWidgetType, michael@0: nsIntMargin* aResult) michael@0: { michael@0: HANDLE theme = GetTheme(aWidgetType); michael@0: if (!theme) michael@0: return ClassicGetWidgetBorder(aContext, aFrame, aWidgetType, aResult); michael@0: michael@0: (*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 0; michael@0: michael@0: if (!WidgetIsContainer(aWidgetType) || michael@0: aWidgetType == NS_THEME_TOOLBOX || michael@0: aWidgetType == NS_THEME_WIN_MEDIA_TOOLBOX || michael@0: aWidgetType == NS_THEME_WIN_COMMUNICATIONS_TOOLBOX || michael@0: aWidgetType == NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX || michael@0: aWidgetType == NS_THEME_STATUSBAR || michael@0: aWidgetType == NS_THEME_RESIZER || aWidgetType == NS_THEME_TAB_PANEL || michael@0: aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL || michael@0: aWidgetType == NS_THEME_SCROLLBAR_TRACK_VERTICAL || michael@0: aWidgetType == NS_THEME_MENUITEM || aWidgetType == NS_THEME_CHECKMENUITEM || michael@0: aWidgetType == NS_THEME_RADIOMENUITEM || aWidgetType == NS_THEME_MENUPOPUP || michael@0: aWidgetType == NS_THEME_MENUIMAGE || aWidgetType == NS_THEME_MENUITEMTEXT || michael@0: aWidgetType == NS_THEME_TOOLBAR_SEPARATOR || michael@0: aWidgetType == NS_THEME_WINDOW_TITLEBAR || michael@0: aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED || michael@0: aWidgetType == NS_THEME_WIN_GLASS || aWidgetType == NS_THEME_WIN_BORDERLESS_GLASS) michael@0: return NS_OK; // Don't worry about it. michael@0: michael@0: int32_t part, state; michael@0: nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (aWidgetType == NS_THEME_TOOLBAR) { michael@0: // make space for the separator line above all toolbars but the first michael@0: if (state == 0) michael@0: aResult->top = TB_SEPARATOR_HEIGHT; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Get our info. michael@0: RECT outerRect; // Create a fake outer rect. michael@0: outerRect.top = outerRect.left = 100; michael@0: outerRect.right = outerRect.bottom = 200; michael@0: RECT contentRect(outerRect); michael@0: HRESULT res = GetThemeBackgroundContentRect(theme, nullptr, part, state, &outerRect, &contentRect); michael@0: michael@0: if (FAILED(res)) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // Now compute the delta in each direction and place it in our michael@0: // nsIntMargin struct. michael@0: aResult->top = contentRect.top - outerRect.top; michael@0: aResult->bottom = outerRect.bottom - contentRect.bottom; michael@0: aResult->left = contentRect.left - outerRect.left; michael@0: aResult->right = outerRect.right - contentRect.right; michael@0: michael@0: // Remove the edges for tabs that are before or after the selected tab, michael@0: if (aWidgetType == NS_THEME_TAB) { michael@0: if (IsLeftToSelectedTab(aFrame)) michael@0: // Remove the right edge, since we won't be drawing it. michael@0: aResult->right = 0; michael@0: else if (IsRightToSelectedTab(aFrame)) michael@0: // Remove the left edge, since we won't be drawing it. michael@0: aResult->left = 0; michael@0: } michael@0: michael@0: if (aFrame && (aWidgetType == NS_THEME_NUMBER_INPUT || michael@0: aWidgetType == NS_THEME_TEXTFIELD || michael@0: aWidgetType == NS_THEME_TEXTFIELD_MULTILINE)) { michael@0: nsIContent* content = aFrame->GetContent(); michael@0: if (content && content->IsHTML()) { michael@0: // We need to pad textfields by 1 pixel, since the caret will draw michael@0: // flush against the edge by default if we don't. michael@0: aResult->top++; michael@0: aResult->left++; michael@0: aResult->bottom++; michael@0: aResult->right++; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeWin::GetWidgetPadding(nsDeviceContext* aContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aWidgetType, michael@0: nsIntMargin* aResult) michael@0: { michael@0: switch (aWidgetType) { michael@0: // Radios and checkboxes return a fixed size in GetMinimumWidgetSize michael@0: // and have a meaningful baseline, so they can't have michael@0: // author-specified padding. michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_RADIO: michael@0: aResult->SizeTo(0, 0, 0, 0); michael@0: return true; michael@0: } michael@0: michael@0: HANDLE theme = GetTheme(aWidgetType); michael@0: michael@0: if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX || michael@0: aWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) { michael@0: aResult->SizeTo(0, 0, 0, 0); michael@0: michael@0: // aero glass doesn't display custom buttons michael@0: if (nsUXThemeData::CheckForCompositor()) michael@0: return true; michael@0: michael@0: // button padding for standard windows michael@0: if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX) { michael@0: aResult->top = GetSystemMetrics(SM_CXFRAME); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: // Content padding michael@0: if (aWidgetType == NS_THEME_WINDOW_TITLEBAR || michael@0: aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) { michael@0: aResult->SizeTo(0, 0, 0, 0); michael@0: // XXX Maximized windows have an offscreen offset equal to michael@0: // the border padding. This should be addressed in nsWindow, michael@0: // but currently can't be, see UpdateNonClientMargins. michael@0: if (aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) michael@0: aResult->top = GetSystemMetrics(SM_CXFRAME) michael@0: + GetSystemMetrics(SM_CXPADDEDBORDER); michael@0: return true; michael@0: } michael@0: michael@0: if (!theme) michael@0: return ClassicGetWidgetPadding(aContext, aFrame, aWidgetType, aResult); michael@0: michael@0: if (aWidgetType == NS_THEME_MENUPOPUP) michael@0: { michael@0: SIZE popupSize; michael@0: GetThemePartSize(theme, nullptr, MENU_POPUPBORDERS, /* state */ 0, nullptr, TS_TRUE, &popupSize); michael@0: aResult->top = aResult->bottom = popupSize.cy; michael@0: aResult->left = aResult->right = popupSize.cx; michael@0: return true; michael@0: } michael@0: michael@0: if (IsVistaOrLater()) { michael@0: if (aWidgetType == NS_THEME_NUMBER_INPUT || michael@0: aWidgetType == NS_THEME_TEXTFIELD || michael@0: aWidgetType == NS_THEME_TEXTFIELD_MULTILINE || michael@0: aWidgetType == NS_THEME_DROPDOWN) michael@0: { michael@0: /* If we have author-specified padding for these elements, don't do the fixups below */ michael@0: if (aFrame->PresContext()->HasAuthorSpecifiedRules(aFrame, NS_AUTHOR_SPECIFIED_PADDING)) michael@0: return false; michael@0: } michael@0: michael@0: /* textfields need extra pixels on all sides, otherwise they michael@0: * wrap their content too tightly. The actual border is drawn 1px michael@0: * inside the specified rectangle, so Gecko will end up making the michael@0: * contents look too small. Instead, we add 2px padding for the michael@0: * contents and fix this. (Used to be 1px added, see bug 430212) michael@0: */ michael@0: if (aWidgetType == NS_THEME_NUMBER_INPUT || michael@0: aWidgetType == NS_THEME_TEXTFIELD || michael@0: aWidgetType == NS_THEME_TEXTFIELD_MULTILINE) { michael@0: aResult->top = aResult->bottom = 2; michael@0: aResult->left = aResult->right = 2; michael@0: return true; michael@0: } else if (IsHTMLContent(aFrame) && aWidgetType == NS_THEME_DROPDOWN) { michael@0: /* For content menulist controls, we need an extra pixel so michael@0: * that we have room to draw our focus rectangle stuff. michael@0: * Otherwise, the focus rect might overlap the control's michael@0: * border. michael@0: */ michael@0: aResult->top = aResult->bottom = 1; michael@0: aResult->left = aResult->right = 1; michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: int32_t right, left, top, bottom; michael@0: right = left = top = bottom = 0; michael@0: switch (aWidgetType) michael@0: { michael@0: case NS_THEME_MENUIMAGE: michael@0: right = 8; michael@0: left = 3; michael@0: break; michael@0: case NS_THEME_MENUCHECKBOX: michael@0: case NS_THEME_MENURADIO: michael@0: right = 8; michael@0: left = 0; michael@0: break; michael@0: case NS_THEME_MENUITEMTEXT: michael@0: // There seem to be exactly 4 pixels from the edge michael@0: // of the gutter to the text: 2px margin (CSS) + 2px padding (here) michael@0: { michael@0: SIZE size(GetGutterSize(theme, nullptr)); michael@0: left = size.cx + 2; michael@0: } michael@0: break; michael@0: case NS_THEME_MENUSEPARATOR: michael@0: { michael@0: SIZE size(GetGutterSize(theme, nullptr)); michael@0: left = size.cx + 5; michael@0: top = 10; michael@0: bottom = 7; michael@0: } michael@0: break; michael@0: default: michael@0: return false; michael@0: } michael@0: michael@0: if (IsFrameRTL(aFrame)) michael@0: { michael@0: aResult->right = left; michael@0: aResult->left = right; michael@0: } michael@0: else michael@0: { michael@0: aResult->right = right; michael@0: aResult->left = left; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeWin::GetWidgetOverflow(nsDeviceContext* aContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aOverflowRect, michael@0: nsRect* aResult) michael@0: { michael@0: /* This is disabled for now, because it causes invalidation problems -- michael@0: * see bug 420381. The effect of not updating the overflow area is that michael@0: * for dropdown buttons in content areas, there is a 1px border on 3 sides michael@0: * where, if invalidated, the dropdown control probably won't be repainted. michael@0: * This is fairly minor, as by default there is nothing in that area, and michael@0: * a border only shows up if the widget is being hovered. michael@0: */ michael@0: #if 0 michael@0: if (IsVistaOrLater()) { michael@0: /* We explicitly draw dropdown buttons in HTML content 1px bigger michael@0: * up, right, and bottom so that they overlap the dropdown's border michael@0: * like they're supposed to. michael@0: */ michael@0: if (aWidgetType == NS_THEME_DROPDOWN_BUTTON && michael@0: IsHTMLContent(aFrame) && michael@0: !IsWidgetStyled(aFrame->GetParent()->PresContext(), michael@0: aFrame->GetParent(), michael@0: NS_THEME_DROPDOWN)) michael@0: { michael@0: int32_t p2a = aContext->AppUnitsPerDevPixel(); michael@0: /* Note: no overflow on the left */ michael@0: nsMargin m(p2a, p2a, p2a, 0); michael@0: aOverflowRect->Inflate (m); michael@0: return true; michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: return false; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeWin::GetMinimumWidgetSize(nsRenderingContext* aContext, nsIFrame* aFrame, michael@0: uint8_t aWidgetType, michael@0: nsIntSize* aResult, bool* aIsOverridable) michael@0: { michael@0: (*aResult).width = (*aResult).height = 0; michael@0: *aIsOverridable = true; michael@0: michael@0: HANDLE theme = GetTheme(aWidgetType); michael@0: if (!theme) michael@0: return ClassicGetMinimumWidgetSize(aContext, aFrame, aWidgetType, aResult, aIsOverridable); michael@0: michael@0: switch (aWidgetType) { michael@0: case NS_THEME_GROUPBOX: michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TOOLBOX: michael@0: case NS_THEME_WIN_MEDIA_TOOLBOX: michael@0: case NS_THEME_WIN_COMMUNICATIONS_TOOLBOX: michael@0: case NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX: michael@0: case NS_THEME_TOOLBAR: michael@0: case NS_THEME_STATUSBAR: michael@0: case NS_THEME_PROGRESSBAR_CHUNK: michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: michael@0: case NS_THEME_TAB_PANELS: michael@0: case NS_THEME_TAB_PANEL: michael@0: case NS_THEME_LISTBOX: michael@0: case NS_THEME_TREEVIEW: michael@0: case NS_THEME_MENUITEMTEXT: michael@0: case NS_THEME_WIN_GLASS: michael@0: case NS_THEME_WIN_BORDERLESS_GLASS: michael@0: return NS_OK; // Don't worry about it. michael@0: } michael@0: michael@0: if (aWidgetType == NS_THEME_MENUITEM && IsTopLevelMenu(aFrame)) michael@0: return NS_OK; // Don't worry about it for top level menus michael@0: michael@0: // Call GetSystemMetrics to determine size for WinXP scrollbars michael@0: // (GetThemeSysSize API returns the optimal size for the theme, but michael@0: // Windows appears to always use metrics when drawing standard scrollbars) michael@0: THEMESIZE sizeReq = TS_TRUE; // Best-fit size michael@0: switch (aWidgetType) { michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: case NS_THEME_DROPDOWN_BUTTON: michael@0: return ClassicGetMinimumWidgetSize(aContext, aFrame, aWidgetType, aResult, aIsOverridable); michael@0: michael@0: case NS_THEME_MENUITEM: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: michael@0: if(!IsTopLevelMenu(aFrame)) michael@0: { michael@0: SIZE gutterSize(GetGutterSize(theme, nullptr)); michael@0: aResult->width = gutterSize.cx; michael@0: aResult->height = gutterSize.cy; michael@0: return NS_OK; michael@0: } michael@0: break; michael@0: michael@0: case NS_THEME_MENUIMAGE: michael@0: case NS_THEME_MENUCHECKBOX: michael@0: case NS_THEME_MENURADIO: michael@0: { michael@0: SIZE boxSize(GetGutterSize(theme, nullptr)); michael@0: aResult->width = boxSize.cx+2; michael@0: aResult->height = boxSize.cy; michael@0: *aIsOverridable = false; michael@0: } michael@0: michael@0: case NS_THEME_MENUITEMTEXT: michael@0: return NS_OK; michael@0: michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: // Best-fit size for progress meters is too large for most michael@0: // themes. We want these widgets to be able to really shrink michael@0: // down, so use the min-size request value (of 0). michael@0: sizeReq = TS_MIN; michael@0: break; michael@0: michael@0: case NS_THEME_RESIZER: michael@0: *aIsOverridable = false; michael@0: break; michael@0: michael@0: case NS_THEME_RANGE_THUMB: michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: michael@0: { michael@0: *aIsOverridable = false; michael@0: // on Vista, GetThemePartAndState returns odd values for michael@0: // scale thumbs, so use a hardcoded size instead. michael@0: if (IsVistaOrLater()) { michael@0: if (aWidgetType == NS_THEME_SCALE_THUMB_HORIZONTAL || michael@0: (aWidgetType == NS_THEME_RANGE_THUMB && IsRangeHorizontal(aFrame))) { michael@0: aResult->width = 12; michael@0: aResult->height = 20; michael@0: } michael@0: else { michael@0: aResult->width = 20; michael@0: aResult->height = 12; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case NS_THEME_SCROLLBAR: michael@0: { michael@0: if (nsLookAndFeel::GetInt( michael@0: nsLookAndFeel::eIntID_UseOverlayScrollbars) != 0) { michael@0: aResult->SizeTo(::GetSystemMetrics(SM_CXHSCROLL), michael@0: ::GetSystemMetrics(SM_CYVSCROLL)); michael@0: return NS_OK; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case NS_THEME_TOOLBAR_SEPARATOR: michael@0: // that's 2px left margin, 2px right margin and 2px separator michael@0: // (the margin is drawn as part of the separator, though) michael@0: aResult->width = 6; michael@0: return NS_OK; michael@0: michael@0: case NS_THEME_BUTTON: michael@0: // We should let HTML buttons shrink to their min size. michael@0: // FIXME bug 403934: We should probably really separate michael@0: // GetPreferredWidgetSize from GetMinimumWidgetSize, so callers can michael@0: // use the one they want. michael@0: if (aFrame->GetContent()->IsHTML()) { michael@0: sizeReq = TS_MIN; michael@0: } michael@0: break; michael@0: michael@0: case NS_THEME_WINDOW_BUTTON_MAXIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_RESTORE: michael@0: // The only way to get accurate titlebar button info is to query a michael@0: // window w/buttons when it's visible. nsWindow takes care of this and michael@0: // stores that info in nsUXThemeData. michael@0: aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_RESTORE].cx; michael@0: aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_RESTORE].cy; michael@0: // For XP, subtract 4 from system metrics dimensions. michael@0: if (!IsVistaOrLater()) { michael@0: aResult->width -= 4; michael@0: aResult->height -= 4; michael@0: } michael@0: AddPaddingRect(aResult, CAPTIONBUTTON_RESTORE); michael@0: *aIsOverridable = false; michael@0: return NS_OK; michael@0: michael@0: case NS_THEME_WINDOW_BUTTON_MINIMIZE: michael@0: aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_MINIMIZE].cx; michael@0: aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_MINIMIZE].cy; michael@0: if (!IsVistaOrLater()) { michael@0: aResult->width -= 4; michael@0: aResult->height -= 4; michael@0: } michael@0: AddPaddingRect(aResult, CAPTIONBUTTON_MINIMIZE); michael@0: *aIsOverridable = false; michael@0: return NS_OK; michael@0: michael@0: case NS_THEME_WINDOW_BUTTON_CLOSE: michael@0: aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_CLOSE].cx; michael@0: aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_CLOSE].cy; michael@0: if (!IsVistaOrLater()) { michael@0: aResult->width -= 4; michael@0: aResult->height -= 4; michael@0: } michael@0: AddPaddingRect(aResult, CAPTIONBUTTON_CLOSE); michael@0: *aIsOverridable = false; michael@0: return NS_OK; michael@0: michael@0: case NS_THEME_WINDOW_TITLEBAR: michael@0: case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: michael@0: aResult->height = GetSystemMetrics(SM_CYCAPTION); michael@0: aResult->height += GetSystemMetrics(SM_CYFRAME); michael@0: aResult->height += GetSystemMetrics(SM_CXPADDEDBORDER); michael@0: *aIsOverridable = false; michael@0: return NS_OK; michael@0: michael@0: case NS_THEME_WINDOW_BUTTON_BOX: michael@0: case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: michael@0: if (nsUXThemeData::CheckForCompositor()) { michael@0: aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cx; michael@0: aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy michael@0: - GetSystemMetrics(SM_CYFRAME) michael@0: - GetSystemMetrics(SM_CXPADDEDBORDER); michael@0: if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) { michael@0: aResult->width += 1; michael@0: aResult->height -= 2; michael@0: } michael@0: *aIsOverridable = false; michael@0: return NS_OK; michael@0: } michael@0: break; michael@0: michael@0: case NS_THEME_WINDOW_FRAME_LEFT: michael@0: case NS_THEME_WINDOW_FRAME_RIGHT: michael@0: case NS_THEME_WINDOW_FRAME_BOTTOM: michael@0: aResult->width = GetSystemMetrics(SM_CXFRAME); michael@0: aResult->height = GetSystemMetrics(SM_CYFRAME); michael@0: *aIsOverridable = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: int32_t part, state; michael@0: nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: HDC hdc = ::GetDC(nullptr); michael@0: if (!hdc) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: SIZE sz; michael@0: GetThemePartSize(theme, hdc, part, state, nullptr, sizeReq, &sz); michael@0: aResult->width = sz.cx; michael@0: aResult->height = sz.cy; michael@0: michael@0: switch(aWidgetType) { michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: michael@0: aResult->width++; michael@0: aResult->height = aResult->height / 2 + 1; michael@0: break; michael@0: michael@0: case NS_THEME_MENUSEPARATOR: michael@0: { michael@0: SIZE gutterSize(GetGutterSize(theme, hdc)); michael@0: aResult->width += gutterSize.cx; michael@0: break; michael@0: } michael@0: michael@0: case NS_THEME_MENUARROW: michael@0: { michael@0: // Use the width of the arrow glyph as padding. See the drawing michael@0: // code for details. michael@0: aResult->width *= 2; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: ::ReleaseDC(nullptr, hdc); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeWin::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, michael@0: nsIAtom* aAttribute, bool* aShouldRepaint) michael@0: { michael@0: // Some widget types just never change state. michael@0: if (aWidgetType == NS_THEME_TOOLBOX || michael@0: aWidgetType == NS_THEME_WIN_MEDIA_TOOLBOX || michael@0: aWidgetType == NS_THEME_WIN_COMMUNICATIONS_TOOLBOX || michael@0: aWidgetType == NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX || michael@0: aWidgetType == NS_THEME_TOOLBAR || michael@0: aWidgetType == NS_THEME_STATUSBAR || aWidgetType == NS_THEME_STATUSBAR_PANEL || michael@0: aWidgetType == NS_THEME_STATUSBAR_RESIZER_PANEL || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_CHUNK || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL || michael@0: aWidgetType == NS_THEME_PROGRESSBAR || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL || michael@0: aWidgetType == NS_THEME_TOOLTIP || michael@0: aWidgetType == NS_THEME_TAB_PANELS || michael@0: aWidgetType == NS_THEME_TAB_PANEL || michael@0: aWidgetType == NS_THEME_TOOLBAR_SEPARATOR || michael@0: aWidgetType == NS_THEME_WIN_GLASS || michael@0: aWidgetType == NS_THEME_WIN_BORDERLESS_GLASS) { michael@0: *aShouldRepaint = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (aWidgetType == NS_THEME_WINDOW_TITLEBAR || michael@0: aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED || michael@0: aWidgetType == NS_THEME_WINDOW_FRAME_LEFT || michael@0: aWidgetType == NS_THEME_WINDOW_FRAME_RIGHT || michael@0: aWidgetType == NS_THEME_WINDOW_FRAME_BOTTOM || michael@0: aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE || michael@0: aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE || michael@0: aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE || michael@0: aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { michael@0: *aShouldRepaint = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // On Vista, the scrollbar buttons need to change state when the track has/doesn't have hover michael@0: if (!IsVistaOrLater() && michael@0: (aWidgetType == NS_THEME_SCROLLBAR_TRACK_VERTICAL || michael@0: aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL)) { michael@0: *aShouldRepaint = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // We need to repaint the dropdown arrow in vista HTML combobox controls when michael@0: // the control is closed to get rid of the hover effect. michael@0: if (IsVistaOrLater() && michael@0: (aWidgetType == NS_THEME_DROPDOWN || aWidgetType == NS_THEME_DROPDOWN_BUTTON) && michael@0: IsHTMLContent(aFrame)) michael@0: { michael@0: *aShouldRepaint = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // XXXdwh Not sure what can really be done here. Can at least guess for michael@0: // specific widgets that they're highly unlikely to have certain states. michael@0: // For example, a toolbar doesn't care about any states. michael@0: if (!aAttribute) { michael@0: // Hover/focus/active changed. Always repaint. michael@0: *aShouldRepaint = true; michael@0: } michael@0: else { michael@0: // Check the attribute to see if it's relevant. michael@0: // disabled, checked, dlgtype, default, etc. michael@0: *aShouldRepaint = false; michael@0: if (aAttribute == nsGkAtoms::disabled || michael@0: aAttribute == nsGkAtoms::checked || michael@0: aAttribute == nsGkAtoms::selected || michael@0: aAttribute == nsGkAtoms::readonly || michael@0: aAttribute == nsGkAtoms::open || michael@0: aAttribute == nsGkAtoms::menuactive || michael@0: aAttribute == nsGkAtoms::focused) michael@0: *aShouldRepaint = true; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNativeThemeWin::ThemeChanged() michael@0: { michael@0: nsUXThemeData::Invalidate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeWin::ThemeSupportsWidget(nsPresContext* aPresContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aWidgetType) michael@0: { michael@0: // XXXdwh We can go even further and call the API to ask if support exists for michael@0: // specific widgets. michael@0: michael@0: if (aPresContext && !aPresContext->PresShell()->IsThemeSupportEnabled()) michael@0: return false; michael@0: michael@0: HANDLE theme = nullptr; michael@0: if (aWidgetType == NS_THEME_CHECKBOX_CONTAINER) michael@0: theme = GetTheme(NS_THEME_CHECKBOX); michael@0: else if (aWidgetType == NS_THEME_RADIO_CONTAINER) michael@0: theme = GetTheme(NS_THEME_RADIO); michael@0: else michael@0: theme = GetTheme(aWidgetType); michael@0: michael@0: if ((theme) || (!theme && ClassicThemeSupportsWidget(aPresContext, aFrame, aWidgetType))) michael@0: // turn off theming for some HTML widgets styled by the page michael@0: return (!IsWidgetStyled(aPresContext, aFrame, aWidgetType)); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeWin::WidgetIsContainer(uint8_t aWidgetType) michael@0: { michael@0: // XXXdwh At some point flesh all of this out. michael@0: if (aWidgetType == NS_THEME_DROPDOWN_BUTTON || michael@0: aWidgetType == NS_THEME_RADIO || michael@0: aWidgetType == NS_THEME_CHECKBOX) michael@0: return false; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeWin::ThemeDrawsFocusForWidget(uint8_t aWidgetType) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeWin::ThemeNeedsComboboxDropmarker() michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeWin::WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType) michael@0: { michael@0: switch (aWidgetType) { michael@0: case NS_THEME_WINDOW_TITLEBAR: michael@0: case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: michael@0: case NS_THEME_WINDOW_FRAME_LEFT: michael@0: case NS_THEME_WINDOW_FRAME_RIGHT: michael@0: case NS_THEME_WINDOW_FRAME_BOTTOM: michael@0: case NS_THEME_WINDOW_BUTTON_CLOSE: michael@0: case NS_THEME_WINDOW_BUTTON_MINIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_MAXIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_RESTORE: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeWin::ShouldHideScrollbars() michael@0: { michael@0: return WinUtils::ShouldHideScrollbars(); michael@0: } michael@0: michael@0: nsITheme::Transparency michael@0: nsNativeThemeWin::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType) michael@0: { michael@0: switch (aWidgetType) { michael@0: case NS_THEME_SCROLLBAR_SMALL: michael@0: case NS_THEME_SCROLLBAR: michael@0: case NS_THEME_STATUSBAR: michael@0: // Knowing that scrollbars and statusbars are opaque improves michael@0: // performance, because we create layers for them. This better be michael@0: // true across all Windows themes! If it's not true, we should michael@0: // paint an opaque background for them to make it true! michael@0: return eOpaque; michael@0: case NS_THEME_WIN_GLASS: michael@0: case NS_THEME_WIN_BORDERLESS_GLASS: michael@0: case NS_THEME_SCALE_HORIZONTAL: michael@0: case NS_THEME_SCALE_VERTICAL: michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: case NS_THEME_PROGRESSBAR_CHUNK: michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: michael@0: case NS_THEME_RANGE: michael@0: return eTransparent; michael@0: } michael@0: michael@0: HANDLE theme = GetTheme(aWidgetType); michael@0: // For the classic theme we don't really have a way of knowing michael@0: if (!theme) { michael@0: // menu backgrounds and tooltips which can't be themed are opaque michael@0: if (aWidgetType == NS_THEME_MENUPOPUP || aWidgetType == NS_THEME_TOOLTIP) { michael@0: return eOpaque; michael@0: } michael@0: return eUnknownTransparency; michael@0: } michael@0: michael@0: int32_t part, state; michael@0: nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); michael@0: // Fail conservatively michael@0: NS_ENSURE_SUCCESS(rv, eUnknownTransparency); michael@0: michael@0: if (part <= 0) { michael@0: // Not a real part code, so IsThemeBackgroundPartiallyTransparent may michael@0: // not work, so don't call it. michael@0: return eUnknownTransparency; michael@0: } michael@0: michael@0: if (IsThemeBackgroundPartiallyTransparent(theme, part, state)) michael@0: return eTransparent; michael@0: return eOpaque; michael@0: } michael@0: michael@0: /* Windows 9x/NT/2000/Classic XP Theme Support */ michael@0: michael@0: bool michael@0: nsNativeThemeWin::ClassicThemeSupportsWidget(nsPresContext* aPresContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aWidgetType) michael@0: { michael@0: switch (aWidgetType) { michael@0: case NS_THEME_RESIZER: michael@0: { michael@0: // The classic native resizer has an opaque grey background which doesn't michael@0: // match the usually white background of the scrollable container, so michael@0: // only support the native resizer if not in a scrollframe. michael@0: nsIFrame* parentFrame = aFrame->GetParent(); michael@0: return (!parentFrame || parentFrame->GetType() != nsGkAtoms::scrollFrame); michael@0: } michael@0: case NS_THEME_MENUBAR: michael@0: case NS_THEME_MENUPOPUP: michael@0: // Classic non-flat menus are handled almost entirely through CSS. michael@0: if (!nsUXThemeData::sFlatMenus) michael@0: return false; michael@0: case NS_THEME_BUTTON: michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TEXTFIELD_MULTILINE: michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_RADIO: michael@0: case NS_THEME_RANGE: michael@0: case NS_THEME_RANGE_THUMB: michael@0: case NS_THEME_GROUPBOX: michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_NON_DISAPPEARING: michael@0: case NS_THEME_SCALE_HORIZONTAL: michael@0: case NS_THEME_SCALE_VERTICAL: michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: michael@0: case NS_THEME_DROPDOWN_BUTTON: michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: michael@0: case NS_THEME_LISTBOX: michael@0: case NS_THEME_TREEVIEW: michael@0: case NS_THEME_DROPDOWN_TEXTFIELD: michael@0: case NS_THEME_DROPDOWN: michael@0: case NS_THEME_TOOLTIP: michael@0: case NS_THEME_STATUSBAR: michael@0: case NS_THEME_STATUSBAR_PANEL: michael@0: case NS_THEME_STATUSBAR_RESIZER_PANEL: michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: case NS_THEME_PROGRESSBAR_CHUNK: michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: michael@0: case NS_THEME_TAB: michael@0: case NS_THEME_TAB_PANEL: michael@0: case NS_THEME_TAB_PANELS: michael@0: case NS_THEME_MENUITEM: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: michael@0: case NS_THEME_MENUCHECKBOX: michael@0: case NS_THEME_MENURADIO: michael@0: case NS_THEME_MENUARROW: michael@0: case NS_THEME_MENUSEPARATOR: michael@0: case NS_THEME_MENUITEMTEXT: michael@0: case NS_THEME_WINDOW_TITLEBAR: michael@0: case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: michael@0: case NS_THEME_WINDOW_FRAME_LEFT: michael@0: case NS_THEME_WINDOW_FRAME_RIGHT: michael@0: case NS_THEME_WINDOW_FRAME_BOTTOM: michael@0: case NS_THEME_WINDOW_BUTTON_CLOSE: michael@0: case NS_THEME_WINDOW_BUTTON_MINIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_MAXIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_RESTORE: michael@0: case NS_THEME_WINDOW_BUTTON_BOX: michael@0: case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: nsresult michael@0: nsNativeThemeWin::ClassicGetWidgetBorder(nsDeviceContext* aContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aWidgetType, michael@0: nsIntMargin* aResult) michael@0: { michael@0: switch (aWidgetType) { michael@0: case NS_THEME_GROUPBOX: michael@0: case NS_THEME_BUTTON: michael@0: (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 2; michael@0: break; michael@0: case NS_THEME_STATUSBAR: michael@0: (*aResult).bottom = (*aResult).left = (*aResult).right = 0; michael@0: (*aResult).top = 2; michael@0: break; michael@0: case NS_THEME_LISTBOX: michael@0: case NS_THEME_TREEVIEW: michael@0: case NS_THEME_DROPDOWN: michael@0: case NS_THEME_DROPDOWN_TEXTFIELD: michael@0: case NS_THEME_TAB: michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TEXTFIELD_MULTILINE: michael@0: (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 2; michael@0: break; michael@0: case NS_THEME_STATUSBAR_PANEL: michael@0: case NS_THEME_STATUSBAR_RESIZER_PANEL: { michael@0: (*aResult).top = 1; michael@0: (*aResult).left = 1; michael@0: (*aResult).bottom = 1; michael@0: (*aResult).right = aFrame->GetNextSibling() ? 3 : 1; michael@0: break; michael@0: } michael@0: case NS_THEME_TOOLTIP: michael@0: (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; michael@0: break; michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; michael@0: break; michael@0: case NS_THEME_MENUBAR: michael@0: (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 0; michael@0: break; michael@0: case NS_THEME_MENUPOPUP: michael@0: (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 3; michael@0: break; michael@0: default: michael@0: (*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 0; michael@0: break; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsNativeThemeWin::ClassicGetWidgetPadding(nsDeviceContext* aContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aWidgetType, michael@0: nsIntMargin* aResult) michael@0: { michael@0: switch (aWidgetType) { michael@0: case NS_THEME_MENUITEM: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: { michael@0: int32_t part, state; michael@0: bool focused; michael@0: michael@0: if (NS_FAILED(ClassicGetThemePartAndState(aFrame, aWidgetType, part, state, focused))) michael@0: return false; michael@0: michael@0: if (part == 1) { // top-level menu michael@0: if (nsUXThemeData::sFlatMenus || !(state & DFCS_PUSHED)) { michael@0: (*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 2; michael@0: } michael@0: else { michael@0: // make top-level menus look sunken when pushed in the Classic look michael@0: (*aResult).top = (*aResult).left = 3; michael@0: (*aResult).bottom = (*aResult).right = 1; michael@0: } michael@0: } michael@0: else { michael@0: (*aResult).top = 0; michael@0: (*aResult).bottom = (*aResult).left = (*aResult).right = 2; michael@0: } michael@0: return true; michael@0: } michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsNativeThemeWin::ClassicGetMinimumWidgetSize(nsRenderingContext* aContext, nsIFrame* aFrame, michael@0: uint8_t aWidgetType, michael@0: nsIntSize* aResult, bool* aIsOverridable) michael@0: { michael@0: (*aResult).width = (*aResult).height = 0; michael@0: *aIsOverridable = true; michael@0: switch (aWidgetType) { michael@0: case NS_THEME_RADIO: michael@0: case NS_THEME_CHECKBOX: michael@0: (*aResult).width = (*aResult).height = 13; michael@0: break; michael@0: case NS_THEME_MENUCHECKBOX: michael@0: case NS_THEME_MENURADIO: michael@0: case NS_THEME_MENUARROW: michael@0: (*aResult).width = ::GetSystemMetrics(SM_CXMENUCHECK); michael@0: (*aResult).height = ::GetSystemMetrics(SM_CYMENUCHECK); michael@0: break; michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: michael@0: (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); michael@0: (*aResult).height = 8; // No good metrics available for this michael@0: *aIsOverridable = false; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); michael@0: (*aResult).height = ::GetSystemMetrics(SM_CYVSCROLL); michael@0: *aIsOverridable = false; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: michael@0: (*aResult).width = ::GetSystemMetrics(SM_CXHSCROLL); michael@0: (*aResult).height = ::GetSystemMetrics(SM_CYHSCROLL); michael@0: *aIsOverridable = false; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: // XXX HACK We should be able to have a minimum height for the scrollbar michael@0: // track. However, this causes problems when uncollapsing a scrollbar michael@0: // inside a tree. See bug 201379 for details. michael@0: michael@0: // (*aResult).height = ::GetSystemMetrics(SM_CYVTHUMB) << 1; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_NON_DISAPPEARING: michael@0: { michael@0: aResult->SizeTo(::GetSystemMetrics(SM_CXHSCROLL), michael@0: ::GetSystemMetrics(SM_CYVSCROLL)); michael@0: break; michael@0: } michael@0: case NS_THEME_RANGE_THUMB: { michael@0: if (IsRangeHorizontal(aFrame)) { michael@0: (*aResult).width = 12; michael@0: (*aResult).height = 20; michael@0: } else { michael@0: (*aResult).width = 20; michael@0: (*aResult).height = 12; michael@0: } michael@0: *aIsOverridable = false; michael@0: break; michael@0: } michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: michael@0: (*aResult).width = 12; michael@0: (*aResult).height = 20; michael@0: *aIsOverridable = false; michael@0: break; michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: michael@0: (*aResult).width = 20; michael@0: (*aResult).height = 12; michael@0: *aIsOverridable = false; michael@0: break; michael@0: case NS_THEME_DROPDOWN_BUTTON: michael@0: (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); michael@0: break; michael@0: case NS_THEME_DROPDOWN: michael@0: case NS_THEME_BUTTON: michael@0: case NS_THEME_GROUPBOX: michael@0: case NS_THEME_LISTBOX: michael@0: case NS_THEME_TREEVIEW: michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TEXTFIELD_MULTILINE: michael@0: case NS_THEME_DROPDOWN_TEXTFIELD: michael@0: case NS_THEME_STATUSBAR: michael@0: case NS_THEME_STATUSBAR_PANEL: michael@0: case NS_THEME_STATUSBAR_RESIZER_PANEL: michael@0: case NS_THEME_PROGRESSBAR_CHUNK: michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: michael@0: case NS_THEME_TOOLTIP: michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: case NS_THEME_TAB: michael@0: case NS_THEME_TAB_PANEL: michael@0: case NS_THEME_TAB_PANELS: michael@0: // no minimum widget size michael@0: break; michael@0: case NS_THEME_RESIZER: { michael@0: NONCLIENTMETRICS nc; michael@0: nc.cbSize = sizeof(nc); michael@0: if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nc), &nc, 0)) michael@0: (*aResult).width = (*aResult).height = abs(nc.lfStatusFont.lfHeight) + 4; michael@0: else michael@0: (*aResult).width = (*aResult).height = 15; michael@0: *aIsOverridable = false; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); michael@0: (*aResult).height = ::GetSystemMetrics(SM_CYVTHUMB); michael@0: // Without theming, divide the thumb size by two in order to look more michael@0: // native michael@0: if (!GetTheme(aWidgetType)) michael@0: (*aResult).height >>= 1; michael@0: *aIsOverridable = false; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: (*aResult).width = ::GetSystemMetrics(SM_CXHTHUMB); michael@0: (*aResult).height = ::GetSystemMetrics(SM_CYHSCROLL); michael@0: // Without theming, divide the thumb size by two in order to look more michael@0: // native michael@0: if (!GetTheme(aWidgetType)) michael@0: (*aResult).width >>= 1; michael@0: *aIsOverridable = false; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: (*aResult).width = ::GetSystemMetrics(SM_CXHTHUMB) << 1; michael@0: break; michael@0: } michael@0: case NS_THEME_MENUSEPARATOR: michael@0: { michael@0: aResult->width = 0; michael@0: aResult->height = 10; michael@0: break; michael@0: } michael@0: michael@0: case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: michael@0: case NS_THEME_WINDOW_TITLEBAR: michael@0: aResult->height = GetSystemMetrics(SM_CYCAPTION); michael@0: aResult->height += GetSystemMetrics(SM_CYFRAME); michael@0: aResult->width = 0; michael@0: break; michael@0: case NS_THEME_WINDOW_FRAME_LEFT: michael@0: case NS_THEME_WINDOW_FRAME_RIGHT: michael@0: aResult->width = GetSystemMetrics(SM_CXFRAME); michael@0: aResult->height = 0; michael@0: break; michael@0: michael@0: case NS_THEME_WINDOW_FRAME_BOTTOM: michael@0: aResult->height = GetSystemMetrics(SM_CYFRAME); michael@0: aResult->width = 0; michael@0: break; michael@0: michael@0: case NS_THEME_WINDOW_BUTTON_CLOSE: michael@0: case NS_THEME_WINDOW_BUTTON_MINIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_MAXIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_RESTORE: michael@0: aResult->width = GetSystemMetrics(SM_CXSIZE); michael@0: aResult->height = GetSystemMetrics(SM_CYSIZE); michael@0: // XXX I have no idea why these caption metrics are always off, michael@0: // but they are. michael@0: aResult->width -= 2; michael@0: aResult->height -= 4; michael@0: if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) { michael@0: AddPaddingRect(aResult, CAPTIONBUTTON_MINIMIZE); michael@0: } michael@0: else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE || michael@0: aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { michael@0: AddPaddingRect(aResult, CAPTIONBUTTON_RESTORE); michael@0: } michael@0: else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) { michael@0: AddPaddingRect(aResult, CAPTIONBUTTON_CLOSE); michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType, michael@0: int32_t& aPart, int32_t& aState, bool& aFocused) michael@0: { michael@0: aFocused = false; michael@0: switch (aWidgetType) { michael@0: case NS_THEME_BUTTON: { michael@0: EventStates contentState; michael@0: michael@0: aPart = DFC_BUTTON; michael@0: aState = DFCS_BUTTONPUSH; michael@0: aFocused = false; michael@0: michael@0: contentState = GetContentState(aFrame, aWidgetType); michael@0: if (IsDisabled(aFrame, contentState)) michael@0: aState |= DFCS_INACTIVE; michael@0: else if (IsOpenButton(aFrame)) michael@0: aState |= DFCS_PUSHED; michael@0: else if (IsCheckedButton(aFrame)) michael@0: aState |= DFCS_CHECKED; michael@0: else { michael@0: if (contentState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)) { michael@0: aState |= DFCS_PUSHED; michael@0: const nsStyleUserInterface *uiData = aFrame->StyleUserInterface(); michael@0: // The down state is flat if the button is focusable michael@0: if (uiData->mUserFocus == NS_STYLE_USER_FOCUS_NORMAL) { michael@0: if (!aFrame->GetContent()->IsHTML()) michael@0: aState |= DFCS_FLAT; michael@0: michael@0: aFocused = true; michael@0: } michael@0: } michael@0: if (contentState.HasState(NS_EVENT_STATE_FOCUS) || michael@0: (aState == DFCS_BUTTONPUSH && IsDefaultButton(aFrame))) { michael@0: aFocused = true; michael@0: } michael@0: michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_RADIO: { michael@0: EventStates contentState; michael@0: aFocused = false; michael@0: michael@0: aPart = DFC_BUTTON; michael@0: aState = 0; michael@0: nsIContent* content = aFrame->GetContent(); michael@0: bool isCheckbox = (aWidgetType == NS_THEME_CHECKBOX); michael@0: bool isChecked = GetCheckedOrSelected(aFrame, !isCheckbox); michael@0: bool isIndeterminate = isCheckbox && GetIndeterminate(aFrame); michael@0: michael@0: if (isCheckbox) { michael@0: // indeterminate state takes precedence over checkedness. michael@0: if (isIndeterminate) { michael@0: aState = DFCS_BUTTON3STATE | DFCS_CHECKED; michael@0: } else { michael@0: aState = DFCS_BUTTONCHECK; michael@0: } michael@0: } else { michael@0: aState = DFCS_BUTTONRADIO; michael@0: } michael@0: if (isChecked) { michael@0: aState |= DFCS_CHECKED; michael@0: } michael@0: michael@0: contentState = GetContentState(aFrame, aWidgetType); michael@0: if (!content->IsXUL() && michael@0: contentState.HasState(NS_EVENT_STATE_FOCUS)) { michael@0: aFocused = true; michael@0: } michael@0: michael@0: if (IsDisabled(aFrame, contentState)) { michael@0: aState |= DFCS_INACTIVE; michael@0: } else if (contentState.HasAllStates(NS_EVENT_STATE_ACTIVE | michael@0: NS_EVENT_STATE_HOVER)) { michael@0: aState |= DFCS_PUSHED; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_MENUITEM: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: { michael@0: bool isTopLevel = false; michael@0: bool isOpen = false; michael@0: bool isContainer = false; michael@0: nsMenuFrame *menuFrame = do_QueryFrame(aFrame); michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: // We indicate top-level-ness using aPart. 0 is a normal menu item, michael@0: // 1 is a top-level menu item. The state of the item is composed of michael@0: // DFCS_* flags only. michael@0: aPart = 0; michael@0: aState = 0; michael@0: michael@0: if (menuFrame) { michael@0: // If this is a real menu item, we should check if it is part of the michael@0: // main menu bar or not, and if it is a container, as these affect michael@0: // rendering. michael@0: isTopLevel = menuFrame->IsOnMenuBar(); michael@0: isOpen = menuFrame->IsOpen(); michael@0: isContainer = menuFrame->IsMenu(); michael@0: } michael@0: michael@0: if (IsDisabled(aFrame, eventState)) michael@0: aState |= DFCS_INACTIVE; michael@0: michael@0: if (isTopLevel) { michael@0: aPart = 1; michael@0: if (isOpen) michael@0: aState |= DFCS_PUSHED; michael@0: } michael@0: michael@0: if (IsMenuActive(aFrame, aWidgetType)) michael@0: aState |= DFCS_HOT; michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_MENUCHECKBOX: michael@0: case NS_THEME_MENURADIO: michael@0: case NS_THEME_MENUARROW: { michael@0: aState = 0; michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: if (IsDisabled(aFrame, eventState)) michael@0: aState |= DFCS_INACTIVE; michael@0: if (IsMenuActive(aFrame, aWidgetType)) michael@0: aState |= DFCS_HOT; michael@0: michael@0: if (aWidgetType == NS_THEME_MENUCHECKBOX || aWidgetType == NS_THEME_MENURADIO) { michael@0: if (IsCheckedButton(aFrame)) michael@0: aState |= DFCS_CHECKED; michael@0: } else if (IsFrameRTL(aFrame)) { michael@0: aState |= DFCS_RTL; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_LISTBOX: michael@0: case NS_THEME_TREEVIEW: michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TEXTFIELD_MULTILINE: michael@0: case NS_THEME_DROPDOWN: michael@0: case NS_THEME_DROPDOWN_TEXTFIELD: michael@0: case NS_THEME_RANGE: michael@0: case NS_THEME_RANGE_THUMB: michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case NS_THEME_SCALE_HORIZONTAL: michael@0: case NS_THEME_SCALE_VERTICAL: michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: michael@0: case NS_THEME_STATUSBAR: michael@0: case NS_THEME_STATUSBAR_PANEL: michael@0: case NS_THEME_STATUSBAR_RESIZER_PANEL: michael@0: case NS_THEME_PROGRESSBAR_CHUNK: michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: michael@0: case NS_THEME_TOOLTIP: michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: case NS_THEME_TAB: michael@0: case NS_THEME_TAB_PANEL: michael@0: case NS_THEME_TAB_PANELS: michael@0: case NS_THEME_MENUBAR: michael@0: case NS_THEME_MENUPOPUP: michael@0: case NS_THEME_GROUPBOX: michael@0: // these don't use DrawFrameControl michael@0: return NS_OK; michael@0: case NS_THEME_DROPDOWN_BUTTON: { michael@0: michael@0: aPart = DFC_SCROLL; michael@0: aState = DFCS_SCROLLCOMBOBOX; michael@0: michael@0: nsIFrame* parentFrame = aFrame->GetParent(); michael@0: bool isHTML = IsHTMLContent(aFrame); michael@0: bool isMenulist = !isHTML && parentFrame->GetType() == nsGkAtoms::menuFrame; michael@0: bool isOpen = false; michael@0: michael@0: // HTML select and XUL menulist dropdown buttons get state from the parent. michael@0: if (isHTML || isMenulist) michael@0: aFrame = parentFrame; michael@0: michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: if (IsDisabled(aFrame, eventState)) { michael@0: aState |= DFCS_INACTIVE; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (isHTML) { michael@0: nsIComboboxControlFrame* ccf = do_QueryFrame(aFrame); michael@0: isOpen = (ccf && ccf->IsDroppedDown()); michael@0: } michael@0: else michael@0: isOpen = IsOpenButton(aFrame); michael@0: michael@0: // XXX Button should look active until the mouse is released, but michael@0: // without making it look active when the popup is clicked. michael@0: if (isOpen && (isHTML || isMenulist)) michael@0: return NS_OK; michael@0: michael@0: // Dropdown button active state doesn't need :hover. michael@0: if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) michael@0: aState |= DFCS_PUSHED | DFCS_FLAT; michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: { michael@0: EventStates contentState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: aPart = DFC_SCROLL; michael@0: switch (aWidgetType) { michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: aState = DFCS_SCROLLUP; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: aState = DFCS_SCROLLDOWN; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: aState = DFCS_SCROLLLEFT; michael@0: break; michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: michael@0: aState = DFCS_SCROLLRIGHT; michael@0: break; michael@0: } michael@0: michael@0: if (IsDisabled(aFrame, contentState)) michael@0: aState |= DFCS_INACTIVE; michael@0: else { michael@0: if (contentState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) michael@0: aState |= DFCS_PUSHED | DFCS_FLAT; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: { michael@0: EventStates contentState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: aPart = DFC_SCROLL; michael@0: switch (aWidgetType) { michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: aState = DFCS_SCROLLUP; michael@0: break; michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: michael@0: aState = DFCS_SCROLLDOWN; michael@0: break; michael@0: } michael@0: michael@0: if (IsDisabled(aFrame, contentState)) michael@0: aState |= DFCS_INACTIVE; michael@0: else { michael@0: if (contentState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) michael@0: aState |= DFCS_PUSHED; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: case NS_THEME_RESIZER: michael@0: aPart = DFC_SCROLL; michael@0: aState = (IsFrameRTL(aFrame)) ? michael@0: DFCS_SCROLLSIZEGRIPRIGHT : DFCS_SCROLLSIZEGRIP; michael@0: return NS_OK; michael@0: case NS_THEME_MENUSEPARATOR: michael@0: aPart = 0; michael@0: aState = 0; michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_TITLEBAR: michael@0: aPart = mozilla::widget::themeconst::WP_CAPTION; michael@0: aState = GetTopLevelWindowActiveState(aFrame); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: michael@0: aPart = mozilla::widget::themeconst::WP_MAXCAPTION; michael@0: aState = GetTopLevelWindowActiveState(aFrame); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_FRAME_LEFT: michael@0: aPart = mozilla::widget::themeconst::WP_FRAMELEFT; michael@0: aState = GetTopLevelWindowActiveState(aFrame); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_FRAME_RIGHT: michael@0: aPart = mozilla::widget::themeconst::WP_FRAMERIGHT; michael@0: aState = GetTopLevelWindowActiveState(aFrame); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_FRAME_BOTTOM: michael@0: aPart = mozilla::widget::themeconst::WP_FRAMEBOTTOM; michael@0: aState = GetTopLevelWindowActiveState(aFrame); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_BUTTON_CLOSE: michael@0: aPart = DFC_CAPTION; michael@0: aState = DFCS_CAPTIONCLOSE | michael@0: GetClassicWindowFrameButtonState(GetContentState(aFrame, michael@0: aWidgetType)); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_BUTTON_MINIMIZE: michael@0: aPart = DFC_CAPTION; michael@0: aState = DFCS_CAPTIONMIN | michael@0: GetClassicWindowFrameButtonState(GetContentState(aFrame, michael@0: aWidgetType)); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_BUTTON_MAXIMIZE: michael@0: aPart = DFC_CAPTION; michael@0: aState = DFCS_CAPTIONMAX | michael@0: GetClassicWindowFrameButtonState(GetContentState(aFrame, michael@0: aWidgetType)); michael@0: return NS_OK; michael@0: case NS_THEME_WINDOW_BUTTON_RESTORE: michael@0: aPart = DFC_CAPTION; michael@0: aState = DFCS_CAPTIONRESTORE | michael@0: GetClassicWindowFrameButtonState(GetContentState(aFrame, michael@0: aWidgetType)); michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Draw classic Windows tab michael@0: // (no system API for this, but DrawEdge can draw all the parts of a tab) michael@0: static void DrawTab(HDC hdc, const RECT& R, int32_t aPosition, bool aSelected, michael@0: bool aDrawLeft, bool aDrawRight) michael@0: { michael@0: int32_t leftFlag, topFlag, rightFlag, lightFlag, shadeFlag; michael@0: RECT topRect, sideRect, bottomRect, lightRect, shadeRect; michael@0: int32_t selectedOffset, lOffset, rOffset; michael@0: michael@0: selectedOffset = aSelected ? 1 : 0; michael@0: lOffset = aDrawLeft ? 2 : 0; michael@0: rOffset = aDrawRight ? 2 : 0; michael@0: michael@0: // Get info for tab orientation/position (Left, Top, Right, Bottom) michael@0: switch (aPosition) { michael@0: case BF_LEFT: michael@0: leftFlag = BF_TOP; topFlag = BF_LEFT; michael@0: rightFlag = BF_BOTTOM; michael@0: lightFlag = BF_DIAGONAL_ENDTOPRIGHT; michael@0: shadeFlag = BF_DIAGONAL_ENDBOTTOMRIGHT; michael@0: michael@0: ::SetRect(&topRect, R.left, R.top+lOffset, R.right, R.bottom-rOffset); michael@0: ::SetRect(&sideRect, R.left+2, R.top, R.right-2+selectedOffset, R.bottom); michael@0: ::SetRect(&bottomRect, R.right-2, R.top, R.right, R.bottom); michael@0: ::SetRect(&lightRect, R.left, R.top, R.left+3, R.top+3); michael@0: ::SetRect(&shadeRect, R.left+1, R.bottom-2, R.left+2, R.bottom-1); michael@0: break; michael@0: case BF_TOP: michael@0: leftFlag = BF_LEFT; topFlag = BF_TOP; michael@0: rightFlag = BF_RIGHT; michael@0: lightFlag = BF_DIAGONAL_ENDTOPRIGHT; michael@0: shadeFlag = BF_DIAGONAL_ENDBOTTOMRIGHT; michael@0: michael@0: ::SetRect(&topRect, R.left+lOffset, R.top, R.right-rOffset, R.bottom); michael@0: ::SetRect(&sideRect, R.left, R.top+2, R.right, R.bottom-1+selectedOffset); michael@0: ::SetRect(&bottomRect, R.left, R.bottom-1, R.right, R.bottom); michael@0: ::SetRect(&lightRect, R.left, R.top, R.left+3, R.top+3); michael@0: ::SetRect(&shadeRect, R.right-2, R.top+1, R.right-1, R.top+2); michael@0: break; michael@0: case BF_RIGHT: michael@0: leftFlag = BF_TOP; topFlag = BF_RIGHT; michael@0: rightFlag = BF_BOTTOM; michael@0: lightFlag = BF_DIAGONAL_ENDTOPLEFT; michael@0: shadeFlag = BF_DIAGONAL_ENDBOTTOMLEFT; michael@0: michael@0: ::SetRect(&topRect, R.left, R.top+lOffset, R.right, R.bottom-rOffset); michael@0: ::SetRect(&sideRect, R.left+2-selectedOffset, R.top, R.right-2, R.bottom); michael@0: ::SetRect(&bottomRect, R.left, R.top, R.left+2, R.bottom); michael@0: ::SetRect(&lightRect, R.right-3, R.top, R.right-1, R.top+2); michael@0: ::SetRect(&shadeRect, R.right-2, R.bottom-3, R.right, R.bottom-1); michael@0: break; michael@0: case BF_BOTTOM: michael@0: leftFlag = BF_LEFT; topFlag = BF_BOTTOM; michael@0: rightFlag = BF_RIGHT; michael@0: lightFlag = BF_DIAGONAL_ENDTOPLEFT; michael@0: shadeFlag = BF_DIAGONAL_ENDBOTTOMLEFT; michael@0: michael@0: ::SetRect(&topRect, R.left+lOffset, R.top, R.right-rOffset, R.bottom); michael@0: ::SetRect(&sideRect, R.left, R.top+2-selectedOffset, R.right, R.bottom-2); michael@0: ::SetRect(&bottomRect, R.left, R.top, R.right, R.top+2); michael@0: ::SetRect(&lightRect, R.left, R.bottom-3, R.left+2, R.bottom-1); michael@0: ::SetRect(&shadeRect, R.right-2, R.bottom-3, R.right, R.bottom-1); michael@0: break; michael@0: } michael@0: michael@0: // Background michael@0: ::FillRect(hdc, &R, (HBRUSH) (COLOR_3DFACE+1) ); michael@0: michael@0: // Tab "Top" michael@0: ::DrawEdge(hdc, &topRect, EDGE_RAISED, BF_SOFT | topFlag); michael@0: michael@0: // Tab "Bottom" michael@0: if (!aSelected) michael@0: ::DrawEdge(hdc, &bottomRect, EDGE_RAISED, BF_SOFT | topFlag); michael@0: michael@0: // Tab "Sides" michael@0: if (!aDrawLeft) michael@0: leftFlag = 0; michael@0: if (!aDrawRight) michael@0: rightFlag = 0; michael@0: ::DrawEdge(hdc, &sideRect, EDGE_RAISED, BF_SOFT | leftFlag | rightFlag); michael@0: michael@0: // Tab Diagonal Corners michael@0: if (aDrawLeft) michael@0: ::DrawEdge(hdc, &lightRect, EDGE_RAISED, BF_SOFT | lightFlag); michael@0: michael@0: if (aDrawRight) michael@0: ::DrawEdge(hdc, &shadeRect, EDGE_RAISED, BF_SOFT | shadeFlag); michael@0: } michael@0: michael@0: static void DrawMenuImage(HDC hdc, const RECT& rc, int32_t aComponent, uint32_t aColor) michael@0: { michael@0: // This procedure creates a memory bitmap to contain the check mark, draws michael@0: // it into the bitmap (it is a mask image), then composes it onto the menu michael@0: // item in appropriate colors. michael@0: HDC hMemoryDC = ::CreateCompatibleDC(hdc); michael@0: if (hMemoryDC) { michael@0: // XXXjgr We should ideally be caching these, but we wont be notified when michael@0: // they change currently, so we can't do so easily. Same for the bitmap. michael@0: int checkW = ::GetSystemMetrics(SM_CXMENUCHECK); michael@0: int checkH = ::GetSystemMetrics(SM_CYMENUCHECK); michael@0: michael@0: HBITMAP hMonoBitmap = ::CreateBitmap(checkW, checkH, 1, 1, nullptr); michael@0: if (hMonoBitmap) { michael@0: michael@0: HBITMAP hPrevBitmap = (HBITMAP) ::SelectObject(hMemoryDC, hMonoBitmap); michael@0: if (hPrevBitmap) { michael@0: michael@0: // XXXjgr This will go pear-shaped if the image is bigger than the michael@0: // provided rect. What should we do? michael@0: RECT imgRect = { 0, 0, checkW, checkH }; michael@0: POINT imgPos = { michael@0: rc.left + (rc.right - rc.left - checkW) / 2, michael@0: rc.top + (rc.bottom - rc.top - checkH) / 2 michael@0: }; michael@0: michael@0: // XXXzeniko Windows renders these 1px lower than you'd expect michael@0: if (aComponent == DFCS_MENUCHECK || aComponent == DFCS_MENUBULLET) michael@0: imgPos.y++; michael@0: michael@0: ::DrawFrameControl(hMemoryDC, &imgRect, DFC_MENU, aComponent); michael@0: COLORREF oldTextCol = ::SetTextColor(hdc, 0x00000000); michael@0: COLORREF oldBackCol = ::SetBkColor(hdc, 0x00FFFFFF); michael@0: ::BitBlt(hdc, imgPos.x, imgPos.y, checkW, checkH, hMemoryDC, 0, 0, SRCAND); michael@0: ::SetTextColor(hdc, ::GetSysColor(aColor)); michael@0: ::SetBkColor(hdc, 0x00000000); michael@0: ::BitBlt(hdc, imgPos.x, imgPos.y, checkW, checkH, hMemoryDC, 0, 0, SRCPAINT); michael@0: ::SetTextColor(hdc, oldTextCol); michael@0: ::SetBkColor(hdc, oldBackCol); michael@0: ::SelectObject(hMemoryDC, hPrevBitmap); michael@0: } michael@0: ::DeleteObject(hMonoBitmap); michael@0: } michael@0: ::DeleteDC(hMemoryDC); michael@0: } michael@0: } michael@0: michael@0: void nsNativeThemeWin::DrawCheckedRect(HDC hdc, const RECT& rc, int32_t fore, int32_t back, michael@0: HBRUSH defaultBack) michael@0: { michael@0: static WORD patBits[8] = { michael@0: 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 michael@0: }; michael@0: michael@0: HBITMAP patBmp = ::CreateBitmap(8, 8, 1, 1, patBits); michael@0: if (patBmp) { michael@0: HBRUSH brush = (HBRUSH) ::CreatePatternBrush(patBmp); michael@0: if (brush) { michael@0: COLORREF oldForeColor = ::SetTextColor(hdc, ::GetSysColor(fore)); michael@0: COLORREF oldBackColor = ::SetBkColor(hdc, ::GetSysColor(back)); michael@0: POINT vpOrg; michael@0: michael@0: ::UnrealizeObject(brush); michael@0: ::GetViewportOrgEx(hdc, &vpOrg); michael@0: ::SetBrushOrgEx(hdc, vpOrg.x + rc.left, vpOrg.y + rc.top, nullptr); michael@0: HBRUSH oldBrush = (HBRUSH) ::SelectObject(hdc, brush); michael@0: ::FillRect(hdc, &rc, brush); michael@0: ::SetTextColor(hdc, oldForeColor); michael@0: ::SetBkColor(hdc, oldBackColor); michael@0: ::SelectObject(hdc, oldBrush); michael@0: ::DeleteObject(brush); michael@0: } michael@0: else michael@0: ::FillRect(hdc, &rc, defaultBack); michael@0: michael@0: ::DeleteObject(patBmp); michael@0: } michael@0: } michael@0: michael@0: nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(nsRenderingContext* aContext, michael@0: nsIFrame* aFrame, michael@0: uint8_t aWidgetType, michael@0: const nsRect& aRect, michael@0: const nsRect& aDirtyRect) michael@0: { michael@0: int32_t part, state; michael@0: bool focused; michael@0: nsresult rv; michael@0: rv = ClassicGetThemePartAndState(aFrame, aWidgetType, part, state, focused); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (AssumeThemePartAndStateAreTransparent(part, state)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: gfxFloat p2a = gfxFloat(aContext->AppUnitsPerDevPixel()); michael@0: RECT widgetRect; michael@0: gfxRect tr(aRect.x, aRect.y, aRect.width, aRect.height), michael@0: dr(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); michael@0: michael@0: tr.ScaleInverse(p2a); michael@0: dr.ScaleInverse(p2a); michael@0: michael@0: nsRefPtr ctx = aContext->ThebesContext(); michael@0: michael@0: gfxWindowsNativeDrawing nativeDrawing(ctx, dr, GetWidgetNativeDrawingFlags(aWidgetType)); michael@0: michael@0: RENDER_AGAIN: michael@0: michael@0: HDC hdc = nativeDrawing.BeginNativeDrawing(); michael@0: if (!hdc) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nativeDrawing.TransformToNativeRect(tr, widgetRect); michael@0: michael@0: rv = NS_OK; michael@0: switch (aWidgetType) { michael@0: // Draw button michael@0: case NS_THEME_BUTTON: { michael@0: if (focused) { michael@0: // draw dark button focus border first michael@0: HBRUSH brush; michael@0: brush = ::GetSysColorBrush(COLOR_3DDKSHADOW); michael@0: if (brush) michael@0: ::FrameRect(hdc, &widgetRect, brush); michael@0: InflateRect(&widgetRect, -1, -1); michael@0: } michael@0: // fall-through... michael@0: } michael@0: // Draw controls supported by DrawFrameControl michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_RADIO: michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: michael@0: case NS_THEME_DROPDOWN_BUTTON: michael@0: case NS_THEME_RESIZER: { michael@0: int32_t oldTA; michael@0: // setup DC to make DrawFrameControl draw correctly michael@0: oldTA = ::SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); michael@0: ::DrawFrameControl(hdc, &widgetRect, part, state); michael@0: ::SetTextAlign(hdc, oldTA); michael@0: michael@0: // Draw focus rectangles for HTML checkboxes and radio buttons michael@0: // XXX it'd be nice to draw these outside of the frame michael@0: if (focused && (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO)) { michael@0: // setup DC to make DrawFocusRect draw correctly michael@0: POINT vpOrg; michael@0: ::GetViewportOrgEx(hdc, &vpOrg); michael@0: ::SetBrushOrgEx(hdc, vpOrg.x + widgetRect.left, vpOrg.y + widgetRect.top, nullptr); michael@0: int32_t oldColor; michael@0: oldColor = ::SetTextColor(hdc, 0); michael@0: // draw focus rectangle michael@0: ::DrawFocusRect(hdc, &widgetRect); michael@0: ::SetTextColor(hdc, oldColor); michael@0: } michael@0: break; michael@0: } michael@0: // Draw controls with 2px 3D inset border michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TEXTFIELD_MULTILINE: michael@0: case NS_THEME_LISTBOX: michael@0: case NS_THEME_DROPDOWN: michael@0: case NS_THEME_DROPDOWN_TEXTFIELD: { michael@0: // Draw inset edge michael@0: ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: // Fill in background michael@0: if (IsDisabled(aFrame, eventState) || michael@0: (aFrame->GetContent()->IsXUL() && michael@0: IsReadOnly(aFrame))) michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_BTNFACE+1)); michael@0: else michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_WINDOW+1)); michael@0: michael@0: break; michael@0: } michael@0: case NS_THEME_TREEVIEW: { michael@0: // Draw inset edge michael@0: ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); michael@0: michael@0: // Fill in window color background michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_WINDOW+1)); michael@0: michael@0: break; michael@0: } michael@0: // Draw ToolTip background michael@0: case NS_THEME_TOOLTIP: michael@0: ::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_WINDOWFRAME)); michael@0: InflateRect(&widgetRect, -1, -1); michael@0: ::FillRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_INFOBK)); michael@0: michael@0: break; michael@0: case NS_THEME_GROUPBOX: michael@0: ::DrawEdge(hdc, &widgetRect, EDGE_ETCHED, BF_RECT | BF_ADJUST); michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_BTNFACE+1)); michael@0: break; michael@0: // Draw 3D face background controls michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: // Draw 3D border michael@0: ::DrawEdge(hdc, &widgetRect, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); michael@0: InflateRect(&widgetRect, -1, -1); michael@0: // fall through michael@0: case NS_THEME_TAB_PANEL: michael@0: case NS_THEME_STATUSBAR: michael@0: case NS_THEME_STATUSBAR_RESIZER_PANEL: { michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_BTNFACE+1)); michael@0: michael@0: break; michael@0: } michael@0: // Draw 3D inset statusbar panel michael@0: case NS_THEME_STATUSBAR_PANEL: { michael@0: if (aFrame->GetNextSibling()) michael@0: widgetRect.right -= 2; // space between sibling status panels michael@0: michael@0: ::DrawEdge(hdc, &widgetRect, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); michael@0: michael@0: break; michael@0: } michael@0: // Draw scrollbar thumb michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_MIDDLE); michael@0: michael@0: break; michael@0: case NS_THEME_RANGE_THUMB: michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: { michael@0: EventStates eventState = GetContentState(aFrame, aWidgetType); michael@0: michael@0: ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST); michael@0: if (IsDisabled(aFrame, eventState)) { michael@0: DrawCheckedRect(hdc, widgetRect, COLOR_3DFACE, COLOR_3DHILIGHT, michael@0: (HBRUSH) COLOR_3DHILIGHT); michael@0: } michael@0: michael@0: break; michael@0: } michael@0: // Draw scrollbar track background michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: { michael@0: michael@0: // Windows fills in the scrollbar track differently michael@0: // depending on whether these are equal michael@0: DWORD color3D, colorScrollbar, colorWindow; michael@0: michael@0: color3D = ::GetSysColor(COLOR_3DFACE); michael@0: colorWindow = ::GetSysColor(COLOR_WINDOW); michael@0: colorScrollbar = ::GetSysColor(COLOR_SCROLLBAR); michael@0: michael@0: if ((color3D != colorScrollbar) && (colorWindow != colorScrollbar)) michael@0: // Use solid brush michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_SCROLLBAR+1)); michael@0: else michael@0: { michael@0: DrawCheckedRect(hdc, widgetRect, COLOR_3DHILIGHT, COLOR_3DFACE, michael@0: (HBRUSH) COLOR_SCROLLBAR+1); michael@0: } michael@0: // XXX should invert the part of the track being clicked here michael@0: // but the track is never :active michael@0: michael@0: break; michael@0: } michael@0: // Draw scale track background michael@0: case NS_THEME_RANGE: michael@0: case NS_THEME_SCALE_VERTICAL: michael@0: case NS_THEME_SCALE_HORIZONTAL: { michael@0: const int32_t trackWidth = 4; michael@0: // When rounding is necessary, we round the position of the track michael@0: // away from the chevron of the thumb to make it look better. michael@0: if (aWidgetType == NS_THEME_SCALE_HORIZONTAL || michael@0: (aWidgetType == NS_THEME_RANGE && IsRangeHorizontal(aFrame))) { michael@0: widgetRect.top += (widgetRect.bottom - widgetRect.top - trackWidth) / 2; michael@0: widgetRect.bottom = widgetRect.top + trackWidth; michael@0: } michael@0: else { michael@0: if (!IsFrameRTL(aFrame)) { michael@0: widgetRect.left += (widgetRect.right - widgetRect.left - trackWidth) / 2; michael@0: widgetRect.right = widgetRect.left + trackWidth; michael@0: } else { michael@0: widgetRect.right -= (widgetRect.right - widgetRect.left - trackWidth) / 2; michael@0: widgetRect.left = widgetRect.right - trackWidth; michael@0: } michael@0: } michael@0: michael@0: ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) GetStockObject(GRAY_BRUSH)); michael@0: michael@0: break; michael@0: } michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); michael@0: break; michael@0: michael@0: case NS_THEME_PROGRESSBAR_CHUNK: { michael@0: nsIFrame* stateFrame = aFrame->GetParent(); michael@0: EventStates eventStates = GetContentState(stateFrame, aWidgetType); michael@0: michael@0: bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates); michael@0: bool vertical = IsVerticalProgress(stateFrame) || michael@0: aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL; michael@0: int32_t overlayPart = GetProgressOverlayStyle(vertical); michael@0: michael@0: nsIContent* content = aFrame->GetContent(); michael@0: if (!indeterminate || !content) { michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); michael@0: break; michael@0: } michael@0: michael@0: RECT overlayRect = michael@0: CalculateProgressOverlayRect(aFrame, &widgetRect, vertical, michael@0: indeterminate, true); michael@0: michael@0: ::FillRect(hdc, &overlayRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); michael@0: michael@0: if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) { michael@0: NS_WARNING("unable to animate progress widget!"); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: // Draw Tab michael@0: case NS_THEME_TAB: { michael@0: DrawTab(hdc, widgetRect, michael@0: IsBottomTab(aFrame) ? BF_BOTTOM : BF_TOP, michael@0: IsSelectedTab(aFrame), michael@0: !IsRightToSelectedTab(aFrame), michael@0: !IsLeftToSelectedTab(aFrame)); michael@0: michael@0: break; michael@0: } michael@0: case NS_THEME_TAB_PANELS: michael@0: ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_SOFT | BF_MIDDLE | michael@0: BF_LEFT | BF_RIGHT | BF_BOTTOM); michael@0: michael@0: break; michael@0: case NS_THEME_MENUBAR: michael@0: break; michael@0: case NS_THEME_MENUPOPUP: michael@0: NS_ASSERTION(nsUXThemeData::sFlatMenus, "Classic menus are styled entirely through CSS"); michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_MENU+1)); michael@0: ::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_BTNSHADOW)); michael@0: break; michael@0: case NS_THEME_MENUITEM: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: michael@0: // part == 0 for normal items michael@0: // part == 1 for top-level menu items michael@0: if (nsUXThemeData::sFlatMenus) { michael@0: // Not disabled and hot/pushed. michael@0: if ((state & (DFCS_HOT | DFCS_PUSHED)) != 0) { michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_MENUHILIGHT+1)); michael@0: ::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_HIGHLIGHT)); michael@0: } michael@0: } else { michael@0: if (part == 1) { michael@0: if ((state & DFCS_INACTIVE) == 0) { michael@0: if ((state & DFCS_PUSHED) != 0) { michael@0: ::DrawEdge(hdc, &widgetRect, BDR_SUNKENOUTER, BF_RECT); michael@0: } else if ((state & DFCS_HOT) != 0) { michael@0: ::DrawEdge(hdc, &widgetRect, BDR_RAISEDINNER, BF_RECT); michael@0: } michael@0: } michael@0: } else { michael@0: if ((state & (DFCS_HOT | DFCS_PUSHED)) != 0) { michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); michael@0: } michael@0: } michael@0: } michael@0: break; michael@0: case NS_THEME_MENUCHECKBOX: michael@0: case NS_THEME_MENURADIO: michael@0: if (!(state & DFCS_CHECKED)) michael@0: break; // nothin' to do michael@0: case NS_THEME_MENUARROW: { michael@0: uint32_t color = COLOR_MENUTEXT; michael@0: if ((state & DFCS_INACTIVE)) michael@0: color = COLOR_GRAYTEXT; michael@0: else if ((state & DFCS_HOT)) michael@0: color = COLOR_HIGHLIGHTTEXT; michael@0: michael@0: if (aWidgetType == NS_THEME_MENUCHECKBOX) michael@0: DrawMenuImage(hdc, widgetRect, DFCS_MENUCHECK, color); michael@0: else if (aWidgetType == NS_THEME_MENURADIO) michael@0: DrawMenuImage(hdc, widgetRect, DFCS_MENUBULLET, color); michael@0: else if (aWidgetType == NS_THEME_MENUARROW) michael@0: DrawMenuImage(hdc, widgetRect, michael@0: (state & DFCS_RTL) ? DFCS_MENUARROWRIGHT : DFCS_MENUARROW, michael@0: color); michael@0: break; michael@0: } michael@0: case NS_THEME_MENUSEPARATOR: { michael@0: // separators are offset by a bit (see menu.css) michael@0: widgetRect.left++; michael@0: widgetRect.right--; michael@0: michael@0: // This magic number is brought to you by the value in menu.css michael@0: widgetRect.top += 4; michael@0: // Our rectangles are 1 pixel high (see border size in menu.css) michael@0: widgetRect.bottom = widgetRect.top+1; michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_3DSHADOW+1)); michael@0: widgetRect.top++; michael@0: widgetRect.bottom++; michael@0: ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_3DHILIGHT+1)); michael@0: break; michael@0: } michael@0: michael@0: case NS_THEME_WINDOW_TITLEBAR: michael@0: case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: michael@0: { michael@0: RECT rect = widgetRect; michael@0: int32_t offset = GetSystemMetrics(SM_CXFRAME); michael@0: rect.bottom -= 1; michael@0: michael@0: // first fill the area to the color of the window background michael@0: FillRect(hdc, &rect, (HBRUSH)(COLOR_3DFACE+1)); michael@0: michael@0: // inset the caption area so it doesn't overflow. michael@0: rect.top += offset; michael@0: // if enabled, draw a gradient titlebar background, otherwise michael@0: // fill with a solid color. michael@0: BOOL bFlag = TRUE; michael@0: SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &bFlag, 0); michael@0: if (!bFlag) { michael@0: if (state == mozilla::widget::themeconst::FS_ACTIVE) michael@0: FillRect(hdc, &rect, (HBRUSH)(COLOR_ACTIVECAPTION+1)); michael@0: else michael@0: FillRect(hdc, &rect, (HBRUSH)(COLOR_INACTIVECAPTION+1)); michael@0: } else { michael@0: DWORD startColor, endColor; michael@0: if (state == mozilla::widget::themeconst::FS_ACTIVE) { michael@0: startColor = GetSysColor(COLOR_ACTIVECAPTION); michael@0: endColor = GetSysColor(COLOR_GRADIENTACTIVECAPTION); michael@0: } else { michael@0: startColor = GetSysColor(COLOR_INACTIVECAPTION); michael@0: endColor = GetSysColor(COLOR_GRADIENTINACTIVECAPTION); michael@0: } michael@0: michael@0: TRIVERTEX vertex[2]; michael@0: vertex[0].x = rect.left; michael@0: vertex[0].y = rect.top; michael@0: vertex[0].Red = GetRValue(startColor) << 8; michael@0: vertex[0].Green = GetGValue(startColor) << 8; michael@0: vertex[0].Blue = GetBValue(startColor) << 8; michael@0: vertex[0].Alpha = 0; michael@0: michael@0: vertex[1].x = rect.right; michael@0: vertex[1].y = rect.bottom; michael@0: vertex[1].Red = GetRValue(endColor) << 8; michael@0: vertex[1].Green = GetGValue(endColor) << 8; michael@0: vertex[1].Blue = GetBValue(endColor) << 8; michael@0: vertex[1].Alpha = 0; michael@0: michael@0: GRADIENT_RECT gRect; michael@0: gRect.UpperLeft = 0; michael@0: gRect.LowerRight = 1; michael@0: // available on win2k & up michael@0: GradientFill(hdc, vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_H); michael@0: } michael@0: michael@0: if (aWidgetType == NS_THEME_WINDOW_TITLEBAR) { michael@0: // frame things up with a top raised border. michael@0: DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_TOP); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case NS_THEME_WINDOW_FRAME_LEFT: michael@0: DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_LEFT); michael@0: break; michael@0: michael@0: case NS_THEME_WINDOW_FRAME_RIGHT: michael@0: DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RIGHT); michael@0: break; michael@0: michael@0: case NS_THEME_WINDOW_FRAME_BOTTOM: michael@0: DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_BOTTOM); michael@0: break; michael@0: michael@0: case NS_THEME_WINDOW_BUTTON_CLOSE: michael@0: case NS_THEME_WINDOW_BUTTON_MINIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_MAXIMIZE: michael@0: case NS_THEME_WINDOW_BUTTON_RESTORE: michael@0: { michael@0: if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) { michael@0: OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_MINIMIZE); michael@0: } michael@0: else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE || michael@0: aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { michael@0: OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_RESTORE); michael@0: } michael@0: else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) { michael@0: OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_CLOSE); michael@0: } michael@0: int32_t oldTA = SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); michael@0: DrawFrameControl(hdc, &widgetRect, part, state); michael@0: SetTextAlign(hdc, oldTA); michael@0: break; michael@0: } michael@0: michael@0: default: michael@0: rv = NS_ERROR_FAILURE; michael@0: break; michael@0: } michael@0: michael@0: nativeDrawing.EndNativeDrawing(); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (nativeDrawing.ShouldRenderAgain()) michael@0: goto RENDER_AGAIN; michael@0: michael@0: nativeDrawing.PaintToContext(); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: uint32_t michael@0: nsNativeThemeWin::GetWidgetNativeDrawingFlags(uint8_t aWidgetType) michael@0: { michael@0: switch (aWidgetType) { michael@0: case NS_THEME_BUTTON: michael@0: case NS_THEME_NUMBER_INPUT: michael@0: case NS_THEME_TEXTFIELD: michael@0: case NS_THEME_TEXTFIELD_MULTILINE: michael@0: michael@0: case NS_THEME_DROPDOWN: michael@0: case NS_THEME_DROPDOWN_TEXTFIELD: michael@0: return michael@0: gfxWindowsNativeDrawing::CANNOT_DRAW_TO_COLOR_ALPHA | michael@0: gfxWindowsNativeDrawing::CAN_AXIS_ALIGNED_SCALE | michael@0: gfxWindowsNativeDrawing::CANNOT_COMPLEX_TRANSFORM; michael@0: michael@0: // need to check these others michael@0: case NS_THEME_RANGE: michael@0: case NS_THEME_RANGE_THUMB: michael@0: case NS_THEME_SCROLLBAR_BUTTON_UP: michael@0: case NS_THEME_SCROLLBAR_BUTTON_DOWN: michael@0: case NS_THEME_SCROLLBAR_BUTTON_LEFT: michael@0: case NS_THEME_SCROLLBAR_BUTTON_RIGHT: michael@0: case NS_THEME_SCROLLBAR_THUMB_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: michael@0: case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case NS_THEME_SCALE_HORIZONTAL: michael@0: case NS_THEME_SCALE_VERTICAL: michael@0: case NS_THEME_SCALE_THUMB_HORIZONTAL: michael@0: case NS_THEME_SCALE_THUMB_VERTICAL: michael@0: case NS_THEME_SPINNER_UP_BUTTON: michael@0: case NS_THEME_SPINNER_DOWN_BUTTON: michael@0: case NS_THEME_LISTBOX: michael@0: case NS_THEME_TREEVIEW: michael@0: case NS_THEME_TOOLTIP: michael@0: case NS_THEME_STATUSBAR: michael@0: case NS_THEME_STATUSBAR_PANEL: michael@0: case NS_THEME_STATUSBAR_RESIZER_PANEL: michael@0: case NS_THEME_RESIZER: michael@0: case NS_THEME_PROGRESSBAR: michael@0: case NS_THEME_PROGRESSBAR_VERTICAL: michael@0: case NS_THEME_PROGRESSBAR_CHUNK: michael@0: case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: michael@0: case NS_THEME_TAB: michael@0: case NS_THEME_TAB_PANEL: michael@0: case NS_THEME_TAB_PANELS: michael@0: case NS_THEME_MENUBAR: michael@0: case NS_THEME_MENUPOPUP: michael@0: case NS_THEME_MENUITEM: michael@0: break; michael@0: michael@0: // the dropdown button /almost/ renders correctly with scaling, michael@0: // except that the graphic in the dropdown button (the downward arrow) michael@0: // doesn't get scaled up. michael@0: case NS_THEME_DROPDOWN_BUTTON: michael@0: // these are definitely no; they're all graphics that don't get scaled up michael@0: case NS_THEME_CHECKBOX: michael@0: case NS_THEME_RADIO: michael@0: case NS_THEME_GROUPBOX: michael@0: case NS_THEME_CHECKMENUITEM: michael@0: case NS_THEME_RADIOMENUITEM: michael@0: case NS_THEME_MENUCHECKBOX: michael@0: case NS_THEME_MENURADIO: michael@0: case NS_THEME_MENUARROW: michael@0: return michael@0: gfxWindowsNativeDrawing::CANNOT_DRAW_TO_COLOR_ALPHA | michael@0: gfxWindowsNativeDrawing::CANNOT_AXIS_ALIGNED_SCALE | michael@0: gfxWindowsNativeDrawing::CANNOT_COMPLEX_TRANSFORM; michael@0: } michael@0: michael@0: return michael@0: gfxWindowsNativeDrawing::CANNOT_DRAW_TO_COLOR_ALPHA | michael@0: gfxWindowsNativeDrawing::CANNOT_AXIS_ALIGNED_SCALE | michael@0: gfxWindowsNativeDrawing::CANNOT_COMPLEX_TRANSFORM; michael@0: } michael@0: michael@0: /////////////////////////////////////////// michael@0: // Creation Routine michael@0: /////////////////////////////////////////// michael@0: michael@0: // from nsWindow.cpp michael@0: extern bool gDisableNativeTheme; michael@0: michael@0: nsresult NS_NewNativeTheme(nsISupports *aOuter, REFNSIID aIID, void **aResult) michael@0: { michael@0: if (gDisableNativeTheme) michael@0: return NS_ERROR_NO_INTERFACE; michael@0: michael@0: if (aOuter) michael@0: return NS_ERROR_NO_AGGREGATION; michael@0: michael@0: nsNativeThemeWin* theme = new nsNativeThemeWin(); michael@0: if (!theme) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: return theme->QueryInterface(aIID, aResult); michael@0: }