Support CHROMIUM_path_rendering

This is partial support for CHROMIUM_path_rendering
and implements basic path management and non-instanced
rendering.

BUG=angleproject:1382

Change-Id: I9c0e88183e0a915d522889323933439d25b45b5f
Reviewed-on: https://chromium-review.googlesource.com/348630
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 2ab9f3a..2559657 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -11,7 +11,9 @@
 
 #include <iterator>
 #include <sstream>
+#include <string.h>
 
+#include "common/matrix_utils.h"
 #include "common/platform.h"
 #include "common/utilities.h"
 #include "libANGLE/Buffer.h"
@@ -20,6 +22,7 @@
 #include "libANGLE/Fence.h"
 #include "libANGLE/Framebuffer.h"
 #include "libANGLE/FramebufferAttachment.h"
+#include "libANGLE/Path.h"
 #include "libANGLE/Program.h"
 #include "libANGLE/Query.h"
 #include "libANGLE/Renderbuffer.h"
@@ -437,6 +440,17 @@
     return reinterpret_cast<GLsync>(static_cast<uintptr_t>(handle));
 }
 
+GLuint Context::createPaths(GLsizei range)
+{
+    auto resultOrError = mResourceManager->createPaths(mImplementation.get(), range);
+    if (resultOrError.isError())
+    {
+        handleError(resultOrError.getError());
+        return 0;
+    }
+    return resultOrError.getResult();
+}
+
 GLuint Context::createVertexArray()
 {
     GLuint vertexArray           = mVertexArrayHandleAllocator.allocate();
@@ -534,6 +548,96 @@
     mResourceManager->deleteFenceSync(static_cast<GLuint>(reinterpret_cast<uintptr_t>(fenceSync)));
 }
 
+void Context::deletePaths(GLuint first, GLsizei range)
+{
+    mResourceManager->deletePaths(first, range);
+}
+
+bool Context::hasPathData(GLuint path) const
+{
+    const auto *pathObj = mResourceManager->getPath(path);
+    if (pathObj == nullptr)
+        return false;
+
+    return pathObj->hasPathData();
+}
+
+bool Context::hasPath(GLuint path) const
+{
+    return mResourceManager->hasPath(path);
+}
+
+void Context::setPathCommands(GLuint path,
+                              GLsizei numCommands,
+                              const GLubyte *commands,
+                              GLsizei numCoords,
+                              GLenum coordType,
+                              const void *coords)
+{
+    auto *pathObject = mResourceManager->getPath(path);
+
+    handleError(pathObject->setCommands(numCommands, commands, numCoords, coordType, coords));
+}
+
+void Context::setPathParameterf(GLuint path, GLenum pname, GLfloat value)
+{
+    auto *pathObj = mResourceManager->getPath(path);
+
+    switch (pname)
+    {
+        case GL_PATH_STROKE_WIDTH_CHROMIUM:
+            pathObj->setStrokeWidth(value);
+            break;
+        case GL_PATH_END_CAPS_CHROMIUM:
+            pathObj->setEndCaps(static_cast<GLenum>(value));
+            break;
+        case GL_PATH_JOIN_STYLE_CHROMIUM:
+            pathObj->setJoinStyle(static_cast<GLenum>(value));
+            break;
+        case GL_PATH_MITER_LIMIT_CHROMIUM:
+            pathObj->setMiterLimit(value);
+            break;
+        case GL_PATH_STROKE_BOUND_CHROMIUM:
+            pathObj->setStrokeBound(value);
+            break;
+        default:
+            UNREACHABLE();
+            break;
+    }
+}
+
+void Context::getPathParameterfv(GLuint path, GLenum pname, GLfloat *value) const
+{
+    const auto *pathObj = mResourceManager->getPath(path);
+
+    switch (pname)
+    {
+        case GL_PATH_STROKE_WIDTH_CHROMIUM:
+            *value = pathObj->getStrokeWidth();
+            break;
+        case GL_PATH_END_CAPS_CHROMIUM:
+            *value = static_cast<GLfloat>(pathObj->getEndCaps());
+            break;
+        case GL_PATH_JOIN_STYLE_CHROMIUM:
+            *value = static_cast<GLfloat>(pathObj->getJoinStyle());
+            break;
+        case GL_PATH_MITER_LIMIT_CHROMIUM:
+            *value = pathObj->getMiterLimit();
+            break;
+        case GL_PATH_STROKE_BOUND_CHROMIUM:
+            *value = pathObj->getStrokeBound();
+            break;
+        default:
+            UNREACHABLE();
+            break;
+    }
+}
+
+void Context::setPathStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+    mGLState.setPathStencilFunc(func, ref, mask);
+}
+
 void Context::deleteVertexArray(GLuint vertexArray)
 {
     auto iter = mVertexArrayMap.find(vertexArray);
@@ -1016,6 +1120,16 @@
       case GL_MAX_TEXTURE_LOD_BIAS:
         *params = mCaps.maxLODBias;
         break;
+
+      case GL_PATH_MODELVIEW_MATRIX_CHROMIUM:
+      case GL_PATH_PROJECTION_MATRIX_CHROMIUM:
+      {
+          ASSERT(mExtensions.pathRendering);
+          const GLfloat *m = mGLState.getPathRenderingMatrix(pname);
+          memcpy(params, m, 16 * sizeof(GLfloat));
+      }
+      break;
+
       default:
           mGLState.getFloatv(pname, params);
           break;
@@ -1269,6 +1383,94 @@
     mGLState.setCoverageModulation(components);
 }
 
