Add WebGL validation extensions to ANGLE.

BUG=angleproject:1523

Change-Id: I6fecb5055ed8087665aeee34b3a066ea8f38d51b
Reviewed-on: https://chromium-review.googlesource.com/386281
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Antoine Labour <piman@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/extensions/ANGLE_webgl_compatibility.txt b/extensions/ANGLE_webgl_compatibility.txt
new file mode 100644
index 0000000..dd3637c
--- /dev/null
+++ b/extensions/ANGLE_webgl_compatibility.txt
@@ -0,0 +1,95 @@
+Name
+
+    ANGLE_webgl_compatibility
+
+Name Strings
+
+    GL_ANGLE_webgl_compatibility
+
+Contributors
+
+    Geoff Lang
+
+Contact
+
+    Geoff Lang (geofflang 'at' google.com)
+
+Notice
+
+    Copyright (c) 2016 The Khronos Group Inc. Copyright terms at
+        http://www.khronos.org/registry/speccopyright.html
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, September 16, 2016
+
+Number
+
+    OpenGL ES Extension #??
+
+Dependencies
+
+    Requires OpenGL ES 2.0
+
+    Written against the OpenGL ES 2.0 specification.
+
+    Interacts with EGL_ANGLE_create_context_webgl_compatibility (or equivalent)
+    extension.
+
+Overview
+
+    With this extension enabled, the OpenGL ES context will have additional
+    features and validation to be compatible with the WebGL specification.
+
+New Procedures and Functions
+
+    boolean EnableExtension(const char *name)
+
+New Tokens
+
+    None
+
+Additions to the OpenGL ES Specification
+
+    The command
+
+       boolean EnableExtension(const char *name)
+
+    enables the OpenGL ES extension named <name>.  Returns true on success and
+    false otherwise.  If the extension does not support being enabled or <name>
+    does not name a valid OpenGL ES extension, INVALID_OPERATION is generated.
+    If the extension is valid but is not supported by the context, no error is
+    generated but false is returned.
+
+    Additional validation will be performed according to the the sections of
+    the WebGL specification entitled "Differences Between WebGL and OpenGL ES
+    2.0" and "Differences Between WebGL and OpenGL ES 3.0".
+
+New State
+
+    None
+
+Conformance Tests
+
+    TBD
+
+Issues
+
+    (1) How can the user determine which extensions can be enabled without
+        potentially generating errors?
+
+      This can be solved by:
+      a) Never generate an error in EnableExtensions, simply return false when
+         the extension is not recognized or cannot be enabled.
+      b) Add another entry point to query all extensions that the context
+         supports enabling.
+
+Revision History
+
+    Rev.    Date         Author     Changes
+    ----  -------------  ---------  ----------------------------------------
+      1   Sept 16, 2016  geofflang  Initial version
diff --git a/extensions/EGL_ANGLE_create_context_webgl_compatibility.txt b/extensions/EGL_ANGLE_create_context_webgl_compatibility.txt
new file mode 100644
index 0000000..2e7fb82
--- /dev/null
+++ b/extensions/EGL_ANGLE_create_context_webgl_compatibility.txt
@@ -0,0 +1,88 @@
+Name
+
+    ANGLE_create_context_webgl_compatibility
+
+Name Strings
+
+    EGL_ANGLE_create_context_webgl_compatibility
+
+Contributors
+
+    Geoff Lang
+
+Contacts
+
+    Geoff Lang (geofflang 'at' google.com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, September 16, 2016
+
+Number
+
+    EGL Extension #??
+
+Dependencies
+
+    Requires EGL 1.4.
+
+    Written against the EGL 1.4 specification.
+
+    This spec interacts with GL_ANGLE_webgl_compatibility (or equivalent)
+    extension.
+
+Overview
+
+    This extension allows the creation of an OpenGL or OpenGL ES context that
+    provides additional WebGL features and validation.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted as an attribute name in the <*attrib_list> argument to
+    eglCreateContext:
+
+        EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE 0x3AAC
+
+Additions to the EGL 1.4 Specification
+
+    Add the following to section 3.7.1 "Creating Rendering Contexts":
+
+    EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE indicates whether a WebGL mode should
+    be enabled for the OpenGL ES context.  In this mode, the OpenGL ES context
+    will provide additional features and validation to be compatible with the
+    WebGL specification. The default value of
+    EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE is EGL_FALSE.
+
+Errors
+
+    None
+
+New State
+
+    None
+
+Conformance Tests
+
+    TBD
+
+Issues
+
+    None
+
+Revision History
+
+    Rev.    Date         Author     Changes
+    ----  -------------  ---------  ----------------------------------------
+      1   Sept 16, 2016  geofflang  Initial version
diff --git a/include/EGL/eglext.h b/include/EGL/eglext.h
index fc0a377..7a513e0 100644
--- a/include/EGL/eglext.h
+++ b/include/EGL/eglext.h
@@ -567,6 +567,11 @@
 #endif
 #endif /* EGL_ANGLE_stream_producer_d3d_texture_nv12 */
 
+#ifndef EGL_ANGLE_create_context_webgl_compatibility
+#define EGL_ANGLE_create_context_webgl_compatibility 1
+#define EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE 0x3AAC
+#endif /* EGL_ANGLE_create_context_webgl_compatibility */
+
 #ifndef EGL_ARM_pixmap_multisample_discard
 #define EGL_ARM_pixmap_multisample_discard 1
 #define EGL_DISCARD_SAMPLES_ARM           0x3286
diff --git a/include/GLES2/gl2ext.h b/include/GLES2/gl2ext.h
index 9e92a03..4ba2ea9 100644
--- a/include/GLES2/gl2ext.h
+++ b/include/GLES2/gl2ext.h
@@ -821,6 +821,14 @@
 #endif
 #endif /* GL_ANGLE_framebuffer_blit */
 
+#ifndef GL_ANGLE_webgl_compatibility
+#define GL_ANGLE_webgl_compatibility 1
+typedef GLboolean(GL_APIENTRYP PFNGLENABLEEXTENSIONANGLEPROC) (const GLchar *name);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLboolean GL_APIENTRY glEnableExtensionANGLE (const GLchar *name);
+#endif
+#endif /* GL_ANGLE_webgl_compatibility */
+
 #ifndef GL_CHROMIUM_framebuffer_mixed_samples
 #define GL_CHROMIUM_frambuffer_mixed_samples 1
 #define GL_COVERAGE_MODULATION_CHROMIUM 0x9332
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index 985d798..7663aa9 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -70,6 +70,11 @@
     }
 }
 
