Mercurial > malikania
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient-js/malikania/js-color.cpp Thu Aug 18 11:07:34 2016 +0200 @@ -0,0 +1,191 @@ +/* + * 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