+void Context::loadPathRenderingMatrix(GLenum matrixMode, const GLfloat *matrix)
+{
+    mGLState.loadPathRenderingMatrix(matrixMode, matrix);
+}
+
+void Context::loadPathRenderingIdentityMatrix(GLenum matrixMode)
+{
+    GLfloat I[16];
+    angle::Matrix<GLfloat>::setToIdentity(I);
+
+    mGLState.loadPathRenderingMatrix(matrixMode, I);
+}
+
+void Context::stencilFillPath(GLuint path, GLenum fillMode, GLuint mask)
+{
+    const auto *pathObj = mResourceManager->getPath(path);
+    if (!pathObj)
+        return;
+
+    // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering?
+    syncRendererState();
+
+    mImplementation->stencilFillPath(pathObj, fillMode, mask);
+}
+
+void Context::stencilStrokePath(GLuint path, GLint reference, GLuint mask)
+{
+    const auto *pathObj = mResourceManager->getPath(path);
+    if (!pathObj)
+        return;
+
+    // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering?
+    syncRendererState();
+
+    mImplementation->stencilStrokePath(pathObj, reference, mask);
+}
+
+void Context::coverFillPath(GLuint path, GLenum coverMode)
+{
+    const auto *pathObj = mResourceManager->getPath(path);
+    if (!pathObj)
+        return;
+
+    // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering?
+    syncRendererState();
+
+    mImplementation->coverFillPath(pathObj, coverMode);
+}
+
+void Context::coverStrokePath(GLuint path, GLenum coverMode)
+{
+    const auto *pathObj = mResourceManager->getPath(path);
+    if (!pathObj)
+        return;
+
+    // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering?
+    syncRendererState();
+
+    mImplementation->coverStrokePath(pathObj, coverMode);
+}
+
+void Context::stencilThenCoverFillPath(GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode)
+{
+    const auto *pathObj = mResourceManager->getPath(path);
+    if (!pathObj)
+        return;
+
+    // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering?
+    syncRendererState();
+
+    mImplementation->stencilThenCoverFillPath(pathObj, fillMode, mask, coverMode);
+}
+
+void Context::stencilThenCoverStrokePath(GLuint path,
+                                         GLint reference,
+                                         GLuint mask,
+                                         GLenum coverMode)
+{
+    const auto *pathObj = mResourceManager->getPath(path);
+    if (!pathObj)
+        return;
+
+    // TODO(svaisanen@nvidia.com): maybe sync only state required for path rendering?
+    syncRendererState();
+
+    mImplementation->stencilThenCoverStrokePath(pathObj, reference, mask, coverMode);
+}
+
 void Context::handleError(const Error &error)
 {
     if (error.isError())