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/. */
6 
7 #include "gfxWindowsPlatform.h"
8 
9 #include "cairo.h"
10 #include "mozilla/ArrayUtils.h"
11 
12 #include "gfxImageSurface.h"
13 #include "gfxWindowsSurface.h"
14 
15 #include "nsUnicharUtils.h"
16 
17 #include "mozilla/Preferences.h"
18 #include "mozilla/Services.h"
19 #include "mozilla/Sprintf.h"
20 #include "mozilla/WindowsVersion.h"
21 #include "nsIGfxInfo.h"
22 #include "nsServiceManagerUtils.h"
23 #include "nsTArray.h"
24 #include "mozilla/Telemetry.h"
25 #include "GeckoProfiler.h"
26 
27 #include "nsIWindowsRegKey.h"
28 #include "nsIFile.h"
29 #include "plbase64.h"
30 #include "nsIXULRuntime.h"
31 #include "imgLoader.h"
32 
33 #include "nsIGfxInfo.h"
34 
35 #include "gfxCrashReporterUtils.h"
36 
37 #include "gfxGDIFontList.h"
38 #include "gfxGDIFont.h"
39 
40 #include "mozilla/layers/CompositorThread.h"
41 #include "DeviceManagerD3D9.h"
42 #include "mozilla/layers/ReadbackManagerD3D11.h"
43 
44 #include "WinUtils.h"
45 
46 #include "gfxDWriteFontList.h"
47 #include "gfxDWriteFonts.h"
48 #include "gfxDWriteCommon.h"
49 #include <dwrite.h>
50 
51 #include "gfxTextRun.h"
52 #include "gfxUserFontSet.h"
53 #include "nsWindowsHelpers.h"
54 #include "gfx2DGlue.h"
55 
56 #include <string>
57 
58 #include <d3d10_1.h>
59 
60 #include "mozilla/gfx/2D.h"
61 
62 #include "nsMemory.h"
63 
64 #include <d3d11.h>
65 
66 #include "nsIMemoryReporter.h"
67 #include <winternl.h>
68 #include "d3dkmtQueryStatistics.h"
69 
70 #include "base/thread.h"
71 #include "gfxPrefs.h"
72 #include "gfxConfig.h"
73 #include "VsyncSource.h"
74 #include "DriverCrashGuard.h"
75 #include "mozilla/dom/ContentParent.h"
76 #include "mozilla/gfx/DeviceManagerDx.h"
77 #include "D3D11Checks.h"
78 
79 using namespace mozilla;
80 using namespace mozilla::gfx;
81 using namespace mozilla::layers;
82 using namespace mozilla::widget;
83 using namespace mozilla::image;
84 
GetDwriteRenderingParams(bool aGDI)85 IDWriteRenderingParams* GetDwriteRenderingParams(bool aGDI)
86 {
87   gfxWindowsPlatform::TextRenderingMode mode = aGDI ?
88     gfxWindowsPlatform::TEXT_RENDERING_GDI_CLASSIC :
89     gfxWindowsPlatform::TEXT_RENDERING_NORMAL;
90   return gfxWindowsPlatform::GetPlatform()->GetRenderingParams(mode);
91 }
92 
DCFromDrawTarget(DrawTarget & aDrawTarget)93 DCFromDrawTarget::DCFromDrawTarget(DrawTarget& aDrawTarget)
94 {
95   mDC = nullptr;
96   if (aDrawTarget.GetBackendType() == BackendType::CAIRO) {
97     cairo_t* ctx = static_cast<cairo_t*>
98       (aDrawTarget.GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));
99     if (ctx) {
100       cairo_surface_t* surf = cairo_get_group_target(ctx);
101       if (surf) {
102         cairo_surface_type_t surfaceType = cairo_surface_get_type(surf);
103         if (surfaceType == CAIRO_SURFACE_TYPE_WIN32 ||
104             surfaceType == CAIRO_SURFACE_TYPE_WIN32_PRINTING) {
105           mDC = cairo_win32_surface_get_dc(surf);
106           mNeedsRelease = false;
107           SaveDC(mDC);
108           cairo_scaled_font_t* scaled = cairo_get_scaled_font(ctx);
109           cairo_win32_scaled_font_select_font(scaled, mDC);
110         }
111       }
112     }
113   }
114 
115   if (!mDC) {
116     // Get the whole screen DC:
117     mDC = GetDC(nullptr);
118     SetGraphicsMode(mDC, GM_ADVANCED);
119     mNeedsRelease = true;
120   }
121 }
122 
123 class GfxD2DVramReporter final : public nsIMemoryReporter
124 {
~GfxD2DVramReporter()125     ~GfxD2DVramReporter() {}
126 
127 public:
128     NS_DECL_ISUPPORTS
129 
CollectReports(nsIHandleReportCallback * aHandleReport,nsISupports * aData,bool aAnonymize)130     NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
131                               nsISupports* aData, bool aAnonymize) override
132     {
133         MOZ_COLLECT_REPORT(
134             "gfx-d2d-vram-draw-target", KIND_OTHER, UNITS_BYTES,
135             Factory::GetD2DVRAMUsageDrawTarget(),
136             "Video memory used by D2D DrawTargets.");
137 
138         MOZ_COLLECT_REPORT(
139             "gfx-d2d-vram-source-surface", KIND_OTHER, UNITS_BYTES,
140             Factory::GetD2DVRAMUsageSourceSurface(),
141             "Video memory used by D2D SourceSurfaces.");
142 
143         return NS_OK;
144     }
145 };
146 
147 NS_IMPL_ISUPPORTS(GfxD2DVramReporter, nsIMemoryReporter)
148 
149 #define GFX_USE_CLEARTYPE_ALWAYS "gfx.font_rendering.cleartype.always_use_for_content"
150 #define GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE "gfx.font_rendering.cleartype.use_for_downloadable_fonts"
151 
152 #define GFX_CLEARTYPE_PARAMS           "gfx.font_rendering.cleartype_params."
153 #define GFX_CLEARTYPE_PARAMS_GAMMA     "gfx.font_rendering.cleartype_params.gamma"
154 #define GFX_CLEARTYPE_PARAMS_CONTRAST  "gfx.font_rendering.cleartype_params.enhanced_contrast"
155 #define GFX_CLEARTYPE_PARAMS_LEVEL     "gfx.font_rendering.cleartype_params.cleartype_level"
156 #define GFX_CLEARTYPE_PARAMS_STRUCTURE "gfx.font_rendering.cleartype_params.pixel_structure"
157 #define GFX_CLEARTYPE_PARAMS_MODE      "gfx.font_rendering.cleartype_params.rendering_mode"
158 
159 class GPUAdapterReporter final : public nsIMemoryReporter
160 {
161     // Callers must Release the DXGIAdapter after use or risk mem-leak
GetDXGIAdapter(IDXGIAdapter ** aDXGIAdapter)162     static bool GetDXGIAdapter(IDXGIAdapter **aDXGIAdapter)
163     {
164         ID3D11Device *d3d11Device;
165         IDXGIDevice *dxgiDevice;
166         bool result = false;
167 
168         if ((d3d11Device = mozilla::gfx::Factory::GetDirect3D11Device())) {
169             if (d3d11Device->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice) == S_OK) {
170                 result = (dxgiDevice->GetAdapter(aDXGIAdapter) == S_OK);
171                 dxgiDevice->Release();
172             }
173         }
174 
175         return result;
176     }
177 
~GPUAdapterReporter()178     ~GPUAdapterReporter() {}
179 
180 public:
181     NS_DECL_ISUPPORTS
182 
183     NS_IMETHOD
CollectReports(nsIHandleReportCallback * aHandleReport,nsISupports * aData,bool aAnonymize)184     CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
185                    bool aAnonymize) override
186     {
187         HANDLE ProcessHandle = GetCurrentProcess();
188 
189         int64_t dedicatedBytesUsed = 0;
190         int64_t sharedBytesUsed = 0;
191         int64_t committedBytesUsed = 0;
192         IDXGIAdapter *DXGIAdapter;
193 
194         HMODULE gdi32Handle;
195         PFND3DKMTQS queryD3DKMTStatistics = nullptr;
196 
197         // GPU memory reporting is not available before Windows 7
198         if (!IsWin7OrLater())
199             return NS_OK;
200 
201         if ((gdi32Handle = LoadLibrary(TEXT("gdi32.dll"))))
202             queryD3DKMTStatistics = (PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
203 
204         if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) {
205             // Most of this block is understood thanks to wj32's work on Process Hacker
206 
207             DXGI_ADAPTER_DESC adapterDesc;
208             D3DKMTQS queryStatistics;
209 
210             DXGIAdapter->GetDesc(&adapterDesc);
211             DXGIAdapter->Release();
212 
213             memset(&queryStatistics, 0, sizeof(D3DKMTQS));
214             queryStatistics.Type = D3DKMTQS_PROCESS;
215             queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
216             queryStatistics.hProcess = ProcessHandle;
217             if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
218                 committedBytesUsed = queryStatistics.QueryResult.ProcessInfo.SystemMemory.BytesAllocated;
219             }
220 
221             memset(&queryStatistics, 0, sizeof(D3DKMTQS));
222             queryStatistics.Type = D3DKMTQS_ADAPTER;
223             queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
224             if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
225                 ULONG i;
226                 ULONG segmentCount = queryStatistics.QueryResult.AdapterInfo.NbSegments;
227 
228                 for (i = 0; i < segmentCount; i++) {
229                     memset(&queryStatistics, 0, sizeof(D3DKMTQS));
230                     queryStatistics.Type = D3DKMTQS_SEGMENT;
231                     queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
232                     queryStatistics.QuerySegment.SegmentId = i;
233 
234                     if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
235                         bool aperture;
236 
237                         // SegmentInformation has a different definition in Win7 than later versions
238                         if (!IsWin8OrLater())
239                             aperture = queryStatistics.QueryResult.SegmentInfoWin7.Aperture;
240                         else
241                             aperture = queryStatistics.QueryResult.SegmentInfoWin8.Aperture;
242 
243                         memset(&queryStatistics, 0, sizeof(D3DKMTQS));
244                         queryStatistics.Type = D3DKMTQS_PROCESS_SEGMENT;
245                         queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
246                         queryStatistics.hProcess = ProcessHandle;
247                         queryStatistics.QueryProcessSegment.SegmentId = i;
248                         if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
249                             ULONGLONG bytesCommitted;
250                             if (!IsWin8OrLater())
251                                 bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo.Win7.BytesCommitted;
252                             else
253                                 bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo.Win8.BytesCommitted;
254                             if (aperture)
255                                 sharedBytesUsed += bytesCommitted;
256                             else
257                                 dedicatedBytesUsed += bytesCommitted;
258                         }
259                     }
260                 }
261             }
262         }
263 
264         FreeLibrary(gdi32Handle);
265 
266         MOZ_COLLECT_REPORT(
267             "gpu-committed", KIND_OTHER, UNITS_BYTES, committedBytesUsed,
268             "Memory committed by the Windows graphics system.");
269 
270         MOZ_COLLECT_REPORT(
271             "gpu-dedicated", KIND_OTHER, UNITS_BYTES,
272             dedicatedBytesUsed,
273             "Out-of-process memory allocated for this process in a physical "
274             "GPU adapter's memory.");
275 
276         MOZ_COLLECT_REPORT(
277             "gpu-shared", KIND_OTHER, UNITS_BYTES,
278             sharedBytesUsed,
279             "In-process memory that is shared with the GPU.");
280 
281         return NS_OK;
282     }
283 };
284 
285 NS_IMPL_ISUPPORTS(GPUAdapterReporter, nsIMemoryReporter)
286 
287 Atomic<size_t> gfxWindowsPlatform::sD3D11SharedTextures;
288 Atomic<size_t> gfxWindowsPlatform::sD3D9SharedTextures;
289 
290 class D3DSharedTexturesReporter final : public nsIMemoryReporter
291 {
~D3DSharedTexturesReporter()292   ~D3DSharedTexturesReporter() {}
293 
294 public:
295   NS_DECL_ISUPPORTS
296 
CollectReports(nsIHandleReportCallback * aHandleReport,nsISupports * aData,bool aAnonymize)297   NS_IMETHOD CollectReports(nsIHandleReportCallback *aHandleReport,
298                             nsISupports* aData, bool aAnonymize) override
299   {
300     if (gfxWindowsPlatform::sD3D11SharedTextures > 0) {
301       MOZ_COLLECT_REPORT(
302         "d3d11-shared-textures", KIND_OTHER, UNITS_BYTES,
303         gfxWindowsPlatform::sD3D11SharedTextures,
304         "D3D11 shared textures.");
305     }
306 
307     if (gfxWindowsPlatform::sD3D9SharedTextures > 0) {
308       MOZ_COLLECT_REPORT(
309         "d3d9-shared-textures", KIND_OTHER, UNITS_BYTES,
310         gfxWindowsPlatform::sD3D9SharedTextures,
311         "D3D9 shared textures.");
312     }
313 
314     return NS_OK;
315   }
316 };
317 
NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter,nsIMemoryReporter)318 NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter, nsIMemoryReporter)
319 
320 gfxWindowsPlatform::gfxWindowsPlatform()
321   : mRenderMode(RENDER_GDI)
322 {
323   mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
324   mUseClearTypeAlways = UNINITIALIZED_VALUE;
325 
326   /*
327    * Initialize COM
328    */
329   CoInitialize(nullptr);
330 
331   RegisterStrongMemoryReporter(new GfxD2DVramReporter());
332   RegisterStrongMemoryReporter(new GPUAdapterReporter());
333   RegisterStrongMemoryReporter(new D3DSharedTexturesReporter());
334 }
335 
~gfxWindowsPlatform()336 gfxWindowsPlatform::~gfxWindowsPlatform()
337 {
338   mozilla::gfx::Factory::D2DCleanup();
339 
340   DeviceManagerD3D9::Shutdown();
341   DeviceManagerDx::Shutdown();
342 
343   /*
344    * Uninitialize COM
345    */
346   CoUninitialize();
347 }
348 
349 static void
UpdateANGLEConfig()350 UpdateANGLEConfig()
351 {
352   if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
353     gfxConfig::Disable(Feature::D3D11_HW_ANGLE, FeatureStatus::Disabled, "D3D11 compositing is disabled");
354   }
355 }
356 
357 void
InitAcceleration()358 gfxWindowsPlatform::InitAcceleration()
359 {
360   gfxPlatform::InitAcceleration();
361 
362   // Set up the D3D11 feature levels we can ask for.
363   if (IsWin8OrLater()) {
364     mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
365   }
366   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
367   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
368   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
369   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3);
370 
371   DeviceManagerDx::Init();
372   DeviceManagerD3D9::Init();
373 
374   InitializeConfig();
375   InitializeDevices();
376   UpdateANGLEConfig();
377   UpdateRenderMode();
378 
379   // If we have Skia and we didn't init dwrite already, do it now.
380   if (!mDWriteFactory && GetDefaultContentBackend() == BackendType::SKIA) {
381     InitDWriteSupport();
382   }
383 
384   // CanUseHardwareVideoDecoding depends on DeviceManagerDx state,
385   // so update the cached value now.
386   UpdateCanUseHardwareVideoDecoding();
387 }
388 
389 bool
CanUseHardwareVideoDecoding()390 gfxWindowsPlatform::CanUseHardwareVideoDecoding()
391 {
392   DeviceManagerDx* dm = DeviceManagerDx::Get();
393   if (!dm) {
394     return false;
395   }
396   if (!gfxPrefs::LayersPreferD3D9() && !dm->TextureSharingWorks()) {
397     return false;
398   }
399   return !dm->IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding();
400 }
401 
402 bool
InitDWriteSupport()403 gfxWindowsPlatform::InitDWriteSupport()
404 {
405   if (!IsVistaOrLater()) {
406     return false;
407   }
408 
409   // DWrite is only supported on Windows 7 with the platform update and higher.
410   // We check this by seeing if D2D1 support is available.
411   if (!Factory::SupportsD2D1()) {
412     return false;
413   }
414 
415   mozilla::ScopedGfxFeatureReporter reporter("DWrite");
416   decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
417       GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
418   if (!createDWriteFactory) {
419     return false;
420   }
421 
422   // I need a direct pointer to be able to cast to IUnknown**, I also need to
423   // remember to release this because the nsRefPtr will AddRef it.
424   RefPtr<IDWriteFactory> factory;
425   HRESULT hr = createDWriteFactory(
426       DWRITE_FACTORY_TYPE_SHARED,
427       __uuidof(IDWriteFactory),
428       (IUnknown **)((IDWriteFactory **)getter_AddRefs(factory)));
429   if (FAILED(hr) || !factory) {
430     return false;
431   }
432 
433   mDWriteFactory = factory;
434   Factory::SetDWriteFactory(mDWriteFactory);
435 
436   SetupClearTypeParams();
437   reporter.SetSuccessful();
438   return true;
439 }
440 
441 bool
HandleDeviceReset()442 gfxWindowsPlatform::HandleDeviceReset()
443 {
444   DeviceResetReason resetReason = DeviceResetReason::OK;
445   if (!DidRenderingDeviceReset(&resetReason)) {
446     return false;
447   }
448 
449   if (resetReason != DeviceResetReason::FORCED_RESET) {
450     Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason));
451   }
452 
453   // Remove devices and adapters.
454   DeviceManagerDx::Get()->ResetDevices();
455 
456   imgLoader::NormalLoader()->ClearCache(true);
457   imgLoader::NormalLoader()->ClearCache(false);
458   imgLoader::PrivateBrowsingLoader()->ClearCache(true);
459   imgLoader::PrivateBrowsingLoader()->ClearCache(false);
460   gfxAlphaBoxBlur::ShutdownBlurCache();
461 
462   if (XRE_IsContentProcess()) {
463     // Fetch updated device parameters.
464     FetchAndImportContentDeviceData();
465     UpdateANGLEConfig();
466   }
467 
468   InitializeDevices();
469   UpdateANGLEConfig();
470   BumpDeviceCounter();
471   return true;
472 }
473 
474 void
UpdateBackendPrefs()475 gfxWindowsPlatform::UpdateBackendPrefs()
476 {
477   uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
478   uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
479   BackendType defaultBackend = BackendType::CAIRO;
480   if (gfxConfig::IsEnabled(Feature::DIRECT2D) && Factory::GetD2D1Device()) {
481     contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
482     canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
483     defaultBackend = BackendType::DIRECT2D1_1;
484   } else {
485     canvasMask |= BackendTypeBit(BackendType::SKIA);
486   }
487   contentMask |= BackendTypeBit(BackendType::SKIA);
488   InitBackendPrefs(canvasMask, defaultBackend, contentMask, defaultBackend);
489 }
490 
491 bool
IsDirect2DBackend()492 gfxWindowsPlatform::IsDirect2DBackend()
493 {
494   return GetDefaultContentBackend() == BackendType::DIRECT2D1_1;
495 }
496 
497 void
UpdateRenderMode()498 gfxWindowsPlatform::UpdateRenderMode()
499 {
500   bool didReset = HandleDeviceReset();
501 
502   UpdateBackendPrefs();
503 
504   if (didReset) {
505     mScreenReferenceDrawTarget =
506       CreateOffscreenContentDrawTarget(IntSize(1, 1), SurfaceFormat::B8G8R8A8);
507     if (!mScreenReferenceDrawTarget) {
508       gfxCriticalNote << "Failed to update reference draw target after device reset"
509                       << ", D3D11 device:" << hexa(Factory::GetDirect3D11Device())
510                       << ", D3D11 status:" << FeatureStatusToString(gfxConfig::GetValue(Feature::D3D11_COMPOSITING))
511                       << ", D2D1 device:" << hexa(Factory::GetD2D1Device())
512                       << ", D2D1 status:" << FeatureStatusToString(gfxConfig::GetValue(Feature::DIRECT2D))
513                       << ", content:" << int(GetDefaultContentBackend())
514                       << ", compositor:" << int(GetCompositorBackend());
515       MOZ_CRASH("GFX: Failed to update reference draw target after device reset");
516     }
517   }
518 }
519 
520 mozilla::gfx::BackendType
GetContentBackendFor(mozilla::layers::LayersBackend aLayers)521 gfxWindowsPlatform::GetContentBackendFor(mozilla::layers::LayersBackend aLayers)
522 {
523   mozilla::gfx::BackendType defaultBackend = gfxPlatform::GetDefaultContentBackend();
524   if (aLayers == LayersBackend::LAYERS_D3D11) {
525     return defaultBackend;
526   }
527 
528   if (defaultBackend == BackendType::DIRECT2D1_1) {
529     // We can't have D2D without D3D11 layers, so fallback to Cairo.
530     return BackendType::CAIRO;
531   }
532 
533   // Otherwise we have some non-accelerated backend and that's ok.
534   return defaultBackend;
535 }
536 
537 gfxPlatformFontList*
CreatePlatformFontList()538 gfxWindowsPlatform::CreatePlatformFontList()
539 {
540     gfxPlatformFontList *pfl;
541 
542     // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd
543     // crashers so blacklist them altogether
544     if (IsNotWin7PreRTM() && GetDWriteFactory()) {
545         pfl = new gfxDWriteFontList();
546         if (NS_SUCCEEDED(pfl->InitFontList())) {
547             return pfl;
548         }
549         // DWrite font initialization failed! Don't know why this would happen,
550         // but apparently it can - see bug 594865.
551         // So we're going to fall back to GDI fonts & rendering.
552         gfxPlatformFontList::Shutdown();
553         DisableD2D(FeatureStatus::Failed, "Failed to initialize fonts",
554                    NS_LITERAL_CSTRING("FEATURE_FAILURE_FONT_FAIL"));
555     }
556 
557     pfl = new gfxGDIFontList();
558 
559     if (NS_SUCCEEDED(pfl->InitFontList())) {
560         return pfl;
561     }
562 
563     gfxPlatformFontList::Shutdown();
564     return nullptr;
565 }
566 
567 // This function will permanently disable D2D for the session. It's intended to
568 // be used when, after initially chosing to use Direct2D, we encounter a
569 // scenario we can't support.
570 //
571 // This is called during gfxPlatform::Init() so at this point there should be no
572 // DrawTargetD2D/1 instances.
573 void
DisableD2D(FeatureStatus aStatus,const char * aMessage,const nsACString & aFailureId)574 gfxWindowsPlatform::DisableD2D(FeatureStatus aStatus, const char* aMessage,
575                                const nsACString& aFailureId)
576 {
577   gfxConfig::SetFailed(Feature::DIRECT2D, aStatus, aMessage, aFailureId);
578   Factory::SetDirect3D11Device(nullptr);
579   UpdateBackendPrefs();
580 }
581 
582 already_AddRefed<gfxASurface>
CreateOffscreenSurface(const IntSize & aSize,gfxImageFormat aFormat)583 gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& aSize,
584                                            gfxImageFormat aFormat)
585 {
586     if (!Factory::AllowedSurfaceSize(aSize)) {
587         return nullptr;
588     }
589 
590     RefPtr<gfxASurface> surf = nullptr;
591 
592 #ifdef CAIRO_HAS_WIN32_SURFACE
593     if (mRenderMode == RENDER_GDI || mRenderMode == RENDER_DIRECT2D)
594         surf = new gfxWindowsSurface(aSize, aFormat);
595 #endif
596 
597     if (!surf || surf->CairoStatus()) {
598         surf = new gfxImageSurface(aSize, aFormat);
599     }
600 
601     return surf.forget();
602 }
603 
604 already_AddRefed<ScaledFont>
GetScaledFontForFont(DrawTarget * aTarget,gfxFont * aFont)605 gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
606 {
607     if (aFont->GetType() == gfxFont::FONT_TYPE_DWRITE) {
608         gfxDWriteFont *font = static_cast<gfxDWriteFont*>(aFont);
609 
610         NativeFont nativeFont;
611         nativeFont.mType = NativeFontType::DWRITE_FONT_FACE;
612         nativeFont.mFont = font->GetFontFace();
613 
614         if (aTarget->GetBackendType() == BackendType::CAIRO) {
615           return Factory::CreateScaledFontWithCairo(nativeFont,
616                                                     font->GetAdjustedSize(),
617                                                     font->GetCairoScaledFont());
618         }
619 
620         return Factory::CreateScaledFontForNativeFont(nativeFont,
621                                                       font->GetAdjustedSize());
622     }
623 
624     NS_ASSERTION(aFont->GetType() == gfxFont::FONT_TYPE_GDI,
625         "Fonts on windows should be GDI or DWrite!");
626 
627     NativeFont nativeFont;
628     nativeFont.mType = NativeFontType::GDI_FONT_FACE;
629     LOGFONT lf;
630     GetObject(static_cast<gfxGDIFont*>(aFont)->GetHFONT(), sizeof(LOGFONT), &lf);
631     nativeFont.mFont = &lf;
632 
633     if (aTarget->GetBackendType() == BackendType::CAIRO) {
634       return Factory::CreateScaledFontWithCairo(nativeFont,
635                                                 aFont->GetAdjustedSize(),
636                                                 aFont->GetCairoScaledFont());
637     }
638 
639     return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
640 }
641 
642 static const char kFontAparajita[] = "Aparajita";
643 static const char kFontArabicTypesetting[] = "Arabic Typesetting";
644 static const char kFontArial[] = "Arial";
645 static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
646 static const char kFontCambria[] = "Cambria";
647 static const char kFontCambriaMath[] = "Cambria Math";
648 static const char kFontEbrima[] = "Ebrima";
649 static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa";
650 static const char kFontEuphemia[] = "Euphemia";
651 static const char kFontEmojiOneMozilla[] = "EmojiOne Mozilla";
652 static const char kFontGabriola[] = "Gabriola";
653 static const char kFontJavaneseText[] = "Javanese Text";
654 static const char kFontKhmerUI[] = "Khmer UI";
655 static const char kFontLaoUI[] = "Lao UI";
656 static const char kFontLeelawadeeUI[] = "Leelawadee UI";
657 static const char kFontLucidaSansUnicode[] = "Lucida Sans Unicode";
658 static const char kFontMVBoli[] = "MV Boli";
659 static const char kFontMalgunGothic[] = "Malgun Gothic";
660 static const char kFontMicrosoftJhengHei[] = "Microsoft JhengHei";
661 static const char kFontMicrosoftNewTaiLue[] = "Microsoft New Tai Lue";
662 static const char kFontMicrosoftPhagsPa[] = "Microsoft PhagsPa";
663 static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le";
664 static const char kFontMicrosoftUighur[] = "Microsoft Uighur";
665 static const char kFontMicrosoftYaHei[] = "Microsoft YaHei";
666 static const char kFontMicrosoftYiBaiti[] = "Microsoft Yi Baiti";
667 static const char kFontMeiryo[] = "Meiryo";
668 static const char kFontMongolianBaiti[] = "Mongolian Baiti";
669 static const char kFontMyanmarText[] = "Myanmar Text";
670 static const char kFontNirmalaUI[] = "Nirmala UI";
671 static const char kFontNyala[] = "Nyala";
672 static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
673 static const char kFontSegoeUI[] = "Segoe UI";
674 static const char kFontSegoeUIEmoji[] = "Segoe UI Emoji";
675 static const char kFontSegoeUISymbol[] = "Segoe UI Symbol";
676 static const char kFontSylfaen[] = "Sylfaen";
677 static const char kFontTraditionalArabic[] = "Traditional Arabic";
678 static const char kFontUtsaah[] = "Utsaah";
679 static const char kFontYuGothic[] = "Yu Gothic";
680 
681 void
GetCommonFallbackFonts(uint32_t aCh,uint32_t aNextCh,Script aRunScript,nsTArray<const char * > & aFontList)682 gfxWindowsPlatform::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
683                                            Script aRunScript,
684                                            nsTArray<const char*>& aFontList)
685 {
686     if (aNextCh == 0xfe0fu) {
687         aFontList.AppendElement(kFontSegoeUIEmoji);
688         aFontList.AppendElement(kFontEmojiOneMozilla);
689     }
690 
691     // Arial is used as the default fallback for system fallback
692     aFontList.AppendElement(kFontArial);
693 
694     if (!IS_IN_BMP(aCh)) {
695         uint32_t p = aCh >> 16;
696         if (p == 1) { // SMP plane
697             if (aNextCh == 0xfe0eu) {
698                 aFontList.AppendElement(kFontSegoeUISymbol);
699                 aFontList.AppendElement(kFontSegoeUIEmoji);
700                 aFontList.AppendElement(kFontEmojiOneMozilla);
701             } else {
702                 if (aNextCh != 0xfe0fu) {
703                     aFontList.AppendElement(kFontSegoeUIEmoji);
704                     aFontList.AppendElement(kFontEmojiOneMozilla);
705                 }
706                 aFontList.AppendElement(kFontSegoeUISymbol);
707             }
708             aFontList.AppendElement(kFontEbrima);
709             aFontList.AppendElement(kFontNirmalaUI);
710             aFontList.AppendElement(kFontCambriaMath);
711         }
712     } else {
713         uint32_t b = (aCh >> 8) & 0xff;
714 
715         switch (b) {
716         case 0x05:
717             aFontList.AppendElement(kFontEstrangeloEdessa);
718             aFontList.AppendElement(kFontCambria);
719             break;
720         case 0x06:
721             aFontList.AppendElement(kFontMicrosoftUighur);
722             break;
723         case 0x07:
724             aFontList.AppendElement(kFontEstrangeloEdessa);
725             aFontList.AppendElement(kFontMVBoli);
726             aFontList.AppendElement(kFontEbrima);
727             break;
728         case 0x09:
729             aFontList.AppendElement(kFontNirmalaUI);
730             aFontList.AppendElement(kFontUtsaah);
731             aFontList.AppendElement(kFontAparajita);
732             break;
733         case 0x0a:
734         case 0x0b:
735         case 0x0c:
736         case 0x0d:
737             aFontList.AppendElement(kFontNirmalaUI);
738             break;
739         case 0x0e:
740             aFontList.AppendElement(kFontLaoUI);
741             aFontList.AppendElement(kFontLeelawadeeUI);
742             break;
743         case 0x10:
744             aFontList.AppendElement(kFontMyanmarText);
745             break;
746         case 0x11:
747             aFontList.AppendElement(kFontMalgunGothic);
748             break;
749         case 0x12:
750         case 0x13:
751             aFontList.AppendElement(kFontNyala);
752             aFontList.AppendElement(kFontPlantagenetCherokee);
753             break;
754         case 0x14:
755         case 0x15:
756         case 0x16:
757             aFontList.AppendElement(kFontEuphemia);
758             aFontList.AppendElement(kFontSegoeUISymbol);
759             break;
760         case 0x17:
761             aFontList.AppendElement(kFontKhmerUI);
762             aFontList.AppendElement(kFontLeelawadeeUI);
763             break;
764         case 0x18:  // Mongolian
765             aFontList.AppendElement(kFontMongolianBaiti);
766             aFontList.AppendElement(kFontEuphemia);
767             break;
768         case 0x19:
769             aFontList.AppendElement(kFontMicrosoftTaiLe);
770             aFontList.AppendElement(kFontMicrosoftNewTaiLue);
771             aFontList.AppendElement(kFontKhmerUI);
772             aFontList.AppendElement(kFontLeelawadeeUI);
773             break;
774         case 0x1a:
775             aFontList.AppendElement(kFontLeelawadeeUI);
776             break;
777         case 0x1c:
778             aFontList.AppendElement(kFontNirmalaUI);
779             break;
780         case 0x20:  // Symbol ranges
781         case 0x21:
782         case 0x22:
783         case 0x23:
784         case 0x24:
785         case 0x25:
786         case 0x26:
787         case 0x27:
788         case 0x29:
789         case 0x2a:
790         case 0x2b:
791         case 0x2c:
792             aFontList.AppendElement(kFontSegoeUI);
793             aFontList.AppendElement(kFontSegoeUISymbol);
794             aFontList.AppendElement(kFontCambria);
795             aFontList.AppendElement(kFontMeiryo);
796             aFontList.AppendElement(kFontArial);
797             aFontList.AppendElement(kFontLucidaSansUnicode);
798             aFontList.AppendElement(kFontEbrima);
799             break;
800         case 0x2d:
801         case 0x2e:
802         case 0x2f:
803             aFontList.AppendElement(kFontEbrima);
804             aFontList.AppendElement(kFontNyala);
805             aFontList.AppendElement(kFontSegoeUI);
806             aFontList.AppendElement(kFontSegoeUISymbol);
807             aFontList.AppendElement(kFontMeiryo);
808             break;
809         case 0x28:  // Braille
810             aFontList.AppendElement(kFontSegoeUISymbol);
811             break;
812         case 0x30:
813         case 0x31:
814             aFontList.AppendElement(kFontMicrosoftYaHei);
815             break;
816         case 0x32:
817             aFontList.AppendElement(kFontMalgunGothic);
818             break;
819         case 0x4d:
820             aFontList.AppendElement(kFontSegoeUISymbol);
821             break;
822         case 0x9f:
823             aFontList.AppendElement(kFontMicrosoftYaHei);
824             aFontList.AppendElement(kFontYuGothic);
825             break;
826         case 0xa0:  // Yi
827         case 0xa1:
828         case 0xa2:
829         case 0xa3:
830         case 0xa4:
831             aFontList.AppendElement(kFontMicrosoftYiBaiti);
832             aFontList.AppendElement(kFontSegoeUI);
833             break;
834         case 0xa5:
835         case 0xa6:
836         case 0xa7:
837             aFontList.AppendElement(kFontEbrima);
838             aFontList.AppendElement(kFontSegoeUI);
839             aFontList.AppendElement(kFontCambriaMath);
840             break;
841         case 0xa8:
842              aFontList.AppendElement(kFontMicrosoftPhagsPa);
843              aFontList.AppendElement(kFontNirmalaUI);
844              break;
845         case 0xa9:
846              aFontList.AppendElement(kFontMalgunGothic);
847              aFontList.AppendElement(kFontJavaneseText);
848              aFontList.AppendElement(kFontLeelawadeeUI);
849              break;
850         case 0xaa:
851              aFontList.AppendElement(kFontMyanmarText);
852              break;
853         case 0xab:
854              aFontList.AppendElement(kFontEbrima);
855              aFontList.AppendElement(kFontNyala);
856              break;
857         case 0xd7:
858              aFontList.AppendElement(kFontMalgunGothic);
859              break;
860         case 0xfb:
861             aFontList.AppendElement(kFontMicrosoftUighur);
862             aFontList.AppendElement(kFontGabriola);
863             aFontList.AppendElement(kFontSylfaen);
864             break;
865         case 0xfc:
866         case 0xfd:
867             aFontList.AppendElement(kFontTraditionalArabic);
868             aFontList.AppendElement(kFontArabicTypesetting);
869             break;
870         case 0xfe:
871             aFontList.AppendElement(kFontTraditionalArabic);
872             aFontList.AppendElement(kFontMicrosoftJhengHei);
873            break;
874        case 0xff:
875             aFontList.AppendElement(kFontMicrosoftJhengHei);
876             break;
877         default:
878             break;
879         }
880     }
881 
882     // Arial Unicode MS has lots of glyphs for obscure characters,
883     // use it as a last resort
884     aFontList.AppendElement(kFontArialUnicodeMS);
885 }
886 
887 gfxFontGroup *
CreateFontGroup(const FontFamilyList & aFontFamilyList,const gfxFontStyle * aStyle,gfxTextPerfMetrics * aTextPerf,gfxUserFontSet * aUserFontSet,gfxFloat aDevToCssSize)888 gfxWindowsPlatform::CreateFontGroup(const FontFamilyList& aFontFamilyList,
889                                     const gfxFontStyle *aStyle,
890                                     gfxTextPerfMetrics* aTextPerf,
891                                     gfxUserFontSet *aUserFontSet,
892                                     gfxFloat aDevToCssSize)
893 {
894     return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf,
895                             aUserFontSet, aDevToCssSize);
896 }
897 
898 bool
IsFontFormatSupported(nsIURI * aFontURI,uint32_t aFormatFlags)899 gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
900 {
901     // check for strange format flags
902     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
903                  "strange font format hint set");
904 
905     // accept supported formats
906     if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
907         return true;
908     }
909 
910     // reject all other formats, known and unknown
911     if (aFormatFlags != 0) {
912         return false;
913     }
914 
915     // no format hint set, need to look at data
916     return true;
917 }
918 
919 bool
DidRenderingDeviceReset(DeviceResetReason * aResetReason)920 gfxWindowsPlatform::DidRenderingDeviceReset(DeviceResetReason* aResetReason)
921 {
922   DeviceManagerDx* dm = DeviceManagerDx::Get();
923   if (!dm) {
924     return false;
925   }
926   return dm->HasDeviceReset(aResetReason);
927 }
928 
929 void
CompositorUpdated()930 gfxWindowsPlatform::CompositorUpdated()
931 {
932   DeviceManagerDx::Get()->ForceDeviceReset(ForcedDeviceResetReason::COMPOSITOR_UPDATED);
933   UpdateRenderMode();
934 }
935 
936 BOOL CALLBACK
InvalidateWindowForDeviceReset(HWND aWnd,LPARAM aMsg)937 InvalidateWindowForDeviceReset(HWND aWnd, LPARAM aMsg)
938 {
939     RedrawWindow(aWnd, nullptr, nullptr,
940                  RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_FRAME);
941     return TRUE;
942 }
943 
944 void
SchedulePaintIfDeviceReset()945 gfxWindowsPlatform::SchedulePaintIfDeviceReset()
946 {
947   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS);
948 
949   DeviceResetReason resetReason = DeviceResetReason::OK;
950   if (!DidRenderingDeviceReset(&resetReason)) {
951     return;
952   }
953 
954   gfxCriticalNote << "(gfxWindowsPlatform) Detected device reset: " << (int)resetReason;
955 
956   // Trigger an ::OnPaint for each window.
957   ::EnumThreadWindows(GetCurrentThreadId(),
958                       InvalidateWindowForDeviceReset,
959                       0);
960 
961   gfxCriticalNote << "(gfxWindowsPlatform) Finished device reset.";
962 }
963 
964 void
GetPlatformCMSOutputProfile(void * & mem,size_t & mem_size)965 gfxWindowsPlatform::GetPlatformCMSOutputProfile(void* &mem, size_t &mem_size)
966 {
967     WCHAR str[MAX_PATH];
968     DWORD size = MAX_PATH;
969     BOOL res;
970 
971     mem = nullptr;
972     mem_size = 0;
973 
974     HDC dc = GetDC(nullptr);
975     if (!dc)
976         return;
977 
978     MOZ_SEH_TRY {
979         res = GetICMProfileW(dc, &size, (LPWSTR)&str);
980     } MOZ_SEH_EXCEPT(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) {
981         res = FALSE;
982     }
983 
984     ReleaseDC(nullptr, dc);
985     if (!res)
986         return;
987 
988 #ifdef _WIN32
989     qcms_data_from_unicode_path(str, &mem, &mem_size);
990 
991 #ifdef DEBUG_tor
992     if (mem_size > 0)
993         fprintf(stderr,
994                 "ICM profile read from %s successfully\n",
995                 NS_ConvertUTF16toUTF8(str).get());
996 #endif // DEBUG_tor
997 #endif // _WIN32
998 }
999 
1000 bool
UseClearTypeForDownloadableFonts()1001 gfxWindowsPlatform::UseClearTypeForDownloadableFonts()
1002 {
1003     if (mUseClearTypeForDownloadableFonts == UNINITIALIZED_VALUE) {
1004         mUseClearTypeForDownloadableFonts = Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, true);
1005     }
1006 
1007     return mUseClearTypeForDownloadableFonts;
1008 }
1009 
1010 bool
UseClearTypeAlways()1011 gfxWindowsPlatform::UseClearTypeAlways()
1012 {
1013     if (mUseClearTypeAlways == UNINITIALIZED_VALUE) {
1014         mUseClearTypeAlways = Preferences::GetBool(GFX_USE_CLEARTYPE_ALWAYS, false);
1015     }
1016 
1017     return mUseClearTypeAlways;
1018 }
1019 
1020 void
GetDLLVersion(char16ptr_t aDLLPath,nsAString & aVersion)1021 gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath, nsAString& aVersion)
1022 {
1023     DWORD versInfoSize, vers[4] = {0};
1024     // version info not available case
1025     aVersion.AssignLiteral(u"0.0.0.0");
1026     versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr);
1027     AutoTArray<BYTE,512> versionInfo;
1028 
1029     if (versInfoSize == 0 ||
1030         !versionInfo.AppendElements(uint32_t(versInfoSize)))
1031     {
1032         return;
1033     }
1034 
1035     if (!GetFileVersionInfoW(aDLLPath, 0, versInfoSize,
1036            LPBYTE(versionInfo.Elements())))
1037     {
1038         return;
1039     }
1040 
1041     UINT len = 0;
1042     VS_FIXEDFILEINFO *fileInfo = nullptr;
1043     if (!VerQueryValue(LPBYTE(versionInfo.Elements()), TEXT("\\"),
1044            (LPVOID *)&fileInfo, &len) ||
1045         len == 0 ||
1046         fileInfo == nullptr)
1047     {
1048         return;
1049     }
1050 
1051     DWORD fileVersMS = fileInfo->dwFileVersionMS;
1052     DWORD fileVersLS = fileInfo->dwFileVersionLS;
1053 
1054     vers[0] = HIWORD(fileVersMS);
1055     vers[1] = LOWORD(fileVersMS);
1056     vers[2] = HIWORD(fileVersLS);
1057     vers[3] = LOWORD(fileVersLS);
1058 
1059     char buf[256];
1060     SprintfLiteral(buf, "%u.%u.%u.%u", vers[0], vers[1], vers[2], vers[3]);
1061     aVersion.Assign(NS_ConvertUTF8toUTF16(buf));
1062 }
1063 
1064 void
GetCleartypeParams(nsTArray<ClearTypeParameterInfo> & aParams)1065 gfxWindowsPlatform::GetCleartypeParams(nsTArray<ClearTypeParameterInfo>& aParams)
1066 {
1067     HKEY  hKey, subKey;
1068     DWORD i, rv, size, type;
1069     WCHAR displayName[256], subkeyName[256];
1070 
1071     aParams.Clear();
1072 
1073     // construct subkeys based on HKLM subkeys, assume they are same for HKCU
1074     rv = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1075                        L"Software\\Microsoft\\Avalon.Graphics",
1076                        0, KEY_READ, &hKey);
1077 
1078     if (rv != ERROR_SUCCESS) {
1079         return;
1080     }
1081 
1082     // enumerate over subkeys
1083     for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) {
1084         size = ArrayLength(displayName);
1085         rv = RegEnumKeyExW(hKey, i, displayName, &size,
1086                            nullptr, nullptr, nullptr, nullptr);
1087         if (rv != ERROR_SUCCESS) {
1088             continue;
1089         }
1090 
1091         ClearTypeParameterInfo ctinfo;
1092         ctinfo.displayName.Assign(displayName);
1093 
1094         DWORD subrv, value;
1095         bool foundData = false;
1096 
1097         swprintf_s(subkeyName, ArrayLength(subkeyName),
1098                    L"Software\\Microsoft\\Avalon.Graphics\\%s", displayName);
1099 
1100         // subkey for gamma, pixel structure
1101         subrv = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1102                               subkeyName, 0, KEY_QUERY_VALUE, &subKey);
1103 
1104         if (subrv == ERROR_SUCCESS) {
1105             size = sizeof(value);
1106             subrv = RegQueryValueExW(subKey, L"GammaLevel", nullptr, &type,
1107                                      (LPBYTE)&value, &size);
1108             if (subrv == ERROR_SUCCESS && type == REG_DWORD) {
1109                 foundData = true;
1110                 ctinfo.gamma = value;
1111             }
1112 
1113             size = sizeof(value);
1114             subrv = RegQueryValueExW(subKey, L"PixelStructure", nullptr, &type,
1115                                      (LPBYTE)&value, &size);
1116             if (subrv == ERROR_SUCCESS && type == REG_DWORD) {
1117                 foundData = true;
1118                 ctinfo.pixelStructure = value;
1119             }
1120 
1121             RegCloseKey(subKey);
1122         }
1123 
1124         // subkey for cleartype level, enhanced contrast
1125         subrv = RegOpenKeyExW(HKEY_CURRENT_USER,
1126                               subkeyName, 0, KEY_QUERY_VALUE, &subKey);
1127 
1128         if (subrv == ERROR_SUCCESS) {
1129             size = sizeof(value);
1130             subrv = RegQueryValueExW(subKey, L"ClearTypeLevel", nullptr, &type,
1131                                      (LPBYTE)&value, &size);
1132             if (subrv == ERROR_SUCCESS && type == REG_DWORD) {
1133                 foundData = true;
1134                 ctinfo.clearTypeLevel = value;
1135             }
1136 
1137             size = sizeof(value);
1138             subrv = RegQueryValueExW(subKey, L"EnhancedContrastLevel",
1139                                      nullptr, &type, (LPBYTE)&value, &size);
1140             if (subrv == ERROR_SUCCESS && type == REG_DWORD) {
1141                 foundData = true;
1142                 ctinfo.enhancedContrast = value;
1143             }
1144 
1145             RegCloseKey(subKey);
1146         }
1147 
1148         if (foundData) {
1149             aParams.AppendElement(ctinfo);
1150         }
1151     }
1152 
1153     RegCloseKey(hKey);
1154 }
1155 
1156 void
FontsPrefsChanged(const char * aPref)1157 gfxWindowsPlatform::FontsPrefsChanged(const char *aPref)
1158 {
1159     bool clearTextFontCaches = true;
1160 
1161     gfxPlatform::FontsPrefsChanged(aPref);
1162 
1163     if (!aPref) {
1164         mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
1165         mUseClearTypeAlways = UNINITIALIZED_VALUE;
1166     } else if (!strcmp(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, aPref)) {
1167         mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
1168     } else if (!strcmp(GFX_USE_CLEARTYPE_ALWAYS, aPref)) {
1169         mUseClearTypeAlways = UNINITIALIZED_VALUE;
1170     } else if (!strncmp(GFX_CLEARTYPE_PARAMS, aPref, strlen(GFX_CLEARTYPE_PARAMS))) {
1171         SetupClearTypeParams();
1172     } else {
1173         clearTextFontCaches = false;
1174     }
1175 
1176     if (clearTextFontCaches) {
1177         gfxFontCache *fc = gfxFontCache::GetCache();
1178         if (fc) {
1179             fc->Flush();
1180         }
1181     }
1182 }
1183 
1184 #define DISPLAY1_REGISTRY_KEY \
1185     HKEY_CURRENT_USER, L"Software\\Microsoft\\Avalon.Graphics\\DISPLAY1"
1186 
1187 #define ENHANCED_CONTRAST_VALUE_NAME L"EnhancedContrastLevel"
1188 
1189 void
SetupClearTypeParams()1190 gfxWindowsPlatform::SetupClearTypeParams()
1191 {
1192     if (GetDWriteFactory()) {
1193         // any missing prefs will default to invalid (-1) and be ignored;
1194         // out-of-range values will also be ignored
1195         FLOAT gamma = -1.0;
1196         FLOAT contrast = -1.0;
1197         FLOAT level = -1.0;
1198         int geometry = -1;
1199         int mode = -1;
1200         int32_t value;
1201         if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_GAMMA, &value))) {
1202             if (value >= 1000 && value <= 2200) {
1203                 gamma = FLOAT(value / 1000.0);
1204             }
1205         }
1206 
1207         if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_CONTRAST, &value))) {
1208             if (value >= 0 && value <= 1000) {
1209                 contrast = FLOAT(value / 100.0);
1210             }
1211         }
1212 
1213         if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_LEVEL, &value))) {
1214             if (value >= 0 && value <= 100) {
1215                 level = FLOAT(value / 100.0);
1216             }
1217         }
1218 
1219         if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_STRUCTURE, &value))) {
1220             if (value >= 0 && value <= 2) {
1221                 geometry = value;
1222             }
1223         }
1224 
1225         if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_MODE, &value))) {
1226             if (value >= 0 && value <= 5) {
1227                 mode = value;
1228             }
1229         }
1230 
1231         cairo_dwrite_set_cleartype_params(gamma, contrast, level, geometry, mode);
1232 
1233         switch (mode) {
1234         case DWRITE_RENDERING_MODE_ALIASED:
1235         case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
1236             mMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
1237             break;
1238         case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
1239             mMeasuringMode = DWRITE_MEASURING_MODE_GDI_NATURAL;
1240             break;
1241         default:
1242             mMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
1243             break;
1244         }
1245 
1246         RefPtr<IDWriteRenderingParams> defaultRenderingParams;
1247         GetDWriteFactory()->CreateRenderingParams(getter_AddRefs(defaultRenderingParams));
1248         // For EnhancedContrast, we override the default if the user has not set it
1249         // in the registry (by using the ClearType Tuner).
1250         if (contrast < 0.0 || contrast > 10.0) {
1251             HKEY hKey;
1252             LONG res = RegOpenKeyExW(DISPLAY1_REGISTRY_KEY,
1253                                      0, KEY_READ, &hKey);
1254             if (res == ERROR_SUCCESS) {
1255                 res = RegQueryValueExW(hKey, ENHANCED_CONTRAST_VALUE_NAME,
1256                                        nullptr, nullptr, nullptr, nullptr);
1257                 if (res == ERROR_SUCCESS) {
1258                     contrast = defaultRenderingParams->GetEnhancedContrast();
1259                 }
1260                 RegCloseKey(hKey);
1261             }
1262 
1263             if (contrast < 0.0 || contrast > 10.0) {
1264                 contrast = 1.0;
1265             }
1266         }
1267 
1268         if (GetDefaultContentBackend() == BackendType::SKIA) {
1269           // Skia doesn't support a contrast value outside of 0-1, so default to 1.0
1270           if (contrast < 0.0 || contrast > 1.0) {
1271             NS_WARNING("Custom dwrite contrast not supported in Skia. Defaulting to 1.0.");
1272             contrast = 1.0;
1273           }
1274         }
1275 
1276         // For parameters that have not been explicitly set,
1277         // we copy values from default params (or our overridden value for contrast)
1278         if (gamma < 1.0 || gamma > 2.2) {
1279             gamma = defaultRenderingParams->GetGamma();
1280         }
1281 
1282         if (level < 0.0 || level > 1.0) {
1283             level = defaultRenderingParams->GetClearTypeLevel();
1284         }
1285 
1286         DWRITE_PIXEL_GEOMETRY dwriteGeometry =
1287           static_cast<DWRITE_PIXEL_GEOMETRY>(geometry);
1288         DWRITE_RENDERING_MODE renderMode =
1289           static_cast<DWRITE_RENDERING_MODE>(mode);
1290 
1291         if (dwriteGeometry < DWRITE_PIXEL_GEOMETRY_FLAT ||
1292             dwriteGeometry > DWRITE_PIXEL_GEOMETRY_BGR) {
1293             dwriteGeometry = defaultRenderingParams->GetPixelGeometry();
1294         }
1295 
1296         if (renderMode < DWRITE_RENDERING_MODE_DEFAULT ||
1297             renderMode > DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC) {
1298             renderMode = defaultRenderingParams->GetRenderingMode();
1299         }
1300 
1301         mRenderingParams[TEXT_RENDERING_NO_CLEARTYPE] = defaultRenderingParams;
1302 
1303         HRESULT hr = GetDWriteFactory()->CreateCustomRenderingParams(
1304             gamma, contrast, level, dwriteGeometry, renderMode,
1305             getter_AddRefs(mRenderingParams[TEXT_RENDERING_NORMAL]));
1306         if (FAILED(hr) || !mRenderingParams[TEXT_RENDERING_NORMAL]) {
1307             mRenderingParams[TEXT_RENDERING_NORMAL] = defaultRenderingParams;
1308         }
1309 
1310         hr = GetDWriteFactory()->CreateCustomRenderingParams(
1311             gamma, contrast, level,
1312             dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
1313             getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]));
1314         if (FAILED(hr) || !mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]) {
1315             mRenderingParams[TEXT_RENDERING_GDI_CLASSIC] =
1316                 defaultRenderingParams;
1317         }
1318     }
1319 }
1320 
1321 ReadbackManagerD3D11*
GetReadbackManager()1322 gfxWindowsPlatform::GetReadbackManager()
1323 {
1324   if (!mD3D11ReadbackManager) {
1325     mD3D11ReadbackManager = new ReadbackManagerD3D11();
1326   }
1327 
1328   return mD3D11ReadbackManager;
1329 }
1330 
1331 bool
IsOptimus()1332 gfxWindowsPlatform::IsOptimus()
1333 {
1334     static int knowIsOptimus = -1;
1335     if (knowIsOptimus == -1) {
1336         // other potential optimus -- nvd3d9wrapx.dll & nvdxgiwrap.dll
1337         if (GetModuleHandleA("nvumdshim.dll") ||
1338             GetModuleHandleA("nvumdshimx.dll"))
1339         {
1340             knowIsOptimus = 1;
1341         } else {
1342             knowIsOptimus = 0;
1343         }
1344     }
1345     return knowIsOptimus;
1346 }
1347 
1348 static inline bool
IsWARPStable()1349 IsWARPStable()
1350 {
1351   // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703.
1352   if (!IsWin8OrLater() || GetModuleHandleA("nvdxgiwrap.dll")) {
1353     return false;
1354   }
1355   return true;
1356 }
1357 
1358 static void
InitializeANGLEConfig()1359 InitializeANGLEConfig()
1360 {
1361   FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
1362 
1363   if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1364     d3d11ANGLE.DisableByDefault(FeatureStatus::Unavailable, "D3D11 compositing is disabled",
1365                                 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_DISABLED"));
1366     return;
1367   }
1368 
1369   d3d11ANGLE.EnableByDefault();
1370 
1371   nsCString message;
1372   nsCString failureId;
1373   if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, &message,
1374                            failureId)) {
1375     d3d11ANGLE.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
1376   }
1377 
1378 }
1379 
1380 void
InitializeDirectDrawConfig()1381 gfxWindowsPlatform::InitializeDirectDrawConfig()
1382 {
1383   MOZ_ASSERT(XRE_IsParentProcess());
1384 
1385   FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW);
1386   ddraw.EnableByDefault();
1387 }
1388 
1389 void
InitializeConfig()1390 gfxWindowsPlatform::InitializeConfig()
1391 {
1392   if (XRE_IsParentProcess()) {
1393     // The parent process first determines which features can be attempted.
1394     // This information is relayed to content processes and the GPU process.
1395     InitializeD3D9Config();
1396     InitializeD3D11Config();
1397     InitializeANGLEConfig();
1398     InitializeD2DConfig();
1399   } else {
1400     FetchAndImportContentDeviceData();
1401     InitializeANGLEConfig();
1402   }
1403 }
1404 
1405 void
InitializeD3D9Config()1406 gfxWindowsPlatform::InitializeD3D9Config()
1407 {
1408   MOZ_ASSERT(XRE_IsParentProcess());
1409 
1410   FeatureState& d3d9 = gfxConfig::GetFeature(Feature::D3D9_COMPOSITING);
1411 
1412   if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
1413     d3d9.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled",
1414                           NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D9_NEED_HWCOMP"));
1415     return;
1416   }
1417 
1418   if (!IsVistaOrLater()) {
1419     d3d9.EnableByDefault();
1420   } else {
1421     d3d9.SetDefaultFromPref(
1422       gfxPrefs::GetLayersAllowD3D9FallbackPrefName(),
1423       true,
1424       gfxPrefs::GetLayersAllowD3D9FallbackPrefDefault());
1425 
1426     if (!d3d9.IsEnabled() && gfxPrefs::LayersPreferD3D9()) {
1427       d3d9.UserEnable("Direct3D9 enabled via layers.prefer-d3d9");
1428     }
1429   }
1430 
1431   nsCString message;
1432   nsCString failureId;
1433   if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &message,
1434                            failureId)) {
1435     d3d9.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
1436   }
1437 
1438   if (gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) {
1439     d3d9.UserForceEnable("Hardware compositing is force-enabled");
1440   }
1441 }
1442 
1443 void
InitializeD3D11Config()1444 gfxWindowsPlatform::InitializeD3D11Config()
1445 {
1446   MOZ_ASSERT(XRE_IsParentProcess());
1447 
1448   FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
1449 
1450   if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
1451     d3d11.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled",
1452                            NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_NEED_HWCOMP"));
1453     return;
1454   }
1455 
1456   d3d11.EnableByDefault();
1457 
1458   if (!IsWin8OrLater() &&
1459       !DeviceManagerDx::Get()->CheckRemotePresentSupport()) {
1460     nsCOMPtr<nsIGfxInfo> gfxInfo;
1461     gfxInfo = services::GetGfxInfo();
1462     nsAutoString adaptorId;
1463     gfxInfo->GetAdapterDeviceID(adaptorId);
1464     // Blacklist Intel HD Graphics 510/520/530 on Windows 7 without platform
1465     // update due to the crashes in Bug 1351349.
1466     if (adaptorId.EqualsLiteral("0x1912") || adaptorId.EqualsLiteral("0x1916") ||
1467         adaptorId.EqualsLiteral("0x1902")) {
1468       d3d11.Disable(FeatureStatus::Blacklisted, "Blacklisted, see bug 1351349",
1469                     NS_LITERAL_CSTRING("FEATURE_FAILURE_BUG_1351349"));
1470     }
1471   }
1472 
1473   // If the user prefers D3D9, act as though they disabled D3D11.
1474   if (gfxPrefs::LayersPreferD3D9()) {
1475     d3d11.UserDisable("Disabled due to user preference for Direct3D 9",
1476                       NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_PREF"));
1477     return;
1478   }
1479 
1480   nsCString message;
1481   nsCString failureId;
1482   if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &message, failureId)) {
1483     d3d11.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
1484   }
1485 
1486   // Check if the user really, really wants WARP.
1487   if (gfxPrefs::LayersD3D11ForceWARP()) {
1488     // Force D3D11 on even if we disabled it.
1489     d3d11.UserForceEnable("User force-enabled WARP");
1490   }
1491 }
1492 
1493 /* static */ void
RecordContentDeviceFailure(TelemetryDeviceCode aDevice)1494 gfxWindowsPlatform::RecordContentDeviceFailure(TelemetryDeviceCode aDevice)
1495 {
1496   // If the parent process fails to acquire a device, we record this
1497   // normally as part of the environment. The exceptional case we're
1498   // looking for here is when the parent process successfully acquires
1499   // a device, but the content process fails to acquire the same device.
1500   // This would not normally be displayed in about:support.
1501   if (!XRE_IsContentProcess()) {
1502     return;
1503   }
1504   Telemetry::Accumulate(Telemetry::GFX_CONTENT_FAILED_TO_ACQUIRE_DEVICE, uint32_t(aDevice));
1505 }
1506 
1507 void
InitializeDevices()1508 gfxWindowsPlatform::InitializeDevices()
1509 {
1510   MOZ_ASSERT(!InSafeMode());
1511 
1512   if (XRE_IsParentProcess()) {
1513     // If we're the UI process, and the GPU process is enabled, then we don't
1514     // initialize any DirectX devices. We do leave them enabled in gfxConfig
1515     // though. If the GPU process fails to create these devices it will send
1516     // a message back and we'll update their status.
1517     if (InitGPUProcessSupport()) {
1518       return;
1519     }
1520 
1521     // No GPU process, continue initializing devices as normal.
1522   }
1523 
1524   // If acceleration is disabled, we refuse to initialize anything.
1525   if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
1526     return;
1527   }
1528 
1529   // If we previously crashed initializing devices, bail out now.
1530   D3D11LayersCrashGuard detectCrashes;
1531   if (detectCrashes.Crashed()) {
1532     gfxConfig::SetFailed(Feature::HW_COMPOSITING,
1533                          FeatureStatus::CrashedOnStartup,
1534                          "Crashed during startup in a previous session");
1535     gfxConfig::SetFailed(Feature::D3D11_COMPOSITING,
1536                          FeatureStatus::CrashedOnStartup,
1537                          "Harware acceleration crashed during startup in a previous session");
1538     gfxConfig::SetFailed(Feature::DIRECT2D,
1539                          FeatureStatus::CrashedOnStartup,
1540                          "Harware acceleration crashed during startup in a previous session");
1541     return;
1542   }
1543 
1544   bool shouldUseD2D = gfxConfig::IsEnabled(Feature::DIRECT2D);
1545 
1546   // First, initialize D3D11. If this succeeds we attempt to use Direct2D.
1547   InitializeD3D11();
1548   InitializeD2D();
1549 
1550   if (!gfxConfig::IsEnabled(Feature::DIRECT2D) &&
1551       XRE_IsContentProcess() &&
1552       shouldUseD2D)
1553   {
1554     RecordContentDeviceFailure(TelemetryDeviceCode::D2D1);
1555   }
1556 }
1557 
1558 void
InitializeD3D11()1559 gfxWindowsPlatform::InitializeD3D11()
1560 {
1561   // This function attempts to initialize our D3D11 devices, if the hardware
1562   // is not blacklisted for D3D11 layers. This first attempt will try to create
1563   // a hardware accelerated device. If this creation fails or the hardware is
1564   // blacklisted, then this function will abort if WARP is disabled, causing us
1565   // to fallback to D3D9 or Basic layers. If WARP is not disabled it will use
1566   // a WARP device which should always be available on Windows 7 and higher.
1567   if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1568     return;
1569   }
1570 
1571   DeviceManagerDx* dm = DeviceManagerDx::Get();
1572   if (XRE_IsParentProcess()) {
1573     if (!dm->CreateCompositorDevices()) {
1574       return;
1575     }
1576   }
1577 
1578   dm->CreateContentDevices();
1579 
1580   // Content process failed to create the d3d11 device while parent process
1581   // succeed.
1582   if (XRE_IsContentProcess() &&
1583       !gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1584     gfxCriticalError() << "[D3D11] Failed to create the D3D11 device in content \
1585                            process.";
1586   }
1587 }
1588 
1589 void
InitializeD2DConfig()1590 gfxWindowsPlatform::InitializeD2DConfig()
1591 {
1592   FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
1593 
1594   if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1595     d2d1.DisableByDefault(FeatureStatus::Unavailable, "Direct2D requires Direct3D 11 compositing",
1596                           NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_D3D11_COMP"));
1597     return;
1598   }
1599   if (!IsVistaOrLater()) {
1600     d2d1.DisableByDefault(FeatureStatus::Unavailable, "Direct2D is not available on Windows XP",
1601                           NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_XP"));
1602     return;
1603   }
1604 
1605   d2d1.SetDefaultFromPref(
1606     gfxPrefs::GetDirect2DDisabledPrefName(),
1607     false,
1608     gfxPrefs::GetDirect2DDisabledPrefDefault());
1609 
1610   nsCString message;
1611   nsCString failureId;
1612   if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT2D, &message, failureId)) {
1613     d2d1.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
1614   }
1615 
1616   if (!d2d1.IsEnabled() && gfxPrefs::Direct2DForceEnabled()) {
1617     d2d1.UserForceEnable("Force-enabled via user-preference");
1618   }
1619 }
1620 
1621 void
InitializeD2D()1622 gfxWindowsPlatform::InitializeD2D()
1623 {
1624   ScopedGfxFeatureReporter d2d1_1("D2D1.1");
1625 
1626   FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
1627 
1628   DeviceManagerDx* dm = DeviceManagerDx::Get();
1629 
1630   // We don't know this value ahead of time, but the user can force-override
1631   // it, so we use Disable instead of SetFailed.
1632   if (dm->IsWARP()) {
1633     d2d1.Disable(FeatureStatus::Blocked, "Direct2D is not compatible with Direct3D11 WARP",
1634                  NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_WARP_BLOCK"));
1635   }
1636 
1637   // If we pass all the initial checks, we can proceed to runtime decisions.
1638   if (!d2d1.IsEnabled()) {
1639     return;
1640   }
1641 
1642   if (!Factory::SupportsD2D1()) {
1643     d2d1.SetFailed(FeatureStatus::Unavailable, "Failed to acquire a Direct2D 1.1 factory",
1644                    NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_FACTORY"));
1645     return;
1646   }
1647 
1648   if (!dm->GetContentDevice()) {
1649     d2d1.SetFailed(FeatureStatus::Failed, "Failed to acquire a Direct3D 11 content device",
1650                    NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_DEVICE"));
1651     return;
1652   }
1653 
1654   if (!dm->TextureSharingWorks()) {
1655     d2d1.SetFailed(FeatureStatus::Failed, "Direct3D11 device does not support texture sharing",
1656                    NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_TXT_SHARING"));
1657     return;
1658   }
1659 
1660   // Using Direct2D depends on DWrite support.
1661   if (!mDWriteFactory && !InitDWriteSupport()) {
1662     d2d1.SetFailed(FeatureStatus::Failed, "Failed to initialize DirectWrite support",
1663                    NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_DWRITE"));
1664     return;
1665   }
1666 
1667   // Verify that Direct2D device creation succeeded.
1668   RefPtr<ID3D11Device> contentDevice = dm->GetContentDevice();
1669   if (!Factory::SetDirect3D11Device(contentDevice)) {
1670     d2d1.SetFailed(FeatureStatus::Failed, "Failed to create a Direct2D device",
1671                    NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_CREATE_FAILED"));
1672     return;
1673   }
1674 
1675   MOZ_ASSERT(d2d1.IsEnabled());
1676   d2d1_1.SetSuccessful();
1677 }
1678 
1679 bool
InitGPUProcessSupport()1680 gfxWindowsPlatform::InitGPUProcessSupport()
1681 {
1682   FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS);
1683 
1684   if (!gpuProc.IsEnabled()) {
1685     return false;
1686   }
1687 
1688   if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1689     // Don't use the GPU process if not using D3D11.
1690     gpuProc.Disable(
1691       FeatureStatus::Unavailable,
1692       "Not using GPU Process since D3D11 is unavailable",
1693       NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_D3D11"));
1694   } else if (!IsWin7SP1OrLater()) {
1695     // For Windows XP, we simply don't care enough to support this
1696     // configuration. On Windows Vista and 7 Pre-SP1, DXGI 1.2 is not
1697     // available and remote presentation for D3D11 will not work. Rather
1698     // than take a regression and use D3D9, we revert back to in-process
1699     // rendering.
1700     gpuProc.Disable(
1701       FeatureStatus::Unavailable,
1702       "Windows XP, Vista, and 7 Pre-SP1 cannot use the GPU process",
1703       NS_LITERAL_CSTRING("FEATURE_FAILURE_OLD_WINDOWS"));
1704   } else if (!IsWin8OrLater()) {
1705     // Windows 7 SP1 can have DXGI 1.2 only via the Platform Update, so we
1706     // explicitly check for that here.
1707     if (!DeviceManagerDx::Get()->CheckRemotePresentSupport()) {
1708       gpuProc.Disable(
1709         FeatureStatus::Unavailable,
1710         "GPU Process requires the Windows 7 Platform Update",
1711         NS_LITERAL_CSTRING("FEATURE_FAILURE_PLATFORM_UPDATE"));
1712     } else {
1713       // Clear anything cached by the above call since we don't need it.
1714       DeviceManagerDx::Get()->ResetDevices();
1715     }
1716   }
1717 
1718   // If we're still enabled at this point, the user set the force-enabled pref.
1719   return gpuProc.IsEnabled();
1720 }
1721 
1722 bool
DwmCompositionEnabled()1723 gfxWindowsPlatform::DwmCompositionEnabled()
1724 {
1725   if (!IsVistaOrLater()) {
1726     return false;
1727   }
1728 
1729   MOZ_ASSERT(WinUtils::dwmIsCompositionEnabledPtr);
1730   BOOL dwmEnabled = false;
1731 
1732   if (FAILED(WinUtils::dwmIsCompositionEnabledPtr(&dwmEnabled))) {
1733     return false;
1734   }
1735 
1736   return dwmEnabled;
1737 }
1738 
1739 class D3DVsyncSource final : public VsyncSource
1740 {
1741 public:
1742 
1743   class D3DVsyncDisplay final : public VsyncSource::Display
1744   {
1745     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(D3DVsyncDisplay)
1746     public:
D3DVsyncDisplay()1747       D3DVsyncDisplay()
1748         : mPrevVsync(TimeStamp::Now())
1749         , mVsyncEnabledLock("D3DVsyncEnabledLock")
1750         , mVsyncEnabled(false)
1751       {
1752         mVsyncThread = new base::Thread("WindowsVsyncThread");
1753         MOZ_RELEASE_ASSERT(mVsyncThread->Start(), "GFX: Could not start Windows vsync thread");
1754         SetVsyncRate();
1755       }
1756 
SetVsyncRate()1757       void SetVsyncRate()
1758       {
1759         if (!gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled()) {
1760           mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
1761           return;
1762         }
1763 
1764         DWM_TIMING_INFO vblankTime;
1765         // Make sure to init the cbSize, otherwise GetCompositionTiming will fail
1766         vblankTime.cbSize = sizeof(DWM_TIMING_INFO);
1767         HRESULT hr = WinUtils::dwmGetCompositionTimingInfoPtr(0, &vblankTime);
1768         if (SUCCEEDED(hr)) {
1769           UNSIGNED_RATIO refreshRate = vblankTime.rateRefresh;
1770           // We get the rate in hertz / time, but we want the rate in ms.
1771           float rate = ((float) refreshRate.uiDenominator
1772                        / (float) refreshRate.uiNumerator) * 1000;
1773           mVsyncRate = TimeDuration::FromMilliseconds(rate);
1774         } else {
1775           mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
1776         }
1777       }
1778 
Shutdown()1779       virtual void Shutdown() override
1780       {
1781         MOZ_ASSERT(NS_IsMainThread());
1782         DisableVsync();
1783         mVsyncThread->Stop();
1784         delete mVsyncThread;
1785       }
1786 
EnableVsync()1787       virtual void EnableVsync() override
1788       {
1789         MOZ_ASSERT(NS_IsMainThread());
1790         MOZ_ASSERT(mVsyncThread->IsRunning());
1791         { // scope lock
1792           MonitorAutoLock lock(mVsyncEnabledLock);
1793           if (mVsyncEnabled) {
1794             return;
1795           }
1796           mVsyncEnabled = true;
1797         }
1798 
1799         mVsyncThread->message_loop()->PostTask(
1800             NewRunnableMethod(this, &D3DVsyncDisplay::VBlankLoop));
1801       }
1802 
DisableVsync()1803       virtual void DisableVsync() override
1804       {
1805         MOZ_ASSERT(NS_IsMainThread());
1806         MOZ_ASSERT(mVsyncThread->IsRunning());
1807         MonitorAutoLock lock(mVsyncEnabledLock);
1808         if (!mVsyncEnabled) {
1809           return;
1810         }
1811         mVsyncEnabled = false;
1812       }
1813 
IsVsyncEnabled()1814       virtual bool IsVsyncEnabled() override
1815       {
1816         MOZ_ASSERT(NS_IsMainThread());
1817         MonitorAutoLock lock(mVsyncEnabledLock);
1818         return mVsyncEnabled;
1819       }
1820 
GetVsyncRate()1821       virtual TimeDuration GetVsyncRate() override
1822       {
1823         return mVsyncRate;
1824       }
1825 
ScheduleSoftwareVsync(TimeStamp aVsyncTimestamp)1826       void ScheduleSoftwareVsync(TimeStamp aVsyncTimestamp)
1827       {
1828         MOZ_ASSERT(IsInVsyncThread());
1829         NS_WARNING("DwmComposition dynamically disabled, falling back to software timers");
1830 
1831         TimeStamp nextVsync = aVsyncTimestamp + mVsyncRate;
1832         TimeDuration delay = nextVsync - TimeStamp::Now();
1833         if (delay.ToMilliseconds() < 0) {
1834           delay = mozilla::TimeDuration::FromMilliseconds(0);
1835         }
1836 
1837         mVsyncThread->message_loop()->PostDelayedTask(
1838             NewRunnableMethod(this, &D3DVsyncDisplay::VBlankLoop),
1839             delay.ToMilliseconds());
1840       }
1841 
1842       // Returns the timestamp for the just happened vsync
GetVBlankTime()1843       TimeStamp GetVBlankTime()
1844       {
1845         TimeStamp vsync = TimeStamp::Now();
1846         TimeStamp now = vsync;
1847 
1848         DWM_TIMING_INFO vblankTime;
1849         // Make sure to init the cbSize, otherwise
1850         // GetCompositionTiming will fail
1851         vblankTime.cbSize = sizeof(DWM_TIMING_INFO);
1852         HRESULT hr = WinUtils::dwmGetCompositionTimingInfoPtr(0, &vblankTime);
1853         if (!SUCCEEDED(hr)) {
1854             return vsync;
1855         }
1856 
1857         LARGE_INTEGER frequency;
1858         QueryPerformanceFrequency(&frequency);
1859 
1860         LARGE_INTEGER qpcNow;
1861         QueryPerformanceCounter(&qpcNow);
1862 
1863         const int microseconds = 1000000;
1864         int64_t adjust = qpcNow.QuadPart - vblankTime.qpcVBlank;
1865         int64_t usAdjust = (adjust * microseconds) / frequency.QuadPart;
1866         vsync -= TimeDuration::FromMicroseconds((double) usAdjust);
1867 
1868         if (IsWin10OrLater()) {
1869           // On Windows 10 and on, DWMGetCompositionTimingInfo, mostly
1870           // reports the upcoming vsync time, which is in the future.
1871           // It can also sometimes report a vblank time in the past.
1872           // Since large parts of Gecko assume TimeStamps can't be in future,
1873           // use the previous vsync.
1874 
1875           // Windows 10 and Intel HD vsync timestamps are messy and
1876           // all over the place once in a while. Most of the time,
1877           // it reports the upcoming vsync. Sometimes, that upcoming
1878           // vsync is in the past. Sometimes that upcoming vsync is before
1879           // the previously seen vsync.
1880           // In these error cases, normalize to Now();
1881           if (vsync >= now) {
1882             vsync = vsync - mVsyncRate;
1883           }
1884         }
1885 
1886         // On Windows 7 and 8, DwmFlush wakes up AFTER qpcVBlankTime
1887         // from DWMGetCompositionTimingInfo. We can return the adjusted vsync.
1888         if (vsync >= now) {
1889             vsync = now;
1890         }
1891 
1892         // Our vsync time is some time very far in the past, adjust to Now.
1893         // 4 ms is arbitrary, so feel free to pick something else if this isn't
1894         // working. See the comment above within IsWin10OrLater().
1895         if ((now - vsync).ToMilliseconds() > 4.0) {
1896             vsync = now;
1897         }
1898 
1899         return vsync;
1900       }
1901 
VBlankLoop()1902       void VBlankLoop()
1903       {
1904         MOZ_ASSERT(IsInVsyncThread());
1905         MOZ_ASSERT(sizeof(int64_t) == sizeof(QPC_TIME));
1906 
1907         TimeStamp vsync = TimeStamp::Now();
1908         mPrevVsync = TimeStamp();
1909         TimeStamp flushTime = TimeStamp::Now();
1910         TimeDuration longVBlank = mVsyncRate * 2;
1911 
1912         for (;;) {
1913           { // scope lock
1914             MonitorAutoLock lock(mVsyncEnabledLock);
1915             if (!mVsyncEnabled) return;
1916           }
1917 
1918           // Large parts of gecko assume that the refresh driver timestamp
1919           // must be <= Now() and cannot be in the future.
1920           MOZ_ASSERT(vsync <= TimeStamp::Now());
1921           Display::NotifyVsync(vsync);
1922 
1923           // DwmComposition can be dynamically enabled/disabled
1924           // so we have to check every time that it's available.
1925           // When it is unavailable, we fallback to software but will try
1926           // to get back to dwm rendering once it's re-enabled
1927           if (!gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled()) {
1928             ScheduleSoftwareVsync(vsync);
1929             return;
1930           }
1931 
1932           // Using WaitForVBlank, the whole system dies because WaitForVBlank
1933           // only works if it's run on the same thread as the Present();
1934           HRESULT hr = WinUtils::dwmFlushProcPtr();
1935           if (!SUCCEEDED(hr)) {
1936             // DWMFlush isn't working, fallback to software vsync.
1937             ScheduleSoftwareVsync(TimeStamp::Now());
1938             return;
1939           }
1940 
1941           TimeStamp now = TimeStamp::Now();
1942           TimeDuration flushDiff = now - flushTime;
1943           flushTime = now;
1944           if ((flushDiff > longVBlank) || mPrevVsync.IsNull()) {
1945             // Our vblank took longer than 2 intervals, readjust our timestamps
1946             vsync = GetVBlankTime();
1947             mPrevVsync = vsync;
1948           } else {
1949             // Instead of giving the actual vsync time, a constant interval
1950             // between vblanks instead of the noise generated via hardware
1951             // is actually what we want. Most apps just care about the diff
1952             // between vblanks to animate, so a clean constant interval is
1953             // smoother.
1954             vsync = mPrevVsync + mVsyncRate;
1955             if (vsync > now) {
1956               // DWMFlush woke up very early, so readjust our times again
1957               vsync = GetVBlankTime();
1958             }
1959 
1960             if (vsync <= mPrevVsync) {
1961               vsync = TimeStamp::Now();
1962             }
1963 
1964             if ((now - vsync).ToMilliseconds() > 2.0) {
1965               // Account for time drift here where vsync never quite catches up to
1966               // Now and we'd fall ever so slightly further behind Now().
1967               vsync = GetVBlankTime();
1968             }
1969 
1970             mPrevVsync = vsync;
1971           }
1972         } // end for
1973       }
1974 
1975     private:
~D3DVsyncDisplay()1976       virtual ~D3DVsyncDisplay()
1977       {
1978         MOZ_ASSERT(NS_IsMainThread());
1979       }
1980 
IsInVsyncThread()1981       bool IsInVsyncThread()
1982       {
1983         return mVsyncThread->thread_id() == PlatformThread::CurrentId();
1984       }
1985 
1986       TimeStamp mPrevVsync;
1987       Monitor mVsyncEnabledLock;
1988       base::Thread* mVsyncThread;
1989       TimeDuration mVsyncRate;
1990       bool mVsyncEnabled;
1991   }; // end d3dvsyncdisplay
1992 
D3DVsyncSource()1993   D3DVsyncSource()
1994   {
1995     mPrimaryDisplay = new D3DVsyncDisplay();
1996   }
1997 
GetGlobalDisplay()1998   virtual Display& GetGlobalDisplay() override
1999   {
2000     return *mPrimaryDisplay;
2001   }
2002 
2003 private:
~D3DVsyncSource()2004   virtual ~D3DVsyncSource()
2005   {
2006   }
2007   RefPtr<D3DVsyncDisplay> mPrimaryDisplay;
2008 }; // end D3DVsyncSource
2009 
2010 already_AddRefed<mozilla::gfx::VsyncSource>
CreateHardwareVsyncSource()2011 gfxWindowsPlatform::CreateHardwareVsyncSource()
2012 {
2013   MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
2014   if (!WinUtils::dwmIsCompositionEnabledPtr) {
2015     NS_WARNING("Dwm composition not available, falling back to software vsync");
2016     return gfxPlatform::CreateHardwareVsyncSource();
2017   }
2018 
2019   BOOL dwmEnabled = false;
2020   WinUtils::dwmIsCompositionEnabledPtr(&dwmEnabled);
2021   if (!dwmEnabled) {
2022     NS_WARNING("DWM not enabled, falling back to software vsync");
2023     return gfxPlatform::CreateHardwareVsyncSource();
2024   }
2025 
2026   RefPtr<VsyncSource> d3dVsyncSource = new D3DVsyncSource();
2027   return d3dVsyncSource.forget();
2028 }
2029 
2030 bool
SupportsApzTouchInput() const2031 gfxWindowsPlatform::SupportsApzTouchInput() const
2032 {
2033   int value = gfxPrefs::TouchEventsEnabled();
2034   return value == 1 || value == 2;
2035 }
2036 
2037 void
GetAcceleratedCompositorBackends(nsTArray<LayersBackend> & aBackends)2038 gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends)
2039 {
2040   if (gfxConfig::IsEnabled(Feature::OPENGL_COMPOSITING) && gfxPrefs::LayersPreferOpenGL()) {
2041     aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
2042   }
2043 
2044   if (gfxConfig::IsEnabled(Feature::D3D9_COMPOSITING) && gfxPrefs::LayersPreferD3D9()) {
2045     aBackends.AppendElement(LayersBackend::LAYERS_D3D9);
2046   }
2047 
2048   if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
2049     aBackends.AppendElement(LayersBackend::LAYERS_D3D11);
2050   }
2051 
2052   if (gfxConfig::IsEnabled(Feature::D3D9_COMPOSITING) && !gfxPrefs::LayersPreferD3D9()) {
2053     aBackends.AppendElement(LayersBackend::LAYERS_D3D9);
2054   }
2055 }
2056 
2057 void
ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData & aData)2058 gfxWindowsPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData)
2059 {
2060   MOZ_ASSERT(XRE_IsParentProcess());
2061 
2062   gfxPlatform::ImportGPUDeviceData(aData);
2063 
2064   gfxConfig::ImportChange(Feature::D3D11_COMPOSITING, aData.d3d11Compositing());
2065   gfxConfig::ImportChange(Feature::D3D9_COMPOSITING, aData.d3d9Compositing());
2066 
2067   DeviceManagerDx* dm = DeviceManagerDx::Get();
2068   if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
2069     dm->ImportDeviceInfo(aData.gpuDevice().get_D3D11DeviceStatus());
2070   } else {
2071     // There should be no devices, so this just takes away the device status.
2072     dm->ResetDevices();
2073 
2074     // Make sure we disable D2D if content processes might use it.
2075     FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
2076     if (d2d1.IsEnabled()) {
2077       d2d1.SetFailed(
2078         FeatureStatus::Unavailable,
2079         "Direct2D requires Direct3D 11 compositing",
2080         NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_D3D11_COMP"));
2081     }
2082   }
2083 
2084   // CanUseHardwareVideoDecoding depends on d3d11 state, so update
2085   // the cached value now.
2086   UpdateCanUseHardwareVideoDecoding();
2087 
2088   // For completeness (and messaging in about:support). Content recomputes this
2089   // on its own, and we won't use ANGLE in the UI process if we're using a GPU
2090   // process.
2091   UpdateANGLEConfig();
2092 }
2093 
2094 void
ImportContentDeviceData(const mozilla::gfx::ContentDeviceData & aData)2095 gfxWindowsPlatform::ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData)
2096 {
2097   MOZ_ASSERT(XRE_IsContentProcess());
2098 
2099   gfxPlatform::ImportContentDeviceData(aData);
2100 
2101   const DevicePrefs& prefs = aData.prefs();
2102   gfxConfig::Inherit(Feature::D3D11_COMPOSITING, prefs.d3d11Compositing());
2103   gfxConfig::Inherit(Feature::D3D9_COMPOSITING, prefs.d3d9Compositing());
2104   gfxConfig::Inherit(Feature::DIRECT2D, prefs.useD2D1());
2105 
2106   if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
2107     DeviceManagerDx* dm = DeviceManagerDx::Get();
2108     dm->ImportDeviceInfo(aData.d3d11());
2109   }
2110 }
2111 
2112 void
BuildContentDeviceData(ContentDeviceData * aOut)2113 gfxWindowsPlatform::BuildContentDeviceData(ContentDeviceData* aOut)
2114 {
2115   // Check for device resets before giving back new graphics information.
2116   UpdateRenderMode();
2117 
2118   gfxPlatform::BuildContentDeviceData(aOut);
2119 
2120   const FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
2121   aOut->prefs().d3d11Compositing() = d3d11.GetValue();
2122   aOut->prefs().d3d9Compositing() = gfxConfig::GetValue(Feature::D3D9_COMPOSITING);
2123   aOut->prefs().useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D);
2124 
2125   if (d3d11.IsEnabled()) {
2126     DeviceManagerDx* dm = DeviceManagerDx::Get();
2127     dm->ExportDeviceInfo(&aOut->d3d11());
2128   }
2129 }
2130 
2131 bool
SupportsPluginDirectDXGIDrawing()2132 gfxWindowsPlatform::SupportsPluginDirectDXGIDrawing()
2133 {
2134   DeviceManagerDx* dm = DeviceManagerDx::Get();
2135   if (!dm->GetContentDevice() || !dm->TextureSharingWorks()) {
2136     return false;
2137   }
2138   return true;
2139 }
2140