Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/canvas/WebGLContextExtensions.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "WebGLContext.h"
7
#include "WebGLContextUtils.h"
8
#include "WebGLExtensions.h"
9
#include "gfxPrefs.h"
10
#include "GLContext.h"
11
12
#include "nsString.h"
13
#include "nsContentUtils.h"
14
#include "mozilla/Preferences.h"
15
#include "mozilla/dom/BindingDeclarations.h"
16
#include "AccessCheck.h"
17
18
namespace mozilla {
19
20
/*static*/ const char*
21
WebGLContext::GetExtensionString(WebGLExtensionID ext)
22
0
{
23
0
    typedef EnumeratedArray<WebGLExtensionID, WebGLExtensionID::Max,
24
0
                            const char*> names_array_t;
25
0
26
0
    static names_array_t sExtensionNamesEnumeratedArray;
27
0
    static bool initialized = false;
28
0
29
0
    if (!initialized) {
30
0
        initialized = true;
31
0
32
0
#define WEBGL_EXTENSION_IDENTIFIER(x) \
33
0
        sExtensionNamesEnumeratedArray[WebGLExtensionID::x] = #x;
34
0
35
0
        WEBGL_EXTENSION_IDENTIFIER(ANGLE_instanced_arrays)
36
0
        WEBGL_EXTENSION_IDENTIFIER(EXT_blend_minmax)
37
0
        WEBGL_EXTENSION_IDENTIFIER(EXT_color_buffer_float)
38
0
        WEBGL_EXTENSION_IDENTIFIER(EXT_color_buffer_half_float)
39
0
        WEBGL_EXTENSION_IDENTIFIER(EXT_frag_depth)
40
0
        WEBGL_EXTENSION_IDENTIFIER(EXT_shader_texture_lod)
41
0
        WEBGL_EXTENSION_IDENTIFIER(EXT_sRGB)
42
0
        WEBGL_EXTENSION_IDENTIFIER(EXT_texture_filter_anisotropic)
43
0
        WEBGL_EXTENSION_IDENTIFIER(EXT_disjoint_timer_query)
44
0
        WEBGL_EXTENSION_IDENTIFIER(MOZ_debug)
45
0
        WEBGL_EXTENSION_IDENTIFIER(OES_element_index_uint)
46
0
        WEBGL_EXTENSION_IDENTIFIER(OES_standard_derivatives)
47
0
        WEBGL_EXTENSION_IDENTIFIER(OES_texture_float)
48
0
        WEBGL_EXTENSION_IDENTIFIER(OES_texture_float_linear)
49
0
        WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float)
50
0
        WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float_linear)
51
0
        WEBGL_EXTENSION_IDENTIFIER(OES_vertex_array_object)
52
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_color_buffer_float)
53
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_astc)
54
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_atc)
55
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc)
56
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc1)
57
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_pvrtc)
58
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc)
59
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc_srgb)
60
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_renderer_info)
61
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_shaders)
62
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_depth_texture)
63
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_draw_buffers)
64
0
        WEBGL_EXTENSION_IDENTIFIER(WEBGL_lose_context)
65
0
66
0
#undef WEBGL_EXTENSION_IDENTIFIER
67
0
    }
68
0
69
0
    return sExtensionNamesEnumeratedArray[ext];
70
0
}
71
72
bool
73
WebGLContext::IsExtensionEnabled(WebGLExtensionID ext) const
74
0
{
75
0
    return mExtensions[ext];
76
0
}
77
78
bool WebGLContext::IsExtensionSupported(dom::CallerType callerType,
79
                                        WebGLExtensionID ext) const
