diff options
Diffstat (limited to 'gfx/thebes')
-rw-r--r-- | gfx/thebes/COLRFonts.cpp | 19 | ||||
-rw-r--r-- | gfx/thebes/DeviceManagerDx.cpp | 155 | ||||
-rw-r--r-- | gfx/thebes/DeviceManagerDx.h | 14 | ||||
-rw-r--r-- | gfx/thebes/gfxAndroidPlatform.cpp | 8 | ||||
-rw-r--r-- | gfx/thebes/gfxFont.cpp | 15 | ||||
-rw-r--r-- | gfx/thebes/gfxFontEntry.cpp | 25 | ||||
-rw-r--r-- | gfx/thebes/gfxFontEntry.h | 3 | ||||
-rw-r--r-- | gfx/thebes/gfxPlatform.cpp | 40 | ||||
-rw-r--r-- | gfx/thebes/gfxPlatform.h | 10 | ||||
-rw-r--r-- | gfx/thebes/gfxPlatformFontList.cpp | 9 | ||||
-rw-r--r-- | gfx/thebes/gfxPlatformFontList.h | 2 | ||||
-rw-r--r-- | gfx/thebes/gfxPlatformMac.cpp | 21 | ||||
-rw-r--r-- | gfx/thebes/gfxPlatformMac.h | 2 | ||||
-rw-r--r-- | gfx/thebes/gfxTextRun.h | 2 | ||||
-rw-r--r-- | gfx/thebes/gfxUserFontSet.cpp | 43 | ||||
-rw-r--r-- | gfx/thebes/gfxUserFontSet.h | 13 | ||||
-rw-r--r-- | gfx/thebes/gfxWindowsPlatform.cpp | 57 | ||||
-rw-r--r-- | gfx/thebes/gfxWindowsPlatform.h | 6 |
18 files changed, 244 insertions, 200 deletions
diff --git a/gfx/thebes/COLRFonts.cpp b/gfx/thebes/COLRFonts.cpp index 6369bf191d..4a451f22d3 100644 --- a/gfx/thebes/COLRFonts.cpp +++ b/gfx/thebes/COLRFonts.cpp @@ -1298,8 +1298,7 @@ struct PaintGlyph { // Core Text's own color font support may step in and ignore the // pattern. So to avoid this, fill the glyph as a path instead. #if XP_MACOSX - RefPtr<Path> path = - aState.mScaledFont->GetPathForGlyphs(buffer, aState.mDrawTarget); + RefPtr<Path> path = GetPathForGlyphs(aState, buffer); aState.mDrawTarget->Fill(path, *fillPattern, aState.mDrawOptions); #else aState.mDrawTarget->FillGlyphs(aState.mScaledFont, buffer, *fillPattern, @@ -1307,8 +1306,7 @@ struct PaintGlyph { #endif return true; } - RefPtr<Path> path = - aState.mScaledFont->GetPathForGlyphs(buffer, aState.mDrawTarget); + RefPtr<Path> path = GetPathForGlyphs(aState, buffer); aState.mDrawTarget->PushClip(path); bool ok = DispatchPaint(aState, aOffset + paintOffset, aBounds); aState.mDrawTarget->PopClip(); @@ -1319,10 +1317,19 @@ struct PaintGlyph { MOZ_ASSERT(format == kFormat); Glyph g{uint16_t(glyphID), Point()}; GlyphBuffer buffer{&g, 1}; - RefPtr<Path> path = - aState.mScaledFont->GetPathForGlyphs(buffer, aState.mDrawTarget); + RefPtr<Path> path = GetPathForGlyphs(aState, buffer); return path->GetFastBounds(); } + + private: + RefPtr<Path> GetPathForGlyphs(const PaintState& aState, + const GlyphBuffer& buffer) const { + if (aState.mDrawTarget->GetBackendType() == BackendType::WEBRENDER_TEXT) { + RefPtr dt = gfxPlatform::ThreadLocalScreenReferenceDrawTarget(); + return aState.mScaledFont->GetPathForGlyphs(buffer, dt); + } + return aState.mScaledFont->GetPathForGlyphs(buffer, aState.mDrawTarget); + } }; struct PaintColrGlyph { diff --git a/gfx/thebes/DeviceManagerDx.cpp b/gfx/thebes/DeviceManagerDx.cpp index ba473e0d1e..7d00e5ac1d 100644 --- a/gfx/thebes/DeviceManagerDx.cpp +++ b/gfx/thebes/DeviceManagerDx.cpp @@ -234,17 +234,47 @@ void DeviceManagerDx::PostUpdateMonitorInfo() { holder->GetCompositorThread()->DelayedDispatch(runnable.forget(), kDelayMS); } +static bool ColorSpaceIsHDR(const DXGI_OUTPUT_DESC1& aDesc) { + // Set isHDR to true if the output has a BT2020 colorspace with EOTF2084 + // gamma curve, this indicates the system is sending an HDR format to + // this monitor. The colorspace returned by DXGI is very vague - we only + // see DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 for HDR and + // DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 for SDR modes, even if the + // monitor is using something like YCbCr444 according to Settings + // (System -> Display Settings -> Advanced Display). To get more specific + // info we would need to query the DISPLAYCONFIG values in WinGDI. + // + // Note that we don't check bit depth here, since as of Windows 11 22H2, + // HDR is supported with 8bpc for lower bandwidth, where DWM converts to + // dithered RGB8 rather than RGB10, which doesn't really matter here. + // + // Since RefreshScreens(), the caller of this function, is triggered + // by WM_DISPLAYCHANGE, this will pick up changes to the monitors in + // all the important cases (resolution/color changes by the user). + // + // Further reading: + // https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range + // https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_sdr_white_level + bool isHDR = (aDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); + + return isHDR; +} + void DeviceManagerDx::UpdateMonitorInfo() { bool systemHdrEnabled = false; + std::set<HMONITOR> hdrMonitors; for (const auto& desc : GetOutputDescs()) { - if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { + if (ColorSpaceIsHDR(desc)) { systemHdrEnabled = true; + hdrMonitors.emplace(desc.Monitor); } } + { MutexAutoLock lock(mDeviceLock); mSystemHdrEnabled = Some(systemHdrEnabled); + mHdrMonitors.swap(hdrMonitors); mUpdateMonitorInfoRunnable = nullptr; } } @@ -329,6 +359,42 @@ bool DeviceManagerDx::SystemHDREnabled() { return mSystemHdrEnabled.ref(); } +bool DeviceManagerDx::WindowHDREnabled(HWND aWindow) { + MOZ_ASSERT(aWindow); + + HMONITOR monitor = ::MonitorFromWindow(aWindow, MONITOR_DEFAULTTONEAREST); + return MonitorHDREnabled(monitor); +} + +bool DeviceManagerDx::MonitorHDREnabled(HMONITOR aMonitor) { + if (!aMonitor) { + return false; + } + + bool needInit = false; + + { + MutexAutoLock lock(mDeviceLock); + if (mSystemHdrEnabled.isNothing()) { + needInit = true; + } + } + + if (needInit) { + UpdateMonitorInfo(); + } + + MutexAutoLock lock(mDeviceLock); + MOZ_ASSERT(mSystemHdrEnabled.isSome()); + + auto it = mHdrMonitors.find(aMonitor); + if (it == mHdrMonitors.end()) { + return false; + } + + return true; +} + void DeviceManagerDx::CheckHardwareStretchingSupport(HwStretchingSupport& aRv) { RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter(); @@ -651,9 +717,11 @@ already_AddRefed<IDXGIAdapter1> DeviceManagerDx::GetDXGIAdapter() { } IDXGIAdapter1* DeviceManagerDx::GetDXGIAdapterLocked() { - if (mAdapter) { + if (mAdapter && mFactory && mFactory->IsCurrent()) { return mAdapter; } + mAdapter = nullptr; + mFactory = nullptr; nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll")); decltype(CreateDXGIFactory1)* createDXGIFactory1 = @@ -668,50 +736,32 @@ IDXGIAdapter1* DeviceManagerDx::GetDXGIAdapterLocked() { // Try to use a DXGI 1.1 adapter in order to share resources // across processes. - RefPtr<IDXGIFactory1> factory1; if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup()) { - RefPtr<IDXGIFactory2> factory2; if (fCreateDXGIFactory2) { auto hr = fCreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, __uuidof(IDXGIFactory2), - getter_AddRefs(factory2)); + getter_AddRefs(mFactory)); MOZ_ALWAYS_TRUE(!FAILED(hr)); } else { NS_WARNING( "fCreateDXGIFactory2 not loaded, cannot create debug IDXGIFactory2."); } - factory1 = factory2; } - if (!factory1) { + if (!mFactory) { HRESULT hr = - createDXGIFactory1(__uuidof(IDXGIFactory1), getter_AddRefs(factory1)); - if (FAILED(hr) || !factory1) { + createDXGIFactory1(__uuidof(IDXGIFactory1), getter_AddRefs(mFactory)); + if (FAILED(hr) || !mFactory) { // This seems to happen with some people running the iZ3D driver. // They won't get acceleration. return nullptr; } } - if (!mDeviceStatus) { - // If we haven't created a device yet, and have no existing device status, - // then this must be the compositor device. Pick the first adapter we can. - if (FAILED(factory1->EnumAdapters1(0, getter_AddRefs(mAdapter)))) { - return nullptr; - } - } else { - // In the UI and GPU process, we clear mDeviceStatus on device reset, so we - // should never reach here. Furthermore, the UI process does not create - // devices when using a GPU process. - // - // So, this should only ever get called on the content process or RDD - // process - MOZ_ASSERT(XRE_IsContentProcess() || XRE_IsRDDProcess()); - - // In the child process, we search for the adapter that matches the parent - // process. The first adapter can be mismatched on dual-GPU systems. + if (mDeviceStatus) { + // Match the adapter to our mDeviceStatus, if possible. for (UINT index = 0;; index++) { RefPtr<IDXGIAdapter1> adapter; - if (FAILED(factory1->EnumAdapters1(index, getter_AddRefs(adapter)))) { + if (FAILED(mFactory->EnumAdapters1(index, getter_AddRefs(adapter)))) { break; } @@ -730,7 +780,9 @@ IDXGIAdapter1* DeviceManagerDx::GetDXGIAdapterLocked() { } if (!mAdapter) { - return nullptr; + mDeviceStatus.reset(); + // Pick the first adapter available. + mFactory->EnumAdapters1(0, getter_AddRefs(mAdapter)); } // We leak this module everywhere, we might as well do so here as well. @@ -1045,7 +1097,7 @@ FeatureStatus DeviceManagerDx::CreateContentDevice() { } RefPtr<ID3D11Device> DeviceManagerDx::CreateDecoderDevice( - bool aHardwareWebRender) { + DeviceFlagSet aFlags) { MutexAutoLock lock(mDeviceLock); if (!mDeviceStatus) { @@ -1054,30 +1106,33 @@ RefPtr<ID3D11Device> DeviceManagerDx::CreateDecoderDevice( bool isAMD = mDeviceStatus->adapter().VendorId == 0x1002; bool reuseDevice = false; - if (gfxVars::ReuseDecoderDevice()) { - reuseDevice = true; - } else if (isAMD) { - reuseDevice = true; - gfxCriticalNoteOnce << "Always have to reuse decoder device on AMD"; - } + if (!aFlags.contains(DeviceFlag::disableDeviceReuse)) { + if (gfxVars::ReuseDecoderDevice()) { + reuseDevice = true; + } else if (isAMD) { + reuseDevice = true; + gfxCriticalNoteOnce << "Always have to reuse decoder device on AMD"; + } - if (reuseDevice) { - // Use mCompositorDevice for decoder device only for hardware WebRender. - if (aHardwareWebRender && mCompositorDevice && - mCompositorDeviceSupportsVideo && !mDecoderDevice) { - mDecoderDevice = mCompositorDevice; - - RefPtr<ID3D10Multithread> multi; - mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread), - getter_AddRefs(multi)); - if (multi) { - MOZ_ASSERT(multi->GetMultithreadProtected()); + if (reuseDevice) { + // Use mCompositorDevice for decoder device only for hardware WebRender. + if (aFlags.contains(DeviceFlag::isHardwareWebRenderInUse) && + mCompositorDevice && mCompositorDeviceSupportsVideo && + !mDecoderDevice) { + mDecoderDevice = mCompositorDevice; + + RefPtr<ID3D10Multithread> multi; + mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread), + getter_AddRefs(multi)); + if (multi) { + MOZ_ASSERT(multi->GetMultithreadProtected()); + } } - } - if (mDecoderDevice) { - RefPtr<ID3D11Device> dev = mDecoderDevice; - return dev.forget(); + if (mDecoderDevice) { + RefPtr<ID3D11Device> dev = mDecoderDevice; + return dev.forget(); + } } } diff --git a/gfx/thebes/DeviceManagerDx.h b/gfx/thebes/DeviceManagerDx.h index c6860c7ffa..1e4182ddec 100644 --- a/gfx/thebes/DeviceManagerDx.h +++ b/gfx/thebes/DeviceManagerDx.h @@ -6,6 +6,7 @@ #ifndef mozilla_gfx_thebes_DeviceManagerDx_h #define mozilla_gfx_thebes_DeviceManagerDx_h +#include <set> #include <vector> #include "gfxPlatform.h" @@ -58,13 +59,18 @@ class DeviceManagerDx final { static DeviceManagerDx* Get() { return sInstance; } + enum class DeviceFlag { + isHardwareWebRenderInUse, + disableDeviceReuse, + }; + using DeviceFlagSet = EnumSet<DeviceFlag, uint8_t>; RefPtr<ID3D11Device> GetCompositorDevice(); RefPtr<ID3D11Device> GetContentDevice(); RefPtr<ID3D11Device> GetCanvasDevice(); RefPtr<ID3D11Device> GetImageDevice(); RefPtr<IDCompositionDevice2> GetDirectCompositionDevice(); RefPtr<ID3D11Device> GetVRDevice(); - RefPtr<ID3D11Device> CreateDecoderDevice(bool aHardwareWebRender); + RefPtr<ID3D11Device> CreateDecoderDevice(DeviceFlagSet aFlags); RefPtr<ID3D11Device> CreateMediaEngineDevice(); IDirectDraw7* GetDirectDraw(); @@ -91,7 +97,10 @@ class DeviceManagerDx final { bool GetOutputFromMonitor(HMONITOR monitor, RefPtr<IDXGIOutput>* aOutOutput); void PostUpdateMonitorInfo(); + void UpdateMonitorInfo(); bool SystemHDREnabled(); + bool WindowHDREnabled(HWND aWindow); + bool MonitorHDREnabled(HMONITOR aMonitor); // Check if the current adapter supports hardware stretching void CheckHardwareStretchingSupport(HwStretchingSupport& aRv); @@ -177,7 +186,6 @@ class DeviceManagerDx final { bool GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) MOZ_REQUIRES(mDeviceLock); - void UpdateMonitorInfo(); std::vector<DXGI_OUTPUT_DESC1> GetOutputDescs(); private: @@ -193,6 +201,7 @@ class DeviceManagerDx final { mutable mozilla::Mutex mDeviceLock; nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels MOZ_GUARDED_BY(mDeviceLock); RefPtr<IDXGIAdapter1> mAdapter MOZ_GUARDED_BY(mDeviceLock); + RefPtr<IDXGIFactory1> mFactory MOZ_GUARDED_BY(mDeviceLock); RefPtr<ID3D11Device> mCompositorDevice MOZ_GUARDED_BY(mDeviceLock); RefPtr<ID3D11Device> mContentDevice MOZ_GUARDED_BY(mDeviceLock); RefPtr<ID3D11Device> mCanvasDevice MOZ_GUARDED_BY(mDeviceLock); @@ -208,6 +217,7 @@ class DeviceManagerDx final { Maybe<DeviceResetReason> mDeviceResetReason MOZ_GUARDED_BY(mDeviceLock); RefPtr<Runnable> mUpdateMonitorInfoRunnable MOZ_GUARDED_BY(mDeviceLock); Maybe<bool> mSystemHdrEnabled MOZ_GUARDED_BY(mDeviceLock); + std::set<HMONITOR> mHdrMonitors MOZ_GUARDED_BY(mDeviceLock); nsModuleHandle mDirectDrawDLL; RefPtr<IDirectDraw7> mDirectDraw; diff --git a/gfx/thebes/gfxAndroidPlatform.cpp b/gfx/thebes/gfxAndroidPlatform.cpp index a121d5550a..fbc3d3fa80 100644 --- a/gfx/thebes/gfxAndroidPlatform.cpp +++ b/gfx/thebes/gfxAndroidPlatform.cpp @@ -89,8 +89,12 @@ gfxAndroidPlatform::gfxAndroidPlatform() { RegisterStrongMemoryReporter(new FreetypeReporter()); - mOffscreenFormat = GetScreenDepth() == 16 ? SurfaceFormat::R5G6B5_UINT16 - : SurfaceFormat::X8R8G8B8_UINT32; + // Bug 1886573: At this point, we don't yet have primary screen depth. + // This setting of screen depth to 0 is preserving existing behavior, + // and should be fixed. + int32_t screenDepth = 0; + mOffscreenFormat = screenDepth == 16 ? SurfaceFormat::R5G6B5_UINT16 + : SurfaceFormat::X8R8G8B8_UINT32; if (StaticPrefs::gfx_android_rgb16_force_AtStartup()) { mOffscreenFormat = SurfaceFormat::R5G6B5_UINT16; diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 618eb49455..c17e786d4f 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -729,15 +729,6 @@ void gfxShapedText::SetupClusterBoundaries(uint32_t aOffset, // preceding letter by any letter-spacing or justification. const char16_t kBengaliVirama = 0x09CD; const char16_t kBengaliYa = 0x09AF; - // Characters treated as hyphens for the purpose of "emergency" breaking - // when the content would otherwise overflow. - auto isHyphen = [](char16_t c) { - return c == char16_t('-') || // HYPHEN-MINUS - c == 0x2010 || // HYPHEN - c == 0x2012 || // FIGURE DASH - c == 0x2013 || // EN DASH - c == 0x058A; // ARMENIAN HYPHEN - }; bool prevWasHyphen = false; while (pos < aLength) { const char16_t ch = aString[pos]; @@ -750,7 +741,7 @@ void gfxShapedText::SetupClusterBoundaries(uint32_t aOffset, } if (ch == char16_t(' ') || ch == kIdeographicSpace) { glyphs[pos].SetIsSpace(); - } else if (isHyphen(ch) && pos && + } else if (nsContentUtils::IsHyphen(ch) && pos && nsContentUtils::IsAlphanumeric(aString[pos - 1])) { prevWasHyphen = true; } else if (ch == kBengaliYa) { @@ -1006,6 +997,10 @@ gfxFont::gfxFont(const RefPtr<UnscaledFont>& aUnscaledFont, } mKerningSet = HasFeatureSet(HB_TAG('k', 'e', 'r', 'n'), mKerningEnabled); + + // Ensure the gfxFontEntry's unitsPerEm and extents fields are initialized, + // so that GetFontExtents can use them without risk of races. + Unused << mFontEntry->UnitsPerEm(); } gfxFont::~gfxFont() { diff --git a/gfx/thebes/gfxFontEntry.cpp b/gfx/thebes/gfxFontEntry.cpp index a9fe04125c..7ff5f82a85 100644 --- a/gfx/thebes/gfxFontEntry.cpp +++ b/gfx/thebes/gfxFontEntry.cpp @@ -259,14 +259,22 @@ already_AddRefed<gfxFont> gfxFontEntry::FindOrMakeFont( } uint16_t gfxFontEntry::UnitsPerEm() { + { + AutoReadLock lock(mLock); + if (mUnitsPerEm) { + return mUnitsPerEm; + } + } + + AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); + AutoWriteLock lock(mLock); + if (!mUnitsPerEm) { - AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); if (headTable) { uint32_t len; const HeadTable* head = reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len)); if (len >= sizeof(HeadTable)) { - mUnitsPerEm = head->unitsPerEm; if (int16_t(head->xMax) > int16_t(head->xMin) && int16_t(head->yMax) > int16_t(head->yMin)) { mXMin = head->xMin; @@ -274,6 +282,7 @@ uint16_t gfxFontEntry::UnitsPerEm() { mXMax = head->xMax; mYMax = head->yMax; } + mUnitsPerEm = head->unitsPerEm; } } @@ -283,12 +292,13 @@ uint16_t gfxFontEntry::UnitsPerEm() { mUnitsPerEm = kInvalidUPEM; } } + return mUnitsPerEm; } bool gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); return GetSVGGlyphs()->HasSVGGlyph(aGlyphId); } @@ -306,8 +316,8 @@ bool gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId, SVGContextPaint* aContextPaint) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); GetSVGGlyphs()->RenderGlyph(aContext, aGlyphId, aContextPaint); } @@ -464,8 +474,9 @@ hb_blob_t* gfxFontEntry::FontTableHashEntry::ShareTableAndGetBlob( HB_MEMORY_MODE_READONLY, mSharedBlobData, DeleteFontTableBlobData); if (mBlob == hb_blob_get_empty()) { // The FontTableBlobData was destroyed during hb_blob_create(). - // The (empty) blob is still be held in the hashtable with a strong + // The (empty) blob will still be held in the hashtable with a strong // reference. + mSharedBlobData = nullptr; return hb_blob_reference(mBlob); } diff --git a/gfx/thebes/gfxFontEntry.h b/gfx/thebes/gfxFontEntry.h index 888b85f2c9..364cf6c79e 100644 --- a/gfx/thebes/gfxFontEntry.h +++ b/gfx/thebes/gfxFontEntry.h @@ -538,6 +538,9 @@ class gfxFontEntry { mozilla::gfx::Rect GetFontExtents(float aFUnitScaleFactor) const { // Flip the y-axis here to match the orientation of Gecko's coordinates. + // We don't need to take a lock here because the min/max fields are inert + // after initialization, and we make sure to initialize them at gfxFont- + // creation time. return mozilla::gfx::Rect(float(mXMin) * aFUnitScaleFactor, float(-mYMax) * aFUnitScaleFactor, float(mXMax - mXMin) * aFUnitScaleFactor, diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index c57564b054..ccc58213ef 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -445,8 +445,7 @@ gfxPlatform::gfxPlatform() mDisplayInfoCollector(this, &gfxPlatform::GetDisplayInfo), mOverlayInfoCollector(this, &gfxPlatform::GetOverlayInfo), mSwapChainInfoCollector(this, &gfxPlatform::GetSwapChainInfo), - mCompositorBackend(layers::LayersBackend::LAYERS_NONE), - mScreenDepth(0) { + mCompositorBackend(layers::LayersBackend::LAYERS_NONE) { mAllowDownloadableFonts = UNINITIALIZED_VALUE; InitBackendPrefs(GetBackendPrefs()); @@ -1064,6 +1063,13 @@ void gfxPlatform::ReportTelemetry() { mozilla::glean::gfx_display::count.Set(screenCount); mozilla::glean::gfx_display::primary_height.Set(rect.Height()); mozilla::glean::gfx_display::primary_width.Set(rect.Width()); + + // Check if any screen known by screenManager supports HDR. + bool supportsHDR = false; + for (const auto& screen : screenManager.CurrentScreenList()) { + supportsHDR |= screen->GetIsHDR(); + } + Telemetry::ScalarSet(Telemetry::ScalarID::GFX_SUPPORTS_HDR, supportsHDR); } nsString adapterDesc; @@ -1120,10 +1126,6 @@ void gfxPlatform::ReportTelemetry() { NS_ConvertUTF16toUTF8(adapterDriverDate)); mozilla::glean::gfx_status::headless.Set(IsHeadless()); - - MOZ_ASSERT(gPlatform, "Need gPlatform to generate some telemetry."); - Telemetry::ScalarSet(Telemetry::ScalarID::GFX_SUPPORTS_HDR, - gPlatform->SupportsHDR()); } static bool IsFeatureSupported(long aFeature, bool aDefault) { @@ -1607,6 +1609,12 @@ already_AddRefed<DataSourceSurface> gfxPlatform::GetWrappedDataSourceSurface( } void gfxPlatform::PopulateScreenInfo() { + // We're only going to set some gfxVars here, which is only possible from + // the parent process. + if (!XRE_IsParentProcess()) { + return; + } + nsCOMPtr<nsIScreenManager> manager = do_GetService("@mozilla.org/gfx/screenmanager;1"); MOZ_ASSERT(manager, "failed to get nsIScreenManager"); @@ -1618,13 +1626,9 @@ void gfxPlatform::PopulateScreenInfo() { return; } - screen->GetColorDepth(&mScreenDepth); - if (XRE_IsParentProcess()) { - gfxVars::SetScreenDepth(mScreenDepth); - } - - int left, top; - screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height); + int32_t screenDepth; + screen->GetColorDepth(&screenDepth); + gfxVars::SetPrimaryScreenDepth(screenDepth); } bool gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget) { @@ -3158,6 +3162,13 @@ void gfxPlatform::InitWebGPUConfig() { #endif gfxVars::SetAllowWebGPU(feature.IsEnabled()); + +#if XP_WIN + if (IsWin10CreatorsUpdateOrLater() && + StaticPrefs::dom_webgpu_allow_present_without_readback()) { + gfxVars::SetAllowWebGPUPresentWithoutReadback(true); + } +#endif } #ifdef XP_WIN @@ -3707,8 +3718,7 @@ uint32_t gfxPlatform::TargetFrameRate() { /* static */ bool gfxPlatform::UseDesktopZoomingScrollbars() { - return StaticPrefs::apz_allow_zooming() && - !StaticPrefs::apz_force_disable_desktop_zooming_scrollbars(); + return StaticPrefs::apz_allow_zooming(); } /*static*/ diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 5af6d77345..452e7208b4 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -646,9 +646,6 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener { */ static mozilla::LogModule* GetLog(eGfxLog aWhichLog); - int GetScreenDepth() const { return mScreenDepth; } - mozilla::gfx::IntSize GetScreenSize() const { return mScreenSize; } - static void PurgeSkiaFontCache(); static bool UsesOffMainThreadCompositing(); @@ -811,8 +808,6 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener { static bool UseDesktopZoomingScrollbars(); - virtual bool SupportsHDR() { return false; } - protected: gfxPlatform(); virtual ~gfxPlatform(); @@ -982,7 +977,7 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener { static void ShutdownCMS(); /** - * This uses nsIScreenManager to determine the screen size and color depth + * This uses nsIScreenManager to determine the primary screen color depth */ void PopulateScreenInfo(); @@ -1027,9 +1022,6 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener { // created yet. mozilla::layers::LayersBackend mCompositorBackend; - int32_t mScreenDepth; - mozilla::gfx::IntSize mScreenSize; - mozilla::Maybe<mozilla::layers::OverlayInfo> mOverlayInfo; mozilla::Maybe<mozilla::layers::SwapChainInfo> mSwapChainInfo; diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index 404d291e03..6c1d641509 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -435,12 +435,6 @@ void gfxPlatformFontList::ApplyWhitelist() { AutoTArray<RefPtr<gfxFontFamily>, 128> accepted; bool whitelistedFontFound = false; for (const auto& entry : mFontFamilies) { - if (entry.GetData()->IsHidden()) { - // Hidden system fonts are exempt from whitelisting, but don't count - // towards determining whether we "kept" any (user-visible) fonts - accepted.AppendElement(entry.GetData()); - continue; - } nsAutoCString fontFamilyName(entry.GetKey()); ToLowerCase(fontFamilyName); if (familyNamesWhitelist.Contains(fontFamilyName)) { @@ -476,8 +470,7 @@ void gfxPlatformFontList::ApplyWhitelist( AutoTArray<fontlist::Family::InitData, 128> accepted; bool keptNonHidden = false; for (auto& f : aFamilies) { - if (f.mVisibility == FontVisibility::Hidden || - familyNamesWhitelist.Contains(f.mKey)) { + if (familyNamesWhitelist.Contains(f.mKey)) { accepted.AppendElement(f); if (f.mVisibility != FontVisibility::Hidden) { keptNonHidden = true; diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index 3ab74c5f74..5a53d8b9ca 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -124,7 +124,7 @@ class ShmemCharMapHashEntry final : public PLDHashEntryHdr { return aCharMap->GetChecksum(); } - enum { ALLOW_MEMMOVE = true }; + enum { ALLOW_MEMMOVE = false }; // because of the Pointer member private: // charMaps are stored in the shared memory that FontList objects point to, diff --git a/gfx/thebes/gfxPlatformMac.cpp b/gfx/thebes/gfxPlatformMac.cpp index 091b0dff28..5c99d389c8 100644 --- a/gfx/thebes/gfxPlatformMac.cpp +++ b/gfx/thebes/gfxPlatformMac.cpp @@ -965,27 +965,6 @@ gfxPlatformMac::CreateGlobalHardwareVsyncSource() { #endif } -bool gfxPlatformMac::SupportsHDR() { - // HDR has 3 requirements: - // 1) high peak brightness - // 2) high contrast ratio - // 3) color depth > 24 - if (GetScreenDepth() <= 24) { - return false; - } - -#ifdef MOZ_WIDGET_UIKIT - return false; -#elif defined(EARLY_BETA_OR_EARLIER) - // Screen is capable. Is the OS capable? - // More-or-less supported in Catalina. - return true; -#else - // Definitely supported in Big Sur. - return nsCocoaFeatures::OnBigSurOrLater(); -#endif -} - nsTArray<uint8_t> gfxPlatformMac::GetPlatformCMSOutputProfileData() { nsTArray<uint8_t> prefProfileData = GetPrefCMSOutputProfileData(); if (!prefProfileData.IsEmpty()) { diff --git a/gfx/thebes/gfxPlatformMac.h b/gfx/thebes/gfxPlatformMac.h index 29bbd7e877..00ab2c1ca8 100644 --- a/gfx/thebes/gfxPlatformMac.h +++ b/gfx/thebes/gfxPlatformMac.h @@ -76,8 +76,6 @@ class gfxPlatformMac : public gfxPlatform { static bool CheckVariationFontSupport(); - bool SupportsHDR() override; - protected: bool AccelerateLayersByDefault() override; diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index 770370c9b1..61cdd3b251 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -122,7 +122,7 @@ class gfxTextRun : public gfxShapedText { } // Returns a gfxShapedText::CompressedGlyph::FLAG_BREAK_TYPE_* value - // as defined in gfxFont.h (may be NONE, NORMAL or HYPHEN). + // as defined in gfxFont.h (may be NONE, NORMAL, HYPHEN or EMERGENCY_WRAP). uint8_t CanBreakBefore(uint32_t aPos) const { MOZ_ASSERT(aPos < GetLength()); return mCharacterGlyphs[aPos].CanBreakBefore(); diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index e9a2f513b3..c761bd9227 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -20,6 +20,7 @@ #include "mozilla/PostTraversalTask.h" #include "mozilla/dom/WorkerCommon.h" #include "gfxOTSUtils.h" +#include "nsFontFaceLoader.h" #include "nsIFontLoadCompleteCallback.h" #include "nsProxyRelease.h" #include "nsContentUtils.h" @@ -392,6 +393,12 @@ void gfxUserFontEntry::LoadNextSrc() { } void gfxUserFontEntry::ContinueLoad() { + if (mUserFontLoadState == STATUS_NOT_LOADED) { + // We must have been cancelled (possibly due to a font-list refresh) while + // the runnable was pending, so just bail out. + return; + } + MOZ_ASSERT(mUserFontLoadState == STATUS_LOAD_PENDING); MOZ_ASSERT(mSrcList[mCurrentSrcIndex].mSourceType == gfxFontFaceSrc::eSourceType_URL); @@ -974,7 +981,8 @@ gfxUserFontSet::gfxUserFontSet() mLocalRulesUsed(false), mRebuildLocalRules(false), mDownloadCount(0), - mDownloadSize(0) { + mDownloadSize(0), + mMutex("gfxUserFontSet") { IncrementGeneration(true); } @@ -1057,7 +1065,7 @@ void gfxUserFontSet::AddUserFontEntry(const nsCString& aFamilyName, } } -void gfxUserFontSet::IncrementGeneration(bool aIsRebuild) { +void gfxUserFontSet::IncrementGenerationLocked(bool aIsRebuild) { // add one, increment again if zero do { mGeneration = ++sFontSetGeneration; @@ -1097,6 +1105,10 @@ void gfxUserFontSet::ForgetLocalFaces() { } void gfxUserFontSet::ForgetLocalFace(gfxUserFontFamily* aFontFamily) { + // Entries for which we might need to cancel a current loader. + AutoTArray<RefPtr<gfxUserFontEntry>, 8> entriesToCancel; + + // Lock the font family while we iterate over its entries. aFontFamily->ReadLock(); const auto& fonts = aFontFamily->GetFontList(); for (const auto& f : fonts) { @@ -1107,14 +1119,28 @@ void gfxUserFontSet::ForgetLocalFace(gfxUserFontFamily* aFontFamily) { ufe->GetPlatformFontEntry()->IsLocalUserFont()) { ufe->mPlatformFontEntry = nullptr; } - // We need to re-evaluate the source list in the context of the new - // platform fontlist, whether or not the entry actually used a local() - // source last time, as one might be newly available. + // If the entry had a local source, we need to re-evaluate the source list + // in the context of the new platform fontlist, whether or not the entry + // actually used a local() source last time, as one might have been added. if (ufe->mSeenLocalSource) { - ufe->LoadCanceled(); + entriesToCancel.AppendElement(ufe); } } aFontFamily->ReadUnlock(); + + // Cancel any current loaders and reset the state of the affected entries. + for (auto& ufe : entriesToCancel) { + if (auto* loader = ufe->GetLoader()) { + // If there's a loader, we need to cancel it, because we'll trigger a + // fresh load if required when we re-resolve the font... + loader->Cancel(); + RemoveLoader(loader); + } else { + // ...otherwise, just reset our state so that we'll re-evaluate the + // source list from the beginning. + ufe->LoadCanceled(); + } + } } /////////////////////////////////////////////////////////////////////////////// @@ -1209,7 +1235,7 @@ void gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry* aFontEntry) { "caching a font associated with no family yet"); // if caching is disabled, simply return - if (Preferences::GetBool("gfx.downloadable_fonts.disable_cache")) { + if (StaticPrefs::gfx_downloadable_fonts_disable_cache()) { return; } @@ -1282,8 +1308,7 @@ void gfxUserFontSet::UserFontCache::ForgetFont(gfxFontEntry* aFontEntry) { gfxFontEntry* gfxUserFontSet::UserFontCache::GetFont( const gfxFontFaceSrc& aSrc, const gfxUserFontEntry& aUserFontEntry) { - if (!sUserFonts || - Preferences::GetBool("gfx.downloadable_fonts.disable_cache")) { + if (!sUserFonts || StaticPrefs::gfx_downloadable_fonts_disable_cache()) { return nullptr; } diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index d67d10fbe6..58cd2a077f 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -11,9 +11,11 @@ #include "gfxFontEntry.h" #include "gfxFontUtils.h" #include "mozilla/AlreadyAddRefed.h" +#include "mozilla/Atomics.h" #include "mozilla/Attributes.h" #include "mozilla/FontPropertyTypes.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/RecursiveMutex.h" #include "mozilla/RefPtr.h" #include "nsCOMPtr.h" #include "nsHashKeys.h" @@ -314,7 +316,11 @@ class gfxUserFontSet { uint64_t GetGeneration() { return mGeneration; } // increment the generation on font load - void IncrementGeneration(bool aIsRebuild = false); + void IncrementGeneration(bool aIsRebuild = false) { + mozilla::RecursiveMutexAutoLock lock(mMutex); + IncrementGenerationLocked(aIsRebuild); + } + void IncrementGenerationLocked(bool aIsRebuild = false) MOZ_REQUIRES(mMutex); // Generation is bumped on font loads but that doesn't affect name-style // mappings. Rebuilds do however affect name-style mappings so need to @@ -520,6 +526,9 @@ class gfxUserFontSet { // helper method for performing the actual userfont set rebuild virtual void DoRebuildUserFontSet() = 0; + // forget about a loader that has been cancelled + virtual void RemoveLoader(nsFontFaceLoader* aLoader) = 0; + // helper method for FindOrCreateUserFontEntry gfxUserFontEntry* FindExistingUserFontEntry( gfxUserFontFamily* aFamily, @@ -548,6 +557,8 @@ class gfxUserFontSet { // performance stats uint32_t mDownloadCount; uint64_t mDownloadSize; + + mutable mozilla::RecursiveMutex mMutex; }; // acts a placeholder until the real font is downloaded diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 93de20f445..4554d487f4 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -82,6 +82,7 @@ #include "mozilla/layers/DeviceAttachmentsD3D11.h" #include "mozilla/WindowsProcessMitigations.h" #include "D3D11Checks.h" +#include "mozilla/ScreenHelperWin.h" using namespace mozilla; using namespace mozilla::gfx; @@ -258,8 +259,7 @@ class D3DSharedTexturesReporter final : public nsIMemoryReporter { NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter, nsIMemoryReporter) -gfxWindowsPlatform::gfxWindowsPlatform() - : mRenderMode(RENDER_GDI), mSupportsHDR(false) { +gfxWindowsPlatform::gfxWindowsPlatform() : mRenderMode(RENDER_GDI) { // If win32k is locked down then we can't use COM STA and shouldn't need it. // Also, we won't be using any GPU memory in this process. if (!IsWin32kLockedDown()) { @@ -400,7 +400,11 @@ void gfxWindowsPlatform::InitAcceleration() { // CanUseHardwareVideoDecoding depends on DeviceManagerDx state, // so update the cached value now. UpdateCanUseHardwareVideoDecoding(); - UpdateSupportsHDR(); + + // Our ScreenHelperWin also depends on DeviceManagerDx state. + if (XRE_IsParentProcess() && !gfxPlatform::IsHeadless()) { + ScreenHelperWin::RefreshScreens(); + } RecordStartupTelemetry(); } @@ -531,53 +535,6 @@ void gfxWindowsPlatform::UpdateRenderMode() { } } -void gfxWindowsPlatform::UpdateSupportsHDR() { - // TODO: This function crashes content processes, for reasons that are not - // obvious from the crash reports. For now, this function can only be executed - // by the parent process. Therefore SupportsHDR() will always return false for - // content processes, as noted in the header. - if (!XRE_IsParentProcess()) { - return; - } - - // Set mSupportsHDR to true if any of the DeviceManager outputs have a BT2020 - // colorspace with EOTF2084 gamma curve, this indicates the system is sending - // an HDR format to at least one monitor. The colorspace returned by DXGI is - // very vague - we only see DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 for HDR - // and DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 for SDR modes, even if the - // monitor is using something like YCbCr444 according to Settings - // (System -> Display Settings -> Advanced Display). To get more specific - // info we would need to query the DISPLAYCONFIG values in WinGDI. - // - // Note that the bit depth used to be checked here, but as of Windows 11 22H2, - // HDR is supported with 8bpc for lower bandwidth, where DWM converts to - // dithered RGB8 rather than RGB10, which doesn't really matter here. - // - // This only returns true if there is an HDR display connected at app start, - // if the user switches to HDR to watch a video, we won't know that here, and - // if no displays are connected we return false (e.g. if Windows Update - // restarted a laptop with its lid closed and no external displays, we will - // see zero outputs here when the app is restarted automatically). - // - // It would be better to track if HDR is ever used and report that telemetry - // so we know if HDR matters, not just when it is detected at app start. - // - // Further reading: - // https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range - // https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_sdr_white_level - DeviceManagerDx* dx = DeviceManagerDx::Get(); - nsTArray<DXGI_OUTPUT_DESC1> outputs = dx->EnumerateOutputs(); - - for (auto& output : outputs) { - if (output.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { - mSupportsHDR = true; - return; - } - } - - mSupportsHDR = false; -} - mozilla::gfx::BackendType gfxWindowsPlatform::GetContentBackendFor( mozilla::layers::LayersBackend aLayers) { mozilla::gfx::BackendType defaultBackend = diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index 0956a384b0..12efaefc40 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -193,9 +193,6 @@ class gfxWindowsPlatform final : public gfxPlatform { static bool CheckVariationFontSupport(); - // Always false for content processes. - bool SupportsHDR() override { return mSupportsHDR; } - protected: bool AccelerateLayersByDefault() override { return true; } @@ -214,10 +211,7 @@ class gfxWindowsPlatform final : public gfxPlatform { BackendPrefsData GetBackendPrefs() const override; - void UpdateSupportsHDR(); - RenderMode mRenderMode; - bool mSupportsHDR; private: void Init(); |