WebGLCompatibility implement and add tests for section 6.4

The checks for VertexAttribPointer were already implemented in a
previous patch, so we only add the checks for DrawElements.

BUG=angleproject:1523
BUG=chromium:668223

Change-Id: I5da55f9a7e7479627099c7f77618353a63b75a8e
Reviewed-on: https://chromium-review.googlesource.com/434958
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 3607de6..f11c1f7 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -3463,16 +3463,38 @@
     const gl::VertexArray *vao     = state.getVertexArray();
     gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
 
+    GLuint typeBytes = gl::GetTypeInfo(type).bytes;
+
+    if (context->getExtensions().webglCompatibility)
+    {
+        ASSERT(isPow2(typeBytes) && typeBytes > 0);
+        if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
+        {
+            // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
+            // The offset arguments to drawElements and [...], must be a multiple of the size of the
+            // data type passed to the call, or an INVALID_OPERATION error is generated.
+            context->handleError(Error(GL_INVALID_OPERATION,
+                                       "indices must be a multiple of the element type size."));
+            return false;
+        }
+        if (!elementArrayBuffer && count > 0)
+        {
+            // [WebGL 1.0] Section 6.2 No Client Side Arrays
+            // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound
+            // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
+            context->handleError(Error(GL_INVALID_OPERATION,
+                                       "There is no element array buffer bound and count > 0."));
+            return false;
+        }
+    }
+
     if (elementArrayBuffer)
     {
-        const gl::Type &typeInfo = gl::GetTypeInfo(type);
-
         GLint64 offset = reinterpret_cast<GLint64>(indices);
-        GLint64 byteCount =
-            static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count) + offset;
+        GLint64 byteCount = static_cast<GLint64>(typeBytes) * static_cast<GLint64>(count) + offset;
 
         // check for integer overflows
-        if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
+        if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeBytes) ||
             byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
         {
             context->handleError(Error(GL_OUT_OF_MEMORY));
@@ -3486,16 +3508,7 @@
             return false;
         }
     }
-    else if (context->getExtensions().webglCompatibility && count > 0)
-    {
-        // [WebGL 1.0] Section 6.2 No Client Side Arrays
-        // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound
-        // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
-        context->handleError(
-            Error(GL_INVALID_OPERATION, "There is no element array buffer bound and count > 0."));
-        return false;
-    }
-    else if (!indices)
+    else if (!indices && count > 0)
     {
         // This is an application error that would normally result in a crash,
         // but we catch it and return an error