diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp index a1e5c4792d..be99491bf8 100644 --- a/dom/canvas/ClientWebGLContext.cpp +++ b/dom/canvas/ClientWebGLContext.cpp @@ -4,6 +4,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ClientWebGLContext.h" +#include "MaskConfig.hpp" +#include +#include #include @@ -750,6 +753,13 @@ void ClientWebGLContext::SetUnpackColorSpace( Run(*mUnpackColorSpace); } +bool ClientWebGLContext::MBoolVal(const std::string& key, bool defaultValue) { + if (auto value = MaskConfig::GetAttribute(key, mIsWebGL2); + value.has_value()) + return value.value(); + return defaultValue; +} + void ClientWebGLContext::GetContextAttributes( dom::Nullable& retval) { retval.SetNull(); @@ -760,15 +770,40 @@ void ClientWebGLContext::GetContextAttributes( const auto& options = mNotLost->info.options; - result.mAlpha.Construct(options.alpha); - result.mDepth = options.depth; - result.mStencil = options.stencil; - result.mAntialias.Construct(options.antialias); - result.mPremultipliedAlpha = options.premultipliedAlpha; - result.mPreserveDrawingBuffer = options.preserveDrawingBuffer; - result.mFailIfMajorPerformanceCaveat = options.failIfMajorPerformanceCaveat; - result.mPowerPreference = options.powerPreference; - result.mForceSoftwareRendering = options.forceSoftwareRendering; + result.mAlpha.Construct(MBoolVal("alpha", options.alpha)); + result.mDepth = MBoolVal("depth", options.depth); + result.mStencil = MBoolVal("stencil", options.stencil); + result.mAntialias.Construct(MBoolVal("antialias", options.antialias)); + result.mPremultipliedAlpha = MBoolVal( + "webGl:contextAttributes.premultipliedAlpha", options.premultipliedAlpha); + result.mPreserveDrawingBuffer = + MBoolVal("preserveDrawingBuffer", options.preserveDrawingBuffer); + result.mFailIfMajorPerformanceCaveat = MBoolVal( + "failIfMajorPerformanceCaveat", options.failIfMajorPerformanceCaveat); + if (auto value = + MaskConfig::GetAttribute("powerPreference", mIsWebGL2); + value.has_value()) { + // Convert to enum + switch (value.value()[0]) { + case 'd': + result.mPowerPreference = dom::WebGLPowerPreference::Default; + break; + case 'l': + result.mPowerPreference = dom::WebGLPowerPreference::Low_power; + break; + case 'h': + result.mPowerPreference = dom::WebGLPowerPreference::High_performance; + break; + default: + // Invalid value + result.mPowerPreference = options.powerPreference; + break; + } + } else { + result.mPowerPreference = options.powerPreference; + } + result.mForceSoftwareRendering = MBoolVal( + "forceSoftwareRendering", options.forceSoftwareRendering); } // ----------------------- @@ -986,18 +1021,28 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) { std::unordered_map webgl::MakeIsEnabledMap(const bool webgl2) { auto ret = std::unordered_map{}; - ret[LOCAL_GL_BLEND] = false; - ret[LOCAL_GL_CULL_FACE] = false; - ret[LOCAL_GL_DEPTH_TEST] = false; - ret[LOCAL_GL_DITHER] = true; - ret[LOCAL_GL_POLYGON_OFFSET_FILL] = false; - ret[LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE] = false; - ret[LOCAL_GL_SAMPLE_COVERAGE] = false; - ret[LOCAL_GL_SCISSOR_TEST] = false; - ret[LOCAL_GL_STENCIL_TEST] = false; + ret[LOCAL_GL_BLEND] = + MaskConfig::MParamGL(LOCAL_GL_BLEND, false, webgl2); + ret[LOCAL_GL_CULL_FACE] = + MaskConfig::MParamGL(LOCAL_GL_CULL_FACE, false, webgl2); + ret[LOCAL_GL_DEPTH_TEST] = + MaskConfig::MParamGL(LOCAL_GL_DEPTH_TEST, false, webgl2); + ret[LOCAL_GL_DITHER] = + MaskConfig::MParamGL(LOCAL_GL_DITHER, true, webgl2); + ret[LOCAL_GL_POLYGON_OFFSET_FILL] = + MaskConfig::MParamGL(LOCAL_GL_POLYGON_OFFSET_FILL, false, webgl2); + ret[LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE] = MaskConfig::MParamGL( + LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false, webgl2); + ret[LOCAL_GL_SAMPLE_COVERAGE] = + MaskConfig::MParamGL(LOCAL_GL_SAMPLE_COVERAGE, false, webgl2); + ret[LOCAL_GL_SCISSOR_TEST] = + MaskConfig::MParamGL(LOCAL_GL_SCISSOR_TEST, false, webgl2); + ret[LOCAL_GL_STENCIL_TEST] = + MaskConfig::MParamGL(LOCAL_GL_STENCIL_TEST, false, webgl2); if (webgl2) { - ret[LOCAL_GL_RASTERIZER_DISCARD] = false; + ret[LOCAL_GL_RASTERIZER_DISCARD] = + MaskConfig::MParamGL(LOCAL_GL_RASTERIZER_DISCARD, false, webgl2); } return ret; @@ -2066,6 +2111,57 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, const auto& state = State(); // - + std::optional< + std::variant> + data; + data = MaskConfig::GLParam(pname, mIsWebGL2); + + if (data.has_value()) { + const auto& value = data.value(); + if (std::holds_alternative(value)) { + retval.set(JS::NumberValue(double(std::get(value)))); + return; + } + if (std::holds_alternative(value)) { + retval.set(JS::NumberValue(std::get(value))); + return; + } + if (std::holds_alternative(value)) { + retval.set(JS::BooleanValue(std::get(value))); + return; + } + if (std::holds_alternative(value)) { + retval.set(StringValue(cx, std::get(value), rv)); + return; + } + if (std::holds_alternative(value)) { + retval.set(JS::NullValue()); + return; + } + } + // If the value is not array (we will handle those later), + // then check if it should be blocked. + switch (pname) { + case LOCAL_GL_DEPTH_RANGE: + case LOCAL_GL_ALIASED_POINT_SIZE_RANGE: + case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: + case LOCAL_GL_COLOR_CLEAR_VALUE: + case LOCAL_GL_BLEND_COLOR: + case LOCAL_GL_MAX_VIEWPORT_DIMS: + case LOCAL_GL_SCISSOR_BOX: + case LOCAL_GL_VIEWPORT: + case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: + case LOCAL_GL_COLOR_WRITEMASK: + case dom::WEBGL_debug_renderer_info_Binding::UNMASKED_RENDERER_WEBGL: + case dom::WEBGL_debug_renderer_info_Binding::UNMASKED_VENDOR_WEBGL: + break; + default: + if (MaskConfig::GetBool(mIsWebGL2 ? "webGl2:parameters:blockIfNotDefined" + : "webGl:parameters:blockIfNotDefined")) { + retval.set(JS::NullValue()); + return; + } + } const auto fnSetRetval_Buffer = [&](const GLenum target) { const auto buffer = *MaybeFind(state.mBoundBufferByTarget, target); @@ -2171,49 +2267,84 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, // 2 floats case LOCAL_GL_DEPTH_RANGE: - retval.set(Create(cx, this, state.mDepthRange, rv)); + retval.set(Create( + cx, this, + MaskConfig::MParamGL>(pname, state.mDepthRange, + mIsWebGL2), + rv)); return; case LOCAL_GL_ALIASED_POINT_SIZE_RANGE: - retval.set( - Create(cx, this, limits.pointSizeRange, rv)); + retval.set(Create( + cx, this, + MaskConfig::MParamGL>( + pname, limits.pointSizeRange, mIsWebGL2), + rv)); return; case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: - retval.set( - Create(cx, this, limits.lineWidthRange, rv)); + retval.set(Create( + cx, this, + MaskConfig::MParamGL>( + pname, limits.lineWidthRange, mIsWebGL2), + rv)); return; // 4 floats case LOCAL_GL_COLOR_CLEAR_VALUE: - retval.set(Create(cx, this, state.mClearColor, rv)); + retval.set(Create( + cx, this, + MaskConfig::MParamGL>(pname, state.mClearColor, + mIsWebGL2), + rv)); return; case LOCAL_GL_BLEND_COLOR: - retval.set(Create(cx, this, state.mBlendColor, rv)); + retval.set(Create( + cx, this, + MaskConfig::MParamGL>(pname, state.mBlendColor, + mIsWebGL2), + rv)); return; // 2 ints case LOCAL_GL_MAX_VIEWPORT_DIMS: { auto maxViewportDim = BitwiseCast(limits.maxViewportDim); const auto dims = std::array{maxViewportDim, maxViewportDim}; - retval.set(Create(cx, this, dims, rv)); + retval.set(Create( + cx, this, + MaskConfig::MParamGL>(pname, dims, + mIsWebGL2), + rv)); return; } // 4 ints case LOCAL_GL_SCISSOR_BOX: - retval.set(Create(cx, this, state.mScissor, rv)); + retval.set(Create( + cx, this, + MaskConfig::MParamGL>(pname, state.mScissor, + mIsWebGL2), + rv)); return; case LOCAL_GL_VIEWPORT: - retval.set(Create(cx, this, state.mViewport, rv)); + retval.set(Create( + cx, this, + MaskConfig::MParamGL>(pname, state.mViewport, + mIsWebGL2), + rv)); return; - // any case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: - retval.set(Create(cx, this, - state.mCompressedTextureFormats, rv)); + std::vector compressedTextureUint32( + state.mCompressedTextureFormats.begin(), + state.mCompressedTextureFormats.end()); + retval.set(Create( + cx, this, + MaskConfig::MParamGLVector(pname, compressedTextureUint32, + mIsWebGL2), + rv)); return; } @@ -2393,6 +2524,10 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, switch (pname) { case dom::WEBGL_debug_renderer_info_Binding::UNMASKED_RENDERER_WEBGL: + if (auto value = MaskConfig::GetString("webGl:renderer")) { + ret = Some(value.value()); + break; + } ret = GetUnmaskedRenderer(); if (ret && StaticPrefs::webgl_sanitize_unmasked_renderer()) { *ret = webgl::SanitizeRenderer(*ret); @@ -2400,6 +2535,10 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, break; case dom::WEBGL_debug_renderer_info_Binding::UNMASKED_VENDOR_WEBGL: + if (auto value = MaskConfig::GetString("webGl:vendor")) { + ret = Some(value.value()); + break; + } ret = GetUnmaskedVendor(); break; @@ -2490,7 +2629,9 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, case LOCAL_GL_COLOR_WRITEMASK: { const auto mask = uint8_t(*maybe); const auto bs = std::bitset<4>(mask); - const auto src = std::array{bs[0], bs[1], bs[2], bs[3]}; + const auto src = MaskConfig::MParamGL>( + pname, std::array{bs[0], bs[1], bs[2], bs[3]}, + mIsWebGL2); JS::Rooted arr(cx); if (!dom::ToJSValue(cx, src.data(), src.size(), &arr)) { rv = NS_ERROR_OUT_OF_MEMORY; @@ -2873,6 +3014,24 @@ ClientWebGLContext::GetShaderPrecisionFormat(const GLenum shadertype, const GLenum precisiontype) { if (IsContextLost()) return nullptr; const auto info = [&]() { + // Check for spoofed value + if (auto value = + MaskConfig::MShaderData(shadertype, precisiontype, mIsWebGL2)) { + const auto& format = value.value(); + return Some(webgl::ShaderPrecisionFormat{ + format[0], // rangeMin + format[1], // rangeMax + format[2] // precision + }); + } + // Check if block if not defined is on + if (MaskConfig::GetBool( + mIsWebGL2 ? "webGl2:shaderPrecisionFormats:blockIfNotDefined" + : "webGl:shaderPrecisionFormats:blockIfNotDefined")) { + Maybe ret; + return ret; + } + const auto& inProcess = mNotLost->inProcess; if (inProcess) { return inProcess->GetShaderPrecisionFormat(shadertype, precisiontype); @@ -5853,6 +6012,17 @@ bool ClientWebGLContext::IsSupported(const WebGLExtensionID ext, return false; } + if (std::vector maskValues = + MaskConfig::GetStringList(mIsWebGL2 ? "webGl2:supportedExtensions" + : "webGl:supportedExtensions"); + !maskValues.empty()) { + if (std::find(maskValues.begin(), maskValues.end(), + GetExtensionName(ext)) != maskValues.end()) { + return true; + } + return false; + } + const auto& limits = Limits(); return limits.supportedExtensions[ext]; } @@ -5864,6 +6034,18 @@ void ClientWebGLContext::GetSupportedExtensions( if (!mNotLost) return; auto& retarr = retval.SetValue(); + + // Implement separately to prevent O(n^2) timing + if (std::vector maskValues = + MaskConfig::GetStringList(mIsWebGL2 ? "webGl2:supportedExtensions" + : "webGl:supportedExtensions"); + !maskValues.empty()) { + for (const auto& ext : maskValues) { + retarr.AppendElement(NS_ConvertUTF8toUTF16(ext)); + } + return; + } + for (const auto i : MakeEnumeratedRange(WebGLExtensionID::Max)) { if (!IsSupported(i, callerType)) continue; diff --git a/dom/canvas/ClientWebGLContext.h b/dom/canvas/ClientWebGLContext.h index 62957ee445..dfb2b8ff53 100644 --- a/dom/canvas/ClientWebGLContext.h +++ b/dom/canvas/ClientWebGLContext.h @@ -1074,6 +1074,9 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, // - + // Helper to get booleans set in MaskConfig + bool MBoolVal(const std::string& key, bool defaultValue); + void GetContextAttributes(dom::Nullable& retval); private: diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index 3a533d36d1..41d74d9b3f 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -221,3 +221,6 @@ if CONFIG["CC_TYPE"] == "gcc": # Add libFuzzer configuration directives include("/tools/fuzzing/libfuzzer-config.mozbuild") + +# DOM Mask +LOCAL_INCLUDES += ["/camoucfg"] \ No newline at end of file