+void TextureCapsMap::clear()
+{
+    mCapsMap.clear();
+}
+
 const TextureCaps &TextureCapsMap::get(GLenum internalFormat) const
 {
     static TextureCaps defaultUnsupportedTexture;
@@ -161,6 +166,7 @@
       bindUniformLocation(false),
       syncQuery(false),
       copyTexture(false),
+      webglCompatibility(false),
       colorBufferFloat(false),
       multisampleCompatibility(false),
       framebufferMixedSamples(false),
@@ -173,78 +179,13 @@
 {
     std::vector<std::string> extensionStrings;
 
-    // clang-format off
-    //                   | Extension name                         | Supported flag           | Output vector   |
-    InsertExtensionString("GL_OES_element_index_uint",             elementIndexUint,          &extensionStrings);
-    InsertExtensionString("GL_OES_packed_depth_stencil",           packedDepthStencil,        &extensionStrings);
-    InsertExtensionString("GL_OES_get_program_binary",             getProgramBinary,          &extensionStrings);
-    InsertExtensionString("GL_OES_rgb8_rgba8",                     rgb8rgba8,                 &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_format_BGRA8888",        textureFormatBGRA8888,     &extensionStrings);
-    InsertExtensionString("GL_EXT_read_format_bgra",               readFormatBGRA,            &extensionStrings);
-    InsertExtensionString("GL_NV_pixel_buffer_object",             pixelBufferObject,         &extensionStrings);
-    InsertExtensionString("GL_OES_mapbuffer",                      mapBuffer,                 &extensionStrings);
-    InsertExtensionString("GL_EXT_map_buffer_range",               mapBufferRange,            &extensionStrings);
-    InsertExtensionString("GL_EXT_color_buffer_half_float",        colorBufferHalfFloat,      &extensionStrings);
-    InsertExtensionString("GL_OES_texture_half_float",             textureHalfFloat,          &extensionStrings);
-    InsertExtensionString("GL_OES_texture_half_float_linear",      textureHalfFloatLinear,    &extensionStrings);
-    InsertExtensionString("GL_OES_texture_float",                  textureFloat,              &extensionStrings);
-    InsertExtensionString("GL_OES_texture_float_linear",           textureFloatLinear,        &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_rg",                     textureRG,                 &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_compression_dxt1",       textureCompressionDXT1,    &extensionStrings);
-    InsertExtensionString("GL_ANGLE_texture_compression_dxt3",     textureCompressionDXT3,    &extensionStrings);
-    InsertExtensionString("GL_ANGLE_texture_compression_dxt5",     textureCompressionDXT5,    &extensionStrings);
-    InsertExtensionString("GL_KHR_texture_compression_astc_hdr",   textureCompressionASTCHDR, &extensionStrings);
-    InsertExtensionString("GL_KHR_texture_compression_astc_ldr",   textureCompressionASTCLDR, &extensionStrings);
-    InsertExtensionString("GL_OES_compressed_ETC1_RGB8_texture",   compressedETC1RGB8Texture, &extensionStrings);
-    InsertExtensionString("GL_EXT_sRGB",                           sRGB,                      &extensionStrings);
-    InsertExtensionString("GL_ANGLE_depth_texture",                depthTextures,             &extensionStrings);
-    InsertExtensionString("GL_OES_depth32",                        depth32,                   &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_storage",                textureStorage,            &extensionStrings);
-    InsertExtensionString("GL_OES_texture_npot",                   textureNPOT,               &extensionStrings);
-    InsertExtensionString("GL_EXT_draw_buffers",                   drawBuffers,               &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_filter_anisotropic",     textureFilterAnisotropic,  &extensionStrings);
-    InsertExtensionString("GL_EXT_occlusion_query_boolean",        occlusionQueryBoolean,     &extensionStrings);
-    InsertExtensionString("GL_NV_fence",                           fence,                     &extensionStrings);
-    InsertExtensionString("GL_ANGLE_timer_query",                  timerQuery,                &extensionStrings);
-    InsertExtensionString("GL_EXT_disjoint_timer_query",           disjointTimerQuery,        &extensionStrings);
-    InsertExtensionString("GL_EXT_robustness",                     robustness,                &extensionStrings);
-    InsertExtensionString("GL_EXT_blend_minmax",                   blendMinMax,               &extensionStrings);
-    InsertExtensionString("GL_ANGLE_framebuffer_blit",             framebufferBlit,           &extensionStrings);
-    InsertExtensionString("GL_ANGLE_framebuffer_multisample",      framebufferMultisample,    &extensionStrings);
-    InsertExtensionString("GL_ANGLE_instanced_arrays",             instancedArrays,           &extensionStrings);
-    InsertExtensionString("GL_ANGLE_pack_reverse_row_order",       packReverseRowOrder,       &extensionStrings);
-    InsertExtensionString("GL_OES_standard_derivatives",           standardDerivatives,       &extensionStrings);
-    InsertExtensionString("GL_EXT_shader_texture_lod",             shaderTextureLOD,          &extensionStrings);
-    InsertExtensionString("GL_NV_shader_framebuffer_fetch",        NVshaderFramebufferFetch,  &extensionStrings);
-    InsertExtensionString("GL_ARM_shader_framebuffer_fetch",       ARMshaderFramebufferFetch, &extensionStrings);
-    InsertExtensionString("GL_EXT_shader_framebuffer_fetch",       shaderFramebufferFetch,    &extensionStrings);
-    InsertExtensionString("GL_EXT_frag_depth",                     fragDepth,                 &extensionStrings);
-    InsertExtensionString("GL_ANGLE_texture_usage",                textureUsage,              &extensionStrings);
-    InsertExtensionString("GL_ANGLE_translated_shader_source",     translatedShaderSource,    &extensionStrings);
-    InsertExtensionString("GL_OES_fbo_render_mipmap",              fboRenderMipmap,           &extensionStrings);
-    InsertExtensionString("GL_EXT_discard_framebuffer",            discardFramebuffer,        &extensionStrings);
-    InsertExtensionString("GL_EXT_debug_marker",                   debugMarker,               &extensionStrings);
-    InsertExtensionString("GL_OES_EGL_image",                      eglImage,                  &extensionStrings);
-    InsertExtensionString("GL_OES_EGL_image_external",             eglImageExternal,          &extensionStrings);
-    InsertExtensionString("GL_OES_EGL_image_external_essl3",       eglImageExternalEssl3,     &extensionStrings);
-    InsertExtensionString("GL_NV_EGL_stream_consumer_external",    eglStreamConsumerExternal, &extensionStrings);
-    InsertExtensionString("GL_EXT_unpack_subimage",                unpackSubimage,            &extensionStrings);
-    InsertExtensionString("GL_NV_pack_subimage",                   packSubimage,              &extensionStrings);
-    InsertExtensionString("GL_EXT_color_buffer_float",             colorBufferFloat,          &extensionStrings);
-    InsertExtensionString("GL_OES_vertex_array_object",            vertexArrayObject,         &extensionStrings);
-    InsertExtensionString("GL_KHR_debug",                          debug,                     &extensionStrings);
-    // TODO(jmadill): Enable this when complete.
-    //InsertExtensionString("GL_KHR_no_error",                     noError,                   &extensionStrings);
-
-    InsertExtensionString("GL_ANGLE_lossy_etc_decode",             lossyETCDecode,            &extensionStrings);
-    InsertExtensionString("GL_CHROMIUM_bind_uniform_location",     bindUniformLocation,       &extensionStrings);
-    InsertExtensionString("GL_CHROMIUM_sync_query",                syncQuery,                 &extensionStrings);
-    InsertExtensionString("GL_CHROMIUM_copy_texture",              copyTexture,               &extensionStrings);
-    InsertExtensionString("GL_EXT_multisample_compatibility",      multisampleCompatibility,  &extensionStrings);
-    InsertExtensionString("GL_CHROMIUM_framebuffer_mixed_samples", framebufferMixedSamples,   &extensionStrings);
-    InsertExtensionString("GL_EXT_texture_norm16",                 textureNorm16,             &extensionStrings);
-    InsertExtensionString("GL_CHROMIUM_path_rendering",            pathRendering,             &extensionStrings);
-    // clang-format on
+    for (const auto &extensionInfo : GetExtensionInfoMap())
+    {
+        if (this->*(extensionInfo.second.ExtensionsMember))
+        {
+            extensionStrings.push_back(extensionInfo.first);
+        }
+    }
 
     return extensionStrings;
 }
@@ -555,6 +496,102 @@
     textureNorm16             = DetermineTextureNorm16Support(textureCaps);
 }
 
+const ExtensionInfoMap &GetExtensionInfoMap()
+{
+    auto buildExtensionInfoMap = []() {
+        auto enableableExtension = [](ExtensionInfo::ExtensionBool member) {
+            ExtensionInfo info;
+            info.Enableable       = true;
+            info.ExtensionsMember = member;
+            return info;
+        };
+
+        auto esOnlyExtension = [](ExtensionInfo::ExtensionBool member) {
+            ExtensionInfo info;
+            info.ExtensionsMember = member;
+            return info;
+        };
+
+        // clang-format off
+        ExtensionInfoMap map;
+        map["GL_OES_element_index_uint"] = enableableExtension(&Extensions::elementIndexUint);
+        map["GL_OES_packed_depth_stencil"] = esOnlyExtension(&Extensions::packedDepthStencil);
+        map["GL_OES_get_program_binary"] = esOnlyExtension(&Extensions::getProgramBinary);
+        map["GL_OES_rgb8_rgba8"] = esOnlyExtension(&Extensions::rgb8rgba8);
+        map["GL_EXT_texture_format_BGRA8888"] = esOnlyExtension(&Extensions::textureFormatBGRA8888);
+        map["GL_EXT_read_format_bgra"] = esOnlyExtension(&Extensions::readFormatBGRA);
+        map["GL_NV_pixel_buffer_object"] = esOnlyExtension(&Extensions::pixelBufferObject);
+        map["GL_OES_mapbuffer"] = esOnlyExtension(&Extensions::mapBuffer);
+        map["GL_EXT_map_buffer_range"] = esOnlyExtension(&Extensions::mapBufferRange);
+        map["GL_EXT_color_buffer_half_float"] = esOnlyExtension(&Extensions::colorBufferHalfFloat);
+        map["GL_OES_texture_half_float"] = esOnlyExtension(&Extensions::textureHalfFloat);
+        map["GL_OES_texture_half_float_linear"] = esOnlyExtension(&Extensions::textureHalfFloatLinear);
+        map["GL_OES_texture_float"] = esOnlyExtension(&Extensions::textureFloat);
+        map["GL_OES_texture_float_linear"] = esOnlyExtension(&Extensions::textureFloatLinear);
+        map["GL_EXT_texture_rg"] = esOnlyExtension(&Extensions::textureRG);
+        map["GL_EXT_texture_compression_dxt1"] = esOnlyExtension(&Extensions::textureCompressionDXT1);
+        map["GL_ANGLE_texture_compression_dxt3"] = esOnlyExtension(&Extensions::textureCompressionDXT3);
+        map["GL_ANGLE_texture_compression_dxt5"] = esOnlyExtension(&Extensions::textureCompressionDXT5);
+        map["GL_KHR_texture_compression_astc_hdr"] = esOnlyExtension(&Extensions::textureCompressionASTCHDR);
+        map["GL_KHR_texture_compression_astc_ldr"] = esOnlyExtension(&Extensions::textureCompressionASTCLDR);
+        map["GL_OES_compressed_ETC1_RGB8_texture"] = esOnlyExtension(&Extensions::compressedETC1RGB8Texture);
+        map["GL_EXT_sRGB"] = esOnlyExtension(&Extensions::sRGB);
+        map["GL_ANGLE_depth_texture"] = esOnlyExtension(&Extensions::depthTextures);
+        map["GL_OES_depth32"] = esOnlyExtension(&Extensions::depth32);
+        map["GL_EXT_texture_storage"] = esOnlyExtension(&Extensions::textureStorage);
+        map["GL_OES_texture_npot"] = esOnlyExtension(&Extensions::textureNPOT);
+        map["GL_EXT_draw_buffers"] = esOnlyExtension(&Extensions::drawBuffers);
+        map["GL_EXT_texture_filter_anisotropic"] = esOnlyExtension(&Extensions::textureFilterAnisotropic);
+        map["GL_EXT_occlusion_query_boolean"] = esOnlyExtension(&Extensions::occlusionQueryBoolean);
+        map["GL_NV_fence"] = esOnlyExtension(&Extensions::fence);
+        map["GL_ANGLE_timer_query"] = esOnlyExtension(&Extensions::timerQuery);
+        map["GL_EXT_disjoint_timer_query"] = esOnlyExtension(&Extensions::disjointTimerQuery);
+        map["GL_EXT_robustness"] = esOnlyExtension(&Extensions::robustness);
+        map["GL_EXT_blend_minmax"] = esOnlyExtension(&Extensions::blendMinMax);
+        map["GL_ANGLE_framebuffer_blit"] = esOnlyExtension(&Extensions::framebufferBlit);
+        map["GL_ANGLE_framebuffer_multisample"] = esOnlyExtension(&Extensions::framebufferMultisample);
+        map["GL_ANGLE_instanced_arrays"] = esOnlyExtension(&Extensions::instancedArrays);
+        map["GL_ANGLE_pack_reverse_row_order"] = esOnlyExtension(&Extensions::packReverseRowOrder);
+        map["GL_OES_standard_derivatives"] = esOnlyExtension(&Extensions::standardDerivatives);
+        map["GL_EXT_shader_texture_lod"] = esOnlyExtension(&Extensions::shaderTextureLOD);
+        map["GL_NV_shader_framebuffer_fetch"] = esOnlyExtension(&Extensions::NVshaderFramebufferFetch);
+        map["GL_ARM_shader_framebuffer_fetch"] = esOnlyExtension(&Extensions::ARMshaderFramebufferFetch);
+        map["GL_EXT_shader_framebuffer_fetch"] = esOnlyExtension(&Extensions::shaderFramebufferFetch);
+        map["GL_EXT_frag_depth"] = esOnlyExtension(&Extensions::fragDepth);
+        map["GL_ANGLE_texture_usage"] = esOnlyExtension(&Extensions::textureUsage);
+        map["GL_ANGLE_translated_shader_source"] = esOnlyExtension(&Extensions::translatedShaderSource);
+        map["GL_OES_fbo_render_mipmap"] = esOnlyExtension(&Extensions::fboRenderMipmap);
+        map["GL_EXT_discard_framebuffer"] = esOnlyExtension(&Extensions::discardFramebuffer);
+        map["GL_EXT_debug_marker"] = esOnlyExtension(&Extensions::debugMarker);
+        map["GL_OES_EGL_image"] = esOnlyExtension(&Extensions::eglImage);
+        map["GL_OES_EGL_image_external"] = esOnlyExtension(&Extensions::eglImageExternal);
+        map["GL_OES_EGL_image_external_essl3"] = esOnlyExtension(&Extensions::eglImageExternalEssl3);
+        map["GL_NV_EGL_stream_consumer_external"] = esOnlyExtension(&Extensions::eglStreamConsumerExternal);
+        map["GL_EXT_unpack_subimage"] = esOnlyExtension(&Extensions::unpackSubimage);
+        map["GL_NV_pack_subimage"] = esOnlyExtension(&Extensions::packSubimage);
+        map["GL_EXT_color_buffer_float"] = esOnlyExtension(&Extensions::colorBufferFloat);
+        map["GL_OES_vertex_array_object"] = esOnlyExtension(&Extensions::vertexArrayObject);
+        map["GL_KHR_debug"] = esOnlyExtension(&Extensions::debug);
+        // TODO(jmadill): Enable this when complete.
+        //map["GL_KHR_no_error"] = esOnlyExtension(&Extensions::noError);
+        map["GL_ANGLE_lossy_etc_decode"] = esOnlyExtension(&Extensions::lossyETCDecode);
+        map["GL_CHROMIUM_bind_uniform_location"] = esOnlyExtension(&Extensions::bindUniformLocation);
+        map["GL_CHROMIUM_sync_query"] = esOnlyExtension(&Extensions::syncQuery);
+        map["GL_CHROMIUM_copy_texture"] = esOnlyExtension(&Extensions::copyTexture);
+        map["GL_ANGLE_webgl_compatibility"] = esOnlyExtension(&Extensions::webglCompatibility);
+        map["GL_EXT_multisample_compatibility"] = esOnlyExtension(&Extensions::multisampleCompatibility);
+        map["GL_CHROMIUM_framebuffer_mixed_samples"] = esOnlyExtension(&Extensions::framebufferMixedSamples);
+        map["GL_EXT_texture_norm16"] = esOnlyExtension(&Extensions::textureNorm16);
+        map["GL_CHROMIUM_path_rendering"] = esOnlyExtension(&Extensions::pathRendering);
+        // clang-format on
+
+        return map;
+    };
+
+    static const ExtensionInfoMap extensionInfo = buildExtensionInfoMap();
+    return extensionInfo;
+}
+
 TypePrecision::TypePrecision()
 {
     range[0] = 0;
@@ -739,7 +776,8 @@
       stream(false),
       streamConsumerGLTexture(false),
       streamConsumerGLTextureYUV(false),
-      streamProducerD3DTextureNV12(false)
+      streamProducerD3DTextureNV12(false),
+      createContextWebGLCompatibility(false)
 {
 }
 
@@ -773,6 +811,7 @@
     InsertExtensionString("EGL_NV_stream_consumer_gltexture_yuv",          streamConsumerGLTextureYUV,     &extensionStrings);
     InsertExtensionString("EGL_ANGLE_flexible_surface_compatibility",      flexibleSurfaceCompatibility,   &extensionStrings);
     InsertExtensionString("EGL_ANGLE_stream_producer_d3d_texture_nv12",    streamProducerD3DTextureNV12,   &extensionStrings);
+    InsertExtensionString("EGL_ANGLE_create_context_webgl_compatibility",  createContextWebGLCompatibility,&extensionStrings);
     // TODO(jmadill): Enable this when complete.
     //InsertExtensionString("KHR_create_context_no_error",                   createContextNoError,           &extensionStrings);
     // clang-format on
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index 6382830..0a0619c 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -52,6 +52,7 @@
 
     void insert(GLenum internalFormat, const TextureCaps &caps);
     void remove(GLenum internalFormat);
+    void clear();
 
     const TextureCaps &get(GLenum internalFormat) const;
 
@@ -292,6 +293,9 @@
     // GL_CHROMIUM_copy_texture
     bool copyTexture;
 
+    // GL_ANGLE_webgl_compatibility
+    bool webglCompatibility;
+
     // ES3 Extension support
 
     // GL_EXT_color_buffer_float
@@ -312,6 +316,19 @@
     bool pathRendering;
 };
 
+struct ExtensionInfo
+{
+    // If this extension can be enabled with glEnableExtension (GL_ANGLE_webgl_compatibility)
+    bool Enableable = false;
+
+    // Pointer to a boolean member of the Extensions struct
+    typedef bool(Extensions::*ExtensionBool);
+    ExtensionBool ExtensionsMember = nullptr;
+};
+
+using ExtensionInfoMap = std::map<std::string, ExtensionInfo>;
+const ExtensionInfoMap &GetExtensionInfoMap();
+
 struct Limitations
 {
     Limitations();
@@ -572,6 +589,9 @@
 
     // EGL_ANGLE_stream_producer_d3d_texture_nv12
     bool streamProducerD3DTextureNV12;
+
+    // EGL_ANGLE_create_context_webgl_compatibility
+    bool createContextWebGLCompatibility;
 };
 
 struct DeviceExtensions
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 32d4fea..48e3933 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -179,6 +179,11 @@
     return (attribs.get(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, EGL_FALSE) == EGL_TRUE);
 }
 
+bool GetWebGLContext(const egl::AttributeMap &attribs)
+{
+    return (attribs.get(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE, EGL_FALSE) == EGL_TRUE);
+}
+
 std::string GetObjectLabelFromPointer(GLsizei length, const GLchar *label)
 {
     std::string labelName;
@@ -244,7 +249,7 @@
 {
     ASSERT(!mRobustAccess);  // Unimplemented
 
-    initCaps();
+    initCaps(GetWebGLContext(attribs));
 
     mGLState.initialize(mCaps, mExtensions, mClientMajorVersion, GetDebug(attribs));
 
@@ -2292,26 +2297,30 @@
     mRendererString = MakeStaticString(rendererString.str());
 }
 
-const std::string &Context::getRendererString() const
+const char *Context::getRendererString() const
 {
     return mRendererString;
 }
 
 void Context::initExtensionStrings()
 {
-    mExtensionStrings = mExtensions.getStrings();
+    for (const auto &extensionString : mExtensions.getStrings())
+    {
+        mExtensionStrings.push_back(MakeStaticString(extensionString));
+    }
 
     std::ostringstream combinedStringStream;
-    std::copy(mExtensionStrings.begin(), mExtensionStrings.end(), std::ostream_iterator<std::string>(combinedStringStream, " "));
-    mExtensionString = combinedStringStream.str();
+    std::copy(mExtensionStrings.begin(), mExtensionStrings.end(),
+              std::ostream_iterator<const char *>(combinedStringStream, " "));
+    mExtensionString = MakeStaticString(combinedStringStream.str());
 }
 
-const std::string &Context::getExtensionString() const
+const char *Context::getExtensionString() const
 {
     return mExtensionString;
 }
 
-const std::string &Context::getExtensionString(size_t idx) const
+const char *Context::getExtensionString(size_t idx) const
 {
     return mExtensionStrings[idx];
 }
@@ -2342,7 +2351,7 @@
     return false;
 }
 
-void Context::initCaps()
+void Context::initCaps(bool webGLContext)
 {
     mCaps = mImplementation->getNativeCaps();
 
@@ -2385,7 +2394,25 @@
 
     mCaps.maxFragmentInputComponents = std::min<GLuint>(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
 
+    // WebGL compatibility
+    mExtensions.webglCompatibility = webGLContext;
+    for (const auto &extensionInfo : GetExtensionInfoMap())
+    {
+        // If this context is for WebGL, disable all enableable extensions
+        if (webGLContext && extensionInfo.second.Enableable)
+        {
+            mExtensions.*(extensionInfo.second.ExtensionsMember) = false;
+        }
+    }
+
+    // Generate texture caps
+    updateCaps();
+}
+
+void Context::updateCaps()
+{
     mCaps.compressedTextureFormats.clear();
+    mTextureCaps.clear();
 
     const TextureCapsMap &rendererFormats = mImplementation->getNativeTextureCaps();
     for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++)
@@ -2924,6 +2951,32 @@
     handleError(texture->generateMipmap());
 }
 
+GLboolean Context::enableExtension(const char *name)
+{
+    const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap();
+    ASSERT(extensionInfos.find(name) != extensionInfos.end());
+    const auto &extension = extensionInfos.at(name);
+    ASSERT(extension.Enableable);
+
+    if (mExtensions.*(extension.ExtensionsMember))
+    {
+        // Extension already enabled
+        return GL_TRUE;
+    }
+
+    const auto &nativeExtensions = mImplementation->getNativeExtensions();
+    if (!(nativeExtensions.*(extension.ExtensionsMember)))
+    {
+        // Underlying implementation does not support this valid extension
+        return GL_FALSE;
+    }
+
+    mExtensions.*(extension.ExtensionsMember) = true;
+    updateCaps();
+    initExtensionStrings();
+    return GL_TRUE;
+}
+
 void Context::copyTextureCHROMIUM(GLuint sourceId,
                                   GLuint destId,
                                   GLint internalFormat,
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index f69ddca..97b3158 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -481,6 +481,8 @@
 
     void generateMipmap(GLenum target);
 
+    GLboolean enableExtension(const char *name);
+
     Error flush();
     Error finish();
 
@@ -582,10 +584,10 @@
     EGLenum getClientType() const;
     EGLenum getRenderBuffer() const;
 
-    const std::string &getRendererString() const;
+    const char *getRendererString() const;
 
-    const std::string &getExtensionString() const;
-    const std::string &getExtensionString(size_t idx) const;
+    const char *getExtensionString() const;
+    const char *getExtensionString(size_t idx) const;
     size_t getExtensionStringCount() const;
 
     rx::ContextImpl *getImplementation() const { return mImplementation.get(); }
@@ -612,7 +614,8 @@
     void initRendererString();
     void initExtensionStrings();
 
-    void initCaps();
+    void initCaps(bool webGLContext);
+    void updateCaps();
 
     LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const;
     LabeledObject *getLabeledObjectFromPtr(const void *ptr) const;
@@ -653,9 +656,9 @@
     ResourceMap<TransformFeedback> mTransformFeedbackMap;
     HandleAllocator mTransformFeedbackAllocator;
 
-    std::string mRendererString;
-    std::string mExtensionString;
-    std::vector<std::string> mExtensionStrings;
+    const char *mRendererString;
+    const char *mExtensionString;
+    std::vector<const char *> mExtensionStrings;
 
     // Recorded errors
     typedef std::set<GLenum> ErrorSet;
diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp
index 26bd0d2..e2a60fc 100644
--- a/src/libANGLE/Display.cpp
+++ b/src/libANGLE/Display.cpp
@@ -918,6 +918,7 @@
     // Some extensions are always available because they are implemented in the EGL layer.
     mDisplayExtensions.createContext        = true;
     mDisplayExtensions.createContextNoError = true;
+    mDisplayExtensions.createContextWebGLCompatibility = true;
 
     // Force EGL_KHR_get_all_proc_addresses on.
     mDisplayExtensions.getAllProcAddresses = true;
diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp
index 6b6893b..3ff51f1 100644
--- a/src/libANGLE/validationEGL.cpp
+++ b/src/libANGLE/validationEGL.cpp
@@ -327,6 +327,21 @@
               }
               break;
 
+          case EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE:
+              if (!display->getExtensions().createContextWebGLCompatibility)
+              {
+                  return Error(EGL_BAD_ATTRIBUTE,
+                               "Attribute EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE requires "
+                               "EGL_ANGLE_create_context_webgl_compatibility.");
+              }
+              if (value != EGL_TRUE && value != EGL_FALSE)
+              {
+                  return Error(
+                      EGL_BAD_ATTRIBUTE,
+                      "EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE must be EGL_TRUE or EGL_FALSE.");
+              }
+              break;
+
           default:
             return Error(EGL_BAD_ATTRIBUTE);
         }
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 339624c..0846f0d 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -482,7 +482,8 @@
               break;
 
           case GL_DEPTH_STENCIL_ATTACHMENT:
-              if (context->getClientMajorVersion() < 3)
+              if (!context->getExtensions().webglCompatibility &&
+                  context->getClientMajorVersion() < 3)
               {
                   context->handleError(Error(GL_INVALID_ENUM));
                   return false;
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index 2775fe9..68285ce 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -3433,4 +3433,24 @@
     return true;
 }
 
+bool ValidateEnableExtensionANGLE(ValidationContext *context, const GLchar *name)
+{
+    if (!context->getExtensions().webglCompatibility)
+    {
+        context->handleError(
+            Error(GL_INVALID_OPERATION, "GL_ANGLE_webgl_compatibility is not available."));
+        return false;
+    }
+
+    const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap();
+    auto extension                         = extensionInfos.find(name);
+    if (extension == extensionInfos.end() || !extension->second.Enableable)
+    {
+        context->handleError(Error(GL_INVALID_OPERATION, "Extension %s is not enableable.", name));
+        return false;
+    }
+
+    return true;
+}
+
 }  // namespace gl
