diff options
-rw-r--r-- | content/handlers/html/Makefile | 1 | ||||
-rw-r--r-- | content/handlers/html/box_construct.c | 286 | ||||
-rw-r--r-- | content/handlers/html/list_counter_style.c | 312 | ||||
-rw-r--r-- | content/handlers/html/list_counter_style.h | 45 |
4 files changed, 366 insertions, 278 deletions
diff --git a/content/handlers/html/Makefile b/content/handlers/html/Makefile index 8bb329b76..968c96feb 100644 --- a/content/handlers/html/Makefile +++ b/content/handlers/html/Makefile @@ -16,6 +16,7 @@ S_HTML := box_construct.c \ imagemap.c \ interaction.c \ layout.c \ + list_counter_style.c \ object.c \ redraw.c \ redraw_border.c \ diff --git a/content/handlers/html/box_construct.c b/content/handlers/html/box_construct.c index cf0d91607..9204090fe 100644 --- a/content/handlers/html/box_construct.c +++ b/content/handlers/html/box_construct.c @@ -47,6 +47,7 @@ #include "html/box_special.h" #include "html/box_normalise.h" #include "html/form_internal.h" +#include "html/list_counter_style.h" /** * Context for box tree construction @@ -396,284 +397,13 @@ static unsigned int compute_list_marker_index(struct box *last) return last->list_marker->rows + 1; } - -/** - * Roman numeral conversion - * - * \return The number of characters that are nesesary for full output - */ -static int -ntoromannumeral(char *buf, const size_t maxlen, int value, const char *C) -{ - const int S[] = { 0, 2, 4, 2, 4, 2, 4 }; - const int D[] = { 1000, 500, 100, 50, 10, 5, 1 }; - const size_t L = sizeof(D) / sizeof(int) - 1; - size_t k = 0; /* index into output buffer */ - unsigned int i = 0; /* index into maps */ - int r, r2; - - while (value > 0) { - if (D[i] <= value) { - r = value / D[i]; - value = value - (r * D[i]); - if (i < L) { - /* lookahead */ - r2 = value / D[i+1]; - } - if (i < L && r2 >= S[i+1]) { - /* will violate repeat boundary on next pass */ - value = value - (r2 * D[i+1]); - if (k < maxlen) buf[k++] = C[i+1]; - if (k < maxlen) buf[k++] = C[i-1]; - } else if (S[i] && r >= S[i]) { - /* violated repeat boundary on this pass */ - if (k < maxlen) buf[k++] = C[i]; - if (k < maxlen) buf[k++] = C[i-1]; - } else { - while (r-- > 0 && k < maxlen) { - buf[k++] = C[i]; - } - } - } - i++; - } - if (k < maxlen) { - buf[k] = '\0'; - } - return k; -} - - -/** - * lower case roman numeral - */ -static int ntolcromannumeral(char *buf, const size_t maxlen, int value) -{ - const char C[] = { 'm', 'd', 'c', 'l', 'x', 'v', 'i' }; - return ntoromannumeral(buf, maxlen, value, C); -} - -/** - * upper case roman numeral - */ -static int ntoucromannumeral(char *buf, const size_t maxlen, int value) -{ - const char C[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' }; - return ntoromannumeral(buf, maxlen, value, C); -} - - -/** - * generate alphabet symbol values for latin and greek labelling - * - * fills array with alphabet values suitable for the input value - * - * \param ares Buffer to recive the converted values - * \param alen the length of \a ares buffer - * \param value The value to convert - * \param slen The number of symbols in the alphabet - * \return The length a complete conversion which may be larger than \a alen - */ -static size_t -calc_alphabet_values(uint8_t *ares, - const size_t alen, - int value, - unsigned char slen) -{ - size_t idx = 0; - uint8_t *first; - uint8_t *last; - - /* generate alphabet values in ascending order */ - while (value > 0) { - --value; - if (idx < alen) ares[idx] = value % slen; - idx++; - value = value / slen; - } - - /* put the values in decending order */ - first = ares; - if (idx < alen) { - last = first + (idx - 1); - } else { - last = first + (alen - 1); - } - while (first < last) { - *first ^= *last; - *last ^= *first; - *first ^= *last; - first++; - last--; - } - - return idx; -} - -/** - * maps alphabet values to output values with a symbol table - * - * Takes a list of alphabet values and for each one outputs the - * compete symbol (in utf8) to an output buffer. - * - * \param buf The oputput buffer - * \param buflen the length of \a buf - * \param aval array of alphabet values - * \param alen The number of values in \a alen - * \param symtab The symbol table - * \param symtablen The number of symbols in \a symtab - * \return The number of bytes needed in the output buffer whichmay be - * larger than \a buflen but the buffer will not be overrun - */ -static int -map_aval_to_symbols(char *buf, const size_t buflen, - const uint8_t *aval, const size_t alen, - const char symtab[][4], const size_t symtablen) -{ - size_t oidx; - size_t aidx; - int sidx; - - oidx = 0; - for (aidx=0; aidx < alen; aidx++) { - sidx=0; - while ((sidx < 4) && - (symtab[aval[aidx]][sidx] != 0)) { - if (oidx < buflen) { - buf[oidx] = symtab[aval[aidx]][sidx]; - } - oidx++; - sidx++; - } - } - return oidx; -} - -static int ntolcalpha(char *buf, const size_t buflen, int value) -{ - size_t alen; - uint8_t aval[20]; - const char symtab[][4] = { - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", - "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", - "u", "v", "w", "x", "y", "z" - }; - const size_t symtablen = sizeof(symtab) / 4; - - alen = calc_alphabet_values(aval, sizeof(aval), value, symtablen); - if (alen >= sizeof(aval)) { - *buf = '?'; - return 1; - } - - return map_aval_to_symbols(buf, buflen, aval, alen, symtab, symtablen); -} - -static int ntoucalpha(char *buf, const size_t buflen, int value) -{ - size_t alen; - uint8_t aval[20]; - const char symtab[][4] = { - "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", - "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", - "U", "V", "W", "X", "Y", "Z" - }; - const size_t symtablen = sizeof(symtab) / 4; - - alen = calc_alphabet_values(aval, sizeof(aval), value, symtablen); - if (alen >= sizeof(aval)) { - *buf = '?'; - return 1; - } - - return map_aval_to_symbols(buf, buflen, aval, alen, symtab, symtablen); -} - -static int ntolcgreek(char *buf, const size_t buflen, int value) -{ - size_t alen; - uint8_t aval[20]; - const char symtab[][4] = { - "α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ", - "λ", "μ", "ν", "ξ", "ο", "π", "ρ", "σ", "τ", "υ", - "φ", "χ", "ψ", "ω" - }; - const size_t symtablen = sizeof(symtab) / 4; - - alen = calc_alphabet_values(aval, sizeof(aval), value, symtablen); - if (alen >= sizeof(aval)) { - *buf = '?'; - return 1; - } - - return map_aval_to_symbols(buf, buflen, aval, alen, symtab, symtablen); -} - /** - * format value into a list marker with a style + * maximum length of a list marker * - * The value is a one based index into the list. This means for - * numeric printing the value must be incremented by one. + * enough for 9,999,999,999,999,999,999 in decimal + * or six characters for 3byte utf8 */ -static size_t -format_list_marker_value(char *text, - size_t text_len, - enum css_list_style_type_e list_style_type, - unsigned int value) -{ - int res = -1; - - switch (list_style_type) { - case CSS_LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO: - res = snprintf(text, text_len, "%02u", value); - break; - - case CSS_LIST_STYLE_TYPE_LOWER_ROMAN: - res = ntolcromannumeral(text, text_len, value); - break; - - case CSS_LIST_STYLE_TYPE_UPPER_ROMAN: - res = ntoucromannumeral(text, text_len, value); - break; - - case CSS_LIST_STYLE_TYPE_LOWER_ALPHA: - case CSS_LIST_STYLE_TYPE_LOWER_LATIN: - res = ntolcalpha(text, text_len, value); - break; - - case CSS_LIST_STYLE_TYPE_UPPER_ALPHA: - case CSS_LIST_STYLE_TYPE_UPPER_LATIN: - res = ntoucalpha(text, text_len, value); - break; - - case CSS_LIST_STYLE_TYPE_LOWER_GREEK: - res = ntolcgreek(text, text_len, value); - break; - - case CSS_LIST_STYLE_TYPE_ARMENIAN: - case CSS_LIST_STYLE_TYPE_GEORGIAN: - case CSS_LIST_STYLE_TYPE_DECIMAL: - default: - res = snprintf(text, text_len, "%u", value); - break; - } - - /* deal with error */ - if (res < 0) { - text[0] = 0; - return 0; - } - - /* deal with overflow */ - if ((size_t)res >= (text_len-2)) { - res = text_len-2; - } - text[res++] = '.'; - text[res++] = 0; - - return res; -} - +#define LIST_MARKER_SIZE 20 /** * Construct a list marker box @@ -731,12 +461,12 @@ box_construct_marker(struct box *box, default: marker->rows = compute_list_marker_index(parent->last); - marker->text = talloc_array(ctx->bctx, char, 20); + marker->text = talloc_array(ctx->bctx, char, LIST_MARKER_SIZE); if (marker->text == NULL) return false; - marker->length = format_list_marker_value(marker->text, - 20, + marker->length = list_counter_style_value(marker->text, + LIST_MARKER_SIZE, list_style_type, marker->rows); break; diff --git a/content/handlers/html/list_counter_style.c b/content/handlers/html/list_counter_style.c new file mode 100644 index 000000000..a5ce3ae64 --- /dev/null +++ b/content/handlers/html/list_counter_style.c @@ -0,0 +1,312 @@ +/* + * Copyright 2021 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * Implementation of css list counter styling + */ + +#include <stddef.h> +#include <stdio.h> + +#include "css/select.h" + +#include "html/list_counter_style.h" + + +/** + * maps alphabet values to output values with a symbol table + * + * Takes a list of alphabet values and for each one outputs the + * compete symbol (in utf8) to an output buffer. + * + * \param buf The oputput buffer + * \param buflen the length of \a buf + * \param aval array of alphabet values + * \param alen The number of values in \a alen + * \param symtab The symbol table + * \param symtablen The number of symbols in \a symtab + * \return The number of bytes needed in the output buffer whichmay be + * larger than \a buflen but the buffer will not be overrun + */ +static int +map_aval_to_symbols(char *buf, const size_t buflen, + const uint8_t *aval, const size_t alen, + const char symtab[][4], const size_t symtablen) +{ + size_t oidx; + size_t aidx; + int sidx; + + oidx = 0; + for (aidx=0; aidx < alen; aidx++) { + sidx=0; + while ((sidx < 4) && + (symtab[aval[aidx]][sidx] != 0)) { + if (oidx < buflen) { + buf[oidx] = symtab[aval[aidx]][sidx]; + } + oidx++; + sidx++; + } + } + return oidx; +} + + +/** + * generate alphabet symbol values for latin and greek labelling + * + * fills array with alphabet values suitable for the input value + * + * \param ares Buffer to recive the converted values + * \param alen the length of \a ares buffer + * \param value The value to convert + * \param slen The number of symbols in the alphabet + * \return The length a complete conversion which may be larger than \a alen + */ +static size_t +calc_alphabet_values(uint8_t *ares, + const size_t alen, + int value, + unsigned char slen) +{ + size_t idx = 0; + uint8_t *first; + uint8_t *last; + + /* generate alphabet values in ascending order */ + while (value > 0) { + --value; + if (idx < alen) ares[idx] = value % slen; + idx++; + value = value / slen; + } + + /* put the values in decending order */ + first = ares; + if (idx < alen) { + last = first + (idx - 1); + } else { + last = first + (alen - 1); + } + while (first < last) { + *first ^= *last; + *last ^= *first; + *first ^= *last; + first++; + last--; + } + + return idx; +} + + +/** + * Roman numeral conversion + * + * \return The number of characters that are nesesary for full output + */ +static int +ntoromannumeral(char *buf, const size_t maxlen, int value, const char *C) +{ + const int S[] = { 0, 2, 4, 2, 4, 2, 4 }; + const int D[] = { 1000, 500, 100, 50, 10, 5, 1 }; + const size_t L = sizeof(D) / sizeof(int) - 1; + size_t k = 0; /* index into output buffer */ + unsigned int i = 0; /* index into maps */ + int r, r2; + + while (value > 0) { + if (D[i] <= value) { + r = value / D[i]; + value = value - (r * D[i]); + if (i < L) { + /* lookahead */ + r2 = value / D[i+1]; + } + if (i < L && r2 >= S[i+1]) { + /* will violate repeat boundary on next pass */ + value = value - (r2 * D[i+1]); + if (k < maxlen) buf[k++] = C[i+1]; + if (k < maxlen) buf[k++] = C[i-1]; + } else if (S[i] && r >= S[i]) { + /* violated repeat boundary on this pass */ + if (k < maxlen) buf[k++] = C[i]; + if (k < maxlen) buf[k++] = C[i-1]; + } else { + while (r-- > 0 && k < maxlen) { + buf[k++] = C[i]; + } + } + } + i++; + } + if (k < maxlen) { + buf[k] = '\0'; + } + return k; +} + + +/** + * lower case roman numeral + */ +static int ntolcromannumeral(char *buf, const size_t maxlen, int value) +{ + const char C[] = { 'm', 'd', 'c', 'l', 'x', 'v', 'i' }; + return ntoromannumeral(buf, maxlen, value, C); +} + +/** + * upper case roman numeral + */ +static int ntoucromannumeral(char *buf, const size_t maxlen, int value) +{ + const char C[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' }; + return ntoromannumeral(buf, maxlen, value, C); +} + + + + +static int ntolcalpha(char *buf, const size_t buflen, int value) +{ + size_t alen; + uint8_t aval[20]; + const char symtab[][4] = { + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", + "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", + "u", "v", "w", "x", "y", "z" + }; + const size_t symtablen = sizeof(symtab) / 4; + + alen = calc_alphabet_values(aval, sizeof(aval), value, symtablen); + if (alen >= sizeof(aval)) { + *buf = '?'; + return 1; + } + + return map_aval_to_symbols(buf, buflen, aval, alen, symtab, symtablen); +} + +static int ntoucalpha(char *buf, const size_t buflen, int value) +{ + size_t alen; + uint8_t aval[20]; + const char symtab[][4] = { + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", + "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", + "U", "V", "W", "X", "Y", "Z" + }; + const size_t symtablen = sizeof(symtab) / 4; + + alen = calc_alphabet_values(aval, sizeof(aval), value, symtablen); + if (alen >= sizeof(aval)) { + *buf = '?'; + return 1; + } + + return map_aval_to_symbols(buf, buflen, aval, alen, symtab, symtablen); +} + +static int ntolcgreek(char *buf, const size_t buflen, int value) +{ + size_t alen; + uint8_t aval[20]; + const char symtab[][4] = { + "α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ", + "λ", "μ", "ν", "ξ", "ο", "π", "ρ", "σ", "τ", "υ", + "φ", "χ", "ψ", "ω" + }; + const size_t symtablen = sizeof(symtab) / 4; + + alen = calc_alphabet_values(aval, sizeof(aval), value, symtablen); + if (alen >= sizeof(aval)) { + *buf = '?'; + return 1; + } + + return map_aval_to_symbols(buf, buflen, aval, alen, symtab, symtablen); +} + + +/** + * format value into a list marker with a style + * + * The value is a one based index into the list. This means for + * numeric printing the value must be incremented by one. + */ +size_t +list_counter_style_value(char *text, + size_t text_len, + enum css_list_style_type_e list_style_type, + unsigned int value) +{ + int res = -1; + + switch (list_style_type) { + case CSS_LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO: + res = snprintf(text, text_len, "%02u", value); + break; + + case CSS_LIST_STYLE_TYPE_LOWER_ROMAN: + res = ntolcromannumeral(text, text_len, value); + break; + + case CSS_LIST_STYLE_TYPE_UPPER_ROMAN: + res = ntoucromannumeral(text, text_len, value); + break; + + case CSS_LIST_STYLE_TYPE_LOWER_ALPHA: + case CSS_LIST_STYLE_TYPE_LOWER_LATIN: + res = ntolcalpha(text, text_len, value); + break; + + case CSS_LIST_STYLE_TYPE_UPPER_ALPHA: + case CSS_LIST_STYLE_TYPE_UPPER_LATIN: + res = ntoucalpha(text, text_len, value); + break; + + case CSS_LIST_STYLE_TYPE_LOWER_GREEK: + res = ntolcgreek(text, text_len, value); + break; + + case CSS_LIST_STYLE_TYPE_ARMENIAN: + case CSS_LIST_STYLE_TYPE_GEORGIAN: + case CSS_LIST_STYLE_TYPE_DECIMAL: + default: + res = snprintf(text, text_len, "%u", value); + break; + } + + /* deal with error */ + if (res < 0) { + text[0] = 0; + return 0; + } + + /* deal with overflow */ + if ((size_t)res >= (text_len-2)) { + res = text_len-2; + } + text[res++] = '.'; + text[res++] = 0; + + return res; +} diff --git a/content/handlers/html/list_counter_style.h b/content/handlers/html/list_counter_style.h new file mode 100644 index 000000000..6446b933d --- /dev/null +++ b/content/handlers/html/list_counter_style.h @@ -0,0 +1,45 @@ +/* + * Copyright 2021 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * List counter style handling + * + * These functions provide font related services. They all work on + * UTF-8 strings with lengths given. + */ + +#ifndef NETSURF_HTML_LIST_COUNTER_STYLE_H +#define NETSURF_HTML_LIST_COUNTER_STYLE_H + +/** + * format value into a list marker with a style + * + * \param text The buffer to recive the output + * \param text_len The length available in \a text + * \param list_style_type The css list style type + * \param value The value to style + * \return The size of data placed in \a text + */ +size_t +list_counter_style_value(char *text, + size_t text_len, + enum css_list_style_type_e list_style_type, + unsigned int value); + +#endif |