diff options
Diffstat (limited to 'pango2/pango-utils.c')
-rw-r--r-- | pango2/pango-utils.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/pango2/pango-utils.c b/pango2/pango-utils.c new file mode 100644 index 00000000..89e20dac --- /dev/null +++ b/pango2/pango-utils.c @@ -0,0 +1,377 @@ +/* Pango2 + * pango-utils.c: Utilities for internal functions and modules + * + * Copyright (C) 2000 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <locale.h> + +#include "pango-font.h" +#include "pango-features.h" +#include "pango-impl-utils.h" + +#include <glib/gstdio.h> + +#ifndef HAVE_FLOCKFILE +# define flockfile(f) (void)1 +# define funlockfile(f) (void)1 +# define getc_unlocked(f) getc(f) +#endif /* !HAVE_FLOCKFILE */ + +#ifdef G_OS_WIN32 + +#include <sys/types.h> + +#define STRICT +#include <windows.h> + +#endif + +/** + * pango2_version: + * + * Returns the encoded version of Pango2 available at run-time. + * + * This is similar to the macro %PANGO2_VERSION except that the macro + * returns the encoded version available at compile-time. A version + * number can be encoded into an integer using PANGO2_VERSION_ENCODE(). + * + * Returns: The encoded version of Pango2 library available at run time. + */ +int +pango2_version (void) +{ + return PANGO2_VERSION; +} + +/** + * pango2_version_string: + * + * Returns the version of Pango2 available at run-time. + * + * This is similar to the macro %PANGO2_VERSION_STRING except that the + * macro returns the version available at compile-time. + * + * Returns: A string containing the version of Pango2 library available + * at run time. The returned string is owned by Pango2 and should not + * be modified or freed. + */ +const char * +pango2_version_string (void) +{ + return PANGO2_VERSION_STRING; +} + +/** + * pango2_version_check: + * @required_major: the required major version + * @required_minor: the required minor version + * @required_micro: the required major version + * + * Checks that the Pango2 library in use is compatible with the + * given version. + * + * Generally you would pass in the constants %PANGO2_VERSION_MAJOR, + * %PANGO2_VERSION_MINOR, %PANGO2_VERSION_MICRO as the three arguments + * to this function; that produces a check that the library in use at + * run-time is compatible with the version of Pango2 the application or + * module was compiled against. + * + * Compatibility is defined by two things: first the version + * of the running library is newer than the version + * @required_major.required_minor.@required_micro. Second + * the running library must be binary compatible with the + * version @required_major.required_minor.@required_micro + * (same major version.) + * + * For compile-time version checking use PANGO2_VERSION_CHECK(). + * + * Return value: (nullable): %NULL if the Pango2 library is compatible + * with the given version, or a string describing the version + * mismatch. The returned string is owned by Pango2 and should not + * be modified or freed. + */ +const char * +pango2_version_check (int required_major, + int required_minor, + int required_micro) +{ + int pango2_effective_micro = 100 * PANGO2_VERSION_MINOR + PANGO2_VERSION_MICRO; + int required_effective_micro = 100 * required_minor + required_micro; + + if (required_major > PANGO2_VERSION_MAJOR) + return "Pango2 version too old (major mismatch)"; + if (required_major < PANGO2_VERSION_MAJOR) + return "Pango2 version too new (major mismatch)"; + if (required_effective_micro < pango2_effective_micro - PANGO2_BINARY_AGE) + return "Pango2 version too new (micro mismatch)"; + if (required_effective_micro > pango2_effective_micro) + return "Pango2 version too old (micro mismatch)"; + return NULL; +} + +/** + * pango2_is_zero_width: + * @ch: a Unicode character + * + * Checks if a character that should not be normally rendered. + * + * This includes all Unicode characters with "ZERO WIDTH" in their name, + * as well as *bidi* formatting characters, and a few other ones. + * + * This is totally different from [func@GLib.unichar_iszerowidth] and is at best misnamed. + * + * Return value: %TRUE if @ch is a zero-width character, %FALSE otherwise + */ +gboolean +pango2_is_zero_width (gunichar ch) +{ +/* Zero Width characters: + * + * 00AD SOFT HYPHEN + * 034F COMBINING GRAPHEME JOINER + * + * 200B ZERO WIDTH SPACE + * 200C ZERO WIDTH NON-JOINER + * 200D ZERO WIDTH JOINER + * 200E LEFT-TO-RIGHT MARK + * 200F RIGHT-TO-LEFT MARK + * + * 2028 LINE SEPARATOR + * + * 2060 WORD JOINER + * 2061 FUNCTION APPLICATION + * 2062 INVISIBLE TIMES + * 2063 INVISIBLE SEPARATOR + * + * 2066 LEFT-TO-RIGHT ISOLATE + * 2067 RIGHT-TO-LEFT ISOLATE + * 2068 FIRST STRONG ISOLATE + * 2069 POP DIRECTIONAL ISOLATE + * + * 202A LEFT-TO-RIGHT EMBEDDING + * 202B RIGHT-TO-LEFT EMBEDDING + * 202C POP DIRECTIONAL FORMATTING + * 202D LEFT-TO-RIGHT OVERRIDE + * 202E RIGHT-TO-LEFT OVERRIDE + * + * FEFF ZERO WIDTH NO-BREAK SPACE + */ + return ((ch & ~(gunichar)0x007F) == 0x2000 && ( + (ch >= 0x200B && ch <= 0x200F) || + (ch >= 0x202A && ch <= 0x202E) || + (ch >= 0x2060 && ch <= 0x2063) || + (ch >= 0x2066 && ch <= 0x2069) || + (ch == 0x2028) + )) || G_UNLIKELY (ch == 0x00AD + || ch == 0x034F + || ch == 0xFEFF); +} + +/** + * pango2_units_from_double: + * @d: double floating-point value + * + * Converts a floating-point number to Pango2 units. + * + * The conversion is done by multiplying @d by %PANGO2_SCALE and + * rounding the result to nearest integer. + * + * Return value: the value in Pango2 units. + */ +int +pango2_units_from_double (double d) +{ + return (int)floor (d * PANGO2_SCALE + 0.5); +} + +/** + * pango2_units_to_double: + * @i: value in Pango2 units + * + * Converts a number in Pango2 units to floating-point. + * + * The conversion is done by dividing @i by %PANGO2_SCALE. + * + * Return value: the double value. + */ +double +pango2_units_to_double (int i) +{ + return (double)i / PANGO2_SCALE; +} + +/** + * pango2_extents_to_pixels: + * @inclusive: (nullable): rectangle to round to pixels inclusively + * @nearest: (nullable): rectangle to round to nearest pixels + * + * Converts extents from Pango2 units to device units. + * + * The conversion is done by dividing by the %PANGO2_SCALE factor and + * performing rounding. + * + * The @inclusive rectangle is converted by flooring the x/y coordinates + * and extending width/height, such that the final rectangle completely + * includes the original rectangle. + * + * The @nearest rectangle is converted by rounding the coordinates + * of the rectangle to the nearest device unit (pixel). + * + * The rule to which argument to use is: if you want the resulting device-space + * rectangle to completely contain the original rectangle, pass it in as + * @inclusive. If you want two touching-but-not-overlapping rectangles stay + * touching-but-not-overlapping after rounding to device units, pass them in + * as @nearest. + */ +void +pango2_extents_to_pixels (Pango2Rectangle *inclusive, + Pango2Rectangle *nearest) +{ + if (inclusive) + { + int orig_x = inclusive->x; + int orig_y = inclusive->y; + + inclusive->x = PANGO2_PIXELS_FLOOR (inclusive->x); + inclusive->y = PANGO2_PIXELS_FLOOR (inclusive->y); + + inclusive->width = PANGO2_PIXELS_CEIL (orig_x + inclusive->width ) - inclusive->x; + inclusive->height = PANGO2_PIXELS_CEIL (orig_y + inclusive->height) - inclusive->y; + } + + if (nearest) + { + int orig_x = nearest->x; + int orig_y = nearest->y; + + nearest->x = PANGO2_PIXELS (nearest->x); + nearest->y = PANGO2_PIXELS (nearest->y); + + nearest->width = PANGO2_PIXELS (orig_x + nearest->width ) - nearest->x; + nearest->height = PANGO2_PIXELS (orig_y + nearest->height) - nearest->y; + } +} + +/** + * pango2_find_paragraph_boundary: + * @text: UTF-8 text + * @length: length of @text in bytes, or -1 if nul-terminated + * @paragraph_delimiter_index: (out): return location for index of + * delimiter + * @next_paragraph_start: (out): return location for start of next + * paragraph + * + * Locates a paragraph boundary in @text. + * + * A boundary is caused by delimiter characters, such as + * a newline, carriage return, carriage return-newline pair, + * or Unicode paragraph separator character. + * + * The index of the run of delimiters is returned in + * @paragraph_delimiter_index. The index of the start of the + * next paragraph (index after all delimiters) is stored n + * @next_paragraph_start. + * + * If no delimiters are found, both @paragraph_delimiter_index + * and @next_paragraph_start are filled with the length of @text + * (an index one off the end). + */ +void +pango2_find_paragraph_boundary (const char *text, + int length, + int *paragraph_delimiter_index, + int *next_paragraph_start) +{ + const char *p = text; + const char *end; + const char *start = NULL; + const char *delimiter = NULL; + + /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in + * Unicode 5.0; update the following code if that changes. + */ + + /* prev_sep is the first byte of the previous separator. Since + * the valid separators are \r, \n, and PARAGRAPH_SEPARATOR, the + * first byte is enough to identify it. + */ + char prev_sep; + +#define PARAGRAPH_SEPARATOR_STRING "\xE2\x80\xA9" + + if (length < 0) + length = strlen (text); + + end = text + length; + + if (paragraph_delimiter_index) + *paragraph_delimiter_index = length; + + if (next_paragraph_start) + *next_paragraph_start = length; + + if (length == 0) + return; + + prev_sep = 0; + while (p < end) + { + if (prev_sep == '\n' || + prev_sep == PARAGRAPH_SEPARATOR_STRING[0]) + { + g_assert (delimiter); + start = p; + break; + } + else if (prev_sep == '\r') + { + /* don't break between \r and \n */ + if (*p != '\n') + { + g_assert (delimiter); + start = p; + break; + } + } + + if (*p == '\n' || + *p == '\r' || + !strncmp(p, PARAGRAPH_SEPARATOR_STRING, strlen (PARAGRAPH_SEPARATOR_STRING))) + { + if (delimiter == NULL) + delimiter = p; + prev_sep = *p; + } + else + prev_sep = 0; + + p = g_utf8_next_char (p); + } + + if (delimiter && paragraph_delimiter_index) + *paragraph_delimiter_index = delimiter - text; + + if (start && next_paragraph_start) + *next_paragraph_start = start - text; +} |