diff --git a/src/libANGLE/validationES2.h b/src/libANGLE/validationES2.h
index b9cf587..1ebb262 100644
--- a/src/libANGLE/validationES2.h
+++ b/src/libANGLE/validationES2.h
@@ -317,6 +317,8 @@
                            GLsizeiptr size,
                            const GLvoid *data);
 
+bool ValidateEnableExtensionANGLE(ValidationContext *context, const GLchar *name);
+
 }  // namespace gl
 
 #endif // LIBANGLE_VALIDATION_ES2_H_
diff --git a/src/libGLESv2/entry_points_egl.cpp b/src/libGLESv2/entry_points_egl.cpp
index 1ed04ea..b3fec07 100644
--- a/src/libGLESv2/entry_points_egl.cpp
+++ b/src/libGLESv2/entry_points_egl.cpp
@@ -1472,6 +1472,9 @@
         INSERT_PROC_ADDRESS(gl, CopyTextureCHROMIUM);
         INSERT_PROC_ADDRESS(gl, CopySubTextureCHROMIUM);
 
+        // GL_ANGLE_webgl_compatibility
+        INSERT_PROC_ADDRESS(gl, EnableExtensionANGLE);
+
         // GLES3 core
         INSERT_PROC_ADDRESS(gl, ReadBuffer);
         INSERT_PROC_ADDRESS(gl, DrawRangeElements);
