summaryrefslogtreecommitdiff
path: root/src/cairo-misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-misc.c')
-rw-r--r--src/cairo-misc.c955
1 files changed, 955 insertions, 0 deletions
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
new file mode 100644
index 000000000..df8a4efc9
--- /dev/null
+++ b/src/cairo-misc.c
@@ -0,0 +1,955 @@
+/* -*- 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);
+}