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