diff --git a/src/libGLESv2/entry_points_gles_2_0.cpp b/src/libGLESv2/entry_points_gles_2_0.cpp
index 7dcca39..a86e696 100644
--- a/src/libGLESv2/entry_points_gles_2_0.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0.cpp
@@ -2101,7 +2101,7 @@
                 return reinterpret_cast<const GLubyte *>("Google Inc.");
 
             case GL_RENDERER:
-                return reinterpret_cast<const GLubyte *>(context->getRendererString().c_str());
+                return reinterpret_cast<const GLubyte *>(context->getRendererString());
 
             case GL_VERSION:
                 if (context->getClientMajorVersion() == 2)
@@ -2128,7 +2128,7 @@
                 }
 
             case GL_EXTENSIONS:
-                return reinterpret_cast<const GLubyte *>(context->getExtensionString().c_str());
+                return reinterpret_cast<const GLubyte *>(context->getExtensionString());
 
             default:
                 context->handleError(Error(GL_INVALID_ENUM));
diff --git a/src/libGLESv2/entry_points_gles_2_0_ext.cpp b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
index cfd64c8..7b114f8 100644
--- a/src/libGLESv2/entry_points_gles_2_0_ext.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
@@ -1935,4 +1935,22 @@
     }
 }
 
+GL_APICALL GLboolean GL_APIENTRY EnableExtensionANGLE(const GLchar *name)
+{
+    EVENT("(const GLchar *name = %p)", name);
+
+    Context *context = GetValidGlobalContext();
+    if (context)
+    {
+        if (!context->skipValidation() && !ValidateEnableExtensionANGLE(context, name))
+        {
+            return GL_FALSE;
+        }
+
+        return context->enableExtension(name) ? GL_TRUE : GL_FALSE;
+    }
+
+    return GL_FALSE;
+}
+
 }  // gl
