Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/source/svg/svg-parse.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/source/svg/svg-parse.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,355 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF 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 Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see <https://www.artifex.com/> or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#include "mupdf/fitz.h" +#include "svg-imp.h" + +#include <string.h> +#include <math.h> + +int svg_is_whitespace_or_comma(int c) +{ + return (c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA) || (c == ','); +} + +int svg_is_whitespace(int c) +{ + return (c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA); +} + +int svg_is_alpha(int c) +{ + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +int svg_is_digit(int c) +{ + return (c >= '0' && c <= '9') || + (c == 'e') || (c == 'E') || + (c == '+') || (c == '-') || (c == '.'); +} + +const char * +svg_lex_number(float *fp, const char *ss) +{ + const char *s = ss; + if (*s == '+' || *s == '-') + ++s; + while (*s >= '0' && *s <= '9') + ++s; + if (*s == '.') { + ++s; + while (*s >= '0' && *s <= '9') + ++s; + } + if (*s == 'e' || *s == 'E') { + ++s; + if (*s == '+' || *s == '-') + ++s; + while (*s >= '0' && *s <= '9') + ++s; + } + *fp = fz_atof(ss); + return s; +} + +float +svg_parse_number(const char *str, float min, float max, float inherit) +{ + float x; + if (!strcmp(str, "inherit")) + return inherit; + x = fz_atof(str); + if (x < min) return min; + if (x > max) return max; + return x; +} + +float +svg_parse_length(const char *str, float percent, float font_size) +{ + char *end; + float val; + + val = fz_strtof(str, &end); + if (end == str) + return 0; /* failed */ + + if (!strcmp(end, "px")) return val; + + if (!strcmp(end, "pt")) return val * 1.0f; + if (!strcmp(end, "pc")) return val * 12.0f; + if (!strcmp(end, "mm")) return val * 2.83464567f; + if (!strcmp(end, "cm")) return val * 28.3464567f; + if (!strcmp(end, "in")) return val * 72.0f; + + if (!strcmp(end, "em")) return val * font_size; + if (!strcmp(end, "ex")) return val * font_size * 0.5f; + + if (!strcmp(end, "%")) + return val * percent * 0.01f; + + if (end[0] == 0) + return val; + + return 0; +} + +/* Return angle in degrees */ +float +svg_parse_angle(const char *str) +{ + char *end; + float val; + + val = fz_strtof(str, &end); + if (end == str) + return 0; /* failed */ + + if (!strcmp(end, "deg")) + return val; + + if (!strcmp(end, "grad")) + return val * 0.9f; + + if (!strcmp(end, "rad")) + return val * FZ_RADIAN; + + return val; +} + +/* Coordinate transformations */ +fz_matrix +svg_parse_transform(fz_context *ctx, svg_document *doc, const char *str, fz_matrix transform) +{ + char keyword[20]; + int keywordlen; + float args[6]; + int nargs; + + nargs = 0; + keywordlen = 0; + + while (*str) + { + while (svg_is_whitespace_or_comma(*str)) + str ++; + if (*str == 0) + break; + + /* + * Parse keyword and opening parenthesis. + */ + + keywordlen = 0; + while (svg_is_alpha(*str) && keywordlen < (int)sizeof(keyword) - 1) + keyword[keywordlen++] = *str++; + keyword[keywordlen] = 0; + + if (keywordlen == 0) + fz_throw(ctx, FZ_ERROR_SYNTAX, "expected keyword in transform attribute"); + + while (svg_is_whitespace(*str)) + str ++; + + if (*str != '(') + fz_throw(ctx, FZ_ERROR_SYNTAX, "expected opening parenthesis in transform attribute"); + str ++; + + /* + * Parse list of numbers until closing parenthesis + */ + + nargs = 0; + while (*str && *str != ')' && nargs < 6) + { + while (svg_is_whitespace_or_comma(*str)) + str ++; + if (svg_is_digit(*str)) + str = svg_lex_number(&args[nargs++], str); + else + break; + } + + if (*str != ')') + fz_throw(ctx, FZ_ERROR_SYNTAX, "expected closing parenthesis in transform attribute"); + str ++; + + /* + * Execute the transform. + */ + + if (!strcmp(keyword, "matrix")) + { + if (nargs != 6) + fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to matrix(): %d", nargs); + transform = fz_concat(fz_make_matrix(args[0], args[1], args[2], args[3], args[4], args[5]), transform); + } + + else if (!strcmp(keyword, "translate")) + { + if (nargs == 1) + transform = fz_concat(fz_translate(args[0], 0), transform); + else if (nargs == 2) + transform = fz_concat(fz_translate(args[0], args[1]), transform); + else + fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to translate(): %d", nargs); + } + + else if (!strcmp(keyword, "scale")) + { + if (nargs == 1) + transform = fz_concat(fz_scale(args[0], args[0]), transform); + else if (nargs == 2) + transform = fz_concat(fz_scale(args[0], args[1]), transform); + else + fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to scale(): %d", nargs); + } + + else if (!strcmp(keyword, "rotate")) + { + if (nargs == 1) + transform = fz_concat(fz_rotate(args[0]), transform); + else if (nargs == 3) + { + transform = fz_concat(fz_translate(args[1], args[2]), transform); + transform = fz_concat(fz_rotate(args[0]), transform); + transform = fz_concat(fz_translate(-args[1], -args[2]), transform); + } + else + fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to rotate(): %d", nargs); + } + + else if (!strcmp(keyword, "skewX")) + { + if (nargs != 1) + fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to skewX(): %d", nargs); + transform = fz_concat(fz_make_matrix(1, 0, tanf(args[0] * FZ_DEGREE), 1, 0, 0), transform); + } + + else if (!strcmp(keyword, "skewY")) + { + if (nargs != 1) + fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to skewY(): %d", nargs); + transform = fz_concat(fz_make_matrix(1, tanf(args[0] * FZ_DEGREE), 0, 1, 0, 0), transform); + } + + else + { + fz_throw(ctx, FZ_ERROR_SYNTAX, "unknown transform function: %s", keyword); + } + } + + return transform; +} + +float +svg_parse_number_from_style(fz_context *ctx, svg_document *doc, const char *style, const char *att, float number) +{ + if (style) + { + char *end, *p = strstr(style, att); + if (p) + { + size_t n = strlen(att); + if (p[n] == ':') + { + p += n + 1; + while (*p && svg_is_whitespace(*p)) + ++p; + number = fz_strtof(p, &end); + if (end[0] == 'i' && end[1] == 'n') return number * 72; + if (end[0] == 'c' && end[1] == 'm') return number * 7200 / 254; + if (end[0] == 'm' && end[1] == 'm') return number * 720 / 254; + if (end[0] == 'p' && end[1] == 'c') return number * 12; + } + } + } + return number; +} + +int +svg_parse_enum_from_style(fz_context *ctx, svg_document *doc, const char *style, const char *att, + int ecount, const char *etable[], int value) +{ + char buf[100], *end, *p; + int i; + if (style) + { + p = strstr(style, att); + if (p) + { + size_t n = strlen(att); + if (p[n] == ':') + { + p += n + 1; + while (*p && svg_is_whitespace(*p)) + ++p; + fz_strlcpy(buf, p, sizeof buf); + end = strchr(buf, ';'); + if (end) + *end = 0; + for (i = 0; i < ecount; ++i) + if (!strcmp(etable[i], buf)) + return i; + } + } + } + return value; +} + +char * +svg_parse_string_from_style(fz_context *ctx, svg_document *doc, const char *style, const char *att, + char *buf, int buf_size, const char *value) +{ + char *end, *p, quote; + if (style) + { + p = strstr(style, att); + if (p) + { + size_t n = strlen(att); + if (p[n] == ':') + { + p += n + 1; + while (*p && svg_is_whitespace(*p)) + ++p; + quote = *p; + if (quote == '\'' || quote == '"') + { + fz_strlcpy(buf, p+1, buf_size); + end = strchr(buf, quote); + } + else + { + fz_strlcpy(buf, p, buf_size); + end = strchr(buf, ';'); + } + if (end) + *end = 0; + return buf; + } + } + } + fz_strlcpy(buf, value, buf_size); + return buf; +}
