diff -r 000000000000 -r 6474c204b198 widget/windows/nsLookAndFeel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widget/windows/nsLookAndFeel.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,678 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#include "nsLookAndFeel.h" +#include +#include +#include "nsStyleConsts.h" +#include "nsUXThemeData.h" +#include "nsUXThemeConstants.h" +#include "gfxFont.h" +#include "gfxWindowsPlatform.h" +#include "mozilla/Telemetry.h" +#include "mozilla/WindowsVersion.h" +#include "gfxFontConstants.h" + +using namespace mozilla; +using namespace mozilla::widget; + +//static +LookAndFeel::OperatingSystemVersion +nsLookAndFeel::GetOperatingSystemVersion() +{ + static OperatingSystemVersion version = eOperatingSystemVersion_Unknown; + + if (version != eOperatingSystemVersion_Unknown) { + return version; + } + + if (IsWin8OrLater()) { + version = eOperatingSystemVersion_Windows8; + } else if (IsWin7OrLater()) { + version = eOperatingSystemVersion_Windows7; + } else if (IsVistaOrLater()) { + version = eOperatingSystemVersion_WindowsVista; + } else { + version = eOperatingSystemVersion_WindowsXP; + } + + return version; +} + +static nsresult GetColorFromTheme(nsUXThemeClass cls, + int32_t aPart, + int32_t aState, + int32_t aPropId, + nscolor &aColor) +{ + COLORREF color; + HRESULT hr = GetThemeColor(nsUXThemeData::GetTheme(cls), aPart, aState, aPropId, &color); + if (hr == S_OK) + { + aColor = COLOREF_2_NSRGB(color); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +static int32_t GetSystemParam(long flag, int32_t def) +{ + DWORD value; + return ::SystemParametersInfo(flag, 0, &value, 0) ? value : def; +} + +namespace mozilla { +namespace widget { +// This is in use here and in dom/events/TouchEvent.cpp +int32_t IsTouchDeviceSupportPresent() +{ + int32_t touchCapabilities; + touchCapabilities = ::GetSystemMetrics(SM_DIGITIZER); + return ((touchCapabilities & NID_READY) && + (touchCapabilities & (NID_EXTERNAL_TOUCH | NID_INTEGRATED_TOUCH))); +} +} } + +nsLookAndFeel::nsLookAndFeel() : nsXPLookAndFeel() +{ + mozilla::Telemetry::Accumulate(mozilla::Telemetry::TOUCH_ENABLED_DEVICE, + IsTouchDeviceSupportPresent()); +} + +nsLookAndFeel::~nsLookAndFeel() +{ +} + +nsresult +nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor) +{ + nsresult res = NS_OK; + + int idx; + switch (aID) { + case eColorID_WindowBackground: + idx = COLOR_WINDOW; + break; + case eColorID_WindowForeground: + idx = COLOR_WINDOWTEXT; + break; + case eColorID_WidgetBackground: + idx = COLOR_BTNFACE; + break; + case eColorID_WidgetForeground: + idx = COLOR_BTNTEXT; + break; + case eColorID_WidgetSelectBackground: + idx = COLOR_HIGHLIGHT; + break; + case eColorID_WidgetSelectForeground: + idx = COLOR_HIGHLIGHTTEXT; + break; + case eColorID_Widget3DHighlight: + idx = COLOR_BTNHIGHLIGHT; + break; + case eColorID_Widget3DShadow: + idx = COLOR_BTNSHADOW; + break; + case eColorID_TextBackground: + idx = COLOR_WINDOW; + break; + case eColorID_TextForeground: + idx = COLOR_WINDOWTEXT; + break; + case eColorID_TextSelectBackground: + case eColorID_IMESelectedRawTextBackground: + case eColorID_IMESelectedConvertedTextBackground: + idx = COLOR_HIGHLIGHT; + break; + case eColorID_TextSelectForeground: + case eColorID_IMESelectedRawTextForeground: + case eColorID_IMESelectedConvertedTextForeground: + idx = COLOR_HIGHLIGHTTEXT; + break; + case eColorID_IMERawInputBackground: + case eColorID_IMEConvertedTextBackground: + aColor = NS_TRANSPARENT; + return NS_OK; + case eColorID_IMERawInputForeground: + case eColorID_IMEConvertedTextForeground: + aColor = NS_SAME_AS_FOREGROUND_COLOR; + return NS_OK; + case eColorID_IMERawInputUnderline: + case eColorID_IMEConvertedTextUnderline: + aColor = NS_SAME_AS_FOREGROUND_COLOR; + return NS_OK; + case eColorID_IMESelectedRawTextUnderline: + case eColorID_IMESelectedConvertedTextUnderline: + aColor = NS_TRANSPARENT; + return NS_OK; + case eColorID_SpellCheckerUnderline: + aColor = NS_RGB(0xff, 0, 0); + return NS_OK; + + // New CSS 2 Color definitions + case eColorID_activeborder: + idx = COLOR_ACTIVEBORDER; + break; + case eColorID_activecaption: + idx = COLOR_ACTIVECAPTION; + break; + case eColorID_appworkspace: + idx = COLOR_APPWORKSPACE; + break; + case eColorID_background: + idx = COLOR_BACKGROUND; + break; + case eColorID_buttonface: + case eColorID__moz_buttonhoverface: + idx = COLOR_BTNFACE; + break; + case eColorID_buttonhighlight: + idx = COLOR_BTNHIGHLIGHT; + break; + case eColorID_buttonshadow: + idx = COLOR_BTNSHADOW; + break; + case eColorID_buttontext: + case eColorID__moz_buttonhovertext: + idx = COLOR_BTNTEXT; + break; + case eColorID_captiontext: + idx = COLOR_CAPTIONTEXT; + break; + case eColorID_graytext: + idx = COLOR_GRAYTEXT; + break; + case eColorID_highlight: + case eColorID__moz_html_cellhighlight: + case eColorID__moz_menuhover: + idx = COLOR_HIGHLIGHT; + break; + case eColorID__moz_menubarhovertext: + if (!IsVistaOrLater() || !IsAppThemed()) + { + idx = nsUXThemeData::sFlatMenus ? + COLOR_HIGHLIGHTTEXT : + COLOR_MENUTEXT; + break; + } + // Fall through + case eColorID__moz_menuhovertext: + if (IsVistaOrLater() && IsAppThemed()) + { + res = ::GetColorFromTheme(eUXMenu, + MENU_POPUPITEM, MPI_HOT, TMT_TEXTCOLOR, aColor); + if (NS_SUCCEEDED(res)) + return res; + // fall through to highlight case + } + case eColorID_highlighttext: + case eColorID__moz_html_cellhighlighttext: + idx = COLOR_HIGHLIGHTTEXT; + break; + case eColorID_inactiveborder: + idx = COLOR_INACTIVEBORDER; + break; + case eColorID_inactivecaption: + idx = COLOR_INACTIVECAPTION; + break; + case eColorID_inactivecaptiontext: + idx = COLOR_INACTIVECAPTIONTEXT; + break; + case eColorID_infobackground: + idx = COLOR_INFOBK; + break; + case eColorID_infotext: + idx = COLOR_INFOTEXT; + break; + case eColorID_menu: + idx = COLOR_MENU; + break; + case eColorID_menutext: + case eColorID__moz_menubartext: + idx = COLOR_MENUTEXT; + break; + case eColorID_scrollbar: + idx = COLOR_SCROLLBAR; + break; + case eColorID_threeddarkshadow: + idx = COLOR_3DDKSHADOW; + break; + case eColorID_threedface: + idx = COLOR_3DFACE; + break; + case eColorID_threedhighlight: + idx = COLOR_3DHIGHLIGHT; + break; + case eColorID_threedlightshadow: + idx = COLOR_3DLIGHT; + break; + case eColorID_threedshadow: + idx = COLOR_3DSHADOW; + break; + case eColorID_window: + idx = COLOR_WINDOW; + break; + case eColorID_windowframe: + idx = COLOR_WINDOWFRAME; + break; + case eColorID_windowtext: + idx = COLOR_WINDOWTEXT; + break; + case eColorID__moz_eventreerow: + case eColorID__moz_oddtreerow: + case eColorID__moz_field: + case eColorID__moz_combobox: + idx = COLOR_WINDOW; + break; + case eColorID__moz_fieldtext: + case eColorID__moz_comboboxtext: + idx = COLOR_WINDOWTEXT; + break; + case eColorID__moz_dialog: + case eColorID__moz_cellhighlight: + idx = COLOR_3DFACE; + break; + case eColorID__moz_win_mediatext: + if (IsVistaOrLater() && IsAppThemed()) { + res = ::GetColorFromTheme(eUXMediaToolbar, + TP_BUTTON, TS_NORMAL, TMT_TEXTCOLOR, aColor); + if (NS_SUCCEEDED(res)) + return res; + } + // if we've gotten here just return -moz-dialogtext instead + idx = COLOR_WINDOWTEXT; + break; + case eColorID__moz_win_communicationstext: + if (IsVistaOrLater() && IsAppThemed()) + { + res = ::GetColorFromTheme(eUXCommunicationsToolbar, + TP_BUTTON, TS_NORMAL, TMT_TEXTCOLOR, aColor); + if (NS_SUCCEEDED(res)) + return res; + } + // if we've gotten here just return -moz-dialogtext instead + idx = COLOR_WINDOWTEXT; + break; + case eColorID__moz_dialogtext: + case eColorID__moz_cellhighlighttext: + idx = COLOR_WINDOWTEXT; + break; + case eColorID__moz_dragtargetzone: + idx = COLOR_HIGHLIGHTTEXT; + break; + case eColorID__moz_buttondefault: + idx = COLOR_3DDKSHADOW; + break; + case eColorID__moz_nativehyperlinktext: + idx = COLOR_HOTLIGHT; + break; + default: + idx = COLOR_WINDOW; + break; + } + + DWORD color = ::GetSysColor(idx); + aColor = COLOREF_2_NSRGB(color); + + return res; +} + +nsresult +nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult) +{ + nsresult res = nsXPLookAndFeel::GetIntImpl(aID, aResult); + if (NS_SUCCEEDED(res)) + return res; + res = NS_OK; + + switch (aID) { + case eIntID_CaretBlinkTime: + aResult = (int32_t)::GetCaretBlinkTime(); + break; + case eIntID_CaretWidth: + aResult = 1; + break; + case eIntID_ShowCaretDuringSelection: + aResult = 0; + break; + case eIntID_SelectTextfieldsOnKeyFocus: + // Select textfield content when focused by kbd + // used by EventStateManager::sTextfieldSelectModel + aResult = 1; + break; + case eIntID_SubmenuDelay: + // This will default to the Windows' default + // (400ms) on error. + aResult = GetSystemParam(SPI_GETMENUSHOWDELAY, 400); + break; + case eIntID_TooltipDelay: + aResult = 500; + break; + case eIntID_MenusCanOverlapOSBar: + // we want XUL popups to be able to overlap the task bar. + aResult = 1; + break; + case eIntID_DragThresholdX: + // The system metric is the number of pixels at which a drag should + // start. Our look and feel metric is the number of pixels you can + // move before starting a drag, so subtract 1. + + aResult = ::GetSystemMetrics(SM_CXDRAG) - 1; + break; + case eIntID_DragThresholdY: + aResult = ::GetSystemMetrics(SM_CYDRAG) - 1; + break; + case eIntID_UseAccessibilityTheme: + // High contrast is a misnomer under Win32 -- any theme can be used with it, + // e.g. normal contrast with large fonts, low contrast, etc. + // The high contrast flag really means -- use this theme and don't override it. + aResult = nsUXThemeData::IsHighContrastOn(); + break; + case eIntID_ScrollArrowStyle: + aResult = eScrollArrowStyle_Single; + break; + case eIntID_ScrollSliderStyle: + aResult = eScrollThumbStyle_Proportional; + break; + case eIntID_TreeOpenDelay: + aResult = 1000; + break; + case eIntID_TreeCloseDelay: + aResult = 0; + break; + case eIntID_TreeLazyScrollDelay: + aResult = 150; + break; + case eIntID_TreeScrollDelay: + aResult = 100; + break; + case eIntID_TreeScrollLinesMax: + aResult = 3; + break; + case eIntID_WindowsClassic: + aResult = !IsAppThemed(); + break; + case eIntID_TouchEnabled: + aResult = IsTouchDeviceSupportPresent(); + break; + case eIntID_WindowsDefaultTheme: + aResult = nsUXThemeData::IsDefaultWindowTheme(); + break; + case eIntID_WindowsThemeIdentifier: + aResult = nsUXThemeData::GetNativeThemeId(); + break; + + case eIntID_OperatingSystemVersionIdentifier: + { + aResult = GetOperatingSystemVersion(); + break; + } + + case eIntID_MacGraphiteTheme: + case eIntID_MacLionTheme: + aResult = 0; + res = NS_ERROR_NOT_IMPLEMENTED; + break; + case eIntID_DWMCompositor: + aResult = nsUXThemeData::CheckForCompositor(); + break; + case eIntID_WindowsGlass: + // Aero Glass is only available prior to Windows 8 when DWM is used. + aResult = (nsUXThemeData::CheckForCompositor() && !IsWin8OrLater()); + break; + case eIntID_AlertNotificationOrigin: + aResult = 0; + { + // Get task bar window handle + HWND shellWindow = FindWindowW(L"Shell_TrayWnd", nullptr); + + if (shellWindow != nullptr) + { + // Determine position + APPBARDATA appBarData; + appBarData.hWnd = shellWindow; + appBarData.cbSize = sizeof(appBarData); + if (SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData)) + { + // Set alert origin as a bit field - see LookAndFeel.h + // 0 represents bottom right, sliding vertically. + switch(appBarData.uEdge) + { + case ABE_LEFT: + aResult = NS_ALERT_HORIZONTAL | NS_ALERT_LEFT; + break; + case ABE_RIGHT: + aResult = NS_ALERT_HORIZONTAL; + break; + case ABE_TOP: + aResult = NS_ALERT_TOP; + // fall through for the right-to-left handling. + case ABE_BOTTOM: + // If the task bar is right-to-left, + // move the origin to the left + if (::GetWindowLong(shellWindow, GWL_EXSTYLE) & + WS_EX_LAYOUTRTL) + aResult |= NS_ALERT_LEFT; + break; + } + } + } + } + break; + case eIntID_IMERawInputUnderlineStyle: + case eIntID_IMEConvertedTextUnderlineStyle: + aResult = NS_STYLE_TEXT_DECORATION_STYLE_DASHED; + break; + case eIntID_IMESelectedRawTextUnderlineStyle: + case eIntID_IMESelectedConvertedTextUnderline: + aResult = NS_STYLE_TEXT_DECORATION_STYLE_NONE; + break; + case eIntID_SpellCheckerUnderlineStyle: + aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY; + break; + case eIntID_ScrollbarButtonAutoRepeatBehavior: + aResult = 0; + break; + case eIntID_SwipeAnimationEnabled: + aResult = 0; + break; + case eIntID_ColorPickerAvailable: + // We don't have a color picker implemented on Metro yet (bug 895464) + aResult = (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro); + break; + case eIntID_UseOverlayScrollbars: + aResult = (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro); + break; + case eIntID_AllowOverlayScrollbarsOverlap: + aResult = 0; + break; + case eIntID_ScrollbarDisplayOnMouseMove: + aResult = 1; + break; + case eIntID_ScrollbarFadeBeginDelay: + aResult = 2500; + break; + case eIntID_ScrollbarFadeDuration: + aResult = 350; + break; + default: + aResult = 0; + res = NS_ERROR_FAILURE; + } + return res; +} + +nsresult +nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult) +{ + nsresult res = nsXPLookAndFeel::GetFloatImpl(aID, aResult); + if (NS_SUCCEEDED(res)) + return res; + res = NS_OK; + + switch (aID) { + case eFloatID_IMEUnderlineRelativeSize: + aResult = 1.0f; + break; + case eFloatID_SpellCheckerUnderlineRelativeSize: + aResult = 1.0f; + break; + default: + aResult = -1.0; + res = NS_ERROR_FAILURE; + } + return res; +} + +static bool +GetSysFontInfo(HDC aHDC, LookAndFeel::FontID anID, + nsString &aFontName, + gfxFontStyle &aFontStyle) +{ + LOGFONTW* ptrLogFont = nullptr; + LOGFONTW logFont; + NONCLIENTMETRICSW ncm; + HGDIOBJ hGDI; + char16_t name[LF_FACESIZE]; + + // Depending on which stock font we want, there are three different + // places we might have to look it up. + switch (anID) { + case LookAndFeel::eFont_Icon: + if (!::SystemParametersInfoW(SPI_GETICONTITLELOGFONT, + sizeof(logFont), (PVOID)&logFont, 0)) + return false; + + ptrLogFont = &logFont; + break; + + case LookAndFeel::eFont_Menu: + case LookAndFeel::eFont_MessageBox: + case LookAndFeel::eFont_SmallCaption: + case LookAndFeel::eFont_StatusBar: + case LookAndFeel::eFont_Tooltips: + ncm.cbSize = sizeof(NONCLIENTMETRICSW); + if (!::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, + sizeof(ncm), (PVOID)&ncm, 0)) + return false; + + switch (anID) { + case LookAndFeel::eFont_Menu: + ptrLogFont = &ncm.lfMenuFont; + break; + case LookAndFeel::eFont_MessageBox: + ptrLogFont = &ncm.lfMessageFont; + break; + case LookAndFeel::eFont_SmallCaption: + ptrLogFont = &ncm.lfSmCaptionFont; + break; + case LookAndFeel::eFont_StatusBar: + case LookAndFeel::eFont_Tooltips: + ptrLogFont = &ncm.lfStatusFont; + break; + } + break; + + case LookAndFeel::eFont_Widget: + case LookAndFeel::eFont_Window: // css3 + case LookAndFeel::eFont_Document: + case LookAndFeel::eFont_Workspace: + case LookAndFeel::eFont_Desktop: + case LookAndFeel::eFont_Info: + case LookAndFeel::eFont_Dialog: + case LookAndFeel::eFont_Button: + case LookAndFeel::eFont_PullDownMenu: + case LookAndFeel::eFont_List: + case LookAndFeel::eFont_Field: + case LookAndFeel::eFont_Caption: + hGDI = ::GetStockObject(DEFAULT_GUI_FONT); + if (!hGDI) + return false; + + if (::GetObjectW(hGDI, sizeof(logFont), &logFont) <= 0) + return false; + + ptrLogFont = &logFont; + break; + } + + // Get scaling factor from physical to logical pixels + float pixelScale = 1.0f / gfxWindowsPlatform::GetPlatform()->GetDPIScale(); + + // The lfHeight is in pixels, and it needs to be adjusted for the + // device it will be displayed on. + // Screens and Printers will differ in DPI + // + // So this accounts for the difference in the DeviceContexts + // The pixelScale will typically be 1.0 for the screen + // (though larger for hi-dpi screens where the Windows resolution + // scale factor is 125% or 150% or even more), and could be + // any value when going to a printer, for example pixelScale is + // 6.25 when going to a 600dpi printer. + float pixelHeight = -ptrLogFont->lfHeight; + if (pixelHeight < 0) { + HFONT hFont = ::CreateFontIndirectW(ptrLogFont); + if (!hFont) + return false; + HGDIOBJ hObject = ::SelectObject(aHDC, hFont); + TEXTMETRIC tm; + ::GetTextMetrics(aHDC, &tm); + ::SelectObject(aHDC, hObject); + ::DeleteObject(hFont); + pixelHeight = tm.tmAscent; + } + pixelHeight *= pixelScale; + + // we have problem on Simplified Chinese system because the system + // report the default font size is 8 points. but if we use 8, the text + // display very ugly. force it to be at 9 points (12 pixels) on that + // system (cp936), but leave other sizes alone. + if (pixelHeight < 12 && ::GetACP() == 936) + pixelHeight = 12; + + aFontStyle.size = pixelHeight; + + // FIXME: What about oblique? + aFontStyle.style = + (ptrLogFont->lfItalic) ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL; + + // FIXME: Other weights? + aFontStyle.weight = + (ptrLogFont->lfWeight == FW_BOLD ? + NS_FONT_WEIGHT_BOLD : NS_FONT_WEIGHT_NORMAL); + + // FIXME: Set aFontStyle->stretch correctly! + aFontStyle.stretch = NS_FONT_STRETCH_NORMAL; + + aFontStyle.systemFont = true; + + name[0] = 0; + memcpy(name, ptrLogFont->lfFaceName, LF_FACESIZE*sizeof(char16_t)); + aFontName = name; + + return true; +} + +bool +nsLookAndFeel::GetFontImpl(FontID anID, nsString &aFontName, + gfxFontStyle &aFontStyle, + float aDevPixPerCSSPixel) +{ + HDC tdc = GetDC(nullptr); + bool status = GetSysFontInfo(tdc, anID, aFontName, aFontStyle); + ReleaseDC(nullptr, tdc); + // now convert the logical font size from GetSysFontInfo into device pixels for layout + aFontStyle.size *= aDevPixPerCSSPixel; + return status; +} + +/* virtual */ +char16_t +nsLookAndFeel::GetPasswordCharacterImpl() +{ +#define UNICODE_BLACK_CIRCLE_CHAR 0x25cf + return UNICODE_BLACK_CIRCLE_CHAR; +}