/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
auto nsNativeThemeWin::IsWidgetNonNative(
nsIFrame* aFrame, StyleAppearance aAppearance) -> NonNative { if (IsWidgetAlwaysNonNative(aFrame, aAppearance)) { return NonNative::Always;
}
// We only know how to draw light widgets, so we defer to the non-native // theme when appropriate. if (Theme::ThemeSupportsWidget(aFrame->PresContext(), aFrame, aAppearance) &&
LookAndFeel::ColorSchemeForFrame(aFrame) ==
LookAndFeel::ColorScheme::Dark) { return NonNative::BecauseColorMismatch;
} return NonNative::No;
}
int leftMargin = checkboxMargins.cxLeftWidth; int rightMargin = checkboxMargins.cxRightWidth; int topMargin = checkboxMargins.cyTopHeight; int bottomMargin = checkboxMargins.cyBottomHeight;
// Figure out how big the menuitem's icon will be (if present) at current DPI // Needs the system scale for consistency with Windows Theme API. double scaleFactor = WinUtils::SystemScaleFactor(); int iconDevicePixels = NSToIntRound(16 * scaleFactor);
SIZE iconSize = {iconDevicePixels, iconDevicePixels}; // Not really sure what margins should be used here, but this seems to work in // practice...
MARGINS margins = {0};
GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL,
TMT_CONTENTMARGINS, nullptr, &margins);
iconSize.cx += margins.cxLeftWidth + margins.cxRightWidth;
iconSize.cy += margins.cyTopHeight + margins.cyBottomHeight;
int width = std::max(
itemSize.cx, std::max(iconSize.cx, checkboxBGSize.cx) + gutterSize.cx); int height = std::max(itemSize.cy, std::max(iconSize.cy, checkboxBGSize.cy));
/* * Notes on progress track and meter part constants: * xp and up: * PP_BAR(_VERT) - base progress track * PP_TRANSPARENTBAR(_VERT) - transparent progress track. this only works if * the underlying surface supports alpha. otherwise * theme lib's DrawThemeBackground falls back on * opaque PP_BAR. we currently don't use this. * PP_CHUNK(_VERT) - xp progress meter. this does not draw an xp style * progress w/chunks, it draws fill using the chunk * graphic. * vista and up: * PP_FILL(_VERT) - progress meter. these have four states/colors. * PP_PULSEOVERLAY(_VERT) - white reflection - an overlay, not sure what this * is used for. * PP_MOVEOVERLAY(_VERT) - green pulse - the pulse effect overlay on * determined progress bars. we also use this for * indeterminate chunk. * * Notes on state constants: * PBBS_NORMAL - green progress * PBBVS_PARTIAL/PBFVS_ERROR - red error progress * PBFS_PAUSED - yellow paused progress * * There is no common controls style indeterminate part on vista and up.
*/
/* * Progress bar related constants. These values are found by experimenting and * comparing against native widgets used by the system. They are very unlikely * exact but try to not be too wrong.
*/ // The amount of time we animate progress meters parts across the frame. staticconstdouble kProgressDeterminateTimeSpan = 3.0; staticconstdouble kProgressIndeterminateTimeSpan = 5.0; // The width of the overlay used to animate the horizontal progress bar (Vista // and later). staticconst int32_t kProgressHorizontalOverlaySize = 120; // The height of the overlay used to animate the vertical progress bar (Vista // and later). staticconst int32_t kProgressVerticalOverlaySize = 45; // The height of the overlay used for the vertical indeterminate progress bar // (Vista and later). staticconst int32_t kProgressVerticalIndeterminateOverlaySize = 60; // The width of the overlay used to animate the indeterminate progress bar // (Windows Classic). staticconst int32_t kProgressClassicOverlaySize = 40;
/* * GetProgressOverlayStyle - returns the proper overlay part for themed * progress bars based on os and orientation.
*/ static int32_t GetProgressOverlayStyle(bool aIsVertical) { return aIsVertical ? PP_MOVEOVERLAYVERT : PP_MOVEOVERLAY;
}
/* * GetProgressOverlaySize - returns the minimum width or height for themed * progress bar overlays. This includes the width of indeterminate chunks * and vista pulse overlays.
*/ static int32_t GetProgressOverlaySize(bool aIsVertical, bool aIsIndeterminate) { if (aIsVertical) { return aIsIndeterminate ? kProgressVerticalIndeterminateOverlaySize
: kProgressVerticalOverlaySize;
} return kProgressHorizontalOverlaySize;
}
/* * IsProgressMeterFilled - Determines if a progress meter is at 100% fill based * on a comparison of the current value and maximum.
*/ staticbool IsProgressMeterFilled(nsIFrame* aFrame) {
NS_ENSURE_TRUE(aFrame, false);
nsIFrame* parentFrame = aFrame->GetParent();
NS_ENSURE_TRUE(parentFrame, false); return nsNativeTheme::GetProgressValue(parentFrame) ==
nsNativeTheme::GetProgressMaxValue(parentFrame);
}
/* * CalculateProgressOverlayRect - returns the padded overlay animation rect * used in rendering progress bars. Resulting rects are used in rendering * vista+ pulse overlays and indeterminate progress meters. Graphics should * be rendered at the origin.
*/
RECT nsNativeThemeWin::CalculateProgressOverlayRect(nsIFrame* aFrame,
RECT* aWidgetRect, bool aIsVertical, bool aIsIndeterminate, bool aIsClassic) {
NS_ASSERTION(aFrame, "bad frame pointer");
NS_ASSERTION(aWidgetRect, "bad rect pointer");
// Recycle a set of progress pulse timers - these timers control the position // of all progress overlays and indeterminate chunks that get rendered. double span = aIsIndeterminate ? kProgressIndeterminateTimeSpan
: kProgressDeterminateTimeSpan;
TimeDuration period; if (!aIsIndeterminate) { if (TimeStamp::Now() >
(mProgressDeterminateTimeStamp + TimeDuration::FromSeconds(span))) {
mProgressDeterminateTimeStamp = TimeStamp::Now();
}
period = TimeStamp::Now() - mProgressDeterminateTimeStamp;
} else { if (TimeStamp::Now() >
(mProgressIndeterminateTimeStamp + TimeDuration::FromSeconds(span))) {
mProgressIndeterminateTimeStamp = TimeStamp::Now();
}
period = TimeStamp::Now() - mProgressIndeterminateTimeStamp;
}
double percent = period / TimeDuration::FromSeconds(span);
if (!aIsVertical && IsFrameRTL(aFrame)) percent = 1 - percent;
RECT overlayRect = *aWidgetRect;
int32_t overlaySize; if (!aIsClassic) {
overlaySize = GetProgressOverlaySize(aIsVertical, aIsIndeterminate);
} else {
overlaySize = kProgressClassicOverlaySize;
}
// Calculate a bounds that is larger than the meters frame such that the // overlay starts and ends completely off the edge of the frame: // [overlay][frame][overlay] // This also yields a nice delay on rotation. Use overlaySize as the minimum // size for [overlay] based on the graphics dims. If [frame] is larger, use // the frame size instead. int trackWidth = frameSize > overlaySize ? frameSize : overlaySize; if (!aIsVertical) { int xPos = aWidgetRect->left - trackWidth;
xPos += (int)ceil(((double)(trackWidth * 2) * percent));
overlayRect.left = xPos;
overlayRect.right = xPos + overlaySize;
} else { int yPos = aWidgetRect->bottom + trackWidth;
yPos -= (int)ceil(((double)(trackWidth * 2) * percent));
overlayRect.bottom = yPos;
overlayRect.top = yPos - overlaySize;
} return overlayRect;
}
/* * DrawProgressMeter - render an appropriate progress meter based on progress * meter style, orientation, and os. Note, this does not render the underlying * progress track. * * @param aFrame the widget frame * @param aAppearance type of widget * @param aTheme progress theme handle * @param aHdc hdc returned by gfxWindowsNativeDrawing * @param aPart the PP_X progress part * @param aState the theme state * @param aWidgetRect bounding rect for the widget * @param aClipRect dirty rect that needs drawing. * @param aAppUnits app units per device pixel
*/ void nsNativeThemeWin::DrawThemedProgressMeter(
nsIFrame* aFrame, StyleAppearance aAppearance, HANDLE aTheme, HDC aHdc, int aPart, int aState, RECT* aWidgetRect, RECT* aClipRect) { if (!aFrame || !aTheme || !aHdc) return;
NS_ASSERTION(aWidgetRect, "bad rect pointer");
NS_ASSERTION(aClipRect, "bad clip rect pointer");
RECT adjWidgetRect, adjClipRect;
adjWidgetRect = *aWidgetRect;
adjClipRect = *aClipRect;
nsIFrame* parentFrame = aFrame->GetParent(); if (!parentFrame) { // We have no parent to work with, just bail.
NS_WARNING("No parent frame for progress rendering. Can't paint."); return;
}
// Vista and up progress meter is fill style, rendered here. We render // the pulse overlay in the follow up section below.
DrawThemeBackground(aTheme, aHdc, aPart, aState, &adjWidgetRect,
&adjClipRect); if (!IsProgressMeterFilled(aFrame)) {
animate = true;
}
if (mBorderCacheValid[cacheBitIndex] & cacheBit) { return mBorderCache[cacheIndex];
}
// Get our info.
RECT outerRect; // Create a fake outer rect.
outerRect.top = outerRect.left = 100;
outerRect.right = outerRect.bottom = 200;
RECT contentRect(outerRect);
HRESULT res = GetThemeBackgroundContentRect(aTheme, nullptr, aPart, aState,
&outerRect, &contentRect);
if (FAILED(res)) { return LayoutDeviceIntMargin();
}
// Now compute the delta in each direction and place it in our // nsIntMargin struct.
LayoutDeviceIntMargin result;
result.top = contentRect.top - outerRect.top;
result.bottom = outerRect.bottom - contentRect.bottom;
result.left = contentRect.left - outerRect.left;
result.right = outerRect.right - contentRect.right;
if (aAppearance == StyleAppearance::Button && aSizeReq == TS_MIN) { // In practice, StyleAppearance::Button is the only widget type which has an // aSizeReq that varies for us, and it can only be TS_MIN or TS_TRUE. Just // stuff that extra bit into the aPart part of the cache, since BP_Count is // well below THEME_PART_DISTINCT_VALUE_COUNT anyway.
cachePart = BP_Count;
}
mozilla::Maybe<nsUXThemeClass> nsNativeThemeWin::GetThemeClass(
StyleAppearance aAppearance) { switch (aAppearance) { case StyleAppearance::Button: return Some(eUXButton); case StyleAppearance::NumberInput: case StyleAppearance::PasswordInput: case StyleAppearance::Textfield: case StyleAppearance::Textarea: return Some(eUXEdit); case StyleAppearance::Toolbarbutton: case StyleAppearance::Separator: return Some(eUXToolbar); case StyleAppearance::ProgressBar: case StyleAppearance::Progresschunk: return Some(eUXProgress); case StyleAppearance::Tab: case StyleAppearance::Tabpanel: case StyleAppearance::Tabpanels: return Some(eUXTab); case StyleAppearance::Range: case StyleAppearance::RangeThumb: return Some(eUXTrackbar); case StyleAppearance::Menulist: case StyleAppearance::MenulistButton: return Some(eUXCombobox); case StyleAppearance::Listbox: return Some(eUXListview); default: return Nothing();
}
}
/** * aPart is filled in with the UXTheme part code. On return, values > 0 * are the actual UXTheme part code; -1 means the widget will be drawn by * us; 0 means that we should use part code 0, which isn't a real part code * but elicits some kind of default behaviour from UXTheme when drawing * (but isThemeBackgroundPartiallyTransparent may not work).
*/
nsresult nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame,
StyleAppearance aAppearance,
int32_t& aPart,
int32_t& aState) { switch (aAppearance) { case StyleAppearance::Button: {
aPart = BP_BUTTON; if (!aFrame) {
aState = TS_NORMAL; return NS_OK;
}
// Check for default dialog buttons. These buttons should always look // focused. if (aState == TS_NORMAL && IsDefaultButton(aFrame)) aState = TS_FOCUSED; return NS_OK;
} case StyleAppearance::NumberInput: case StyleAppearance::PasswordInput: case StyleAppearance::Textfield: case StyleAppearance::Textarea: {
ElementState elementState = GetContentState(aFrame, aAppearance);
/* Note: the NOSCROLL type has a rounded corner in each corner. The more * specific HSCROLL, VSCROLL, HVSCROLL types have side and/or top/bottom * edges rendered as straight horizontal lines with sharp corners to * accommodate a scrollbar. However, the scrollbar gets rendered on top * of this for us, so we don't care, and can just use NOSCROLL here.
*/
aPart = TFP_EDITBORDER_NOSCROLL;
/* On Vista/Win7, we use CBP_DROPBORDER instead of DROPFRAME for HTML * content or for editable menulists; this gives us the thin outline,
* instead of the gradient-filled background */ if (useDropBorder)
aPart = CBP_DROPBORDER; else
aPart = CBP_DROPFRAME;
// When running with per-monitor DPI (on Win8.1+), and rendering on a display // with a different DPI setting from the system's default scaling, we need to // apply scaling to native-themed elements as the Windows theme APIs assume // the system default resolution. staticinlinedouble GetThemeDpiScaleFactor(nsPresContext* aPresContext) { if (WinUtils::IsPerMonitorDPIAware() ||
StaticPrefs::layout_css_devPixelsPerPx() > 0.0) {
nsCOMPtr<nsIWidget> rootWidget = aPresContext->GetRootWidget(); if (rootWidget) { double systemScale = WinUtils::SystemScaleFactor(); return rootWidget->GetDefaultScale().scale / systemScale;
}
} return 1.0;
}
// ^^ without the right sdk, assume xp theming and fall through.
int32_t part, state;
nsresult rv = GetThemePartAndState(aFrame, aAppearance, part, state); if (NS_FAILED(rv)) return rv;
if (AssumeThemePartAndStateAreTransparent(part, state)) { return NS_OK;
}
if (aAppearance == StyleAppearance::Tab) { // For left edge and right edge tabs, we need to adjust the widget // rects and clip rects so that the edges don't get drawn. bool isLeft = IsLeftToSelectedTab(aFrame); bool isRight = !isLeft && IsRightToSelectedTab(aFrame);
if (isLeft || isRight) { // HACK ALERT: There appears to be no way to really obtain this value, so // we're forced to just use the default value for Luna (which also happens // to be correct for all the other skins I've tried).
int32_t edgeSize = 2;
// Armed with the size of the edge, we now need to either shift to the // left or to the right. The clip rect won't include this extra area, so // we know that we're effectively shifting the edge out of view (such that // it won't be painted). if (isLeft) // The right edge should not be drawn. Extend our rect by the edge // size.
widgetRect.right += edgeSize; else // The left edge should not be drawn. Move the widget rect's left coord // back.
widgetRect.left -= edgeSize;
}
}
// widgetRect is the bounding box for a widget, yet the scale track is only // a small portion of this size, so the edges of the scale need to be // adjusted to the real size of the track. if (aAppearance == StyleAppearance::Range) {
RECT contentRect;
GetThemeBackgroundContentRect(theme, hdc, part, state, &widgetRect,
&contentRect);
// When rounding is necessary, we round the position of the track // away from the chevron of the thumb to make it look better. if (IsRangeHorizontal(aFrame)) {
contentRect.top += (contentRect.bottom - contentRect.top - siz.cy) / 2;
contentRect.bottom = contentRect.top + siz.cy;
} else { if (!IsFrameRTL(aFrame)) {
contentRect.left += (contentRect.right - contentRect.left - siz.cx) / 2;
contentRect.right = contentRect.left + siz.cx;
} else {
contentRect.right -=
(contentRect.right - contentRect.left - siz.cx) / 2;
contentRect.left = contentRect.right - siz.cx;
}
}
if (state == TFS_EDITBORDER_DISABLED) {
InflateRect(&widgetRect, -1, -1);
::FillRect(hdc, &widgetRect, reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1));
}
} elseif (aAppearance == StyleAppearance::ProgressBar) { // DrawThemeBackground renders each corner with a solid white pixel. // Restore these pixels to the underlying color. Tracks are rendered // using alpha recovery, so this makes the corners transparent.
COLORREF color;
color = GetPixel(hdc, widgetRect.left, widgetRect.top);
DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect);
SetPixel(hdc, widgetRect.left, widgetRect.top, color);
SetPixel(hdc, widgetRect.right - 1, widgetRect.top, color);
SetPixel(hdc, widgetRect.right - 1, widgetRect.bottom - 1, color);
SetPixel(hdc, widgetRect.left, widgetRect.bottom - 1, color);
} elseif (aAppearance == StyleAppearance::Progresschunk) {
DrawThemedProgressMeter(aFrame, aAppearance, theme, hdc, part, state,
&widgetRect, &clipRect);
} // If part is negative, the element wishes us to not render a themed // background, instead opting to be drawn specially below. elseif (part >= 0) {
DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect);
}
// Draw focus rectangles for range elements // XXX it'd be nice to draw these outside of the frame if (aAppearance == StyleAppearance::Range) {
ElementState contentState = GetContentState(aFrame, aAppearance);
if (contentState.HasState(ElementState::FOCUSRING)) {
POINT vpOrg;
HPEN hPen = nullptr;
result = GetCachedWidgetBorder(theme, themeClass.value(), aAppearance, part,
state);
// Remove the edges for tabs that are before or after the selected tab, if (aAppearance == StyleAppearance::Tab) { if (IsLeftToSelectedTab(aFrame)) // Remove the right edge, since we won't be drawing it.
result.right = 0; elseif (IsRightToSelectedTab(aFrame)) // Remove the left edge, since we won't be drawing it.
result.left = 0;
}
if (aFrame && (aAppearance == StyleAppearance::NumberInput ||
aAppearance == StyleAppearance::PasswordInput ||
aAppearance == StyleAppearance::Textfield ||
aAppearance == StyleAppearance::Textarea)) {
nsIContent* content = aFrame->GetContent(); if (content && content->IsHTMLElement()) { // We need to pad textfields by 1 pixel, since the caret will draw // flush against the edge by default if we don't.
result.top.value++;
result.left.value++;
result.bottom.value++;
result.right.value++;
}
}
bool ok = true;
HANDLE theme = GetTheme(aAppearance); if (!theme) {
ok = ClassicGetWidgetPadding(aContext, aFrame, aAppearance, aResult);
ScaleForFrameDPI(aResult, aFrame); return ok;
}
/* textfields need extra pixels on all sides, otherwise they wrap their * content too tightly. The actual border is drawn 1px inside the specified * rectangle, so Gecko will end up making the contents look too small. * Instead, we add 2px padding for the contents and fix this. (Used to be 1px * added, see bug 430212)
*/ if (aAppearance == StyleAppearance::NumberInput ||
aAppearance == StyleAppearance::PasswordInput ||
aAppearance == StyleAppearance::Textfield ||
aAppearance == StyleAppearance::Textarea) {
aResult->top = aResult->bottom = 2;
aResult->left = aResult->right = 2;
ScaleForFrameDPI(aResult, aFrame); return ok;
} elseif (IsHTMLContent(aFrame) &&
(aAppearance == StyleAppearance::Menulist ||
aAppearance == StyleAppearance::MenulistButton)) { /* For content menulist controls, we need an extra pixel so that we have * room to draw our focus rectangle stuff. Otherwise, the focus rect might * overlap the control's border.
*/
aResult->top = aResult->bottom = 1;
aResult->left = aResult->right = 1;
ScaleForFrameDPI(aResult, aFrame); return ok;
}
int32_t right, left, top, bottom;
right = left = top = bottom = 0; switch (aAppearance) { case StyleAppearance::Button: if (aFrame->GetContent()->IsXULElement()) {
top = 2;
bottom = 3;
}
left = right = 5; break; default: returnfalse;
}
/* This is disabled for now, because it causes invalidation problems -- * see bug 420381. The effect of not updating the overflow area is that * for dropdown buttons in content areas, there is a 1px border on 3 sides * where, if invalidated, the dropdown control probably won't be repainted. * This is fairly minor, as by default there is nothing in that area, and * a border only shows up if the widget is being hovered. * * TODO(jwatt): Figure out what do to about * StyleAppearance::MozMenulistArrowButton too.
*/ #if 0 /* We explicitly draw dropdown buttons in HTML content 1px bigger up, right, * and bottom so that they overlap the dropdown's border like they're * supposed to.
*/ if (aAppearance == StyleAppearance::MenulistButton &&
IsHTMLContent(aFrame) &&
!IsWidgetStyled(aFrame->GetParent()->PresContext(),
aFrame->GetParent(),
StyleAppearance::Menulist))
{
int32_t p2a = aContext->AppUnitsPerDevPixel(); /* Note: no overflow on the left */
nsMargin m(p2a, p2a, p2a, 0);
aOverflowRect->Inflate (m); returntrue;
} #endif
mozilla::Maybe<nsUXThemeClass> themeClass = GetThemeClass(aAppearance);
HTHEME theme = NULL; if (!themeClass.isNothing()) {
theme = nsUXThemeData::GetTheme(themeClass.value());
} if (!theme) { auto result = ClassicGetMinimumWidgetSize(aFrame, aAppearance);
ScaleForFrameDPI(&result, aFrame); return result;
}
switch (aAppearance) { case StyleAppearance::NumberInput: case StyleAppearance::PasswordInput: case StyleAppearance::Textfield: case StyleAppearance::Progresschunk: case StyleAppearance::Tabpanels: case StyleAppearance::Tabpanel: case StyleAppearance::Listbox: return {}; // Don't worry about it. default: break;
}
// Call GetSystemMetrics to determine size for WinXP scrollbars // (GetThemeSysSize API returns the optimal size for the theme, but // Windows appears to always use metrics when drawing standard scrollbars)
THEMESIZE sizeReq = TS_TRUE; // Best-fit size switch (aAppearance) { case StyleAppearance::ProgressBar: // Best-fit size for progress meters is too large for most // themes. We want these widgets to be able to really shrink // down, so use the min-size request value (of 0).
sizeReq = TS_MIN; break;
case StyleAppearance::RangeThumb: {
LayoutDeviceIntSize result(12, 20); if (!IsRangeHorizontal(aFrame)) {
std::swap(result.width, result.height);
}
ScaleForFrameDPI(&result, aFrame); return result;
}
case StyleAppearance::Separator: { // that's 2px left margin, 2px right margin and 2px separator // (the margin is drawn as part of the separator, though)
LayoutDeviceIntSize result(6, 0);
ScaleForFrameDPI(&result, aFrame); return result;
}
case StyleAppearance::Button: // We should let HTML buttons shrink to their min size. // FIXME bug 403934: We should probably really separate // GetPreferredWidgetSize from GetMinimumWidgetSize, so callers can // use the one they want. if (aFrame->GetContent()->IsHTMLElement()) {
sizeReq = TS_MIN;
} break;
bool nsNativeThemeWin::ThemeSupportsWidget(nsPresContext* aPresContext,
nsIFrame* aFrame,
StyleAppearance aAppearance) { // XXXdwh We can go even further and call the API to ask if support exists for // specific widgets.
if (IsWidgetAlwaysNonNative(aFrame, aAppearance)) { return Theme::ThemeSupportsWidget(aPresContext, aFrame, aAppearance);
}
HANDLE theme = GetTheme(aAppearance); if (theme || ClassicThemeSupportsWidget(aFrame, aAppearance)) // turn off theming for some HTML widgets styled by the page return !IsWidgetStyled(aPresContext, aFrame, aAppearance);
returnfalse;
}
bool nsNativeThemeWin::ThemeDrawsFocusForWidget(nsIFrame* aFrame,
StyleAppearance aAppearance) { if (IsWidgetNonNative(aFrame, aAppearance) != NonNative::No) { return Theme::ThemeDrawsFocusForWidget(aFrame, aAppearance);
} switch (aAppearance) { case StyleAppearance::Menulist: case StyleAppearance::MenulistButton: case StyleAppearance::Textarea: case StyleAppearance::Textfield: case StyleAppearance::NumberInput: case StyleAppearance::PasswordInput: returntrue; default: returnfalse;
}
}
switch (aAppearance) { case StyleAppearance::ProgressBar: case StyleAppearance::Progresschunk: case StyleAppearance::Range: return eTransparent; default: break;
}
HANDLE theme = GetTheme(aAppearance); // For the classic theme we don't really have a way of knowing if (!theme) { return eUnknownTransparency;
}
if (part <= 0) { // Not a real part code, so IsThemeBackgroundPartiallyTransparent may // not work, so don't call it. return eUnknownTransparency;
}
if (IsThemeBackgroundPartiallyTransparent(theme, part, state)) return eTransparent; return eOpaque;
}
/* Windows 9x/NT/2000/Classic XP Theme Support */
bool nsNativeThemeWin::ClassicThemeSupportsWidget(nsIFrame* aFrame,
StyleAppearance aAppearance) { switch (aAppearance) { case StyleAppearance::Button: case StyleAppearance::NumberInput: case StyleAppearance::PasswordInput: case StyleAppearance::Textfield: case StyleAppearance::Textarea: case StyleAppearance::Range: case StyleAppearance::RangeThumb: case StyleAppearance::Menulist: case StyleAppearance::MenulistButton: case StyleAppearance::Listbox: case StyleAppearance::ProgressBar: case StyleAppearance::Progresschunk: case StyleAppearance::Tab: case StyleAppearance::Tabpanel: case StyleAppearance::Tabpanels: returntrue; default: returnfalse;
}
}
LayoutDeviceIntMargin nsNativeThemeWin::ClassicGetWidgetBorder(
nsDeviceContext* aContext, nsIFrame* aFrame, StyleAppearance aAppearance) {
LayoutDeviceIntMargin result; switch (aAppearance) { case StyleAppearance::Button:
result.top = result.left = result.bottom = result.right = 2; break; case StyleAppearance::Listbox: case StyleAppearance::Menulist: case StyleAppearance::MenulistButton: case StyleAppearance::Tab: case StyleAppearance::NumberInput: case StyleAppearance::PasswordInput: case StyleAppearance::Textfield: case StyleAppearance::Textarea:
result.top = result.left = result.bottom = result.right = 2; break; case StyleAppearance::ProgressBar:
result.top = result.left = result.bottom = result.right = 1; break; default:
result.top = result.bottom = result.left = result.right = 0; break;
} return result;
}
LayoutDeviceIntSize nsNativeThemeWin::ClassicGetMinimumWidgetSize(
nsIFrame* aFrame, StyleAppearance aAppearance) {
LayoutDeviceIntSize result; switch (aAppearance) { case StyleAppearance::RangeThumb: { if (IsRangeHorizontal(aFrame)) {
result.width = 12;
result.height = 20;
} else {
result.width = 20;
result.height = 12;
} break;
} case StyleAppearance::Menulist: case StyleAppearance::MenulistButton: case StyleAppearance::Button: case StyleAppearance::Listbox: case StyleAppearance::NumberInput: case StyleAppearance::PasswordInput: case StyleAppearance::Textfield: case StyleAppearance::Textarea: case StyleAppearance::Progresschunk: case StyleAppearance::ProgressBar: case StyleAppearance::Tab: case StyleAppearance::Tabpanel: case StyleAppearance::Tabpanels: // no minimum widget size break;
ElementState contentState = GetContentState(aFrame, aAppearance); if (contentState.HasState(ElementState::DISABLED)) {
aState |= DFCS_INACTIVE;
} elseif (IsOpenButton(aFrame)) {
aState |= DFCS_PUSHED;
} elseif (IsCheckedButton(aFrame)) {
aState |= DFCS_CHECKED;
} else { if (contentState.HasAllStates(ElementState::ACTIVE |
ElementState::HOVER)) {
aState |= DFCS_PUSHED; // The down state is flat if the button is focusable if (aFrame->StyleUI()->UserFocus() == StyleUserFocus::Normal) { if (!aFrame->GetContent()->IsHTMLElement()) aState |= DFCS_FLAT;
aFocused = true;
}
} // On Windows, focused buttons are always drawn as such by the native // theme, that's why we check ElementState::FOCUS instead of // ElementState::FOCUSRING. if (contentState.HasState(ElementState::FOCUS) ||
(aState == DFCS_BUTTONPUSH && IsDefaultButton(aFrame))) {
aFocused = true;
}
}
return NS_OK;
} case StyleAppearance::Listbox: case StyleAppearance::NumberInput: case StyleAppearance::PasswordInput: case StyleAppearance::Textfield: case StyleAppearance::Textarea: case StyleAppearance::Menulist: case StyleAppearance::MenulistButton: case StyleAppearance::Range: case StyleAppearance::RangeThumb: case StyleAppearance::Progresschunk: case StyleAppearance::ProgressBar: case StyleAppearance::Tab: case StyleAppearance::Tabpanel: case StyleAppearance::Tabpanels: // these don't use DrawFrameControl return NS_OK; default: return NS_ERROR_FAILURE;
}
}
// Draw classic Windows tab // (no system API for this, but DrawEdge can draw all the parts of a tab) staticvoid DrawTab(HDC hdc, const RECT& R, int32_t aPosition, bool aSelected, bool aDrawLeft, bool aDrawRight) {
int32_t leftFlag, topFlag, rightFlag, lightFlag, shadeFlag;
RECT topRect, sideRect, bottomRect, lightRect, shadeRect;
int32_t selectedOffset, lOffset, rOffset;
if (nativeDrawing.ShouldRenderAgain()) goto RENDER_AGAIN;
nativeDrawing.PaintToContext();
return rv;
}
uint32_t nsNativeThemeWin::GetWidgetNativeDrawingFlags(
StyleAppearance aAppearance) { switch (aAppearance) { case StyleAppearance::Button: case StyleAppearance::NumberInput: case StyleAppearance::PasswordInput: case StyleAppearance::Textfield: case StyleAppearance::Textarea: case StyleAppearance::Menulist: case StyleAppearance::MenulistButton: return gfxWindowsNativeDrawing::CANNOT_DRAW_TO_COLOR_ALPHA |
gfxWindowsNativeDrawing::CAN_AXIS_ALIGNED_SCALE |
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.