80
0
{
81
0
    bool allowPrivilegedExts = false;
82
0
83
0
    // Chrome contexts need access to debug information even when
84
0
    // webgl.disable-extensions is set. This is used in the graphics
85
0
    // section of about:support
86
0
    if (callerType == dom::CallerType::System) {
87
0
        allowPrivilegedExts = true;
88
0
    }
89
0
90
0
    if (gfxPrefs::WebGLPrivilegedExtensionsEnabled()) {
91
0
        allowPrivilegedExts = true;
92
0
    }
93
0
94
0
    if (allowPrivilegedExts) {
95
0
        switch (ext) {
96
0
        case WebGLExtensionID::EXT_disjoint_timer_query:
97
0
            return WebGLExtensionDisjointTimerQuery::IsSupported(this);
98
0
        case WebGLExtensionID::MOZ_debug:
99
0
            return true;
100
0
        case WebGLExtensionID::WEBGL_debug_renderer_info:
101
0
            return true;
102
0
        case WebGLExtensionID::WEBGL_debug_shaders:
103
0
            return true;
104
0
        default:
105
0
            // For warnings-as-errors.
106
0
            break;
107
0
        }
108
0
    }
109
0
110
0
    return IsExtensionSupported(ext);
111
0
}
112
113
bool
114
WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
115
0
{
116
0
    if (mDisableExtensions)
117
0
        return false;
118
0
119
0
    // Extensions for both WebGL 1 and 2.
120
0
    switch (ext) {
121
0
    // In alphabetical order
122
0
    // EXT_
123
0
    case WebGLExtensionID::EXT_texture_filter_anisotropic:
124
0
        return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);
125
0
126
0
    // OES_
127
0
    case WebGLExtensionID::OES_texture_float_linear:
128
0
        return gl->IsSupported(gl::GLFeature::texture_float_linear);
129
0
130
0
    // WEBGL_
131
0
    case WebGLExtensionID::WEBGL_compressed_texture_astc:
132
0
        return WebGLExtensionCompressedTextureASTC::IsSupported(this);
133
0
    case WebGLExtensionID::WEBGL_compressed_texture_atc:
134
0
        return gl->IsExtensionSupported(gl::GLContext::AMD_compressed_ATC_texture);
135
0
    case WebGLExtensionID::WEBGL_compressed_texture_etc:
136
0
        return gl->IsSupported(gl::GLFeature::ES3_compatibility) &&
137
0
               !gl->IsANGLE();
138
0
    case WebGLExtensionID::WEBGL_compressed_texture_etc1:
139
0
        return gl->IsExtensionSupported(gl::GLContext::OES_compressed_ETC1_RGB8_texture) &&
140
0
               !gl->IsANGLE();
141
0
    case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
142
0
        return gl->IsExtensionSupported(gl::GLContext::IMG_texture_compression_pvrtc);
143
0
    case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
144
0
        return WebGLExtensionCompressedTextureS3TC::IsSupported(this);
145
0
    case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb:
146
0
        return WebGLExtensionCompressedTextureS3TC_SRGB::IsSupported(this);
147
0
    case WebGLExtensionID::WEBGL_debug_renderer_info:
148
0
        return Preferences::GetBool("webgl.enable-debug-renderer-info", false) &&
149
0
               !nsContentUtils::ShouldResistFingerprinting();
150
0
    case WebGLExtensionID::WEBGL_debug_shaders:
151
0
        return !nsContentUtils::ShouldResistFingerprinting();
152
0
    case WebGLExtensionID::WEBGL_lose_context:
153
0
        // We always support this extension.
154
0
        return true;
155
0
156
0
    default:
157
0
        // For warnings-as-errors.
158
0
        break;
159
0
    }
