import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 847287 patch 4 - Add a method to nsRuleNode that reports the properties overriding a CSS animation. r=birtles (993741c96)
- Bug 847287 patch 5 - Add method to update animations on layer. r=birtles (32f2a293d)
- Bug 847287 patch 6 - Set mWinsInCascade for CSS Animations. r=birtles (6b511909d)
- Bug 847287 patch 7 - Dynamically update cascade results when animations start or stop being in effect. r=birtles (5ee6be671)
- Bug 847287 patch 8 - Only update transition manager's cascade results when an animation starts or stops being in effect. r=birtles (921be34b0)
- Bug 847287 patch 9 - Use fully-updated style rule for animations when updating cascade results for transitions. r=birtles (883af79a8)
- Bug 847287 patch 10 - Only call CheckNeedsRefresh if we might have changed mNeedsRefreshes, to make it cheaper to call EnsureStyleRuleFor more than once per refresh cycle. r=birtles (fe16261aa)
- Bug 847287 patch 11 - Only check that we can throttle animations once per refresh cycle (or invalidation of style rule), to make it cheaper to call EnsureStyleRuleFor more than once per refresh cycle. r=birtles (ccad05663)
- Bug 847287 patch 12 - Check mWinsInCascade for all callers of GetAnimationOfProperty/HasAnimationOfProperty. r=birtles (e64960b09)
- Bug 847287 patch 13 - Apply animations/transitions on the layer in the order that reflects how they override, rather than the opposite. r=birtles (4ad1ce381)
- Bug 1149848 - Stop calling NotifyAnimated (and thus repeatedly cycling layer activity) when sending OMT animations to the compositor. r=birtles (51fc3e010)
- Bug 1149848 patch 2 - Remove no-longer-needed flags to GetAnimationsForCompositor. r=birtles (1adf12a3a)
- rewrite to comply with Bug 1208465 - Part 2: Disable using Direct2D when 1.1 is unavailable. (b4599fe9a)
- Bug 1238028: When D2D 1.0 is not allowed disable D2D completely when not using 1.1. r=jrmuizel (d3eb2bace)
- Bug 1142260 - Re-sorted the prefs in gfxPrefs.h and added a big scary warning at the bottom of the list. r=kats (ca76ad66f)
- Bug 1150767 - Add pref for requiring hardware-backed GL. - r=jrmuizel (5972b4984)
- add comment (7ebc21fee)
- Bug 1164970 - Implement failIfMajorPerformanceCaveat. r=jgilbert, r=ehsan (5f9bea2f2)
This commit is contained in:
2020-04-03 13:22:54 +08:00
parent b418aff0b5
commit 842aa75632
21 changed files with 540 additions and 201 deletions
+5 -1
View File
@@ -272,7 +272,11 @@ Animation::GetAnimationOfProperty(nsCSSProperty aProperty) const
for (size_t propIdx = 0, propEnd = mProperties.Length();
propIdx != propEnd; ++propIdx) {
if (aProperty == mProperties[propIdx].mProperty) {
return &mProperties[propIdx];
const AnimationProperty* result = &mProperties[propIdx];
if (!result->mWinsInCascade) {
result = nullptr;
}
return result;
}
}
return nullptr;
+6 -3
View File
@@ -159,9 +159,12 @@ struct AnimationProperty
// then use this to decide whether to apply the style both in the CSS
// cascade and for OMTA.
//
// FIXME (bug 847287): For CSS Animations, which are overridden by
// !important rules in the cascade, we actually determine this from
// the CSS cascade computations, and then use it for OMTA.
// For CSS Animations, which are overridden by !important rules in the
// cascade, we actually determine this from the CSS cascade
// computations, and then use it for OMTA.
// **NOTE**: For CSS animations, we only bother setting mWinsInCascade
// accurately for properties that we can animate on the compositor.
// For other properties, we make it always be true.
bool mWinsInCascade;
InfallibleTArray<AnimationPropertySegment> mSegments;
+39 -1
View File
@@ -193,6 +193,7 @@ WebGLContextOptions::WebGLContextOptions()
, premultipliedAlpha(true)
, antialias(true)
, preserveDrawingBuffer(false)
, failIfMajorPerformanceCaveat(false)
{
// Set default alpha state based on preference.
if (Preferences::GetBool("webgl.default-no-alpha", false))
@@ -436,6 +437,7 @@ WebGLContext::SetContextOptions(JSContext* cx, JS::Handle<JS::Value> options)
newOpts.premultipliedAlpha = attributes.mPremultipliedAlpha;
newOpts.antialias = attributes.mAntialias;
newOpts.preserveDrawingBuffer = attributes.mPreserveDrawingBuffer;
newOpts.failIfMajorPerformanceCaveat = attributes.mFailIfMajorPerformanceCaveat;
if (attributes.mAlpha.WasPassed())
newOpts.alpha = attributes.mAlpha.Value();
@@ -503,6 +505,30 @@ IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature)
return status != nsIGfxInfo::FEATURE_STATUS_OK;
}
static bool
HasAcceleratedLayers(const nsCOMPtr<nsIGfxInfo>& gfxInfo)
{
int32_t status;
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status);
if (status)
return true;
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS, &status);
if (status)
return true;
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS, &status);
if (status)
return true;
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status);
if (status)
return true;
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status);
if (status)
return true;
return false;
}
static already_AddRefed<GLContext>
CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
bool requireCompatProfile, WebGLContext* webgl)
@@ -572,7 +598,6 @@ CreateHeadlessEGL(bool forceEnabled, bool requireCompatProfile,
return gl.forget();
}
static already_AddRefed<GLContext>
CreateHeadlessGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
@@ -871,6 +896,18 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
bool failIfMajorPerformanceCaveat =
!gfxPrefs::WebGLDisableFailIfMajorPerformanceCaveat() &&
!HasAcceleratedLayers(gfxInfo);
if (failIfMajorPerformanceCaveat) {
Nullable<dom::WebGLContextAttributes> contextAttributes;
this->GetContextAttributes(contextAttributes);
if (contextAttributes.Value().mFailIfMajorPerformanceCaveat) {
return NS_ERROR_FAILURE;
}
}
// Alright, now let's start trying.
bool forceEnabled = Preferences::GetBool("webgl.force-enabled", false);
@@ -1251,6 +1288,7 @@ WebGLContext::GetContextAttributes(Nullable<dom::WebGLContextAttributes>& retval
result.mAntialias = mOptions.antialias;
result.mPremultipliedAlpha = mOptions.premultipliedAlpha;
result.mPreserveDrawingBuffer = mOptions.preserveDrawingBuffer;
result.mFailIfMajorPerformanceCaveat = mOptions.failIfMajorPerformanceCaveat;
}
/* [noscript] DOMString mozGetUnderlyingParamString(in GLenum pname); */
+1
View File
@@ -130,6 +130,7 @@ struct WebGLContextOptions
bool premultipliedAlpha;
bool antialias;
bool preserveDrawingBuffer;
bool failIfMajorPerformanceCaveat;
};
// From WebGLContextUtils
+1
View File
@@ -41,6 +41,7 @@ dictionary WebGLContextAttributes {
boolean antialias = true;
boolean premultipliedAlpha = true;
boolean preserveDrawingBuffer = false;
boolean failIfMajorPerformanceCaveat = false;
};
interface WebGLBuffer {
+21 -7
View File
@@ -9,10 +9,9 @@
#include "nsDebug.h"
#include "nsIWidget.h"
#include <OpenGL/gl.h>
#include "gfxPrefs.h"
#include "gfxFailure.h"
#include "gfxPrefs.h"
#include "prenv.h"
#include "mozilla/Preferences.h"
#include "GeckoProfiler.h"
#include "mozilla/gfx/MacIOSurface.h"
@@ -185,7 +184,11 @@ static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered[] = {
};
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen[] = {
NSOpenGLPFAPixelBuffer,
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_accel[] = {
NSOpenGLPFAAccelerated,
0
};
@@ -202,8 +205,10 @@ CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs)
{
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc]
initWithAttributes:attribs];
if (!format)
if (!format) {
NS_WARNING("Failed to create NSOpenGLPixelFormat.");
return nullptr;
}
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format
shareContext:nullptr];
@@ -265,9 +270,14 @@ CreateOffscreenFBOContext(bool requireCompatProfile)
}
if (!context) {
profile = ContextProfile::OpenGLCompatibility;
context = CreateWithFormat(kAttribs_offscreen);
if (gfxPrefs::RequireHardwareGL())
context = CreateWithFormat(kAttribs_offscreen_accel);
else
context = CreateWithFormat(kAttribs_offscreen);
}
if (!context) {
NS_WARNING("Failed to create NSOpenGLContext.");
return nullptr;
}
@@ -286,8 +296,10 @@ GLContextProviderCGL::CreateHeadless(bool requireCompatProfile)
if (!gl)
return nullptr;
if (!gl->Init())
if (!gl->Init()) {
NS_WARNING("Failed during Init.");
return nullptr;
}
return gl.forget();
}
@@ -298,8 +310,10 @@ GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size,
bool requireCompatProfile)
{
nsRefPtr<GLContext> glContext = CreateHeadless(requireCompatProfile);
if (!glContext->InitOffscreen(ToIntSize(size), caps))
if (!glContext->InitOffscreen(ToIntSize(size), caps)) {
NS_WARNING("Failed during InitOffscreen.");
return nullptr;
}
return glContext.forget();
}
+1
View File
@@ -1108,6 +1108,7 @@ public:
// Call AddAnimation to add a new animation to this layer from layout code.
// Caller must fill in all the properties of the returned animation.
// A later animation overrides an earlier one.
Animation* AddAnimation();
// ClearAnimations clears animations on this layer.
void ClearAnimations();
@@ -440,7 +440,8 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint)
bool activeAnimations = false;
for (uint32_t i = animations.Length(); i-- !=0; ) {
// Process in order, since later animations override earlier ones.
for (size_t i = 0, iEnd = animations.Length(); i < iEnd; ++i) {
Animation& animation = animations[i];
AnimData& animData = animationData[i];
+68 -62
View File
@@ -137,22 +137,22 @@ private:
DECL_GFX_PREF(Live, "apz.allow_checkerboarding", APZAllowCheckerboarding, bool, true);
DECL_GFX_PREF(Live, "apz.asyncscroll.throttle", APZAsyncScrollThrottleTime, int32_t, 100);
DECL_GFX_PREF(Live, "apz.asyncscroll.timeout", APZAsyncScrollTimeout, int32_t, 300);
DECL_GFX_PREF(Live, "apz.axis_lock.mode", APZAxisLockMode, int32_t, 0);
DECL_GFX_PREF(Live, "apz.axis_lock.lock_angle", APZAxisLockAngle, float, float(M_PI / 6.0) /* 30 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_threshold", APZAxisBreakoutThreshold, float, 1.0f / 32.0f);
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_angle", APZAxisBreakoutAngle, float, float(M_PI / 8.0) /* 22.5 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_threshold", APZAxisBreakoutThreshold, float, 1.0f / 32.0f);
DECL_GFX_PREF(Live, "apz.axis_lock.direct_pan_angle", APZAllowedDirectPanAngle, float, float(M_PI / 3.0) /* 60 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.lock_angle", APZAxisLockAngle, float, float(M_PI / 6.0) /* 30 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.mode", APZAxisLockMode, int32_t, 0);
DECL_GFX_PREF(Live, "apz.content_response_timeout", APZContentResponseTimeout, int32_t, 300);
DECL_GFX_PREF(Live, "apz.cross_slide.enabled", APZCrossSlideEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.danger_zone_x", APZDangerZoneX, int32_t, 50);
DECL_GFX_PREF(Live, "apz.danger_zone_y", APZDangerZoneY, int32_t, 100);
DECL_GFX_PREF(Live, "apz.enlarge_displayport_when_clipped", APZEnlargeDisplayPortWhenClipped, bool, false);
DECL_GFX_PREF(Live, "apz.fling_accel_interval_ms", APZFlingAccelInterval, int32_t, 500);
DECL_GFX_PREF(Live, "apz.fling_accel_base_mult", APZFlingAccelBaseMultiplier, float, 1.0f);
DECL_GFX_PREF(Live, "apz.fling_accel_interval_ms", APZFlingAccelInterval, int32_t, 500);
DECL_GFX_PREF(Live, "apz.fling_accel_supplemental_mult", APZFlingAccelSupplementalMultiplier, float, 1.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_x1", APZCurveFunctionX1, float, 0.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_y1", APZCurveFunctionY1, float, 0.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_x2", APZCurveFunctionX2, float, 1.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_y1", APZCurveFunctionY1, float, 0.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_y2", APZCurveFunctionY2, float, 1.0f);
DECL_GFX_PREF(Live, "apz.fling_curve_threshold_inches_per_ms", APZCurveThreshold, float, -1.0f);
DECL_GFX_PREF(Once, "apz.fling_friction", APZFlingFriction, float, 0.002f);
@@ -165,11 +165,11 @@ private:
DECL_GFX_PREF(Live, "apz.num_paint_duration_samples", APZNumPaintDurationSamples, int32_t, 3);
DECL_GFX_PREF(Live, "apz.overscroll.enabled", APZOverscrollEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.overscroll.min_pan_distance_ratio", APZMinPanDistanceRatio, float, 1.0f);
DECL_GFX_PREF(Live, "apz.overscroll.stretch_factor", APZOverscrollStretchFactor, float, 0.5f);
DECL_GFX_PREF(Live, "apz.overscroll.spring_stiffness", APZOverscrollSpringStiffness, float, 0.001f);
DECL_GFX_PREF(Live, "apz.overscroll.spring_friction", APZOverscrollSpringFriction, float, 0.015f);
DECL_GFX_PREF(Live, "apz.overscroll.spring_stiffness", APZOverscrollSpringStiffness, float, 0.001f);
DECL_GFX_PREF(Live, "apz.overscroll.stop_distance_threshold", APZOverscrollStopDistanceThreshold, float, 5.0f);
DECL_GFX_PREF(Live, "apz.overscroll.stop_velocity_threshold", APZOverscrollStopVelocityThreshold, float, 0.01f);
DECL_GFX_PREF(Live, "apz.overscroll.stretch_factor", APZOverscrollStretchFactor, float, 0.5f);
DECL_GFX_PREF(Live, "apz.pan_repaint_interval", APZPanRepaintInterval, int32_t, 250);
DECL_GFX_PREF(Live, "apz.printtree", APZPrintTree, bool, false);
DECL_GFX_PREF(Live, "apz.smooth_scroll_repaint_interval", APZSmoothScrollRepaintInterval, int32_t, 75);
@@ -184,17 +184,20 @@ private:
DECL_GFX_PREF(Live, "apz.y_stationary_size_multiplier", APZYStationarySizeMultiplier, float, 3.5f);
DECL_GFX_PREF(Live, "apz.zoom_animation_duration_ms", APZZoomAnimationDuration, int32_t, 250);
DECL_GFX_PREF(Once, "dom.vr.enabled", VREnabled, bool, false);
DECL_GFX_PREF(Once, "dom.vr.add-test-devices", VRAddTestDevices, int32_t, 1);
DECL_GFX_PREF(Once, "gfx.android.rgb16.force", AndroidRGB16Force, bool, false);
#if defined(ANDROID)
DECL_GFX_PREF(Once, "gfx.apitrace.enabled", UseApitrace, bool, false);
#endif
DECL_GFX_PREF(Live, "gfx.canvas.auto_accelerate.min_calls", CanvasAutoAccelerateMinCalls, int32_t, 4);
DECL_GFX_PREF(Live, "gfx.canvas.auto_accelerate.min_frames", CanvasAutoAccelerateMinFrames, int32_t, 30);
DECL_GFX_PREF(Live, "gfx.canvas.auto_accelerate.min_seconds", CanvasAutoAccelerateMinSeconds, float, 5.0f);
DECL_GFX_PREF(Live, "gfx.canvas.auto_accelerate.min_calls", CanvasAutoAccelerateMinCalls, int32_t, 4);
DECL_GFX_PREF(Live, "gfx.canvas.azure.accelerated", CanvasAzureAccelerated, bool, false);
DECL_GFX_PREF(Once, "gfx.canvas.skiagl.dynamic-cache", CanvasSkiaGLDynamicCache, bool, false);
DECL_GFX_PREF(Once, "gfx.canvas.skiagl.cache-size", CanvasSkiaGLCacheSize, int32_t, 96);
DECL_GFX_PREF(Once, "gfx.canvas.skiagl.cache-items", CanvasSkiaGLCacheItems, int32_t, 256);
DECL_GFX_PREF(Once, "gfx.canvas.skiagl.cache-size", CanvasSkiaGLCacheSize, int32_t, 96);
DECL_GFX_PREF(Once, "gfx.canvas.skiagl.dynamic-cache", CanvasSkiaGLDynamicCache, bool, false);
DECL_GFX_PREF(Live, "gfx.color_management.enablev4", CMSEnableV4, bool, false);
DECL_GFX_PREF(Live, "gfx.color_management.mode", CMSMode, int32_t,-1);
@@ -204,7 +207,8 @@ private:
DECL_GFX_PREF(Once, "gfx.direct2d.disabled", Direct2DDisabled, bool, false);
DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled", Direct2DForceEnabled, bool, false);
DECL_GFX_PREF(Live, "gfx.direct2d.use1_1", Direct2DUse1_1, bool, false);
DECL_GFX_PREF(Live, "gfx.direct2d.allow-fallback", Direct2DAllowFallback, bool, false);
DECL_GFX_PREF(Live, "gfx.direct2d.allow1_0", Direct2DAllow1_0, bool, false);
DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false);
DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels", GrallocFenceWithReadPixels, bool, false);
DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false);
DECL_GFX_PREF(Live, "gfx.layerscope.port", LayerScopePort, int32_t, 23456);
@@ -214,28 +218,28 @@ private:
DECL_GFX_PREF(Once, "gfx.max-alloc-size", MaxAllocSize, int32_t, (int32_t)500000000);
DECL_GFX_PREF(Once, "gfx.max-texture-size", MaxTextureSize, int32_t, (int32_t)32767);
DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled", PerfWarnings, bool, false);
DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs", WorkAroundDriverBugs, bool, true);
DECL_GFX_PREF(Once, "gfx.touch.resample", TouchResampling, bool, false);
DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false);
// These times should be in milliseconds
DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold", TouchResampleVsyncDelayThreshold, int32_t, 20);
DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict", TouchResampleMaxPredict, int32_t, 8);
DECL_GFX_PREF(Once, "gfx.touch.resample.old-touch-threshold",TouchResampleOldTouchThreshold, int32_t, 17);
DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust", TouchVsyncSampleAdjust, int32_t, 5);
// Use vsync events generated by hardware
DECL_GFX_PREF(Once, "gfx.vsync.hw-vsync.enabled", HardwareVsyncEnabled, bool, false);
DECL_GFX_PREF(Once, "gfx.vsync.compositor", VsyncAlignedCompositor, bool, false);
DECL_GFX_PREF(Once, "gfx.vsync.refreshdriver", VsyncAlignedRefreshDriver, bool, false);
// On b2g, in really bad cases, I've seen up to 80 ms delays between touch events and the main thread
// processing them. So 80 ms / 16 = 5 vsync events. Double it up just to be on the safe side, so 10.
DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count", CompositorUnobserveCount, int32_t, 10);
DECL_GFX_PREF(Once, "gfx.touch.resample", TouchResampling, bool, false);
// These times should be in milliseconds
DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict", TouchResampleMaxPredict, int32_t, 8);
DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust", TouchVsyncSampleAdjust, int32_t, 5);
DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold", TouchResampleVsyncDelayThreshold, int32_t, 20);
DECL_GFX_PREF(Once, "gfx.touch.resample.old-touch-threshold",TouchResampleOldTouchThreshold, int32_t, 17);
// Use vsync events generated by hardware
DECL_GFX_PREF(Once, "gfx.vsync.hw-vsync.enabled", HardwareVsyncEnabled, bool, false);
DECL_GFX_PREF(Once, "gfx.vsync.refreshdriver", VsyncAlignedRefreshDriver, bool, false);
DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs", WorkAroundDriverBugs, bool, true);
DECL_GFX_PREF(Live, "gl.msaa-level", MSAALevel, uint32_t, 2);
DECL_GFX_PREF(Live, "gl.require-hardware", RequireHardwareGL, bool, false);
DECL_GFX_PREF(Once, "image.cache.timeweight", ImageCacheTimeWeight, int32_t, 500);
DECL_GFX_PREF(Once, "image.cache.size", ImageCacheSize, int32_t, 5*1024*1024);
DECL_GFX_PREF(Once, "image.cache.timeweight", ImageCacheTimeWeight, int32_t, 500);
DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, true);
DECL_GFX_PREF(Live, "image.high_quality_downscaling.enabled", ImageHQDownscalingEnabled, bool, false);
DECL_GFX_PREF(Live, "image.high_quality_downscaling.min_factor", ImageHQDownscalingMinFactor, uint32_t, 1000);
@@ -256,9 +260,9 @@ private:
DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram", FPSPrintHistogram, bool, false);
DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
DECL_GFX_PREF(Once, "layers.acceleration.force-enabled", LayersAccelerationForceEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled", AsyncPanZoomEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.async-video.enabled", AsyncVideoEnabled, bool, true);
DECL_GFX_PREF(Once, "layers.async-video-oop.enabled", AsyncVideoOOPEnabled, bool, true);
DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled", AsyncPanZoomEnabled, bool, false);
DECL_GFX_PREF(Live, "layers.bench.enabled", LayersBenchEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.bufferrotation.enabled", BufferRotationEnabled, bool, true);
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
@@ -270,83 +274,72 @@ private:
// preference value, defaulting to true.
DECL_GFX_PREF(Once, "layers.componentalpha.enabled", ComponentAlphaEnabled, bool, true);
#endif
DECL_GFX_PREF(Once, "layers.d3d11.disable-warp", LayersD3D11DisableWARP, bool, false);
DECL_GFX_PREF(Once, "layers.d3d11.force-warp", LayersD3D11ForceWARP, bool, false);
DECL_GFX_PREF(Live, "layers.draw-bigimage-borders", DrawBigImageBorders, bool, false);
DECL_GFX_PREF(Live, "layers.draw-borders", DrawLayerBorders, bool, false);
DECL_GFX_PREF(Live, "layers.draw-tile-borders", DrawTileBorders, bool, false);
DECL_GFX_PREF(Live, "layers.flash-borders", FlashLayerBorders, bool, false);
DECL_GFX_PREF(Live, "layers.draw-layer-info", DrawLayerInfo, bool, false);
DECL_GFX_PREF(Live, "layers.dump", LayersDump, bool, false);
DECL_GFX_PREF(Live, "layers.dump-texture", LayersDumpTexture, bool, false);
#ifdef MOZ_DUMP_PAINTING
DECL_GFX_PREF(Live, "layers.dump-decision", LayersDumpDecision, bool, false);
DECL_GFX_PREF(Live, "layers.dump-client-layers", DumpClientLayers, bool, false);
DECL_GFX_PREF(Live, "layers.dump-decision", LayersDumpDecision, bool, false);
DECL_GFX_PREF(Live, "layers.dump-host-layers", DumpHostLayers, bool, false);
#endif
DECL_GFX_PREF(Live, "layers.transaction.warning-ms", LayerTransactionWarning, uint32_t, 200);
// 0 is "no change" for contrast, positive values increase it, negative values
// decrease it until we hit mid gray at -1 contrast, after that it gets weird.
DECL_GFX_PREF(Live, "layers.effect.contrast", LayersEffectContrast, float, 0.0f);
DECL_GFX_PREF(Live, "layers.effect.grayscale", LayersEffectGrayscale, bool, false);
DECL_GFX_PREF(Live, "layers.effect.invert", LayersEffectInvert, bool, false);
DECL_GFX_PREF(Once, "layers.enable-tiles", LayersTilesEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.tiled-drawtarget.enabled", TiledDrawTargetEnabled, bool, false);
DECL_GFX_PREF(Live, "layers.flash-borders", FlashLayerBorders, bool, false);
DECL_GFX_PREF(Once, "layers.force-shmem-tiles", ForceShmemTiles, bool, false);
DECL_GFX_PREF(Live, "layers.frame-counter", DrawFrameCounter, bool, false);
DECL_GFX_PREF(Once, "layers.gralloc.disable", DisableGralloc, bool, false);
DECL_GFX_PREF(Live, "layers.low-precision-buffer", UseLowPrecisionBuffer, bool, false);
DECL_GFX_PREF(Live, "layers.low-precision-opacity", LowPrecisionOpacity, float, 1.0f);
DECL_GFX_PREF(Live, "layers.low-precision-resolution", LowPrecisionResolution, float, 0.25f);
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.enabled", LayersOffMainThreadCompositionEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-enabled", LayersOffMainThreadCompositionForceEnabled, bool, false);
DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.testing.enabled", LayersOffMainThreadCompositionTestingEnabled, bool, false);
DECL_GFX_PREF(Live, "layers.orientation.sync.timeout", OrientationSyncMillis, uint32_t, (uint32_t)0);
DECL_GFX_PREF(Once, "layers.overzealous-gralloc-unlocking", OverzealousGrallocUnlocking, bool, false);
DECL_GFX_PREF(Once, "layers.prefer-d3d9", LayersPreferD3D9, bool, false);
DECL_GFX_PREF(Once, "layers.prefer-opengl", LayersPreferOpenGL, bool, false);
DECL_GFX_PREF(Live, "layers.progressive-paint", ProgressivePaintDoNotUseDirectly, bool, false);
DECL_GFX_PREF(Once, "layers.stereo-video.enabled", StereoVideoEnabled, bool, false);
// We allow for configurable and rectangular tile size to avoid wasting memory on devices whose
// screen size does not align nicely to the default tile size. Although layers can be any size,
// they are often the same size as the screen, especially for width.
DECL_GFX_PREF(Once, "layers.tile-width", LayersTileWidth, int32_t, 256);
DECL_GFX_PREF(Once, "layers.tile-height", LayersTileHeight, int32_t, 256);
DECL_GFX_PREF(Once, "layers.tiles.adjust", LayersTilesAdjust, bool, true);
DECL_GFX_PREF(Once, "layers.tile-max-pool-size", LayersTileMaxPoolSize, uint32_t, (uint32_t)50);
DECL_GFX_PREF(Once, "layers.tile-shrink-pool-timeout", LayersTileShrinkPoolTimeout, uint32_t, (uint32_t)1000);
DECL_GFX_PREF(Once, "layers.overzealous-gralloc-unlocking", OverzealousGrallocUnlocking, bool, false);
DECL_GFX_PREF(Once, "layers.force-shmem-tiles", ForceShmemTiles, bool, false);
DECL_GFX_PREF(Live, "layers.frame-counter", DrawFrameCounter, bool, false);
DECL_GFX_PREF(Live, "layers.low-precision-buffer", UseLowPrecisionBuffer, bool, false);
DECL_GFX_PREF(Live, "layers.low-precision-resolution", LowPrecisionResolution, float, 0.25f);
DECL_GFX_PREF(Live, "layers.low-precision-opacity", LowPrecisionOpacity, float, 1.0f);
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.enabled", LayersOffMainThreadCompositionEnabled, bool, false);
DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-enabled", LayersOffMainThreadCompositionForceEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.testing.enabled", LayersOffMainThreadCompositionTestingEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces", UseImageOffscreenSurfaces, bool, false);
DECL_GFX_PREF(Live, "layers.orientation.sync.timeout", OrientationSyncMillis, uint32_t, (uint32_t)0);
DECL_GFX_PREF(Once, "layers.d3d11.disable-warp", LayersD3D11DisableWARP, bool, false);
DECL_GFX_PREF(Once, "layers.d3d11.force-warp", LayersD3D11ForceWARP, bool, false);
DECL_GFX_PREF(Once, "layers.prefer-d3d9", LayersPreferD3D9, bool, false);
DECL_GFX_PREF(Once, "layers.prefer-opengl", LayersPreferOpenGL, bool, false);
DECL_GFX_PREF(Live, "layers.progressive-paint", ProgressivePaintDoNotUseDirectly, bool, false);
DECL_GFX_PREF(Once, "layers.tiled-drawtarget.enabled", TiledDrawTargetEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.tiles.adjust", LayersTilesAdjust, bool, true);
DECL_GFX_PREF(Live, "layers.transaction.warning-ms", LayerTransactionWarning, uint32_t, 200);
DECL_GFX_PREF(Once, "layers.uniformity-info", UniformityInfo, bool, false);
DECL_GFX_PREF(Once, "layers.gralloc.disable", DisableGralloc, bool, false);
DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces", UseImageOffscreenSurfaces, bool, false);
DECL_GFX_PREF(Live, "layout.css.scroll-behavior.damping-ratio", ScrollBehaviorDampingRatio, float, 1.0f);
DECL_GFX_PREF(Live, "layout.css.scroll-behavior.enabled", ScrollBehaviorEnabled, bool, false);
DECL_GFX_PREF(Live, "layout.css.scroll-behavior.spring-constant", ScrollBehaviorSpringConstant, float, 250.0f);
DECL_GFX_PREF(Live, "layout.css.scroll-snap.prediction-sensitivity", ScrollSnapPredictionSensitivity, float, 0.750f);
DECL_GFX_PREF(Live, "layout.css.scroll-snap.prediction-max-velocity", ScrollSnapPredictionMaxVelocity, int32_t, 2000);
DECL_GFX_PREF(Live, "layout.css.scroll-snap.prediction-sensitivity", ScrollSnapPredictionSensitivity, float, 0.750f);
DECL_GFX_PREF(Once, "layout.css.touch_action.enabled", TouchActionEnabled, bool, false);
DECL_GFX_PREF(Once, "layout.frame_rate", LayoutFrameRate, int32_t, -1);
DECL_GFX_PREF(Live, "layout.display-list.dump", LayoutDumpDisplayList, bool, false);
DECL_GFX_PREF(Live, "layout.event-regions.enabled", LayoutEventRegionsEnabled, bool, false);
DECL_GFX_PREF(Once, "layout.frame_rate", LayoutFrameRate, int32_t, -1);
DECL_GFX_PREF(Once, "layout.paint_rects_separately", LayoutPaintRectsSeparately, bool, true);
#ifdef MOZ_JXR
DECL_GFX_PREF(Live, "media.jxr.enabled", MediaJXREnabled, bool, false);
DECL_GFX_PREF(Live, "media.jxr.workaround_alphaplane_bug", MediaJXRWorkaroundAlphaplaneBug, bool, false);
#endif
DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false);
DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay", UiClickHoldContextMenusDelay, int32_t, 500);
DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false);
DECL_GFX_PREF(Once, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false);
DECL_GFX_PREF(Once, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false);
DECL_GFX_PREF(Once, "layers.stereo-video.enabled", StereoVideoEnabled, bool, false);
DECL_GFX_PREF(Once, "dom.vr.enabled", VREnabled, bool, false);
DECL_GFX_PREF(Once, "dom.vr.add-test-devices", VRAddTestDevices, int32_t, 1);
// This and code dependent on it should be removed once containerless scrolling looks stable.
DECL_GFX_PREF(Once, "layout.scroll.root-frame-containers", LayoutUseContainersForRootFrames, bool, true);
@@ -354,6 +347,19 @@ private:
// This affects whether events will be routed through APZ or not.
DECL_GFX_PREF(Once, "mousewheel.system_scroll_override_on_root_content.enabled",
MouseWheelHasScrollDeltaOverride, bool, false);
DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false);
DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay", UiClickHoldContextMenusDelay, int32_t, 500);
DECL_GFX_PREF(Once, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false);
DECL_GFX_PREF(Once, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false);
DECL_GFX_PREF(Live, "webgl.disable-fail-if-major-performance-caveat",
WebGLDisableFailIfMajorPerformanceCaveat, bool, false);
DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false);
// WARNING:
// Please make sure that you've added your new preference to the list above in alphabetical order.
// Please do not just append it to the end of the list.
public:
// Manage the singleton:
static gfxPrefs& GetSingleton()
+1 -3
View File
@@ -650,9 +650,7 @@ gfxWindowsPlatform::CreateDevice(nsRefPtr<IDXGIAdapter1> &adapter1,
void
gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
{
// Check if fallback to unsupported D2D version is allowed when
// the Direct2D 1.1 feature set isn't available.
if (!Factory::SupportsD2D1() && !gfxPrefs::Direct2DAllowFallback()) {
if ((!Factory::SupportsD2D1() || !gfxPrefs::Direct2DUse1_1()) && !gfxPrefs::Direct2DAllow1_0()) {
return;
}
+16 -15
View File
@@ -413,6 +413,7 @@ AddAnimationsForProperty(nsIFrame* aFrame, nsCSSProperty aProperty,
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
"inconsistent property flags");
// Add from first to last (since last overrides)
for (size_t playerIdx = 0; playerIdx < aPlayers.Length(); playerIdx++) {
AnimationPlayer* player = aPlayers[playerIdx];
if (!player->IsPlaying()) {
@@ -426,17 +427,17 @@ AddAnimationsForProperty(nsIFrame* aFrame, nsCSSProperty aProperty,
continue;
}
if (!property->mWinsInCascade) {
// We have an animation or transition, but it isn't actually
// winning in the CSS cascade, so we don't want to send it to the
// compositor.
// I believe that anything that changes mWinsInCascade should
// trigger this code again, either because of a restyle that
// changes the properties in question, or because of the
// main-thread style update that results when an animation stops
// filling.
continue;
}
// Note that if mWinsInCascade on property was false,
// GetAnimationOfProperty returns null instead.
// This is what we want, since if we have an animation or transition
// that isn't actually winning in the CSS cascade, we don't want to
// send it to the compositor.
// I believe that anything that changes mWinsInCascade should
// trigger this code again, either because of a restyle that changes
// the properties in question, or because of the main-thread style
// update that results when an animation stops being in effect.
MOZ_ASSERT(property->mWinsInCascade,
"GetAnimationOfProperty already tested mWinsInCascade");
// Don't add animations that are pending when their corresponding
// refresh driver is under test control. This is because any pending
@@ -501,11 +502,9 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
return;
}
AnimationPlayerCollection* transitions =
nsTransitionManager::GetAnimationsForCompositor(content, aProperty,
GetCompositorAnimationOptions::NotifyActiveLayerTracker);
nsTransitionManager::GetAnimationsForCompositor(content, aProperty);
AnimationPlayerCollection* animations =
nsAnimationManager::GetAnimationsForCompositor(content, aProperty,
GetCompositorAnimationOptions::NotifyActiveLayerTracker);
nsAnimationManager::GetAnimationsForCompositor(content, aProperty);
if (!animations && !transitions) {
return;
@@ -562,6 +561,8 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
data = null_t();
}
// When both are running, animations override transitions. We want
// to add the ones that override last.
if (transitions) {
AddAnimationsForProperty(aFrame, aProperty, transitions->mPlayers,
aLayer, data, pending);
+64 -43
View File
@@ -120,9 +120,8 @@ CommonAnimationManager::CheckNeedsRefresh()
AnimationPlayerCollection*
CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent,
nsIAtom* aElementProperty,
nsCSSProperty aProperty,
GetCompositorAnimationOptions aFlags)
nsIAtom* aElementProperty,
nsCSSProperty aProperty)
{
if (!aContent->MayHaveAnimations())
return nullptr;
@@ -137,23 +136,7 @@ CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent,
return nullptr;
}
if (!(aFlags & GetCompositorAnimationOptions::NotifyActiveLayerTracker)) {
return collection;
}
// This animation can be done on the compositor.
// Mark the frame as active, in case we are able to throttle this animation.
nsIFrame* frame = nsLayoutUtils::GetStyleFrame(collection->mElement);
if (frame) {
const auto& info = sLayerAnimationInfo;
for (size_t i = 0; i < ArrayLength(info); i++) {
if (aProperty == info[i].mProperty) {
ActiveLayerTracker::NotifyAnimated(frame, aProperty);
break;
}
}
}
return collection;
}
@@ -416,6 +399,21 @@ CommonAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement,
nsDisplayItem::TYPE_OPACITY,
nsChangeHint_UpdateOpacityLayer } };
/* static */ const CommonAnimationManager::LayerAnimationRecord*
CommonAnimationManager::LayerAnimationRecordFor(nsCSSProperty aProperty)
{
MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
"unexpected property");
const auto& info = sLayerAnimationInfo;
for (size_t i = 0; i < ArrayLength(info); ++i) {
if (aProperty == info[i].mProperty) {
return &info[i];
}
}
return nullptr;
}
#ifdef DEBUG
/* static */ void
CommonAnimationManager::Initialize()
@@ -653,6 +651,30 @@ AnimationPlayerCollection::CanPerformOnCompositorThread(
return true;
}
void
AnimationPlayerCollection::PostUpdateLayerAnimations()
{
nsCSSPropertySet propsHandled;
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
const auto& properties = mPlayers[playerIdx]->GetSource()->Properties();
for (size_t propIdx = properties.Length(); propIdx-- != 0; ) {
nsCSSProperty prop = properties[propIdx].mProperty;
if (nsCSSProps::PropHasFlags(prop,
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR) &&
!propsHandled.HasProperty(prop)) {
propsHandled.AddProperty(prop);
nsChangeHint changeHint = css::CommonAnimationManager::
LayerAnimationRecordFor(prop)->mChangeHint;
dom::Element* element = GetElementToRestyle();
if (element) {
mManager->mPresContext->RestyleManager()->
PostRestyleEvent(element, nsRestyleHint(0), changeHint);
}
}
}
}
}
bool
AnimationPlayerCollection::HasAnimationOfProperty(
nsCSSProperty aProperty) const
@@ -754,6 +776,12 @@ AnimationPlayerCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime,
return;
}
if (!mStyleRuleRefreshTime.IsNull() &&
mStyleRuleRefreshTime == aRefreshTime) {
// mStyleRule may be null and valid, if we have no style to apply.
return;
}
// If we're performing animations on the compositor thread, then we can skip
// most of the work in this method. But even if we are throttled, then we
// have to do the work if an animation is ending in order to get correct end
@@ -773,35 +801,28 @@ AnimationPlayerCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime,
return;
}
// mStyleRule may be null and valid, if we have no style to apply.
if (mStyleRuleRefreshTime.IsNull() ||
mStyleRuleRefreshTime != aRefreshTime) {
mStyleRuleRefreshTime = aRefreshTime;
mStyleRule = nullptr;
// We'll set mNeedsRefreshes to true below in all cases where we need them.
mNeedsRefreshes = false;
if (mManager->IsAnimationManager()) {
// Update cascade results before updating the style rule, since the
// cascade results can influence the style rule.
static_cast<nsAnimationManager*>(mManager)->MaybeUpdateCascadeResults(this);
}
// If multiple animations specify behavior for the same property the
// animation which occurs last in the value of animation-name wins.
// As a result, we iterate from last animation to first and, if a
// property has already been set, we don't leave it.
nsCSSPropertySet properties;
mStyleRuleRefreshTime = aRefreshTime;
mStyleRule = nullptr;
// We'll set mNeedsRefreshes to true below in all cases where we need them.
mNeedsRefreshes = false;
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
mPlayers[playerIdx]->ComposeStyle(mStyleRule, properties,
mNeedsRefreshes);
}
// If multiple animations specify behavior for the same property the
// animation which occurs last in the value of animation-name wins.
// As a result, we iterate from last animation to first and, if a
// property has already been set, we don't leave it.
nsCSSPropertySet properties;
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
mPlayers[playerIdx]->ComposeStyle(mStyleRule, properties, mNeedsRefreshes);
}
mManager->CheckNeedsRefresh();
// If one of our animations just started or stopped filling, we need
// to notify the transition manager. This does the notification a bit
// more than necessary, but it's easier than doing it exactly.
if (mManager->IsAnimationManager()) {
mManager->mPresContext->TransitionManager()->
UpdateCascadeResultsWithAnimations(this);
}
}
bool
+13 -10
View File
@@ -35,14 +35,6 @@ namespace mozilla {
class RestyleTracker;
struct AnimationPlayerCollection;
// Options to set when fetching animations to run on the compositor.
enum class GetCompositorAnimationOptions {
// When fetching compositor animations, if there are any such animations,
// also let the ActiveLayerTracker know at the same time.
NotifyActiveLayerTracker = 1 << 0
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(GetCompositorAnimationOptions)
namespace css {
bool IsGeometricProperty(nsCSSProperty aProperty);
@@ -77,6 +69,9 @@ public:
static void Initialize();
#endif
// NOTE: This can return null after Disconnect().
nsPresContext* PresContext() const { return mPresContext; }
/**
* Notify the manager that the pres context is going away.
*/
@@ -136,6 +131,12 @@ protected:
public:
static const LayerAnimationRecord sLayerAnimationInfo[kLayerRecords];
// Will return non-null for any property with the
// CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR flag; should only be called
// on such properties.
static const LayerAnimationRecord*
LayerAnimationRecordFor(nsCSSProperty aProperty);
protected:
virtual ~CommonAnimationManager();
@@ -160,8 +161,7 @@ protected:
static AnimationPlayerCollection*
GetAnimationsForCompositor(nsIContent* aContent,
nsIAtom* aElementProperty,
nsCSSProperty aProperty,
GetCompositorAnimationOptions aFlags);
nsCSSProperty aProperty);
PRCList mElementCollections;
nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
@@ -302,6 +302,9 @@ struct AnimationPlayerCollection : public PRCList
// (This is useful for determining whether throttle the animation
// (suppress main-thread style updates).)
bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const;
void PostUpdateLayerAnimations();
bool HasAnimationOfProperty(nsCSSProperty aProperty) const;
bool IsForElement() const { // rather than for a pseudo-element
+141
View File
@@ -222,6 +222,32 @@ nsAnimationManager::QueueEvents(AnimationPlayerCollection* aCollection,
}
}
void
nsAnimationManager::MaybeUpdateCascadeResults(AnimationPlayerCollection* aCollection)
{
for (size_t playerIdx = aCollection->mPlayers.Length(); playerIdx-- != 0; ) {
CSSAnimationPlayer* player =
aCollection->mPlayers[playerIdx]->AsCSSAnimationPlayer();
if (player->HasInEffectSource() != player->mInEffectForCascadeResults) {
// Update our own cascade results.
mozilla::dom::Element* element = aCollection->GetElementToRestyle();
if (element) {
nsIFrame* frame = element->GetPrimaryFrame();
if (frame) {
UpdateCascadeResults(frame->StyleContext(), aCollection);
}
}
// Notify the transition manager, whose results might depend on ours.
mPresContext->TransitionManager()->
UpdateCascadeResultsWithAnimations(aCollection);
return;
}
}
}
/* virtual */ size_t
nsAnimationManager::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
@@ -391,6 +417,8 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
newPlayers[newPlayerIdx]->Cancel();
}
UpdateCascadeResults(aStyleContext, collection);
TimeStamp refreshTime = mPresContext->RefreshDriver()->MostRecentRefresh();
UpdateStyleAndEvents(collection, refreshTime,
EnsureStyleRule_IsNotThrottled);
@@ -706,6 +734,119 @@ nsAnimationManager::BuildSegment(InfallibleTArray<AnimationPropertySegment>&
return true;
}
/* static */ void
nsAnimationManager::UpdateCascadeResults(
nsStyleContext* aStyleContext,
AnimationPlayerCollection* aElementAnimations)
{
/*
* Figure out which properties we need to examine.
*/
// size of 2 since we only currently have 2 properties we animate on
// the compositor
nsAutoTArray<nsCSSProperty, 2> propertiesToTrack;
{
nsCSSPropertySet propertiesToTrackAsSet;
for (size_t playerIdx = aElementAnimations->mPlayers.Length();
playerIdx-- != 0; ) {
const AnimationPlayer* player = aElementAnimations->mPlayers[playerIdx];
const Animation* anim = player->GetSource();
if (!anim) {
continue;
}
for (size_t propIdx = 0, propEnd = anim->Properties().Length();
propIdx != propEnd; ++propIdx) {
const AnimationProperty& prop = anim->Properties()[propIdx];
// We only bother setting mWinsInCascade for properties that we
// can animate on the compositor.
if (nsCSSProps::PropHasFlags(prop.mProperty,
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) {
if (!propertiesToTrackAsSet.HasProperty(prop.mProperty)) {
propertiesToTrack.AppendElement(prop.mProperty);
propertiesToTrackAsSet.AddProperty(prop.mProperty);
}
}
}
}
}
/*
* Determine whether those properties are set in things that
* override animations.
*/
nsCSSPropertySet propertiesOverridden;
nsRuleNode::ComputePropertiesOverridingAnimation(propertiesToTrack,
aStyleContext,
propertiesOverridden);
/*
* Set mWinsInCascade based both on what is overridden at levels
* higher than animations and based on one animation overriding
* another.
*
* We iterate from the last animation to the first, just like we do
* when calling ComposeStyle from
* AnimationPlayerCollection::EnsureStyleRuleFor. Later animations
* override earlier ones, so we add properties to the set of
* overridden properties as we encounter them, if the animation is
* currently in effect.
*/
bool changed = false;
for (size_t playerIdx = aElementAnimations->mPlayers.Length();
playerIdx-- != 0; ) {
CSSAnimationPlayer* player =
aElementAnimations->mPlayers[playerIdx]->AsCSSAnimationPlayer();
Animation* anim = player->GetSource();
player->mInEffectForCascadeResults = player->HasInEffectSource();
if (!anim) {
continue;
}
for (size_t propIdx = 0, propEnd = anim->Properties().Length();
propIdx != propEnd; ++propIdx) {
AnimationProperty& prop = anim->Properties()[propIdx];
// We only bother setting mWinsInCascade for properties that we
// can animate on the compositor.
if (nsCSSProps::PropHasFlags(prop.mProperty,
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) {
bool newWinsInCascade =
!propertiesOverridden.HasProperty(prop.mProperty);
if (newWinsInCascade != prop.mWinsInCascade) {
changed = true;
}
prop.mWinsInCascade = newWinsInCascade;
if (prop.mWinsInCascade && player->mInEffectForCascadeResults) {
// This animation is in effect right now, so it overrides
// earlier animations. (For animations that aren't in effect,
// we set mWinsInCascade as though they were, but they don't
// suppress animations lower in the cascade.)
propertiesOverridden.AddProperty(prop.mProperty);
}
}
}
}
if (changed) {
nsPresContext* presContext = aElementAnimations->mManager->PresContext();
presContext->RestyleManager()->IncrementAnimationGeneration();
aElementAnimations->UpdateAnimationGeneration(presContext);
aElementAnimations->PostUpdateLayerAnimations();
// Invalidate our style rule.
aElementAnimations->mNeedsRefreshes = true;
aElementAnimations->mStyleRuleRefreshTime = TimeStamp();
}
}
/* virtual */ void
nsAnimationManager::WillRefresh(mozilla::TimeStamp aTime)
{
+16 -4
View File
@@ -80,6 +80,13 @@ public:
void QueueEvents(EventArray& aEventsToDispatch);
// Is this animation currently in effect for the purposes of computing
// mWinsInCascade. (In general, this can be computed from the timing
// function. This boolean remembers the state as of the last time we
// called UpdateCascadeResults so we know if it changes and we need to
// call UpdateCascadeResults again.)
bool mInEffectForCascadeResults;
protected:
virtual ~CSSAnimationPlayer() { }
virtual css::CommonAnimationManager* GetAnimationManager() const override;
@@ -159,12 +166,10 @@ public:
}
static mozilla::AnimationPlayerCollection*
GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty,
mozilla::GetCompositorAnimationOptions aFlags
= mozilla::GetCompositorAnimationOptions(0))
GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty)
{
return mozilla::css::CommonAnimationManager::GetAnimationsForCompositor(
aContent, nsGkAtoms::animationsProperty, aProperty, aFlags);
aContent, nsGkAtoms::animationsProperty, aProperty);
}
void UpdateStyleAndEvents(mozilla::AnimationPlayerCollection* aEA,
@@ -173,6 +178,9 @@ public:
void QueueEvents(mozilla::AnimationPlayerCollection* aEA,
mozilla::EventArray &aEventsToDispatch);
void MaybeUpdateCascadeResults(mozilla::AnimationPlayerCollection*
aCollection);
// nsIStyleRuleProcessor (parts)
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
const MOZ_MUST_OVERRIDE override;
@@ -239,6 +247,10 @@ private:
mozilla::css::Declaration* aFromDeclaration,
float aToKey, nsStyleContext* aToContext);
static void UpdateCascadeResults(nsStyleContext* aStyleContext,
mozilla::AnimationPlayerCollection*
aElementAnimations);
// The guts of DispatchEvents
void DoDispatchEvents();
+84
View File
@@ -47,6 +47,7 @@
#include "CSSVariableResolver.h"
#include "nsCSSParser.h"
#include "CounterStyleManager.h"
#include "nsCSSPropertySet.h"
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <malloc.h>
@@ -9695,6 +9696,89 @@ nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
return false;
}
/* static */ void
nsRuleNode::ComputePropertiesOverridingAnimation(
const nsTArray<nsCSSProperty>& aProperties,
nsStyleContext* aStyleContext,
nsCSSPropertySet& aPropertiesOverridden)
{
/*
* Set up an nsRuleData with all the structs needed for all of the
* properties in aProperties.
*/
uint32_t structBits = 0;
size_t nprops = 0;
size_t offsets[nsStyleStructID_Length];
for (size_t propIdx = 0, propEnd = aProperties.Length();
propIdx < propEnd; ++propIdx) {
nsCSSProperty prop = aProperties[propIdx];
nsStyleStructID sid = nsCSSProps::kSIDTable[prop];
uint32_t bit = nsCachedStyleData::GetBitForSID(sid);
if (!(structBits & bit)) {
structBits |= bit;
offsets[sid] = nprops;
nprops += nsCSSProps::PropertyCountInStruct(sid);
}
}
void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
AutoCSSValueArray dataArray(dataStorage, nprops);
// We're relying on the use of |aStyleContext| not mutating it!
nsRuleData ruleData(structBits, dataArray.get(),
aStyleContext->PresContext(), aStyleContext);
for (nsStyleStructID sid = nsStyleStructID(0);
sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
if (structBits & nsCachedStyleData::GetBitForSID(sid)) {
ruleData.mValueOffsets[sid] = offsets[sid];
}
}
/*
* Actually walk up the rule tree until we're someplace less
* specific than animations.
*/
for (nsRuleNode* ruleNode = aStyleContext->RuleNode(); ruleNode;
ruleNode = ruleNode->GetParent()) {
nsIStyleRule *rule = ruleNode->GetRule();
if (rule) {
ruleData.mLevel = ruleNode->GetLevel();
ruleData.mIsImportantRule = ruleNode->IsImportantRule();
// Transitions are the only non-!important level overriding
// animations in the cascade ordering. They also don't actually
// override animations, since transitions are suppressed when both
// are present. And since we might not have called
// UpdateCascadeResults (which updates when they are suppressed
// due to the presence of animations for the same element and
// property) for transitions yet (which will make their
// MapRuleInfoInto skip the properties that are currently
// animating), we should skip them explicitly.
if (ruleData.mLevel == nsStyleSet::eTransitionSheet) {
continue;
}
if (!ruleData.mIsImportantRule) {
// We're now equal to or less than the animation level; stop.
break;
}
rule->MapRuleInfoInto(&ruleData);
}
}
/*
* Fill in which properties were overridden.
*/
for (size_t propIdx = 0, propEnd = aProperties.Length();
propIdx < propEnd; ++propIdx) {
nsCSSProperty prop = aProperties[propIdx];
if (ruleData.ValueFor(prop)->GetUnit() != eCSSUnit_Null) {
aPropertiesOverridden.AddProperty(prop);
}
}
}
/* static */
bool
nsRuleNode::ComputeColor(const nsCSSValue& aValue, nsPresContext* aPresContext,
+12 -1
View File
@@ -18,7 +18,7 @@ class nsStyleContext;
struct nsRuleData;
class nsIStyleRule;
struct nsCSSValueList;
class nsCSSPropertySet;
class nsCSSValue;
struct nsCSSRect;
@@ -738,6 +738,17 @@ public:
uint32_t ruleTypeMask,
bool aAuthorColorsAllowed);
/**
* Fill in to aPropertiesOverridden all of the properties in aProperties
* that, for this rule node, have a declaration that is higher than the
* animation level in the CSS Cascade.
*/
static void
ComputePropertiesOverridingAnimation(
const nsTArray<nsCSSProperty>& aProperties,
nsStyleContext* aStyleContext,
nsCSSPropertySet& aPropertiesOverridden);
// Expose this so media queries can use it
static nscoord CalcLengthWithInitialFont(nsPresContext* aPresContext,
const nsCSSValue& aValue);
+13 -4
View File
@@ -615,7 +615,7 @@ nsTransitionManager::UpdateCascadeResultsWithTransitions(
void
nsTransitionManager::UpdateCascadeResultsWithAnimations(
const AnimationPlayerCollection* aAnimations)
AnimationPlayerCollection* aAnimations)
{
AnimationPlayerCollection* transitions =
mPresContext->TransitionManager()->
@@ -641,7 +641,7 @@ nsTransitionManager::UpdateCascadeResultsWithAnimationsToBeDestroyed(
void
nsTransitionManager::UpdateCascadeResults(
AnimationPlayerCollection* aTransitions,
const AnimationPlayerCollection* aAnimations)
AnimationPlayerCollection* aAnimations)
{
if (!aTransitions) {
// Nothing to do.
@@ -656,8 +656,15 @@ nsTransitionManager::UpdateCascadeResults(
// http://dev.w3.org/csswg/css-transitions/#application says that
// transitions do not apply when the same property has a CSS Animation
// on that element (even though animations are lower in the cascade).
if (aAnimations && aAnimations->mStyleRule) {
aAnimations->mStyleRule->AddPropertiesToSet(propertiesUsed);
if (aAnimations) {
TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
// Passing EnsureStyleRule_IsThrottled is OK since we will
// unthrottle when animations are finishing.
aAnimations->EnsureStyleRuleFor(now, EnsureStyleRule_IsThrottled);
if (aAnimations->mStyleRule) {
aAnimations->mStyleRule->AddPropertiesToSet(propertiesUsed);
}
}
// Since we should never have more than one transition for the same
@@ -685,7 +692,9 @@ nsTransitionManager::UpdateCascadeResults(
}
if (changed) {
mPresContext->RestyleManager()->IncrementAnimationGeneration();
aTransitions->UpdateAnimationGeneration(mPresContext);
aTransitions->PostUpdateLayerAnimations();
// Invalidate our style rule.
aTransitions->mStyleRuleRefreshTime = TimeStamp();
+4 -6
View File
@@ -104,12 +104,10 @@ public:
typedef mozilla::AnimationPlayerCollection AnimationPlayerCollection;
static AnimationPlayerCollection*
GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty,
mozilla::GetCompositorAnimationOptions aFlags
= mozilla::GetCompositorAnimationOptions(0))
GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty)
{
return mozilla::css::CommonAnimationManager::GetAnimationsForCompositor(
aContent, nsGkAtoms::transitionsProperty, aProperty, aFlags);
aContent, nsGkAtoms::transitionsProperty, aProperty);
}
/**
@@ -133,11 +131,11 @@ public:
void UpdateCascadeResultsWithTransitions(
AnimationPlayerCollection* aTransitions);
void UpdateCascadeResultsWithAnimations(
const AnimationPlayerCollection* aAnimations);
AnimationPlayerCollection* aAnimations);
void UpdateCascadeResultsWithAnimationsToBeDestroyed(
const AnimationPlayerCollection* aAnimations);
void UpdateCascadeResults(AnimationPlayerCollection* aTransitions,
const AnimationPlayerCollection* aAnimations);
AnimationPlayerCollection* aAnimations);
void SetInAnimationOnlyStyleUpdate(bool aInAnimationOnlyUpdate) {
mInAnimationOnlyStyleUpdate = aInAnimationOnlyUpdate;
+29 -39
View File
@@ -430,48 +430,42 @@ addAsyncAnimTest(function *() {
yield waitForPaintsFlushed();
omta_is("transform", { tx: 32 }, RunningOn.Compositor,
"anim2 + anim1 + anim2, translate at 2s");
// Bug 980769
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.1",
"anim2 + anim1 + anim2, opacity at 2s");
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.1",
"anim2 + anim1 + anim2, opacity at 2s");
// drop one of the anim2, and list anim3 as well, which animates
// the same property as anim2
gDiv.style.animation = "anim1 linear 10s, anim2 linear 20s, anim3 linear 10s";
yield waitForPaintsFlushed();
omta_is("transform", { tx: 32 }, RunningOn.Compositor,
"anim1 + anim2 + anim3, translate at 2s");
// Bug 980769
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0",
"anim1 + anim2 + anim3, opacity at 2s");
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0",
"anim1 + anim2 + anim3, opacity at 2s");
advance_clock(1000);
omta_is("transform", { tx: 48 }, RunningOn.Compositor,
"anim1 + anim2 + anim3, translate at 3s");
// Bug 980769
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.1",
"anim1 + anim2 + anim3, opacity at 3s");
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.1",
"anim1 + anim2 + anim3, opacity at 3s");
// now swap the anim3 and anim2 order
gDiv.style.animation = "anim1 linear 10s, anim3 linear 10s, anim2 linear 20s";
yield waitForPaintsFlushed();
omta_is("transform", { tx: 48 }, RunningOn.Compositor,
"anim1 + anim3 + anim2, translate at 3s");
// Bug 980769
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.15",
"anim1 + anim3 + anim2, opacity at 3s");
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.15",
"anim1 + anim3 + anim2, opacity at 3s");
advance_clock(2000); // (unlike test_animations.html, we seek 2s forwards here
// since at 4s anim2 and anim3 produce the same result so
// we can't tell which won.)
omta_is("transform", { tx: 80 }, RunningOn.Compositor,
"anim1 + anim3 + anim2, translate at 5s");
// Bug 980769
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.25",
"anim1 + anim3 + anim2, opacity at 5s");
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.25",
"anim1 + anim3 + anim2, opacity at 5s");
// swap anim3 and anim2 back
gDiv.style.animation = "anim1 linear 10s, anim2 linear 20s, anim3 linear 10s";
yield waitForPaintsFlushed();
omta_is("transform", { tx: 80 }, RunningOn.Compositor,
"anim1 + anim2 + anim3, translate at 5s");
// Bug 980769
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.3",
"anim1 + anim2 + anim3, opacity at 5s");
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.3",
"anim1 + anim2 + anim3, opacity at 5s");
// seek past end of anim1
advance_clock(5100);
yield waitForPaints();
@@ -494,9 +488,8 @@ addAsyncAnimTest(function *() {
yield waitForPaintsFlushed();
omta_is("transform", { tx: 82 }, RunningOn.Compositor,
"anim1 + anim2 + anim3, translate at 11s with fill mode");
// Bug 980769 - We should get 0.9 but instead
todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.9",
"anim1 + anim2 + anim3, opacity at 11s");
is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.9",
"anim1 + anim2 + anim3, opacity at 11s");
done_div();
});
@@ -1527,9 +1520,8 @@ addAsyncAnimTest(function *() {
new_div("animation: always_fifty 1s linear infinite; " +
"transform: translate(200px) ! important;");
yield waitForPaintsFlushed();
// Bug 847287 - off main thread animations don't cascade correctly
omta_todo_is("transform", { tx: 200 }, RunningOn.TodoMainThread,
"important author rules override animations");
omta_is("transform", { tx: 200 }, RunningOn.MainThread,
"important author rules override animations");
done_div();
});
@@ -1721,11 +1713,9 @@ addAsyncAnimTest(function *() {
"animation-timing-function: linear; " +
"animation-delay: -250ms, -250ms, -750ms, -500ms;");
yield waitForPaintsFlushed();
// Bug 980769 - off main thread animations incorrectly handle multiple
// animations of the same property and element
omta_todo_is("opacity", 0.75, RunningOn.Compositor,
"animation-name list length is the length that matters, " +
"and the last occurrence of a name wins");
omta_is("opacity", 0.75, RunningOn.Compositor,
"animation-name list length is the length that matters, " +
"and the last occurrence of a name wins");
omta_is("transform", { ty: 25 }, RunningOn.Compositor,
"animation-name list length is the length that matters");
done_div();
@@ -2108,35 +2098,35 @@ addAsyncAnimTest(function *() {
new_div("animation: anim2 1s linear forwards; opacity: 0.5 ! important");
yield waitForPaintsFlushed();
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
omta_is("opacity", 0.5, RunningOn.MainThread,
"opacity overriding animation at start (0s)");
advance_clock(750);
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
omta_is("opacity", 0.5, RunningOn.MainThread,
"opacity overriding animation while running (750ms)");
advance_clock(1000);
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
omta_is("opacity", 0.5, RunningOn.MainThread,
"opacity overriding animation while filling (1750ms)");
done_div();
new_div("animation: anim2 1s linear; opacity: 0.5 ! important");
yield waitForPaintsFlushed();
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
omta_is("opacity", 0.5, RunningOn.MainThread,
"opacity overriding animation at start (0s)");
advance_clock(750);
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
omta_is("opacity", 0.5, RunningOn.MainThread,
"opacity overriding animation while running (750ms)");
advance_clock(1000);
omta_todo_is("opacity", 0.5, RunningOn.TodoMainThread,
omta_is("opacity", 0.5, RunningOn.MainThread,
"opacity overriding animation after complete (1750ms)");
done_div();
// One animation overriding another, and then not.
new_div("animation: anim2 1s linear, anim3 500ms linear reverse");
yield waitForPaintsFlushed();
omta_todo_is("opacity", 1, RunningOn.Compositor,
omta_is("opacity", 1, RunningOn.Compositor,
"anim3 overriding anim2 at start (0s)");
advance_clock(400);
omta_todo_is("opacity", 0.2, RunningOn.Compositor,
omta_is("opacity", 0.2, RunningOn.Compositor,
"anim3 overriding anim2 at 400ms");
advance_clock(200);
// Wait for paints because we're resending animations to the
@@ -2158,7 +2148,7 @@ addAsyncAnimTest(function *() {
"anim2 at 300ms");
gDiv.style.animation = "anim2 1s steps(8, end), anim3 500ms steps(4, end)";
yield waitForPaintsFlushed();
omta_todo_is("opacity", 0, RunningOn.Compositor,
omta_is("opacity", 0, RunningOn.Compositor,
"anim3 overriding anim2 at 300ms");
advance_clock(475);
omta_is("opacity", 0.75, RunningOn.Compositor,
@@ -2186,7 +2176,7 @@ addAsyncAnimTest(function *() {
"anim2 at 300ms");
gDiv.style.animation = "anim2 1s steps(8, end), anim3 500ms steps(4, end)";
yield waitForPaintsFlushed();
omta_todo_is("opacity", 0, RunningOn.Compositor,
omta_is("opacity", 0, RunningOn.Compositor,
"anim3 overriding anim2 at 300ms");
advance_clock(475);
omta_is("opacity", 0.75, RunningOn.Compositor,
+3 -1
View File
@@ -4238,6 +4238,9 @@ pref("webgl.enable-draft-extensions", false);
pref("webgl.enable-privileged-extensions", false);
pref("webgl.bypass-shader-validation", false);
pref("webgl.enable-prototype-webgl2", false);
pref("webgl.disable-fail-if-major-performance-caveat", false);
pref("gl.require-hardware", false);
#ifdef XP_WIN
pref("webgl.angle.try-d3d11", true);
pref("webgl.angle.force-d3d11", false);
@@ -4379,7 +4382,6 @@ pref("gfx.xrender.enabled",true);
// Whether to disable the automatic detection and use of direct2d.
pref("gfx.direct2d.disabled", false);
pref("gfx.direct2d.use1_1", true);
pref("gfx.direct2d.allow-fallback", false);
// Whether to attempt to enable Direct2D regardless of automatic detection or
// blacklisting