diff options
Diffstat (limited to 'libs/cairo-1.16.0/src/cairo-misc.c')
-rw-r--r-- | libs/cairo-1.16.0/src/cairo-misc.c | 1118 |
1 files changed, 1118 insertions, 0 deletions
diff --git a/libs/cairo-1.16.0/src/cairo-misc.c b/libs/cairo-1.16.0/src/cairo-misc.c new file mode 100644 index 0000000..6e63bc7 --- /dev/null +++ b/libs/cairo-1.16.0/src/cairo-misc.c @@ -0,0 +1,1118 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2007 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + * Adrian Johnson <ajohnson@redneon.com> + */ + +#include "cairoint.h" +#include "cairo-error-private.h" + +#include <stdio.h> +#include <errno.h> +#include <locale.h> +#ifdef HAVE_XLOCALE_H +#include <xlocale.h> +#endif + +COMPILE_TIME_ASSERT ((int)CAIRO_STATUS_LAST_STATUS < (int)CAIRO_INT_STATUS_UNSUPPORTED); +COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127); + +/** + * SECTION:cairo-status + * @Title: Error handling + * @Short_Description: Decoding cairo's status + * @See_Also: cairo_status(), cairo_surface_status(), cairo_pattern_status(), + * cairo_font_face_status(), cairo_scaled_font_status(), + * cairo_region_status() + * + * Cairo uses a single status type to represent all kinds of errors. A status + * value of %CAIRO_STATUS_SUCCESS represents no error and has an integer value + * of zero. All other status values represent an error. + * + * Cairo's error handling is designed to be easy to use and safe. All major + * cairo objects <firstterm>retain</firstterm> an error status internally which + * can be queried anytime by the users using cairo*_status() calls. In + * the mean time, it is safe to call all cairo functions normally even if the + * underlying object is in an error status. This means that no error handling + * code is required before or after each individual cairo function call. + **/ + +/* Public stuff */ + +/** + * cairo_status_to_string: + * @status: a cairo status + * + * Provides a human-readable description of a #cairo_status_t. + * + * Returns: a string representation of the status + * + * Since: 1.0 + **/ +const char * +cairo_status_to_string (cairo_status_t status) +{ + switch (status) { + case CAIRO_STATUS_SUCCESS: + return "no error has occurred"; + case CAIRO_STATUS_NO_MEMORY: + return "out of memory"; + case CAIRO_STATUS_INVALID_RESTORE: + return "cairo_restore() without matching cairo_save()"; + case CAIRO_STATUS_INVALID_POP_GROUP: + return "no saved group to pop, i.e. cairo_pop_group() without matching cairo_push_group()"; + case CAIRO_STATUS_NO_CURRENT_POINT: + return "no current point defined"; + case CAIRO_STATUS_INVALID_MATRIX: + return "invalid matrix (not invertible)"; + case CAIRO_STATUS_INVALID_STATUS: + return "invalid value for an input cairo_status_t"; + case CAIRO_STATUS_NULL_POINTER: + return "NULL pointer"; + case CAIRO_STATUS_INVALID_STRING: + return "input string not valid UTF-8"; + case CAIRO_STATUS_INVALID_PATH_DATA: + return "input path data not valid"; + case CAIRO_STATUS_READ_ERROR: + return "error while reading from input stream"; + case CAIRO_STATUS_WRITE_ERROR: + return "error while writing to output stream"; + case CAIRO_STATUS_SURFACE_FINISHED: + return "the target surface has been finished"; + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: + return "the surface type is not appropriate for the operation"; + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: + return "the pattern type is not appropriate for the operation"; + case CAIRO_STATUS_INVALID_CONTENT: + return "invalid value for an input cairo_content_t"; + case CAIRO_STATUS_INVALID_FORMAT: + return "invalid value for an input cairo_format_t"; + case CAIRO_STATUS_INVALID_VISUAL: + return "invalid value for an input Visual*"; + case CAIRO_STATUS_FILE_NOT_FOUND: + return "file not found"; + case CAIRO_STATUS_INVALID_DASH: + return "invalid value for a dash setting"; + case CAIRO_STATUS_INVALID_DSC_COMMENT: + return "invalid value for a DSC comment"; + case CAIRO_STATUS_INVALID_INDEX: + return "invalid index passed to getter"; + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: + return "clip region not representable in desired format"; + case CAIRO_STATUS_TEMP_FILE_ERROR: + return "error creating or writing to a temporary file"; + case CAIRO_STATUS_INVALID_STRIDE: + return "invalid value for stride"; + case CAIRO_STATUS_FONT_TYPE_MISMATCH: + return "the font type is not appropriate for the operation"; + case CAIRO_STATUS_USER_FONT_IMMUTABLE: + return "the user-font is immutable"; + case CAIRO_STATUS_USER_FONT_ERROR: + return "error occurred in a user-font callback function"; + case CAIRO_STATUS_NEGATIVE_COUNT: + return "negative number used where it is not allowed"; + case CAIRO_STATUS_INVALID_CLUSTERS: + return "input clusters do not represent the accompanying text and glyph arrays"; + case CAIRO_STATUS_INVALID_SLANT: + return "invalid value for an input cairo_font_slant_t"; + case CAIRO_STATUS_INVALID_WEIGHT: + return "invalid value for an input cairo_font_weight_t"; + case CAIRO_STATUS_INVALID_SIZE: + return "invalid value (typically too big) for the size of the input (surface, pattern, etc.)"; + case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: + return "user-font method not implemented"; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: + return "the device type is not appropriate for the operation"; + case CAIRO_STATUS_DEVICE_ERROR: + return "an operation to the device caused an unspecified error"; + case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: + return "invalid operation during mesh pattern construction"; + case CAIRO_STATUS_DEVICE_FINISHED: + return "the target device has been finished"; + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: + return "CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID used but no CAIRO_MIME_TYPE_JBIG2_GLOBAL data provided"; + case CAIRO_STATUS_PNG_ERROR: + return "error occurred in libpng while reading from or writing to a PNG file"; + case CAIRO_STATUS_FREETYPE_ERROR: + return "error occurred in libfreetype"; + case CAIRO_STATUS_WIN32_GDI_ERROR: + return "error occurred in the Windows Graphics Device Interface"; + case CAIRO_STATUS_TAG_ERROR: + return "invalid tag name, attributes, or nesting"; + default: + case CAIRO_STATUS_LAST_STATUS: + return "<unknown error status>"; + } +} + + +/** + * cairo_glyph_allocate: + * @num_glyphs: number of glyphs to allocate + * + * Allocates an array of #cairo_glyph_t's. + * This function is only useful in implementations of + * #cairo_user_scaled_font_text_to_glyphs_func_t where the user + * needs to allocate an array of glyphs that cairo will free. + * For all other uses, user can use their own allocation method + * for glyphs. + * + * This function returns %NULL if @num_glyphs is not positive, + * or if out of memory. That means, the %NULL return value + * signals out-of-memory only if @num_glyphs was positive. + * + * Returns: the newly allocated array of glyphs that should be + * freed using cairo_glyph_free() + * + * Since: 1.8 + **/ +cairo_glyph_t * +cairo_glyph_allocate (int num_glyphs) +{ + if (num_glyphs <= 0) + return NULL; + + return _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); +} +slim_hidden_def (cairo_glyph_allocate); + +/** + * cairo_glyph_free: + * @glyphs: array of glyphs to free, or %NULL + * + * Frees an array of #cairo_glyph_t's allocated using cairo_glyph_allocate(). + * This function is only useful to free glyph array returned + * by cairo_scaled_font_text_to_glyphs() where cairo returns + * an array of glyphs that the user will free. + * For all other uses, user can use their own allocation method + * for glyphs. + * + * Since: 1.8 + **/ +void +cairo_glyph_free (cairo_glyph_t *glyphs) +{ + free (glyphs); +} +slim_hidden_def (cairo_glyph_free); + +/** + * cairo_text_cluster_allocate: + * @num_clusters: number of text_clusters to allocate + * + * Allocates an array of #cairo_text_cluster_t's. + * This function is only useful in implementations of + * #cairo_user_scaled_font_text_to_glyphs_func_t where the user + * needs to allocate an array of text clusters that cairo will free. + * For all other uses, user can use their own allocation method + * for text clusters. + * + * This function returns %NULL if @num_clusters is not positive, + * or if out of memory. That means, the %NULL return value + * signals out-of-memory only if @num_clusters was positive. + * + * Returns: the newly allocated array of text clusters that should be + * freed using cairo_text_cluster_free() + * + * Since: 1.8 + **/ +cairo_text_cluster_t * +cairo_text_cluster_allocate (int num_clusters) +{ + if (num_clusters <= 0) + return NULL; + + return _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t)); +} +slim_hidden_def (cairo_text_cluster_allocate); + +/** + * cairo_text_cluster_free: + * @clusters: array of text clusters to free, or %NULL + * + * Frees an array of #cairo_text_cluster's allocated using cairo_text_cluster_allocate(). + * This function is only useful to free text cluster array returned + * by cairo_scaled_font_text_to_glyphs() where cairo returns + * an array of text clusters that the user will free. + * For all other uses, user can use their own allocation method + * for text clusters. + * + * Since: 1.8 + **/ +void +cairo_text_cluster_free (cairo_text_cluster_t *clusters) +{ + free (clusters); +} +slim_hidden_def (cairo_text_cluster_free); + + +/* Private stuff */ + +/** + * _cairo_validate_text_clusters: + * @utf8: UTF-8 text + * @utf8_len: length of @utf8 in bytes + * @glyphs: array of glyphs + * @num_glyphs: number of glyphs + * @clusters: array of cluster mapping information + * @num_clusters: number of clusters in the mapping + * @cluster_flags: cluster flags + * + * Check that clusters cover the entire glyphs and utf8 arrays, + * and that cluster boundaries are UTF-8 boundaries. + * + * Return value: %CAIRO_STATUS_SUCCESS upon success, or + * %CAIRO_STATUS_INVALID_CLUSTERS on error. + * The error is either invalid UTF-8 input, + * or bad cluster mapping. + **/ +cairo_status_t +_cairo_validate_text_clusters (const char *utf8, + int utf8_len, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags) +{ + cairo_status_t status; + unsigned int n_bytes = 0; + unsigned int n_glyphs = 0; + int i; + + for (i = 0; i < num_clusters; i++) { + int cluster_bytes = clusters[i].num_bytes; + int cluster_glyphs = clusters[i].num_glyphs; + + if (cluster_bytes < 0 || cluster_glyphs < 0) + goto BAD; + + /* A cluster should cover at least one character or glyph. + * I can't see any use for a 0,0 cluster. + * I can't see an immediate use for a zero-text cluster + * right now either, but they don't harm. + * Zero-glyph clusters on the other hand are useful for + * things like U+200C ZERO WIDTH NON-JOINER */ + if (cluster_bytes == 0 && cluster_glyphs == 0) + goto BAD; + + /* Since n_bytes and n_glyphs are unsigned, but the rest of + * values involved are signed, we can detect overflow easily */ + if (n_bytes+cluster_bytes > (unsigned int)utf8_len || n_glyphs+cluster_glyphs > (unsigned int)num_glyphs) + goto BAD; + + /* Make sure we've got valid UTF-8 for the cluster */ + status = _cairo_utf8_to_ucs4 (utf8+n_bytes, cluster_bytes, NULL, NULL); + if (unlikely (status)) + return _cairo_error (CAIRO_STATUS_INVALID_CLUSTERS); + + n_bytes += cluster_bytes ; + n_glyphs += cluster_glyphs; + } + + if (n_bytes != (unsigned int) utf8_len || n_glyphs != (unsigned int) num_glyphs) { + BAD: + return _cairo_error (CAIRO_STATUS_INVALID_CLUSTERS); + } + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_operator_bounded_by_mask: + * @op: a #cairo_operator_t + * + * A bounded operator is one where mask pixel + * of zero results in no effect on the destination image. + * + * Unbounded operators often require special handling; if you, for + * example, draw trapezoids with an unbounded operator, the effect + * extends past the bounding box of the trapezoids. + * + * Return value: %TRUE if the operator is bounded by the mask operand + **/ +cairo_bool_t +_cairo_operator_bounded_by_mask (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return TRUE; + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_ATOP: + return FALSE; + } + + ASSERT_NOT_REACHED; + return FALSE; +} + +/** + * _cairo_operator_bounded_by_source: + * @op: a #cairo_operator_t + * + * A bounded operator is one where source pixels of zero + * (in all four components, r, g, b and a) effect no change + * in the resulting destination image. + * + * Unbounded operators often require special handling; if you, for + * example, copy a surface with the SOURCE operator, the effect + * extends past the bounding box of the source surface. + * + * Return value: %TRUE if the operator is bounded by the source operand + **/ +cairo_bool_t +_cairo_operator_bounded_by_source (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return TRUE; + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_ATOP: + return FALSE; + } + + ASSERT_NOT_REACHED; + return FALSE; +} + +uint32_t +_cairo_operator_bounded_by_either (cairo_operator_t op) +{ + switch (op) { + default: + ASSERT_NOT_REACHED; + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE; + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + return CAIRO_OPERATOR_BOUND_BY_MASK; + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_ATOP: + return 0; + } + +} + +#if DISABLE_SOME_FLOATING_POINT +/* This function is identical to the C99 function lround(), except that it + * performs arithmetic rounding (floor(d + .5) instead of away-from-zero rounding) and + * has a valid input range of (INT_MIN, INT_MAX] instead of + * [INT_MIN, INT_MAX]. It is much faster on both x86 and FPU-less systems + * than other commonly used methods for rounding (lround, round, rint, lrint + * or float (d + 0.5)). + * + * The reason why this function is much faster on x86 than other + * methods is due to the fact that it avoids the fldcw instruction. + * This instruction incurs a large performance penalty on modern Intel + * processors due to how it prevents efficient instruction pipelining. + * + * The reason why this function is much faster on FPU-less systems is for + * an entirely different reason. All common rounding methods involve multiple + * floating-point operations. Each one of these operations has to be + * emulated in software, which adds up to be a large performance penalty. + * This function doesn't perform any floating-point calculations, and thus + * avoids this penalty. + */ +int +_cairo_lround (double d) +{ + uint32_t top, shift_amount, output; + union { + double d; + uint64_t ui64; + uint32_t ui32[2]; + } u; + + u.d = d; + + /* If the integer word order doesn't match the float word order, we swap + * the words of the input double. This is needed because we will be + * treating the whole double as a 64-bit unsigned integer. Notice that we + * use WORDS_BIGENDIAN to detect the integer word order, which isn't + * exactly correct because WORDS_BIGENDIAN refers to byte order, not word + * order. Thus, we are making the assumption that the byte order is the + * same as the integer word order which, on the modern machines that we + * care about, is OK. + */ +#if ( defined(FLOAT_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)) || \ + (!defined(FLOAT_WORDS_BIGENDIAN) && defined(WORDS_BIGENDIAN)) + { + uint32_t temp = u.ui32[0]; + u.ui32[0] = u.ui32[1]; + u.ui32[1] = temp; + } +#endif + +#ifdef WORDS_BIGENDIAN + #define MSW (0) /* Most Significant Word */ + #define LSW (1) /* Least Significant Word */ +#else + #define MSW (1) + #define LSW (0) +#endif + + /* By shifting the most significant word of the input double to the + * right 20 places, we get the very "top" of the double where the exponent + * and sign bit lie. + */ + top = u.ui32[MSW] >> 20; + + /* Here, we calculate how much we have to shift the mantissa to normalize + * it to an integer value. We extract the exponent "top" by masking out the + * sign bit, then we calculate the shift amount by subtracting the exponent + * from the bias. Notice that the correct bias for 64-bit doubles is + * actually 1075, but we use 1053 instead for two reasons: + * + * 1) To perform rounding later on, we will first need the target + * value in a 31.1 fixed-point format. Thus, the bias needs to be one + * less: (1075 - 1: 1074). + * + * 2) To avoid shifting the mantissa as a full 64-bit integer (which is + * costly on certain architectures), we break the shift into two parts. + * First, the upper and lower parts of the mantissa are shifted + * individually by a constant amount that all valid inputs will require + * at the very least. This amount is chosen to be 21, because this will + * allow the two parts of the mantissa to later be combined into a + * single 32-bit representation, on which the remainder of the shift + * will be performed. Thus, we decrease the bias by an additional 21: + * (1074 - 21: 1053). + */ + shift_amount = 1053 - (top & 0x7FF); + + /* We are done with the exponent portion in "top", so here we shift it off + * the end. + */ + top >>= 11; + + /* Before we perform any operations on the mantissa, we need to OR in + * the implicit 1 at the top (see the IEEE-754 spec). We needn't mask + * off the sign bit nor the exponent bits because these higher bits won't + * make a bit of difference in the rest of our calculations. + */ + u.ui32[MSW] |= 0x100000; + + /* If the input double is negative, we have to decrease the mantissa + * by a hair. This is an important part of performing arithmetic rounding, + * as negative numbers must round towards positive infinity in the + * halfwase case of -x.5. Since "top" contains only the sign bit at this + * point, we can just decrease the mantissa by the value of "top". + */ + u.ui64 -= top; + + /* By decrementing "top", we create a bitmask with a value of either + * 0x0 (if the input was negative) or 0xFFFFFFFF (if the input was positive + * and thus the unsigned subtraction underflowed) that we'll use later. + */ + top--; + + /* Here, we shift the mantissa by the constant value as described above. + * We can emulate a 64-bit shift right by 21 through shifting the top 32 + * bits left 11 places and ORing in the bottom 32 bits shifted 21 places + * to the right. Both parts of the mantissa are now packed into a single + * 32-bit integer. Although we severely truncate the lower part in the + * process, we still have enough significant bits to perform the conversion + * without error (for all valid inputs). + */ + output = (u.ui32[MSW] << 11) | (u.ui32[LSW] >> 21); + + /* Next, we perform the shift that converts the X.Y fixed-point number + * currently found in "output" to the desired 31.1 fixed-point format + * needed for the following rounding step. It is important to consider + * all possible values for "shift_amount" at this point: + * + * - {shift_amount < 0} Since shift_amount is an unsigned integer, it + * really can't have a value less than zero. But, if the shift_amount + * calculation above caused underflow (which would happen with + * input > INT_MAX or input <= INT_MIN) then shift_amount will now be + * a very large number, and so this shift will result in complete + * garbage. But that's OK, as the input was out of our range, so our + * output is undefined. + * + * - {shift_amount > 31} If the magnitude of the input was very small + * (i.e. |input| << 1.0), shift_amount will have a value greater than + * 31. Thus, this shift will also result in garbage. After performing + * the shift, we will zero-out "output" if this is the case. + * + * - {0 <= shift_amount < 32} In this case, the shift will properly convert + * the mantissa into a 31.1 fixed-point number. + */ + output >>= shift_amount; + + /* This is where we perform rounding with the 31.1 fixed-point number. + * Since what we're after is arithmetic rounding, we simply add the single + * fractional bit into the integer part of "output", and just keep the + * integer part. + */ + output = (output >> 1) + (output & 1); + + /* Here, we zero-out the result if the magnitude if the input was very small + * (as explained in the section above). Notice that all input out of the + * valid range is also caught by this condition, which means we produce 0 + * for all invalid input, which is a nice side effect. + * + * The most straightforward way to do this would be: + * + * if (shift_amount > 31) + * output = 0; + * + * But we can use a little trick to avoid the potential branch. The + * expression (shift_amount > 31) will be either 1 or 0, which when + * decremented will be either 0x0 or 0xFFFFFFFF (unsigned underflow), + * which can be used to conditionally mask away all the bits in "output" + * (in the 0x0 case), effectively zeroing it out. Certain, compilers would + * have done this for us automatically. + */ + output &= ((shift_amount > 31) - 1); + + /* If the input double was a negative number, then we have to negate our + * output. The most straightforward way to do this would be: + * + * if (!top) + * output = -output; + * + * as "top" at this point is either 0x0 (if the input was negative) or + * 0xFFFFFFFF (if the input was positive). But, we can use a trick to + * avoid the branch. Observe that the following snippet of code has the + * same effect as the reference snippet above: + * + * if (!top) + * output = 0 - output; + * else + * output = output - 0; + * + * Armed with the bitmask found in "top", we can condense the two statements + * into the following: + * + * output = (output & top) - (output & ~top); + * + * where, in the case that the input double was negative, "top" will be 0, + * and the statement will be equivalent to: + * + * output = (0) - (output); + * + * and if the input double was positive, "top" will be 0xFFFFFFFF, and the + * statement will be equivalent to: + * + * output = (output) - (0); + * + * Which, as pointed out earlier, is equivalent to the original reference + * snippet. + */ + output = (output & top) - (output & ~top); + + return output; +#undef MSW +#undef LSW +} +#endif + +/* Convert a 32-bit IEEE single precision floating point number to a + * 'half' representation (s10.5) + */ +uint16_t +_cairo_half_from_float (float f) +{ + union { + uint32_t ui; + float f; + } u; + int s, e, m; + + u.f = f; + s = (u.ui >> 16) & 0x00008000; + e = ((u.ui >> 23) & 0x000000ff) - (127 - 15); + m = u.ui & 0x007fffff; + if (e <= 0) { + if (e < -10) { + /* underflow */ + return 0; + } + + m = (m | 0x00800000) >> (1 - e); + + /* round to nearest, round 0.5 up. */ + if (m & 0x00001000) + m += 0x00002000; + return s | (m >> 13); + } else if (e == 0xff - (127 - 15)) { + if (m == 0) { + /* infinity */ + return s | 0x7c00; + } else { + /* nan */ + m >>= 13; + return s | 0x7c00 | m | (m == 0); + } + } else { + /* round to nearest, round 0.5 up. */ + if (m & 0x00001000) { + m += 0x00002000; + + if (m & 0x00800000) { + m = 0; + e += 1; + } + } + + if (e > 30) { + /* overflow -> infinity */ + return s | 0x7c00; + } + + return s | (e << 10) | (m >> 13); + } +} + +#ifndef __BIONIC__ +# include <locale.h> + +const char * +_cairo_get_locale_decimal_point (void) +{ + struct lconv *locale_data = localeconv (); + return locale_data->decimal_point; +} + +#else +/* Android's Bionic libc doesn't provide decimal_point */ +const char * +_cairo_get_locale_decimal_point (void) +{ + return "."; +} +#endif + +#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L) + +static locale_t C_locale; + +static locale_t +get_C_locale (void) +{ + locale_t C; + +retry: + C = (locale_t) _cairo_atomic_ptr_get ((void **) &C_locale); + + if (unlikely (!C)) { + C = newlocale (LC_ALL_MASK, "C", NULL); + + if (!_cairo_atomic_ptr_cmpxchg ((void **) &C_locale, NULL, C)) { + freelocale (C_locale); + goto retry; + } + } + + return C; +} + +double +_cairo_strtod (const char *nptr, char **endptr) +{ + return strtod_l (nptr, endptr, get_C_locale ()); +} + +#else + +/* strtod replacement that ignores locale and only accepts decimal points */ +double +_cairo_strtod (const char *nptr, char **endptr) +{ + const char *decimal_point; + int decimal_point_len; + const char *p; + char buf[100]; + char *bufptr; + char *bufend = buf + sizeof(buf) - 1; + double value; + char *end; + int delta; + cairo_bool_t have_dp; + + decimal_point = _cairo_get_locale_decimal_point (); + decimal_point_len = strlen (decimal_point); + assert (decimal_point_len != 0); + + p = nptr; + bufptr = buf; + delta = 0; + have_dp = FALSE; + while (*p && _cairo_isspace (*p)) { + p++; + delta++; + } + + while (*p && (bufptr + decimal_point_len < bufend)) { + if (_cairo_isdigit (*p)) { + *bufptr++ = *p; + } else if (*p == '.') { + if (have_dp) + break; + strncpy (bufptr, decimal_point, decimal_point_len); + bufptr += decimal_point_len; + delta -= decimal_point_len - 1; + have_dp = TRUE; + } else { + break; + } + p++; + } + *bufptr = 0; + + value = strtod (buf, &end); + if (endptr) { + if (end == buf) + *endptr = (char*)(nptr); + else + *endptr = (char*)(nptr + (end - buf) + delta); + } + + return value; +} +#endif + +/** + * _cairo_fopen: + * @filename: filename to open + * @mode: mode string with which to open the file + * @file_out: reference to file handle + * + * Exactly like the C library function, but possibly doing encoding + * conversion on the filename. On all platforms, the filename is + * passed directly to the system, but on Windows, the filename is + * interpreted as UTF-8, rather than in a codepage that would depend + * on system settings. + * + * Return value: CAIRO_STATUS_SUCCESS when the filename was converted + * successfully to the native encoding, or the error reported by + * _cairo_utf8_to_utf16 otherwise. To check if the file handle could + * be obtained, dereference file_out and compare its value against + * NULL + **/ +cairo_status_t +_cairo_fopen (const char *filename, const char *mode, FILE **file_out) +{ + FILE *result; +#ifdef _WIN32 /* also defined on x86_64 */ + uint16_t *filename_w; + uint16_t *mode_w; + cairo_status_t status; + + *file_out = NULL; + + if (filename == NULL || mode == NULL) { + errno = EINVAL; + return CAIRO_STATUS_SUCCESS; + } + + if ((status = _cairo_utf8_to_utf16 (filename, -1, &filename_w, NULL)) != CAIRO_STATUS_SUCCESS) { + errno = EINVAL; + return status; + } + + if ((status = _cairo_utf8_to_utf16 (mode, -1, &mode_w, NULL)) != CAIRO_STATUS_SUCCESS) { + free (filename_w); + errno = EINVAL; + return status; + } + + result = _wfopen(filename_w, mode_w); + + free (filename_w); + free (mode_w); + +#else /* Use fopen directly */ + result = fopen (filename, mode); +#endif + + *file_out = result; + + return CAIRO_STATUS_SUCCESS; +} + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +/* We require Windows 2000 features such as ETO_PDY */ +#if !defined(WINVER) || (WINVER < 0x0500) +# define WINVER 0x0500 +#endif +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) +# define _WIN32_WINNT 0x0500 +#endif + +#include <windows.h> +#include <io.h> + +#if !_WIN32_WCE +/* tmpfile() replacement for Windows. + * + * On Windows tmpfile() creates the file in the root directory. This + * may fail due to unsufficient privileges. However, this isn't a + * problem on Windows CE so we don't use it there. + */ +FILE * +_cairo_win32_tmpfile (void) +{ + DWORD path_len; + WCHAR path_name[MAX_PATH + 1]; + WCHAR file_name[MAX_PATH + 1]; + HANDLE handle; + int fd; + FILE *fp; + + path_len = GetTempPathW (MAX_PATH, path_name); + if (path_len <= 0 || path_len >= MAX_PATH) + return NULL; + + if (GetTempFileNameW (path_name, L"ps_", 0, file_name) == 0) + return NULL; + + handle = CreateFileW (file_name, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + DeleteFileW (file_name); + return NULL; + } + + fd = _open_osfhandle((intptr_t) handle, 0); + if (fd < 0) { + CloseHandle (handle); + return NULL; + } + + fp = fdopen(fd, "w+b"); + if (fp == NULL) { + _close(fd); + return NULL; + } + + return fp; +} +#endif /* !_WIN32_WCE */ + +#endif /* _WIN32 */ + +typedef struct _cairo_intern_string { + cairo_hash_entry_t hash_entry; + int len; + char *string; +} cairo_intern_string_t; + +static cairo_hash_table_t *_cairo_intern_string_ht; + +unsigned long +_cairo_string_hash (const char *str, int len) +{ + const signed char *p = (const signed char *) str; + unsigned int h = *p; + + for (p += 1; len > 0; len--, p++) + h = (h << 5) - h + *p; + + return h; +} + +static cairo_bool_t +_intern_string_equal (const void *_a, const void *_b) +{ + const cairo_intern_string_t *a = _a; + const cairo_intern_string_t *b = _b; + + if (a->len != b->len) + return FALSE; + + return memcmp (a->string, b->string, a->len) == 0; +} + +cairo_status_t +_cairo_intern_string (const char **str_inout, int len) +{ + char *str = (char *) *str_inout; + cairo_intern_string_t tmpl, *istring; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (len < 0) + len = strlen (str); + tmpl.hash_entry.hash = _cairo_string_hash (str, len); + tmpl.len = len; + tmpl.string = (char *) str; + + CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex); + if (_cairo_intern_string_ht == NULL) { + _cairo_intern_string_ht = _cairo_hash_table_create (_intern_string_equal); + if (unlikely (_cairo_intern_string_ht == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + } + + istring = _cairo_hash_table_lookup (_cairo_intern_string_ht, + &tmpl.hash_entry); + if (istring == NULL) { + istring = _cairo_malloc (sizeof (cairo_intern_string_t) + len + 1); + if (likely (istring != NULL)) { + istring->hash_entry.hash = tmpl.hash_entry.hash; + istring->len = tmpl.len; + istring->string = (char *) (istring + 1); + memcpy (istring->string, str, len); + istring->string[len] = '\0'; + + status = _cairo_hash_table_insert (_cairo_intern_string_ht, + &istring->hash_entry); + if (unlikely (status)) { + free (istring); + goto BAIL; + } + } else { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + } + + *str_inout = istring->string; + + BAIL: + CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex); + return status; +} + +static void +_intern_string_pluck (void *entry, void *closure) +{ + _cairo_hash_table_remove (closure, entry); + free (entry); +} + +void +_cairo_intern_string_reset_static_data (void) +{ + CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex); + if (_cairo_intern_string_ht != NULL) { + _cairo_hash_table_foreach (_cairo_intern_string_ht, + _intern_string_pluck, + _cairo_intern_string_ht); + _cairo_hash_table_destroy(_cairo_intern_string_ht); + _cairo_intern_string_ht = NULL; + } + CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex); +} |