Mercurial > malikania
view libclient-js/malikania/js-color.cpp @ 37:702e0a2b9e5e
Misc: make JavaScript different libraries, Closes T3
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 18 Aug 2016 11:07:34 +0200 |
parents | libclient/malikania/js-color.cpp@9af360f34c7d |
children |
line wrap: on
line source
/* * js-color.cpp -- color description (JavaScript binding) * * Copyright (c) 2013-2016 Malikania Authors * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <cassert> #include "js-color.hpp" #include "util.hpp" namespace malikania { namespace { std::uint8_t clampComponent(duk_context *ctx, int value, bool required) { if (value < 0 || value > 255) { if (required) duk_error(ctx, DUK_ERR_RANGE_ERROR, "%d is out of range (0, 255)", value); else value = util::clamp(value, 0, 255); } return static_cast<std::uint8_t>(value); } Color parseString(duk_context *ctx, duk_idx_t index, bool required) { assert(duk_is_string(ctx, index)); Color color; try { color = Color(duk_get_string(ctx, index)); } catch (const std::exception &ex) { if (required) duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return color; } Color parseObject(duk_context *ctx, duk_idx_t index, bool required) { assert(duk_is_object(ctx, index)); auto require = [&] (const auto prop) -> std::uint8_t { if (required && !duk_has_prop_string(ctx, index, prop)) duk_error(ctx, DUK_ERR_ERROR, "missing %s property in color description", prop); duk_get_prop_string(ctx, index, prop); auto comp = duk_get_int(ctx, -1); duk_pop(ctx); return clampComponent(ctx, comp, required); }; // Alpha is optional. duk_get_prop_string(ctx, index, "alpha"); auto alpha = duk_is_number(ctx, -1) ? duk_to_int(ctx, -1) : 255; duk_pop(ctx); return Color( require("red"), require("green"), require("blue"), clampComponent(ctx, alpha, required) ); } Color parse(duk_context *ctx, duk_idx_t index, bool required, Color color = {}) { switch (duk_get_type(ctx, index)) { case DUK_TYPE_STRING: color = parseString(ctx, index, required); break; case DUK_TYPE_OBJECT: color = parseObject(ctx, index, required); break; default: if (required) duk_error(ctx, DUK_ERR_TYPE_ERROR, "color (string, object) expected"); break; } return color; } duk_ret_t constructor(duk_context *ctx) { Color color; /* * The constructor allows an additional signature that takes 4 number * arguments, otherwise use the literal parsing functions. */ if (duk_get_top(ctx) >= 3) { // Alpha is optional. auto alpha = duk_is_number(ctx, 3) ? duk_to_int(ctx, 3) : 255; color = Color( clampComponent(ctx, duk_require_int(ctx, 0), true), clampComponent(ctx, duk_require_int(ctx, 1), true), clampComponent(ctx, duk_require_int(ctx, 2), true), clampComponent(ctx, alpha, true) ); } else if (duk_get_top(ctx) == 1) color = parse(ctx, 0, true); duk_ret_t ret; // Allow both constructor and non constructor calls. if (duk_is_constructor_call(ctx)) { duk_push_this(ctx); dukx_put_color(ctx, color); duk_pop(ctx); ret = 0; } else { dukx_push_color(ctx, color); ret = 1; } return ret; } } //! namespace Color dukx_get_color(duk_context *ctx, duk_idx_t index) { return parse(ctx, index, false); } Color dukx_require_color(duk_context *ctx, duk_idx_t index) { return parse(ctx, index, true); } Color dukx_optional_color(duk_context *ctx, duk_idx_t index, Color def) { return parse(ctx, index, false, std::move(def)); } void dukx_push_color(duk_context *ctx, const Color &color) { StackAssert sa(ctx, 1); duk_push_object(ctx); dukx_put_color(ctx, color); } void dukx_put_color(duk_context *ctx, const Color &color) { assert(duk_is_object(ctx, -1)); StackAssert sa(ctx, 0); duk_push_uint(ctx, color.red()); duk_put_prop_string(ctx, -2, "red"); duk_push_uint(ctx, color.green()); duk_put_prop_string(ctx, -2, "green"); duk_push_uint(ctx, color.blue()); duk_put_prop_string(ctx, -2, "blue"); duk_push_uint(ctx, color.alpha()); duk_put_prop_string(ctx, -2, "alpha"); } void dukx_load_color(duk_context *ctx) { StackAssert sa(ctx, 0); duk_get_global_string(ctx, "Malikania"); duk_push_c_function(ctx, constructor, DUK_VARARGS); duk_put_prop_string(ctx, -2, "Color"); duk_pop(ctx); } } // !malikania