| /* |
| * Copyright © 2026 Behdad Esfahbod |
| * |
| * This is part of HarfBuzz, a text shaping library. |
| * |
| * Permission is hereby granted, without written agreement and without |
| * license or royalty fees, to use, copy, modify, and distribute this |
| * software and its documentation for any purpose, provided that the |
| * above copyright notice and the following two paragraphs appear in |
| * all copies of this software. |
| * |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
| * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
| * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
| * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| * |
| * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
| * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
| * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
| * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| * |
| * Author(s): Behdad Esfahbod |
| */ |
| |
| #ifndef HB_VECTOR_BUF_HH |
| #define HB_VECTOR_BUF_HH |
| |
| #include "hb.hh" |
| #include "hb-vector.hh" |
| #include <math.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| HB_INTERNAL const char * |
| hb_vector_decimal_point_get (void); |
| |
| struct hb_vector_buf_t : hb_vector_t<char> |
| { |
| unsigned precision = 2; |
| |
| unsigned scale_precision () const |
| { return precision < 7 ? 7 : precision; } |
| |
| bool append_len (const char *s, unsigned l) |
| { |
| unsigned old_len = length; |
| if (unlikely (!resize_dirty ((int) (old_len + l)))) |
| return false; |
| hb_memcpy (arrayZ + old_len, s, l); |
| return true; |
| } |
| |
| bool append_c (char ch) |
| { return push_or_fail (ch); } |
| |
| bool append_str (const char *s) |
| { return append_len (s, (unsigned) strlen (s)); } |
| |
| bool append_unsigned (unsigned v) |
| { |
| char tmp[16]; |
| snprintf (tmp, sizeof (tmp), "%u", v); |
| return append_len (tmp, (unsigned) strlen (tmp)); |
| } |
| |
| bool append_hex_byte (unsigned v) |
| { |
| char tmp[2] = {"0123456789ABCDEF"[(v >> 4) & 15], |
| "0123456789ABCDEF"[v & 15]}; |
| return append_len (tmp, 2); |
| } |
| |
| void append_num (float v) |
| { append_num (v, precision); } |
| |
| void append_num (float v, unsigned p) |
| { |
| if (p > 12) p = 12; |
| |
| float rounded_zero_threshold = 0.5f; |
| for (unsigned i = 0; i < p; i++) |
| rounded_zero_threshold *= 0.1f; |
| if (fabsf (v) < rounded_zero_threshold) |
| v = 0.f; |
| |
| if (!(v == v) || !std::isfinite (v)) |
| { |
| append_c ('0'); |
| return; |
| } |
| |
| char fmt[6]; |
| snprintf (fmt, sizeof (fmt), "%%.%uf", p); |
| char out[128]; |
| snprintf (out, sizeof (out), fmt, (double) v); |
| |
| const char *decimal_point = hb_vector_decimal_point_get (); |
| |
| if (decimal_point[0] != '.' || decimal_point[1] != '\0') |
| { |
| char *dp = strstr (out, decimal_point); |
| if (dp) |
| { |
| unsigned dp_len = (unsigned) strlen (decimal_point); |
| unsigned tail_len = (unsigned) strlen (dp + dp_len); |
| memmove (dp + 1, dp + dp_len, tail_len + 1); |
| *dp = '.'; |
| } |
| } |
| |
| char *dot = strchr (out, '.'); |
| if (dot) |
| { |
| char *end = out + strlen (out) - 1; |
| while (end > dot && *end == '0') |
| *end-- = '\0'; |
| if (end == dot) |
| *end = '\0'; |
| } |
| |
| append_len (out, (unsigned) strlen (out)); |
| } |
| |
| void append_svg_color (hb_color_t color, bool with_alpha) |
| { |
| unsigned r = hb_color_get_red (color); |
| unsigned g = hb_color_get_green (color); |
| unsigned b = hb_color_get_blue (color); |
| unsigned a = hb_color_get_alpha (color); |
| append_c ('#'); |
| if (((r >> 4) == (r & 0xF)) && |
| ((g >> 4) == (g & 0xF)) && |
| ((b >> 4) == (b & 0xF))) |
| { |
| append_c ("0123456789ABCDEF"[r & 0xF]); |
| append_c ("0123456789ABCDEF"[g & 0xF]); |
| append_c ("0123456789ABCDEF"[b & 0xF]); |
| } |
| else |
| { |
| append_hex_byte (r); |
| append_hex_byte (g); |
| append_hex_byte (b); |
| } |
| if (with_alpha && a != 255) |
| { |
| append_str ("\" fill-opacity=\""); |
| append_num (a / 255.f, 4); |
| } |
| } |
| |
| bool append_base64 (const uint8_t *data, unsigned len) |
| { |
| unsigned out_len = ((len + 2) / 3) * 4; |
| unsigned old_len = length; |
| if (unlikely (!resize_dirty ((int) (old_len + out_len)))) |
| return false; |
| |
| char *dst = arrayZ + old_len; |
| unsigned di = 0; |
| unsigned i = 0; |
| while (i + 2 < len) |
| { |
| unsigned v = ((unsigned) data[i] << 16) | |
| ((unsigned) data[i + 1] << 8) | |
| ((unsigned) data[i + 2]); |
| dst[di++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(v >> 18) & 63]; |
| dst[di++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(v >> 12) & 63]; |
| dst[di++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(v >> 6) & 63]; |
| dst[di++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[v & 63]; |
| i += 3; |
| } |
| |
| if (i < len) |
| { |
| unsigned v = (unsigned) data[i] << 16; |
| if (i + 1 < len) |
| v |= (unsigned) data[i + 1] << 8; |
| dst[di++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(v >> 18) & 63]; |
| dst[di++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(v >> 12) & 63]; |
| dst[di++] = (i + 1 < len) ? "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(v >> 6) & 63] : '='; |
| dst[di++] = '='; |
| } |
| |
| return true; |
| } |
| }; |
| |
| #endif /* HB_VECTOR_BUF_HH */ |