1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/nsNativeThemeWin.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,4051 @@ 1.4 +/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsNativeThemeWin.h" 1.10 +#include "mozilla/EventStates.h" 1.11 +#include "mozilla/WindowsVersion.h" 1.12 +#include "nsRenderingContext.h" 1.13 +#include "nsRect.h" 1.14 +#include "nsSize.h" 1.15 +#include "nsTransform2D.h" 1.16 +#include "nsThemeConstants.h" 1.17 +#include "nsIPresShell.h" 1.18 +#include "nsPresContext.h" 1.19 +#include "nsIContent.h" 1.20 +#include "nsIFrame.h" 1.21 +#include "nsNameSpaceManager.h" 1.22 +#include "nsIDOMHTMLInputElement.h" 1.23 +#include "nsLookAndFeel.h" 1.24 +#include "nsMenuFrame.h" 1.25 +#include "nsGkAtoms.h" 1.26 +#include <malloc.h> 1.27 +#include "nsWindow.h" 1.28 +#include "nsIComboboxControlFrame.h" 1.29 +#include "prinrval.h" 1.30 +#include "WinUtils.h" 1.31 + 1.32 +#include "gfxPlatform.h" 1.33 +#include "gfxContext.h" 1.34 +#include "gfxWindowsPlatform.h" 1.35 +#include "gfxWindowsSurface.h" 1.36 +#include "gfxWindowsNativeDrawing.h" 1.37 + 1.38 +#include "nsUXThemeData.h" 1.39 +#include "nsUXThemeConstants.h" 1.40 +#include <algorithm> 1.41 + 1.42 +using mozilla::IsVistaOrLater; 1.43 +using namespace mozilla; 1.44 +using namespace mozilla::widget; 1.45 + 1.46 +#ifdef PR_LOGGING 1.47 +extern PRLogModuleInfo* gWindowsLog; 1.48 +#endif 1.49 + 1.50 +NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeWin, nsNativeTheme, nsITheme) 1.51 + 1.52 +nsNativeThemeWin::nsNativeThemeWin() : 1.53 + mProgressDeterminateTimeStamp(TimeStamp::Now()), 1.54 + mProgressIndeterminateTimeStamp(TimeStamp::Now()) 1.55 +{ 1.56 + // If there is a relevant change in forms.css for windows platform, 1.57 + // static widget style variables (e.g. sButtonBorderSize) should be 1.58 + // reinitialized here. 1.59 +} 1.60 + 1.61 +nsNativeThemeWin::~nsNativeThemeWin() 1.62 +{ 1.63 + nsUXThemeData::Invalidate(); 1.64 +} 1.65 + 1.66 +static int32_t 1.67 +GetTopLevelWindowActiveState(nsIFrame *aFrame) 1.68 +{ 1.69 + // Get the widget. nsIFrame's GetNearestWidget walks up the view chain 1.70 + // until it finds a real window. 1.71 + nsIWidget* widget = aFrame->GetNearestWidget(); 1.72 + nsWindowBase * window = static_cast<nsWindowBase*>(widget); 1.73 + if (!window) 1.74 + return mozilla::widget::themeconst::FS_INACTIVE; 1.75 + if (widget && !window->IsTopLevelWidget() && 1.76 + !(window = window->GetParentWindowBase(false))) 1.77 + return mozilla::widget::themeconst::FS_INACTIVE; 1.78 + 1.79 + if (window->GetWindowHandle() == ::GetActiveWindow()) 1.80 + return mozilla::widget::themeconst::FS_ACTIVE; 1.81 + return mozilla::widget::themeconst::FS_INACTIVE; 1.82 +} 1.83 + 1.84 +static int32_t 1.85 +GetWindowFrameButtonState(nsIFrame* aFrame, EventStates eventState) 1.86 +{ 1.87 + if (GetTopLevelWindowActiveState(aFrame) == 1.88 + mozilla::widget::themeconst::FS_INACTIVE) { 1.89 + if (eventState.HasState(NS_EVENT_STATE_HOVER)) 1.90 + return mozilla::widget::themeconst::BS_HOT; 1.91 + return mozilla::widget::themeconst::BS_INACTIVE; 1.92 + } 1.93 + 1.94 + if (eventState.HasState(NS_EVENT_STATE_HOVER)) { 1.95 + if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) 1.96 + return mozilla::widget::themeconst::BS_PUSHED; 1.97 + return mozilla::widget::themeconst::BS_HOT; 1.98 + } 1.99 + return mozilla::widget::themeconst::BS_NORMAL; 1.100 +} 1.101 + 1.102 +static int32_t 1.103 +GetClassicWindowFrameButtonState(EventStates eventState) 1.104 +{ 1.105 + if (eventState.HasState(NS_EVENT_STATE_ACTIVE) && 1.106 + eventState.HasState(NS_EVENT_STATE_HOVER)) 1.107 + return DFCS_BUTTONPUSH|DFCS_PUSHED; 1.108 + return DFCS_BUTTONPUSH; 1.109 +} 1.110 + 1.111 +static bool 1.112 +IsTopLevelMenu(nsIFrame *aFrame) 1.113 +{ 1.114 + bool isTopLevel(false); 1.115 + nsMenuFrame *menuFrame = do_QueryFrame(aFrame); 1.116 + if (menuFrame) { 1.117 + isTopLevel = menuFrame->IsOnMenuBar(); 1.118 + } 1.119 + return isTopLevel; 1.120 +} 1.121 + 1.122 +static MARGINS 1.123 +GetCheckboxMargins(HANDLE theme, HDC hdc) 1.124 +{ 1.125 + MARGINS checkboxContent = {0}; 1.126 + GetThemeMargins(theme, hdc, MENU_POPUPCHECK, MCB_NORMAL, 1.127 + TMT_CONTENTMARGINS, nullptr, &checkboxContent); 1.128 + return checkboxContent; 1.129 +} 1.130 + 1.131 +static SIZE 1.132 +GetCheckboxBGSize(HANDLE theme, HDC hdc) 1.133 +{ 1.134 + SIZE checkboxSize; 1.135 + GetThemePartSize(theme, hdc, MENU_POPUPCHECK, MC_CHECKMARKNORMAL, 1.136 + nullptr, TS_TRUE, &checkboxSize); 1.137 + 1.138 + MARGINS checkboxMargins = GetCheckboxMargins(theme, hdc); 1.139 + 1.140 + int leftMargin = checkboxMargins.cxLeftWidth; 1.141 + int rightMargin = checkboxMargins.cxRightWidth; 1.142 + int topMargin = checkboxMargins.cyTopHeight; 1.143 + int bottomMargin = checkboxMargins.cyBottomHeight; 1.144 + 1.145 + int width = leftMargin + checkboxSize.cx + rightMargin; 1.146 + int height = topMargin + checkboxSize.cy + bottomMargin; 1.147 + SIZE ret; 1.148 + ret.cx = width; 1.149 + ret.cy = height; 1.150 + return ret; 1.151 +} 1.152 + 1.153 +static SIZE 1.154 +GetCheckboxBGBounds(HANDLE theme, HDC hdc) 1.155 +{ 1.156 + MARGINS checkboxBGSizing = {0}; 1.157 + MARGINS checkboxBGContent = {0}; 1.158 + GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, 1.159 + TMT_SIZINGMARGINS, nullptr, &checkboxBGSizing); 1.160 + GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, 1.161 + TMT_CONTENTMARGINS, nullptr, &checkboxBGContent); 1.162 + 1.163 +#define posdx(d) ((d) > 0 ? d : 0) 1.164 + 1.165 + int dx = posdx(checkboxBGContent.cxRightWidth - 1.166 + checkboxBGSizing.cxRightWidth) + 1.167 + posdx(checkboxBGContent.cxLeftWidth - 1.168 + checkboxBGSizing.cxLeftWidth); 1.169 + int dy = posdx(checkboxBGContent.cyTopHeight - 1.170 + checkboxBGSizing.cyTopHeight) + 1.171 + posdx(checkboxBGContent.cyBottomHeight - 1.172 + checkboxBGSizing.cyBottomHeight); 1.173 + 1.174 +#undef posdx 1.175 + 1.176 + SIZE ret(GetCheckboxBGSize(theme, hdc)); 1.177 + ret.cx += dx; 1.178 + ret.cy += dy; 1.179 + return ret; 1.180 +} 1.181 + 1.182 +static SIZE 1.183 +GetGutterSize(HANDLE theme, HDC hdc) 1.184 +{ 1.185 + SIZE gutterSize; 1.186 + GetThemePartSize(theme, hdc, MENU_POPUPGUTTER, 0, nullptr, TS_TRUE, &gutterSize); 1.187 + 1.188 + SIZE checkboxBGSize(GetCheckboxBGBounds(theme, hdc)); 1.189 + 1.190 + SIZE itemSize; 1.191 + GetThemePartSize(theme, hdc, MENU_POPUPITEM, MPI_NORMAL, nullptr, TS_TRUE, &itemSize); 1.192 + 1.193 + // Figure out how big the menuitem's icon will be (if present) at current DPI 1.194 + double scaleFactor = nsIWidget::DefaultScaleOverride(); 1.195 + if (scaleFactor <= 0.0) { 1.196 + scaleFactor = gfxWindowsPlatform::GetPlatform()->GetDPIScale(); 1.197 + } 1.198 + int iconDevicePixels = NSToIntRound(16 * scaleFactor); 1.199 + SIZE iconSize = { 1.200 + iconDevicePixels, iconDevicePixels 1.201 + }; 1.202 + // Not really sure what margins should be used here, but this seems to work in practice... 1.203 + MARGINS margins = {0}; 1.204 + GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, 1.205 + TMT_CONTENTMARGINS, nullptr, &margins); 1.206 + iconSize.cx += margins.cxLeftWidth + margins.cxRightWidth; 1.207 + iconSize.cy += margins.cyTopHeight + margins.cyBottomHeight; 1.208 + 1.209 + int width = std::max(itemSize.cx, std::max(iconSize.cx, checkboxBGSize.cx) + gutterSize.cx); 1.210 + int height = std::max(itemSize.cy, std::max(iconSize.cy, checkboxBGSize.cy)); 1.211 + 1.212 + SIZE ret; 1.213 + ret.cx = width; 1.214 + ret.cy = height; 1.215 + return ret; 1.216 +} 1.217 + 1.218 +/* DrawThemeBGRTLAware - render a theme part based on rtl state. 1.219 + * Some widgets are not direction-neutral and need to be drawn reversed for 1.220 + * RTL. Windows provides a way to do this with SetLayout, but this reverses 1.221 + * the entire drawing area of a given device context, which means that its 1.222 + * use will also affect the positioning of the widget. There are two ways 1.223 + * to work around this: 1.224 + * 1.225 + * Option 1: Alter the position of the rect that we send so that we cancel 1.226 + * out the positioning effects of SetLayout 1.227 + * Option 2: Create a memory DC with the widgetRect's dimensions, draw onto 1.228 + * that, and then transfer the results back to our DC 1.229 + * 1.230 + * This function tries to implement option 1, under the assumption that the 1.231 + * correct way to reverse the effects of SetLayout is to translate the rect 1.232 + * such that the offset from the DC bitmap's left edge to the old rect's 1.233 + * left edge is equal to the offset from the DC bitmap's right edge to the 1.234 + * new rect's right edge. In other words, 1.235 + * (oldRect.left + vpOrg.x) == ((dcBMP.width - vpOrg.x) - newRect.right) 1.236 + */ 1.237 +static HRESULT 1.238 +DrawThemeBGRTLAware(HANDLE aTheme, HDC aHdc, int aPart, int aState, 1.239 + const RECT *aWidgetRect, const RECT *aClipRect, 1.240 + bool aIsRtl) 1.241 +{ 1.242 + NS_ASSERTION(aTheme, "Bad theme handle."); 1.243 + NS_ASSERTION(aHdc, "Bad hdc."); 1.244 + NS_ASSERTION(aWidgetRect, "Bad rect."); 1.245 + NS_ASSERTION(aClipRect, "Bad clip rect."); 1.246 + 1.247 + if (!aIsRtl) { 1.248 + return DrawThemeBackground(aTheme, aHdc, aPart, aState, 1.249 + aWidgetRect, aClipRect); 1.250 + } 1.251 + 1.252 + HGDIOBJ hObj = GetCurrentObject(aHdc, OBJ_BITMAP); 1.253 + BITMAP bitmap; 1.254 + POINT vpOrg; 1.255 + 1.256 + if (hObj && GetObject(hObj, sizeof(bitmap), &bitmap) && 1.257 + GetViewportOrgEx(aHdc, &vpOrg)) { 1.258 + RECT newWRect(*aWidgetRect); 1.259 + newWRect.left = bitmap.bmWidth - (aWidgetRect->right + 2*vpOrg.x); 1.260 + newWRect.right = bitmap.bmWidth - (aWidgetRect->left + 2*vpOrg.x); 1.261 + 1.262 + RECT newCRect; 1.263 + RECT *newCRectPtr = nullptr; 1.264 + 1.265 + if (aClipRect) { 1.266 + newCRect.top = aClipRect->top; 1.267 + newCRect.bottom = aClipRect->bottom; 1.268 + newCRect.left = bitmap.bmWidth - (aClipRect->right + 2*vpOrg.x); 1.269 + newCRect.right = bitmap.bmWidth - (aClipRect->left + 2*vpOrg.x); 1.270 + newCRectPtr = &newCRect; 1.271 + } 1.272 + 1.273 + SetLayout(aHdc, LAYOUT_RTL); 1.274 + HRESULT hr = DrawThemeBackground(aTheme, aHdc, aPart, aState, &newWRect, 1.275 + newCRectPtr); 1.276 + SetLayout(aHdc, 0); 1.277 + if (SUCCEEDED(hr)) { 1.278 + return hr; 1.279 + } 1.280 + } 1.281 + return DrawThemeBackground(aTheme, aHdc, aPart, aState, 1.282 + aWidgetRect, aClipRect); 1.283 +} 1.284 + 1.285 +/* 1.286 + * Caption button padding data - 'hot' button padding. 1.287 + * These areas are considered hot, in that they activate 1.288 + * a button when hovered or clicked. The button graphic 1.289 + * is drawn inside the padding border. Unrecognized themes 1.290 + * are treated as their recognized counterparts for now. 1.291 + * left top right bottom 1.292 + * classic min 1 2 0 1 1.293 + * classic max 0 2 1 1 1.294 + * classic close 1 2 2 1 1.295 + * 1.296 + * aero basic min 1 2 0 2 1.297 + * aero basic max 0 2 1 2 1.298 + * aero basic close 1 2 1 2 1.299 + * 1.300 + * xp theme min 0 2 0 2 1.301 + * xp theme max 0 2 1 2 1.302 + * xp theme close 1 2 2 2 1.303 + * 1.304 + * 'cold' button padding - generic button padding, should 1.305 + * be handled in css. 1.306 + * left top right bottom 1.307 + * classic min 0 0 0 0 1.308 + * classic max 0 0 0 0 1.309 + * classic close 0 0 0 0 1.310 + * 1.311 + * aero basic min 0 0 1 0 1.312 + * aero basic max 1 0 0 0 1.313 + * aero basic close 0 0 0 0 1.314 + * 1.315 + * xp theme min 0 0 1 0 1.316 + * xp theme max 1 0 0 0 1.317 + * xp theme close 0 0 0 0 1.318 + */ 1.319 + 1.320 +enum CaptionDesktopTheme { 1.321 + CAPTION_CLASSIC = 0, 1.322 + CAPTION_BASIC, 1.323 + CAPTION_XPTHEME, 1.324 +}; 1.325 + 1.326 +enum CaptionButton { 1.327 + CAPTIONBUTTON_MINIMIZE = 0, 1.328 + CAPTIONBUTTON_RESTORE, 1.329 + CAPTIONBUTTON_CLOSE, 1.330 +}; 1.331 + 1.332 +struct CaptionButtonPadding { 1.333 + RECT hotPadding[3]; 1.334 +}; 1.335 + 1.336 +// RECT: left, top, right, bottom 1.337 +static CaptionButtonPadding buttonData[3] = { 1.338 + { 1.339 + { { 1, 2, 0, 1 }, { 0, 2, 1, 1 }, { 1, 2, 2, 1 } } 1.340 + }, 1.341 + { 1.342 + { { 1, 2, 0, 2 }, { 0, 2, 1, 2 }, { 1, 2, 2, 2 } } 1.343 + }, 1.344 + { 1.345 + { { 0, 2, 0, 2 }, { 0, 2, 1, 2 }, { 1, 2, 2, 2 } } 1.346 + } 1.347 +}; 1.348 + 1.349 +// Adds "hot" caption button padding to minimum widget size. 1.350 +static void 1.351 +AddPaddingRect(nsIntSize* aSize, CaptionButton button) { 1.352 + if (!aSize) 1.353 + return; 1.354 + RECT offset; 1.355 + if (!IsAppThemed()) 1.356 + offset = buttonData[CAPTION_CLASSIC].hotPadding[button]; 1.357 + else if (!IsVistaOrLater()) 1.358 + offset = buttonData[CAPTION_XPTHEME].hotPadding[button]; 1.359 + else 1.360 + offset = buttonData[CAPTION_BASIC].hotPadding[button]; 1.361 + aSize->width += offset.left + offset.right; 1.362 + aSize->height += offset.top + offset.bottom; 1.363 +} 1.364 + 1.365 +// If we've added padding to the minimum widget size, offset 1.366 +// the area we draw into to compensate. 1.367 +static void 1.368 +OffsetBackgroundRect(RECT& rect, CaptionButton button) { 1.369 + RECT offset; 1.370 + if (!IsAppThemed()) 1.371 + offset = buttonData[CAPTION_CLASSIC].hotPadding[button]; 1.372 + else if (!IsVistaOrLater()) 1.373 + offset = buttonData[CAPTION_XPTHEME].hotPadding[button]; 1.374 + else 1.375 + offset = buttonData[CAPTION_BASIC].hotPadding[button]; 1.376 + rect.left += offset.left; 1.377 + rect.top += offset.top; 1.378 + rect.right -= offset.right; 1.379 + rect.bottom -= offset.bottom; 1.380 +} 1.381 + 1.382 +/* 1.383 + * Notes on progress track and meter part constants: 1.384 + * xp and up: 1.385 + * PP_BAR(_VERT) - base progress track 1.386 + * PP_TRANSPARENTBAR(_VERT) - transparent progress track. this only works if 1.387 + * the underlying surface supports alpha. otherwise 1.388 + * theme lib's DrawThemeBackground falls back on 1.389 + * opaque PP_BAR. we currently don't use this. 1.390 + * PP_CHUNK(_VERT) - xp progress meter. this does not draw an xp style 1.391 + * progress w/chunks, it draws fill using the chunk 1.392 + * graphic. 1.393 + * vista and up: 1.394 + * PP_FILL(_VERT) - progress meter. these have four states/colors. 1.395 + * PP_PULSEOVERLAY(_VERT) - white reflection - an overlay, not sure what this 1.396 + * is used for. 1.397 + * PP_MOVEOVERLAY(_VERT) - green pulse - the pulse effect overlay on 1.398 + * determined progress bars. we also use this for 1.399 + * indeterminate chunk. 1.400 + * 1.401 + * Notes on state constants: 1.402 + * PBBS_NORMAL - green progress 1.403 + * PBBVS_PARTIAL/PBFVS_ERROR - red error progress 1.404 + * PBFS_PAUSED - yellow paused progress 1.405 + * 1.406 + * There is no common controls style indeterminate part on vista and up. 1.407 + */ 1.408 + 1.409 +/* 1.410 + * Progress bar related constants. These values are found by experimenting and 1.411 + * comparing against native widgets used by the system. They are very unlikely 1.412 + * exact but try to not be too wrong. 1.413 + */ 1.414 +// The amount of time we animate progress meters parts across the frame. 1.415 +static const double kProgressDeterminateTimeSpan = 3.0; 1.416 +static const double kProgressIndeterminateTimeSpan = 5.0; 1.417 +// The width of the overlay used to animate the horizontal progress bar (Vista and later). 1.418 +static const int32_t kProgressHorizontalVistaOverlaySize = 120; 1.419 +// The width of the overlay used for the horizontal indeterminate progress bars on XP. 1.420 +static const int32_t kProgressHorizontalXPOverlaySize = 55; 1.421 +// The height of the overlay used to animate the vertical progress bar (Vista and later). 1.422 +static const int32_t kProgressVerticalOverlaySize = 45; 1.423 +// The height of the overlay used for the vertical indeterminate progress bar (Vista and later). 1.424 +static const int32_t kProgressVerticalIndeterminateOverlaySize = 60; 1.425 +// The width of the overlay used to animate the indeterminate progress bar (Windows Classic). 1.426 +static const int32_t kProgressClassicOverlaySize = 40; 1.427 + 1.428 +/* 1.429 + * GetProgressOverlayStyle - returns the proper overlay part for themed 1.430 + * progress bars based on os and orientation. 1.431 + */ 1.432 +static int32_t 1.433 +GetProgressOverlayStyle(bool aIsVertical) 1.434 +{ 1.435 + if (aIsVertical) { 1.436 + if (IsVistaOrLater()) { 1.437 + return PP_MOVEOVERLAYVERT; 1.438 + } 1.439 + return PP_CHUNKVERT; 1.440 + } else { 1.441 + if (IsVistaOrLater()) { 1.442 + return PP_MOVEOVERLAY; 1.443 + } 1.444 + return PP_CHUNK; 1.445 + } 1.446 +} 1.447 + 1.448 +/* 1.449 + * GetProgressOverlaySize - returns the minimum width or height for themed 1.450 + * progress bar overlays. This includes the width of indeterminate chunks 1.451 + * and vista pulse overlays. 1.452 + */ 1.453 +static int32_t 1.454 +GetProgressOverlaySize(bool aIsVertical, bool aIsIndeterminate) 1.455 +{ 1.456 + if (IsVistaOrLater()) { 1.457 + if (aIsVertical) { 1.458 + return aIsIndeterminate ? kProgressVerticalIndeterminateOverlaySize 1.459 + : kProgressVerticalOverlaySize; 1.460 + } 1.461 + return kProgressHorizontalVistaOverlaySize; 1.462 + } 1.463 + return kProgressHorizontalXPOverlaySize; 1.464 +} 1.465 + 1.466 +/* 1.467 + * IsProgressMeterFilled - Determines if a progress meter is at 100% fill based 1.468 + * on a comparison of the current value and maximum. 1.469 + */ 1.470 +static bool 1.471 +IsProgressMeterFilled(nsIFrame* aFrame) 1.472 +{ 1.473 + NS_ENSURE_TRUE(aFrame, false); 1.474 + nsIFrame* parentFrame = aFrame->GetParent(); 1.475 + NS_ENSURE_TRUE(parentFrame, false); 1.476 + return nsNativeTheme::GetProgressValue(parentFrame) == 1.477 + nsNativeTheme::GetProgressMaxValue(parentFrame); 1.478 +} 1.479 + 1.480 +/* 1.481 + * CalculateProgressOverlayRect - returns the padded overlay animation rect 1.482 + * used in rendering progress bars. Resulting rects are used in rendering 1.483 + * vista+ pulse overlays and indeterminate progress meters. Graphics should 1.484 + * be rendered at the origin. 1.485 + */ 1.486 +RECT 1.487 +nsNativeThemeWin::CalculateProgressOverlayRect(nsIFrame* aFrame, 1.488 + RECT* aWidgetRect, 1.489 + bool aIsVertical, 1.490 + bool aIsIndeterminate, 1.491 + bool aIsClassic) 1.492 +{ 1.493 + NS_ASSERTION(aFrame, "bad frame pointer"); 1.494 + NS_ASSERTION(aWidgetRect, "bad rect pointer"); 1.495 + 1.496 + int32_t frameSize = aIsVertical ? aWidgetRect->bottom - aWidgetRect->top 1.497 + : aWidgetRect->right - aWidgetRect->left; 1.498 + 1.499 + // Recycle a set of progress pulse timers - these timers control the position 1.500 + // of all progress overlays and indeterminate chunks that get rendered. 1.501 + double span = aIsIndeterminate ? kProgressIndeterminateTimeSpan 1.502 + : kProgressDeterminateTimeSpan; 1.503 + TimeDuration period; 1.504 + if (!aIsIndeterminate) { 1.505 + if (TimeStamp::Now() > (mProgressDeterminateTimeStamp + 1.506 + TimeDuration::FromSeconds(span))) { 1.507 + mProgressDeterminateTimeStamp = TimeStamp::Now(); 1.508 + } 1.509 + period = TimeStamp::Now() - mProgressDeterminateTimeStamp; 1.510 + } else { 1.511 + if (TimeStamp::Now() > (mProgressIndeterminateTimeStamp + 1.512 + TimeDuration::FromSeconds(span))) { 1.513 + mProgressIndeterminateTimeStamp = TimeStamp::Now(); 1.514 + } 1.515 + period = TimeStamp::Now() - mProgressIndeterminateTimeStamp; 1.516 + } 1.517 + 1.518 + double percent = period / TimeDuration::FromSeconds(span); 1.519 + 1.520 + if (!aIsVertical && IsFrameRTL(aFrame)) 1.521 + percent = 1 - percent; 1.522 + 1.523 + RECT overlayRect = *aWidgetRect; 1.524 + int32_t overlaySize; 1.525 + if (!aIsClassic) { 1.526 + overlaySize = GetProgressOverlaySize(aIsVertical, aIsIndeterminate); 1.527 + } else { 1.528 + overlaySize = kProgressClassicOverlaySize; 1.529 + } 1.530 + 1.531 + // Calculate a bounds that is larger than the meters frame such that the 1.532 + // overlay starts and ends completely off the edge of the frame: 1.533 + // [overlay][frame][overlay] 1.534 + // This also yields a nice delay on rotation. Use overlaySize as the minimum 1.535 + // size for [overlay] based on the graphics dims. If [frame] is larger, use 1.536 + // the frame size instead. 1.537 + int trackWidth = frameSize > overlaySize ? frameSize : overlaySize; 1.538 + if (!aIsVertical) { 1.539 + int xPos = aWidgetRect->left - trackWidth; 1.540 + xPos += (int)ceil(((double)(trackWidth*2) * percent)); 1.541 + overlayRect.left = xPos; 1.542 + overlayRect.right = xPos + overlaySize; 1.543 + } else { 1.544 + int yPos = aWidgetRect->bottom + trackWidth; 1.545 + yPos -= (int)ceil(((double)(trackWidth*2) * percent)); 1.546 + overlayRect.bottom = yPos; 1.547 + overlayRect.top = yPos - overlaySize; 1.548 + } 1.549 + return overlayRect; 1.550 +} 1.551 + 1.552 +/* 1.553 + * DrawChunkProgressMeter - renders an xp style chunked progress meter. Called 1.554 + * by DrawProgressMeter. 1.555 + * 1.556 + * @param aTheme progress theme handle 1.557 + * @param aHdc hdc returned by gfxWindowsNativeDrawing 1.558 + * @param aPart the PP_X progress part 1.559 + * @param aState the theme state 1.560 + * @param aFrame the elements frame 1.561 + * @param aWidgetRect bounding rect for the widget 1.562 + * @param aClipRect dirty rect that needs drawing. 1.563 + * @param aAppUnits app units per device pixel 1.564 + * @param aIsIndeterm is an indeterminate progress? 1.565 + * @param aIsVertical render a vertical progress? 1.566 + * @param aIsRtl direction is rtl 1.567 + */ 1.568 +static void 1.569 +DrawChunkProgressMeter(HTHEME aTheme, HDC aHdc, int aPart, 1.570 + int aState, nsIFrame* aFrame, RECT* aWidgetRect, 1.571 + RECT* aClipRect, gfxFloat aAppUnits, bool aIsIndeterm, 1.572 + bool aIsVertical, bool aIsRtl) 1.573 +{ 1.574 + NS_ASSERTION(aTheme, "Bad theme."); 1.575 + NS_ASSERTION(aHdc, "Bad hdc."); 1.576 + NS_ASSERTION(aWidgetRect, "Bad rect."); 1.577 + NS_ASSERTION(aClipRect, "Bad clip rect."); 1.578 + NS_ASSERTION(aFrame, "Bad frame."); 1.579 + 1.580 + // For horizontal meters, the theme lib paints the right graphic but doesn't 1.581 + // paint the chunks, so we do that manually. For vertical meters, the theme 1.582 + // library draws everything correctly. 1.583 + if (aIsVertical) { 1.584 + DrawThemeBackground(aTheme, aHdc, aPart, aState, aWidgetRect, aClipRect); 1.585 + return; 1.586 + } 1.587 + 1.588 + // query for the proper chunk metrics 1.589 + int chunkSize, spaceSize; 1.590 + if (FAILED(GetThemeMetric(aTheme, aHdc, aPart, aState, 1.591 + TMT_PROGRESSCHUNKSIZE, &chunkSize)) || 1.592 + FAILED(GetThemeMetric(aTheme, aHdc, aPart, aState, 1.593 + TMT_PROGRESSSPACESIZE, &spaceSize))) { 1.594 + DrawThemeBackground(aTheme, aHdc, aPart, aState, aWidgetRect, aClipRect); 1.595 + return; 1.596 + } 1.597 + 1.598 + // render chunks 1.599 + if (!aIsRtl || aIsIndeterm) { 1.600 + for (int chunk = aWidgetRect->left; chunk <= aWidgetRect->right; 1.601 + chunk += (chunkSize+spaceSize)) { 1.602 + if (!aIsIndeterm && ((chunk + chunkSize) > aWidgetRect->right)) { 1.603 + // aWidgetRect->right represents the end of the meter. Partial blocks 1.604 + // don't get rendered with one exception, so exit here if we don't have 1.605 + // a full chunk to draw. 1.606 + // The above is true *except* when the meter is at 100% fill, in which 1.607 + // case Windows renders any remaining partial block. Query the parent 1.608 + // frame to find out if we're at 100%. 1.609 + if (!IsProgressMeterFilled(aFrame)) { 1.610 + break; 1.611 + } 1.612 + } 1.613 + RECT bounds = 1.614 + { chunk, aWidgetRect->top, chunk + chunkSize, aWidgetRect->bottom }; 1.615 + DrawThemeBackground(aTheme, aHdc, aPart, aState, &bounds, aClipRect); 1.616 + } 1.617 + } else { 1.618 + // rtl needs to grow in the opposite direction to look right. 1.619 + for (int chunk = aWidgetRect->right; chunk >= aWidgetRect->left; 1.620 + chunk -= (chunkSize+spaceSize)) { 1.621 + if ((chunk - chunkSize) < aWidgetRect->left) { 1.622 + if (!IsProgressMeterFilled(aFrame)) { 1.623 + break; 1.624 + } 1.625 + } 1.626 + RECT bounds = 1.627 + { chunk - chunkSize, aWidgetRect->top, chunk, aWidgetRect->bottom }; 1.628 + DrawThemeBackground(aTheme, aHdc, aPart, aState, &bounds, aClipRect); 1.629 + } 1.630 + } 1.631 +} 1.632 + 1.633 +/* 1.634 + * DrawProgressMeter - render an appropriate progress meter based on progress 1.635 + * meter style, orientation, and os. Note, this does not render the underlying 1.636 + * progress track. 1.637 + * 1.638 + * @param aFrame the widget frame 1.639 + * @param aWidgetType type of widget 1.640 + * @param aTheme progress theme handle 1.641 + * @param aHdc hdc returned by gfxWindowsNativeDrawing 1.642 + * @param aPart the PP_X progress part 1.643 + * @param aState the theme state 1.644 + * @param aWidgetRect bounding rect for the widget 1.645 + * @param aClipRect dirty rect that needs drawing. 1.646 + * @param aAppUnits app units per device pixel 1.647 + */ 1.648 +void 1.649 +nsNativeThemeWin::DrawThemedProgressMeter(nsIFrame* aFrame, int aWidgetType, 1.650 + HANDLE aTheme, HDC aHdc, 1.651 + int aPart, int aState, 1.652 + RECT* aWidgetRect, RECT* aClipRect, 1.653 + gfxFloat aAppUnits) 1.654 +{ 1.655 + if (!aFrame || !aTheme || !aHdc) 1.656 + return; 1.657 + 1.658 + NS_ASSERTION(aWidgetRect, "bad rect pointer"); 1.659 + NS_ASSERTION(aClipRect, "bad clip rect pointer"); 1.660 + 1.661 + RECT adjWidgetRect, adjClipRect; 1.662 + adjWidgetRect = *aWidgetRect; 1.663 + adjClipRect = *aClipRect; 1.664 + if (!IsVistaOrLater()) { 1.665 + // Adjust clipping out by one pixel. XP progress meters are inset, 1.666 + // Vista+ are not. 1.667 + InflateRect(&adjWidgetRect, 1, 1); 1.668 + InflateRect(&adjClipRect, 1, 1); 1.669 + } 1.670 + 1.671 + nsIFrame* parentFrame = aFrame->GetParent(); 1.672 + if (!parentFrame) { 1.673 + // We have no parent to work with, just bail. 1.674 + NS_WARNING("No parent frame for progress rendering. Can't paint."); 1.675 + return; 1.676 + } 1.677 + 1.678 + EventStates eventStates = GetContentState(parentFrame, aWidgetType); 1.679 + bool vertical = IsVerticalProgress(parentFrame) || 1.680 + aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL; 1.681 + bool indeterminate = IsIndeterminateProgress(parentFrame, eventStates); 1.682 + bool animate = indeterminate; 1.683 + 1.684 + if (IsVistaOrLater()) { 1.685 + // Vista and up progress meter is fill style, rendered here. We render 1.686 + // the pulse overlay in the follow up section below. 1.687 + DrawThemeBackground(aTheme, aHdc, aPart, aState, 1.688 + &adjWidgetRect, &adjClipRect); 1.689 + if (!IsProgressMeterFilled(aFrame)) { 1.690 + animate = true; 1.691 + } 1.692 + } else if (!indeterminate) { 1.693 + // XP progress meters are 'chunk' style. 1.694 + DrawChunkProgressMeter(aTheme, aHdc, aPart, aState, aFrame, 1.695 + &adjWidgetRect, &adjClipRect, aAppUnits, 1.696 + indeterminate, vertical, IsFrameRTL(aFrame)); 1.697 + } 1.698 + 1.699 + if (animate) { 1.700 + // Indeterminate rendering 1.701 + int32_t overlayPart = GetProgressOverlayStyle(vertical); 1.702 + RECT overlayRect = 1.703 + CalculateProgressOverlayRect(aFrame, &adjWidgetRect, vertical, 1.704 + indeterminate, false); 1.705 + if (IsVistaOrLater()) { 1.706 + DrawThemeBackground(aTheme, aHdc, overlayPart, aState, &overlayRect, 1.707 + &adjClipRect); 1.708 + } else { 1.709 + DrawChunkProgressMeter(aTheme, aHdc, overlayPart, aState, aFrame, 1.710 + &overlayRect, &adjClipRect, aAppUnits, 1.711 + indeterminate, vertical, IsFrameRTL(aFrame)); 1.712 + } 1.713 + 1.714 + if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 60)) { 1.715 + NS_WARNING("unable to animate progress widget!"); 1.716 + } 1.717 + } 1.718 +} 1.719 + 1.720 +HANDLE 1.721 +nsNativeThemeWin::GetTheme(uint8_t aWidgetType) 1.722 +{ 1.723 + if (!IsVistaOrLater()) { 1.724 + // On XP or earlier, render dropdowns as textfields; 1.725 + // doing it the right way works fine with the MS themes, 1.726 + // but breaks on a lot of custom themes (presumably because MS 1.727 + // apps do the textfield border business as well). 1.728 + if (aWidgetType == NS_THEME_DROPDOWN) 1.729 + aWidgetType = NS_THEME_TEXTFIELD; 1.730 + } 1.731 + 1.732 + switch (aWidgetType) { 1.733 + case NS_THEME_BUTTON: 1.734 + case NS_THEME_RADIO: 1.735 + case NS_THEME_CHECKBOX: 1.736 + case NS_THEME_GROUPBOX: 1.737 + return nsUXThemeData::GetTheme(eUXButton); 1.738 + case NS_THEME_NUMBER_INPUT: 1.739 + case NS_THEME_TEXTFIELD: 1.740 + case NS_THEME_TEXTFIELD_MULTILINE: 1.741 + return nsUXThemeData::GetTheme(eUXEdit); 1.742 + case NS_THEME_TOOLTIP: 1.743 + // XP/2K3 should force a classic treatment of tooltips 1.744 + return !IsVistaOrLater() ? 1.745 + nullptr : nsUXThemeData::GetTheme(eUXTooltip); 1.746 + case NS_THEME_TOOLBOX: 1.747 + return nsUXThemeData::GetTheme(eUXRebar); 1.748 + case NS_THEME_WIN_MEDIA_TOOLBOX: 1.749 + return nsUXThemeData::GetTheme(eUXMediaRebar); 1.750 + case NS_THEME_WIN_COMMUNICATIONS_TOOLBOX: 1.751 + return nsUXThemeData::GetTheme(eUXCommunicationsRebar); 1.752 + case NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX: 1.753 + return nsUXThemeData::GetTheme(eUXBrowserTabBarRebar); 1.754 + case NS_THEME_TOOLBAR: 1.755 + case NS_THEME_TOOLBAR_BUTTON: 1.756 + case NS_THEME_TOOLBAR_SEPARATOR: 1.757 + return nsUXThemeData::GetTheme(eUXToolbar); 1.758 + case NS_THEME_PROGRESSBAR: 1.759 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.760 + case NS_THEME_PROGRESSBAR_CHUNK: 1.761 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: 1.762 + return nsUXThemeData::GetTheme(eUXProgress); 1.763 + case NS_THEME_TAB: 1.764 + case NS_THEME_TAB_PANEL: 1.765 + case NS_THEME_TAB_PANELS: 1.766 + return nsUXThemeData::GetTheme(eUXTab); 1.767 + case NS_THEME_SCROLLBAR: 1.768 + case NS_THEME_SCROLLBAR_SMALL: 1.769 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.770 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.771 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.772 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.773 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.774 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: 1.775 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.776 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.777 + return nsUXThemeData::GetTheme(eUXScrollbar); 1.778 + case NS_THEME_RANGE: 1.779 + case NS_THEME_RANGE_THUMB: 1.780 + case NS_THEME_SCALE_HORIZONTAL: 1.781 + case NS_THEME_SCALE_VERTICAL: 1.782 + case NS_THEME_SCALE_THUMB_HORIZONTAL: 1.783 + case NS_THEME_SCALE_THUMB_VERTICAL: 1.784 + return nsUXThemeData::GetTheme(eUXTrackbar); 1.785 + case NS_THEME_SPINNER_UP_BUTTON: 1.786 + case NS_THEME_SPINNER_DOWN_BUTTON: 1.787 + return nsUXThemeData::GetTheme(eUXSpin); 1.788 + case NS_THEME_STATUSBAR: 1.789 + case NS_THEME_STATUSBAR_PANEL: 1.790 + case NS_THEME_STATUSBAR_RESIZER_PANEL: 1.791 + case NS_THEME_RESIZER: 1.792 + return nsUXThemeData::GetTheme(eUXStatus); 1.793 + case NS_THEME_DROPDOWN: 1.794 + case NS_THEME_DROPDOWN_BUTTON: 1.795 + return nsUXThemeData::GetTheme(eUXCombobox); 1.796 + case NS_THEME_TREEVIEW_HEADER_CELL: 1.797 + case NS_THEME_TREEVIEW_HEADER_SORTARROW: 1.798 + return nsUXThemeData::GetTheme(eUXHeader); 1.799 + case NS_THEME_LISTBOX: 1.800 + case NS_THEME_LISTBOX_LISTITEM: 1.801 + case NS_THEME_TREEVIEW: 1.802 + case NS_THEME_TREEVIEW_TWISTY_OPEN: 1.803 + case NS_THEME_TREEVIEW_TREEITEM: 1.804 + return nsUXThemeData::GetTheme(eUXListview); 1.805 + case NS_THEME_MENUBAR: 1.806 + case NS_THEME_MENUPOPUP: 1.807 + case NS_THEME_MENUITEM: 1.808 + case NS_THEME_CHECKMENUITEM: 1.809 + case NS_THEME_RADIOMENUITEM: 1.810 + case NS_THEME_MENUCHECKBOX: 1.811 + case NS_THEME_MENURADIO: 1.812 + case NS_THEME_MENUSEPARATOR: 1.813 + case NS_THEME_MENUARROW: 1.814 + case NS_THEME_MENUIMAGE: 1.815 + case NS_THEME_MENUITEMTEXT: 1.816 + return nsUXThemeData::GetTheme(eUXMenu); 1.817 + case NS_THEME_WINDOW_TITLEBAR: 1.818 + case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: 1.819 + case NS_THEME_WINDOW_FRAME_LEFT: 1.820 + case NS_THEME_WINDOW_FRAME_RIGHT: 1.821 + case NS_THEME_WINDOW_FRAME_BOTTOM: 1.822 + case NS_THEME_WINDOW_BUTTON_CLOSE: 1.823 + case NS_THEME_WINDOW_BUTTON_MINIMIZE: 1.824 + case NS_THEME_WINDOW_BUTTON_MAXIMIZE: 1.825 + case NS_THEME_WINDOW_BUTTON_RESTORE: 1.826 + case NS_THEME_WINDOW_BUTTON_BOX: 1.827 + case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: 1.828 + case NS_THEME_WIN_GLASS: 1.829 + case NS_THEME_WIN_BORDERLESS_GLASS: 1.830 + return nsUXThemeData::GetTheme(eUXWindowFrame); 1.831 + } 1.832 + return nullptr; 1.833 +} 1.834 + 1.835 +int32_t 1.836 +nsNativeThemeWin::StandardGetState(nsIFrame* aFrame, uint8_t aWidgetType, 1.837 + bool wantFocused) 1.838 +{ 1.839 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.840 + if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) 1.841 + return TS_ACTIVE; 1.842 + if (eventState.HasState(NS_EVENT_STATE_HOVER)) 1.843 + return TS_HOVER; 1.844 + if (wantFocused && eventState.HasState(NS_EVENT_STATE_FOCUS)) 1.845 + return TS_FOCUSED; 1.846 + 1.847 + return TS_NORMAL; 1.848 +} 1.849 + 1.850 +bool 1.851 +nsNativeThemeWin::IsMenuActive(nsIFrame *aFrame, uint8_t aWidgetType) 1.852 +{ 1.853 + nsIContent* content = aFrame->GetContent(); 1.854 + if (content->IsXUL() && 1.855 + content->NodeInfo()->Equals(nsGkAtoms::richlistitem)) 1.856 + return CheckBooleanAttr(aFrame, nsGkAtoms::selected); 1.857 + 1.858 + return CheckBooleanAttr(aFrame, nsGkAtoms::menuactive); 1.859 +} 1.860 + 1.861 +/** 1.862 + * aPart is filled in with the UXTheme part code. On return, values > 0 1.863 + * are the actual UXTheme part code; -1 means the widget will be drawn by 1.864 + * us; 0 means that we should use part code 0, which isn't a real part code 1.865 + * but elicits some kind of default behaviour from UXTheme when drawing 1.866 + * (but isThemeBackgroundPartiallyTransparent may not work). 1.867 + */ 1.868 +nsresult 1.869 +nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType, 1.870 + int32_t& aPart, int32_t& aState) 1.871 +{ 1.872 + if (!IsVistaOrLater()) { 1.873 + // See GetTheme 1.874 + if (aWidgetType == NS_THEME_DROPDOWN) 1.875 + aWidgetType = NS_THEME_TEXTFIELD; 1.876 + } 1.877 + 1.878 + switch (aWidgetType) { 1.879 + case NS_THEME_BUTTON: { 1.880 + aPart = BP_BUTTON; 1.881 + if (!aFrame) { 1.882 + aState = TS_NORMAL; 1.883 + return NS_OK; 1.884 + } 1.885 + 1.886 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.887 + if (IsDisabled(aFrame, eventState)) { 1.888 + aState = TS_DISABLED; 1.889 + return NS_OK; 1.890 + } else if (IsOpenButton(aFrame) || 1.891 + IsCheckedButton(aFrame)) { 1.892 + aState = TS_ACTIVE; 1.893 + return NS_OK; 1.894 + } 1.895 + 1.896 + aState = StandardGetState(aFrame, aWidgetType, true); 1.897 + 1.898 + // Check for default dialog buttons. These buttons should always look 1.899 + // focused. 1.900 + if (aState == TS_NORMAL && IsDefaultButton(aFrame)) 1.901 + aState = TS_FOCUSED; 1.902 + return NS_OK; 1.903 + } 1.904 + case NS_THEME_CHECKBOX: 1.905 + case NS_THEME_RADIO: { 1.906 + bool isCheckbox = (aWidgetType == NS_THEME_CHECKBOX); 1.907 + aPart = isCheckbox ? BP_CHECKBOX : BP_RADIO; 1.908 + 1.909 + enum InputState { 1.910 + UNCHECKED = 0, CHECKED, INDETERMINATE 1.911 + }; 1.912 + InputState inputState = UNCHECKED; 1.913 + bool isXULCheckboxRadio = false; 1.914 + 1.915 + if (!aFrame) { 1.916 + aState = TS_NORMAL; 1.917 + } else { 1.918 + if (GetCheckedOrSelected(aFrame, !isCheckbox)) { 1.919 + inputState = CHECKED; 1.920 + } if (isCheckbox && GetIndeterminate(aFrame)) { 1.921 + inputState = INDETERMINATE; 1.922 + } 1.923 + 1.924 + EventStates eventState = 1.925 + GetContentState(isXULCheckboxRadio ? aFrame->GetParent() : aFrame, 1.926 + aWidgetType); 1.927 + if (IsDisabled(aFrame, eventState)) { 1.928 + aState = TS_DISABLED; 1.929 + } else { 1.930 + aState = StandardGetState(aFrame, aWidgetType, false); 1.931 + } 1.932 + } 1.933 + 1.934 + // 4 unchecked states, 4 checked states, 4 indeterminate states. 1.935 + aState += inputState * 4; 1.936 + return NS_OK; 1.937 + } 1.938 + case NS_THEME_GROUPBOX: { 1.939 + aPart = BP_GROUPBOX; 1.940 + aState = TS_NORMAL; 1.941 + // Since we don't support groupbox disabled and GBS_DISABLED looks the 1.942 + // same as GBS_NORMAL don't bother supporting GBS_DISABLED. 1.943 + return NS_OK; 1.944 + } 1.945 + case NS_THEME_NUMBER_INPUT: 1.946 + case NS_THEME_TEXTFIELD: 1.947 + case NS_THEME_TEXTFIELD_MULTILINE: { 1.948 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.949 + 1.950 + if (IsVistaOrLater()) { 1.951 + /* Note: the NOSCROLL type has a rounded corner in each 1.952 + * corner. The more specific HSCROLL, VSCROLL, HVSCROLL types 1.953 + * have side and/or top/bottom edges rendered as straight 1.954 + * horizontal lines with sharp corners to accommodate a 1.955 + * scrollbar. However, the scrollbar gets rendered on top of 1.956 + * this for us, so we don't care, and can just use NOSCROLL 1.957 + * here. 1.958 + */ 1.959 + aPart = TFP_EDITBORDER_NOSCROLL; 1.960 + 1.961 + if (!aFrame) { 1.962 + aState = TFS_EDITBORDER_NORMAL; 1.963 + } else if (IsDisabled(aFrame, eventState)) { 1.964 + aState = TFS_EDITBORDER_DISABLED; 1.965 + } else if (IsReadOnly(aFrame)) { 1.966 + /* no special read-only state */ 1.967 + aState = TFS_EDITBORDER_NORMAL; 1.968 + } else { 1.969 + nsIContent* content = aFrame->GetContent(); 1.970 + 1.971 + /* XUL textboxes don't get focused themselves, because they have child 1.972 + * html:input.. but we can check the XUL focused attributes on them 1.973 + */ 1.974 + if (content && content->IsXUL() && IsFocused(aFrame)) 1.975 + aState = TFS_EDITBORDER_FOCUSED; 1.976 + else if (eventState.HasAtLeastOneOfStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS)) 1.977 + aState = TFS_EDITBORDER_FOCUSED; 1.978 + else if (eventState.HasState(NS_EVENT_STATE_HOVER)) 1.979 + aState = TFS_EDITBORDER_HOVER; 1.980 + else 1.981 + aState = TFS_EDITBORDER_NORMAL; 1.982 + } 1.983 + } else { 1.984 + aPart = TFP_TEXTFIELD; 1.985 + 1.986 + if (!aFrame) 1.987 + aState = TS_NORMAL; 1.988 + else if (IsDisabled(aFrame, eventState)) 1.989 + aState = TS_DISABLED; 1.990 + else if (IsReadOnly(aFrame)) 1.991 + aState = TFS_READONLY; 1.992 + else 1.993 + aState = StandardGetState(aFrame, aWidgetType, true); 1.994 + } 1.995 + 1.996 + return NS_OK; 1.997 + } 1.998 + case NS_THEME_TOOLTIP: { 1.999 + aPart = TTP_STANDARD; 1.1000 + aState = TS_NORMAL; 1.1001 + return NS_OK; 1.1002 + } 1.1003 + case NS_THEME_PROGRESSBAR: 1.1004 + case NS_THEME_PROGRESSBAR_VERTICAL: { 1.1005 + // Note IsVerticalProgress only tests for orient css attrribute, 1.1006 + // NS_THEME_PROGRESSBAR_VERTICAL is dedicated to -moz-appearance: 1.1007 + // progressbar-vertical. 1.1008 + bool vertical = IsVerticalProgress(aFrame) || 1.1009 + aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL; 1.1010 + aPart = vertical ? PP_BARVERT : PP_BAR; 1.1011 + aState = PBBS_NORMAL; 1.1012 + return NS_OK; 1.1013 + } 1.1014 + case NS_THEME_PROGRESSBAR_CHUNK: 1.1015 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: { 1.1016 + nsIFrame* parentFrame = aFrame->GetParent(); 1.1017 + EventStates eventStates = GetContentState(parentFrame, aWidgetType); 1.1018 + if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL || 1.1019 + IsVerticalProgress(parentFrame)) { 1.1020 + aPart = IsVistaOrLater() ? 1.1021 + PP_FILLVERT : PP_CHUNKVERT; 1.1022 + } else { 1.1023 + aPart = IsVistaOrLater() ? 1.1024 + PP_FILL : PP_CHUNK; 1.1025 + } 1.1026 + 1.1027 + aState = PBBVS_NORMAL; 1.1028 + return NS_OK; 1.1029 + } 1.1030 + case NS_THEME_TOOLBAR_BUTTON: { 1.1031 + aPart = BP_BUTTON; 1.1032 + if (!aFrame) { 1.1033 + aState = TS_NORMAL; 1.1034 + return NS_OK; 1.1035 + } 1.1036 + 1.1037 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1038 + if (IsDisabled(aFrame, eventState)) { 1.1039 + aState = TS_DISABLED; 1.1040 + return NS_OK; 1.1041 + } 1.1042 + if (IsOpenButton(aFrame)) { 1.1043 + aState = TS_ACTIVE; 1.1044 + return NS_OK; 1.1045 + } 1.1046 + 1.1047 + if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) 1.1048 + aState = TS_ACTIVE; 1.1049 + else if (eventState.HasState(NS_EVENT_STATE_HOVER)) { 1.1050 + if (IsCheckedButton(aFrame)) 1.1051 + aState = TB_HOVER_CHECKED; 1.1052 + else 1.1053 + aState = TS_HOVER; 1.1054 + } 1.1055 + else { 1.1056 + if (IsCheckedButton(aFrame)) 1.1057 + aState = TB_CHECKED; 1.1058 + else 1.1059 + aState = TS_NORMAL; 1.1060 + } 1.1061 + 1.1062 + return NS_OK; 1.1063 + } 1.1064 + case NS_THEME_TOOLBAR_SEPARATOR: { 1.1065 + aPart = TP_SEPARATOR; 1.1066 + aState = TS_NORMAL; 1.1067 + return NS_OK; 1.1068 + } 1.1069 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.1070 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.1071 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.1072 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: { 1.1073 + aPart = SP_BUTTON; 1.1074 + aState = (aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP)*4; 1.1075 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1076 + if (!aFrame) 1.1077 + aState += TS_NORMAL; 1.1078 + else if (IsDisabled(aFrame, eventState)) 1.1079 + aState += TS_DISABLED; 1.1080 + else { 1.1081 + nsIFrame *parent = aFrame->GetParent(); 1.1082 + EventStates parentState = 1.1083 + GetContentState(parent, parent->StyleDisplay()->mAppearance); 1.1084 + if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) 1.1085 + aState += TS_ACTIVE; 1.1086 + else if (eventState.HasState(NS_EVENT_STATE_HOVER)) 1.1087 + aState += TS_HOVER; 1.1088 + else if (IsVistaOrLater() && 1.1089 + parentState.HasState(NS_EVENT_STATE_HOVER)) 1.1090 + aState = (aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP) + SP_BUTTON_IMPLICIT_HOVER_BASE; 1.1091 + else 1.1092 + aState += TS_NORMAL; 1.1093 + } 1.1094 + return NS_OK; 1.1095 + } 1.1096 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.1097 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: { 1.1098 + aPart = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL) ? 1.1099 + SP_TRACKSTARTHOR : SP_TRACKSTARTVERT; 1.1100 + aState = TS_NORMAL; 1.1101 + return NS_OK; 1.1102 + } 1.1103 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.1104 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: { 1.1105 + aPart = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL) ? 1.1106 + SP_THUMBHOR : SP_THUMBVERT; 1.1107 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1108 + if (!aFrame) 1.1109 + aState = TS_NORMAL; 1.1110 + else if (IsDisabled(aFrame, eventState)) 1.1111 + aState = TS_DISABLED; 1.1112 + else { 1.1113 + if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) // Hover is not also a requirement for 1.1114 + // the thumb, since the drag is not canceled 1.1115 + // when you move outside the thumb. 1.1116 + aState = TS_ACTIVE; 1.1117 + else if (eventState.HasState(NS_EVENT_STATE_HOVER)) 1.1118 + aState = TS_HOVER; 1.1119 + else 1.1120 + aState = TS_NORMAL; 1.1121 + } 1.1122 + return NS_OK; 1.1123 + } 1.1124 + case NS_THEME_RANGE: 1.1125 + case NS_THEME_SCALE_HORIZONTAL: 1.1126 + case NS_THEME_SCALE_VERTICAL: { 1.1127 + if (aWidgetType == NS_THEME_SCALE_HORIZONTAL || 1.1128 + (aWidgetType == NS_THEME_RANGE && 1.1129 + IsRangeHorizontal(aFrame))) { 1.1130 + aPart = TKP_TRACK; 1.1131 + aState = TRS_NORMAL; 1.1132 + } else { 1.1133 + aPart = TKP_TRACKVERT; 1.1134 + aState = TRVS_NORMAL; 1.1135 + } 1.1136 + return NS_OK; 1.1137 + } 1.1138 + case NS_THEME_RANGE_THUMB: 1.1139 + case NS_THEME_SCALE_THUMB_HORIZONTAL: 1.1140 + case NS_THEME_SCALE_THUMB_VERTICAL: { 1.1141 + if (aWidgetType == NS_THEME_RANGE_THUMB) { 1.1142 + if (IsRangeHorizontal(aFrame)) { 1.1143 + aPart = TKP_THUMBBOTTOM; 1.1144 + } else { 1.1145 + aPart = IsFrameRTL(aFrame) ? TKP_THUMBLEFT : TKP_THUMBRIGHT; 1.1146 + } 1.1147 + } else { 1.1148 + aPart = (aWidgetType == NS_THEME_SCALE_THUMB_HORIZONTAL) ? 1.1149 + TKP_THUMB : TKP_THUMBVERT; 1.1150 + } 1.1151 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1152 + if (!aFrame) 1.1153 + aState = TS_NORMAL; 1.1154 + else if (IsDisabled(aFrame, eventState)) { 1.1155 + aState = TKP_DISABLED; 1.1156 + } 1.1157 + else { 1.1158 + if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) // Hover is not also a requirement for 1.1159 + // the thumb, since the drag is not canceled 1.1160 + // when you move outside the thumb. 1.1161 + aState = TS_ACTIVE; 1.1162 + else if (eventState.HasState(NS_EVENT_STATE_FOCUS)) 1.1163 + aState = TKP_FOCUSED; 1.1164 + else if (eventState.HasState(NS_EVENT_STATE_HOVER)) 1.1165 + aState = TS_HOVER; 1.1166 + else 1.1167 + aState = TS_NORMAL; 1.1168 + } 1.1169 + return NS_OK; 1.1170 + } 1.1171 + case NS_THEME_SPINNER_UP_BUTTON: 1.1172 + case NS_THEME_SPINNER_DOWN_BUTTON: { 1.1173 + aPart = (aWidgetType == NS_THEME_SPINNER_UP_BUTTON) ? 1.1174 + SPNP_UP : SPNP_DOWN; 1.1175 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1176 + if (!aFrame) 1.1177 + aState = TS_NORMAL; 1.1178 + else if (IsDisabled(aFrame, eventState)) 1.1179 + aState = TS_DISABLED; 1.1180 + else 1.1181 + aState = StandardGetState(aFrame, aWidgetType, false); 1.1182 + return NS_OK; 1.1183 + } 1.1184 + case NS_THEME_TOOLBOX: 1.1185 + case NS_THEME_WIN_MEDIA_TOOLBOX: 1.1186 + case NS_THEME_WIN_COMMUNICATIONS_TOOLBOX: 1.1187 + case NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX: 1.1188 + case NS_THEME_STATUSBAR: 1.1189 + case NS_THEME_SCROLLBAR: 1.1190 + case NS_THEME_SCROLLBAR_SMALL: { 1.1191 + aState = 0; 1.1192 + if (IsVistaOrLater()) { 1.1193 + // On vista, they have a part 1.1194 + aPart = RP_BACKGROUND; 1.1195 + } else { 1.1196 + // Otherwise, they don't. (But I bet 1.1197 + // RP_BACKGROUND would work here, too); 1.1198 + aPart = 0; 1.1199 + } 1.1200 + return NS_OK; 1.1201 + } 1.1202 + case NS_THEME_TOOLBAR: { 1.1203 + // Use -1 to indicate we don't wish to have the theme background drawn 1.1204 + // for this item. We will pass any nessessary information via aState, 1.1205 + // and will render the item using separate code. 1.1206 + aPart = -1; 1.1207 + aState = 0; 1.1208 + if (aFrame) { 1.1209 + nsIContent* content = aFrame->GetContent(); 1.1210 + nsIContent* parent = content->GetParent(); 1.1211 + // XXXzeniko hiding the first toolbar will result in an unwanted margin 1.1212 + if (parent && parent->GetFirstChild() == content) { 1.1213 + aState = 1; 1.1214 + } 1.1215 + } 1.1216 + return NS_OK; 1.1217 + } 1.1218 + case NS_THEME_STATUSBAR_PANEL: 1.1219 + case NS_THEME_STATUSBAR_RESIZER_PANEL: 1.1220 + case NS_THEME_RESIZER: { 1.1221 + aPart = (aWidgetType - NS_THEME_STATUSBAR_PANEL) + 1; 1.1222 + aState = TS_NORMAL; 1.1223 + return NS_OK; 1.1224 + } 1.1225 + case NS_THEME_TREEVIEW: 1.1226 + case NS_THEME_LISTBOX: { 1.1227 + aPart = TREEVIEW_BODY; 1.1228 + aState = TS_NORMAL; 1.1229 + return NS_OK; 1.1230 + } 1.1231 + case NS_THEME_TAB_PANELS: { 1.1232 + aPart = TABP_PANELS; 1.1233 + aState = TS_NORMAL; 1.1234 + return NS_OK; 1.1235 + } 1.1236 + case NS_THEME_TAB_PANEL: { 1.1237 + aPart = TABP_PANEL; 1.1238 + aState = TS_NORMAL; 1.1239 + return NS_OK; 1.1240 + } 1.1241 + case NS_THEME_TAB: { 1.1242 + aPart = TABP_TAB; 1.1243 + if (!aFrame) { 1.1244 + aState = TS_NORMAL; 1.1245 + return NS_OK; 1.1246 + } 1.1247 + 1.1248 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1249 + if (IsDisabled(aFrame, eventState)) { 1.1250 + aState = TS_DISABLED; 1.1251 + return NS_OK; 1.1252 + } 1.1253 + 1.1254 + if (IsSelectedTab(aFrame)) { 1.1255 + aPart = TABP_TAB_SELECTED; 1.1256 + aState = TS_ACTIVE; // The selected tab is always "pressed". 1.1257 + } 1.1258 + else 1.1259 + aState = StandardGetState(aFrame, aWidgetType, true); 1.1260 + 1.1261 + return NS_OK; 1.1262 + } 1.1263 + case NS_THEME_TREEVIEW_HEADER_SORTARROW: { 1.1264 + // XXX Probably will never work due to a bug in the Luna theme. 1.1265 + aPart = 4; 1.1266 + aState = 1; 1.1267 + return NS_OK; 1.1268 + } 1.1269 + case NS_THEME_TREEVIEW_HEADER_CELL: { 1.1270 + aPart = 1; 1.1271 + if (!aFrame) { 1.1272 + aState = TS_NORMAL; 1.1273 + return NS_OK; 1.1274 + } 1.1275 + 1.1276 + aState = StandardGetState(aFrame, aWidgetType, true); 1.1277 + 1.1278 + return NS_OK; 1.1279 + } 1.1280 + case NS_THEME_DROPDOWN: { 1.1281 + nsIContent* content = aFrame->GetContent(); 1.1282 + bool isHTML = content && content->IsHTML(); 1.1283 + bool useDropBorder = isHTML || IsMenuListEditable(aFrame); 1.1284 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1285 + 1.1286 + /* On Vista/Win7, we use CBP_DROPBORDER instead of DROPFRAME for HTML 1.1287 + * content or for editable menulists; this gives us the thin outline, 1.1288 + * instead of the gradient-filled background */ 1.1289 + if (useDropBorder) 1.1290 + aPart = CBP_DROPBORDER; 1.1291 + else 1.1292 + aPart = CBP_DROPFRAME; 1.1293 + 1.1294 + if (IsDisabled(aFrame, eventState)) { 1.1295 + aState = TS_DISABLED; 1.1296 + } else if (IsReadOnly(aFrame)) { 1.1297 + aState = TS_NORMAL; 1.1298 + } else if (IsOpenButton(aFrame)) { 1.1299 + aState = TS_ACTIVE; 1.1300 + } else { 1.1301 + if (useDropBorder && (eventState.HasState(NS_EVENT_STATE_FOCUS) || IsFocused(aFrame))) 1.1302 + aState = TS_ACTIVE; 1.1303 + else if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) 1.1304 + aState = TS_ACTIVE; 1.1305 + else if (eventState.HasState(NS_EVENT_STATE_HOVER)) 1.1306 + aState = TS_HOVER; 1.1307 + else 1.1308 + aState = TS_NORMAL; 1.1309 + } 1.1310 + 1.1311 + return NS_OK; 1.1312 + } 1.1313 + case NS_THEME_DROPDOWN_BUTTON: { 1.1314 + bool isHTML = IsHTMLContent(aFrame); 1.1315 + nsIFrame* parentFrame = aFrame->GetParent(); 1.1316 + bool isMenulist = !isHTML && parentFrame->GetType() == nsGkAtoms::menuFrame; 1.1317 + bool isOpen = false; 1.1318 + 1.1319 + // HTML select and XUL menulist dropdown buttons get state from the parent. 1.1320 + if (isHTML || isMenulist) 1.1321 + aFrame = parentFrame; 1.1322 + 1.1323 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1324 + aPart = IsVistaOrLater() ? 1.1325 + CBP_DROPMARKER_VISTA : CBP_DROPMARKER; 1.1326 + 1.1327 + // For HTML controls with author styling, we should fall 1.1328 + // back to the old dropmarker style to avoid clashes with 1.1329 + // author-specified backgrounds and borders (bug #441034) 1.1330 + if (isHTML && IsWidgetStyled(aFrame->PresContext(), aFrame, NS_THEME_DROPDOWN)) 1.1331 + aPart = CBP_DROPMARKER; 1.1332 + 1.1333 + if (IsDisabled(aFrame, eventState)) { 1.1334 + aState = TS_DISABLED; 1.1335 + return NS_OK; 1.1336 + } 1.1337 + 1.1338 + if (isHTML) { 1.1339 + nsIComboboxControlFrame* ccf = do_QueryFrame(aFrame); 1.1340 + isOpen = (ccf && ccf->IsDroppedDown()); 1.1341 + } 1.1342 + else 1.1343 + isOpen = IsOpenButton(aFrame); 1.1344 + 1.1345 + if (IsVistaOrLater()) { 1.1346 + if (isHTML || IsMenuListEditable(aFrame)) { 1.1347 + if (isOpen) { 1.1348 + /* Hover is propagated, but we need to know whether we're 1.1349 + * hovering just the combobox frame, not the dropdown frame. 1.1350 + * But, we can't get that information, since hover is on the 1.1351 + * content node, and they share the same content node. So, 1.1352 + * instead, we cheat -- if the dropdown is open, we always 1.1353 + * show the hover state. This looks fine in practice. 1.1354 + */ 1.1355 + aState = TS_HOVER; 1.1356 + return NS_OK; 1.1357 + } 1.1358 + } else { 1.1359 + /* On Vista, the dropdown indicator on a menulist button in 1.1360 + * chrome is not given a hover effect. When the frame isn't 1.1361 + * isn't HTML content, we cheat and force the dropdown state 1.1362 + * to be normal. (Bug 430434) 1.1363 + */ 1.1364 + aState = TS_NORMAL; 1.1365 + return NS_OK; 1.1366 + } 1.1367 + } 1.1368 + 1.1369 + aState = TS_NORMAL; 1.1370 + 1.1371 + // Dropdown button active state doesn't need :hover. 1.1372 + if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) { 1.1373 + if (isOpen && (isHTML || isMenulist)) { 1.1374 + // XXX Button should look active until the mouse is released, but 1.1375 + // without making it look active when the popup is clicked. 1.1376 + return NS_OK; 1.1377 + } 1.1378 + aState = TS_ACTIVE; 1.1379 + } 1.1380 + else if (eventState.HasState(NS_EVENT_STATE_HOVER)) { 1.1381 + // No hover effect for XUL menulists and autocomplete dropdown buttons 1.1382 + // while the dropdown menu is open. 1.1383 + if (isOpen) { 1.1384 + // XXX HTML select dropdown buttons should have the hover effect when 1.1385 + // hovering the combobox frame, but not the popup frame. 1.1386 + return NS_OK; 1.1387 + } 1.1388 + aState = TS_HOVER; 1.1389 + } 1.1390 + return NS_OK; 1.1391 + } 1.1392 + case NS_THEME_MENUPOPUP: { 1.1393 + aPart = MENU_POPUPBACKGROUND; 1.1394 + aState = MB_ACTIVE; 1.1395 + return NS_OK; 1.1396 + } 1.1397 + case NS_THEME_MENUITEM: 1.1398 + case NS_THEME_CHECKMENUITEM: 1.1399 + case NS_THEME_RADIOMENUITEM: { 1.1400 + bool isTopLevel = false; 1.1401 + bool isOpen = false; 1.1402 + bool isHover = false; 1.1403 + nsMenuFrame *menuFrame = do_QueryFrame(aFrame); 1.1404 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1405 + 1.1406 + isTopLevel = IsTopLevelMenu(aFrame); 1.1407 + 1.1408 + if (menuFrame) 1.1409 + isOpen = menuFrame->IsOpen(); 1.1410 + 1.1411 + isHover = IsMenuActive(aFrame, aWidgetType); 1.1412 + 1.1413 + if (isTopLevel) { 1.1414 + aPart = MENU_BARITEM; 1.1415 + 1.1416 + if (isOpen) 1.1417 + aState = MBI_PUSHED; 1.1418 + else if (isHover) 1.1419 + aState = MBI_HOT; 1.1420 + else 1.1421 + aState = MBI_NORMAL; 1.1422 + 1.1423 + // the disabled states are offset by 3 1.1424 + if (IsDisabled(aFrame, eventState)) 1.1425 + aState += 3; 1.1426 + } else { 1.1427 + aPart = MENU_POPUPITEM; 1.1428 + 1.1429 + if (isHover) 1.1430 + aState = MPI_HOT; 1.1431 + else 1.1432 + aState = MPI_NORMAL; 1.1433 + 1.1434 + // the disabled states are offset by 2 1.1435 + if (IsDisabled(aFrame, eventState)) 1.1436 + aState += 2; 1.1437 + } 1.1438 + 1.1439 + return NS_OK; 1.1440 + } 1.1441 + case NS_THEME_MENUSEPARATOR: 1.1442 + aPart = MENU_POPUPSEPARATOR; 1.1443 + aState = 0; 1.1444 + return NS_OK; 1.1445 + case NS_THEME_MENUARROW: 1.1446 + { 1.1447 + aPart = MENU_POPUPSUBMENU; 1.1448 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1449 + aState = IsDisabled(aFrame, eventState) ? MSM_DISABLED : MSM_NORMAL; 1.1450 + return NS_OK; 1.1451 + } 1.1452 + case NS_THEME_MENUCHECKBOX: 1.1453 + case NS_THEME_MENURADIO: 1.1454 + { 1.1455 + bool isChecked; 1.1456 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1457 + 1.1458 + // NOTE: we can probably use NS_EVENT_STATE_CHECKED 1.1459 + isChecked = CheckBooleanAttr(aFrame, nsGkAtoms::checked); 1.1460 + 1.1461 + aPart = MENU_POPUPCHECK; 1.1462 + aState = MC_CHECKMARKNORMAL; 1.1463 + 1.1464 + // Radio states are offset by 2 1.1465 + if (aWidgetType == NS_THEME_MENURADIO) 1.1466 + aState += 2; 1.1467 + 1.1468 + // the disabled states are offset by 1 1.1469 + if (IsDisabled(aFrame, eventState)) 1.1470 + aState += 1; 1.1471 + 1.1472 + return NS_OK; 1.1473 + } 1.1474 + case NS_THEME_MENUITEMTEXT: 1.1475 + case NS_THEME_MENUIMAGE: 1.1476 + aPart = -1; 1.1477 + aState = 0; 1.1478 + return NS_OK; 1.1479 + 1.1480 + case NS_THEME_WINDOW_TITLEBAR: 1.1481 + aPart = mozilla::widget::themeconst::WP_CAPTION; 1.1482 + aState = GetTopLevelWindowActiveState(aFrame); 1.1483 + return NS_OK; 1.1484 + case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: 1.1485 + aPart = mozilla::widget::themeconst::WP_MAXCAPTION; 1.1486 + aState = GetTopLevelWindowActiveState(aFrame); 1.1487 + return NS_OK; 1.1488 + case NS_THEME_WINDOW_FRAME_LEFT: 1.1489 + aPart = mozilla::widget::themeconst::WP_FRAMELEFT; 1.1490 + aState = GetTopLevelWindowActiveState(aFrame); 1.1491 + return NS_OK; 1.1492 + case NS_THEME_WINDOW_FRAME_RIGHT: 1.1493 + aPart = mozilla::widget::themeconst::WP_FRAMERIGHT; 1.1494 + aState = GetTopLevelWindowActiveState(aFrame); 1.1495 + return NS_OK; 1.1496 + case NS_THEME_WINDOW_FRAME_BOTTOM: 1.1497 + aPart = mozilla::widget::themeconst::WP_FRAMEBOTTOM; 1.1498 + aState = GetTopLevelWindowActiveState(aFrame); 1.1499 + return NS_OK; 1.1500 + case NS_THEME_WINDOW_BUTTON_CLOSE: 1.1501 + aPart = mozilla::widget::themeconst::WP_CLOSEBUTTON; 1.1502 + aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); 1.1503 + return NS_OK; 1.1504 + case NS_THEME_WINDOW_BUTTON_MINIMIZE: 1.1505 + aPart = mozilla::widget::themeconst::WP_MINBUTTON; 1.1506 + aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); 1.1507 + return NS_OK; 1.1508 + case NS_THEME_WINDOW_BUTTON_MAXIMIZE: 1.1509 + aPart = mozilla::widget::themeconst::WP_MAXBUTTON; 1.1510 + aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); 1.1511 + return NS_OK; 1.1512 + case NS_THEME_WINDOW_BUTTON_RESTORE: 1.1513 + aPart = mozilla::widget::themeconst::WP_RESTOREBUTTON; 1.1514 + aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); 1.1515 + return NS_OK; 1.1516 + case NS_THEME_WINDOW_BUTTON_BOX: 1.1517 + case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: 1.1518 + case NS_THEME_WIN_GLASS: 1.1519 + case NS_THEME_WIN_BORDERLESS_GLASS: 1.1520 + aPart = -1; 1.1521 + aState = 0; 1.1522 + return NS_OK; 1.1523 + } 1.1524 + 1.1525 + aPart = 0; 1.1526 + aState = 0; 1.1527 + return NS_ERROR_FAILURE; 1.1528 +} 1.1529 + 1.1530 +static bool 1.1531 +AssumeThemePartAndStateAreTransparent(int32_t aPart, int32_t aState) 1.1532 +{ 1.1533 + if (aPart == MENU_POPUPITEM && aState == MBI_NORMAL) { 1.1534 + return true; 1.1535 + } 1.1536 + return false; 1.1537 +} 1.1538 + 1.1539 +NS_IMETHODIMP 1.1540 +nsNativeThemeWin::DrawWidgetBackground(nsRenderingContext* aContext, 1.1541 + nsIFrame* aFrame, 1.1542 + uint8_t aWidgetType, 1.1543 + const nsRect& aRect, 1.1544 + const nsRect& aDirtyRect) 1.1545 +{ 1.1546 + HANDLE theme = GetTheme(aWidgetType); 1.1547 + if (!theme) 1.1548 + return ClassicDrawWidgetBackground(aContext, aFrame, aWidgetType, aRect, aDirtyRect); 1.1549 + 1.1550 + // ^^ without the right sdk, assume xp theming and fall through. 1.1551 + if (nsUXThemeData::CheckForCompositor()) { 1.1552 + switch (aWidgetType) { 1.1553 + case NS_THEME_WINDOW_TITLEBAR: 1.1554 + case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: 1.1555 + case NS_THEME_WINDOW_FRAME_LEFT: 1.1556 + case NS_THEME_WINDOW_FRAME_RIGHT: 1.1557 + case NS_THEME_WINDOW_FRAME_BOTTOM: 1.1558 + // Nothing to draw, these areas are glass. Minimum dimensions 1.1559 + // should be set, so xul content should be layed out correctly. 1.1560 + return NS_OK; 1.1561 + break; 1.1562 + case NS_THEME_WINDOW_BUTTON_CLOSE: 1.1563 + case NS_THEME_WINDOW_BUTTON_MINIMIZE: 1.1564 + case NS_THEME_WINDOW_BUTTON_MAXIMIZE: 1.1565 + case NS_THEME_WINDOW_BUTTON_RESTORE: 1.1566 + // Not conventional bitmaps, can't be retrieved. If we fall 1.1567 + // through here and call the theme library we'll get aero 1.1568 + // basic bitmaps. 1.1569 + return NS_OK; 1.1570 + break; 1.1571 + case NS_THEME_WIN_GLASS: 1.1572 + case NS_THEME_WIN_BORDERLESS_GLASS: 1.1573 + // Nothing to draw, this is the glass background. 1.1574 + return NS_OK; 1.1575 + case NS_THEME_WINDOW_BUTTON_BOX: 1.1576 + case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: 1.1577 + // We handle these through nsIWidget::UpdateThemeGeometries 1.1578 + return NS_OK; 1.1579 + break; 1.1580 + } 1.1581 + } 1.1582 + 1.1583 + int32_t part, state; 1.1584 + nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); 1.1585 + if (NS_FAILED(rv)) 1.1586 + return rv; 1.1587 + 1.1588 + if (AssumeThemePartAndStateAreTransparent(part, state)) { 1.1589 + return NS_OK; 1.1590 + } 1.1591 + 1.1592 + gfxFloat p2a = gfxFloat(aContext->AppUnitsPerDevPixel()); 1.1593 + RECT widgetRect; 1.1594 + RECT clipRect; 1.1595 + gfxRect tr(aRect.x, aRect.y, aRect.width, aRect.height), 1.1596 + dr(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); 1.1597 + 1.1598 + tr.ScaleInverse(p2a); 1.1599 + dr.ScaleInverse(p2a); 1.1600 + 1.1601 + nsRefPtr<gfxContext> ctx = aContext->ThebesContext(); 1.1602 + 1.1603 + gfxWindowsNativeDrawing nativeDrawing(ctx, dr, GetWidgetNativeDrawingFlags(aWidgetType)); 1.1604 + 1.1605 +RENDER_AGAIN: 1.1606 + 1.1607 + HDC hdc = nativeDrawing.BeginNativeDrawing(); 1.1608 + if (!hdc) 1.1609 + return NS_ERROR_FAILURE; 1.1610 + 1.1611 + nativeDrawing.TransformToNativeRect(tr, widgetRect); 1.1612 + nativeDrawing.TransformToNativeRect(dr, clipRect); 1.1613 + 1.1614 +#if 0 1.1615 + { 1.1616 + PR_LOG(gWindowsLog, PR_LOG_ERROR, 1.1617 + (stderr, "xform: %f %f %f %f [%f %f]\n", m.xx, m.yx, m.xy, m.yy, 1.1618 + m.x0, m.y0)); 1.1619 + PR_LOG(gWindowsLog, PR_LOG_ERROR, 1.1620 + (stderr, "tr: [%d %d %d %d]\ndr: [%d %d %d %d]\noff: [%f %f]\n", 1.1621 + tr.x, tr.y, tr.width, tr.height, dr.x, dr.y, dr.width, dr.height, 1.1622 + offset.x, offset.y)); 1.1623 + } 1.1624 +#endif 1.1625 + 1.1626 + if (aWidgetType == NS_THEME_WINDOW_TITLEBAR) { 1.1627 + // Clip out the left and right corners of the frame, all we want in 1.1628 + // is the middle section. 1.1629 + widgetRect.left -= GetSystemMetrics(SM_CXFRAME); 1.1630 + widgetRect.right += GetSystemMetrics(SM_CXFRAME); 1.1631 + } else if (aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) { 1.1632 + // The origin of the window is off screen when maximized and windows 1.1633 + // doesn't compensate for this in rendering the background. Push the 1.1634 + // top of the bitmap down by SM_CYFRAME so we get the full graphic. 1.1635 + widgetRect.top += GetSystemMetrics(SM_CYFRAME); 1.1636 + } else if (aWidgetType == NS_THEME_TAB) { 1.1637 + // For left edge and right edge tabs, we need to adjust the widget 1.1638 + // rects and clip rects so that the edges don't get drawn. 1.1639 + bool isLeft = IsLeftToSelectedTab(aFrame); 1.1640 + bool isRight = !isLeft && IsRightToSelectedTab(aFrame); 1.1641 + 1.1642 + if (isLeft || isRight) { 1.1643 + // HACK ALERT: There appears to be no way to really obtain this value, so we're forced 1.1644 + // to just use the default value for Luna (which also happens to be correct for 1.1645 + // all the other skins I've tried). 1.1646 + int32_t edgeSize = 2; 1.1647 + 1.1648 + // Armed with the size of the edge, we now need to either shift to the left or to the 1.1649 + // right. The clip rect won't include this extra area, so we know that we're 1.1650 + // effectively shifting the edge out of view (such that it won't be painted). 1.1651 + if (isLeft) 1.1652 + // The right edge should not be drawn. Extend our rect by the edge size. 1.1653 + widgetRect.right += edgeSize; 1.1654 + else 1.1655 + // The left edge should not be drawn. Move the widget rect's left coord back. 1.1656 + widgetRect.left -= edgeSize; 1.1657 + } 1.1658 + } 1.1659 + else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) { 1.1660 + OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_MINIMIZE); 1.1661 + } 1.1662 + else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE || 1.1663 + aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { 1.1664 + OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_RESTORE); 1.1665 + } 1.1666 + else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) { 1.1667 + OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_CLOSE); 1.1668 + } 1.1669 + 1.1670 + // widgetRect is the bounding box for a widget, yet the scale track is only 1.1671 + // a small portion of this size, so the edges of the scale need to be 1.1672 + // adjusted to the real size of the track. 1.1673 + if (aWidgetType == NS_THEME_RANGE || 1.1674 + aWidgetType == NS_THEME_SCALE_HORIZONTAL || 1.1675 + aWidgetType == NS_THEME_SCALE_VERTICAL) { 1.1676 + RECT contentRect; 1.1677 + GetThemeBackgroundContentRect(theme, hdc, part, state, &widgetRect, &contentRect); 1.1678 + 1.1679 + SIZE siz; 1.1680 + GetThemePartSize(theme, hdc, part, state, &widgetRect, TS_TRUE, &siz); 1.1681 + 1.1682 + // When rounding is necessary, we round the position of the track 1.1683 + // away from the chevron of the thumb to make it look better. 1.1684 + if (aWidgetType == NS_THEME_SCALE_HORIZONTAL || 1.1685 + (aWidgetType == NS_THEME_RANGE && IsRangeHorizontal(aFrame))) { 1.1686 + contentRect.top += (contentRect.bottom - contentRect.top - siz.cy) / 2; 1.1687 + contentRect.bottom = contentRect.top + siz.cy; 1.1688 + } 1.1689 + else { 1.1690 + if (!IsFrameRTL(aFrame)) { 1.1691 + contentRect.left += (contentRect.right - contentRect.left - siz.cx) / 2; 1.1692 + contentRect.right = contentRect.left + siz.cx; 1.1693 + } else { 1.1694 + contentRect.right -= (contentRect.right - contentRect.left - siz.cx) / 2; 1.1695 + contentRect.left = contentRect.right - siz.cx; 1.1696 + } 1.1697 + } 1.1698 + 1.1699 + DrawThemeBackground(theme, hdc, part, state, &contentRect, &clipRect); 1.1700 + } 1.1701 + else if (aWidgetType == NS_THEME_MENUCHECKBOX || aWidgetType == NS_THEME_MENURADIO) 1.1702 + { 1.1703 + bool isChecked = false; 1.1704 + isChecked = CheckBooleanAttr(aFrame, nsGkAtoms::checked); 1.1705 + 1.1706 + if (isChecked) 1.1707 + { 1.1708 + int bgState = MCB_NORMAL; 1.1709 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.1710 + 1.1711 + // the disabled states are offset by 1 1.1712 + if (IsDisabled(aFrame, eventState)) 1.1713 + bgState += 1; 1.1714 + 1.1715 + SIZE checkboxBGSize(GetCheckboxBGSize(theme, hdc)); 1.1716 + 1.1717 + RECT checkBGRect = widgetRect; 1.1718 + if (IsFrameRTL(aFrame)) { 1.1719 + checkBGRect.left = checkBGRect.right-checkboxBGSize.cx; 1.1720 + } else { 1.1721 + checkBGRect.right = checkBGRect.left+checkboxBGSize.cx; 1.1722 + } 1.1723 + 1.1724 + // Center the checkbox background vertically in the menuitem 1.1725 + checkBGRect.top += (checkBGRect.bottom - checkBGRect.top)/2 - checkboxBGSize.cy/2; 1.1726 + checkBGRect.bottom = checkBGRect.top + checkboxBGSize.cy; 1.1727 + 1.1728 + DrawThemeBackground(theme, hdc, MENU_POPUPCHECKBACKGROUND, bgState, &checkBGRect, &clipRect); 1.1729 + 1.1730 + MARGINS checkMargins = GetCheckboxMargins(theme, hdc); 1.1731 + RECT checkRect = checkBGRect; 1.1732 + checkRect.left += checkMargins.cxLeftWidth; 1.1733 + checkRect.right -= checkMargins.cxRightWidth; 1.1734 + checkRect.top += checkMargins.cyTopHeight; 1.1735 + checkRect.bottom -= checkMargins.cyBottomHeight; 1.1736 + DrawThemeBackground(theme, hdc, MENU_POPUPCHECK, state, &checkRect, &clipRect); 1.1737 + } 1.1738 + } 1.1739 + else if (aWidgetType == NS_THEME_MENUPOPUP) 1.1740 + { 1.1741 + DrawThemeBackground(theme, hdc, MENU_POPUPBORDERS, /* state */ 0, &widgetRect, &clipRect); 1.1742 + SIZE borderSize; 1.1743 + GetThemePartSize(theme, hdc, MENU_POPUPBORDERS, 0, nullptr, TS_TRUE, &borderSize); 1.1744 + 1.1745 + RECT bgRect = widgetRect; 1.1746 + bgRect.top += borderSize.cy; 1.1747 + bgRect.bottom -= borderSize.cy; 1.1748 + bgRect.left += borderSize.cx; 1.1749 + bgRect.right -= borderSize.cx; 1.1750 + 1.1751 + DrawThemeBackground(theme, hdc, MENU_POPUPBACKGROUND, /* state */ 0, &bgRect, &clipRect); 1.1752 + 1.1753 + SIZE gutterSize(GetGutterSize(theme, hdc)); 1.1754 + 1.1755 + RECT gutterRect; 1.1756 + gutterRect.top = bgRect.top; 1.1757 + gutterRect.bottom = bgRect.bottom; 1.1758 + if (IsFrameRTL(aFrame)) { 1.1759 + gutterRect.right = bgRect.right; 1.1760 + gutterRect.left = gutterRect.right-gutterSize.cx; 1.1761 + } else { 1.1762 + gutterRect.left = bgRect.left; 1.1763 + gutterRect.right = gutterRect.left+gutterSize.cx; 1.1764 + } 1.1765 + 1.1766 + DrawThemeBGRTLAware(theme, hdc, MENU_POPUPGUTTER, /* state */ 0, 1.1767 + &gutterRect, &clipRect, IsFrameRTL(aFrame)); 1.1768 + } 1.1769 + else if (aWidgetType == NS_THEME_MENUSEPARATOR) 1.1770 + { 1.1771 + SIZE gutterSize(GetGutterSize(theme,hdc)); 1.1772 + 1.1773 + RECT sepRect = widgetRect; 1.1774 + if (IsFrameRTL(aFrame)) 1.1775 + sepRect.right -= gutterSize.cx; 1.1776 + else 1.1777 + sepRect.left += gutterSize.cx; 1.1778 + 1.1779 + DrawThemeBackground(theme, hdc, MENU_POPUPSEPARATOR, /* state */ 0, &sepRect, &clipRect); 1.1780 + } 1.1781 + else if (aWidgetType == NS_THEME_MENUARROW) 1.1782 + { 1.1783 + // We're dpi aware and as such on systems that have dpi > 96 set, the 1.1784 + // theme library expects us to do proper positioning and scaling of glyphs. 1.1785 + // For NS_THEME_MENUARROW, layout may hand us a widget rect larger than the 1.1786 + // glyph rect we request in GetMinimumWidgetSize. To prevent distortion we 1.1787 + // have to position and scale what we draw. 1.1788 + 1.1789 + SIZE glyphSize; 1.1790 + GetThemePartSize(theme, hdc, part, state, nullptr, TS_TRUE, &glyphSize); 1.1791 + 1.1792 + int32_t widgetHeight = widgetRect.bottom - widgetRect.top; 1.1793 + 1.1794 + RECT renderRect = widgetRect; 1.1795 + 1.1796 + // We request (glyph width * 2, glyph height) in GetMinimumWidgetSize. In 1.1797 + // Firefox some menu items provide the full height of the item to us, in 1.1798 + // others our widget rect is the exact dims of our arrow glyph. Adjust the 1.1799 + // vertical position by the added space, if any exists. 1.1800 + renderRect.top += ((widgetHeight - glyphSize.cy) / 2); 1.1801 + renderRect.bottom = renderRect.top + glyphSize.cy; 1.1802 + // I'm using the width of the arrow glyph for the arrow-side padding. 1.1803 + // AFAICT there doesn't appear to be a theme constant we can query 1.1804 + // for this value. Generally this looks correct, and has the added 1.1805 + // benefit of being a dpi adjusted value. 1.1806 + if (!IsFrameRTL(aFrame)) { 1.1807 + renderRect.right = widgetRect.right - glyphSize.cx; 1.1808 + renderRect.left = renderRect.right - glyphSize.cx; 1.1809 + } else { 1.1810 + renderRect.left = glyphSize.cx; 1.1811 + renderRect.right = renderRect.left + glyphSize.cx; 1.1812 + } 1.1813 + DrawThemeBGRTLAware(theme, hdc, part, state, &renderRect, &clipRect, 1.1814 + IsFrameRTL(aFrame)); 1.1815 + } 1.1816 + // The following widgets need to be RTL-aware 1.1817 + else if (aWidgetType == NS_THEME_RESIZER || 1.1818 + aWidgetType == NS_THEME_DROPDOWN_BUTTON) 1.1819 + { 1.1820 + DrawThemeBGRTLAware(theme, hdc, part, state, 1.1821 + &widgetRect, &clipRect, IsFrameRTL(aFrame)); 1.1822 + } 1.1823 + else if (aWidgetType == NS_THEME_PROGRESSBAR || 1.1824 + aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL) { 1.1825 + // DrawThemeBackground renders each corner with a solid white pixel. 1.1826 + // Restore these pixels to the underlying color. Tracks are rendered 1.1827 + // using alpha recovery, so this makes the corners transparent. 1.1828 + COLORREF color; 1.1829 + color = GetPixel(hdc, widgetRect.left, widgetRect.top); 1.1830 + DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect); 1.1831 + SetPixel(hdc, widgetRect.left, widgetRect.top, color); 1.1832 + SetPixel(hdc, widgetRect.right-1, widgetRect.top, color); 1.1833 + SetPixel(hdc, widgetRect.right-1, widgetRect.bottom-1, color); 1.1834 + SetPixel(hdc, widgetRect.left, widgetRect.bottom-1, color); 1.1835 + } 1.1836 + else if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK || 1.1837 + aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL) { 1.1838 + DrawThemedProgressMeter(aFrame, aWidgetType, theme, hdc, part, state, 1.1839 + &widgetRect, &clipRect, p2a); 1.1840 + } 1.1841 + // If part is negative, the element wishes us to not render a themed 1.1842 + // background, instead opting to be drawn specially below. 1.1843 + else if (part >= 0) { 1.1844 + DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect); 1.1845 + } 1.1846 + 1.1847 + // Draw focus rectangles for XP HTML checkboxes and radio buttons 1.1848 + // XXX it'd be nice to draw these outside of the frame 1.1849 + if (((aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO) && 1.1850 + aFrame->GetContent()->IsHTML()) || 1.1851 + aWidgetType == NS_THEME_RANGE || 1.1852 + aWidgetType == NS_THEME_SCALE_HORIZONTAL || 1.1853 + aWidgetType == NS_THEME_SCALE_VERTICAL) { 1.1854 + EventStates contentState = GetContentState(aFrame, aWidgetType); 1.1855 + 1.1856 + if (contentState.HasState(NS_EVENT_STATE_FOCUS)) { 1.1857 + POINT vpOrg; 1.1858 + HPEN hPen = nullptr; 1.1859 + 1.1860 + uint8_t id = SaveDC(hdc); 1.1861 + 1.1862 + ::SelectClipRgn(hdc, nullptr); 1.1863 + ::GetViewportOrgEx(hdc, &vpOrg); 1.1864 + ::SetBrushOrgEx(hdc, vpOrg.x + widgetRect.left, vpOrg.y + widgetRect.top, nullptr); 1.1865 + 1.1866 + // On vista, choose our own colors and draw an XP style half focus rect 1.1867 + // for focused checkboxes and a full rect when active. 1.1868 + if (IsVistaOrLater() && 1.1869 + aWidgetType == NS_THEME_CHECKBOX) { 1.1870 + LOGBRUSH lb; 1.1871 + lb.lbStyle = BS_SOLID; 1.1872 + lb.lbColor = RGB(255,255,255); 1.1873 + lb.lbHatch = 0; 1.1874 + 1.1875 + hPen = ::ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, nullptr); 1.1876 + ::SelectObject(hdc, hPen); 1.1877 + 1.1878 + // If pressed, draw the upper left corner of the dotted rect. 1.1879 + if (contentState.HasState(NS_EVENT_STATE_ACTIVE)) { 1.1880 + ::MoveToEx(hdc, widgetRect.left, widgetRect.bottom-1, nullptr); 1.1881 + ::LineTo(hdc, widgetRect.left, widgetRect.top); 1.1882 + ::LineTo(hdc, widgetRect.right-1, widgetRect.top); 1.1883 + } 1.1884 + 1.1885 + // Draw the lower right corner of the dotted rect. 1.1886 + ::MoveToEx(hdc, widgetRect.right-1, widgetRect.top, nullptr); 1.1887 + ::LineTo(hdc, widgetRect.right-1, widgetRect.bottom-1); 1.1888 + ::LineTo(hdc, widgetRect.left, widgetRect.bottom-1); 1.1889 + } else { 1.1890 + ::SetTextColor(hdc, 0); 1.1891 + ::DrawFocusRect(hdc, &widgetRect); 1.1892 + } 1.1893 + ::RestoreDC(hdc, id); 1.1894 + if (hPen) { 1.1895 + ::DeleteObject(hPen); 1.1896 + } 1.1897 + } 1.1898 + } 1.1899 + else if (aWidgetType == NS_THEME_TOOLBAR && state == 0) { 1.1900 + // Draw toolbar separator lines above all toolbars except the first one. 1.1901 + // The lines are part of the Rebar theme, which is loaded for NS_THEME_TOOLBOX. 1.1902 + theme = GetTheme(NS_THEME_TOOLBOX); 1.1903 + if (!theme) 1.1904 + return NS_ERROR_FAILURE; 1.1905 + 1.1906 + widgetRect.bottom = widgetRect.top + TB_SEPARATOR_HEIGHT; 1.1907 + DrawThemeEdge(theme, hdc, RP_BAND, 0, &widgetRect, EDGE_ETCHED, BF_TOP, nullptr); 1.1908 + } 1.1909 + else if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL || 1.1910 + aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL) 1.1911 + { 1.1912 + // Draw the decorative gripper for the scrollbar thumb button, if it fits 1.1913 + 1.1914 + SIZE gripSize; 1.1915 + MARGINS thumbMgns; 1.1916 + int gripPart = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL) ? 1.1917 + SP_GRIPPERHOR : SP_GRIPPERVERT; 1.1918 + 1.1919 + if (GetThemePartSize(theme, hdc, gripPart, state, nullptr, TS_TRUE, &gripSize) == S_OK && 1.1920 + GetThemeMargins(theme, hdc, part, state, TMT_CONTENTMARGINS, nullptr, &thumbMgns) == S_OK && 1.1921 + gripSize.cx + thumbMgns.cxLeftWidth + thumbMgns.cxRightWidth <= widgetRect.right - widgetRect.left && 1.1922 + gripSize.cy + thumbMgns.cyTopHeight + thumbMgns.cyBottomHeight <= widgetRect.bottom - widgetRect.top) 1.1923 + { 1.1924 + DrawThemeBackground(theme, hdc, gripPart, state, &widgetRect, &clipRect); 1.1925 + } 1.1926 + } 1.1927 + 1.1928 + nativeDrawing.EndNativeDrawing(); 1.1929 + 1.1930 + if (nativeDrawing.ShouldRenderAgain()) 1.1931 + goto RENDER_AGAIN; 1.1932 + 1.1933 + nativeDrawing.PaintToContext(); 1.1934 + 1.1935 + return NS_OK; 1.1936 +} 1.1937 + 1.1938 +NS_IMETHODIMP 1.1939 +nsNativeThemeWin::GetWidgetBorder(nsDeviceContext* aContext, 1.1940 + nsIFrame* aFrame, 1.1941 + uint8_t aWidgetType, 1.1942 + nsIntMargin* aResult) 1.1943 +{ 1.1944 + HANDLE theme = GetTheme(aWidgetType); 1.1945 + if (!theme) 1.1946 + return ClassicGetWidgetBorder(aContext, aFrame, aWidgetType, aResult); 1.1947 + 1.1948 + (*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 0; 1.1949 + 1.1950 + if (!WidgetIsContainer(aWidgetType) || 1.1951 + aWidgetType == NS_THEME_TOOLBOX || 1.1952 + aWidgetType == NS_THEME_WIN_MEDIA_TOOLBOX || 1.1953 + aWidgetType == NS_THEME_WIN_COMMUNICATIONS_TOOLBOX || 1.1954 + aWidgetType == NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX || 1.1955 + aWidgetType == NS_THEME_STATUSBAR || 1.1956 + aWidgetType == NS_THEME_RESIZER || aWidgetType == NS_THEME_TAB_PANEL || 1.1957 + aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL || 1.1958 + aWidgetType == NS_THEME_SCROLLBAR_TRACK_VERTICAL || 1.1959 + aWidgetType == NS_THEME_MENUITEM || aWidgetType == NS_THEME_CHECKMENUITEM || 1.1960 + aWidgetType == NS_THEME_RADIOMENUITEM || aWidgetType == NS_THEME_MENUPOPUP || 1.1961 + aWidgetType == NS_THEME_MENUIMAGE || aWidgetType == NS_THEME_MENUITEMTEXT || 1.1962 + aWidgetType == NS_THEME_TOOLBAR_SEPARATOR || 1.1963 + aWidgetType == NS_THEME_WINDOW_TITLEBAR || 1.1964 + aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED || 1.1965 + aWidgetType == NS_THEME_WIN_GLASS || aWidgetType == NS_THEME_WIN_BORDERLESS_GLASS) 1.1966 + return NS_OK; // Don't worry about it. 1.1967 + 1.1968 + int32_t part, state; 1.1969 + nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); 1.1970 + if (NS_FAILED(rv)) 1.1971 + return rv; 1.1972 + 1.1973 + if (aWidgetType == NS_THEME_TOOLBAR) { 1.1974 + // make space for the separator line above all toolbars but the first 1.1975 + if (state == 0) 1.1976 + aResult->top = TB_SEPARATOR_HEIGHT; 1.1977 + return NS_OK; 1.1978 + } 1.1979 + 1.1980 + // Get our info. 1.1981 + RECT outerRect; // Create a fake outer rect. 1.1982 + outerRect.top = outerRect.left = 100; 1.1983 + outerRect.right = outerRect.bottom = 200; 1.1984 + RECT contentRect(outerRect); 1.1985 + HRESULT res = GetThemeBackgroundContentRect(theme, nullptr, part, state, &outerRect, &contentRect); 1.1986 + 1.1987 + if (FAILED(res)) 1.1988 + return NS_ERROR_FAILURE; 1.1989 + 1.1990 + // Now compute the delta in each direction and place it in our 1.1991 + // nsIntMargin struct. 1.1992 + aResult->top = contentRect.top - outerRect.top; 1.1993 + aResult->bottom = outerRect.bottom - contentRect.bottom; 1.1994 + aResult->left = contentRect.left - outerRect.left; 1.1995 + aResult->right = outerRect.right - contentRect.right; 1.1996 + 1.1997 + // Remove the edges for tabs that are before or after the selected tab, 1.1998 + if (aWidgetType == NS_THEME_TAB) { 1.1999 + if (IsLeftToSelectedTab(aFrame)) 1.2000 + // Remove the right edge, since we won't be drawing it. 1.2001 + aResult->right = 0; 1.2002 + else if (IsRightToSelectedTab(aFrame)) 1.2003 + // Remove the left edge, since we won't be drawing it. 1.2004 + aResult->left = 0; 1.2005 + } 1.2006 + 1.2007 + if (aFrame && (aWidgetType == NS_THEME_NUMBER_INPUT || 1.2008 + aWidgetType == NS_THEME_TEXTFIELD || 1.2009 + aWidgetType == NS_THEME_TEXTFIELD_MULTILINE)) { 1.2010 + nsIContent* content = aFrame->GetContent(); 1.2011 + if (content && content->IsHTML()) { 1.2012 + // We need to pad textfields by 1 pixel, since the caret will draw 1.2013 + // flush against the edge by default if we don't. 1.2014 + aResult->top++; 1.2015 + aResult->left++; 1.2016 + aResult->bottom++; 1.2017 + aResult->right++; 1.2018 + } 1.2019 + } 1.2020 + 1.2021 + return NS_OK; 1.2022 +} 1.2023 + 1.2024 +bool 1.2025 +nsNativeThemeWin::GetWidgetPadding(nsDeviceContext* aContext, 1.2026 + nsIFrame* aFrame, 1.2027 + uint8_t aWidgetType, 1.2028 + nsIntMargin* aResult) 1.2029 +{ 1.2030 + switch (aWidgetType) { 1.2031 + // Radios and checkboxes return a fixed size in GetMinimumWidgetSize 1.2032 + // and have a meaningful baseline, so they can't have 1.2033 + // author-specified padding. 1.2034 + case NS_THEME_CHECKBOX: 1.2035 + case NS_THEME_RADIO: 1.2036 + aResult->SizeTo(0, 0, 0, 0); 1.2037 + return true; 1.2038 + } 1.2039 + 1.2040 + HANDLE theme = GetTheme(aWidgetType); 1.2041 + 1.2042 + if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX || 1.2043 + aWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) { 1.2044 + aResult->SizeTo(0, 0, 0, 0); 1.2045 + 1.2046 + // aero glass doesn't display custom buttons 1.2047 + if (nsUXThemeData::CheckForCompositor()) 1.2048 + return true; 1.2049 + 1.2050 + // button padding for standard windows 1.2051 + if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX) { 1.2052 + aResult->top = GetSystemMetrics(SM_CXFRAME); 1.2053 + } 1.2054 + return true; 1.2055 + } 1.2056 + 1.2057 + // Content padding 1.2058 + if (aWidgetType == NS_THEME_WINDOW_TITLEBAR || 1.2059 + aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) { 1.2060 + aResult->SizeTo(0, 0, 0, 0); 1.2061 + // XXX Maximized windows have an offscreen offset equal to 1.2062 + // the border padding. This should be addressed in nsWindow, 1.2063 + // but currently can't be, see UpdateNonClientMargins. 1.2064 + if (aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) 1.2065 + aResult->top = GetSystemMetrics(SM_CXFRAME) 1.2066 + + GetSystemMetrics(SM_CXPADDEDBORDER); 1.2067 + return true; 1.2068 + } 1.2069 + 1.2070 + if (!theme) 1.2071 + return ClassicGetWidgetPadding(aContext, aFrame, aWidgetType, aResult); 1.2072 + 1.2073 + if (aWidgetType == NS_THEME_MENUPOPUP) 1.2074 + { 1.2075 + SIZE popupSize; 1.2076 + GetThemePartSize(theme, nullptr, MENU_POPUPBORDERS, /* state */ 0, nullptr, TS_TRUE, &popupSize); 1.2077 + aResult->top = aResult->bottom = popupSize.cy; 1.2078 + aResult->left = aResult->right = popupSize.cx; 1.2079 + return true; 1.2080 + } 1.2081 + 1.2082 + if (IsVistaOrLater()) { 1.2083 + if (aWidgetType == NS_THEME_NUMBER_INPUT || 1.2084 + aWidgetType == NS_THEME_TEXTFIELD || 1.2085 + aWidgetType == NS_THEME_TEXTFIELD_MULTILINE || 1.2086 + aWidgetType == NS_THEME_DROPDOWN) 1.2087 + { 1.2088 + /* If we have author-specified padding for these elements, don't do the fixups below */ 1.2089 + if (aFrame->PresContext()->HasAuthorSpecifiedRules(aFrame, NS_AUTHOR_SPECIFIED_PADDING)) 1.2090 + return false; 1.2091 + } 1.2092 + 1.2093 + /* textfields need extra pixels on all sides, otherwise they 1.2094 + * wrap their content too tightly. The actual border is drawn 1px 1.2095 + * inside the specified rectangle, so Gecko will end up making the 1.2096 + * contents look too small. Instead, we add 2px padding for the 1.2097 + * contents and fix this. (Used to be 1px added, see bug 430212) 1.2098 + */ 1.2099 + if (aWidgetType == NS_THEME_NUMBER_INPUT || 1.2100 + aWidgetType == NS_THEME_TEXTFIELD || 1.2101 + aWidgetType == NS_THEME_TEXTFIELD_MULTILINE) { 1.2102 + aResult->top = aResult->bottom = 2; 1.2103 + aResult->left = aResult->right = 2; 1.2104 + return true; 1.2105 + } else if (IsHTMLContent(aFrame) && aWidgetType == NS_THEME_DROPDOWN) { 1.2106 + /* For content menulist controls, we need an extra pixel so 1.2107 + * that we have room to draw our focus rectangle stuff. 1.2108 + * Otherwise, the focus rect might overlap the control's 1.2109 + * border. 1.2110 + */ 1.2111 + aResult->top = aResult->bottom = 1; 1.2112 + aResult->left = aResult->right = 1; 1.2113 + return true; 1.2114 + } 1.2115 + } 1.2116 + 1.2117 + int32_t right, left, top, bottom; 1.2118 + right = left = top = bottom = 0; 1.2119 + switch (aWidgetType) 1.2120 + { 1.2121 + case NS_THEME_MENUIMAGE: 1.2122 + right = 8; 1.2123 + left = 3; 1.2124 + break; 1.2125 + case NS_THEME_MENUCHECKBOX: 1.2126 + case NS_THEME_MENURADIO: 1.2127 + right = 8; 1.2128 + left = 0; 1.2129 + break; 1.2130 + case NS_THEME_MENUITEMTEXT: 1.2131 + // There seem to be exactly 4 pixels from the edge 1.2132 + // of the gutter to the text: 2px margin (CSS) + 2px padding (here) 1.2133 + { 1.2134 + SIZE size(GetGutterSize(theme, nullptr)); 1.2135 + left = size.cx + 2; 1.2136 + } 1.2137 + break; 1.2138 + case NS_THEME_MENUSEPARATOR: 1.2139 + { 1.2140 + SIZE size(GetGutterSize(theme, nullptr)); 1.2141 + left = size.cx + 5; 1.2142 + top = 10; 1.2143 + bottom = 7; 1.2144 + } 1.2145 + break; 1.2146 + default: 1.2147 + return false; 1.2148 + } 1.2149 + 1.2150 + if (IsFrameRTL(aFrame)) 1.2151 + { 1.2152 + aResult->right = left; 1.2153 + aResult->left = right; 1.2154 + } 1.2155 + else 1.2156 + { 1.2157 + aResult->right = right; 1.2158 + aResult->left = left; 1.2159 + } 1.2160 + 1.2161 + return true; 1.2162 +} 1.2163 + 1.2164 +bool 1.2165 +nsNativeThemeWin::GetWidgetOverflow(nsDeviceContext* aContext, 1.2166 + nsIFrame* aFrame, 1.2167 + uint8_t aOverflowRect, 1.2168 + nsRect* aResult) 1.2169 +{ 1.2170 + /* This is disabled for now, because it causes invalidation problems -- 1.2171 + * see bug 420381. The effect of not updating the overflow area is that 1.2172 + * for dropdown buttons in content areas, there is a 1px border on 3 sides 1.2173 + * where, if invalidated, the dropdown control probably won't be repainted. 1.2174 + * This is fairly minor, as by default there is nothing in that area, and 1.2175 + * a border only shows up if the widget is being hovered. 1.2176 + */ 1.2177 +#if 0 1.2178 + if (IsVistaOrLater()) { 1.2179 + /* We explicitly draw dropdown buttons in HTML content 1px bigger 1.2180 + * up, right, and bottom so that they overlap the dropdown's border 1.2181 + * like they're supposed to. 1.2182 + */ 1.2183 + if (aWidgetType == NS_THEME_DROPDOWN_BUTTON && 1.2184 + IsHTMLContent(aFrame) && 1.2185 + !IsWidgetStyled(aFrame->GetParent()->PresContext(), 1.2186 + aFrame->GetParent(), 1.2187 + NS_THEME_DROPDOWN)) 1.2188 + { 1.2189 + int32_t p2a = aContext->AppUnitsPerDevPixel(); 1.2190 + /* Note: no overflow on the left */ 1.2191 + nsMargin m(p2a, p2a, p2a, 0); 1.2192 + aOverflowRect->Inflate (m); 1.2193 + return true; 1.2194 + } 1.2195 + } 1.2196 +#endif 1.2197 + 1.2198 + return false; 1.2199 +} 1.2200 + 1.2201 +NS_IMETHODIMP 1.2202 +nsNativeThemeWin::GetMinimumWidgetSize(nsRenderingContext* aContext, nsIFrame* aFrame, 1.2203 + uint8_t aWidgetType, 1.2204 + nsIntSize* aResult, bool* aIsOverridable) 1.2205 +{ 1.2206 + (*aResult).width = (*aResult).height = 0; 1.2207 + *aIsOverridable = true; 1.2208 + 1.2209 + HANDLE theme = GetTheme(aWidgetType); 1.2210 + if (!theme) 1.2211 + return ClassicGetMinimumWidgetSize(aContext, aFrame, aWidgetType, aResult, aIsOverridable); 1.2212 + 1.2213 + switch (aWidgetType) { 1.2214 + case NS_THEME_GROUPBOX: 1.2215 + case NS_THEME_NUMBER_INPUT: 1.2216 + case NS_THEME_TEXTFIELD: 1.2217 + case NS_THEME_TOOLBOX: 1.2218 + case NS_THEME_WIN_MEDIA_TOOLBOX: 1.2219 + case NS_THEME_WIN_COMMUNICATIONS_TOOLBOX: 1.2220 + case NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX: 1.2221 + case NS_THEME_TOOLBAR: 1.2222 + case NS_THEME_STATUSBAR: 1.2223 + case NS_THEME_PROGRESSBAR_CHUNK: 1.2224 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: 1.2225 + case NS_THEME_TAB_PANELS: 1.2226 + case NS_THEME_TAB_PANEL: 1.2227 + case NS_THEME_LISTBOX: 1.2228 + case NS_THEME_TREEVIEW: 1.2229 + case NS_THEME_MENUITEMTEXT: 1.2230 + case NS_THEME_WIN_GLASS: 1.2231 + case NS_THEME_WIN_BORDERLESS_GLASS: 1.2232 + return NS_OK; // Don't worry about it. 1.2233 + } 1.2234 + 1.2235 + if (aWidgetType == NS_THEME_MENUITEM && IsTopLevelMenu(aFrame)) 1.2236 + return NS_OK; // Don't worry about it for top level menus 1.2237 + 1.2238 + // Call GetSystemMetrics to determine size for WinXP scrollbars 1.2239 + // (GetThemeSysSize API returns the optimal size for the theme, but 1.2240 + // Windows appears to always use metrics when drawing standard scrollbars) 1.2241 + THEMESIZE sizeReq = TS_TRUE; // Best-fit size 1.2242 + switch (aWidgetType) { 1.2243 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.2244 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.2245 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.2246 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.2247 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.2248 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: 1.2249 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.2250 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.2251 + case NS_THEME_DROPDOWN_BUTTON: 1.2252 + return ClassicGetMinimumWidgetSize(aContext, aFrame, aWidgetType, aResult, aIsOverridable); 1.2253 + 1.2254 + case NS_THEME_MENUITEM: 1.2255 + case NS_THEME_CHECKMENUITEM: 1.2256 + case NS_THEME_RADIOMENUITEM: 1.2257 + if(!IsTopLevelMenu(aFrame)) 1.2258 + { 1.2259 + SIZE gutterSize(GetGutterSize(theme, nullptr)); 1.2260 + aResult->width = gutterSize.cx; 1.2261 + aResult->height = gutterSize.cy; 1.2262 + return NS_OK; 1.2263 + } 1.2264 + break; 1.2265 + 1.2266 + case NS_THEME_MENUIMAGE: 1.2267 + case NS_THEME_MENUCHECKBOX: 1.2268 + case NS_THEME_MENURADIO: 1.2269 + { 1.2270 + SIZE boxSize(GetGutterSize(theme, nullptr)); 1.2271 + aResult->width = boxSize.cx+2; 1.2272 + aResult->height = boxSize.cy; 1.2273 + *aIsOverridable = false; 1.2274 + } 1.2275 + 1.2276 + case NS_THEME_MENUITEMTEXT: 1.2277 + return NS_OK; 1.2278 + 1.2279 + case NS_THEME_PROGRESSBAR: 1.2280 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.2281 + // Best-fit size for progress meters is too large for most 1.2282 + // themes. We want these widgets to be able to really shrink 1.2283 + // down, so use the min-size request value (of 0). 1.2284 + sizeReq = TS_MIN; 1.2285 + break; 1.2286 + 1.2287 + case NS_THEME_RESIZER: 1.2288 + *aIsOverridable = false; 1.2289 + break; 1.2290 + 1.2291 + case NS_THEME_RANGE_THUMB: 1.2292 + case NS_THEME_SCALE_THUMB_HORIZONTAL: 1.2293 + case NS_THEME_SCALE_THUMB_VERTICAL: 1.2294 + { 1.2295 + *aIsOverridable = false; 1.2296 + // on Vista, GetThemePartAndState returns odd values for 1.2297 + // scale thumbs, so use a hardcoded size instead. 1.2298 + if (IsVistaOrLater()) { 1.2299 + if (aWidgetType == NS_THEME_SCALE_THUMB_HORIZONTAL || 1.2300 + (aWidgetType == NS_THEME_RANGE_THUMB && IsRangeHorizontal(aFrame))) { 1.2301 + aResult->width = 12; 1.2302 + aResult->height = 20; 1.2303 + } 1.2304 + else { 1.2305 + aResult->width = 20; 1.2306 + aResult->height = 12; 1.2307 + } 1.2308 + return NS_OK; 1.2309 + } 1.2310 + break; 1.2311 + } 1.2312 + 1.2313 + case NS_THEME_SCROLLBAR: 1.2314 + { 1.2315 + if (nsLookAndFeel::GetInt( 1.2316 + nsLookAndFeel::eIntID_UseOverlayScrollbars) != 0) { 1.2317 + aResult->SizeTo(::GetSystemMetrics(SM_CXHSCROLL), 1.2318 + ::GetSystemMetrics(SM_CYVSCROLL)); 1.2319 + return NS_OK; 1.2320 + } 1.2321 + break; 1.2322 + } 1.2323 + 1.2324 + case NS_THEME_TOOLBAR_SEPARATOR: 1.2325 + // that's 2px left margin, 2px right margin and 2px separator 1.2326 + // (the margin is drawn as part of the separator, though) 1.2327 + aResult->width = 6; 1.2328 + return NS_OK; 1.2329 + 1.2330 + case NS_THEME_BUTTON: 1.2331 + // We should let HTML buttons shrink to their min size. 1.2332 + // FIXME bug 403934: We should probably really separate 1.2333 + // GetPreferredWidgetSize from GetMinimumWidgetSize, so callers can 1.2334 + // use the one they want. 1.2335 + if (aFrame->GetContent()->IsHTML()) { 1.2336 + sizeReq = TS_MIN; 1.2337 + } 1.2338 + break; 1.2339 + 1.2340 + case NS_THEME_WINDOW_BUTTON_MAXIMIZE: 1.2341 + case NS_THEME_WINDOW_BUTTON_RESTORE: 1.2342 + // The only way to get accurate titlebar button info is to query a 1.2343 + // window w/buttons when it's visible. nsWindow takes care of this and 1.2344 + // stores that info in nsUXThemeData. 1.2345 + aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_RESTORE].cx; 1.2346 + aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_RESTORE].cy; 1.2347 + // For XP, subtract 4 from system metrics dimensions. 1.2348 + if (!IsVistaOrLater()) { 1.2349 + aResult->width -= 4; 1.2350 + aResult->height -= 4; 1.2351 + } 1.2352 + AddPaddingRect(aResult, CAPTIONBUTTON_RESTORE); 1.2353 + *aIsOverridable = false; 1.2354 + return NS_OK; 1.2355 + 1.2356 + case NS_THEME_WINDOW_BUTTON_MINIMIZE: 1.2357 + aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_MINIMIZE].cx; 1.2358 + aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_MINIMIZE].cy; 1.2359 + if (!IsVistaOrLater()) { 1.2360 + aResult->width -= 4; 1.2361 + aResult->height -= 4; 1.2362 + } 1.2363 + AddPaddingRect(aResult, CAPTIONBUTTON_MINIMIZE); 1.2364 + *aIsOverridable = false; 1.2365 + return NS_OK; 1.2366 + 1.2367 + case NS_THEME_WINDOW_BUTTON_CLOSE: 1.2368 + aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_CLOSE].cx; 1.2369 + aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_CLOSE].cy; 1.2370 + if (!IsVistaOrLater()) { 1.2371 + aResult->width -= 4; 1.2372 + aResult->height -= 4; 1.2373 + } 1.2374 + AddPaddingRect(aResult, CAPTIONBUTTON_CLOSE); 1.2375 + *aIsOverridable = false; 1.2376 + return NS_OK; 1.2377 + 1.2378 + case NS_THEME_WINDOW_TITLEBAR: 1.2379 + case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: 1.2380 + aResult->height = GetSystemMetrics(SM_CYCAPTION); 1.2381 + aResult->height += GetSystemMetrics(SM_CYFRAME); 1.2382 + aResult->height += GetSystemMetrics(SM_CXPADDEDBORDER); 1.2383 + *aIsOverridable = false; 1.2384 + return NS_OK; 1.2385 + 1.2386 + case NS_THEME_WINDOW_BUTTON_BOX: 1.2387 + case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: 1.2388 + if (nsUXThemeData::CheckForCompositor()) { 1.2389 + aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cx; 1.2390 + aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy 1.2391 + - GetSystemMetrics(SM_CYFRAME) 1.2392 + - GetSystemMetrics(SM_CXPADDEDBORDER); 1.2393 + if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) { 1.2394 + aResult->width += 1; 1.2395 + aResult->height -= 2; 1.2396 + } 1.2397 + *aIsOverridable = false; 1.2398 + return NS_OK; 1.2399 + } 1.2400 + break; 1.2401 + 1.2402 + case NS_THEME_WINDOW_FRAME_LEFT: 1.2403 + case NS_THEME_WINDOW_FRAME_RIGHT: 1.2404 + case NS_THEME_WINDOW_FRAME_BOTTOM: 1.2405 + aResult->width = GetSystemMetrics(SM_CXFRAME); 1.2406 + aResult->height = GetSystemMetrics(SM_CYFRAME); 1.2407 + *aIsOverridable = false; 1.2408 + return NS_OK; 1.2409 + } 1.2410 + 1.2411 + int32_t part, state; 1.2412 + nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); 1.2413 + if (NS_FAILED(rv)) 1.2414 + return rv; 1.2415 + 1.2416 + HDC hdc = ::GetDC(nullptr); 1.2417 + if (!hdc) 1.2418 + return NS_ERROR_FAILURE; 1.2419 + 1.2420 + SIZE sz; 1.2421 + GetThemePartSize(theme, hdc, part, state, nullptr, sizeReq, &sz); 1.2422 + aResult->width = sz.cx; 1.2423 + aResult->height = sz.cy; 1.2424 + 1.2425 + switch(aWidgetType) { 1.2426 + case NS_THEME_SPINNER_UP_BUTTON: 1.2427 + case NS_THEME_SPINNER_DOWN_BUTTON: 1.2428 + aResult->width++; 1.2429 + aResult->height = aResult->height / 2 + 1; 1.2430 + break; 1.2431 + 1.2432 + case NS_THEME_MENUSEPARATOR: 1.2433 + { 1.2434 + SIZE gutterSize(GetGutterSize(theme, hdc)); 1.2435 + aResult->width += gutterSize.cx; 1.2436 + break; 1.2437 + } 1.2438 + 1.2439 + case NS_THEME_MENUARROW: 1.2440 + { 1.2441 + // Use the width of the arrow glyph as padding. See the drawing 1.2442 + // code for details. 1.2443 + aResult->width *= 2; 1.2444 + break; 1.2445 + } 1.2446 + } 1.2447 + 1.2448 + ::ReleaseDC(nullptr, hdc); 1.2449 + return NS_OK; 1.2450 +} 1.2451 + 1.2452 +NS_IMETHODIMP 1.2453 +nsNativeThemeWin::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, 1.2454 + nsIAtom* aAttribute, bool* aShouldRepaint) 1.2455 +{ 1.2456 + // Some widget types just never change state. 1.2457 + if (aWidgetType == NS_THEME_TOOLBOX || 1.2458 + aWidgetType == NS_THEME_WIN_MEDIA_TOOLBOX || 1.2459 + aWidgetType == NS_THEME_WIN_COMMUNICATIONS_TOOLBOX || 1.2460 + aWidgetType == NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX || 1.2461 + aWidgetType == NS_THEME_TOOLBAR || 1.2462 + aWidgetType == NS_THEME_STATUSBAR || aWidgetType == NS_THEME_STATUSBAR_PANEL || 1.2463 + aWidgetType == NS_THEME_STATUSBAR_RESIZER_PANEL || 1.2464 + aWidgetType == NS_THEME_PROGRESSBAR_CHUNK || 1.2465 + aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL || 1.2466 + aWidgetType == NS_THEME_PROGRESSBAR || 1.2467 + aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL || 1.2468 + aWidgetType == NS_THEME_TOOLTIP || 1.2469 + aWidgetType == NS_THEME_TAB_PANELS || 1.2470 + aWidgetType == NS_THEME_TAB_PANEL || 1.2471 + aWidgetType == NS_THEME_TOOLBAR_SEPARATOR || 1.2472 + aWidgetType == NS_THEME_WIN_GLASS || 1.2473 + aWidgetType == NS_THEME_WIN_BORDERLESS_GLASS) { 1.2474 + *aShouldRepaint = false; 1.2475 + return NS_OK; 1.2476 + } 1.2477 + 1.2478 + if (aWidgetType == NS_THEME_WINDOW_TITLEBAR || 1.2479 + aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED || 1.2480 + aWidgetType == NS_THEME_WINDOW_FRAME_LEFT || 1.2481 + aWidgetType == NS_THEME_WINDOW_FRAME_RIGHT || 1.2482 + aWidgetType == NS_THEME_WINDOW_FRAME_BOTTOM || 1.2483 + aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE || 1.2484 + aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE || 1.2485 + aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE || 1.2486 + aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { 1.2487 + *aShouldRepaint = true; 1.2488 + return NS_OK; 1.2489 + } 1.2490 + 1.2491 + // On Vista, the scrollbar buttons need to change state when the track has/doesn't have hover 1.2492 + if (!IsVistaOrLater() && 1.2493 + (aWidgetType == NS_THEME_SCROLLBAR_TRACK_VERTICAL || 1.2494 + aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL)) { 1.2495 + *aShouldRepaint = false; 1.2496 + return NS_OK; 1.2497 + } 1.2498 + 1.2499 + // We need to repaint the dropdown arrow in vista HTML combobox controls when 1.2500 + // the control is closed to get rid of the hover effect. 1.2501 + if (IsVistaOrLater() && 1.2502 + (aWidgetType == NS_THEME_DROPDOWN || aWidgetType == NS_THEME_DROPDOWN_BUTTON) && 1.2503 + IsHTMLContent(aFrame)) 1.2504 + { 1.2505 + *aShouldRepaint = true; 1.2506 + return NS_OK; 1.2507 + } 1.2508 + 1.2509 + // XXXdwh Not sure what can really be done here. Can at least guess for 1.2510 + // specific widgets that they're highly unlikely to have certain states. 1.2511 + // For example, a toolbar doesn't care about any states. 1.2512 + if (!aAttribute) { 1.2513 + // Hover/focus/active changed. Always repaint. 1.2514 + *aShouldRepaint = true; 1.2515 + } 1.2516 + else { 1.2517 + // Check the attribute to see if it's relevant. 1.2518 + // disabled, checked, dlgtype, default, etc. 1.2519 + *aShouldRepaint = false; 1.2520 + if (aAttribute == nsGkAtoms::disabled || 1.2521 + aAttribute == nsGkAtoms::checked || 1.2522 + aAttribute == nsGkAtoms::selected || 1.2523 + aAttribute == nsGkAtoms::readonly || 1.2524 + aAttribute == nsGkAtoms::open || 1.2525 + aAttribute == nsGkAtoms::menuactive || 1.2526 + aAttribute == nsGkAtoms::focused) 1.2527 + *aShouldRepaint = true; 1.2528 + } 1.2529 + 1.2530 + return NS_OK; 1.2531 +} 1.2532 + 1.2533 +NS_IMETHODIMP 1.2534 +nsNativeThemeWin::ThemeChanged() 1.2535 +{ 1.2536 + nsUXThemeData::Invalidate(); 1.2537 + return NS_OK; 1.2538 +} 1.2539 + 1.2540 +bool 1.2541 +nsNativeThemeWin::ThemeSupportsWidget(nsPresContext* aPresContext, 1.2542 + nsIFrame* aFrame, 1.2543 + uint8_t aWidgetType) 1.2544 +{ 1.2545 + // XXXdwh We can go even further and call the API to ask if support exists for 1.2546 + // specific widgets. 1.2547 + 1.2548 + if (aPresContext && !aPresContext->PresShell()->IsThemeSupportEnabled()) 1.2549 + return false; 1.2550 + 1.2551 + HANDLE theme = nullptr; 1.2552 + if (aWidgetType == NS_THEME_CHECKBOX_CONTAINER) 1.2553 + theme = GetTheme(NS_THEME_CHECKBOX); 1.2554 + else if (aWidgetType == NS_THEME_RADIO_CONTAINER) 1.2555 + theme = GetTheme(NS_THEME_RADIO); 1.2556 + else 1.2557 + theme = GetTheme(aWidgetType); 1.2558 + 1.2559 + if ((theme) || (!theme && ClassicThemeSupportsWidget(aPresContext, aFrame, aWidgetType))) 1.2560 + // turn off theming for some HTML widgets styled by the page 1.2561 + return (!IsWidgetStyled(aPresContext, aFrame, aWidgetType)); 1.2562 + 1.2563 + return false; 1.2564 +} 1.2565 + 1.2566 +bool 1.2567 +nsNativeThemeWin::WidgetIsContainer(uint8_t aWidgetType) 1.2568 +{ 1.2569 + // XXXdwh At some point flesh all of this out. 1.2570 + if (aWidgetType == NS_THEME_DROPDOWN_BUTTON || 1.2571 + aWidgetType == NS_THEME_RADIO || 1.2572 + aWidgetType == NS_THEME_CHECKBOX) 1.2573 + return false; 1.2574 + return true; 1.2575 +} 1.2576 + 1.2577 +bool 1.2578 +nsNativeThemeWin::ThemeDrawsFocusForWidget(uint8_t aWidgetType) 1.2579 +{ 1.2580 + return false; 1.2581 +} 1.2582 + 1.2583 +bool 1.2584 +nsNativeThemeWin::ThemeNeedsComboboxDropmarker() 1.2585 +{ 1.2586 + return true; 1.2587 +} 1.2588 + 1.2589 +bool 1.2590 +nsNativeThemeWin::WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType) 1.2591 +{ 1.2592 + switch (aWidgetType) { 1.2593 + case NS_THEME_WINDOW_TITLEBAR: 1.2594 + case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: 1.2595 + case NS_THEME_WINDOW_FRAME_LEFT: 1.2596 + case NS_THEME_WINDOW_FRAME_RIGHT: 1.2597 + case NS_THEME_WINDOW_FRAME_BOTTOM: 1.2598 + case NS_THEME_WINDOW_BUTTON_CLOSE: 1.2599 + case NS_THEME_WINDOW_BUTTON_MINIMIZE: 1.2600 + case NS_THEME_WINDOW_BUTTON_MAXIMIZE: 1.2601 + case NS_THEME_WINDOW_BUTTON_RESTORE: 1.2602 + return true; 1.2603 + default: 1.2604 + return false; 1.2605 + } 1.2606 +} 1.2607 + 1.2608 +bool 1.2609 +nsNativeThemeWin::ShouldHideScrollbars() 1.2610 +{ 1.2611 + return WinUtils::ShouldHideScrollbars(); 1.2612 +} 1.2613 + 1.2614 +nsITheme::Transparency 1.2615 +nsNativeThemeWin::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType) 1.2616 +{ 1.2617 + switch (aWidgetType) { 1.2618 + case NS_THEME_SCROLLBAR_SMALL: 1.2619 + case NS_THEME_SCROLLBAR: 1.2620 + case NS_THEME_STATUSBAR: 1.2621 + // Knowing that scrollbars and statusbars are opaque improves 1.2622 + // performance, because we create layers for them. This better be 1.2623 + // true across all Windows themes! If it's not true, we should 1.2624 + // paint an opaque background for them to make it true! 1.2625 + return eOpaque; 1.2626 + case NS_THEME_WIN_GLASS: 1.2627 + case NS_THEME_WIN_BORDERLESS_GLASS: 1.2628 + case NS_THEME_SCALE_HORIZONTAL: 1.2629 + case NS_THEME_SCALE_VERTICAL: 1.2630 + case NS_THEME_PROGRESSBAR: 1.2631 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.2632 + case NS_THEME_PROGRESSBAR_CHUNK: 1.2633 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: 1.2634 + case NS_THEME_RANGE: 1.2635 + return eTransparent; 1.2636 + } 1.2637 + 1.2638 + HANDLE theme = GetTheme(aWidgetType); 1.2639 + // For the classic theme we don't really have a way of knowing 1.2640 + if (!theme) { 1.2641 + // menu backgrounds and tooltips which can't be themed are opaque 1.2642 + if (aWidgetType == NS_THEME_MENUPOPUP || aWidgetType == NS_THEME_TOOLTIP) { 1.2643 + return eOpaque; 1.2644 + } 1.2645 + return eUnknownTransparency; 1.2646 + } 1.2647 + 1.2648 + int32_t part, state; 1.2649 + nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); 1.2650 + // Fail conservatively 1.2651 + NS_ENSURE_SUCCESS(rv, eUnknownTransparency); 1.2652 + 1.2653 + if (part <= 0) { 1.2654 + // Not a real part code, so IsThemeBackgroundPartiallyTransparent may 1.2655 + // not work, so don't call it. 1.2656 + return eUnknownTransparency; 1.2657 + } 1.2658 + 1.2659 + if (IsThemeBackgroundPartiallyTransparent(theme, part, state)) 1.2660 + return eTransparent; 1.2661 + return eOpaque; 1.2662 +} 1.2663 + 1.2664 +/* Windows 9x/NT/2000/Classic XP Theme Support */ 1.2665 + 1.2666 +bool 1.2667 +nsNativeThemeWin::ClassicThemeSupportsWidget(nsPresContext* aPresContext, 1.2668 + nsIFrame* aFrame, 1.2669 + uint8_t aWidgetType) 1.2670 +{ 1.2671 + switch (aWidgetType) { 1.2672 + case NS_THEME_RESIZER: 1.2673 + { 1.2674 + // The classic native resizer has an opaque grey background which doesn't 1.2675 + // match the usually white background of the scrollable container, so 1.2676 + // only support the native resizer if not in a scrollframe. 1.2677 + nsIFrame* parentFrame = aFrame->GetParent(); 1.2678 + return (!parentFrame || parentFrame->GetType() != nsGkAtoms::scrollFrame); 1.2679 + } 1.2680 + case NS_THEME_MENUBAR: 1.2681 + case NS_THEME_MENUPOPUP: 1.2682 + // Classic non-flat menus are handled almost entirely through CSS. 1.2683 + if (!nsUXThemeData::sFlatMenus) 1.2684 + return false; 1.2685 + case NS_THEME_BUTTON: 1.2686 + case NS_THEME_NUMBER_INPUT: 1.2687 + case NS_THEME_TEXTFIELD: 1.2688 + case NS_THEME_TEXTFIELD_MULTILINE: 1.2689 + case NS_THEME_CHECKBOX: 1.2690 + case NS_THEME_RADIO: 1.2691 + case NS_THEME_RANGE: 1.2692 + case NS_THEME_RANGE_THUMB: 1.2693 + case NS_THEME_GROUPBOX: 1.2694 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.2695 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.2696 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.2697 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: 1.2698 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.2699 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.2700 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.2701 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.2702 + case NS_THEME_SCROLLBAR_NON_DISAPPEARING: 1.2703 + case NS_THEME_SCALE_HORIZONTAL: 1.2704 + case NS_THEME_SCALE_VERTICAL: 1.2705 + case NS_THEME_SCALE_THUMB_HORIZONTAL: 1.2706 + case NS_THEME_SCALE_THUMB_VERTICAL: 1.2707 + case NS_THEME_DROPDOWN_BUTTON: 1.2708 + case NS_THEME_SPINNER_UP_BUTTON: 1.2709 + case NS_THEME_SPINNER_DOWN_BUTTON: 1.2710 + case NS_THEME_LISTBOX: 1.2711 + case NS_THEME_TREEVIEW: 1.2712 + case NS_THEME_DROPDOWN_TEXTFIELD: 1.2713 + case NS_THEME_DROPDOWN: 1.2714 + case NS_THEME_TOOLTIP: 1.2715 + case NS_THEME_STATUSBAR: 1.2716 + case NS_THEME_STATUSBAR_PANEL: 1.2717 + case NS_THEME_STATUSBAR_RESIZER_PANEL: 1.2718 + case NS_THEME_PROGRESSBAR: 1.2719 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.2720 + case NS_THEME_PROGRESSBAR_CHUNK: 1.2721 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: 1.2722 + case NS_THEME_TAB: 1.2723 + case NS_THEME_TAB_PANEL: 1.2724 + case NS_THEME_TAB_PANELS: 1.2725 + case NS_THEME_MENUITEM: 1.2726 + case NS_THEME_CHECKMENUITEM: 1.2727 + case NS_THEME_RADIOMENUITEM: 1.2728 + case NS_THEME_MENUCHECKBOX: 1.2729 + case NS_THEME_MENURADIO: 1.2730 + case NS_THEME_MENUARROW: 1.2731 + case NS_THEME_MENUSEPARATOR: 1.2732 + case NS_THEME_MENUITEMTEXT: 1.2733 + case NS_THEME_WINDOW_TITLEBAR: 1.2734 + case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: 1.2735 + case NS_THEME_WINDOW_FRAME_LEFT: 1.2736 + case NS_THEME_WINDOW_FRAME_RIGHT: 1.2737 + case NS_THEME_WINDOW_FRAME_BOTTOM: 1.2738 + case NS_THEME_WINDOW_BUTTON_CLOSE: 1.2739 + case NS_THEME_WINDOW_BUTTON_MINIMIZE: 1.2740 + case NS_THEME_WINDOW_BUTTON_MAXIMIZE: 1.2741 + case NS_THEME_WINDOW_BUTTON_RESTORE: 1.2742 + case NS_THEME_WINDOW_BUTTON_BOX: 1.2743 + case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: 1.2744 + return true; 1.2745 + } 1.2746 + return false; 1.2747 +} 1.2748 + 1.2749 +nsresult 1.2750 +nsNativeThemeWin::ClassicGetWidgetBorder(nsDeviceContext* aContext, 1.2751 + nsIFrame* aFrame, 1.2752 + uint8_t aWidgetType, 1.2753 + nsIntMargin* aResult) 1.2754 +{ 1.2755 + switch (aWidgetType) { 1.2756 + case NS_THEME_GROUPBOX: 1.2757 + case NS_THEME_BUTTON: 1.2758 + (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 2; 1.2759 + break; 1.2760 + case NS_THEME_STATUSBAR: 1.2761 + (*aResult).bottom = (*aResult).left = (*aResult).right = 0; 1.2762 + (*aResult).top = 2; 1.2763 + break; 1.2764 + case NS_THEME_LISTBOX: 1.2765 + case NS_THEME_TREEVIEW: 1.2766 + case NS_THEME_DROPDOWN: 1.2767 + case NS_THEME_DROPDOWN_TEXTFIELD: 1.2768 + case NS_THEME_TAB: 1.2769 + case NS_THEME_NUMBER_INPUT: 1.2770 + case NS_THEME_TEXTFIELD: 1.2771 + case NS_THEME_TEXTFIELD_MULTILINE: 1.2772 + (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 2; 1.2773 + break; 1.2774 + case NS_THEME_STATUSBAR_PANEL: 1.2775 + case NS_THEME_STATUSBAR_RESIZER_PANEL: { 1.2776 + (*aResult).top = 1; 1.2777 + (*aResult).left = 1; 1.2778 + (*aResult).bottom = 1; 1.2779 + (*aResult).right = aFrame->GetNextSibling() ? 3 : 1; 1.2780 + break; 1.2781 + } 1.2782 + case NS_THEME_TOOLTIP: 1.2783 + (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; 1.2784 + break; 1.2785 + case NS_THEME_PROGRESSBAR: 1.2786 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.2787 + (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; 1.2788 + break; 1.2789 + case NS_THEME_MENUBAR: 1.2790 + (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 0; 1.2791 + break; 1.2792 + case NS_THEME_MENUPOPUP: 1.2793 + (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 3; 1.2794 + break; 1.2795 + default: 1.2796 + (*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 0; 1.2797 + break; 1.2798 + } 1.2799 + return NS_OK; 1.2800 +} 1.2801 + 1.2802 +bool 1.2803 +nsNativeThemeWin::ClassicGetWidgetPadding(nsDeviceContext* aContext, 1.2804 + nsIFrame* aFrame, 1.2805 + uint8_t aWidgetType, 1.2806 + nsIntMargin* aResult) 1.2807 +{ 1.2808 + switch (aWidgetType) { 1.2809 + case NS_THEME_MENUITEM: 1.2810 + case NS_THEME_CHECKMENUITEM: 1.2811 + case NS_THEME_RADIOMENUITEM: { 1.2812 + int32_t part, state; 1.2813 + bool focused; 1.2814 + 1.2815 + if (NS_FAILED(ClassicGetThemePartAndState(aFrame, aWidgetType, part, state, focused))) 1.2816 + return false; 1.2817 + 1.2818 + if (part == 1) { // top-level menu 1.2819 + if (nsUXThemeData::sFlatMenus || !(state & DFCS_PUSHED)) { 1.2820 + (*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 2; 1.2821 + } 1.2822 + else { 1.2823 + // make top-level menus look sunken when pushed in the Classic look 1.2824 + (*aResult).top = (*aResult).left = 3; 1.2825 + (*aResult).bottom = (*aResult).right = 1; 1.2826 + } 1.2827 + } 1.2828 + else { 1.2829 + (*aResult).top = 0; 1.2830 + (*aResult).bottom = (*aResult).left = (*aResult).right = 2; 1.2831 + } 1.2832 + return true; 1.2833 + } 1.2834 + case NS_THEME_PROGRESSBAR: 1.2835 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.2836 + (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; 1.2837 + return true; 1.2838 + default: 1.2839 + return false; 1.2840 + } 1.2841 +} 1.2842 + 1.2843 +nsresult 1.2844 +nsNativeThemeWin::ClassicGetMinimumWidgetSize(nsRenderingContext* aContext, nsIFrame* aFrame, 1.2845 + uint8_t aWidgetType, 1.2846 + nsIntSize* aResult, bool* aIsOverridable) 1.2847 +{ 1.2848 + (*aResult).width = (*aResult).height = 0; 1.2849 + *aIsOverridable = true; 1.2850 + switch (aWidgetType) { 1.2851 + case NS_THEME_RADIO: 1.2852 + case NS_THEME_CHECKBOX: 1.2853 + (*aResult).width = (*aResult).height = 13; 1.2854 + break; 1.2855 + case NS_THEME_MENUCHECKBOX: 1.2856 + case NS_THEME_MENURADIO: 1.2857 + case NS_THEME_MENUARROW: 1.2858 + (*aResult).width = ::GetSystemMetrics(SM_CXMENUCHECK); 1.2859 + (*aResult).height = ::GetSystemMetrics(SM_CYMENUCHECK); 1.2860 + break; 1.2861 + case NS_THEME_SPINNER_UP_BUTTON: 1.2862 + case NS_THEME_SPINNER_DOWN_BUTTON: 1.2863 + (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); 1.2864 + (*aResult).height = 8; // No good metrics available for this 1.2865 + *aIsOverridable = false; 1.2866 + break; 1.2867 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.2868 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.2869 + (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); 1.2870 + (*aResult).height = ::GetSystemMetrics(SM_CYVSCROLL); 1.2871 + *aIsOverridable = false; 1.2872 + break; 1.2873 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.2874 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: 1.2875 + (*aResult).width = ::GetSystemMetrics(SM_CXHSCROLL); 1.2876 + (*aResult).height = ::GetSystemMetrics(SM_CYHSCROLL); 1.2877 + *aIsOverridable = false; 1.2878 + break; 1.2879 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.2880 + // XXX HACK We should be able to have a minimum height for the scrollbar 1.2881 + // track. However, this causes problems when uncollapsing a scrollbar 1.2882 + // inside a tree. See bug 201379 for details. 1.2883 + 1.2884 + // (*aResult).height = ::GetSystemMetrics(SM_CYVTHUMB) << 1; 1.2885 + break; 1.2886 + case NS_THEME_SCROLLBAR_NON_DISAPPEARING: 1.2887 + { 1.2888 + aResult->SizeTo(::GetSystemMetrics(SM_CXHSCROLL), 1.2889 + ::GetSystemMetrics(SM_CYVSCROLL)); 1.2890 + break; 1.2891 + } 1.2892 + case NS_THEME_RANGE_THUMB: { 1.2893 + if (IsRangeHorizontal(aFrame)) { 1.2894 + (*aResult).width = 12; 1.2895 + (*aResult).height = 20; 1.2896 + } else { 1.2897 + (*aResult).width = 20; 1.2898 + (*aResult).height = 12; 1.2899 + } 1.2900 + *aIsOverridable = false; 1.2901 + break; 1.2902 + } 1.2903 + case NS_THEME_SCALE_THUMB_HORIZONTAL: 1.2904 + (*aResult).width = 12; 1.2905 + (*aResult).height = 20; 1.2906 + *aIsOverridable = false; 1.2907 + break; 1.2908 + case NS_THEME_SCALE_THUMB_VERTICAL: 1.2909 + (*aResult).width = 20; 1.2910 + (*aResult).height = 12; 1.2911 + *aIsOverridable = false; 1.2912 + break; 1.2913 + case NS_THEME_DROPDOWN_BUTTON: 1.2914 + (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); 1.2915 + break; 1.2916 + case NS_THEME_DROPDOWN: 1.2917 + case NS_THEME_BUTTON: 1.2918 + case NS_THEME_GROUPBOX: 1.2919 + case NS_THEME_LISTBOX: 1.2920 + case NS_THEME_TREEVIEW: 1.2921 + case NS_THEME_NUMBER_INPUT: 1.2922 + case NS_THEME_TEXTFIELD: 1.2923 + case NS_THEME_TEXTFIELD_MULTILINE: 1.2924 + case NS_THEME_DROPDOWN_TEXTFIELD: 1.2925 + case NS_THEME_STATUSBAR: 1.2926 + case NS_THEME_STATUSBAR_PANEL: 1.2927 + case NS_THEME_STATUSBAR_RESIZER_PANEL: 1.2928 + case NS_THEME_PROGRESSBAR_CHUNK: 1.2929 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: 1.2930 + case NS_THEME_TOOLTIP: 1.2931 + case NS_THEME_PROGRESSBAR: 1.2932 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.2933 + case NS_THEME_TAB: 1.2934 + case NS_THEME_TAB_PANEL: 1.2935 + case NS_THEME_TAB_PANELS: 1.2936 + // no minimum widget size 1.2937 + break; 1.2938 + case NS_THEME_RESIZER: { 1.2939 + NONCLIENTMETRICS nc; 1.2940 + nc.cbSize = sizeof(nc); 1.2941 + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nc), &nc, 0)) 1.2942 + (*aResult).width = (*aResult).height = abs(nc.lfStatusFont.lfHeight) + 4; 1.2943 + else 1.2944 + (*aResult).width = (*aResult).height = 15; 1.2945 + *aIsOverridable = false; 1.2946 + break; 1.2947 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.2948 + (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); 1.2949 + (*aResult).height = ::GetSystemMetrics(SM_CYVTHUMB); 1.2950 + // Without theming, divide the thumb size by two in order to look more 1.2951 + // native 1.2952 + if (!GetTheme(aWidgetType)) 1.2953 + (*aResult).height >>= 1; 1.2954 + *aIsOverridable = false; 1.2955 + break; 1.2956 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.2957 + (*aResult).width = ::GetSystemMetrics(SM_CXHTHUMB); 1.2958 + (*aResult).height = ::GetSystemMetrics(SM_CYHSCROLL); 1.2959 + // Without theming, divide the thumb size by two in order to look more 1.2960 + // native 1.2961 + if (!GetTheme(aWidgetType)) 1.2962 + (*aResult).width >>= 1; 1.2963 + *aIsOverridable = false; 1.2964 + break; 1.2965 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.2966 + (*aResult).width = ::GetSystemMetrics(SM_CXHTHUMB) << 1; 1.2967 + break; 1.2968 + } 1.2969 + case NS_THEME_MENUSEPARATOR: 1.2970 + { 1.2971 + aResult->width = 0; 1.2972 + aResult->height = 10; 1.2973 + break; 1.2974 + } 1.2975 + 1.2976 + case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: 1.2977 + case NS_THEME_WINDOW_TITLEBAR: 1.2978 + aResult->height = GetSystemMetrics(SM_CYCAPTION); 1.2979 + aResult->height += GetSystemMetrics(SM_CYFRAME); 1.2980 + aResult->width = 0; 1.2981 + break; 1.2982 + case NS_THEME_WINDOW_FRAME_LEFT: 1.2983 + case NS_THEME_WINDOW_FRAME_RIGHT: 1.2984 + aResult->width = GetSystemMetrics(SM_CXFRAME); 1.2985 + aResult->height = 0; 1.2986 + break; 1.2987 + 1.2988 + case NS_THEME_WINDOW_FRAME_BOTTOM: 1.2989 + aResult->height = GetSystemMetrics(SM_CYFRAME); 1.2990 + aResult->width = 0; 1.2991 + break; 1.2992 + 1.2993 + case NS_THEME_WINDOW_BUTTON_CLOSE: 1.2994 + case NS_THEME_WINDOW_BUTTON_MINIMIZE: 1.2995 + case NS_THEME_WINDOW_BUTTON_MAXIMIZE: 1.2996 + case NS_THEME_WINDOW_BUTTON_RESTORE: 1.2997 + aResult->width = GetSystemMetrics(SM_CXSIZE); 1.2998 + aResult->height = GetSystemMetrics(SM_CYSIZE); 1.2999 + // XXX I have no idea why these caption metrics are always off, 1.3000 + // but they are. 1.3001 + aResult->width -= 2; 1.3002 + aResult->height -= 4; 1.3003 + if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) { 1.3004 + AddPaddingRect(aResult, CAPTIONBUTTON_MINIMIZE); 1.3005 + } 1.3006 + else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE || 1.3007 + aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { 1.3008 + AddPaddingRect(aResult, CAPTIONBUTTON_RESTORE); 1.3009 + } 1.3010 + else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) { 1.3011 + AddPaddingRect(aResult, CAPTIONBUTTON_CLOSE); 1.3012 + } 1.3013 + break; 1.3014 + 1.3015 + default: 1.3016 + return NS_ERROR_FAILURE; 1.3017 + } 1.3018 + return NS_OK; 1.3019 +} 1.3020 + 1.3021 + 1.3022 +nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType, 1.3023 + int32_t& aPart, int32_t& aState, bool& aFocused) 1.3024 +{ 1.3025 + aFocused = false; 1.3026 + switch (aWidgetType) { 1.3027 + case NS_THEME_BUTTON: { 1.3028 + EventStates contentState; 1.3029 + 1.3030 + aPart = DFC_BUTTON; 1.3031 + aState = DFCS_BUTTONPUSH; 1.3032 + aFocused = false; 1.3033 + 1.3034 + contentState = GetContentState(aFrame, aWidgetType); 1.3035 + if (IsDisabled(aFrame, contentState)) 1.3036 + aState |= DFCS_INACTIVE; 1.3037 + else if (IsOpenButton(aFrame)) 1.3038 + aState |= DFCS_PUSHED; 1.3039 + else if (IsCheckedButton(aFrame)) 1.3040 + aState |= DFCS_CHECKED; 1.3041 + else { 1.3042 + if (contentState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)) { 1.3043 + aState |= DFCS_PUSHED; 1.3044 + const nsStyleUserInterface *uiData = aFrame->StyleUserInterface(); 1.3045 + // The down state is flat if the button is focusable 1.3046 + if (uiData->mUserFocus == NS_STYLE_USER_FOCUS_NORMAL) { 1.3047 + if (!aFrame->GetContent()->IsHTML()) 1.3048 + aState |= DFCS_FLAT; 1.3049 + 1.3050 + aFocused = true; 1.3051 + } 1.3052 + } 1.3053 + if (contentState.HasState(NS_EVENT_STATE_FOCUS) || 1.3054 + (aState == DFCS_BUTTONPUSH && IsDefaultButton(aFrame))) { 1.3055 + aFocused = true; 1.3056 + } 1.3057 + 1.3058 + } 1.3059 + 1.3060 + return NS_OK; 1.3061 + } 1.3062 + case NS_THEME_CHECKBOX: 1.3063 + case NS_THEME_RADIO: { 1.3064 + EventStates contentState; 1.3065 + aFocused = false; 1.3066 + 1.3067 + aPart = DFC_BUTTON; 1.3068 + aState = 0; 1.3069 + nsIContent* content = aFrame->GetContent(); 1.3070 + bool isCheckbox = (aWidgetType == NS_THEME_CHECKBOX); 1.3071 + bool isChecked = GetCheckedOrSelected(aFrame, !isCheckbox); 1.3072 + bool isIndeterminate = isCheckbox && GetIndeterminate(aFrame); 1.3073 + 1.3074 + if (isCheckbox) { 1.3075 + // indeterminate state takes precedence over checkedness. 1.3076 + if (isIndeterminate) { 1.3077 + aState = DFCS_BUTTON3STATE | DFCS_CHECKED; 1.3078 + } else { 1.3079 + aState = DFCS_BUTTONCHECK; 1.3080 + } 1.3081 + } else { 1.3082 + aState = DFCS_BUTTONRADIO; 1.3083 + } 1.3084 + if (isChecked) { 1.3085 + aState |= DFCS_CHECKED; 1.3086 + } 1.3087 + 1.3088 + contentState = GetContentState(aFrame, aWidgetType); 1.3089 + if (!content->IsXUL() && 1.3090 + contentState.HasState(NS_EVENT_STATE_FOCUS)) { 1.3091 + aFocused = true; 1.3092 + } 1.3093 + 1.3094 + if (IsDisabled(aFrame, contentState)) { 1.3095 + aState |= DFCS_INACTIVE; 1.3096 + } else if (contentState.HasAllStates(NS_EVENT_STATE_ACTIVE | 1.3097 + NS_EVENT_STATE_HOVER)) { 1.3098 + aState |= DFCS_PUSHED; 1.3099 + } 1.3100 + 1.3101 + return NS_OK; 1.3102 + } 1.3103 + case NS_THEME_MENUITEM: 1.3104 + case NS_THEME_CHECKMENUITEM: 1.3105 + case NS_THEME_RADIOMENUITEM: { 1.3106 + bool isTopLevel = false; 1.3107 + bool isOpen = false; 1.3108 + bool isContainer = false; 1.3109 + nsMenuFrame *menuFrame = do_QueryFrame(aFrame); 1.3110 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.3111 + 1.3112 + // We indicate top-level-ness using aPart. 0 is a normal menu item, 1.3113 + // 1 is a top-level menu item. The state of the item is composed of 1.3114 + // DFCS_* flags only. 1.3115 + aPart = 0; 1.3116 + aState = 0; 1.3117 + 1.3118 + if (menuFrame) { 1.3119 + // If this is a real menu item, we should check if it is part of the 1.3120 + // main menu bar or not, and if it is a container, as these affect 1.3121 + // rendering. 1.3122 + isTopLevel = menuFrame->IsOnMenuBar(); 1.3123 + isOpen = menuFrame->IsOpen(); 1.3124 + isContainer = menuFrame->IsMenu(); 1.3125 + } 1.3126 + 1.3127 + if (IsDisabled(aFrame, eventState)) 1.3128 + aState |= DFCS_INACTIVE; 1.3129 + 1.3130 + if (isTopLevel) { 1.3131 + aPart = 1; 1.3132 + if (isOpen) 1.3133 + aState |= DFCS_PUSHED; 1.3134 + } 1.3135 + 1.3136 + if (IsMenuActive(aFrame, aWidgetType)) 1.3137 + aState |= DFCS_HOT; 1.3138 + 1.3139 + return NS_OK; 1.3140 + } 1.3141 + case NS_THEME_MENUCHECKBOX: 1.3142 + case NS_THEME_MENURADIO: 1.3143 + case NS_THEME_MENUARROW: { 1.3144 + aState = 0; 1.3145 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.3146 + 1.3147 + if (IsDisabled(aFrame, eventState)) 1.3148 + aState |= DFCS_INACTIVE; 1.3149 + if (IsMenuActive(aFrame, aWidgetType)) 1.3150 + aState |= DFCS_HOT; 1.3151 + 1.3152 + if (aWidgetType == NS_THEME_MENUCHECKBOX || aWidgetType == NS_THEME_MENURADIO) { 1.3153 + if (IsCheckedButton(aFrame)) 1.3154 + aState |= DFCS_CHECKED; 1.3155 + } else if (IsFrameRTL(aFrame)) { 1.3156 + aState |= DFCS_RTL; 1.3157 + } 1.3158 + return NS_OK; 1.3159 + } 1.3160 + case NS_THEME_LISTBOX: 1.3161 + case NS_THEME_TREEVIEW: 1.3162 + case NS_THEME_NUMBER_INPUT: 1.3163 + case NS_THEME_TEXTFIELD: 1.3164 + case NS_THEME_TEXTFIELD_MULTILINE: 1.3165 + case NS_THEME_DROPDOWN: 1.3166 + case NS_THEME_DROPDOWN_TEXTFIELD: 1.3167 + case NS_THEME_RANGE: 1.3168 + case NS_THEME_RANGE_THUMB: 1.3169 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.3170 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.3171 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.3172 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.3173 + case NS_THEME_SCALE_HORIZONTAL: 1.3174 + case NS_THEME_SCALE_VERTICAL: 1.3175 + case NS_THEME_SCALE_THUMB_HORIZONTAL: 1.3176 + case NS_THEME_SCALE_THUMB_VERTICAL: 1.3177 + case NS_THEME_STATUSBAR: 1.3178 + case NS_THEME_STATUSBAR_PANEL: 1.3179 + case NS_THEME_STATUSBAR_RESIZER_PANEL: 1.3180 + case NS_THEME_PROGRESSBAR_CHUNK: 1.3181 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: 1.3182 + case NS_THEME_TOOLTIP: 1.3183 + case NS_THEME_PROGRESSBAR: 1.3184 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.3185 + case NS_THEME_TAB: 1.3186 + case NS_THEME_TAB_PANEL: 1.3187 + case NS_THEME_TAB_PANELS: 1.3188 + case NS_THEME_MENUBAR: 1.3189 + case NS_THEME_MENUPOPUP: 1.3190 + case NS_THEME_GROUPBOX: 1.3191 + // these don't use DrawFrameControl 1.3192 + return NS_OK; 1.3193 + case NS_THEME_DROPDOWN_BUTTON: { 1.3194 + 1.3195 + aPart = DFC_SCROLL; 1.3196 + aState = DFCS_SCROLLCOMBOBOX; 1.3197 + 1.3198 + nsIFrame* parentFrame = aFrame->GetParent(); 1.3199 + bool isHTML = IsHTMLContent(aFrame); 1.3200 + bool isMenulist = !isHTML && parentFrame->GetType() == nsGkAtoms::menuFrame; 1.3201 + bool isOpen = false; 1.3202 + 1.3203 + // HTML select and XUL menulist dropdown buttons get state from the parent. 1.3204 + if (isHTML || isMenulist) 1.3205 + aFrame = parentFrame; 1.3206 + 1.3207 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.3208 + 1.3209 + if (IsDisabled(aFrame, eventState)) { 1.3210 + aState |= DFCS_INACTIVE; 1.3211 + return NS_OK; 1.3212 + } 1.3213 + 1.3214 + if (isHTML) { 1.3215 + nsIComboboxControlFrame* ccf = do_QueryFrame(aFrame); 1.3216 + isOpen = (ccf && ccf->IsDroppedDown()); 1.3217 + } 1.3218 + else 1.3219 + isOpen = IsOpenButton(aFrame); 1.3220 + 1.3221 + // XXX Button should look active until the mouse is released, but 1.3222 + // without making it look active when the popup is clicked. 1.3223 + if (isOpen && (isHTML || isMenulist)) 1.3224 + return NS_OK; 1.3225 + 1.3226 + // Dropdown button active state doesn't need :hover. 1.3227 + if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) 1.3228 + aState |= DFCS_PUSHED | DFCS_FLAT; 1.3229 + 1.3230 + return NS_OK; 1.3231 + } 1.3232 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.3233 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.3234 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.3235 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: { 1.3236 + EventStates contentState = GetContentState(aFrame, aWidgetType); 1.3237 + 1.3238 + aPart = DFC_SCROLL; 1.3239 + switch (aWidgetType) { 1.3240 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.3241 + aState = DFCS_SCROLLUP; 1.3242 + break; 1.3243 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.3244 + aState = DFCS_SCROLLDOWN; 1.3245 + break; 1.3246 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.3247 + aState = DFCS_SCROLLLEFT; 1.3248 + break; 1.3249 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: 1.3250 + aState = DFCS_SCROLLRIGHT; 1.3251 + break; 1.3252 + } 1.3253 + 1.3254 + if (IsDisabled(aFrame, contentState)) 1.3255 + aState |= DFCS_INACTIVE; 1.3256 + else { 1.3257 + if (contentState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) 1.3258 + aState |= DFCS_PUSHED | DFCS_FLAT; 1.3259 + } 1.3260 + 1.3261 + return NS_OK; 1.3262 + } 1.3263 + case NS_THEME_SPINNER_UP_BUTTON: 1.3264 + case NS_THEME_SPINNER_DOWN_BUTTON: { 1.3265 + EventStates contentState = GetContentState(aFrame, aWidgetType); 1.3266 + 1.3267 + aPart = DFC_SCROLL; 1.3268 + switch (aWidgetType) { 1.3269 + case NS_THEME_SPINNER_UP_BUTTON: 1.3270 + aState = DFCS_SCROLLUP; 1.3271 + break; 1.3272 + case NS_THEME_SPINNER_DOWN_BUTTON: 1.3273 + aState = DFCS_SCROLLDOWN; 1.3274 + break; 1.3275 + } 1.3276 + 1.3277 + if (IsDisabled(aFrame, contentState)) 1.3278 + aState |= DFCS_INACTIVE; 1.3279 + else { 1.3280 + if (contentState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) 1.3281 + aState |= DFCS_PUSHED; 1.3282 + } 1.3283 + 1.3284 + return NS_OK; 1.3285 + } 1.3286 + case NS_THEME_RESIZER: 1.3287 + aPart = DFC_SCROLL; 1.3288 + aState = (IsFrameRTL(aFrame)) ? 1.3289 + DFCS_SCROLLSIZEGRIPRIGHT : DFCS_SCROLLSIZEGRIP; 1.3290 + return NS_OK; 1.3291 + case NS_THEME_MENUSEPARATOR: 1.3292 + aPart = 0; 1.3293 + aState = 0; 1.3294 + return NS_OK; 1.3295 + case NS_THEME_WINDOW_TITLEBAR: 1.3296 + aPart = mozilla::widget::themeconst::WP_CAPTION; 1.3297 + aState = GetTopLevelWindowActiveState(aFrame); 1.3298 + return NS_OK; 1.3299 + case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: 1.3300 + aPart = mozilla::widget::themeconst::WP_MAXCAPTION; 1.3301 + aState = GetTopLevelWindowActiveState(aFrame); 1.3302 + return NS_OK; 1.3303 + case NS_THEME_WINDOW_FRAME_LEFT: 1.3304 + aPart = mozilla::widget::themeconst::WP_FRAMELEFT; 1.3305 + aState = GetTopLevelWindowActiveState(aFrame); 1.3306 + return NS_OK; 1.3307 + case NS_THEME_WINDOW_FRAME_RIGHT: 1.3308 + aPart = mozilla::widget::themeconst::WP_FRAMERIGHT; 1.3309 + aState = GetTopLevelWindowActiveState(aFrame); 1.3310 + return NS_OK; 1.3311 + case NS_THEME_WINDOW_FRAME_BOTTOM: 1.3312 + aPart = mozilla::widget::themeconst::WP_FRAMEBOTTOM; 1.3313 + aState = GetTopLevelWindowActiveState(aFrame); 1.3314 + return NS_OK; 1.3315 + case NS_THEME_WINDOW_BUTTON_CLOSE: 1.3316 + aPart = DFC_CAPTION; 1.3317 + aState = DFCS_CAPTIONCLOSE | 1.3318 + GetClassicWindowFrameButtonState(GetContentState(aFrame, 1.3319 + aWidgetType)); 1.3320 + return NS_OK; 1.3321 + case NS_THEME_WINDOW_BUTTON_MINIMIZE: 1.3322 + aPart = DFC_CAPTION; 1.3323 + aState = DFCS_CAPTIONMIN | 1.3324 + GetClassicWindowFrameButtonState(GetContentState(aFrame, 1.3325 + aWidgetType)); 1.3326 + return NS_OK; 1.3327 + case NS_THEME_WINDOW_BUTTON_MAXIMIZE: 1.3328 + aPart = DFC_CAPTION; 1.3329 + aState = DFCS_CAPTIONMAX | 1.3330 + GetClassicWindowFrameButtonState(GetContentState(aFrame, 1.3331 + aWidgetType)); 1.3332 + return NS_OK; 1.3333 + case NS_THEME_WINDOW_BUTTON_RESTORE: 1.3334 + aPart = DFC_CAPTION; 1.3335 + aState = DFCS_CAPTIONRESTORE | 1.3336 + GetClassicWindowFrameButtonState(GetContentState(aFrame, 1.3337 + aWidgetType)); 1.3338 + return NS_OK; 1.3339 + } 1.3340 + return NS_ERROR_FAILURE; 1.3341 +} 1.3342 + 1.3343 +// Draw classic Windows tab 1.3344 +// (no system API for this, but DrawEdge can draw all the parts of a tab) 1.3345 +static void DrawTab(HDC hdc, const RECT& R, int32_t aPosition, bool aSelected, 1.3346 + bool aDrawLeft, bool aDrawRight) 1.3347 +{ 1.3348 + int32_t leftFlag, topFlag, rightFlag, lightFlag, shadeFlag; 1.3349 + RECT topRect, sideRect, bottomRect, lightRect, shadeRect; 1.3350 + int32_t selectedOffset, lOffset, rOffset; 1.3351 + 1.3352 + selectedOffset = aSelected ? 1 : 0; 1.3353 + lOffset = aDrawLeft ? 2 : 0; 1.3354 + rOffset = aDrawRight ? 2 : 0; 1.3355 + 1.3356 + // Get info for tab orientation/position (Left, Top, Right, Bottom) 1.3357 + switch (aPosition) { 1.3358 + case BF_LEFT: 1.3359 + leftFlag = BF_TOP; topFlag = BF_LEFT; 1.3360 + rightFlag = BF_BOTTOM; 1.3361 + lightFlag = BF_DIAGONAL_ENDTOPRIGHT; 1.3362 + shadeFlag = BF_DIAGONAL_ENDBOTTOMRIGHT; 1.3363 + 1.3364 + ::SetRect(&topRect, R.left, R.top+lOffset, R.right, R.bottom-rOffset); 1.3365 + ::SetRect(&sideRect, R.left+2, R.top, R.right-2+selectedOffset, R.bottom); 1.3366 + ::SetRect(&bottomRect, R.right-2, R.top, R.right, R.bottom); 1.3367 + ::SetRect(&lightRect, R.left, R.top, R.left+3, R.top+3); 1.3368 + ::SetRect(&shadeRect, R.left+1, R.bottom-2, R.left+2, R.bottom-1); 1.3369 + break; 1.3370 + case BF_TOP: 1.3371 + leftFlag = BF_LEFT; topFlag = BF_TOP; 1.3372 + rightFlag = BF_RIGHT; 1.3373 + lightFlag = BF_DIAGONAL_ENDTOPRIGHT; 1.3374 + shadeFlag = BF_DIAGONAL_ENDBOTTOMRIGHT; 1.3375 + 1.3376 + ::SetRect(&topRect, R.left+lOffset, R.top, R.right-rOffset, R.bottom); 1.3377 + ::SetRect(&sideRect, R.left, R.top+2, R.right, R.bottom-1+selectedOffset); 1.3378 + ::SetRect(&bottomRect, R.left, R.bottom-1, R.right, R.bottom); 1.3379 + ::SetRect(&lightRect, R.left, R.top, R.left+3, R.top+3); 1.3380 + ::SetRect(&shadeRect, R.right-2, R.top+1, R.right-1, R.top+2); 1.3381 + break; 1.3382 + case BF_RIGHT: 1.3383 + leftFlag = BF_TOP; topFlag = BF_RIGHT; 1.3384 + rightFlag = BF_BOTTOM; 1.3385 + lightFlag = BF_DIAGONAL_ENDTOPLEFT; 1.3386 + shadeFlag = BF_DIAGONAL_ENDBOTTOMLEFT; 1.3387 + 1.3388 + ::SetRect(&topRect, R.left, R.top+lOffset, R.right, R.bottom-rOffset); 1.3389 + ::SetRect(&sideRect, R.left+2-selectedOffset, R.top, R.right-2, R.bottom); 1.3390 + ::SetRect(&bottomRect, R.left, R.top, R.left+2, R.bottom); 1.3391 + ::SetRect(&lightRect, R.right-3, R.top, R.right-1, R.top+2); 1.3392 + ::SetRect(&shadeRect, R.right-2, R.bottom-3, R.right, R.bottom-1); 1.3393 + break; 1.3394 + case BF_BOTTOM: 1.3395 + leftFlag = BF_LEFT; topFlag = BF_BOTTOM; 1.3396 + rightFlag = BF_RIGHT; 1.3397 + lightFlag = BF_DIAGONAL_ENDTOPLEFT; 1.3398 + shadeFlag = BF_DIAGONAL_ENDBOTTOMLEFT; 1.3399 + 1.3400 + ::SetRect(&topRect, R.left+lOffset, R.top, R.right-rOffset, R.bottom); 1.3401 + ::SetRect(&sideRect, R.left, R.top+2-selectedOffset, R.right, R.bottom-2); 1.3402 + ::SetRect(&bottomRect, R.left, R.top, R.right, R.top+2); 1.3403 + ::SetRect(&lightRect, R.left, R.bottom-3, R.left+2, R.bottom-1); 1.3404 + ::SetRect(&shadeRect, R.right-2, R.bottom-3, R.right, R.bottom-1); 1.3405 + break; 1.3406 + } 1.3407 + 1.3408 + // Background 1.3409 + ::FillRect(hdc, &R, (HBRUSH) (COLOR_3DFACE+1) ); 1.3410 + 1.3411 + // Tab "Top" 1.3412 + ::DrawEdge(hdc, &topRect, EDGE_RAISED, BF_SOFT | topFlag); 1.3413 + 1.3414 + // Tab "Bottom" 1.3415 + if (!aSelected) 1.3416 + ::DrawEdge(hdc, &bottomRect, EDGE_RAISED, BF_SOFT | topFlag); 1.3417 + 1.3418 + // Tab "Sides" 1.3419 + if (!aDrawLeft) 1.3420 + leftFlag = 0; 1.3421 + if (!aDrawRight) 1.3422 + rightFlag = 0; 1.3423 + ::DrawEdge(hdc, &sideRect, EDGE_RAISED, BF_SOFT | leftFlag | rightFlag); 1.3424 + 1.3425 + // Tab Diagonal Corners 1.3426 + if (aDrawLeft) 1.3427 + ::DrawEdge(hdc, &lightRect, EDGE_RAISED, BF_SOFT | lightFlag); 1.3428 + 1.3429 + if (aDrawRight) 1.3430 + ::DrawEdge(hdc, &shadeRect, EDGE_RAISED, BF_SOFT | shadeFlag); 1.3431 +} 1.3432 + 1.3433 +static void DrawMenuImage(HDC hdc, const RECT& rc, int32_t aComponent, uint32_t aColor) 1.3434 +{ 1.3435 + // This procedure creates a memory bitmap to contain the check mark, draws 1.3436 + // it into the bitmap (it is a mask image), then composes it onto the menu 1.3437 + // item in appropriate colors. 1.3438 + HDC hMemoryDC = ::CreateCompatibleDC(hdc); 1.3439 + if (hMemoryDC) { 1.3440 + // XXXjgr We should ideally be caching these, but we wont be notified when 1.3441 + // they change currently, so we can't do so easily. Same for the bitmap. 1.3442 + int checkW = ::GetSystemMetrics(SM_CXMENUCHECK); 1.3443 + int checkH = ::GetSystemMetrics(SM_CYMENUCHECK); 1.3444 + 1.3445 + HBITMAP hMonoBitmap = ::CreateBitmap(checkW, checkH, 1, 1, nullptr); 1.3446 + if (hMonoBitmap) { 1.3447 + 1.3448 + HBITMAP hPrevBitmap = (HBITMAP) ::SelectObject(hMemoryDC, hMonoBitmap); 1.3449 + if (hPrevBitmap) { 1.3450 + 1.3451 + // XXXjgr This will go pear-shaped if the image is bigger than the 1.3452 + // provided rect. What should we do? 1.3453 + RECT imgRect = { 0, 0, checkW, checkH }; 1.3454 + POINT imgPos = { 1.3455 + rc.left + (rc.right - rc.left - checkW) / 2, 1.3456 + rc.top + (rc.bottom - rc.top - checkH) / 2 1.3457 + }; 1.3458 + 1.3459 + // XXXzeniko Windows renders these 1px lower than you'd expect 1.3460 + if (aComponent == DFCS_MENUCHECK || aComponent == DFCS_MENUBULLET) 1.3461 + imgPos.y++; 1.3462 + 1.3463 + ::DrawFrameControl(hMemoryDC, &imgRect, DFC_MENU, aComponent); 1.3464 + COLORREF oldTextCol = ::SetTextColor(hdc, 0x00000000); 1.3465 + COLORREF oldBackCol = ::SetBkColor(hdc, 0x00FFFFFF); 1.3466 + ::BitBlt(hdc, imgPos.x, imgPos.y, checkW, checkH, hMemoryDC, 0, 0, SRCAND); 1.3467 + ::SetTextColor(hdc, ::GetSysColor(aColor)); 1.3468 + ::SetBkColor(hdc, 0x00000000); 1.3469 + ::BitBlt(hdc, imgPos.x, imgPos.y, checkW, checkH, hMemoryDC, 0, 0, SRCPAINT); 1.3470 + ::SetTextColor(hdc, oldTextCol); 1.3471 + ::SetBkColor(hdc, oldBackCol); 1.3472 + ::SelectObject(hMemoryDC, hPrevBitmap); 1.3473 + } 1.3474 + ::DeleteObject(hMonoBitmap); 1.3475 + } 1.3476 + ::DeleteDC(hMemoryDC); 1.3477 + } 1.3478 +} 1.3479 + 1.3480 +void nsNativeThemeWin::DrawCheckedRect(HDC hdc, const RECT& rc, int32_t fore, int32_t back, 1.3481 + HBRUSH defaultBack) 1.3482 +{ 1.3483 + static WORD patBits[8] = { 1.3484 + 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 1.3485 + }; 1.3486 + 1.3487 + HBITMAP patBmp = ::CreateBitmap(8, 8, 1, 1, patBits); 1.3488 + if (patBmp) { 1.3489 + HBRUSH brush = (HBRUSH) ::CreatePatternBrush(patBmp); 1.3490 + if (brush) { 1.3491 + COLORREF oldForeColor = ::SetTextColor(hdc, ::GetSysColor(fore)); 1.3492 + COLORREF oldBackColor = ::SetBkColor(hdc, ::GetSysColor(back)); 1.3493 + POINT vpOrg; 1.3494 + 1.3495 + ::UnrealizeObject(brush); 1.3496 + ::GetViewportOrgEx(hdc, &vpOrg); 1.3497 + ::SetBrushOrgEx(hdc, vpOrg.x + rc.left, vpOrg.y + rc.top, nullptr); 1.3498 + HBRUSH oldBrush = (HBRUSH) ::SelectObject(hdc, brush); 1.3499 + ::FillRect(hdc, &rc, brush); 1.3500 + ::SetTextColor(hdc, oldForeColor); 1.3501 + ::SetBkColor(hdc, oldBackColor); 1.3502 + ::SelectObject(hdc, oldBrush); 1.3503 + ::DeleteObject(brush); 1.3504 + } 1.3505 + else 1.3506 + ::FillRect(hdc, &rc, defaultBack); 1.3507 + 1.3508 + ::DeleteObject(patBmp); 1.3509 + } 1.3510 +} 1.3511 + 1.3512 +nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(nsRenderingContext* aContext, 1.3513 + nsIFrame* aFrame, 1.3514 + uint8_t aWidgetType, 1.3515 + const nsRect& aRect, 1.3516 + const nsRect& aDirtyRect) 1.3517 +{ 1.3518 + int32_t part, state; 1.3519 + bool focused; 1.3520 + nsresult rv; 1.3521 + rv = ClassicGetThemePartAndState(aFrame, aWidgetType, part, state, focused); 1.3522 + if (NS_FAILED(rv)) 1.3523 + return rv; 1.3524 + 1.3525 + if (AssumeThemePartAndStateAreTransparent(part, state)) { 1.3526 + return NS_OK; 1.3527 + } 1.3528 + 1.3529 + gfxFloat p2a = gfxFloat(aContext->AppUnitsPerDevPixel()); 1.3530 + RECT widgetRect; 1.3531 + gfxRect tr(aRect.x, aRect.y, aRect.width, aRect.height), 1.3532 + dr(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); 1.3533 + 1.3534 + tr.ScaleInverse(p2a); 1.3535 + dr.ScaleInverse(p2a); 1.3536 + 1.3537 + nsRefPtr<gfxContext> ctx = aContext->ThebesContext(); 1.3538 + 1.3539 + gfxWindowsNativeDrawing nativeDrawing(ctx, dr, GetWidgetNativeDrawingFlags(aWidgetType)); 1.3540 + 1.3541 +RENDER_AGAIN: 1.3542 + 1.3543 + HDC hdc = nativeDrawing.BeginNativeDrawing(); 1.3544 + if (!hdc) 1.3545 + return NS_ERROR_FAILURE; 1.3546 + 1.3547 + nativeDrawing.TransformToNativeRect(tr, widgetRect); 1.3548 + 1.3549 + rv = NS_OK; 1.3550 + switch (aWidgetType) { 1.3551 + // Draw button 1.3552 + case NS_THEME_BUTTON: { 1.3553 + if (focused) { 1.3554 + // draw dark button focus border first 1.3555 + HBRUSH brush; 1.3556 + brush = ::GetSysColorBrush(COLOR_3DDKSHADOW); 1.3557 + if (brush) 1.3558 + ::FrameRect(hdc, &widgetRect, brush); 1.3559 + InflateRect(&widgetRect, -1, -1); 1.3560 + } 1.3561 + // fall-through... 1.3562 + } 1.3563 + // Draw controls supported by DrawFrameControl 1.3564 + case NS_THEME_CHECKBOX: 1.3565 + case NS_THEME_RADIO: 1.3566 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.3567 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.3568 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.3569 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: 1.3570 + case NS_THEME_SPINNER_UP_BUTTON: 1.3571 + case NS_THEME_SPINNER_DOWN_BUTTON: 1.3572 + case NS_THEME_DROPDOWN_BUTTON: 1.3573 + case NS_THEME_RESIZER: { 1.3574 + int32_t oldTA; 1.3575 + // setup DC to make DrawFrameControl draw correctly 1.3576 + oldTA = ::SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); 1.3577 + ::DrawFrameControl(hdc, &widgetRect, part, state); 1.3578 + ::SetTextAlign(hdc, oldTA); 1.3579 + 1.3580 + // Draw focus rectangles for HTML checkboxes and radio buttons 1.3581 + // XXX it'd be nice to draw these outside of the frame 1.3582 + if (focused && (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO)) { 1.3583 + // setup DC to make DrawFocusRect draw correctly 1.3584 + POINT vpOrg; 1.3585 + ::GetViewportOrgEx(hdc, &vpOrg); 1.3586 + ::SetBrushOrgEx(hdc, vpOrg.x + widgetRect.left, vpOrg.y + widgetRect.top, nullptr); 1.3587 + int32_t oldColor; 1.3588 + oldColor = ::SetTextColor(hdc, 0); 1.3589 + // draw focus rectangle 1.3590 + ::DrawFocusRect(hdc, &widgetRect); 1.3591 + ::SetTextColor(hdc, oldColor); 1.3592 + } 1.3593 + break; 1.3594 + } 1.3595 + // Draw controls with 2px 3D inset border 1.3596 + case NS_THEME_NUMBER_INPUT: 1.3597 + case NS_THEME_TEXTFIELD: 1.3598 + case NS_THEME_TEXTFIELD_MULTILINE: 1.3599 + case NS_THEME_LISTBOX: 1.3600 + case NS_THEME_DROPDOWN: 1.3601 + case NS_THEME_DROPDOWN_TEXTFIELD: { 1.3602 + // Draw inset edge 1.3603 + ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 1.3604 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.3605 + 1.3606 + // Fill in background 1.3607 + if (IsDisabled(aFrame, eventState) || 1.3608 + (aFrame->GetContent()->IsXUL() && 1.3609 + IsReadOnly(aFrame))) 1.3610 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_BTNFACE+1)); 1.3611 + else 1.3612 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_WINDOW+1)); 1.3613 + 1.3614 + break; 1.3615 + } 1.3616 + case NS_THEME_TREEVIEW: { 1.3617 + // Draw inset edge 1.3618 + ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 1.3619 + 1.3620 + // Fill in window color background 1.3621 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_WINDOW+1)); 1.3622 + 1.3623 + break; 1.3624 + } 1.3625 + // Draw ToolTip background 1.3626 + case NS_THEME_TOOLTIP: 1.3627 + ::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_WINDOWFRAME)); 1.3628 + InflateRect(&widgetRect, -1, -1); 1.3629 + ::FillRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_INFOBK)); 1.3630 + 1.3631 + break; 1.3632 + case NS_THEME_GROUPBOX: 1.3633 + ::DrawEdge(hdc, &widgetRect, EDGE_ETCHED, BF_RECT | BF_ADJUST); 1.3634 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_BTNFACE+1)); 1.3635 + break; 1.3636 + // Draw 3D face background controls 1.3637 + case NS_THEME_PROGRESSBAR: 1.3638 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.3639 + // Draw 3D border 1.3640 + ::DrawEdge(hdc, &widgetRect, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); 1.3641 + InflateRect(&widgetRect, -1, -1); 1.3642 + // fall through 1.3643 + case NS_THEME_TAB_PANEL: 1.3644 + case NS_THEME_STATUSBAR: 1.3645 + case NS_THEME_STATUSBAR_RESIZER_PANEL: { 1.3646 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_BTNFACE+1)); 1.3647 + 1.3648 + break; 1.3649 + } 1.3650 + // Draw 3D inset statusbar panel 1.3651 + case NS_THEME_STATUSBAR_PANEL: { 1.3652 + if (aFrame->GetNextSibling()) 1.3653 + widgetRect.right -= 2; // space between sibling status panels 1.3654 + 1.3655 + ::DrawEdge(hdc, &widgetRect, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); 1.3656 + 1.3657 + break; 1.3658 + } 1.3659 + // Draw scrollbar thumb 1.3660 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.3661 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.3662 + ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_MIDDLE); 1.3663 + 1.3664 + break; 1.3665 + case NS_THEME_RANGE_THUMB: 1.3666 + case NS_THEME_SCALE_THUMB_VERTICAL: 1.3667 + case NS_THEME_SCALE_THUMB_HORIZONTAL: { 1.3668 + EventStates eventState = GetContentState(aFrame, aWidgetType); 1.3669 + 1.3670 + ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST); 1.3671 + if (IsDisabled(aFrame, eventState)) { 1.3672 + DrawCheckedRect(hdc, widgetRect, COLOR_3DFACE, COLOR_3DHILIGHT, 1.3673 + (HBRUSH) COLOR_3DHILIGHT); 1.3674 + } 1.3675 + 1.3676 + break; 1.3677 + } 1.3678 + // Draw scrollbar track background 1.3679 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.3680 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: { 1.3681 + 1.3682 + // Windows fills in the scrollbar track differently 1.3683 + // depending on whether these are equal 1.3684 + DWORD color3D, colorScrollbar, colorWindow; 1.3685 + 1.3686 + color3D = ::GetSysColor(COLOR_3DFACE); 1.3687 + colorWindow = ::GetSysColor(COLOR_WINDOW); 1.3688 + colorScrollbar = ::GetSysColor(COLOR_SCROLLBAR); 1.3689 + 1.3690 + if ((color3D != colorScrollbar) && (colorWindow != colorScrollbar)) 1.3691 + // Use solid brush 1.3692 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_SCROLLBAR+1)); 1.3693 + else 1.3694 + { 1.3695 + DrawCheckedRect(hdc, widgetRect, COLOR_3DHILIGHT, COLOR_3DFACE, 1.3696 + (HBRUSH) COLOR_SCROLLBAR+1); 1.3697 + } 1.3698 + // XXX should invert the part of the track being clicked here 1.3699 + // but the track is never :active 1.3700 + 1.3701 + break; 1.3702 + } 1.3703 + // Draw scale track background 1.3704 + case NS_THEME_RANGE: 1.3705 + case NS_THEME_SCALE_VERTICAL: 1.3706 + case NS_THEME_SCALE_HORIZONTAL: { 1.3707 + const int32_t trackWidth = 4; 1.3708 + // When rounding is necessary, we round the position of the track 1.3709 + // away from the chevron of the thumb to make it look better. 1.3710 + if (aWidgetType == NS_THEME_SCALE_HORIZONTAL || 1.3711 + (aWidgetType == NS_THEME_RANGE && IsRangeHorizontal(aFrame))) { 1.3712 + widgetRect.top += (widgetRect.bottom - widgetRect.top - trackWidth) / 2; 1.3713 + widgetRect.bottom = widgetRect.top + trackWidth; 1.3714 + } 1.3715 + else { 1.3716 + if (!IsFrameRTL(aFrame)) { 1.3717 + widgetRect.left += (widgetRect.right - widgetRect.left - trackWidth) / 2; 1.3718 + widgetRect.right = widgetRect.left + trackWidth; 1.3719 + } else { 1.3720 + widgetRect.right -= (widgetRect.right - widgetRect.left - trackWidth) / 2; 1.3721 + widgetRect.left = widgetRect.right - trackWidth; 1.3722 + } 1.3723 + } 1.3724 + 1.3725 + ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 1.3726 + ::FillRect(hdc, &widgetRect, (HBRUSH) GetStockObject(GRAY_BRUSH)); 1.3727 + 1.3728 + break; 1.3729 + } 1.3730 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: 1.3731 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); 1.3732 + break; 1.3733 + 1.3734 + case NS_THEME_PROGRESSBAR_CHUNK: { 1.3735 + nsIFrame* stateFrame = aFrame->GetParent(); 1.3736 + EventStates eventStates = GetContentState(stateFrame, aWidgetType); 1.3737 + 1.3738 + bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates); 1.3739 + bool vertical = IsVerticalProgress(stateFrame) || 1.3740 + aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL; 1.3741 + int32_t overlayPart = GetProgressOverlayStyle(vertical); 1.3742 + 1.3743 + nsIContent* content = aFrame->GetContent(); 1.3744 + if (!indeterminate || !content) { 1.3745 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); 1.3746 + break; 1.3747 + } 1.3748 + 1.3749 + RECT overlayRect = 1.3750 + CalculateProgressOverlayRect(aFrame, &widgetRect, vertical, 1.3751 + indeterminate, true); 1.3752 + 1.3753 + ::FillRect(hdc, &overlayRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); 1.3754 + 1.3755 + if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) { 1.3756 + NS_WARNING("unable to animate progress widget!"); 1.3757 + } 1.3758 + break; 1.3759 + } 1.3760 + 1.3761 + // Draw Tab 1.3762 + case NS_THEME_TAB: { 1.3763 + DrawTab(hdc, widgetRect, 1.3764 + IsBottomTab(aFrame) ? BF_BOTTOM : BF_TOP, 1.3765 + IsSelectedTab(aFrame), 1.3766 + !IsRightToSelectedTab(aFrame), 1.3767 + !IsLeftToSelectedTab(aFrame)); 1.3768 + 1.3769 + break; 1.3770 + } 1.3771 + case NS_THEME_TAB_PANELS: 1.3772 + ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_SOFT | BF_MIDDLE | 1.3773 + BF_LEFT | BF_RIGHT | BF_BOTTOM); 1.3774 + 1.3775 + break; 1.3776 + case NS_THEME_MENUBAR: 1.3777 + break; 1.3778 + case NS_THEME_MENUPOPUP: 1.3779 + NS_ASSERTION(nsUXThemeData::sFlatMenus, "Classic menus are styled entirely through CSS"); 1.3780 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_MENU+1)); 1.3781 + ::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_BTNSHADOW)); 1.3782 + break; 1.3783 + case NS_THEME_MENUITEM: 1.3784 + case NS_THEME_CHECKMENUITEM: 1.3785 + case NS_THEME_RADIOMENUITEM: 1.3786 + // part == 0 for normal items 1.3787 + // part == 1 for top-level menu items 1.3788 + if (nsUXThemeData::sFlatMenus) { 1.3789 + // Not disabled and hot/pushed. 1.3790 + if ((state & (DFCS_HOT | DFCS_PUSHED)) != 0) { 1.3791 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_MENUHILIGHT+1)); 1.3792 + ::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_HIGHLIGHT)); 1.3793 + } 1.3794 + } else { 1.3795 + if (part == 1) { 1.3796 + if ((state & DFCS_INACTIVE) == 0) { 1.3797 + if ((state & DFCS_PUSHED) != 0) { 1.3798 + ::DrawEdge(hdc, &widgetRect, BDR_SUNKENOUTER, BF_RECT); 1.3799 + } else if ((state & DFCS_HOT) != 0) { 1.3800 + ::DrawEdge(hdc, &widgetRect, BDR_RAISEDINNER, BF_RECT); 1.3801 + } 1.3802 + } 1.3803 + } else { 1.3804 + if ((state & (DFCS_HOT | DFCS_PUSHED)) != 0) { 1.3805 + ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); 1.3806 + } 1.3807 + } 1.3808 + } 1.3809 + break; 1.3810 + case NS_THEME_MENUCHECKBOX: 1.3811 + case NS_THEME_MENURADIO: 1.3812 + if (!(state & DFCS_CHECKED)) 1.3813 + break; // nothin' to do 1.3814 + case NS_THEME_MENUARROW: { 1.3815 + uint32_t color = COLOR_MENUTEXT; 1.3816 + if ((state & DFCS_INACTIVE)) 1.3817 + color = COLOR_GRAYTEXT; 1.3818 + else if ((state & DFCS_HOT)) 1.3819 + color = COLOR_HIGHLIGHTTEXT; 1.3820 + 1.3821 + if (aWidgetType == NS_THEME_MENUCHECKBOX) 1.3822 + DrawMenuImage(hdc, widgetRect, DFCS_MENUCHECK, color); 1.3823 + else if (aWidgetType == NS_THEME_MENURADIO) 1.3824 + DrawMenuImage(hdc, widgetRect, DFCS_MENUBULLET, color); 1.3825 + else if (aWidgetType == NS_THEME_MENUARROW) 1.3826 + DrawMenuImage(hdc, widgetRect, 1.3827 + (state & DFCS_RTL) ? DFCS_MENUARROWRIGHT : DFCS_MENUARROW, 1.3828 + color); 1.3829 + break; 1.3830 + } 1.3831 + case NS_THEME_MENUSEPARATOR: { 1.3832 + // separators are offset by a bit (see menu.css) 1.3833 + widgetRect.left++; 1.3834 + widgetRect.right--; 1.3835 + 1.3836 + // This magic number is brought to you by the value in menu.css 1.3837 + widgetRect.top += 4; 1.3838 + // Our rectangles are 1 pixel high (see border size in menu.css) 1.3839 + widgetRect.bottom = widgetRect.top+1; 1.3840 + ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_3DSHADOW+1)); 1.3841 + widgetRect.top++; 1.3842 + widgetRect.bottom++; 1.3843 + ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_3DHILIGHT+1)); 1.3844 + break; 1.3845 + } 1.3846 + 1.3847 + case NS_THEME_WINDOW_TITLEBAR: 1.3848 + case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: 1.3849 + { 1.3850 + RECT rect = widgetRect; 1.3851 + int32_t offset = GetSystemMetrics(SM_CXFRAME); 1.3852 + rect.bottom -= 1; 1.3853 + 1.3854 + // first fill the area to the color of the window background 1.3855 + FillRect(hdc, &rect, (HBRUSH)(COLOR_3DFACE+1)); 1.3856 + 1.3857 + // inset the caption area so it doesn't overflow. 1.3858 + rect.top += offset; 1.3859 + // if enabled, draw a gradient titlebar background, otherwise 1.3860 + // fill with a solid color. 1.3861 + BOOL bFlag = TRUE; 1.3862 + SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &bFlag, 0); 1.3863 + if (!bFlag) { 1.3864 + if (state == mozilla::widget::themeconst::FS_ACTIVE) 1.3865 + FillRect(hdc, &rect, (HBRUSH)(COLOR_ACTIVECAPTION+1)); 1.3866 + else 1.3867 + FillRect(hdc, &rect, (HBRUSH)(COLOR_INACTIVECAPTION+1)); 1.3868 + } else { 1.3869 + DWORD startColor, endColor; 1.3870 + if (state == mozilla::widget::themeconst::FS_ACTIVE) { 1.3871 + startColor = GetSysColor(COLOR_ACTIVECAPTION); 1.3872 + endColor = GetSysColor(COLOR_GRADIENTACTIVECAPTION); 1.3873 + } else { 1.3874 + startColor = GetSysColor(COLOR_INACTIVECAPTION); 1.3875 + endColor = GetSysColor(COLOR_GRADIENTINACTIVECAPTION); 1.3876 + } 1.3877 + 1.3878 + TRIVERTEX vertex[2]; 1.3879 + vertex[0].x = rect.left; 1.3880 + vertex[0].y = rect.top; 1.3881 + vertex[0].Red = GetRValue(startColor) << 8; 1.3882 + vertex[0].Green = GetGValue(startColor) << 8; 1.3883 + vertex[0].Blue = GetBValue(startColor) << 8; 1.3884 + vertex[0].Alpha = 0; 1.3885 + 1.3886 + vertex[1].x = rect.right; 1.3887 + vertex[1].y = rect.bottom; 1.3888 + vertex[1].Red = GetRValue(endColor) << 8; 1.3889 + vertex[1].Green = GetGValue(endColor) << 8; 1.3890 + vertex[1].Blue = GetBValue(endColor) << 8; 1.3891 + vertex[1].Alpha = 0; 1.3892 + 1.3893 + GRADIENT_RECT gRect; 1.3894 + gRect.UpperLeft = 0; 1.3895 + gRect.LowerRight = 1; 1.3896 + // available on win2k & up 1.3897 + GradientFill(hdc, vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_H); 1.3898 + } 1.3899 + 1.3900 + if (aWidgetType == NS_THEME_WINDOW_TITLEBAR) { 1.3901 + // frame things up with a top raised border. 1.3902 + DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_TOP); 1.3903 + } 1.3904 + break; 1.3905 + } 1.3906 + 1.3907 + case NS_THEME_WINDOW_FRAME_LEFT: 1.3908 + DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_LEFT); 1.3909 + break; 1.3910 + 1.3911 + case NS_THEME_WINDOW_FRAME_RIGHT: 1.3912 + DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RIGHT); 1.3913 + break; 1.3914 + 1.3915 + case NS_THEME_WINDOW_FRAME_BOTTOM: 1.3916 + DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_BOTTOM); 1.3917 + break; 1.3918 + 1.3919 + case NS_THEME_WINDOW_BUTTON_CLOSE: 1.3920 + case NS_THEME_WINDOW_BUTTON_MINIMIZE: 1.3921 + case NS_THEME_WINDOW_BUTTON_MAXIMIZE: 1.3922 + case NS_THEME_WINDOW_BUTTON_RESTORE: 1.3923 + { 1.3924 + if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) { 1.3925 + OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_MINIMIZE); 1.3926 + } 1.3927 + else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE || 1.3928 + aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { 1.3929 + OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_RESTORE); 1.3930 + } 1.3931 + else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) { 1.3932 + OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_CLOSE); 1.3933 + } 1.3934 + int32_t oldTA = SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); 1.3935 + DrawFrameControl(hdc, &widgetRect, part, state); 1.3936 + SetTextAlign(hdc, oldTA); 1.3937 + break; 1.3938 + } 1.3939 + 1.3940 + default: 1.3941 + rv = NS_ERROR_FAILURE; 1.3942 + break; 1.3943 + } 1.3944 + 1.3945 + nativeDrawing.EndNativeDrawing(); 1.3946 + 1.3947 + if (NS_FAILED(rv)) 1.3948 + return rv; 1.3949 + 1.3950 + if (nativeDrawing.ShouldRenderAgain()) 1.3951 + goto RENDER_AGAIN; 1.3952 + 1.3953 + nativeDrawing.PaintToContext(); 1.3954 + 1.3955 + return rv; 1.3956 +} 1.3957 + 1.3958 +uint32_t 1.3959 +nsNativeThemeWin::GetWidgetNativeDrawingFlags(uint8_t aWidgetType) 1.3960 +{ 1.3961 + switch (aWidgetType) { 1.3962 + case NS_THEME_BUTTON: 1.3963 + case NS_THEME_NUMBER_INPUT: 1.3964 + case NS_THEME_TEXTFIELD: 1.3965 + case NS_THEME_TEXTFIELD_MULTILINE: 1.3966 + 1.3967 + case NS_THEME_DROPDOWN: 1.3968 + case NS_THEME_DROPDOWN_TEXTFIELD: 1.3969 + return 1.3970 + gfxWindowsNativeDrawing::CANNOT_DRAW_TO_COLOR_ALPHA | 1.3971 + gfxWindowsNativeDrawing::CAN_AXIS_ALIGNED_SCALE | 1.3972 + gfxWindowsNativeDrawing::CANNOT_COMPLEX_TRANSFORM; 1.3973 + 1.3974 + // need to check these others 1.3975 + case NS_THEME_RANGE: 1.3976 + case NS_THEME_RANGE_THUMB: 1.3977 + case NS_THEME_SCROLLBAR_BUTTON_UP: 1.3978 + case NS_THEME_SCROLLBAR_BUTTON_DOWN: 1.3979 + case NS_THEME_SCROLLBAR_BUTTON_LEFT: 1.3980 + case NS_THEME_SCROLLBAR_BUTTON_RIGHT: 1.3981 + case NS_THEME_SCROLLBAR_THUMB_VERTICAL: 1.3982 + case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: 1.3983 + case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 1.3984 + case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: 1.3985 + case NS_THEME_SCALE_HORIZONTAL: 1.3986 + case NS_THEME_SCALE_VERTICAL: 1.3987 + case NS_THEME_SCALE_THUMB_HORIZONTAL: 1.3988 + case NS_THEME_SCALE_THUMB_VERTICAL: 1.3989 + case NS_THEME_SPINNER_UP_BUTTON: 1.3990 + case NS_THEME_SPINNER_DOWN_BUTTON: 1.3991 + case NS_THEME_LISTBOX: 1.3992 + case NS_THEME_TREEVIEW: 1.3993 + case NS_THEME_TOOLTIP: 1.3994 + case NS_THEME_STATUSBAR: 1.3995 + case NS_THEME_STATUSBAR_PANEL: 1.3996 + case NS_THEME_STATUSBAR_RESIZER_PANEL: 1.3997 + case NS_THEME_RESIZER: 1.3998 + case NS_THEME_PROGRESSBAR: 1.3999 + case NS_THEME_PROGRESSBAR_VERTICAL: 1.4000 + case NS_THEME_PROGRESSBAR_CHUNK: 1.4001 + case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: 1.4002 + case NS_THEME_TAB: 1.4003 + case NS_THEME_TAB_PANEL: 1.4004 + case NS_THEME_TAB_PANELS: 1.4005 + case NS_THEME_MENUBAR: 1.4006 + case NS_THEME_MENUPOPUP: 1.4007 + case NS_THEME_MENUITEM: 1.4008 + break; 1.4009 + 1.4010 + // the dropdown button /almost/ renders correctly with scaling, 1.4011 + // except that the graphic in the dropdown button (the downward arrow) 1.4012 + // doesn't get scaled up. 1.4013 + case NS_THEME_DROPDOWN_BUTTON: 1.4014 + // these are definitely no; they're all graphics that don't get scaled up 1.4015 + case NS_THEME_CHECKBOX: 1.4016 + case NS_THEME_RADIO: 1.4017 + case NS_THEME_GROUPBOX: 1.4018 + case NS_THEME_CHECKMENUITEM: 1.4019 + case NS_THEME_RADIOMENUITEM: 1.4020 + case NS_THEME_MENUCHECKBOX: 1.4021 + case NS_THEME_MENURADIO: 1.4022 + case NS_THEME_MENUARROW: 1.4023 + return 1.4024 + gfxWindowsNativeDrawing::CANNOT_DRAW_TO_COLOR_ALPHA | 1.4025 + gfxWindowsNativeDrawing::CANNOT_AXIS_ALIGNED_SCALE | 1.4026 + gfxWindowsNativeDrawing::CANNOT_COMPLEX_TRANSFORM; 1.4027 + } 1.4028 + 1.4029 + return 1.4030 + gfxWindowsNativeDrawing::CANNOT_DRAW_TO_COLOR_ALPHA | 1.4031 + gfxWindowsNativeDrawing::CANNOT_AXIS_ALIGNED_SCALE | 1.4032 + gfxWindowsNativeDrawing::CANNOT_COMPLEX_TRANSFORM; 1.4033 +} 1.4034 + 1.4035 +/////////////////////////////////////////// 1.4036 +// Creation Routine 1.4037 +/////////////////////////////////////////// 1.4038 + 1.4039 +// from nsWindow.cpp 1.4040 +extern bool gDisableNativeTheme; 1.4041 + 1.4042 +nsresult NS_NewNativeTheme(nsISupports *aOuter, REFNSIID aIID, void **aResult) 1.4043 +{ 1.4044 + if (gDisableNativeTheme) 1.4045 + return NS_ERROR_NO_INTERFACE; 1.4046 + 1.4047 + if (aOuter) 1.4048 + return NS_ERROR_NO_AGGREGATION; 1.4049 + 1.4050 + nsNativeThemeWin* theme = new nsNativeThemeWin(); 1.4051 + if (!theme) 1.4052 + return NS_ERROR_OUT_OF_MEMORY; 1.4053 + return theme->QueryInterface(aIID, aResult); 1.4054 +}