diff --git a/src/libGLESv2/entry_points_gles_2_0_ext.h b/src/libGLESv2/entry_points_gles_2_0_ext.h
index 86216d2..1f1f7b4 100644
--- a/src/libGLESv2/entry_points_gles_2_0_ext.h
+++ b/src/libGLESv2/entry_points_gles_2_0_ext.h
@@ -259,6 +259,9 @@
                                                      GLboolean unpackPremultiplyAlpha,
                                                      GLboolean unpackUnmultiplyAlpha);
 
+// GL_ANGLE_webgl_compatibility
+GL_APICALL GLboolean GL_APIENTRY EnableExtensionANGLE(const GLchar *name);
+
 }  // namespace gl
 
 #endif // LIBGLESV2_ENTRYPOINTGLES20EXT_H_
diff --git a/src/libGLESv2/entry_points_gles_3_0.cpp b/src/libGLESv2/entry_points_gles_3_0.cpp
index dabb334..f5dcd5d 100644
--- a/src/libGLESv2/entry_points_gles_3_0.cpp
+++ b/src/libGLESv2/entry_points_gles_3_0.cpp
@@ -1441,7 +1441,7 @@
             return NULL;
         }
 
-        return reinterpret_cast<const GLubyte*>(context->getExtensionString(index).c_str());
+        return reinterpret_cast<const GLubyte *>(context->getExtensionString(index));
     }
 
     return NULL;
