diff -r 000000000000 -r 6474c204b198 gfx/thebes/gfxWindowsPlatform.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/thebes/gfxWindowsPlatform.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,1548 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=8 sts=4 et sw=4 tw=80: */ +/* 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 "mozilla/ArrayUtils.h" + +#include "gfxWindowsPlatform.h" + +#include "gfxImageSurface.h" +#include "gfxWindowsSurface.h" + +#include "nsUnicharUtils.h" + +#include "mozilla/Preferences.h" +#include "mozilla/WindowsVersion.h" +#include "nsServiceManagerUtils.h" +#include "nsTArray.h" + +#include "nsIWindowsRegKey.h" +#include "nsIFile.h" +#include "plbase64.h" +#include "nsIXULRuntime.h" + +#include "nsIGfxInfo.h" + +#include "gfxCrashReporterUtils.h" + +#include "gfxGDIFontList.h" +#include "gfxGDIFont.h" + +#include "mozilla/layers/CompositorParent.h" // for CompositorParent::IsInCompositorThread +#include "DeviceManagerD3D9.h" + +#include "WinUtils.h" + +#ifdef CAIRO_HAS_DWRITE_FONT +#include "gfxDWriteFontList.h" +#include "gfxDWriteFonts.h" +#include "gfxDWriteCommon.h" +#include +#endif + +#include "gfxUserFontSet.h" +#include "nsWindowsHelpers.h" +#include "gfx2DGlue.h" + +#include + +#ifdef CAIRO_HAS_D2D_SURFACE +#include "gfxD2DSurface.h" + +#include + +#include "mozilla/gfx/2D.h" + +#include "nsMemory.h" +#endif + +#include + +#include "nsIMemoryReporter.h" +#include +#include "d3dkmtQueryStatistics.h" + +#include "SurfaceCache.h" +#include "gfxPrefs.h" + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace mozilla::layers; +using namespace mozilla::widget; +using namespace mozilla::image; + +#ifdef CAIRO_HAS_D2D_SURFACE + +static const char *kFeatureLevelPref = + "gfx.direct3d.last_used_feature_level_idx"; +static const int kSupportedFeatureLevels[] = + { D3D10_FEATURE_LEVEL_10_1, D3D10_FEATURE_LEVEL_10_0, + D3D10_FEATURE_LEVEL_9_3 }; + +class GfxD2DSurfaceReporter MOZ_FINAL : public nsIMemoryReporter +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData) + { + nsresult rv; + + int64_t amount = cairo_d2d_get_image_surface_cache_usage(); + rv = MOZ_COLLECT_REPORT( + "gfx-d2d-surface-cache", KIND_OTHER, UNITS_BYTES, amount, + "Memory used by the Direct2D internal surface cache."); + NS_ENSURE_SUCCESS(rv, rv); + + cairo_device_t *device = + gfxWindowsPlatform::GetPlatform()->GetD2DDevice(); + amount = device ? cairo_d2d_get_surface_vram_usage(device) : 0; + rv = MOZ_COLLECT_REPORT( + "gfx-d2d-surface-vram", KIND_OTHER, UNITS_BYTES, amount, + "Video memory used by D2D surfaces."); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(GfxD2DSurfaceReporter, nsIMemoryReporter) + +#endif + +class GfxD2DVramReporter MOZ_FINAL : public nsIMemoryReporter +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData) + { + nsresult rv; + + rv = MOZ_COLLECT_REPORT( + "gfx-d2d-vram-draw-target", KIND_OTHER, UNITS_BYTES, + Factory::GetD2DVRAMUsageDrawTarget(), + "Video memory used by D2D DrawTargets."); + NS_ENSURE_SUCCESS(rv, rv); + + rv = MOZ_COLLECT_REPORT( + "gfx-d2d-vram-source-surface", KIND_OTHER, UNITS_BYTES, + Factory::GetD2DVRAMUsageSourceSurface(), + "Video memory used by D2D SourceSurfaces."); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(GfxD2DVramReporter, nsIMemoryReporter) + +#define GFX_USE_CLEARTYPE_ALWAYS "gfx.font_rendering.cleartype.always_use_for_content" +#define GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE "gfx.font_rendering.cleartype.use_for_downloadable_fonts" + +#define GFX_CLEARTYPE_PARAMS "gfx.font_rendering.cleartype_params." +#define GFX_CLEARTYPE_PARAMS_GAMMA "gfx.font_rendering.cleartype_params.gamma" +#define GFX_CLEARTYPE_PARAMS_CONTRAST "gfx.font_rendering.cleartype_params.enhanced_contrast" +#define GFX_CLEARTYPE_PARAMS_LEVEL "gfx.font_rendering.cleartype_params.cleartype_level" +#define GFX_CLEARTYPE_PARAMS_STRUCTURE "gfx.font_rendering.cleartype_params.pixel_structure" +#define GFX_CLEARTYPE_PARAMS_MODE "gfx.font_rendering.cleartype_params.rendering_mode" + +class GPUAdapterReporter : public nsIMemoryReporter +{ + // Callers must Release the DXGIAdapter after use or risk mem-leak + static bool GetDXGIAdapter(IDXGIAdapter **DXGIAdapter) + { + ID3D10Device1 *D2D10Device; + IDXGIDevice *DXGIDevice; + bool result = false; + + if (D2D10Device = mozilla::gfx::Factory::GetDirect3D10Device()) { + if (D2D10Device->QueryInterface(__uuidof(IDXGIDevice), (void **)&DXGIDevice) == S_OK) { + result = (DXGIDevice->GetAdapter(DXGIAdapter) == S_OK); + DXGIDevice->Release(); + } + } + + return result; + } + +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD + CollectReports(nsIMemoryReporterCallback* aCb, + nsISupports* aClosure) + { + HANDLE ProcessHandle = GetCurrentProcess(); + + int64_t dedicatedBytesUsed = 0; + int64_t sharedBytesUsed = 0; + int64_t committedBytesUsed = 0; + IDXGIAdapter *DXGIAdapter; + + HMODULE gdi32Handle; + PFND3DKMTQS queryD3DKMTStatistics; + + // GPU memory reporting is not available before Windows 7 + if (!IsWin7OrLater()) + return NS_OK; + + if (gdi32Handle = LoadLibrary(TEXT("gdi32.dll"))) + queryD3DKMTStatistics = (PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics"); + + if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) { + // Most of this block is understood thanks to wj32's work on Process Hacker + + DXGI_ADAPTER_DESC adapterDesc; + D3DKMTQS queryStatistics; + + DXGIAdapter->GetDesc(&adapterDesc); + DXGIAdapter->Release(); + + memset(&queryStatistics, 0, sizeof(D3DKMTQS)); + queryStatistics.Type = D3DKMTQS_PROCESS; + queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; + queryStatistics.hProcess = ProcessHandle; + if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { + committedBytesUsed = queryStatistics.QueryResult.ProcessInfo.SystemMemory.BytesAllocated; + } + + memset(&queryStatistics, 0, sizeof(D3DKMTQS)); + queryStatistics.Type = D3DKMTQS_ADAPTER; + queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; + if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { + ULONG i; + ULONG segmentCount = queryStatistics.QueryResult.AdapterInfo.NbSegments; + + for (i = 0; i < segmentCount; i++) { + memset(&queryStatistics, 0, sizeof(D3DKMTQS)); + queryStatistics.Type = D3DKMTQS_SEGMENT; + queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; + queryStatistics.QuerySegment.SegmentId = i; + + if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { + bool aperture; + + // SegmentInformation has a different definition in Win7 than later versions + if (!IsWin8OrLater()) + aperture = queryStatistics.QueryResult.SegmentInfoWin7.Aperture; + else + aperture = queryStatistics.QueryResult.SegmentInfoWin8.Aperture; + + memset(&queryStatistics, 0, sizeof(D3DKMTQS)); + queryStatistics.Type = D3DKMTQS_PROCESS_SEGMENT; + queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; + queryStatistics.hProcess = ProcessHandle; + queryStatistics.QueryProcessSegment.SegmentId = i; + if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { + ULONGLONG bytesCommitted; + if (!IsWin8OrLater()) + bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo.Win7.BytesCommitted; + else + bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo.Win8.BytesCommitted; + if (aperture) + sharedBytesUsed += bytesCommitted; + else + dedicatedBytesUsed += bytesCommitted; + } + } + } + } + } + + FreeLibrary(gdi32Handle); + +#define REPORT(_path, _amount, _desc) \ + do { \ + nsresult rv; \ + rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \ + KIND_OTHER, UNITS_BYTES, _amount, \ + NS_LITERAL_CSTRING(_desc), aClosure); \ + NS_ENSURE_SUCCESS(rv, rv); \ + } while (0) + + REPORT("gpu-committed", committedBytesUsed, + "Memory committed by the Windows graphics system."); + + REPORT("gpu-dedicated", dedicatedBytesUsed, + "Out-of-process memory allocated for this process in a " + "physical GPU adapter's memory."); + + REPORT("gpu-shared", sharedBytesUsed, + "In-process memory that is shared with the GPU."); + +#undef REPORT + + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(GPUAdapterReporter, nsIMemoryReporter) + +static __inline void +BuildKeyNameFromFontName(nsAString &aName) +{ + if (aName.Length() >= LF_FACESIZE) + aName.Truncate(LF_FACESIZE - 1); + ToLowerCase(aName); +} + +gfxWindowsPlatform::gfxWindowsPlatform() + : mD3D11DeviceInitialized(false) + , mPrefFonts(50) +{ + mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; + mUseClearTypeAlways = UNINITIALIZED_VALUE; + + mUsingGDIFonts = false; + + /* + * Initialize COM + */ + CoInitialize(nullptr); + +#ifdef CAIRO_HAS_D2D_SURFACE + RegisterStrongMemoryReporter(new GfxD2DSurfaceReporter()); + mD2DDevice = nullptr; +#endif + RegisterStrongMemoryReporter(new GfxD2DVramReporter()); + + UpdateRenderMode(); + + RegisterStrongMemoryReporter(new GPUAdapterReporter()); +} + +gfxWindowsPlatform::~gfxWindowsPlatform() +{ + mDeviceManager = nullptr; + + // not calling FT_Done_FreeType because cairo may still hold references to + // these FT_Faces. See bug 458169. +#ifdef CAIRO_HAS_D2D_SURFACE + if (mD2DDevice) { + cairo_release_device(mD2DDevice); + } +#endif + + mozilla::gfx::Factory::D2DCleanup(); + + /* + * Uninitialize COM + */ + CoUninitialize(); +} + +double +gfxWindowsPlatform::GetDPIScale() +{ + return WinUtils::LogToPhysFactor(); +} + +void +gfxWindowsPlatform::UpdateRenderMode() +{ +/* Pick the default render mode for + * desktop. + */ + mRenderMode = RENDER_GDI; + + bool isVistaOrHigher = IsVistaOrLater(); + + bool safeMode = false; + nsCOMPtr xr = do_GetService("@mozilla.org/xre/runtime;1"); + if (xr) + xr->GetInSafeMode(&safeMode); + + mUseDirectWrite = Preferences::GetBool("gfx.font_rendering.directwrite.enabled", false); + +#ifdef CAIRO_HAS_D2D_SURFACE + bool d2dDisabled = false; + bool d2dForceEnabled = false; + bool d2dBlocked = false; + + nsCOMPtr gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); + if (gfxInfo) { + int32_t status; + if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) { + if (status != nsIGfxInfo::FEATURE_NO_INFO) { + d2dBlocked = true; + } + } + } + + // These will only be evaluated once, and any subsequent changes to + // the preferences will be ignored until restart. + d2dDisabled = gfxPrefs::Direct2DDisabled(); + d2dForceEnabled = gfxPrefs::Direct2DForceEnabled(); + + bool tryD2D = d2dForceEnabled || (!d2dBlocked && !gfxPrefs::LayersPreferD3D9()); + + // Do not ever try if d2d is explicitly disabled, + // or if we're not using DWrite fonts. + if (d2dDisabled || mUsingGDIFonts) { + tryD2D = false; + } + + if (isVistaOrHigher && !safeMode && tryD2D) { + VerifyD2DDevice(d2dForceEnabled); + if (mD2DDevice) { + mRenderMode = RENDER_DIRECT2D; + mUseDirectWrite = true; + } + } else { + mD2DDevice = nullptr; + } +#endif + +#ifdef CAIRO_HAS_DWRITE_FONT + // Enable when it's preffed on -and- we're using Vista or higher. Or when + // we're going to use D2D. + if (!mDWriteFactory && (mUseDirectWrite && isVistaOrHigher)) { + mozilla::ScopedGfxFeatureReporter reporter("DWrite"); + decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*) + GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory"); + + if (createDWriteFactory) { + /** + * I need a direct pointer to be able to cast to IUnknown**, I also + * need to remember to release this because the nsRefPtr will + * AddRef it. + */ + IDWriteFactory *factory; + HRESULT hr = createDWriteFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(&factory)); + + if (SUCCEEDED(hr) && factory) { + mDWriteFactory = factory; + factory->Release(); + hr = mDWriteFactory->CreateTextAnalyzer( + getter_AddRefs(mDWriteAnalyzer)); + } + + SetupClearTypeParams(); + + if (hr == S_OK) + reporter.SetSuccessful(); + } + } +#endif + + uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO); + uint32_t contentMask = BackendTypeBit(BackendType::CAIRO); + BackendType defaultBackend = BackendType::CAIRO; + if (mRenderMode == RENDER_DIRECT2D) { + canvasMask |= BackendTypeBit(BackendType::DIRECT2D); + contentMask |= BackendTypeBit(BackendType::DIRECT2D); + defaultBackend = BackendType::DIRECT2D; + } else { + canvasMask |= BackendTypeBit(BackendType::SKIA); + } + contentMask |= BackendTypeBit(BackendType::SKIA); + InitBackendPrefs(canvasMask, defaultBackend, + contentMask, defaultBackend); +} + +#ifdef CAIRO_HAS_D2D_SURFACE +HRESULT +gfxWindowsPlatform::CreateDevice(nsRefPtr &adapter1, + int featureLevelIndex) +{ + nsModuleHandle d3d10module(LoadLibrarySystem32(L"d3d10_1.dll")); + if (!d3d10module) + return E_FAIL; + decltype(D3D10CreateDevice1)* createD3DDevice = + (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module, "D3D10CreateDevice1"); + if (!createD3DDevice) + return E_FAIL; + + nsRefPtr device; + HRESULT hr = + createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr, + D3D10_CREATE_DEVICE_BGRA_SUPPORT | + D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, + static_cast(kSupportedFeatureLevels[featureLevelIndex]), + D3D10_1_SDK_VERSION, getter_AddRefs(device)); + + // If we fail here, the DirectX version or video card probably + // changed. We previously could use 10.1 but now we can't + // anymore. Revert back to doing a 10.0 check first before + // the 10.1 check. + if (device) { + mD2DDevice = cairo_d2d_create_device_from_d3d10device(device); + + // Setup a pref for future launch optimizaitons when in main process. + if (XRE_GetProcessType() == GeckoProcessType_Default) { + Preferences::SetInt(kFeatureLevelPref, featureLevelIndex); + } + } + + return device ? S_OK : hr; +} +#endif + +void +gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce) +{ +#ifdef CAIRO_HAS_D2D_SURFACE + if (mD2DDevice) { + ID3D10Device1 *device = cairo_d2d_device_get_device(mD2DDevice); + + if (SUCCEEDED(device->GetDeviceRemovedReason())) { + return; + } + mD2DDevice = nullptr; + + // Surface cache needs to be invalidated since it may contain vector + // images rendered with our old, broken D2D device. + SurfaceCache::DiscardAll(); + } + + mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce); + + nsRefPtr device; + + int supportedFeatureLevelsCount = ArrayLength(kSupportedFeatureLevels); + // If we're not running in Metro don't allow DX9.3 + if (!IsRunningInWindowsMetro()) { + supportedFeatureLevelsCount--; + } + + nsRefPtr adapter1 = GetDXGIAdapter(); + + if (!adapter1) { + // Unable to create adapter, abort acceleration. + return; + } + + // It takes a lot of time (5-10% of startup time or ~100ms) to do both + // a createD3DDevice on D3D10_FEATURE_LEVEL_10_0. We therefore store + // the last used feature level to go direct to that. + int featureLevelIndex = Preferences::GetInt(kFeatureLevelPref, 0); + if (featureLevelIndex >= supportedFeatureLevelsCount || featureLevelIndex < 0) + featureLevelIndex = 0; + + // Start with the last used feature level, and move to lower DX versions + // until we find one that works. + HRESULT hr = E_FAIL; + for (int i = featureLevelIndex; i < supportedFeatureLevelsCount; i++) { + hr = CreateDevice(adapter1, i); + // If it succeeded we found the first available feature level + if (SUCCEEDED(hr)) + break; + } + + // If we succeeded in creating a device, try for a newer device + // that we haven't tried yet. + if (SUCCEEDED(hr)) { + for (int i = featureLevelIndex - 1; i >= 0; i--) { + hr = CreateDevice(adapter1, i); + // If it failed then we don't have new hardware + if (FAILED(hr)) { + break; + } + } + } + + if (!mD2DDevice && aAttemptForce) { + mD2DDevice = cairo_d2d_create_device(); + } + + if (mD2DDevice) { + reporter.SetSuccessful(); + mozilla::gfx::Factory::SetDirect3D10Device(cairo_d2d_device_get_device(mD2DDevice)); + } +#endif +} + +gfxPlatformFontList* +gfxWindowsPlatform::CreatePlatformFontList() +{ + mUsingGDIFonts = false; + gfxPlatformFontList *pfl; +#ifdef CAIRO_HAS_DWRITE_FONT + // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd + // crashers so blacklist them altogether + if (IsNotWin7PreRTM() && GetDWriteFactory()) { + pfl = new gfxDWriteFontList(); + if (NS_SUCCEEDED(pfl->InitFontList())) { + return pfl; + } + // DWrite font initialization failed! Don't know why this would happen, + // but apparently it can - see bug 594865. + // So we're going to fall back to GDI fonts & rendering. + gfxPlatformFontList::Shutdown(); + SetRenderMode(RENDER_GDI); + } +#endif + pfl = new gfxGDIFontList(); + mUsingGDIFonts = true; + + if (NS_SUCCEEDED(pfl->InitFontList())) { + return pfl; + } + + gfxPlatformFontList::Shutdown(); + return nullptr; +} + +already_AddRefed +gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& size, + gfxContentType contentType) +{ + nsRefPtr surf = nullptr; + +#ifdef CAIRO_HAS_WIN32_SURFACE + if (mRenderMode == RENDER_GDI) + surf = new gfxWindowsSurface(ThebesIntSize(size), + OptimalFormatForContent(contentType)); +#endif + +#ifdef CAIRO_HAS_D2D_SURFACE + if (mRenderMode == RENDER_DIRECT2D) + surf = new gfxD2DSurface(ThebesIntSize(size), + OptimalFormatForContent(contentType)); +#endif + + if (!surf || surf->CairoStatus()) { + surf = new gfxImageSurface(ThebesIntSize(size), + OptimalFormatForContent(contentType)); + } + + return surf.forget(); +} + +already_AddRefed +gfxWindowsPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize, + gfxContentType aContentType) +{ +#ifdef CAIRO_HAS_D2D_SURFACE + if (mRenderMode == RENDER_DIRECT2D) { + nsRefPtr surface = + new gfxImageSurface(aSize, OptimalFormatForContent(aContentType)); + return surface.forget(); + } +#endif + + nsRefPtr surface = CreateOffscreenSurface(aSize.ToIntSize(), + aContentType); +#ifdef DEBUG + nsRefPtr imageSurface = surface->GetAsImageSurface(); + NS_ASSERTION(imageSurface, "Surface cannot be converted to a gfxImageSurface"); +#endif + return surface.forget(); +} + +TemporaryRef +gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) +{ + if (aFont->GetType() == gfxFont::FONT_TYPE_DWRITE) { + gfxDWriteFont *font = static_cast(aFont); + + NativeFont nativeFont; + nativeFont.mType = NativeFontType::DWRITE_FONT_FACE; + nativeFont.mFont = font->GetFontFace(); + + if (aTarget->GetType() == BackendType::CAIRO) { + return Factory::CreateScaledFontWithCairo(nativeFont, + font->GetAdjustedSize(), + font->GetCairoScaledFont()); + } + + return Factory::CreateScaledFontForNativeFont(nativeFont, + font->GetAdjustedSize()); + } + + NS_ASSERTION(aFont->GetType() == gfxFont::FONT_TYPE_GDI, + "Fonts on windows should be GDI or DWrite!"); + + NativeFont nativeFont; + nativeFont.mType = NativeFontType::GDI_FONT_FACE; + LOGFONT lf; + GetObject(static_cast(aFont)->GetHFONT(), sizeof(LOGFONT), &lf); + nativeFont.mFont = &lf; + + if (aTarget->GetType() == BackendType::CAIRO) { + return Factory::CreateScaledFontWithCairo(nativeFont, + aFont->GetAdjustedSize(), + aFont->GetCairoScaledFont()); + } + + return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); +} + +already_AddRefed +gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) +{ +#ifdef XP_WIN + if (aTarget->GetType() == BackendType::DIRECT2D) { + if (!GetD2DDevice()) { + // We no longer have a D2D device, can't do this. + return nullptr; + } + + RefPtr texture = + static_cast(aTarget->GetNativeSurface(NativeSurfaceType::D3D10_TEXTURE)); + + if (!texture) { + return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); + } + + aTarget->Flush(); + + nsRefPtr surf = + new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat())); + + // shouldn't this hold a reference? + surf->SetData(&kDrawTarget, aTarget, nullptr); + return surf.forget(); + } +#endif + + return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); +} + +nsresult +gfxWindowsPlatform::GetFontList(nsIAtom *aLangGroup, + const nsACString& aGenericFamily, + nsTArray& aListOfFonts) +{ + gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts); + + return NS_OK; +} + +static void +RemoveCharsetFromFontSubstitute(nsAString &aName) +{ + int32_t comma = aName.FindChar(char16_t(',')); + if (comma >= 0) + aName.Truncate(comma); +} + +nsresult +gfxWindowsPlatform::UpdateFontList() +{ + gfxPlatformFontList::PlatformFontList()->UpdateFontList(); + + return NS_OK; +} + +static const char kFontAparajita[] = "Aparajita"; +static const char kFontArabicTypesetting[] = "Arabic Typesetting"; +static const char kFontArial[] = "Arial"; +static const char kFontArialUnicodeMS[] = "Arial Unicode MS"; +static const char kFontCambria[] = "Cambria"; +static const char kFontCambriaMath[] = "Cambria Math"; +static const char kFontEbrima[] = "Ebrima"; +static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa"; +static const char kFontEuphemia[] = "Euphemia"; +static const char kFontGabriola[] = "Gabriola"; +static const char kFontJavaneseText[] = "Javanese Text"; +static const char kFontKhmerUI[] = "Khmer UI"; +static const char kFontLaoUI[] = "Lao UI"; +static const char kFontLeelawadeeUI[] = "Leelawadee UI"; +static const char kFontLucidaSansUnicode[] = "Lucida Sans Unicode"; +static const char kFontMVBoli[] = "MV Boli"; +static const char kFontMalgunGothic[] = "Malgun Gothic"; +static const char kFontMicrosoftJhengHei[] = "Microsoft JhengHei"; +static const char kFontMicrosoftNewTaiLue[] = "Microsoft New Tai Lue"; +static const char kFontMicrosoftPhagsPa[] = "Microsoft PhagsPa"; +static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le"; +static const char kFontMicrosoftUighur[] = "Microsoft Uighur"; +static const char kFontMicrosoftYaHei[] = "Microsoft YaHei"; +static const char kFontMicrosoftYiBaiti[] = "Microsoft Yi Baiti"; +static const char kFontMeiryo[] = "Meiryo"; +static const char kFontMongolianBaiti[] = "Mongolian Baiti"; +static const char kFontMyanmarText[] = "Myanmar Text"; +static const char kFontNirmalaUI[] = "Nirmala UI"; +static const char kFontNyala[] = "Nyala"; +static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee"; +static const char kFontSegoeUI[] = "Segoe UI"; +static const char kFontSegoeUISymbol[] = "Segoe UI Symbol"; +static const char kFontSylfaen[] = "Sylfaen"; +static const char kFontTraditionalArabic[] = "Traditional Arabic"; +static const char kFontUtsaah[] = "Utsaah"; +static const char kFontYuGothic[] = "Yu Gothic"; + +void +gfxWindowsPlatform::GetCommonFallbackFonts(const uint32_t aCh, + int32_t aRunScript, + nsTArray& aFontList) +{ + // Arial is used as the default fallback for system fallback + aFontList.AppendElement(kFontArial); + + if (!IS_IN_BMP(aCh)) { + uint32_t p = aCh >> 16; + if (p == 1) { // SMP plane + aFontList.AppendElement(kFontSegoeUISymbol); + aFontList.AppendElement(kFontEbrima); + aFontList.AppendElement(kFontNirmalaUI); + aFontList.AppendElement(kFontCambriaMath); + } + } else { + uint32_t b = (aCh >> 8) & 0xff; + + switch (b) { + case 0x05: + aFontList.AppendElement(kFontEstrangeloEdessa); + aFontList.AppendElement(kFontCambria); + break; + case 0x06: + aFontList.AppendElement(kFontMicrosoftUighur); + break; + case 0x07: + aFontList.AppendElement(kFontEstrangeloEdessa); + aFontList.AppendElement(kFontMVBoli); + aFontList.AppendElement(kFontEbrima); + break; + case 0x09: + aFontList.AppendElement(kFontNirmalaUI); + aFontList.AppendElement(kFontUtsaah); + aFontList.AppendElement(kFontAparajita); + break; + case 0x0e: + aFontList.AppendElement(kFontLaoUI); + break; + case 0x10: + aFontList.AppendElement(kFontMyanmarText); + break; + case 0x11: + aFontList.AppendElement(kFontMalgunGothic); + break; + case 0x12: + case 0x13: + aFontList.AppendElement(kFontNyala); + aFontList.AppendElement(kFontPlantagenetCherokee); + break; + case 0x14: + case 0x15: + case 0x16: + aFontList.AppendElement(kFontEuphemia); + aFontList.AppendElement(kFontSegoeUISymbol); + break; + case 0x17: + aFontList.AppendElement(kFontKhmerUI); + break; + case 0x18: // Mongolian + aFontList.AppendElement(kFontMongolianBaiti); + aFontList.AppendElement(kFontEuphemia); + break; + case 0x19: + aFontList.AppendElement(kFontMicrosoftTaiLe); + aFontList.AppendElement(kFontMicrosoftNewTaiLue); + aFontList.AppendElement(kFontKhmerUI); + break; + break; + case 0x1a: + aFontList.AppendElement(kFontLeelawadeeUI); + break; + case 0x1c: + aFontList.AppendElement(kFontNirmalaUI); + break; + case 0x20: // Symbol ranges + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + aFontList.AppendElement(kFontSegoeUI); + aFontList.AppendElement(kFontSegoeUISymbol); + aFontList.AppendElement(kFontCambria); + aFontList.AppendElement(kFontMeiryo); + aFontList.AppendElement(kFontArial); + aFontList.AppendElement(kFontLucidaSansUnicode); + aFontList.AppendElement(kFontEbrima); + break; + case 0x2d: + case 0x2e: + case 0x2f: + aFontList.AppendElement(kFontEbrima); + aFontList.AppendElement(kFontNyala); + aFontList.AppendElement(kFontSegoeUI); + aFontList.AppendElement(kFontSegoeUISymbol); + aFontList.AppendElement(kFontMeiryo); + break; + case 0x28: // Braille + aFontList.AppendElement(kFontSegoeUISymbol); + break; + case 0x30: + case 0x31: + aFontList.AppendElement(kFontMicrosoftYaHei); + break; + case 0x32: + aFontList.AppendElement(kFontMalgunGothic); + break; + case 0x4d: + aFontList.AppendElement(kFontSegoeUISymbol); + break; + case 0x9f: + aFontList.AppendElement(kFontMicrosoftYaHei); + aFontList.AppendElement(kFontYuGothic); + break; + case 0xa0: // Yi + case 0xa1: + case 0xa2: + case 0xa3: + case 0xa4: + aFontList.AppendElement(kFontMicrosoftYiBaiti); + aFontList.AppendElement(kFontSegoeUI); + break; + case 0xa5: + case 0xa6: + case 0xa7: + aFontList.AppendElement(kFontEbrima); + aFontList.AppendElement(kFontSegoeUI); + aFontList.AppendElement(kFontCambriaMath); + break; + case 0xa8: + aFontList.AppendElement(kFontMicrosoftPhagsPa); + aFontList.AppendElement(kFontNirmalaUI); + break; + case 0xa9: + aFontList.AppendElement(kFontMalgunGothic); + aFontList.AppendElement(kFontJavaneseText); + break; + case 0xaa: + aFontList.AppendElement(kFontMyanmarText); + break; + case 0xab: + aFontList.AppendElement(kFontEbrima); + aFontList.AppendElement(kFontNyala); + break; + case 0xd7: + aFontList.AppendElement(kFontMalgunGothic); + break; + case 0xfb: + aFontList.AppendElement(kFontMicrosoftUighur); + aFontList.AppendElement(kFontGabriola); + aFontList.AppendElement(kFontSylfaen); + break; + case 0xfc: + case 0xfd: + aFontList.AppendElement(kFontTraditionalArabic); + aFontList.AppendElement(kFontArabicTypesetting); + break; + case 0xfe: + aFontList.AppendElement(kFontTraditionalArabic); + aFontList.AppendElement(kFontMicrosoftJhengHei); + break; + case 0xff: + aFontList.AppendElement(kFontMicrosoftJhengHei); + break; + default: + break; + } + } + + // Arial Unicode MS has lots of glyphs for obscure characters, + // use it as a last resort + aFontList.AppendElement(kFontArialUnicodeMS); +} + +struct ResolveData { + ResolveData(gfxPlatform::FontResolverCallback aCallback, + gfxWindowsPlatform *aCaller, const nsAString *aFontName, + void *aClosure) : + mFoundCount(0), mCallback(aCallback), mCaller(aCaller), + mFontName(aFontName), mClosure(aClosure) {} + uint32_t mFoundCount; + gfxPlatform::FontResolverCallback mCallback; + gfxWindowsPlatform *mCaller; + const nsAString *mFontName; + void *mClosure; +}; + +nsresult +gfxWindowsPlatform::ResolveFontName(const nsAString& aFontName, + FontResolverCallback aCallback, + void *aClosure, + bool& aAborted) +{ + nsAutoString resolvedName; + if (!gfxPlatformFontList::PlatformFontList()-> + ResolveFontName(aFontName, resolvedName)) { + aAborted = false; + return NS_OK; + } + aAborted = !(*aCallback)(resolvedName, aClosure); + return NS_OK; +} + +nsresult +gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) +{ + gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName); + return NS_OK; +} + +gfxFontGroup * +gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies, + const gfxFontStyle *aStyle, + gfxUserFontSet *aUserFontSet) +{ + return new gfxFontGroup(aFamilies, aStyle, aUserFontSet); +} + +gfxFontEntry* +gfxWindowsPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, + const nsAString& aFontName) +{ + return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, + aFontName); +} + +gfxFontEntry* +gfxWindowsPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, + const uint8_t *aFontData, uint32_t aLength) +{ + return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry, + aFontData, + aLength); +} + +bool +gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) +{ + // check for strange format flags + NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED), + "strange font format hint set"); + + // accept supported formats + if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF | + gfxUserFontSet::FLAG_FORMAT_OPENTYPE | + gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) { + return true; + } + + // reject all other formats, known and unknown + if (aFormatFlags != 0) { + return false; + } + + // no format hint set, need to look at data + return true; +} + +gfxFontFamily * +gfxWindowsPlatform::FindFontFamily(const nsAString& aName) +{ + return gfxPlatformFontList::PlatformFontList()->FindFamily(aName); +} + +gfxFontEntry * +gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle) +{ + nsRefPtr ff = FindFontFamily(aName); + if (!ff) + return nullptr; + + bool aNeedsBold; + return ff->FindFontForStyle(aFontStyle, aNeedsBold); +} + +void +gfxWindowsPlatform::GetPlatformCMSOutputProfile(void* &mem, size_t &mem_size) +{ + WCHAR str[MAX_PATH]; + DWORD size = MAX_PATH; + BOOL res; + + mem = nullptr; + mem_size = 0; + + HDC dc = GetDC(nullptr); + if (!dc) + return; + +#if _MSC_VER + __try { + res = GetICMProfileW(dc, &size, (LPWSTR)&str); + } __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { + res = FALSE; + } +#else + res = GetICMProfileW(dc, &size, (LPWSTR)&str); +#endif + + ReleaseDC(nullptr, dc); + if (!res) + return; + +#ifdef _WIN32 + qcms_data_from_unicode_path(str, &mem, &mem_size); + +#ifdef DEBUG_tor + if (mem_size > 0) + fprintf(stderr, + "ICM profile read from %s successfully\n", + NS_ConvertUTF16toUTF8(str).get()); +#endif // DEBUG_tor +#endif // _WIN32 +} + +bool +gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray > *array) +{ + return mPrefFonts.Get(aKey, array); +} + +void +gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray >& array) +{ + mPrefFonts.Put(aKey, array); +} + +bool +gfxWindowsPlatform::UseClearTypeForDownloadableFonts() +{ + if (mUseClearTypeForDownloadableFonts == UNINITIALIZED_VALUE) { + mUseClearTypeForDownloadableFonts = Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, true); + } + + return mUseClearTypeForDownloadableFonts; +} + +bool +gfxWindowsPlatform::UseClearTypeAlways() +{ + if (mUseClearTypeAlways == UNINITIALIZED_VALUE) { + mUseClearTypeAlways = Preferences::GetBool(GFX_USE_CLEARTYPE_ALWAYS, false); + } + + return mUseClearTypeAlways; +} + +void +gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath, nsAString& aVersion) +{ + DWORD versInfoSize, vers[4] = {0}; + // version info not available case + aVersion.Assign(NS_LITERAL_STRING("0.0.0.0")); + versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr); + nsAutoTArray versionInfo; + + if (versInfoSize == 0 || + !versionInfo.AppendElements(uint32_t(versInfoSize))) + { + return; + } + + if (!GetFileVersionInfoW(aDLLPath, 0, versInfoSize, + LPBYTE(versionInfo.Elements()))) + { + return; + } + + UINT len = 0; + VS_FIXEDFILEINFO *fileInfo = nullptr; + if (!VerQueryValue(LPBYTE(versionInfo.Elements()), TEXT("\\"), + (LPVOID *)&fileInfo, &len) || + len == 0 || + fileInfo == nullptr) + { + return; + } + + DWORD fileVersMS = fileInfo->dwFileVersionMS; + DWORD fileVersLS = fileInfo->dwFileVersionLS; + + vers[0] = HIWORD(fileVersMS); + vers[1] = LOWORD(fileVersMS); + vers[2] = HIWORD(fileVersLS); + vers[3] = LOWORD(fileVersLS); + + char buf[256]; + sprintf(buf, "%d.%d.%d.%d", vers[0], vers[1], vers[2], vers[3]); + aVersion.Assign(NS_ConvertUTF8toUTF16(buf)); +} + +void +gfxWindowsPlatform::GetCleartypeParams(nsTArray& aParams) +{ + HKEY hKey, subKey; + DWORD i, rv, size, type; + WCHAR displayName[256], subkeyName[256]; + + aParams.Clear(); + + // construct subkeys based on HKLM subkeys, assume they are same for HKCU + rv = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"Software\\Microsoft\\Avalon.Graphics", + 0, KEY_READ, &hKey); + + if (rv != ERROR_SUCCESS) { + return; + } + + // enumerate over subkeys + for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) { + size = ArrayLength(displayName); + rv = RegEnumKeyExW(hKey, i, displayName, &size, + nullptr, nullptr, nullptr, nullptr); + if (rv != ERROR_SUCCESS) { + continue; + } + + ClearTypeParameterInfo ctinfo; + ctinfo.displayName.Assign(displayName); + + DWORD subrv, value; + bool foundData = false; + + swprintf_s(subkeyName, ArrayLength(subkeyName), + L"Software\\Microsoft\\Avalon.Graphics\\%s", displayName); + + // subkey for gamma, pixel structure + subrv = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + subkeyName, 0, KEY_QUERY_VALUE, &subKey); + + if (subrv == ERROR_SUCCESS) { + size = sizeof(value); + subrv = RegQueryValueExW(subKey, L"GammaLevel", nullptr, &type, + (LPBYTE)&value, &size); + if (subrv == ERROR_SUCCESS && type == REG_DWORD) { + foundData = true; + ctinfo.gamma = value; + } + + size = sizeof(value); + subrv = RegQueryValueExW(subKey, L"PixelStructure", nullptr, &type, + (LPBYTE)&value, &size); + if (subrv == ERROR_SUCCESS && type == REG_DWORD) { + foundData = true; + ctinfo.pixelStructure = value; + } + + RegCloseKey(subKey); + } + + // subkey for cleartype level, enhanced contrast + subrv = RegOpenKeyExW(HKEY_CURRENT_USER, + subkeyName, 0, KEY_QUERY_VALUE, &subKey); + + if (subrv == ERROR_SUCCESS) { + size = sizeof(value); + subrv = RegQueryValueExW(subKey, L"ClearTypeLevel", nullptr, &type, + (LPBYTE)&value, &size); + if (subrv == ERROR_SUCCESS && type == REG_DWORD) { + foundData = true; + ctinfo.clearTypeLevel = value; + } + + size = sizeof(value); + subrv = RegQueryValueExW(subKey, L"EnhancedContrastLevel", + nullptr, &type, (LPBYTE)&value, &size); + if (subrv == ERROR_SUCCESS && type == REG_DWORD) { + foundData = true; + ctinfo.enhancedContrast = value; + } + + RegCloseKey(subKey); + } + + if (foundData) { + aParams.AppendElement(ctinfo); + } + } + + RegCloseKey(hKey); +} + +void +gfxWindowsPlatform::FontsPrefsChanged(const char *aPref) +{ + bool clearTextFontCaches = true; + + gfxPlatform::FontsPrefsChanged(aPref); + + if (!aPref) { + mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; + mUseClearTypeAlways = UNINITIALIZED_VALUE; + } else if (!strcmp(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, aPref)) { + mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; + } else if (!strcmp(GFX_USE_CLEARTYPE_ALWAYS, aPref)) { + mUseClearTypeAlways = UNINITIALIZED_VALUE; + } else if (!strncmp(GFX_CLEARTYPE_PARAMS, aPref, strlen(GFX_CLEARTYPE_PARAMS))) { + SetupClearTypeParams(); + } else { + clearTextFontCaches = false; + } + + if (clearTextFontCaches) { + gfxFontCache *fc = gfxFontCache::GetCache(); + if (fc) { + fc->Flush(); + } + } +} + +#define ENHANCED_CONTRAST_REGISTRY_KEY \ + HKEY_CURRENT_USER, "Software\\Microsoft\\Avalon.Graphics\\DISPLAY1\\EnhancedContrastLevel" + +void +gfxWindowsPlatform::SetupClearTypeParams() +{ +#if CAIRO_HAS_DWRITE_FONT + if (GetDWriteFactory()) { + // any missing prefs will default to invalid (-1) and be ignored; + // out-of-range values will also be ignored + FLOAT gamma = -1.0; + FLOAT contrast = -1.0; + FLOAT level = -1.0; + int geometry = -1; + int mode = -1; + int32_t value; + if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_GAMMA, &value))) { + if (value >= 1000 && value <= 2200) { + gamma = FLOAT(value / 1000.0); + } + } + + if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_CONTRAST, &value))) { + if (value >= 0 && value <= 1000) { + contrast = FLOAT(value / 100.0); + } + } + + if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_LEVEL, &value))) { + if (value >= 0 && value <= 100) { + level = FLOAT(value / 100.0); + } + } + + if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_STRUCTURE, &value))) { + if (value >= 0 && value <= 2) { + geometry = value; + } + } + + if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_MODE, &value))) { + if (value >= 0 && value <= 5) { + mode = value; + } + } + + cairo_dwrite_set_cleartype_params(gamma, contrast, level, geometry, mode); + + switch (mode) { + case DWRITE_RENDERING_MODE_ALIASED: + case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC: + mMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; + break; + case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL: + mMeasuringMode = DWRITE_MEASURING_MODE_GDI_NATURAL; + break; + default: + mMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; + break; + } + + nsRefPtr defaultRenderingParams; + GetDWriteFactory()->CreateRenderingParams(getter_AddRefs(defaultRenderingParams)); + // For EnhancedContrast, we override the default if the user has not set it + // in the registry (by using the ClearType Tuner). + if (contrast >= 0.0 && contrast <= 10.0) { + contrast = contrast; + } else { + HKEY hKey; + if (RegOpenKeyExA(ENHANCED_CONTRAST_REGISTRY_KEY, + 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + contrast = defaultRenderingParams->GetEnhancedContrast(); + RegCloseKey(hKey); + } else { + contrast = 1.0; + } + } + + // For parameters that have not been explicitly set, + // we copy values from default params (or our overridden value for contrast) + if (gamma < 1.0 || gamma > 2.2) { + gamma = defaultRenderingParams->GetGamma(); + } + + if (level < 0.0 || level > 1.0) { + level = defaultRenderingParams->GetClearTypeLevel(); + } + + DWRITE_PIXEL_GEOMETRY dwriteGeometry = + static_cast(geometry); + DWRITE_RENDERING_MODE renderMode = + static_cast(mode); + + if (dwriteGeometry < DWRITE_PIXEL_GEOMETRY_FLAT || + dwriteGeometry > DWRITE_PIXEL_GEOMETRY_BGR) { + dwriteGeometry = defaultRenderingParams->GetPixelGeometry(); + } + + if (renderMode < DWRITE_RENDERING_MODE_DEFAULT || + renderMode > DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC) { + renderMode = defaultRenderingParams->GetRenderingMode(); + } + + mRenderingParams[TEXT_RENDERING_NO_CLEARTYPE] = defaultRenderingParams; + + GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level, + dwriteGeometry, renderMode, + getter_AddRefs(mRenderingParams[TEXT_RENDERING_NORMAL])); + + GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level, + dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC, + getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC])); + } +#endif +} + +void +gfxWindowsPlatform::OnDeviceManagerDestroy(DeviceManagerD3D9* aDeviceManager) +{ + if (aDeviceManager == mDeviceManager) { + mDeviceManager = nullptr; + } +} + +IDirect3DDevice9* +gfxWindowsPlatform::GetD3D9Device() +{ + DeviceManagerD3D9* manager = GetD3D9DeviceManager(); + return manager ? manager->device() : nullptr; +} + +DeviceManagerD3D9* +gfxWindowsPlatform::GetD3D9DeviceManager() +{ + // We should only create the d3d9 device on the compositor thread + // or we don't have a compositor thread. + if (!mDeviceManager && + (CompositorParent::IsInCompositorThread() || + !CompositorParent::CompositorLoop())) { + mDeviceManager = new DeviceManagerD3D9(); + if (!mDeviceManager->Init()) { + NS_WARNING("Could not initialise device manager"); + mDeviceManager = nullptr; + } + } + + return mDeviceManager; +} + +ID3D11Device* +gfxWindowsPlatform::GetD3D11Device() +{ + if (mD3D11DeviceInitialized) { + return mD3D11Device; + } + + mD3D11DeviceInitialized = true; + + nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll")); + decltype(D3D11CreateDevice)* d3d11CreateDevice = (decltype(D3D11CreateDevice)*) + GetProcAddress(d3d11Module, "D3D11CreateDevice"); + + if (!d3d11CreateDevice) { + return nullptr; + } + + nsTArray featureLevels; + if (IsWin8OrLater()) { + featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1); + } + featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0); + featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1); + featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0); + featureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3); + + RefPtr adapter = GetDXGIAdapter(); + + if (!adapter) { + return nullptr; + } + + HRESULT hr = d3d11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, + D3D11_CREATE_DEVICE_BGRA_SUPPORT, + featureLevels.Elements(), featureLevels.Length(), + D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr); + + // We leak these everywhere and we need them our entire runtime anyway, let's + // leak it here as well. + d3d11Module.disown(); + + return mD3D11Device; +} + +bool +gfxWindowsPlatform::IsOptimus() +{ + return GetModuleHandleA("nvumdshim.dll"); +} + +int +gfxWindowsPlatform::GetScreenDepth() const +{ + // if the system doesn't have all displays with the same + // pixel format, just return 24 and move on with life. + if (!GetSystemMetrics(SM_SAMEDISPLAYFORMAT)) + return 24; + + HDC hdc = GetDC(nullptr); + if (!hdc) + return 24; + + int depth = GetDeviceCaps(hdc, BITSPIXEL) * + GetDeviceCaps(hdc, PLANES); + + ReleaseDC(nullptr, hdc); + + return depth; +} + +IDXGIAdapter1* +gfxWindowsPlatform::GetDXGIAdapter() +{ + if (mAdapter) { + return mAdapter; + } + + nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll")); + decltype(CreateDXGIFactory1)* createDXGIFactory1 = (decltype(CreateDXGIFactory1)*) + GetProcAddress(dxgiModule, "CreateDXGIFactory1"); + + // Try to use a DXGI 1.1 adapter in order to share resources + // across processes. + if (createDXGIFactory1) { + nsRefPtr factory1; + HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1), + getter_AddRefs(factory1)); + + if (FAILED(hr) || !factory1) { + // This seems to happen with some people running the iZ3D driver. + // They won't get acceleration. + return nullptr; + } + + hr = factory1->EnumAdapters1(0, byRef(mAdapter)); + if (FAILED(hr)) { + // We should return and not accelerate if we can't obtain + // an adapter. + return nullptr; + } + } + + // We leak this module everywhere, we might as well do so here as well. + dxgiModule.disown(); + + return mAdapter; +}