Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ArrayUtils.h"
9 #include "gfxWindowsPlatform.h"
11 #include "gfxImageSurface.h"
12 #include "gfxWindowsSurface.h"
14 #include "nsUnicharUtils.h"
16 #include "mozilla/Preferences.h"
17 #include "mozilla/WindowsVersion.h"
18 #include "nsServiceManagerUtils.h"
19 #include "nsTArray.h"
21 #include "nsIWindowsRegKey.h"
22 #include "nsIFile.h"
23 #include "plbase64.h"
24 #include "nsIXULRuntime.h"
26 #include "nsIGfxInfo.h"
28 #include "gfxCrashReporterUtils.h"
30 #include "gfxGDIFontList.h"
31 #include "gfxGDIFont.h"
33 #include "mozilla/layers/CompositorParent.h" // for CompositorParent::IsInCompositorThread
34 #include "DeviceManagerD3D9.h"
36 #include "WinUtils.h"
38 #ifdef CAIRO_HAS_DWRITE_FONT
39 #include "gfxDWriteFontList.h"
40 #include "gfxDWriteFonts.h"
41 #include "gfxDWriteCommon.h"
42 #include <dwrite.h>
43 #endif
45 #include "gfxUserFontSet.h"
46 #include "nsWindowsHelpers.h"
47 #include "gfx2DGlue.h"
49 #include <string>
51 #ifdef CAIRO_HAS_D2D_SURFACE
52 #include "gfxD2DSurface.h"
54 #include <d3d10_1.h>
56 #include "mozilla/gfx/2D.h"
58 #include "nsMemory.h"
59 #endif
61 #include <d3d11.h>
63 #include "nsIMemoryReporter.h"
64 #include <winternl.h>
65 #include "d3dkmtQueryStatistics.h"
67 #include "SurfaceCache.h"
68 #include "gfxPrefs.h"
70 using namespace mozilla;
71 using namespace mozilla::gfx;
72 using namespace mozilla::layers;
73 using namespace mozilla::widget;
74 using namespace mozilla::image;
76 #ifdef CAIRO_HAS_D2D_SURFACE
78 static const char *kFeatureLevelPref =
79 "gfx.direct3d.last_used_feature_level_idx";
80 static const int kSupportedFeatureLevels[] =
81 { D3D10_FEATURE_LEVEL_10_1, D3D10_FEATURE_LEVEL_10_0,
82 D3D10_FEATURE_LEVEL_9_3 };
84 class GfxD2DSurfaceReporter MOZ_FINAL : public nsIMemoryReporter
85 {
86 public:
87 NS_DECL_ISUPPORTS
89 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
90 nsISupports* aData)
91 {
92 nsresult rv;
94 int64_t amount = cairo_d2d_get_image_surface_cache_usage();
95 rv = MOZ_COLLECT_REPORT(
96 "gfx-d2d-surface-cache", KIND_OTHER, UNITS_BYTES, amount,
97 "Memory used by the Direct2D internal surface cache.");
98 NS_ENSURE_SUCCESS(rv, rv);
100 cairo_device_t *device =
101 gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
102 amount = device ? cairo_d2d_get_surface_vram_usage(device) : 0;
103 rv = MOZ_COLLECT_REPORT(
104 "gfx-d2d-surface-vram", KIND_OTHER, UNITS_BYTES, amount,
105 "Video memory used by D2D surfaces.");
106 NS_ENSURE_SUCCESS(rv, rv);
108 return NS_OK;
109 }
110 };
112 NS_IMPL_ISUPPORTS(GfxD2DSurfaceReporter, nsIMemoryReporter)
114 #endif
116 class GfxD2DVramReporter MOZ_FINAL : public nsIMemoryReporter
117 {
118 public:
119 NS_DECL_ISUPPORTS
121 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
122 nsISupports* aData)
123 {
124 nsresult rv;
126 rv = MOZ_COLLECT_REPORT(
127 "gfx-d2d-vram-draw-target", KIND_OTHER, UNITS_BYTES,
128 Factory::GetD2DVRAMUsageDrawTarget(),
129 "Video memory used by D2D DrawTargets.");
130 NS_ENSURE_SUCCESS(rv, rv);
132 rv = MOZ_COLLECT_REPORT(
133 "gfx-d2d-vram-source-surface", KIND_OTHER, UNITS_BYTES,
134 Factory::GetD2DVRAMUsageSourceSurface(),
135 "Video memory used by D2D SourceSurfaces.");
136 NS_ENSURE_SUCCESS(rv, rv);
138 return NS_OK;
139 }
140 };
142 NS_IMPL_ISUPPORTS(GfxD2DVramReporter, nsIMemoryReporter)
144 #define GFX_USE_CLEARTYPE_ALWAYS "gfx.font_rendering.cleartype.always_use_for_content"
145 #define GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE "gfx.font_rendering.cleartype.use_for_downloadable_fonts"
147 #define GFX_CLEARTYPE_PARAMS "gfx.font_rendering.cleartype_params."
148 #define GFX_CLEARTYPE_PARAMS_GAMMA "gfx.font_rendering.cleartype_params.gamma"
149 #define GFX_CLEARTYPE_PARAMS_CONTRAST "gfx.font_rendering.cleartype_params.enhanced_contrast"
150 #define GFX_CLEARTYPE_PARAMS_LEVEL "gfx.font_rendering.cleartype_params.cleartype_level"
151 #define GFX_CLEARTYPE_PARAMS_STRUCTURE "gfx.font_rendering.cleartype_params.pixel_structure"
152 #define GFX_CLEARTYPE_PARAMS_MODE "gfx.font_rendering.cleartype_params.rendering_mode"
154 class GPUAdapterReporter : public nsIMemoryReporter
155 {
156 // Callers must Release the DXGIAdapter after use or risk mem-leak
157 static bool GetDXGIAdapter(IDXGIAdapter **DXGIAdapter)
158 {
159 ID3D10Device1 *D2D10Device;
160 IDXGIDevice *DXGIDevice;
161 bool result = false;
163 if (D2D10Device = mozilla::gfx::Factory::GetDirect3D10Device()) {
164 if (D2D10Device->QueryInterface(__uuidof(IDXGIDevice), (void **)&DXGIDevice) == S_OK) {
165 result = (DXGIDevice->GetAdapter(DXGIAdapter) == S_OK);
166 DXGIDevice->Release();
167 }
168 }
170 return result;
171 }
173 public:
174 NS_DECL_ISUPPORTS
176 NS_IMETHOD
177 CollectReports(nsIMemoryReporterCallback* aCb,
178 nsISupports* aClosure)
179 {
180 HANDLE ProcessHandle = GetCurrentProcess();
182 int64_t dedicatedBytesUsed = 0;
183 int64_t sharedBytesUsed = 0;
184 int64_t committedBytesUsed = 0;
185 IDXGIAdapter *DXGIAdapter;
187 HMODULE gdi32Handle;
188 PFND3DKMTQS queryD3DKMTStatistics;
190 // GPU memory reporting is not available before Windows 7
191 if (!IsWin7OrLater())
192 return NS_OK;
194 if (gdi32Handle = LoadLibrary(TEXT("gdi32.dll")))
195 queryD3DKMTStatistics = (PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
197 if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) {
198 // Most of this block is understood thanks to wj32's work on Process Hacker
200 DXGI_ADAPTER_DESC adapterDesc;
201 D3DKMTQS queryStatistics;
203 DXGIAdapter->GetDesc(&adapterDesc);
204 DXGIAdapter->Release();
206 memset(&queryStatistics, 0, sizeof(D3DKMTQS));
207 queryStatistics.Type = D3DKMTQS_PROCESS;
208 queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
209 queryStatistics.hProcess = ProcessHandle;
210 if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
211 committedBytesUsed = queryStatistics.QueryResult.ProcessInfo.SystemMemory.BytesAllocated;
212 }
214 memset(&queryStatistics, 0, sizeof(D3DKMTQS));
215 queryStatistics.Type = D3DKMTQS_ADAPTER;
216 queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
217 if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
218 ULONG i;
219 ULONG segmentCount = queryStatistics.QueryResult.AdapterInfo.NbSegments;
221 for (i = 0; i < segmentCount; i++) {
222 memset(&queryStatistics, 0, sizeof(D3DKMTQS));
223 queryStatistics.Type = D3DKMTQS_SEGMENT;
224 queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
225 queryStatistics.QuerySegment.SegmentId = i;
227 if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
228 bool aperture;
230 // SegmentInformation has a different definition in Win7 than later versions
231 if (!IsWin8OrLater())
232 aperture = queryStatistics.QueryResult.SegmentInfoWin7.Aperture;
233 else
234 aperture = queryStatistics.QueryResult.SegmentInfoWin8.Aperture;
236 memset(&queryStatistics, 0, sizeof(D3DKMTQS));
237 queryStatistics.Type = D3DKMTQS_PROCESS_SEGMENT;
238 queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
239 queryStatistics.hProcess = ProcessHandle;
240 queryStatistics.QueryProcessSegment.SegmentId = i;
241 if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
242 ULONGLONG bytesCommitted;
243 if (!IsWin8OrLater())
244 bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo.Win7.BytesCommitted;
245 else
246 bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo.Win8.BytesCommitted;
247 if (aperture)
248 sharedBytesUsed += bytesCommitted;
249 else
250 dedicatedBytesUsed += bytesCommitted;
251 }
252 }
253 }
254 }
255 }
257 FreeLibrary(gdi32Handle);
259 #define REPORT(_path, _amount, _desc) \
260 do { \
261 nsresult rv; \
262 rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
263 KIND_OTHER, UNITS_BYTES, _amount, \
264 NS_LITERAL_CSTRING(_desc), aClosure); \
265 NS_ENSURE_SUCCESS(rv, rv); \
266 } while (0)
268 REPORT("gpu-committed", committedBytesUsed,
269 "Memory committed by the Windows graphics system.");
271 REPORT("gpu-dedicated", dedicatedBytesUsed,
272 "Out-of-process memory allocated for this process in a "
273 "physical GPU adapter's memory.");
275 REPORT("gpu-shared", sharedBytesUsed,
276 "In-process memory that is shared with the GPU.");
278 #undef REPORT
280 return NS_OK;
281 }
282 };
284 NS_IMPL_ISUPPORTS(GPUAdapterReporter, nsIMemoryReporter)
286 static __inline void
287 BuildKeyNameFromFontName(nsAString &aName)
288 {
289 if (aName.Length() >= LF_FACESIZE)
290 aName.Truncate(LF_FACESIZE - 1);
291 ToLowerCase(aName);
292 }
294 gfxWindowsPlatform::gfxWindowsPlatform()
295 : mD3D11DeviceInitialized(false)
296 , mPrefFonts(50)
297 {
298 mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
299 mUseClearTypeAlways = UNINITIALIZED_VALUE;
301 mUsingGDIFonts = false;
303 /*
304 * Initialize COM
305 */
306 CoInitialize(nullptr);
308 #ifdef CAIRO_HAS_D2D_SURFACE
309 RegisterStrongMemoryReporter(new GfxD2DSurfaceReporter());
310 mD2DDevice = nullptr;
311 #endif
312 RegisterStrongMemoryReporter(new GfxD2DVramReporter());
314 UpdateRenderMode();
316 RegisterStrongMemoryReporter(new GPUAdapterReporter());
317 }
319 gfxWindowsPlatform::~gfxWindowsPlatform()
320 {
321 mDeviceManager = nullptr;
323 // not calling FT_Done_FreeType because cairo may still hold references to
324 // these FT_Faces. See bug 458169.
325 #ifdef CAIRO_HAS_D2D_SURFACE
326 if (mD2DDevice) {
327 cairo_release_device(mD2DDevice);
328 }
329 #endif
331 mozilla::gfx::Factory::D2DCleanup();
333 /*
334 * Uninitialize COM
335 */
336 CoUninitialize();
337 }
339 double
340 gfxWindowsPlatform::GetDPIScale()
341 {
342 return WinUtils::LogToPhysFactor();
343 }
345 void
346 gfxWindowsPlatform::UpdateRenderMode()
347 {
348 /* Pick the default render mode for
349 * desktop.
350 */
351 mRenderMode = RENDER_GDI;
353 bool isVistaOrHigher = IsVistaOrLater();
355 bool safeMode = false;
356 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
357 if (xr)
358 xr->GetInSafeMode(&safeMode);
360 mUseDirectWrite = Preferences::GetBool("gfx.font_rendering.directwrite.enabled", false);
362 #ifdef CAIRO_HAS_D2D_SURFACE
363 bool d2dDisabled = false;
364 bool d2dForceEnabled = false;
365 bool d2dBlocked = false;
367 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
368 if (gfxInfo) {
369 int32_t status;
370 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
371 if (status != nsIGfxInfo::FEATURE_NO_INFO) {
372 d2dBlocked = true;
373 }
374 }
375 }
377 // These will only be evaluated once, and any subsequent changes to
378 // the preferences will be ignored until restart.
379 d2dDisabled = gfxPrefs::Direct2DDisabled();
380 d2dForceEnabled = gfxPrefs::Direct2DForceEnabled();
382 bool tryD2D = d2dForceEnabled || (!d2dBlocked && !gfxPrefs::LayersPreferD3D9());
384 // Do not ever try if d2d is explicitly disabled,
385 // or if we're not using DWrite fonts.
386 if (d2dDisabled || mUsingGDIFonts) {
387 tryD2D = false;
388 }
390 if (isVistaOrHigher && !safeMode && tryD2D) {
391 VerifyD2DDevice(d2dForceEnabled);
392 if (mD2DDevice) {
393 mRenderMode = RENDER_DIRECT2D;
394 mUseDirectWrite = true;
395 }
396 } else {
397 mD2DDevice = nullptr;
398 }
399 #endif
401 #ifdef CAIRO_HAS_DWRITE_FONT
402 // Enable when it's preffed on -and- we're using Vista or higher. Or when
403 // we're going to use D2D.
404 if (!mDWriteFactory && (mUseDirectWrite && isVistaOrHigher)) {
405 mozilla::ScopedGfxFeatureReporter reporter("DWrite");
406 decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
407 GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
409 if (createDWriteFactory) {
410 /**
411 * I need a direct pointer to be able to cast to IUnknown**, I also
412 * need to remember to release this because the nsRefPtr will
413 * AddRef it.
414 */
415 IDWriteFactory *factory;
416 HRESULT hr = createDWriteFactory(
417 DWRITE_FACTORY_TYPE_SHARED,
418 __uuidof(IDWriteFactory),
419 reinterpret_cast<IUnknown**>(&factory));
421 if (SUCCEEDED(hr) && factory) {
422 mDWriteFactory = factory;
423 factory->Release();
424 hr = mDWriteFactory->CreateTextAnalyzer(
425 getter_AddRefs(mDWriteAnalyzer));
426 }
428 SetupClearTypeParams();
430 if (hr == S_OK)
431 reporter.SetSuccessful();
432 }
433 }
434 #endif
436 uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
437 uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
438 BackendType defaultBackend = BackendType::CAIRO;
439 if (mRenderMode == RENDER_DIRECT2D) {
440 canvasMask |= BackendTypeBit(BackendType::DIRECT2D);
441 contentMask |= BackendTypeBit(BackendType::DIRECT2D);
442 defaultBackend = BackendType::DIRECT2D;
443 } else {
444 canvasMask |= BackendTypeBit(BackendType::SKIA);
445 }
446 contentMask |= BackendTypeBit(BackendType::SKIA);
447 InitBackendPrefs(canvasMask, defaultBackend,
448 contentMask, defaultBackend);
449 }
451 #ifdef CAIRO_HAS_D2D_SURFACE
452 HRESULT
453 gfxWindowsPlatform::CreateDevice(nsRefPtr<IDXGIAdapter1> &adapter1,
454 int featureLevelIndex)
455 {
456 nsModuleHandle d3d10module(LoadLibrarySystem32(L"d3d10_1.dll"));
457 if (!d3d10module)
458 return E_FAIL;
459 decltype(D3D10CreateDevice1)* createD3DDevice =
460 (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module, "D3D10CreateDevice1");
461 if (!createD3DDevice)
462 return E_FAIL;
464 nsRefPtr<ID3D10Device1> device;
465 HRESULT hr =
466 createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
467 D3D10_CREATE_DEVICE_BGRA_SUPPORT |
468 D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
469 static_cast<D3D10_FEATURE_LEVEL1>(kSupportedFeatureLevels[featureLevelIndex]),
470 D3D10_1_SDK_VERSION, getter_AddRefs(device));
472 // If we fail here, the DirectX version or video card probably
473 // changed. We previously could use 10.1 but now we can't
474 // anymore. Revert back to doing a 10.0 check first before
475 // the 10.1 check.
476 if (device) {
477 mD2DDevice = cairo_d2d_create_device_from_d3d10device(device);
479 // Setup a pref for future launch optimizaitons when in main process.
480 if (XRE_GetProcessType() == GeckoProcessType_Default) {
481 Preferences::SetInt(kFeatureLevelPref, featureLevelIndex);
482 }
483 }
485 return device ? S_OK : hr;
486 }
487 #endif
489 void
490 gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
491 {
492 #ifdef CAIRO_HAS_D2D_SURFACE
493 if (mD2DDevice) {
494 ID3D10Device1 *device = cairo_d2d_device_get_device(mD2DDevice);
496 if (SUCCEEDED(device->GetDeviceRemovedReason())) {
497 return;
498 }
499 mD2DDevice = nullptr;
501 // Surface cache needs to be invalidated since it may contain vector
502 // images rendered with our old, broken D2D device.
503 SurfaceCache::DiscardAll();
504 }
506 mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce);
508 nsRefPtr<ID3D10Device1> device;
510 int supportedFeatureLevelsCount = ArrayLength(kSupportedFeatureLevels);
511 // If we're not running in Metro don't allow DX9.3
512 if (!IsRunningInWindowsMetro()) {
513 supportedFeatureLevelsCount--;
514 }
516 nsRefPtr<IDXGIAdapter1> adapter1 = GetDXGIAdapter();
518 if (!adapter1) {
519 // Unable to create adapter, abort acceleration.
520 return;
521 }
523 // It takes a lot of time (5-10% of startup time or ~100ms) to do both
524 // a createD3DDevice on D3D10_FEATURE_LEVEL_10_0. We therefore store
525 // the last used feature level to go direct to that.
526 int featureLevelIndex = Preferences::GetInt(kFeatureLevelPref, 0);
527 if (featureLevelIndex >= supportedFeatureLevelsCount || featureLevelIndex < 0)
528 featureLevelIndex = 0;
530 // Start with the last used feature level, and move to lower DX versions
531 // until we find one that works.
532 HRESULT hr = E_FAIL;
533 for (int i = featureLevelIndex; i < supportedFeatureLevelsCount; i++) {
534 hr = CreateDevice(adapter1, i);
535 // If it succeeded we found the first available feature level
536 if (SUCCEEDED(hr))
537 break;
538 }
540 // If we succeeded in creating a device, try for a newer device
541 // that we haven't tried yet.
542 if (SUCCEEDED(hr)) {
543 for (int i = featureLevelIndex - 1; i >= 0; i--) {
544 hr = CreateDevice(adapter1, i);
545 // If it failed then we don't have new hardware
546 if (FAILED(hr)) {
547 break;
548 }
549 }
550 }
552 if (!mD2DDevice && aAttemptForce) {
553 mD2DDevice = cairo_d2d_create_device();
554 }
556 if (mD2DDevice) {
557 reporter.SetSuccessful();
558 mozilla::gfx::Factory::SetDirect3D10Device(cairo_d2d_device_get_device(mD2DDevice));
559 }
560 #endif
561 }
563 gfxPlatformFontList*
564 gfxWindowsPlatform::CreatePlatformFontList()
565 {
566 mUsingGDIFonts = false;
567 gfxPlatformFontList *pfl;
568 #ifdef CAIRO_HAS_DWRITE_FONT
569 // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd
570 // crashers so blacklist them altogether
571 if (IsNotWin7PreRTM() && GetDWriteFactory()) {
572 pfl = new gfxDWriteFontList();
573 if (NS_SUCCEEDED(pfl->InitFontList())) {
574 return pfl;
575 }
576 // DWrite font initialization failed! Don't know why this would happen,
577 // but apparently it can - see bug 594865.
578 // So we're going to fall back to GDI fonts & rendering.
579 gfxPlatformFontList::Shutdown();
580 SetRenderMode(RENDER_GDI);
581 }
582 #endif
583 pfl = new gfxGDIFontList();
584 mUsingGDIFonts = true;
586 if (NS_SUCCEEDED(pfl->InitFontList())) {
587 return pfl;
588 }
590 gfxPlatformFontList::Shutdown();
591 return nullptr;
592 }
594 already_AddRefed<gfxASurface>
595 gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& size,
596 gfxContentType contentType)
597 {
598 nsRefPtr<gfxASurface> surf = nullptr;
600 #ifdef CAIRO_HAS_WIN32_SURFACE
601 if (mRenderMode == RENDER_GDI)
602 surf = new gfxWindowsSurface(ThebesIntSize(size),
603 OptimalFormatForContent(contentType));
604 #endif
606 #ifdef CAIRO_HAS_D2D_SURFACE
607 if (mRenderMode == RENDER_DIRECT2D)
608 surf = new gfxD2DSurface(ThebesIntSize(size),
609 OptimalFormatForContent(contentType));
610 #endif
612 if (!surf || surf->CairoStatus()) {
613 surf = new gfxImageSurface(ThebesIntSize(size),
614 OptimalFormatForContent(contentType));
615 }
617 return surf.forget();
618 }
620 already_AddRefed<gfxASurface>
621 gfxWindowsPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize,
622 gfxContentType aContentType)
623 {
624 #ifdef CAIRO_HAS_D2D_SURFACE
625 if (mRenderMode == RENDER_DIRECT2D) {
626 nsRefPtr<gfxASurface> surface =
627 new gfxImageSurface(aSize, OptimalFormatForContent(aContentType));
628 return surface.forget();
629 }
630 #endif
632 nsRefPtr<gfxASurface> surface = CreateOffscreenSurface(aSize.ToIntSize(),
633 aContentType);
634 #ifdef DEBUG
635 nsRefPtr<gfxImageSurface> imageSurface = surface->GetAsImageSurface();
636 NS_ASSERTION(imageSurface, "Surface cannot be converted to a gfxImageSurface");
637 #endif
638 return surface.forget();
639 }
641 TemporaryRef<ScaledFont>
642 gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
643 {
644 if (aFont->GetType() == gfxFont::FONT_TYPE_DWRITE) {
645 gfxDWriteFont *font = static_cast<gfxDWriteFont*>(aFont);
647 NativeFont nativeFont;
648 nativeFont.mType = NativeFontType::DWRITE_FONT_FACE;
649 nativeFont.mFont = font->GetFontFace();
651 if (aTarget->GetType() == BackendType::CAIRO) {
652 return Factory::CreateScaledFontWithCairo(nativeFont,
653 font->GetAdjustedSize(),
654 font->GetCairoScaledFont());
655 }
657 return Factory::CreateScaledFontForNativeFont(nativeFont,
658 font->GetAdjustedSize());
659 }
661 NS_ASSERTION(aFont->GetType() == gfxFont::FONT_TYPE_GDI,
662 "Fonts on windows should be GDI or DWrite!");
664 NativeFont nativeFont;
665 nativeFont.mType = NativeFontType::GDI_FONT_FACE;
666 LOGFONT lf;
667 GetObject(static_cast<gfxGDIFont*>(aFont)->GetHFONT(), sizeof(LOGFONT), &lf);
668 nativeFont.mFont = &lf;
670 if (aTarget->GetType() == BackendType::CAIRO) {
671 return Factory::CreateScaledFontWithCairo(nativeFont,
672 aFont->GetAdjustedSize(),
673 aFont->GetCairoScaledFont());
674 }
676 return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
677 }
679 already_AddRefed<gfxASurface>
680 gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
681 {
682 #ifdef XP_WIN
683 if (aTarget->GetType() == BackendType::DIRECT2D) {
684 if (!GetD2DDevice()) {
685 // We no longer have a D2D device, can't do this.
686 return nullptr;
687 }
689 RefPtr<ID3D10Texture2D> texture =
690 static_cast<ID3D10Texture2D*>(aTarget->GetNativeSurface(NativeSurfaceType::D3D10_TEXTURE));
692 if (!texture) {
693 return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
694 }
696 aTarget->Flush();
698 nsRefPtr<gfxASurface> surf =
699 new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat()));
701 // shouldn't this hold a reference?
702 surf->SetData(&kDrawTarget, aTarget, nullptr);
703 return surf.forget();
704 }
705 #endif
707 return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
708 }
710 nsresult
711 gfxWindowsPlatform::GetFontList(nsIAtom *aLangGroup,
712 const nsACString& aGenericFamily,
713 nsTArray<nsString>& aListOfFonts)
714 {
715 gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts);
717 return NS_OK;
718 }
720 static void
721 RemoveCharsetFromFontSubstitute(nsAString &aName)
722 {
723 int32_t comma = aName.FindChar(char16_t(','));
724 if (comma >= 0)
725 aName.Truncate(comma);
726 }
728 nsresult
729 gfxWindowsPlatform::UpdateFontList()
730 {
731 gfxPlatformFontList::PlatformFontList()->UpdateFontList();
733 return NS_OK;
734 }
736 static const char kFontAparajita[] = "Aparajita";
737 static const char kFontArabicTypesetting[] = "Arabic Typesetting";
738 static const char kFontArial[] = "Arial";
739 static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
740 static const char kFontCambria[] = "Cambria";
741 static const char kFontCambriaMath[] = "Cambria Math";
742 static const char kFontEbrima[] = "Ebrima";
743 static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa";
744 static const char kFontEuphemia[] = "Euphemia";
745 static const char kFontGabriola[] = "Gabriola";
746 static const char kFontJavaneseText[] = "Javanese Text";
747 static const char kFontKhmerUI[] = "Khmer UI";
748 static const char kFontLaoUI[] = "Lao UI";
749 static const char kFontLeelawadeeUI[] = "Leelawadee UI";
750 static const char kFontLucidaSansUnicode[] = "Lucida Sans Unicode";
751 static const char kFontMVBoli[] = "MV Boli";
752 static const char kFontMalgunGothic[] = "Malgun Gothic";
753 static const char kFontMicrosoftJhengHei[] = "Microsoft JhengHei";
754 static const char kFontMicrosoftNewTaiLue[] = "Microsoft New Tai Lue";
755 static const char kFontMicrosoftPhagsPa[] = "Microsoft PhagsPa";
756 static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le";
757 static const char kFontMicrosoftUighur[] = "Microsoft Uighur";
758 static const char kFontMicrosoftYaHei[] = "Microsoft YaHei";
759 static const char kFontMicrosoftYiBaiti[] = "Microsoft Yi Baiti";
760 static const char kFontMeiryo[] = "Meiryo";
761 static const char kFontMongolianBaiti[] = "Mongolian Baiti";
762 static const char kFontMyanmarText[] = "Myanmar Text";
763 static const char kFontNirmalaUI[] = "Nirmala UI";
764 static const char kFontNyala[] = "Nyala";
765 static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
766 static const char kFontSegoeUI[] = "Segoe UI";
767 static const char kFontSegoeUISymbol[] = "Segoe UI Symbol";
768 static const char kFontSylfaen[] = "Sylfaen";
769 static const char kFontTraditionalArabic[] = "Traditional Arabic";
770 static const char kFontUtsaah[] = "Utsaah";
771 static const char kFontYuGothic[] = "Yu Gothic";
773 void
774 gfxWindowsPlatform::GetCommonFallbackFonts(const uint32_t aCh,
775 int32_t aRunScript,
776 nsTArray<const char*>& aFontList)
777 {
778 // Arial is used as the default fallback for system fallback
779 aFontList.AppendElement(kFontArial);
781 if (!IS_IN_BMP(aCh)) {
782 uint32_t p = aCh >> 16;
783 if (p == 1) { // SMP plane
784 aFontList.AppendElement(kFontSegoeUISymbol);
785 aFontList.AppendElement(kFontEbrima);
786 aFontList.AppendElement(kFontNirmalaUI);
787 aFontList.AppendElement(kFontCambriaMath);
788 }
789 } else {
790 uint32_t b = (aCh >> 8) & 0xff;
792 switch (b) {
793 case 0x05:
794 aFontList.AppendElement(kFontEstrangeloEdessa);
795 aFontList.AppendElement(kFontCambria);
796 break;
797 case 0x06:
798 aFontList.AppendElement(kFontMicrosoftUighur);
799 break;
800 case 0x07:
801 aFontList.AppendElement(kFontEstrangeloEdessa);
802 aFontList.AppendElement(kFontMVBoli);
803 aFontList.AppendElement(kFontEbrima);
804 break;
805 case 0x09:
806 aFontList.AppendElement(kFontNirmalaUI);
807 aFontList.AppendElement(kFontUtsaah);
808 aFontList.AppendElement(kFontAparajita);
809 break;
810 case 0x0e:
811 aFontList.AppendElement(kFontLaoUI);
812 break;
813 case 0x10:
814 aFontList.AppendElement(kFontMyanmarText);
815 break;
816 case 0x11:
817 aFontList.AppendElement(kFontMalgunGothic);
818 break;
819 case 0x12:
820 case 0x13:
821 aFontList.AppendElement(kFontNyala);
822 aFontList.AppendElement(kFontPlantagenetCherokee);
823 break;
824 case 0x14:
825 case 0x15:
826 case 0x16:
827 aFontList.AppendElement(kFontEuphemia);
828 aFontList.AppendElement(kFontSegoeUISymbol);
829 break;
830 case 0x17:
831 aFontList.AppendElement(kFontKhmerUI);
832 break;
833 case 0x18: // Mongolian
834 aFontList.AppendElement(kFontMongolianBaiti);
835 aFontList.AppendElement(kFontEuphemia);
836 break;
837 case 0x19:
838 aFontList.AppendElement(kFontMicrosoftTaiLe);
839 aFontList.AppendElement(kFontMicrosoftNewTaiLue);
840 aFontList.AppendElement(kFontKhmerUI);
841 break;
842 break;
843 case 0x1a:
844 aFontList.AppendElement(kFontLeelawadeeUI);
845 break;
846 case 0x1c:
847 aFontList.AppendElement(kFontNirmalaUI);
848 break;
849 case 0x20: // Symbol ranges
850 case 0x21:
851 case 0x22:
852 case 0x23:
853 case 0x24:
854 case 0x25:
855 case 0x26:
856 case 0x27:
857 case 0x29:
858 case 0x2a:
859 case 0x2b:
860 case 0x2c:
861 aFontList.AppendElement(kFontSegoeUI);
862 aFontList.AppendElement(kFontSegoeUISymbol);
863 aFontList.AppendElement(kFontCambria);
864 aFontList.AppendElement(kFontMeiryo);
865 aFontList.AppendElement(kFontArial);
866 aFontList.AppendElement(kFontLucidaSansUnicode);
867 aFontList.AppendElement(kFontEbrima);
868 break;
869 case 0x2d:
870 case 0x2e:
871 case 0x2f:
872 aFontList.AppendElement(kFontEbrima);
873 aFontList.AppendElement(kFontNyala);
874 aFontList.AppendElement(kFontSegoeUI);
875 aFontList.AppendElement(kFontSegoeUISymbol);
876 aFontList.AppendElement(kFontMeiryo);
877 break;
878 case 0x28: // Braille
879 aFontList.AppendElement(kFontSegoeUISymbol);
880 break;
881 case 0x30:
882 case 0x31:
883 aFontList.AppendElement(kFontMicrosoftYaHei);
884 break;
885 case 0x32:
886 aFontList.AppendElement(kFontMalgunGothic);
887 break;
888 case 0x4d:
889 aFontList.AppendElement(kFontSegoeUISymbol);
890 break;
891 case 0x9f:
892 aFontList.AppendElement(kFontMicrosoftYaHei);
893 aFontList.AppendElement(kFontYuGothic);
894 break;
895 case 0xa0: // Yi
896 case 0xa1:
897 case 0xa2:
898 case 0xa3:
899 case 0xa4:
900 aFontList.AppendElement(kFontMicrosoftYiBaiti);
901 aFontList.AppendElement(kFontSegoeUI);
902 break;
903 case 0xa5:
904 case 0xa6:
905 case 0xa7:
906 aFontList.AppendElement(kFontEbrima);
907 aFontList.AppendElement(kFontSegoeUI);
908 aFontList.AppendElement(kFontCambriaMath);
909 break;
910 case 0xa8:
911 aFontList.AppendElement(kFontMicrosoftPhagsPa);
912 aFontList.AppendElement(kFontNirmalaUI);
913 break;
914 case 0xa9:
915 aFontList.AppendElement(kFontMalgunGothic);
916 aFontList.AppendElement(kFontJavaneseText);
917 break;
918 case 0xaa:
919 aFontList.AppendElement(kFontMyanmarText);
920 break;
921 case 0xab:
922 aFontList.AppendElement(kFontEbrima);
923 aFontList.AppendElement(kFontNyala);
924 break;
925 case 0xd7:
926 aFontList.AppendElement(kFontMalgunGothic);
927 break;
928 case 0xfb:
929 aFontList.AppendElement(kFontMicrosoftUighur);
930 aFontList.AppendElement(kFontGabriola);
931 aFontList.AppendElement(kFontSylfaen);
932 break;
933 case 0xfc:
934 case 0xfd:
935 aFontList.AppendElement(kFontTraditionalArabic);
936 aFontList.AppendElement(kFontArabicTypesetting);
937 break;
938 case 0xfe:
939 aFontList.AppendElement(kFontTraditionalArabic);
940 aFontList.AppendElement(kFontMicrosoftJhengHei);
941 break;
942 case 0xff:
943 aFontList.AppendElement(kFontMicrosoftJhengHei);
944 break;
945 default:
946 break;
947 }
948 }
950 // Arial Unicode MS has lots of glyphs for obscure characters,
951 // use it as a last resort
952 aFontList.AppendElement(kFontArialUnicodeMS);
953 }
955 struct ResolveData {
956 ResolveData(gfxPlatform::FontResolverCallback aCallback,
957 gfxWindowsPlatform *aCaller, const nsAString *aFontName,
958 void *aClosure) :
959 mFoundCount(0), mCallback(aCallback), mCaller(aCaller),
960 mFontName(aFontName), mClosure(aClosure) {}
961 uint32_t mFoundCount;
962 gfxPlatform::FontResolverCallback mCallback;
963 gfxWindowsPlatform *mCaller;
964 const nsAString *mFontName;
965 void *mClosure;
966 };
968 nsresult
969 gfxWindowsPlatform::ResolveFontName(const nsAString& aFontName,
970 FontResolverCallback aCallback,
971 void *aClosure,
972 bool& aAborted)
973 {
974 nsAutoString resolvedName;
975 if (!gfxPlatformFontList::PlatformFontList()->
976 ResolveFontName(aFontName, resolvedName)) {
977 aAborted = false;
978 return NS_OK;
979 }
980 aAborted = !(*aCallback)(resolvedName, aClosure);
981 return NS_OK;
982 }
984 nsresult
985 gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
986 {
987 gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
988 return NS_OK;
989 }
991 gfxFontGroup *
992 gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
993 const gfxFontStyle *aStyle,
994 gfxUserFontSet *aUserFontSet)
995 {
996 return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
997 }
999 gfxFontEntry*
1000 gfxWindowsPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
1001 const nsAString& aFontName)
1002 {
1003 return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry,
1004 aFontName);
1005 }
1007 gfxFontEntry*
1008 gfxWindowsPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
1009 const uint8_t *aFontData, uint32_t aLength)
1010 {
1011 return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
1012 aFontData,
1013 aLength);
1014 }
1016 bool
1017 gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
1018 {
1019 // check for strange format flags
1020 NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
1021 "strange font format hint set");
1023 // accept supported formats
1024 if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF |
1025 gfxUserFontSet::FLAG_FORMAT_OPENTYPE |
1026 gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
1027 return true;
1028 }
1030 // reject all other formats, known and unknown
1031 if (aFormatFlags != 0) {
1032 return false;
1033 }
1035 // no format hint set, need to look at data
1036 return true;
1037 }
1039 gfxFontFamily *
1040 gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
1041 {
1042 return gfxPlatformFontList::PlatformFontList()->FindFamily(aName);
1043 }
1045 gfxFontEntry *
1046 gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
1047 {
1048 nsRefPtr<gfxFontFamily> ff = FindFontFamily(aName);
1049 if (!ff)
1050 return nullptr;
1052 bool aNeedsBold;
1053 return ff->FindFontForStyle(aFontStyle, aNeedsBold);
1054 }
1056 void
1057 gfxWindowsPlatform::GetPlatformCMSOutputProfile(void* &mem, size_t &mem_size)
1058 {
1059 WCHAR str[MAX_PATH];
1060 DWORD size = MAX_PATH;
1061 BOOL res;
1063 mem = nullptr;
1064 mem_size = 0;
1066 HDC dc = GetDC(nullptr);
1067 if (!dc)
1068 return;
1070 #if _MSC_VER
1071 __try {
1072 res = GetICMProfileW(dc, &size, (LPWSTR)&str);
1073 } __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) {
1074 res = FALSE;
1075 }
1076 #else
1077 res = GetICMProfileW(dc, &size, (LPWSTR)&str);
1078 #endif
1080 ReleaseDC(nullptr, dc);
1081 if (!res)
1082 return;
1084 #ifdef _WIN32
1085 qcms_data_from_unicode_path(str, &mem, &mem_size);
1087 #ifdef DEBUG_tor
1088 if (mem_size > 0)
1089 fprintf(stderr,
1090 "ICM profile read from %s successfully\n",
1091 NS_ConvertUTF16toUTF8(str).get());
1092 #endif // DEBUG_tor
1093 #endif // _WIN32
1094 }
1096 bool
1097 gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> > *array)
1098 {
1099 return mPrefFonts.Get(aKey, array);
1100 }
1102 void
1103 gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> >& array)
1104 {
1105 mPrefFonts.Put(aKey, array);
1106 }
1108 bool
1109 gfxWindowsPlatform::UseClearTypeForDownloadableFonts()
1110 {
1111 if (mUseClearTypeForDownloadableFonts == UNINITIALIZED_VALUE) {
1112 mUseClearTypeForDownloadableFonts = Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, true);
1113 }
1115 return mUseClearTypeForDownloadableFonts;
1116 }
1118 bool
1119 gfxWindowsPlatform::UseClearTypeAlways()
1120 {
1121 if (mUseClearTypeAlways == UNINITIALIZED_VALUE) {
1122 mUseClearTypeAlways = Preferences::GetBool(GFX_USE_CLEARTYPE_ALWAYS, false);
1123 }
1125 return mUseClearTypeAlways;
1126 }
1128 void
1129 gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath, nsAString& aVersion)
1130 {
1131 DWORD versInfoSize, vers[4] = {0};
1132 // version info not available case
1133 aVersion.Assign(NS_LITERAL_STRING("0.0.0.0"));
1134 versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr);
1135 nsAutoTArray<BYTE,512> versionInfo;
1137 if (versInfoSize == 0 ||
1138 !versionInfo.AppendElements(uint32_t(versInfoSize)))
1139 {
1140 return;
1141 }
1143 if (!GetFileVersionInfoW(aDLLPath, 0, versInfoSize,
1144 LPBYTE(versionInfo.Elements())))
1145 {
1146 return;
1147 }
1149 UINT len = 0;
1150 VS_FIXEDFILEINFO *fileInfo = nullptr;
1151 if (!VerQueryValue(LPBYTE(versionInfo.Elements()), TEXT("\\"),
1152 (LPVOID *)&fileInfo, &len) ||
1153 len == 0 ||
1154 fileInfo == nullptr)
1155 {
1156 return;
1157 }
1159 DWORD fileVersMS = fileInfo->dwFileVersionMS;
1160 DWORD fileVersLS = fileInfo->dwFileVersionLS;
1162 vers[0] = HIWORD(fileVersMS);
1163 vers[1] = LOWORD(fileVersMS);
1164 vers[2] = HIWORD(fileVersLS);
1165 vers[3] = LOWORD(fileVersLS);
1167 char buf[256];
1168 sprintf(buf, "%d.%d.%d.%d", vers[0], vers[1], vers[2], vers[3]);
1169 aVersion.Assign(NS_ConvertUTF8toUTF16(buf));
1170 }
1172 void
1173 gfxWindowsPlatform::GetCleartypeParams(nsTArray<ClearTypeParameterInfo>& aParams)
1174 {
1175 HKEY hKey, subKey;
1176 DWORD i, rv, size, type;
1177 WCHAR displayName[256], subkeyName[256];
1179 aParams.Clear();
1181 // construct subkeys based on HKLM subkeys, assume they are same for HKCU
1182 rv = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1183 L"Software\\Microsoft\\Avalon.Graphics",
1184 0, KEY_READ, &hKey);
1186 if (rv != ERROR_SUCCESS) {
1187 return;
1188 }
1190 // enumerate over subkeys
1191 for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) {
1192 size = ArrayLength(displayName);
1193 rv = RegEnumKeyExW(hKey, i, displayName, &size,
1194 nullptr, nullptr, nullptr, nullptr);
1195 if (rv != ERROR_SUCCESS) {
1196 continue;
1197 }
1199 ClearTypeParameterInfo ctinfo;
1200 ctinfo.displayName.Assign(displayName);
1202 DWORD subrv, value;
1203 bool foundData = false;
1205 swprintf_s(subkeyName, ArrayLength(subkeyName),
1206 L"Software\\Microsoft\\Avalon.Graphics\\%s", displayName);
1208 // subkey for gamma, pixel structure
1209 subrv = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1210 subkeyName, 0, KEY_QUERY_VALUE, &subKey);
1212 if (subrv == ERROR_SUCCESS) {
1213 size = sizeof(value);
1214 subrv = RegQueryValueExW(subKey, L"GammaLevel", nullptr, &type,
1215 (LPBYTE)&value, &size);
1216 if (subrv == ERROR_SUCCESS && type == REG_DWORD) {
1217 foundData = true;
1218 ctinfo.gamma = value;
1219 }
1221 size = sizeof(value);
1222 subrv = RegQueryValueExW(subKey, L"PixelStructure", nullptr, &type,
1223 (LPBYTE)&value, &size);
1224 if (subrv == ERROR_SUCCESS && type == REG_DWORD) {
1225 foundData = true;
1226 ctinfo.pixelStructure = value;
1227 }
1229 RegCloseKey(subKey);
1230 }
1232 // subkey for cleartype level, enhanced contrast
1233 subrv = RegOpenKeyExW(HKEY_CURRENT_USER,
1234 subkeyName, 0, KEY_QUERY_VALUE, &subKey);
1236 if (subrv == ERROR_SUCCESS) {
1237 size = sizeof(value);
1238 subrv = RegQueryValueExW(subKey, L"ClearTypeLevel", nullptr, &type,
1239 (LPBYTE)&value, &size);
1240 if (subrv == ERROR_SUCCESS && type == REG_DWORD) {
1241 foundData = true;
1242 ctinfo.clearTypeLevel = value;
1243 }
1245 size = sizeof(value);
1246 subrv = RegQueryValueExW(subKey, L"EnhancedContrastLevel",
1247 nullptr, &type, (LPBYTE)&value, &size);
1248 if (subrv == ERROR_SUCCESS && type == REG_DWORD) {
1249 foundData = true;
1250 ctinfo.enhancedContrast = value;
1251 }
1253 RegCloseKey(subKey);
1254 }
1256 if (foundData) {
1257 aParams.AppendElement(ctinfo);
1258 }
1259 }
1261 RegCloseKey(hKey);
1262 }
1264 void
1265 gfxWindowsPlatform::FontsPrefsChanged(const char *aPref)
1266 {
1267 bool clearTextFontCaches = true;
1269 gfxPlatform::FontsPrefsChanged(aPref);
1271 if (!aPref) {
1272 mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
1273 mUseClearTypeAlways = UNINITIALIZED_VALUE;
1274 } else if (!strcmp(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, aPref)) {
1275 mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
1276 } else if (!strcmp(GFX_USE_CLEARTYPE_ALWAYS, aPref)) {
1277 mUseClearTypeAlways = UNINITIALIZED_VALUE;
1278 } else if (!strncmp(GFX_CLEARTYPE_PARAMS, aPref, strlen(GFX_CLEARTYPE_PARAMS))) {
1279 SetupClearTypeParams();
1280 } else {
1281 clearTextFontCaches = false;
1282 }
1284 if (clearTextFontCaches) {
1285 gfxFontCache *fc = gfxFontCache::GetCache();
1286 if (fc) {
1287 fc->Flush();
1288 }
1289 }
1290 }
1292 #define ENHANCED_CONTRAST_REGISTRY_KEY \
1293 HKEY_CURRENT_USER, "Software\\Microsoft\\Avalon.Graphics\\DISPLAY1\\EnhancedContrastLevel"
1295 void
1296 gfxWindowsPlatform::SetupClearTypeParams()
1297 {
1298 #if CAIRO_HAS_DWRITE_FONT
1299 if (GetDWriteFactory()) {
1300 // any missing prefs will default to invalid (-1) and be ignored;
1301 // out-of-range values will also be ignored
1302 FLOAT gamma = -1.0;
1303 FLOAT contrast = -1.0;
1304 FLOAT level = -1.0;
1305 int geometry = -1;
1306 int mode = -1;
1307 int32_t value;
1308 if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_GAMMA, &value))) {
1309 if (value >= 1000 && value <= 2200) {
1310 gamma = FLOAT(value / 1000.0);
1311 }
1312 }
1314 if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_CONTRAST, &value))) {
1315 if (value >= 0 && value <= 1000) {
1316 contrast = FLOAT(value / 100.0);
1317 }
1318 }
1320 if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_LEVEL, &value))) {
1321 if (value >= 0 && value <= 100) {
1322 level = FLOAT(value / 100.0);
1323 }
1324 }
1326 if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_STRUCTURE, &value))) {
1327 if (value >= 0 && value <= 2) {
1328 geometry = value;
1329 }
1330 }
1332 if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_MODE, &value))) {
1333 if (value >= 0 && value <= 5) {
1334 mode = value;
1335 }
1336 }
1338 cairo_dwrite_set_cleartype_params(gamma, contrast, level, geometry, mode);
1340 switch (mode) {
1341 case DWRITE_RENDERING_MODE_ALIASED:
1342 case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
1343 mMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
1344 break;
1345 case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
1346 mMeasuringMode = DWRITE_MEASURING_MODE_GDI_NATURAL;
1347 break;
1348 default:
1349 mMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
1350 break;
1351 }
1353 nsRefPtr<IDWriteRenderingParams> defaultRenderingParams;
1354 GetDWriteFactory()->CreateRenderingParams(getter_AddRefs(defaultRenderingParams));
1355 // For EnhancedContrast, we override the default if the user has not set it
1356 // in the registry (by using the ClearType Tuner).
1357 if (contrast >= 0.0 && contrast <= 10.0) {
1358 contrast = contrast;
1359 } else {
1360 HKEY hKey;
1361 if (RegOpenKeyExA(ENHANCED_CONTRAST_REGISTRY_KEY,
1362 0, KEY_READ, &hKey) == ERROR_SUCCESS)
1363 {
1364 contrast = defaultRenderingParams->GetEnhancedContrast();
1365 RegCloseKey(hKey);
1366 } else {
1367 contrast = 1.0;
1368 }
1369 }
1371 // For parameters that have not been explicitly set,
1372 // we copy values from default params (or our overridden value for contrast)
1373 if (gamma < 1.0 || gamma > 2.2) {
1374 gamma = defaultRenderingParams->GetGamma();
1375 }
1377 if (level < 0.0 || level > 1.0) {
1378 level = defaultRenderingParams->GetClearTypeLevel();
1379 }
1381 DWRITE_PIXEL_GEOMETRY dwriteGeometry =
1382 static_cast<DWRITE_PIXEL_GEOMETRY>(geometry);
1383 DWRITE_RENDERING_MODE renderMode =
1384 static_cast<DWRITE_RENDERING_MODE>(mode);
1386 if (dwriteGeometry < DWRITE_PIXEL_GEOMETRY_FLAT ||
1387 dwriteGeometry > DWRITE_PIXEL_GEOMETRY_BGR) {
1388 dwriteGeometry = defaultRenderingParams->GetPixelGeometry();
1389 }
1391 if (renderMode < DWRITE_RENDERING_MODE_DEFAULT ||
1392 renderMode > DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC) {
1393 renderMode = defaultRenderingParams->GetRenderingMode();
1394 }
1396 mRenderingParams[TEXT_RENDERING_NO_CLEARTYPE] = defaultRenderingParams;
1398 GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level,
1399 dwriteGeometry, renderMode,
1400 getter_AddRefs(mRenderingParams[TEXT_RENDERING_NORMAL]));
1402 GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level,
1403 dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
1404 getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]));
1405 }
1406 #endif
1407 }
1409 void
1410 gfxWindowsPlatform::OnDeviceManagerDestroy(DeviceManagerD3D9* aDeviceManager)
1411 {
1412 if (aDeviceManager == mDeviceManager) {
1413 mDeviceManager = nullptr;
1414 }
1415 }
1417 IDirect3DDevice9*
1418 gfxWindowsPlatform::GetD3D9Device()
1419 {
1420 DeviceManagerD3D9* manager = GetD3D9DeviceManager();
1421 return manager ? manager->device() : nullptr;
1422 }
1424 DeviceManagerD3D9*
1425 gfxWindowsPlatform::GetD3D9DeviceManager()
1426 {
1427 // We should only create the d3d9 device on the compositor thread
1428 // or we don't have a compositor thread.
1429 if (!mDeviceManager &&
1430 (CompositorParent::IsInCompositorThread() ||
1431 !CompositorParent::CompositorLoop())) {
1432 mDeviceManager = new DeviceManagerD3D9();
1433 if (!mDeviceManager->Init()) {
1434 NS_WARNING("Could not initialise device manager");
1435 mDeviceManager = nullptr;
1436 }
1437 }
1439 return mDeviceManager;
1440 }
1442 ID3D11Device*
1443 gfxWindowsPlatform::GetD3D11Device()
1444 {
1445 if (mD3D11DeviceInitialized) {
1446 return mD3D11Device;
1447 }
1449 mD3D11DeviceInitialized = true;
1451 nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll"));
1452 decltype(D3D11CreateDevice)* d3d11CreateDevice = (decltype(D3D11CreateDevice)*)
1453 GetProcAddress(d3d11Module, "D3D11CreateDevice");
1455 if (!d3d11CreateDevice) {
1456 return nullptr;
1457 }
1459 nsTArray<D3D_FEATURE_LEVEL> featureLevels;
1460 if (IsWin8OrLater()) {
1461 featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
1462 }
1463 featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
1464 featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
1465 featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
1466 featureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3);
1468 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
1470 if (!adapter) {
1471 return nullptr;
1472 }
1474 HRESULT hr = d3d11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
1475 D3D11_CREATE_DEVICE_BGRA_SUPPORT,
1476 featureLevels.Elements(), featureLevels.Length(),
1477 D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
1479 // We leak these everywhere and we need them our entire runtime anyway, let's
1480 // leak it here as well.
1481 d3d11Module.disown();
1483 return mD3D11Device;
1484 }
1486 bool
1487 gfxWindowsPlatform::IsOptimus()
1488 {
1489 return GetModuleHandleA("nvumdshim.dll");
1490 }
1492 int
1493 gfxWindowsPlatform::GetScreenDepth() const
1494 {
1495 // if the system doesn't have all displays with the same
1496 // pixel format, just return 24 and move on with life.
1497 if (!GetSystemMetrics(SM_SAMEDISPLAYFORMAT))
1498 return 24;
1500 HDC hdc = GetDC(nullptr);
1501 if (!hdc)
1502 return 24;
1504 int depth = GetDeviceCaps(hdc, BITSPIXEL) *
1505 GetDeviceCaps(hdc, PLANES);
1507 ReleaseDC(nullptr, hdc);
1509 return depth;
1510 }
1512 IDXGIAdapter1*
1513 gfxWindowsPlatform::GetDXGIAdapter()
1514 {
1515 if (mAdapter) {
1516 return mAdapter;
1517 }
1519 nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
1520 decltype(CreateDXGIFactory1)* createDXGIFactory1 = (decltype(CreateDXGIFactory1)*)
1521 GetProcAddress(dxgiModule, "CreateDXGIFactory1");
1523 // Try to use a DXGI 1.1 adapter in order to share resources
1524 // across processes.
1525 if (createDXGIFactory1) {
1526 nsRefPtr<IDXGIFactory1> factory1;
1527 HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1),
1528 getter_AddRefs(factory1));
1530 if (FAILED(hr) || !factory1) {
1531 // This seems to happen with some people running the iZ3D driver.
1532 // They won't get acceleration.
1533 return nullptr;
1534 }
1536 hr = factory1->EnumAdapters1(0, byRef(mAdapter));
1537 if (FAILED(hr)) {
1538 // We should return and not accelerate if we can't obtain
1539 // an adapter.
1540 return nullptr;
1541 }
1542 }
1544 // We leak this module everywhere, we might as well do so here as well.
1545 dxgiModule.disown();
1547 return mAdapter;
1548 }