#include #include #include #define RAPIDJSON_ASSERT(x) if (!(x)) throw ::std::runtime_error("Error parsing font description: " BOOST_PP_STRINGIZE(x)); #include #include namespace psemek::ui { namespace { std::string_view to_string(rapidjson::ParseErrorCode const & code) { using namespace rapidjson; switch (code) { case kParseErrorNone: return "no error"; case kParseErrorDocumentEmpty: return "document is empty"; case kParseErrorDocumentRootNotSingular: return "document root must not be followed by other values"; case kParseErrorValueInvalid: return "invalid value"; case kParseErrorObjectMissName: return "missing a name for object member"; case kParseErrorObjectMissColon: return "missing a colon after a name of object member"; case kParseErrorObjectMissCommaOrCurlyBracket: return "missing a comma or '}' after an object member"; case kParseErrorArrayMissCommaOrSquareBracket: return "missing a comma or ']' after an array element"; case kParseErrorStringUnicodeEscapeInvalidHex: return R"(Incorrect hex digit after \\u escape in string)"; case kParseErrorStringUnicodeSurrogateInvalid: return "surrogate pair in string is invalid"; case kParseErrorStringEscapeInvalid: return "invalid escape character in string"; case kParseErrorStringMissQuotationMark: return "missing a closing quotation mark in string"; case kParseErrorStringInvalidEncoding: return "invalid encoding in string"; case kParseErrorNumberTooBig: return "number too big to be stored in double"; case kParseErrorNumberMissFraction: return "missing fraction part in number"; case kParseErrorNumberMissExponent: return "missing exponent in number"; case kParseErrorTermination: return "parsing was terminated"; case kParseErrorUnspecificSyntaxError: return "unspecific syntax error"; default: return "(unknown error)"; } }; } bmfont_data bmfont_data::parse(io::istream && stream) { auto description_str = io::read_full(std::move(stream)); description_str.push_back(0); rapidjson::Document document; document.ParseInsitu(description_str.data()); if (document.HasParseError()) throw std::runtime_error(util::to_string("Error msdf font description: ", to_string(document.GetParseError()), " at ", document.GetErrorOffset())); bmfont_data result; { auto const & info = document["info"]; result.name = info["face"].GetString(); int size = info["size"].GetInt(); result.size = {size, size}; } if (document.HasMember("distanceField")) { auto const & sdf = document["distanceField"]; result.sdf_scale = sdf["distanceRange"].GetFloat(); } { auto const & sdf = document["common"]; result.baseline = sdf["base"].GetInt(); } { auto chars = document["chars"].GetArray(); for (auto const & charInfo : chars) { char32_t id = charInfo["id"].GetUint(); auto & data = result.glyphs[id]; data.start_x = charInfo["x"].GetInt(); data.start_y = charInfo["y"].GetInt(); data.size_x = charInfo["width"].GetInt(); data.size_y = charInfo["height"].GetInt(); data.offset_x = charInfo["xoffset"].GetInt(); data.offset_y = charInfo["yoffset"].GetInt(); data.advance = charInfo["xadvance"].GetInt(); data.offset_y = - data.offset_y - data.size_y; } } return result; } }