diff --git a/src/tests/angle_end2end_tests.gypi b/src/tests/angle_end2end_tests.gypi
index 9941e96..d23d481 100644
--- a/src/tests/angle_end2end_tests.gypi
+++ b/src/tests/angle_end2end_tests.gypi
@@ -75,6 +75,7 @@
             '<(angle_path)/src/tests/gl_tests/UnpackRowLength.cpp',
             '<(angle_path)/src/tests/gl_tests/VertexAttributeTest.cpp',
             '<(angle_path)/src/tests/gl_tests/ViewportTest.cpp',
+            '<(angle_path)/src/tests/gl_tests/WebGLCompatibilityTest.cpp',
             '<(angle_path)/src/tests/egl_tests/EGLContextCompatibilityTest.cpp',
             '<(angle_path)/src/tests/egl_tests/EGLContextSharingTest.cpp',
             '<(angle_path)/src/tests/egl_tests/EGLQueryContextTest.cpp',
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
new file mode 100644
index 0000000..087247f
--- /dev/null
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
@@ -0,0 +1,127 @@
+//
+// Copyright 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// WebGLCompatibilityTest.cpp : Tests of the GL_ANGLE_webgl_compatibility extension.
+
+#include "test_utils/ANGLETest.h"
+
+#include "test_utils/gl_raii.h"
+
+namespace angle
+{
+
+class WebGLCompatibilityTest : public ANGLETest
+{
+  protected:
+    WebGLCompatibilityTest()
+    {
+        setWindowWidth(128);
+        setWindowHeight(128);
+        setConfigRedBits(8);
+        setConfigGreenBits(8);
+        setConfigBlueBits(8);
+        setConfigAlphaBits(8);
+        setWebGLCompatibilityEnabled(true);
+    }
+
+    void SetUp() override
+    {
+        ANGLETest::SetUp();
+        glEnableExtensionANGLE = reinterpret_cast<PFNGLENABLEEXTENSIONANGLEPROC>(
+            eglGetProcAddress("glEnableExtensionANGLE"));
+    }
+
+    void TearDown() override { ANGLETest::TearDown(); }
+
+    PFNGLENABLEEXTENSIONANGLEPROC glEnableExtensionANGLE = nullptr;
+};
+
+// Context creation would fail if EGL_ANGLE_create_context_webgl_compatibility was not available so
+// the GL extension should always be present
+TEST_P(WebGLCompatibilityTest, ExtensionStringExposed)
+{
+    EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
+}
+
+// Verify that all extension entry points are available
+TEST_P(WebGLCompatibilityTest, EntryPoints)
+{
+    if (extensionEnabled("GL_ANGLE_webgl_compatibility"))
+    {
+        EXPECT_NE(nullptr, eglGetProcAddress("glEnableExtensionANGLE"));
+    }
+}
+
+// WebGL 1 allows GL_DEPTH_STENCIL_ATTACHMENT as a valid binding point.  Make sure it is usable,
+// even in ES2 contexts.
+TEST_P(WebGLCompatibilityTest, DepthStencilBindingPoint)
+{
+    GLRenderbuffer renderbuffer;
+    glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
+
+    GLFramebuffer framebuffer;
+    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+                              renderbuffer.get());
+
+    EXPECT_GL_NO_ERROR();
+}
+
+// Test that attempting to enable an extension that doesn't exist generates GL_INVALID_OPERATION
+TEST_P(WebGLCompatibilityTest, EnableExtensionValidation)
+{
+    EXPECT_EQ(GL_FALSE, glEnableExtensionANGLE("invalid_extension_string"));
+    EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+}
+
+// Test enabling the GL_OES_element_index_uint extension
+TEST_P(WebGLCompatibilityTest, EnableExtensionUintIndices)
+{
+    if (getClientMajorVersion() != 2)
+    {
+        // This test only works on ES2 where uint indices are not available by default
+        return;
+    }
+
+    EXPECT_FALSE(extensionEnabled("GL_OES_element_index_uint"));
+
+    GLBuffer indexBuffer;
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
+
+    GLuint data[] = {0, 1, 2, 1, 3, 2};
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
+
+    ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
+                     "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
+    glUseProgram(program.get());
+
+    glDrawElements(GL_TRIANGLES, 2, GL_UNSIGNED_INT, nullptr);
+    EXPECT_GL_ERROR(GL_INVALID_ENUM);
+
+    if (glEnableExtensionANGLE("GL_OES_element_index_uint"))
+    {
+        EXPECT_GL_NO_ERROR();
+        EXPECT_TRUE(extensionEnabled("GL_OES_element_index_uint"));
+
+        glDrawElements(GL_TRIANGLES, 2, GL_UNSIGNED_INT, nullptr);
+        EXPECT_GL_NO_ERROR();
+    }
+}
+
+// Use this to select which configurations (e.g. which renderer, which GLES major version) these
+// tests should be run against.
+ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
+                       ES2_D3D9(),
+                       ES2_D3D11(),
+                       ES3_D3D11(),
+                       ES2_D3D11_FL9_3(),
+                       ES2_OPENGL(),
+                       ES3_OPENGL(),
+                       ES2_OPENGLES(),
+                       ES3_OPENGLES());
+
+}  // namespace
diff --git a/src/tests/test_utils/ANGLETest.cpp b/src/tests/test_utils/ANGLETest.cpp
index 1a9d8b5..7bec1e1 100644
--- a/src/tests/test_utils/ANGLETest.cpp
+++ b/src/tests/test_utils/ANGLETest.cpp
@@ -643,6 +643,11 @@
     mEGLWindow->setNoErrorEnabled(enabled);
 }
 
