Exposed SkMeshSpecification

Exposed SkMeshSpecification through MeshSpecification, exposing Make
methods as well as constructing a Attribute and Varying data classes.

Bug: b/254354404
Test: build hwui
Change-Id: I1040bde091575ac4bb786f7600d016b7c9168831
diff --git a/libs/hwui/jni/MeshSpecification.cpp b/libs/hwui/jni/MeshSpecification.cpp
new file mode 100644
index 0000000..22fa4d3
--- /dev/null
+++ b/libs/hwui/jni/MeshSpecification.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <SkMesh.h>
+
+#include "GraphicsJNI.h"
+#include "graphics_jni_helpers.h"
+
+namespace android {
+
+using Attribute = SkMeshSpecification::Attribute;
+using Varying = SkMeshSpecification::Varying;
+
+static struct {
+    jclass clazz{};
+    jfieldID type{};
+    jfieldID offset{};
+    jfieldID name{};
+} gAttributeInfo;
+
+static struct {
+    jclass clazz{};
+    jfieldID type{};
+    jfieldID name{};
+} gVaryingInfo;
+
+std::vector<Attribute> extractAttributes(JNIEnv* env, jobjectArray attributes) {
+    int size = env->GetArrayLength(attributes);
+    std::vector<Attribute> attVector;
+    attVector.reserve(size);
+    for (int i = 0; i < size; i++) {
+        jobject attribute = env->GetObjectArrayElement(attributes, i);
+        auto name = (jstring)env->GetObjectField(attribute, gAttributeInfo.name);
+        auto attName = ScopedUtfChars(env, name);
+        Attribute temp{Attribute::Type(env->GetIntField(attribute, gAttributeInfo.type)),
+                       static_cast<size_t>(env->GetIntField(attribute, gAttributeInfo.offset)),
+                       SkString(attName.c_str())};
+        attVector.push_back(std::move(temp));
+    }
+
+    return attVector;
+}
+
+std::vector<Varying> extractVaryings(JNIEnv* env, jobjectArray varyings) {
+    int size = env->GetArrayLength(varyings);
+    std::vector<Varying> varyVector;
+    varyVector.reserve(size);
+    for (int i = 0; i < size; i++) {
+        jobject varying = env->GetObjectArrayElement(varyings, i);
+        auto name = (jstring)env->GetObjectField(varying, gVaryingInfo.name);
+        auto varyName = ScopedUtfChars(env, name);
+        Varying temp{Varying::Type(env->GetIntField(varying, gVaryingInfo.type)),
+                     SkString(varyName.c_str())};
+        varyVector.push_back(std::move(temp));
+    }
+
+    return varyVector;
+}
+
+static jlong Make(JNIEnv* env, jobject thiz, jobjectArray attributeArray, jint vertexStride,
+                  jobjectArray varyingArray, jstring vertexShader, jstring fragmentShader) {
+    auto attributes = extractAttributes(env, attributeArray);
+    auto varyings = extractVaryings(env, varyingArray);
+    auto skVertexShader = ScopedUtfChars(env, vertexShader);
+    auto skFragmentShader = ScopedUtfChars(env, fragmentShader);
+    auto meshSpec = SkMeshSpecification::Make(attributes, vertexStride, varyings,
+                                              SkString(skVertexShader.c_str()),
+                                              SkString(skFragmentShader.c_str()))
+                            .specification;
+    return reinterpret_cast<jlong>(meshSpec.release());
+}
+
+static jlong MakeWithCS(JNIEnv* env, jobject thiz, jobjectArray attributeArray, jint vertexStride,
+                        jobjectArray varyingArray, jstring vertexShader, jstring fragmentShader,
+                        jlong colorSpace) {
+    auto attributes = extractAttributes(env, attributeArray);
+    auto varyings = extractVaryings(env, varyingArray);
+    auto skVertexShader = ScopedUtfChars(env, vertexShader);
+    auto skFragmentShader = ScopedUtfChars(env, fragmentShader);
+    auto meshSpec = SkMeshSpecification::Make(attributes, vertexStride, varyings,
+                                              SkString(skVertexShader.c_str()),
+                                              SkString(skFragmentShader.c_str()),
+                                              GraphicsJNI::getNativeColorSpace(colorSpace))
+                            .specification;
+
+    return reinterpret_cast<jlong>(meshSpec.release());
+}
+
+static jlong MakeWithAlpha(JNIEnv* env, jobject thiz, jobjectArray attributeArray,
+                           jint vertexStride, jobjectArray varyingArray, jstring vertexShader,
+                           jstring fragmentShader, jlong colorSpace, jint alphaType) {
+    auto attributes = extractAttributes(env, attributeArray);
+    auto varyings = extractVaryings(env, varyingArray);
+    auto skVertexShader = ScopedUtfChars(env, vertexShader);
+    auto skFragmentShader = ScopedUtfChars(env, fragmentShader);
+    auto meshSpec = SkMeshSpecification::Make(
+                            attributes, vertexStride, varyings, SkString(skVertexShader.c_str()),
+                            SkString(skFragmentShader.c_str()),
+                            GraphicsJNI::getNativeColorSpace(colorSpace), SkAlphaType(alphaType))
+                            .specification;
+    return reinterpret_cast<jlong>(meshSpec.release());
+}
+
+static void MeshSpecification_safeUnref(SkMeshSpecification* meshSpec) {
+    SkSafeUnref(meshSpec);
+}
+
+static jlong getMeshSpecificationFinalizer() {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&MeshSpecification_safeUnref));
+}
+
+static const JNINativeMethod gMeshSpecificationMethods[] = {
+        {"nativeGetFinalizer", "()J", (void*)getMeshSpecificationFinalizer},
+        {"nativeMake",
+         "([Landroid/graphics/MeshSpecification$Attribute;I[Landroid/graphics/"
+         "MeshSpecification$Varying;"
+         "Ljava/lang/String;Ljava/lang/String;)J",
+         (void*)Make},
+        {"nativeMakeWithCS",
+         "([Landroid/graphics/MeshSpecification$Attribute;I"
+         "[Landroid/graphics/MeshSpecification$Varying;Ljava/lang/String;Ljava/lang/String;J)J",
+         (void*)MakeWithCS},
+        {"nativeMakeWithAlpha",
+         "([Landroid/graphics/MeshSpecification$Attribute;I"
+         "[Landroid/graphics/MeshSpecification$Varying;Ljava/lang/String;Ljava/lang/String;JI)J",
+         (void*)MakeWithAlpha}};
+
+int register_android_graphics_MeshSpecification(JNIEnv* env) {
+    android::RegisterMethodsOrDie(env, "android/graphics/MeshSpecification",
+                                  gMeshSpecificationMethods, NELEM(gMeshSpecificationMethods));
+
+    gAttributeInfo.clazz = env->FindClass("android/graphics/MeshSpecification$Attribute");
+    gAttributeInfo.type = env->GetFieldID(gAttributeInfo.clazz, "mType", "I");
+    gAttributeInfo.offset = env->GetFieldID(gAttributeInfo.clazz, "mOffset", "I");
+    gAttributeInfo.name = env->GetFieldID(gAttributeInfo.clazz, "mName", "Ljava/lang/String;");
+
+    gVaryingInfo.clazz = env->FindClass("android/graphics/MeshSpecification$Varying");
+    gVaryingInfo.type = env->GetFieldID(gVaryingInfo.clazz, "mType", "I");
+    gVaryingInfo.name = env->GetFieldID(gVaryingInfo.clazz, "mName", "Ljava/lang/String;");
+    return 0;
+}
+
+}  // namespace android
\ No newline at end of file