gecko/gfx/thebes/gfxWindowsPlatform.cpp
Ehsan Akhgari 6220f98ec6 Backed out 9 changesets (bug 943660, bug 936964) because of ASAN use-after-free crashes on browser-chrome and mochitest-other
Backed out changeset 85486c4aa3d8 (bug 936964)
Backed out changeset 25312eb71998 (bug 936964)
Backed out changeset 6dbb8333960c (bug 936964)
Backed out changeset da6465ad476f (bug 936964)
Backed out changeset a87ffc992f38 (bug 936964)
Backed out changeset 4ae3a61182db (bug 936964)
Backed out changeset 34e9c3137804 (bug 936964)
Backed out changeset fd1459e71585 (bug 936964)
Backed out changeset 3e8a701d8bdc (bug 943660)

Landed on a CLOSED TREE

--HG--
rename : content/canvas/src/WebGLMemoryTracker.h => content/canvas/src/WebGLMemoryReporterWrapper.h
2013-11-27 20:05:00 -05:00

1521 lines
47 KiB
C++

/* -*- 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/Util.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"
#ifdef CAIRO_HAS_DWRITE_FONT
#include "gfxDWriteFontList.h"
#include "gfxDWriteFonts.h"
#include "gfxDWriteCommon.h"
#include <dwrite.h>
#endif
#include "gfxUserFontSet.h"
#include "nsWindowsHelpers.h"
#include "gfx2DGlue.h"
#include <string>
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;
#ifdef CAIRO_HAS_D2D_SURFACE
#include "gfxD2DSurface.h"
#include <d3d10_1.h>
#include "mozilla/gfx/2D.h"
#include "nsMemory.h"
#endif
#include <d3d11.h>
#include "nsIMemoryReporter.h"
#include <winternl.h>
#include "d3dkmtQueryStatistics.h"
using namespace mozilla;
#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 GfxD2DSurfaceCacheReporter MOZ_FINAL : public MemoryUniReporter
{
public:
GfxD2DSurfaceCacheReporter()
: MemoryUniReporter("gfx-d2d-surface-cache", KIND_OTHER, UNITS_BYTES,
"Memory used by the Direct2D internal surface cache.")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
return cairo_d2d_get_image_surface_cache_usage();
}
};
namespace
{
bool OncePreferenceDirect2DDisabled()
{
static int preferenceValue = -1;
if (preferenceValue < 0) {
preferenceValue = Preferences::GetBool("gfx.direct2d.disabled", false);
}
return !!preferenceValue;
}
bool OncePreferenceDirect2DForceEnabled()
{
static int preferenceValue = -1;
if (preferenceValue < 0) {
preferenceValue = Preferences::GetBool("gfx.direct2d.force-enabled", false);
}
return !!preferenceValue;
}
} // anonymous namespace
class GfxD2DSurfaceVramReporter MOZ_FINAL : public MemoryUniReporter
{
public:
GfxD2DSurfaceVramReporter()
: MemoryUniReporter("gfx-d2d-surface-vram", KIND_OTHER, UNITS_BYTES,
"Video memory used by D2D surfaces.")
{}
private:
int64_t Amount() MOZ_OVERRIDE {
cairo_device_t *device =
gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
return device ? cairo_d2d_get_surface_vram_usage(device) : 0;
}
};
#endif
class GfxD2DVramDrawTargetReporter MOZ_FINAL : public MemoryUniReporter
{
public:
GfxD2DVramDrawTargetReporter()
: MemoryUniReporter("gfx-d2d-vram-draw-target", KIND_OTHER, UNITS_BYTES,
"Video memory used by D2D DrawTargets.")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
return Factory::GetD2DVRAMUsageDrawTarget();
}
};
class GfxD2DVramSourceSurfaceReporter MOZ_FINAL : public MemoryUniReporter
{
public:
GfxD2DVramSourceSurfaceReporter()
: MemoryUniReporter("gfx-d2d-vram-source-surface",
KIND_OTHER, UNITS_BYTES,
"Video memory used by D2D SourceSurfaces.")
{}
private:
int64_t Amount() MOZ_OVERRIDE
{
return Factory::GetD2DVRAMUsageSourceSurface();
}
};
#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"
#ifdef CAIRO_HAS_DWRITE_FONT
// DirectWrite is not available on all platforms, we need to use the function
// pointer.
typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)(
DWRITE_FACTORY_TYPE factoryType,
REFIID iid,
IUnknown **factory
);
#endif
#ifdef CAIRO_HAS_D2D_SURFACE
typedef HRESULT (WINAPI*D3D10CreateDevice1Func)(
IDXGIAdapter *pAdapter,
D3D10_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
D3D10_FEATURE_LEVEL1 HardwareLevel,
UINT SDKVersion,
ID3D10Device1 **ppDevice
);
#endif
typedef HRESULT(WINAPI*CreateDXGIFactory1Func)(
REFIID riid,
void **ppFactory
);
typedef HRESULT (WINAPI*D3D11CreateDeviceFunc)(
IDXGIAdapter *pAdapter,
D3D_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
D3D_FEATURE_LEVEL *pFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
ID3D11Device **ppDevice,
D3D_FEATURE_LEVEL *pFeatureLevel,
ID3D11DeviceContext *ppImmediateContext
);
class GPUAdapterReporter : public MemoryMultiReporter
{
// 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:
GPUAdapterReporter()
: MemoryMultiReporter("gpu-adapter")
{}
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))) {
if (aperture)
sharedBytesUsed += queryStatistics.QueryResult
.ProcessSegmentInfo
.BytesCommitted;
else
dedicatedBytesUsed += queryStatistics.QueryResult
.ProcessSegmentInfo
.BytesCommitted;
}
}
}
}
}
FreeLibrary(gdi32Handle);
#define REPORT(_path, _amount, _desc) \
do { \
nsresult rv; \
rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
nsIMemoryReporter::KIND_OTHER, \
nsIMemoryReporter::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;
}
};
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);
mScreenDC = GetDC(nullptr);
#ifdef CAIRO_HAS_D2D_SURFACE
RegisterStrongMemoryReporter(new GfxD2DSurfaceCacheReporter());
RegisterStrongMemoryReporter(new GfxD2DSurfaceVramReporter());
mD2DDevice = nullptr;
#endif
RegisterStrongMemoryReporter(new GfxD2DVramDrawTargetReporter());
RegisterStrongMemoryReporter(new GfxD2DVramSourceSurfaceReporter());
UpdateRenderMode();
// This reporter is disabled because it frequently gives bogus values. See
// bug 917496.
//RegisterStrongMemoryReporter(new GPUAdapterReporter());
}
gfxWindowsPlatform::~gfxWindowsPlatform()
{
mDeviceManager = nullptr;
::ReleaseDC(nullptr, mScreenDC);
// 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();
}
void
gfxWindowsPlatform::UpdateRenderMode()
{
/* Pick the default render mode for
* desktop.
*/
mRenderMode = RENDER_GDI;
bool isVistaOrHigher = IsVistaOrLater();
bool safeMode = false;
nsCOMPtr<nsIXULRuntime> 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<nsIGfxInfo> 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 = OncePreferenceDirect2DDisabled();
d2dForceEnabled = OncePreferenceDirect2DForceEnabled();
bool tryD2D = !d2dBlocked || d2dForceEnabled;
// 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");
DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc)
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<IUnknown**>(&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 = 1 << BACKEND_CAIRO;
uint32_t contentMask = 1 << BACKEND_CAIRO;
BackendType defaultBackend = BACKEND_CAIRO;
if (mRenderMode == RENDER_DIRECT2D) {
canvasMask |= 1 << BACKEND_DIRECT2D;
contentMask |= 1 << BACKEND_DIRECT2D;
defaultBackend = BACKEND_DIRECT2D;
} else {
canvasMask |= 1 << BACKEND_SKIA;
}
InitBackendPrefs(canvasMask, defaultBackend,
contentMask, defaultBackend);
}
#ifdef CAIRO_HAS_D2D_SURFACE
HRESULT
gfxWindowsPlatform::CreateDevice(nsRefPtr<IDXGIAdapter1> &adapter1,
int featureLevelIndex)
{
nsModuleHandle d3d10module(LoadLibrarySystem32(L"d3d10_1.dll"));
if (!d3d10module)
return E_FAIL;
D3D10CreateDevice1Func createD3DDevice =
(D3D10CreateDevice1Func)GetProcAddress(d3d10module, "D3D10CreateDevice1");
if (!createD3DDevice)
return E_FAIL;
nsRefPtr<ID3D10Device1> device;
HRESULT hr =
createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
static_cast<D3D10_FEATURE_LEVEL1>(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
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;
}
mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce);
nsRefPtr<ID3D10Device1> device;
int supportedFeatureLevelsCount = ArrayLength(kSupportedFeatureLevels);
// If we're not running in Metro don't allow DX9.3
if (!IsRunningInWindowsMetro()) {
supportedFeatureLevelsCount--;
}
nsRefPtr<IDXGIAdapter1> 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
if (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<gfxASurface>
gfxWindowsPlatform::CreateOffscreenSurface(const gfxIntSize& size,
gfxContentType contentType)
{
nsRefPtr<gfxASurface> surf = nullptr;
#ifdef CAIRO_HAS_WIN32_SURFACE
if (mRenderMode == RENDER_GDI)
surf = new gfxWindowsSurface(size, OptimalFormatForContent(contentType));
#endif
#ifdef CAIRO_HAS_D2D_SURFACE
if (mRenderMode == RENDER_DIRECT2D)
surf = new gfxD2DSurface(size, OptimalFormatForContent(contentType));
#endif
if (!surf || surf->CairoStatus()) {
surf = new gfxImageSurface(size, OptimalFormatForContent(contentType));
}
return surf.forget();
}
already_AddRefed<gfxASurface>
gfxWindowsPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize,
gfxContentType aContentType)
{
#ifdef CAIRO_HAS_D2D_SURFACE
if (mRenderMode == RENDER_DIRECT2D) {
nsRefPtr<gfxASurface> surface =
new gfxImageSurface(aSize, OptimalFormatForContent(aContentType));
return surface.forget();
}
#endif
nsRefPtr<gfxASurface> surface = CreateOffscreenSurface(aSize, aContentType);
#ifdef DEBUG
nsRefPtr<gfxImageSurface> imageSurface = surface->GetAsImageSurface();
NS_ASSERTION(imageSurface, "Surface cannot be converted to a gfxImageSurface");
#endif
return surface.forget();
}
TemporaryRef<ScaledFont>
gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
{
if (aFont->GetType() == gfxFont::FONT_TYPE_DWRITE) {
gfxDWriteFont *font = static_cast<gfxDWriteFont*>(aFont);
NativeFont nativeFont;
nativeFont.mType = NATIVE_FONT_DWRITE_FONT_FACE;
nativeFont.mFont = font->GetFontFace();
if (aTarget->GetType() == BACKEND_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 = NATIVE_FONT_GDI_FONT_FACE;
LOGFONT lf;
GetObject(static_cast<gfxGDIFont*>(aFont)->GetHFONT(), sizeof(LOGFONT), &lf);
nativeFont.mFont = &lf;
if (aTarget->GetType() == BACKEND_CAIRO) {
return Factory::CreateScaledFontWithCairo(nativeFont,
aFont->GetAdjustedSize(),
aFont->GetCairoScaledFont());
}
return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
}
already_AddRefed<gfxASurface>
gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
{
#ifdef XP_WIN
if (aTarget->GetType() == BACKEND_DIRECT2D) {
if (!GetD2DDevice()) {
// We no longer have a D2D device, can't do this.
return nullptr;
}
RefPtr<ID3D10Texture2D> texture =
static_cast<ID3D10Texture2D*>(aTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE));
if (!texture) {
return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
}
aTarget->Flush();
nsRefPtr<gfxASurface> 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<nsString>& aListOfFonts)
{
gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts);
return NS_OK;
}
static void
RemoveCharsetFromFontSubstitute(nsAString &aName)
{
int32_t comma = aName.FindChar(PRUnichar(','));
if (comma >= 0)
aName.Truncate(comma);
}
nsresult
gfxWindowsPlatform::UpdateFontList()
{
gfxPlatformFontList::PlatformFontList()->UpdateFontList();
return NS_OK;
}
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 kFontKhmerUI[] = "Khmer UI";
static const char kFontLaoUI[] = "Lao 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 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";
void
gfxWindowsPlatform::GetCommonFallbackFonts(const uint32_t aCh,
int32_t aRunScript,
nsTArray<const char*>& 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(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 0x0e:
aFontList.AppendElement(kFontLaoUI);
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);
break;
case 0x19:
aFontList.AppendElement(kFontMicrosoftTaiLe);
aFontList.AppendElement(kFontMicrosoftNewTaiLue);
aFontList.AppendElement(kFontKhmerUI);
break;
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(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 0xa0: // Yi
case 0xa1:
case 0xa2:
case 0xa3:
case 0xa4:
aFontList.AppendElement(kFontMicrosoftYiBaiti);
break;
case 0xa5:
case 0xa6:
case 0xa7:
aFontList.AppendElement(kFontEbrima);
aFontList.AppendElement(kFontCambriaMath);
break;
case 0xa8:
aFontList.AppendElement(kFontMicrosoftPhagsPa);
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<gfxFontFamily> ff = FindFontFamily(aName);
if (!ff)
return nullptr;
bool aNeedsBold;
return ff->FindFontForStyle(aFontStyle, aNeedsBold);
}
qcms_profile*
gfxWindowsPlatform::GetPlatformCMSOutputProfile()
{
WCHAR str[MAX_PATH];
DWORD size = MAX_PATH;
BOOL res;
HDC dc = GetDC(nullptr);
if (!dc)
return nullptr;
#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 nullptr;
qcms_profile* profile = qcms_profile_from_unicode_path(str);
#ifdef DEBUG_tor
if (profile)
fprintf(stderr,
"ICM profile read from %s successfully\n",
NS_ConvertUTF16toUTF8(str).get());
#endif
return profile;
}
bool
gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> > *array)
{
return mPrefFonts.Get(aKey, array);
}
void
gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> >& 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(const PRUnichar *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<BYTE,512> 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<ClearTypeParameterInfo>& 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<IDWriteRenderingParams> 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<DWRITE_PIXEL_GEOMETRY>(geometry);
DWRITE_RENDERING_MODE renderMode =
static_cast<DWRITE_RENDERING_MODE>(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"));
D3D11CreateDeviceFunc d3d11CreateDevice = (D3D11CreateDeviceFunc)
GetProcAddress(d3d11Module, "D3D11CreateDevice");
if (!d3d11CreateDevice) {
return nullptr;
}
nsTArray<D3D_FEATURE_LEVEL> 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<IDXGIAdapter1> 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");
}
IDXGIAdapter1*
gfxWindowsPlatform::GetDXGIAdapter()
{
if (mAdapter) {
return mAdapter;
}
nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
CreateDXGIFactory1Func createDXGIFactory1 = (CreateDXGIFactory1Func)
GetProcAddress(dxgiModule, "CreateDXGIFactory1");
// Try to use a DXGI 1.1 adapter in order to share resources
// across processes.
if (createDXGIFactory1) {
nsRefPtr<IDXGIFactory1> 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;
}