+void ANGLETest::setWebGLCompatibilityEnabled(bool webglCompatibility)
+{
+    mEGLWindow->setWebGLCompatibilityEnabled(webglCompatibility);
+}
+
 int ANGLETest::getClientMajorVersion() const
 {
     return mEGLWindow->getClientMajorVersion();
diff --git a/src/tests/test_utils/ANGLETest.h b/src/tests/test_utils/ANGLETest.h
index e1c6fba..73b69cd 100644
--- a/src/tests/test_utils/ANGLETest.h
+++ b/src/tests/test_utils/ANGLETest.h
@@ -211,6 +211,7 @@
     void setMultisampleEnabled(bool enabled);
     void setDebugEnabled(bool enabled);
     void setNoErrorEnabled(bool enabled);
+    void setWebGLCompatibilityEnabled(bool webglCompatibility);
 
     int getClientMajorVersion() const;
     int getClientMinorVersion() const;
diff --git a/util/EGLWindow.cpp b/util/EGLWindow.cpp
index 2f436d9..a59391f 100644
--- a/util/EGLWindow.cpp
+++ b/util/EGLWindow.cpp
@@ -110,6 +110,7 @@
       mMultisample(false),
       mDebug(false),
       mNoError(false),
+      mWebGLCompatibility(false),
       mSwapInterval(-1)
 {
 }
@@ -207,6 +208,14 @@
         return false;
     }
 
