Skip to content

Commit

Permalink
Add storage (serialization/deserialization) module
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 716350769
  • Loading branch information
sfreilich authored and copybara-github committed Jan 16, 2025
1 parent 65e368b commit a5e555b
Show file tree
Hide file tree
Showing 45 changed files with 8,090 additions and 7 deletions.
13 changes: 7 additions & 6 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,20 @@ git_repository(
remote = "https://github.com/google/ink-stroke-modeler.git",
)

bazel_dep(name = "rules_android", version = "0.6.0")
bazel_dep(
name = "rules_jni",
version = "0.10.1",
)

git_repository(
name = "libtess2",
build_file = "third_party/libtess2/BUILD.bazel",
commit = "fc52516467dfa124bdd967c15c7cf9faf02a34ca",
remote = "https://github.com/memononen/libtess2.git",
)

bazel_dep(name = "protobuf", version = "29.3")
bazel_dep(name = "rules_android", version = "0.6.0")
bazel_dep(
name = "rules_jni",
version = "0.10.1",
)

SKIA_COMMIT = "515a23f3cbe1e2f54ffa6821e6da6f4891763f47"

http_archive(
Expand Down
3 changes: 2 additions & 1 deletion ink/jni/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2024 Google LLC
# Copyright 2024-2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -32,6 +32,7 @@ cc_binary(
"//ink/color/internal/jni:native",
"//ink/geometry/internal/jni:native",
"//ink/rendering/skia/common_internal/jni:native",
"//ink/storage/internal/jni:native",
"//ink/strokes/internal/jni:native",
],
)
18 changes: 18 additions & 0 deletions ink/jni/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,21 @@ cc_library(
],
}),
)

cc_library(
name = "jni_proto_util",
srcs = ["jni_proto_util.cc"],
hdrs = ["jni_proto_util.h"],
deps = [
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@protobuf//:protobuf_lite",
] + select({
"@platforms//os:android": [],
"//conditions:default": [
"@rules_jni//jni",
],
}),
)
80 changes: 80 additions & 0 deletions ink/jni/internal/jni_proto_util.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2024 Google LLC
//
// 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 "ink/jni/internal/jni_proto_util.h"

#include <jni.h>

#include <cstddef>

#include "absl/log/absl_check.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/message_lite.h"

namespace ink {
namespace jni {

absl::Status ParseProto(JNIEnv* env, jbyteArray serialized_proto,
google::protobuf::MessageLite& dest) {
return ParseProto(env, serialized_proto, 0,
env->GetArrayLength(serialized_proto), dest);
}

absl::Status ParseProto(JNIEnv* env, jbyteArray serialized_proto, jint offset,
jint size, google::protobuf::MessageLite& dest) {
// TODO(b/290213178): See how often this copies using the isCopy pointer
// argument, and consider using critical arrays to minimize copying.
jbyte* bytes = env->GetByteArrayElements(serialized_proto, nullptr);
ABSL_CHECK(bytes);
bool success = dest.ParseFromArray(bytes + offset, size);
env->ReleaseByteArrayElements(serialized_proto, bytes, 0);
if (!success) {
return absl::InvalidArgumentError(absl::StrCat(
"Failed to parse ", dest.GetTypeName(), " proto from byte[]."));
}
return absl::OkStatus();
}

absl::Status ParseProtoFromBuffer(JNIEnv* env,
jobject serialized_proto_direct_buffer,
jint offset, jint size,
google::protobuf::MessageLite& dest) {
void* addr = env->GetDirectBufferAddress(serialized_proto_direct_buffer);
ABSL_CHECK(addr);
// Cannot do arithmetic on void* due to unknown size of elements, so
// explicitly cast to clarify that the offset (and size) are in bytes.
jbyte* bytes = static_cast<jbyte*>(addr);
bool success = dest.ParseFromArray(bytes + offset, size);
if (!success) {
return absl::InvalidArgumentError(absl::StrCat(
"Failed to parse ", dest.GetTypeName(), " proto from direct buffer."));
}
return absl::OkStatus();
}

jbyteArray SerializeProto(JNIEnv* env, const google::protobuf::MessageLite& src) {
size_t size = src.ByteSizeLong();
jbyteArray serialized_proto = env->NewByteArray(size);
ABSL_CHECK(serialized_proto);
jbyte* bytes = env->GetByteArrayElements(serialized_proto, nullptr);
ABSL_CHECK(bytes);
bool success = src.SerializeToArray(bytes, size);
env->ReleaseByteArrayElements(serialized_proto, bytes, 0);
ABSL_CHECK(success);
return serialized_proto;
}

} // namespace jni
} // namespace ink
56 changes: 56 additions & 0 deletions ink/jni/internal/jni_proto_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2024 Google LLC
//
// 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.

#ifndef INK_JNI_INTERNAL_JNI_PROTO_UTIL_H_
#define INK_JNI_INTERNAL_JNI_PROTO_UTIL_H_

#include <jni.h>

#include "absl/status/status.h"
#include "google/protobuf/message_lite.h"

namespace ink {
namespace jni {

// Attempts to parse a serialized proto. If the proto doesn't parse, returns
// a non-OK absl::Status.
[[nodiscard]] absl::Status ParseProto(JNIEnv* env, jbyteArray serialized_proto,
google::protobuf::MessageLite& dest);

// Attempts to parse a serialized proto. If the proto doesn't parse, returns
// a non-OK absl::Status. `offset` is the starting point of the data within the
// `serialized_proto` array, and `size` is how far beyond `offset` the data
// continues.
[[nodiscard]] absl::Status ParseProto(JNIEnv* env, jbyteArray serialized_proto,
jint offset, jint size,
google::protobuf::MessageLite& dest);

// Attempts to parse a serialized proto from a direct java.nio.ByteBuffer. If
// the proto doesn't parse, returns a non-OK absl::Status. `offset` is the
// starting point of the data within the `serialized_proto` array, and `size`
// is how far beyond `offset` the data continues.
// Note: This has a different name than `ParseProto`, as jbyteArray is a type of
// jobject so the two definitions would clash rather than serve as overloads.
[[nodiscard]] absl::Status ParseProtoFromBuffer(
JNIEnv* env, jobject serialized_proto_direct_buffer, jint offset, jint size,
google::protobuf::MessageLite& dest);

// Serializes a proto into a newly-allocated Java byte array.
[[nodiscard]] jbyteArray SerializeProto(JNIEnv* env,
const google::protobuf::MessageLite& src);

} // namespace jni
} // namespace ink

#endif // INK_JNI_INTERNAL_JNI_PROTO_UTIL_H_
Loading

0 comments on commit a5e555b

Please sign in to comment.