summaryrefslogtreecommitdiffstats
path: root/gfx/thebes
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/thebes')
-rw-r--r--gfx/thebes/COLRFonts.cpp19
-rw-r--r--gfx/thebes/DeviceManagerDx.cpp155
-rw-r--r--gfx/thebes/DeviceManagerDx.h14
-rw-r--r--gfx/thebes/gfxAndroidPlatform.cpp8
-rw-r--r--gfx/thebes/gfxFont.cpp15
-rw-r--r--gfx/thebes/gfxFontEntry.cpp25
-rw-r--r--gfx/thebes/gfxFontEntry.h3
-rw-r--r--gfx/thebes/gfxPlatform.cpp40
-rw-r--r--gfx/thebes/gfxPlatform.h10
-rw-r--r--gfx/thebes/gfxPlatformFontList.cpp9
-rw-r--r--gfx/thebes/gfxPlatformFontList.h2
-rw-r--r--gfx/thebes/gfxPlatformMac.cpp21
-rw-r--r--gfx/thebes/gfxPlatformMac.h2
-rw-r--r--gfx/thebes/gfxTextRun.h2
-rw-r--r--gfx/thebes/gfxUserFontSet.cpp43
-rw-r--r--gfx/thebes/gfxUserFontSet.h13
-rw-r--r--gfx/thebes/gfxWindowsPlatform.cpp57
-rw-r--r--gfx/thebes/gfxWindowsPlatform.h6
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();