160
0
161
0
    if (IsWebGL2()) {
162
0
        // WebGL2-only extensions
163
0
        switch (ext) {
164
0
        // EXT_
165
0
        case WebGLExtensionID::EXT_color_buffer_float:
166
0
            return WebGLExtensionEXTColorBufferFloat::IsSupported(this);
167
0
168
0
        default:
169
0
            // For warnings-as-errors.
170
0
            break;
171
0
        }
172
0
    } else {
173
0
        // WebGL1-only extensions
174
0
        switch (ext) {
175
0
        // ANGLE_
176
0
        case WebGLExtensionID::ANGLE_instanced_arrays:
177
0
            return WebGLExtensionInstancedArrays::IsSupported(this);
178
0
179
0
        // EXT_
180
0
        case WebGLExtensionID::EXT_blend_minmax:
181
0
            return WebGLExtensionBlendMinMax::IsSupported(this);
182
0
        case WebGLExtensionID::EXT_color_buffer_half_float:
183
0
            return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
184
0
        case WebGLExtensionID::EXT_frag_depth:
185
0
            return WebGLExtensionFragDepth::IsSupported(this);
186
0
        case WebGLExtensionID::EXT_shader_texture_lod:
187
0
            return gl->IsSupported(gl::GLFeature::shader_texture_lod);
188
0
        case WebGLExtensionID::EXT_sRGB:
189
0
            return WebGLExtensionSRGB::IsSupported(this);
190
0
191
0
        // OES_
192
0
        case WebGLExtensionID::OES_element_index_uint:
193
0
            return gl->IsSupported(gl::GLFeature::element_index_uint);
194
0
        case WebGLExtensionID::OES_standard_derivatives:
195
0
            return gl->IsSupported(gl::GLFeature::standard_derivatives);
196
0
        case WebGLExtensionID::OES_texture_float:
197
0
            return WebGLExtensionTextureFloat::IsSupported(this);
198
0
        case WebGLExtensionID::OES_texture_half_float:
199
0
            return WebGLExtensionTextureHalfFloat::IsSupported(this);
200
0
        case WebGLExtensionID::OES_texture_half_float_linear:
201
0
            return gl->IsSupported(gl::GLFeature::texture_half_float_linear);
202
0
203
0
        case WebGLExtensionID::OES_vertex_array_object:
204
0
            return true;
205
0
206
0
        // WEBGL_
207
0
        case WebGLExtensionID::WEBGL_color_buffer_float:
208
0
            return WebGLExtensionColorBufferFloat::IsSupported(this);
209
0
        case WebGLExtensionID::WEBGL_depth_texture:
210
0
            // WEBGL_depth_texture supports DEPTH_STENCIL textures
211
0
            if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil))
212
0
                return false;
213
0
214
0
            return gl->IsSupported(gl::GLFeature::depth_texture) ||
215
0
                   gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture);
216
0
        case WebGLExtensionID::WEBGL_draw_buffers:
217
0
            return WebGLExtensionDrawBuffers::IsSupported(this);
218
0
        default:
219
0
            // For warnings-as-errors.
220
0
            break;
221
0
        }
222
0
223
0
        if (gfxPrefs::WebGLDraftExtensionsEnabled()) {
224
0
            /*
225
0
            switch (ext) {
226
0
            default:
227
0
                // For warnings-as-errors.
228
0
                break;
229
0
            }
230
0
            */
231
0
        }
232
0
    }
233
0
234
0
    return false;
235
0
}
236
237
static bool
238
CompareWebGLExtensionName(const nsACString& name, const char* other)
239
0
{
240
0
    return name.Equals(other, nsCaseInsensitiveCStringComparator());
241
0
}
242
243
WebGLExtensionBase*
244
WebGLContext::EnableSupportedExtension(dom::CallerType callerType,
245
                                       WebGLExtensionID ext)
246
0
{
247
0
    if (!IsExtensionEnabled(ext)) {
248
0
        if (!IsExtensionSupported(callerType, ext))
249
0
            return nullptr;
250
0
251
0
        EnableExtension(ext);
252
0
    }
253
0
254
0
    return mExtensions[ext];
255
0
}
256
257
void
258
WebGLContext::GetExtension(JSContext* cx,
259
                           const nsAString& wideName,
260
                           JS::MutableHandle<JSObject*> retval,
261
                           dom::CallerType callerType,
262
                           ErrorResult& rv)
