From 8ef825d5bbc05cd645525f0c8130e55bc384b896 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Sat, 9 Aug 2014 15:28:50 +0200 Subject: [PATCH] Parse delta exceptions file completely. Make `Deltas' structure a linked list. Rename old functions `TA_deltas_parse' and `TA_deltas_show' to `deltas_parse_line' and `deltas_show_line'. Add new versions for `TA_deltas_parse' and `TA_deltas_show' that handle all delta exceptions. --- lib/ta.h | 1 + lib/tadeltas.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- lib/tadeltas.h | 62 ++++++++----- 3 files changed, 313 insertions(+), 34 deletions(-) diff --git a/lib/ta.h b/lib/ta.h index de544ad..54902d5 100644 --- a/lib/ta.h +++ b/lib/ta.h @@ -30,6 +30,7 @@ #include #include +#include #define TTFAUTOHINT_GLYPH ".ttfautohint" diff --git a/lib/tadeltas.c b/lib/tadeltas.c index d7f46a1..37483d0 100644 --- a/lib/tadeltas.c +++ b/lib/tadeltas.c @@ -289,12 +289,29 @@ get_shift(char** string_p, } -TA_Error -TA_deltas_parse(FONT* font, - const char* s, - char** err_pos, - Deltas** deltas_p, - int ppem_min, int ppem_max) +/* + * Parse a delta exceptions line. + * + * In case of success (this is, the delta exceptions description in `s' is + * valid), `pos' is a pointer to the final zero byte in string `s'. In case + * of an error, it points to the offending character in string `s'. + * + * If s is NULL, the function exits immediately, with NULL as the value of + * `pos'. + * + * If the user provides a non-NULL `deltas' value, `deltas_parse' stores the + * parsed result in `*deltas', allocating the necessary memory. If there is + * no data (for example, an empty string or whitespace only) nothing gets + * allocated, and `*deltas' is set to NULL. + * + */ + +static TA_Error +deltas_parse_line(FONT* font, + const char* s, + char** err_pos, + Deltas** deltas_p, + int ppem_min, int ppem_max) { TA_Error error; @@ -553,19 +570,27 @@ TA_deltas_parse(FONT* font, void TA_deltas_free(Deltas* deltas) { - if (!deltas) - return; + while (deltas) + { + Deltas* tmp; - number_set_free(deltas->points); - number_set_free(deltas->ppems); - free(deltas); + number_set_free(deltas->points); + number_set_free(deltas->ppems); + + tmp = deltas; + deltas = deltas->next; + free(tmp); + } } +/* `len' is the length of the returned string */ + char* -TA_deltas_show(FONT* font, - Deltas* deltas) +deltas_show_line(FONT* font, + int* len, + Deltas* deltas) { int ret; char glyph_name_buf[64]; @@ -619,7 +644,240 @@ Exit: if (ret == -1) return NULL; + *len = ret; + return deltas_buf; } + +char* +TA_deltas_show(FONT* font, + Deltas* deltas) +{ + char* s; + int s_len; + + + /* we return an empty string if there is no data */ + s = (char*)malloc(1); + if (!s) + return NULL; + + *s = '\0'; + s_len = 1; + + while (deltas) + { + char* tmp; + int tmp_len; + char* s_new; + int s_len_new; + + + tmp = deltas_show_line(font, &tmp_len, deltas); + if (!tmp) + { + free(s); + return NULL; + } + + /* append current line to buffer, followed by a newline character */ + s_len_new = s_len + tmp_len + 1; + s_new = (char*)realloc(s, s_len_new); + if (!s_new) + { + free(s); + free(tmp); + return NULL; + } + + strcpy(s_new + s_len - 1, tmp); + s_new[s_len_new - 2] = '\n'; + s_new[s_len_new - 1] = '\0'; + + s = s_new; + s_len = s_len_new; + + free(tmp); + + deltas = deltas->next; + } + + return s; +} + + +/* Get a line from a buffer, starting at `pos'. The final EOL */ +/* character (or character pair) of the line (if existing) gets removed. */ +/* After the call, `pos' points to the position right after the line in */ +/* the buffer. The line is allocated with `malloc'; it returns NULL for */ +/* end of data and allocation errors; the latter can be recognized by a */ +/* changed value of `pos'. */ + +static char* +get_line(char** pos) +{ + const char* start = *pos; + const char* p = start; + size_t len; + char* s; + + + if (!*p) + return NULL; + + while (*p) + { + if (*p == '\n' || *p == '\r') + break; + + p++; + } + + len = p - start + 1; + + if (*p == '\r') + { + len--; + p++; + + if (*p == '\n') + p++; + } + else if (*p == '\n') + { + len--; + p++; + } + + *pos = (char*)p; + + s = (char*)malloc(len + 1); + if (!s) + return NULL; + + if (len) + strncpy(s, start, len); + s[len] = '\0'; + + return s; +} + + +TA_Error +TA_deltas_parse(FONT* font, + Deltas** deltas, + unsigned int* errlinenum_p, + char** errline_p, + char** errpos_p) +{ + FT_Error error; + + Deltas* cur; + Deltas* new_deltas; + Deltas* tmp; + Deltas* list; + + unsigned int linenum; + + char* bufpos; + char* bufpos_old; + + + /* nothing to do if no data */ + if (!font->deltas_buf) + return TA_Err_Ok; + + bufpos = font->deltas_buf; + bufpos_old = bufpos; + + linenum = 0; + cur = NULL; + + /* parse line by line */ + for (;;) + { + char* line; + char* errpos; + + + line = get_line(&bufpos); + if (!line) + { + if (bufpos == bufpos_old) /* end of data */ + break; + + *errlinenum_p = linenum; + *errline_p = NULL; + *errpos_p = NULL; + + return FT_Err_Out_Of_Memory; + } + + error = deltas_parse_line(font, + line, + &errpos, + deltas ? &new_deltas : NULL, + DELTA_PPEM_MIN, DELTA_PPEM_MAX); + if (error) + { + *errlinenum_p = linenum; + *errline_p = line; + *errpos_p = errpos; + + TA_deltas_free(cur); + + return error; + } + + if (deltas && new_deltas) + { + new_deltas->next = cur; + cur = new_deltas; + } + + free(line); + linenum++; + bufpos_old = bufpos; + } + + /* success; now reverse list to have elements in original order */ + list = NULL; + + while (cur) + { + tmp = cur; + cur = cur->next; + tmp->next = list; + list = tmp; + } + + if (deltas) + *deltas = list; + + return TA_Err_Ok; +} + + +/* + * + * Using + * + * delta_shift = 3 , + * + * the possible shift values in the instructions are indexed as follows: + * + * 0 -1px + * 1 -7/8px + * ... + * 7 -1/8px + * 8 1/8px + * ... + * 14 7/8px + * 15 1px + * + * (note that there is no index for a zero shift). + */ + + /* end of tadeltas.c */ diff --git a/lib/tadeltas.h b/lib/tadeltas.h index f221197..2bec05e 100644 --- a/lib/tadeltas.h +++ b/lib/tadeltas.h @@ -33,9 +33,26 @@ extern "C" { /* - * A structure to hold delta exceptions for a glyph. It gets allocated by a - * successful call to `TA_deltas_parse'. Use `TA_deltas_free' to deallocate - * it. + * For the generated TrueType bytecode, we use + * + * delta_base = 6 , + * + * which gives us the following ppem ranges for the three delta + * instructions: + * + * DELTAP1 6-21ppem + * DELTAP2 22-37ppem + * DELTAP3 38-53ppem . + */ + +#define DELTA_PPEM_MIN 6 +#define DELTA_PPEM_MAX 53 + + +/* + * A structure to hold delta exceptions for a glyph. A linked list of it + * gets allocated by a successful call to `TA_deltas_parse'. Use + * `TA_deltas_free' to deallocate the list. * * `x_shift' and `y_shift' are always in the range [-8;8]. */ @@ -48,12 +65,15 @@ typedef struct Deltas_ char x_shift; char y_shift; number_range* ppems; + + struct Deltas_* next; } Deltas; /* - * Parse a delta exceptions description in string `s', which has the - * following syntax: + * Parse a delta exceptions file. + * + * A line in a delta exceptions file has the following syntax: * * [] p [x ] [y ] @ * @@ -79,34 +99,34 @@ typedef struct Deltas_ * * Values for , must be in the range * [DELTA_SHIFT_MIN;DELTA_SHIFT_MAX]. Values for must be in the - * range given by `ppem_min' and `ppem_max'. Values for are - * limited by the number of points in the glyph. + * range [DELTA_PPEM_MIN;DELTA_PPEM_MAX]. Values for are limited + * by the number of points in the glyph. * * A comment starts with character `#'; the rest of the line is ignored. An * empty line is ignored also. * - * In case of success (this is, the delta exceptions description in `s' is - * valid), `pos' is a pointer to the final zero byte in string `s'. In case - * of an error, it points to the offending character in string `s'. - * - * If s is NULL, the function exits immediately, with NULL as the value of - * `pos'. + * The returned error codes are in the range 0x200-0x2FF; see + * `ttfautohint-errors.h' for all possible values. * * If the user provides a non-NULL `deltas' value, `TA_deltas_parse' stores - * the parsed result in `*deltas', allocated with `malloc'. If there is no - * data (for example, an empty string or whitespace only) nothing gets - * allocated, and `*deltas' is set to NULL. + * the parsed result in `*deltas'. If there is no data (for example, an + * empty string or whitespace only) nothing gets allocated, and `*deltas' is + * set to NULL. * - * The returned error codes are in the range 0x200-0x2FF; see - * `ttfautohint-errors.h' for all possible values. + * In case of error, `errlinenum_p' gives the line number in the delta + * exceptions file where the error occurred, `errline_p' the corresponding + * line, and `errpos_p' the position in this line. If there is no error, + * those three values are undefined. Both `errline_p' and `errpos_p' can be + * NULL even in case of an error; otherwise `errline_p' must be deallocated + * by the user. */ TA_Error TA_deltas_parse(FONT* font, - const char* s, - char** err_pos, Deltas** deltas, - int ppem_min, int ppem_max); + unsigned int* errlinenum_p, + char** errline_p, + char** errpos_p); /* -- 2.11.4.GIT