Import of the watch repository from Pebble

This commit is contained in:
Matthieu Jeanson 2024-12-12 16:43:03 -08:00 committed by Katharine Berry
commit 3b92768480
10334 changed files with 2564465 additions and 0 deletions

View file

@ -0,0 +1,260 @@
/*
* 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 "rocky_api_util.h"
#include "rocky_api_errors.h"
#include "applib/app_logging.h"
#include "kernel/pbl_malloc.h"
#include "system/passert.h"
#include "util/size.h"
#include "util/trig.h"
#include "vendor/jerryscript/jerry-libm/include/math.h" // easiest way to get M_PI
#include <stdlib.h>
#include <string.h>
#define ROCKY_SINGLETON "_rocky"
// [MT] including <math.h> causes the jerry-libm header to get included again :(
extern double round(double d);
uintptr_t rocky_util_uint_from_value(const jerry_value_t value) {
uintptr_t rv = 0;
if (jerry_value_is_number(value)) {
rv = jerry_get_number_value(value);
} else if (jerry_value_is_string(value)) {
uint32_t sz = jerry_get_utf8_string_size(value);
char buf[sz + 1];
memset(buf, 0, sz + 1);
jerry_string_to_utf8_char_buffer(value, (jerry_char_t *)buf, sz);
rv = strtoul(buf, NULL, 0);
}
return rv;
}
int32_t jerry_get_int32_value(jerry_value_t value) {
return (int32_t)(round(jerry_get_number_value(value)));
}
int32_t jerry_get_angle_value(jerry_value_t value) {
return (int32_t)
(jerry_get_number_value(value) * TRIG_MAX_ANGLE / (2 * M_PI)) + TRIG_MAX_ANGLE / 4;
}
char *rocky_string_alloc_and_copy(const jerry_value_t string) {
char *out_str = NULL;
if (jerry_value_is_string(string)) {
uint32_t sz = jerry_get_utf8_string_size(string);
out_str = task_zalloc_check(sz + 1);
jerry_string_to_utf8_char_buffer(string, (jerry_char_t *)out_str, sz);
}
return out_str;
}
void rocky_log_exception(const char *message, jerry_value_t exception) {
// using APP_LOG in this function so that 3rd-parties will know what went wrong with their JS
APP_LOG(APP_LOG_LEVEL_ERROR, "Exception while %s", message);
jerry_char_t buffer[100] = {};
const ssize_t written = jerry_object_to_string_to_utf8_char_buffer(exception, buffer,
sizeof(buffer) - 1);
if (written > 0) {
APP_LOG(APP_LOG_LEVEL_ERROR, "%s", buffer);
} else {
APP_LOG(APP_LOG_LEVEL_ERROR, "no further info.");
}
}
void jerry_set_object_field(jerry_value_t object, const char *field, jerry_value_t value) {
JS_VAR prop_name = jerry_create_string((jerry_char_t *)field);
JS_UNUSED_VAL = jerry_set_property(object, prop_name, value);
}
jerry_value_t jerry_get_object_field(jerry_value_t object, const char* field) {
JS_VAR prop_name = jerry_create_string((jerry_char_t *) field);
const bool has_property = jerry_has_property(object, prop_name);
JS_VAR value = (has_property) ? jerry_get_property(object, prop_name) : jerry_create_undefined();
return jerry_acquire_value(value);
}
bool rocky_str_equal(jerry_value_t str_js, const char *str) {
char buffer[40] = {0};
PBL_ASSERTN(strlen(str) < sizeof(buffer));
jerry_string_to_utf8_char_buffer(str_js, (jerry_char_t *) buffer, sizeof(buffer));
return strcmp(buffer, str) == 0;
}
jerry_value_t jerry_get_object_getter_result(jerry_value_t object, const char *getter_name) {
JS_VAR getter = jerry_get_object_field(object, getter_name);
const bool is_function = jerry_value_is_function(getter);
JS_VAR result = (is_function) ? jerry_call_function(getter, object, NULL, 0)
: jerry_create_undefined();
return jerry_acquire_value(result);
}
jerry_value_t rocky_creator_object(void *ignore) {
return jerry_create_object();
}
jerry_value_t rocky_creator_empty_array(void *ignore) {
return jerry_create_array(0);
}
jerry_value_t rocky_get_or_create_object(jerry_value_t parent, const char *name,
RockyObjectCreatorFunc creator_func, void *data,
bool *was_created) {
if (jerry_value_is_undefined(parent)) {
parent = jerry_get_global_object();
// it's safe to release the global object here already, it will never be destroyed
jerry_release_value(parent);
}
// check the object doesn't already exist
JS_VAR val = jerry_get_object_field(parent, name);
if (!jerry_value_is_undefined(val)) {
if (was_created) {
*was_created = false;
}
return jerry_acquire_value(val);
}
JS_VAR result = creator_func(data);
jerry_set_object_field(parent, name, result);
if (was_created) {
*was_created = true;
}
return jerry_acquire_value(result);
}
static jerry_value_t prv_create_function(void *c_function_ptr) {
return jerry_create_external_function(c_function_ptr);
}
bool rocky_add_function(jerry_value_t parent, char *name, jerry_external_handler_t handler) {
bool result = false;
JS_UNUSED_VAL = rocky_get_or_create_object(parent, name, prv_create_function, handler, &result);
return result;
}
bool rocky_add_global_function(char *name, jerry_external_handler_t handler) {
return rocky_add_function(jerry_create_undefined(), name, handler);
}
jerry_value_t rocky_add_constructor(char *name, jerry_external_handler_t handler) {
JS_VAR prototype = jerry_create_object();
JS_VAR rocky_object = rocky_get_rocky_singleton();
JS_VAR constructor = rocky_get_or_create_object(rocky_object, name,
prv_create_function, handler, NULL);
// JerryScript doesn't create a prototype for external/C functions :( probably to save memory?
jerry_set_object_field(prototype, "constructor", constructor);
jerry_set_object_field(constructor, "prototype", prototype);
return jerry_acquire_value(prototype);
}
jerry_value_t rocky_create_with_constructor(const char *rocky_constructor_name,
const jerry_value_t args_p[],
jerry_size_t args_count) {
JS_VAR rocky_object = rocky_get_rocky_singleton();
JS_VAR constructor = jerry_get_object_field(rocky_object, rocky_constructor_name);
JS_VAR object = jerry_construct_object(constructor, args_p, args_count);
return jerry_acquire_value(object);
}
// TODO: PBL-35780 make this part of app_state_get_rocky_runtime_context()
SECTION(".rocky_bss") static jerry_value_t s_rocky_singleton;
void rocky_set_rocky_singleton(jerry_value_t v) {
s_rocky_singleton = jerry_acquire_value(v);
JS_VAR global = jerry_get_global_object();
jerry_set_object_field(global, ROCKY_SINGLETON, v);
}
jerry_value_t rocky_get_rocky_singleton(void) {
return jerry_acquire_value(s_rocky_singleton);
}
void rocky_delete_singleton(void) {
JS_VAR rocky_str = jerry_create_string((const jerry_char_t *)ROCKY_SINGLETON);
JS_VAR global = jerry_get_global_object();
jerry_delete_property(global, rocky_str);
}
void rocky_define_property(jerry_value_t parent, const char *prop_name,
jerry_external_handler_t getter,
jerry_external_handler_t setter) {
jerry_property_descriptor_t prop_desc = {};
jerry_init_property_descriptor_fields(&prop_desc);
prop_desc.is_get_defined = getter != NULL;
prop_desc.getter = jerry_create_external_function(getter);
prop_desc.is_set_defined = setter != NULL;
prop_desc.setter = jerry_create_external_function(setter);
JS_VAR prop_name_js = jerry_create_string((const jerry_char_t *) prop_name);
JS_UNUSED_VAL = jerry_define_own_property(parent, prop_name_js, &prop_desc);
jerry_release_value(prop_desc.getter);
jerry_release_value(prop_desc.setter);
}
// If result has an error flag set, log the error.
// Note: this function releases the passed in value.
T_STATIC void prv_log_uncaught_error(const jerry_value_t result) {
if (jerry_value_has_error_flag(result)) {
rocky_error_print(result);
}
jerry_release_value(result);
}
void rocky_util_eval_and_log_uncaught_error(const jerry_char_t *source_p, size_t source_size) {
prv_log_uncaught_error(jerry_eval(source_p, source_size, false /*strict*/));
}
void rocky_util_call_user_function_and_log_uncaught_error(const jerry_value_t func_obj_val,
const jerry_value_t this_val,
const jerry_value_t args_p[],
jerry_size_t args_count) {
prv_log_uncaught_error(jerry_call_function(func_obj_val, this_val, args_p, args_count));
}
jerry_value_t rocky_util_create_date(struct tm *tick_time) {
JS_VAR date_constructor = jerry_get_global_builtin((const jerry_char_t *)"Date");
if (!jerry_value_is_constructor(date_constructor)) {
return jerry_create_undefined();
}
jerry_value_t date_obj;
if (tick_time) {
jerry_value_t args[] = {
jerry_create_number(1900 + tick_time->tm_year), jerry_create_number(tick_time->tm_mon),
jerry_create_number(tick_time->tm_mday), jerry_create_number(tick_time->tm_hour),
jerry_create_number(tick_time->tm_min), jerry_create_number(tick_time->tm_sec)
};
date_obj = jerry_construct_object(date_constructor, args, ARRAY_LENGTH(args));
for (unsigned i = 0; i < ARRAY_LENGTH(args); ++i) {
jerry_release_value(args[i]);
}
} else {
date_obj = jerry_construct_object(date_constructor, NULL, 0);
}
return date_obj;
}
void rocky_cleanup_js_var(const jerry_value_t *var) {
jerry_release_value(*var);
}