| /* -*- 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" |
| |
| 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"; |
| 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 |
| |
| #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; |
| |
| static unsigned long |
| _intern_string_hash (const char *str, int len) |
| { |
| const signed char *p = (const signed char *) str; |
| unsigned int h = *p; |
| |
| for (p += 1; --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 = _intern_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 = 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); |
| } |