263
0
{
264
0
    retval.set(nullptr);
265
0
    const FuncScope funcScope(*this, "getExtension");
266
0
    if (IsContextLost())
267
0
        return;
268
0
269
0
    NS_LossyConvertUTF16toASCII name(wideName);
270
0
271
0
    WebGLExtensionID ext = WebGLExtensionID::Unknown;
272
0
273
0
    // step 1: figure what extension is wanted
274
0
    for (size_t i = 0; i < size_t(WebGLExtensionID::Max); i++) {
275
0
        WebGLExtensionID extension = WebGLExtensionID(i);
276
0
277
0
        if (CompareWebGLExtensionName(name, GetExtensionString(extension))) {
278
0
            ext = extension;
279
0
            break;
280
0
        }
281
0
    }
282
0
283
0
    if (ext == WebGLExtensionID::Unknown)
284
0
        return;
285
0
286
0
    // step 2: check if the extension is supported
287
0
    if (!IsExtensionSupported(callerType, ext))
288
0
        return;
289
0
290
0
    // step 3: if the extension hadn't been previously been created, create it now, thus enabling it
291
0
    WebGLExtensionBase* extObj = EnableSupportedExtension(callerType, ext);
292
0
    if (!extObj)
293
0
        return;
294
0
295
0
    // Step 4: Enable any implied extensions.
296
0
    switch (ext) {
297
0
    case WebGLExtensionID::OES_texture_float:
298
0
        EnableSupportedExtension(callerType,
299
0
                                 WebGLExtensionID::WEBGL_color_buffer_float);
300
0
        break;
301
0
302
0
    case WebGLExtensionID::OES_texture_half_float:
303
0
        EnableSupportedExtension(callerType,
304
0
                                 WebGLExtensionID::EXT_color_buffer_half_float);
305
0
        break;
306
0
307
0
    default:
308
0
        break;
309
0
    }
310
0
311
0
    retval.set(WebGLObjectAsJSObject(cx, extObj, rv));
312
0
}
313
314
void
315
WebGLContext::EnableExtension(WebGLExtensionID ext)
316
0
{
317
0
    MOZ_ASSERT(IsExtensionEnabled(ext) == false);
318
0
319
0
    WebGLExtensionBase* obj = nullptr;
320
0
    switch (ext) {
321
0
    // ANGLE_
322
0
    case WebGLExtensionID::ANGLE_instanced_arrays:
323
0
        obj = new WebGLExtensionInstancedArrays(this);
324
0
        break;
325
0
326
0
    // EXT_
327
0
    case WebGLExtensionID::EXT_blend_minmax:
328
0
        obj = new WebGLExtensionBlendMinMax(this);
329
0
        break;
330
0
    case WebGLExtensionID::EXT_color_buffer_float:
331
0
        obj = new WebGLExtensionEXTColorBufferFloat(this);
332
0
        break;
333
0
    case WebGLExtensionID::EXT_color_buffer_half_float:
334
0
        obj = new WebGLExtensionColorBufferHalfFloat(this);
335
0
        break;
336
0
    case WebGLExtensionID::EXT_disjoint_timer_query:
337
0
        obj = new WebGLExtensionDisjointTimerQuery(this);
338
0
        break;
339
0
    case WebGLExtensionID::EXT_frag_depth:
340
0
        obj = new WebGLExtensionFragDepth(this);
341
0
        break;
342
0
    case WebGLExtensionID::EXT_shader_texture_lod:
343
0
        obj = new WebGLExtensionShaderTextureLod(this);
344
0
        break;
345
0
    case WebGLExtensionID::EXT_sRGB:
346
0
        obj = new WebGLExtensionSRGB(this);
347
0
        break;
348
0
    case WebGLExtensionID::EXT_texture_filter_anisotropic:
349
0
        obj = new WebGLExtensionTextureFilterAnisotropic(this);
350
0
        break;
351
0
352
0
    // MOZ_
353
0
    case WebGLExtensionID::MOZ_debug:
354
0
        obj = new WebGLExtensionMOZDebug(this);
355
0
        break;
356
0
357
0
    // OES_
358
0
    case WebGLExtensionID::OES_element_index_uint:
359
0
        obj = new WebGLExtensionElementIndexUint(this);
360
0
        break;
361
0
    case WebGLExtensionID::OES_standard_derivatives:
362
0
        obj = new WebGLExtensionStandardDerivatives(this);
363
0
        break;
364
0
    case WebGLExtensionID::OES_texture_float:
365
0
        obj = new WebGLExtensionTextureFloat(this);
366
0
        break;
367
0
    case WebGLExtensionID::OES_texture_float_linear:
368
0
        obj = new WebGLExtensionTextureFloatLinear(this);
369
0
        break;
370
0
    case WebGLExtensionID::OES_texture_half_float:
371
0
        obj = new WebGLExtensionTextureHalfFloat(this);
372
0
        break;
373
0
    case WebGLExtensionID::OES_texture_half_float_linear:
374
0
        obj = new WebGLExtensionTextureHalfFloatLinear(this);
375
0
        break;
376
0
    case WebGLExtensionID::OES_vertex_array_object:
377
0
        obj = new WebGLExtensionVertexArray(this);
378
0
        break;
379
0
380
0
    // WEBGL_
381
0
    case WebGLExtensionID::WEBGL_color_buffer_float:
382
0
        obj = new WebGLExtensionColorBufferFloat(this);
383
0
        break;
384
0
    case WebGLExtensionID::WEBGL_compressed_texture_astc:
385
0
        obj = new WebGLExtensionCompressedTextureASTC(this);
386
0
        break;
387
0
    case WebGLExtensionID::WEBGL_compressed_texture_atc:
388
0
        obj = new WebGLExtensionCompressedTextureATC(this);
389
0
        break;
390
0
    case WebGLExtensionID::WEBGL_compressed_texture_etc:
391
0
        obj = new WebGLExtensionCompressedTextureES3(this);
392
0
        break;
393
0
    case WebGLExtensionID::WEBGL_compressed_texture_etc1:
394
0
        obj = new WebGLExtensionCompressedTextureETC1(this);
395
0
        break;
396
0
    case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
397
0
        obj = new WebGLExtensionCompressedTexturePVRTC(this);
398
0
        break;
399
0
    case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
400
0
        obj = new WebGLExtensionCompressedTextureS3TC(this);
401
0
        break;
402
0
    case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb:
403
0
        obj = new WebGLExtensionCompressedTextureS3TC_SRGB(this);
404
0
        break;
405
0
    case WebGLExtensionID::WEBGL_debug_renderer_info:
406
0
        obj = new WebGLExtensionDebugRendererInfo(this);
407
0
        break;
408
0
    case WebGLExtensionID::WEBGL_debug_shaders:
409
0
        obj = new WebGLExtensionDebugShaders(this);
410
0
        break;
411
0
    case WebGLExtensionID::WEBGL_depth_texture:
412
0
        obj = new WebGLExtensionDepthTexture(this);
413
0
        break;
414
0
    case WebGLExtensionID::WEBGL_draw_buffers:
415
0
        obj = new WebGLExtensionDrawBuffers(this);
416
0
        break;
417
0
    case WebGLExtensionID::WEBGL_lose_context:
418
0
        obj = new WebGLExtensionLoseContext(this);
419
0
        break;
420
0
421
0
    default:
422
0
        MOZ_ASSERT(false, "should not get there.");
423
0
    }
424
0
425
0
    mExtensions[ext] = obj;
426
0
}
427
428
void
429
WebGLContext::GetSupportedExtensions(dom::Nullable< nsTArray<nsString> >& retval,
430
                                     dom::CallerType callerType)
431
0
{
432
0
    retval.SetNull();
433
0
    const FuncScope funcScope(*this, "getSupportedExtensions");
434
0
    if (IsContextLost())
435
0
        return;
436
0
437
0
    nsTArray<nsString>& arr = retval.SetValue();
438
0
439
0
    for (size_t i = 0; i < size_t(WebGLExtensionID::Max); i++) {
440
0
        const auto extension = WebGLExtensionID(i);
441
0
        if (extension == WebGLExtensionID::MOZ_debug)
442
0
            continue; // Hide MOZ_debug from this list.
443
0
444
0
        if (IsExtensionSupported(callerType, extension)) {
445
0
            const char* extStr = GetExtensionString(extension);
446
0
            arr.AppendElement(NS_ConvertUTF8toUTF16(extStr));
447
0
        }
448
0
    }
449
0
}
450
451
} // namespace mozilla