+    bool hasWebGLCompatibility =
+        strstr(displayExtensions, "EGL_ANGLE_create_context_webgl_compatibility") != nullptr;
+    if (mWebGLCompatibility && !hasWebGLCompatibility)
+    {
+        destroyGL();
+        return false;
+    }
+
     eglBindAPI(EGL_OPENGL_ES_API);
     if (eglGetError() != EGL_SUCCESS)
     {
@@ -275,6 +284,12 @@
 
         contextAttributes.push_back(EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
         contextAttributes.push_back(mNoError ? EGL_TRUE : EGL_FALSE);
+
+        if (hasWebGLCompatibility)
+        {
+            contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
+            contextAttributes.push_back(mWebGLCompatibility ? EGL_TRUE : EGL_FALSE);
+        }
     }
     contextAttributes.push_back(EGL_NONE);
 
diff --git a/util/EGLWindow.h b/util/EGLWindow.h
index 4352a2b..11b6470 100644
--- a/util/EGLWindow.h
+++ b/util/EGLWindow.h
@@ -68,6 +68,10 @@
     void setMultisample(bool multisample) { mMultisample = multisample; }
     void setDebugEnabled(bool debug) { mDebug = debug; }
     void setNoErrorEnabled(bool noError) { mNoError = noError; }
+    void setWebGLCompatibilityEnabled(bool webglCompatibility)
+    {
+        mWebGLCompatibility = webglCompatibility;
+    }
     void setSwapInterval(EGLint swapInterval) { mSwapInterval = swapInterval; }
 
     static EGLBoolean FindEGLConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *config);
@@ -113,6 +117,7 @@
     bool mMultisample;
     bool mDebug;
     bool mNoError;
+    bool mWebGLCompatibility;
     EGLint mSwapInterval;
 };