[cairo-commit] 18 commits - doc/public src/cairo.c src/cairo-font-face.c src/cairo-gstate.c src/cairo.h src/cairoint.h src/cairo-misc.c src/cairo-pdf-operators.c src/cairo-pdf-surface.c src/cairo-scaled-font.c src/cairo-scaled-font-subsets.c src/cairo-surface.c src/cairo-truetype-subset.c src/cairo-unicode.c src/cairo-user-font.c src/cairo-win32-font.c test/.gitignore test/Makefile.am test/toy-font-face.c test/user-font.c test/user-font-proxy.c test/user-font-proxy-pdf-ref.png test/user-font-proxy-ps-ref.png
Behdad Esfahbod
behdad at kemper.freedesktop.org
Fri Aug 8 00:08:04 PDT 2008
doc/public/Headers.mk | 1
doc/public/Makefile.am | 1
doc/public/cairo-sections.txt | 9
doc/public/tmpl/cairo-scaled-font.sgml | 18 +
doc/public/tmpl/cairo-status.sgml | 2
doc/public/tmpl/cairo-text.sgml | 72 ++++++
doc/public/tmpl/cairo-user-fonts.sgml | 5
src/cairo-font-face.c | 196 ++++++++++++++++-
src/cairo-gstate.c | 44 ++--
src/cairo-misc.c | 182 ++++++++++++++++
src/cairo-pdf-operators.c | 6
src/cairo-pdf-surface.c | 2
src/cairo-scaled-font-subsets.c | 30 +-
src/cairo-scaled-font.c | 363 +++++++++++++++++++++++++++++----
src/cairo-surface.c | 2
src/cairo-truetype-subset.c | 11 -
src/cairo-unicode.c | 42 +++
src/cairo-user-font.c | 82 ++++---
src/cairo-win32-font.c | 2
src/cairo.c | 205 +++++++++++-------
src/cairo.h | 138 +++++++++++-
src/cairoint.h | 71 ++++--
test/.gitignore | 1
test/Makefile.am | 3
test/toy-font-face.c | 129 +++++++++++
test/user-font-proxy-pdf-ref.png |binary
test/user-font-proxy-ps-ref.png |binary
test/user-font-proxy.c | 104 +++++----
test/user-font.c | 13 -
29 files changed, 1453 insertions(+), 281 deletions(-)
New commits:
commit eabe572981e1e415171dbfde81c3bf94297355b4
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Fri Aug 8 00:56:36 2008 -0400
Document all new API
Also validate clusters generated by font backends.
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 4b9cdc5..0f9a4c6 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -292,6 +292,7 @@ cairo_scaled_font_extents
cairo_text_extents_t
cairo_scaled_font_text_extents
cairo_scaled_font_glyph_extents
+cairo_scaled_font_text_to_glyphs
cairo_scaled_font_get_font_face
cairo_scaled_font_get_font_options
cairo_scaled_font_get_font_matrix
@@ -412,6 +413,10 @@ cairo_toy_font_face_create
cairo_toy_font_face_get_family
cairo_toy_font_face_get_slant
cairo_toy_font_face_get_weight
+cairo_glyph_allocate
+cairo_glyph_free
+cairo_text_cluster_allocate
+cairo_text_cluster_free
</SECTION>
<SECTION>
diff --git a/doc/public/tmpl/cairo-scaled-font.sgml b/doc/public/tmpl/cairo-scaled-font.sgml
index 97922ef..1abf0f3 100644
--- a/doc/public/tmpl/cairo-scaled-font.sgml
+++ b/doc/public/tmpl/cairo-scaled-font.sgml
@@ -119,6 +119,24 @@ size and transformation and a certain set of font options.
@extents:
+<!-- ##### FUNCTION cairo_scaled_font_text_to_glyphs ##### -->
+<para>
+
+</para>
+
+ at scaled_font:
+ at x:
+ at y:
+ at utf8:
+ at utf8_len:
+ at glyphs:
+ at num_glyphs:
+ at clusters:
+ at num_clusters:
+ at backward:
+ at Returns:
+
+
<!-- ##### FUNCTION cairo_scaled_font_get_font_face ##### -->
<para>
diff --git a/doc/public/tmpl/cairo-text.sgml b/doc/public/tmpl/cairo-text.sgml
index 3e5c6bb..54fb9bd 100644
--- a/doc/public/tmpl/cairo-text.sgml
+++ b/doc/public/tmpl/cairo-text.sgml
@@ -282,3 +282,37 @@ Cairo has two sets of text rendering capabilities:
@Returns:
+<!-- ##### FUNCTION cairo_glyph_allocate ##### -->
+<para>
+
+</para>
+
+ at num_glyphs:
+ at Returns:
+
+
+<!-- ##### FUNCTION cairo_glyph_free ##### -->
+<para>
+
+</para>
+
+ at glyphs:
+
+
+<!-- ##### FUNCTION cairo_text_cluster_allocate ##### -->
+<para>
+
+</para>
+
+ at num_clusters:
+ at Returns:
+
+
+<!-- ##### FUNCTION cairo_text_cluster_free ##### -->
+<para>
+
+</para>
+
+ at clusters:
+
+
diff --git a/doc/public/tmpl/cairo-user-fonts.sgml b/doc/public/tmpl/cairo-user-fonts.sgml
index 1a9322a..b64bf25 100644
--- a/doc/public/tmpl/cairo-user-fonts.sgml
+++ b/doc/public/tmpl/cairo-user-fonts.sgml
@@ -23,6 +23,7 @@ User Fonts
</para>
@scaled_font:
+ at cr:
@extents:
@Returns:
@@ -46,8 +47,12 @@ User Fonts
@scaled_font:
@utf8:
+ at utf8_len:
@glyphs:
@num_glyphs:
+ at clusters:
+ at num_clusters:
+ at backward:
@Returns:
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 1e74c67..9a0ede0 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -153,6 +153,7 @@ cairo_glyph_allocate (int num_glyphs)
return _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
}
+slim_hidden_def (cairo_glyph_allocate);
/**
* cairo_glyph_free:
@@ -173,6 +174,7 @@ cairo_glyph_free (cairo_glyph_t *glyphs)
if (glyphs)
free (glyphs);
}
+slim_hidden_def (cairo_glyph_free);
/**
* cairo_text_cluster_allocate:
@@ -202,10 +204,11 @@ cairo_text_cluster_allocate (int num_clusters)
return _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
}
+slim_hidden_def (cairo_text_cluster_allocate);
/**
* cairo_text_cluster_free:
- * @text_clusters: array of text clusters to free, or %NULL
+ * @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
@@ -222,11 +225,82 @@ cairo_text_cluster_free (cairo_text_cluster_t *clusters)
if (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
+ * @backward: whether the text to glyphs mapping goes backward
+ *
+ * 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_bool_t backward)
+{
+ 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 (status)
+ return 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_STATUS_INVALID_CLUSTERS;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
* _cairo_operator_bounded_by_mask:
* @op: a #cairo_operator_t
*
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index fa54231..1429780 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1083,7 +1083,7 @@ slim_hidden_def (cairo_scaled_font_extents);
/**
* cairo_scaled_font_text_extents:
* @scaled_font: a #cairo_scaled_font_t
- * @utf8: a string of text, encoded in UTF-8
+ * @utf8: a NUL-terminated string of text, encoded in UTF-8
* @extents: a #cairo_text_extents_t which to store the retrieved extents.
*
* Gets the extents for a string of text. The extents describe a
@@ -1268,6 +1268,143 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
}
slim_hidden_def (cairo_scaled_font_glyph_extents);
+/**
+ * cairo_scaled_font_text_to_glyphs:
+ * @x: X position to place first glyph
+ * @y: Y position to place first glyph
+ * @scaled_font: a #cairo_scaled_font_t
+ * @utf8: a string of text encoded in UTF-8
+ * @utf8_len: length of @utf8 in bytes, or -1 if it is NUL-terminated
+ * @glyphs: pointer to array of glyphs to fill
+ * @num_glyphs: pointer to number of glyphs
+ * @clusters: pointer to array of cluster mapping information to fill, or %NULL
+ * @num_clusters: pointer to number of clusters, or %NULL
+ * @backward: pointer to whether the text to glyphs mapping goes backward, or
+ * %NULL
+ *
+ * Converts UTF-8 text to an array of glyphs, optionally with cluster
+ * mapping, that can be used to render later using @scaled_font.
+ *
+ * If @glyphs initially points to a non-%NULL value, that array is used
+ * as a glyph buffer, and @num_glyphs should point to the number of glyph
+ * entries available there. If the provided glyph array is too short for
+ * the conversion, a new glyph array is allocated using cairo_glyph_allocate()
+ * and placed in @glyphs. Upon return, @num_glyphs always contains the
+ * number of generated glyphs. If the value @glyphs points at has changed
+ * after the call, the user is responsible for freeing the allocated glyph
+ * array using cairo_glyph_free().
+ *
+ * If @clusters is not %NULL, @num_clusters and @backward should not be %NULL,
+ * and cluster mapping will be computed.
+ * The semantics of how cluster array allocation works is similar to the glyph
+ * array. That is,
+ * if @clusters initially points to a non-%NULL value, that array is used
+ * as a cluster buffer, and @num_clusters should point to the number of cluster
+ * entries available there. If the provided cluster array is too short for
+ * the conversion, a new cluster array is allocated using cairo_text_cluster_allocate()
+ * and placed in @clusters. Upon return, @num_clusters always contains the
+ * number of generated clusters. If the value @clusters points at has changed
+ * after the call, the user is responsible for freeing the allocated cluster
+ * array using cairo_text_cluster_free().
+ *
+ * In the simplest case, @glyphs and @clusters can point to %NULL initially
+ * and a suitable array will be allocated. In code:
+ * <informalexample><programlisting>
+ * cairo_status_t status;
+ *
+ * cairo_glyph_t *glyphs = NULL;
+ * int num_glyphs;
+ * cairo_text_cluster_t *clusters = NULL;
+ * int num_clusters;
+ * cairo_bool_t backward;
+ *
+ * status = cairo_scaled_font_text_to_glyphs (scaled_font,
+ * x, y,
+ * utf8, utf8_len,
+ * &glyphs, &num_glyphs,
+ * &clusters, &num_clusters,
+ * &backward);
+ *
+ * if (status == CAIRO_STATUS_SUCCESS) {
+ * cairo_show_text_glyphs (cr,
+ * utf8, utf8_len,
+ * *glyphs, *num_glyphs,
+ * *clusters, *num_clusters,
+ * *backward);
+ *
+ * cairo_glyph_free (*glyphs);
+ * cairo_text_cluster_free (*clusters);
+ * }
+ * </programlisting></informalexample>
+ *
+ * If no cluster mapping is needed:
+ * <informalexample><programlisting>
+ * cairo_status_t status;
+ *
+ * cairo_glyph_t *glyphs = NULL;
+ * int num_glyphs;
+ *
+ * status = cairo_scaled_font_text_to_glyphs (scaled_font,
+ * x, y,
+ * utf8, utf8_len,
+ * &glyphs, &num_glyphs,
+ * NULL, NULL,
+ * NULL);
+ *
+ * if (status == CAIRO_STATUS_SUCCESS) {
+ * cairo_show_glyphs (cr, *glyphs, *num_glyphs);
+ * cairo_glyph_free (*glyphs);
+ * }
+ * </programlisting></informalexample>
+ *
+ * If stack-based glyph and cluster arrays are to be used for small
+ * arrays:
+ * <informalexample><programlisting>
+ * cairo_status_t status;
+ *
+ * cairo_glyph_t stack_glyphs[40];
+ * cairo_glyph_t *glyphs = stack_glyphs;
+ * int num_glyphs = sizeof (stack_glyphs) / sizeof (stack_glyphs[0]);
+ * cairo_text_cluster_t stack_clusters[40];
+ * cairo_text_cluster_t *clusters = stack_clusters;
+ * int num_clusters = sizeof (stack_clusters) / sizeof (stack_clusters[0]);
+ * cairo_bool_t backward;
+ *
+ * status = cairo_scaled_font_text_to_glyphs (scaled_font,
+ * x, y,
+ * utf8, utf8_len,
+ * &glyphs, &num_glyphs,
+ * &clusters, &num_clusters,
+ * &backward);
+ *
+ * if (status == CAIRO_STATUS_SUCCESS) {
+ * cairo_show_text_glyphs (cr,
+ * utf8, utf8_len,
+ * *glyphs, *num_glyphs,
+ * *clusters, *num_clusters,
+ * *backward);
+ *
+ * if (glyphs != stack_glyphs)
+ * cairo_glyph_free (*glyphs);
+ * if (clusters != stack_clusters)
+ * cairo_text_cluster_free (*clusters);
+ * }
+ * </programlisting></informalexample>
+ *
+ * For details of how (@clusters, @num_clusters, and @backward map input
+ * UTF-8 text to the output glyphs see cairo_show_text_glyphs().
+ *
+ * The output values can be readily passed to cairo_show_text_glyphs()
+ * cairo_show_glyphs(), or related functions, assuming that the exact
+ * same @scaled_font is used for the operation.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS upon success, or an error status
+ * if the input values are wrong or if conversion failed. If the input
+ * values are correct but the conversion failed, the error status is also
+ * set on @scaled_font.
+ *
+ * Since: 1.8
+ **/
cairo_status_t
cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
double x,
@@ -1300,6 +1437,10 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
goto BAIL;
}
+ /* Special case for NULL and -1 */
+ if (utf8 == NULL && utf8_len == -1)
+ utf8_len = 0;
+
/* No NULLs for non-NULLs! */
if ((utf8_len && utf8 == NULL) ||
(clusters && num_clusters == NULL) ||
@@ -1364,8 +1505,44 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
clusters, num_clusters,
backward);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+
+ if (status == CAIRO_STATUS_SUCCESS) {
+
+ /* The checks here are crude; we only should do them in
+ * user-font backend, but they don't hurt here. This stuff
+ * can be hard to get right. */
+
+ if (*num_glyphs < 0) {
+ status = CAIRO_STATUS_NEGATIVE_COUNT;
+ goto DONE;
+ }
+ if (num_glyphs && *glyphs == NULL) {
+ status = CAIRO_STATUS_NULL_POINTER;
+ goto DONE;
+ }
+
+ if (clusters) {
+
+ if (*num_clusters < 0) {
+ status = CAIRO_STATUS_NEGATIVE_COUNT;
+ goto DONE;
+ }
+ if (num_clusters && *clusters == NULL) {
+ status = CAIRO_STATUS_NULL_POINTER;
+ goto DONE;
+ }
+
+ /* Dont trust the backend, validate clusters! */
+ status = _cairo_validate_text_clusters (utf8, utf8_len,
+ *glyphs, *num_glyphs,
+ *clusters, *num_clusters,
+ *backward);
+ }
+ }
+
goto DONE;
+ }
}
if (*num_glyphs < num_chars) {
@@ -1450,6 +1627,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
return status;
}
+slim_hidden_def (cairo_scaled_font_text_to_glyphs);
/*
* Compute a device-space bounding box for the glyphs.
diff --git a/src/cairo.c b/src/cairo.c
index e42fd70..82cd80b 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -2971,7 +2971,7 @@ cairo_get_scaled_font (cairo_t *cr)
/**
* cairo_text_extents:
* @cr: a #cairo_t
- * @utf8: a string of text encoded in UTF-8, or %NULL
+ * @utf8: a NUL-terminated string of text encoded in UTF-8, or %NULL
* @extents: a #cairo_text_extents_t object into which the results
* will be stored
*
@@ -3088,7 +3088,7 @@ cairo_glyph_extents (cairo_t *cr,
/**
* cairo_show_text:
* @cr: a cairo context
- * @utf8: a string of text encoded in UTF-8, or %NULL
+ * @utf8: a NUL-terminated string of text encoded in UTF-8, or %NULL
*
* A drawing operator that generates the shape from a string of UTF-8
* characters, rendered according to the current font_face, font_size
@@ -3179,8 +3179,8 @@ cairo_show_text (cairo_t *cr, const char *utf8)
* @num_glyphs: number of glyphs to show
*
* A drawing operator that generates the shape from an array of glyphs,
- * rendered according to the current font_face, font_size
- * (font_matrix), and font_options.
+ * rendered according to the current font face, font size
+ * (font matrix), and font options.
**/
void
cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
@@ -3212,12 +3212,66 @@ cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
_cairo_set_error (cr, status);
}
+/**
+ * cairo_has_show_text_glyphs:
+ * @cr: a cairo context
+ *
+ * Returns whether the target surface of a cairo context supports
+ * sophisticated cairo_show_text_glyphs() operations. That is,
+ * whether it actually uses the provided text and cluster data
+ * to a cairo_show_text_glyphs() call.
+ *
+ * Note: Even if this function returns %FALSE, a
+ * cairo_show_text_glyphs() operation will still succeed. It just will
+ * act like a cairo_show_glyphs() operation. Users can use this
+ * function to avoid computing UTF-8 text and cluster mapping if the
+ * target surface does not use it.
+ *
+ * Return value: %TRUE if the target surface of @cr supports
+ * cairo_show_text_glyphs(), %FALSE otherwise
+ *
+ * Since: 1.8
+ **/
cairo_bool_t
cairo_has_show_text_glyphs (cairo_t *cr)
{
return _cairo_gstate_has_show_text_glyphs (cr->gstate);
}
+slim_hidden_def (cairo_has_show_text_glyphs);
+/**
+ * cairo_show_text_glyphs:
+ * @cr: a cairo context
+ * @utf8: a string of text encoded in UTF-8
+ * @utf8_len: length of @utf8 in bytes, or -1 if it is NUL-terminated
+ * @glyphs: array of glyphs to show
+ * @num_glyphs: number of glyphs to show
+ * @clusters: array of cluster mapping information
+ * @num_clusters: number of clusters in the mapping
+ * @backward: whether the text to glyphs mapping goes backward
+ *
+ * This operation has rendering effects similar to cairo_show_glyphs()
+ * but, if the target surface supports it, uses the provided text and
+ * cluster mapping to embed the text for the glyphs shown in the output.
+ * The cairo_has_show_text_glyphs() function can be used to query that.
+ * If the target does not support it, this function acts like
+ * cairo_show_glyphs().
+ *
+ * The mapping between @utf8 and @glyphs is provided by an array of
+ * <firstterm>clusters</firstterm>. Each cluster covers a number of
+ * text bytes and glyphs, and neighboring clusters cover neighboring
+ * areas of @utf8 and @glyphs. The clusters should collectively cover @utf8
+ * and @glyphs in entirety.
+ *
+ * The first cluster always covers bytes from the beginning of @utf8.
+ * If @backward is %FALSE, the first cluster also covers the beginning
+ * of @glyphs, otherwise it covers the end of the @glyphs array and
+ * following clusters move backward.
+ *
+ * See #cairo_text_cluster_t for constraints on valid clusters.
+ *
+ * Since: 1.8
+ **/
void
cairo_show_text_glyphs (cairo_t *cr,
const char *utf8,
@@ -3235,6 +3289,10 @@ cairo_show_text_glyphs (cairo_t *cr,
/* A slew of sanity checks */
+ /* Special case for NULL and -1 */
+ if (utf8 == NULL && utf8_len == -1)
+ utf8_len = 0;
+
/* No NULLs for non-zeros */
if ((num_glyphs && glyphs == NULL) ||
(utf8_len && utf8 == NULL) ||
@@ -3255,48 +3313,22 @@ cairo_show_text_glyphs (cairo_t *cr,
/* Make sure clusters cover the entire glyphs and utf8 arrays,
* and that cluster boundaries are UTF-8 boundaries. */
- {
- 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 (status) {
- _cairo_set_error (cr, status);
- return;
- }
-
- n_bytes += cluster_bytes ;
- n_glyphs += cluster_glyphs;
- }
-
- if (n_bytes != (unsigned int)utf8_len || n_glyphs != (unsigned int)num_glyphs) {
- BAD:
- _cairo_set_error (cr, CAIRO_STATUS_INVALID_CLUSTERS);
- return;
- }
+ status = _cairo_validate_text_clusters (utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ backward);
+ if (status == CAIRO_STATUS_INVALID_CLUSTERS) {
+ /* Either got invalid UTF-8 text, or cluster mapping is bad.
+ * Differentiate those. */
+
+ cairo_status_t status2;
+
+ status2 = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, NULL);
+ if (status2)
+ status = status2;
+
+ _cairo_set_error (cr, status);
+ return;
}
if (num_glyphs == 0 && utf8_len == 0)
@@ -3314,7 +3346,7 @@ cairo_show_text_glyphs (cairo_t *cr,
/**
* cairo_text_path:
* @cr: a cairo context
- * @utf8: a string of text encoded in UTF-8, or %NULL
+ * @utf8: a NUL-terminated string of text encoded in UTF-8, or %NULL
*
* Adds closed paths for text to the current path. The generated
* path if filled, achieves an effect similar to that of
@@ -3522,11 +3554,11 @@ cairo_has_current_point (cairo_t *cr)
* cairo_move_to(), cairo_line_to(), cairo_curve_to(),
* cairo_rel_move_to(), cairo_rel_line_to(), cairo_rel_curve_to(),
* cairo_arc(), cairo_arc_negative(), cairo_rectangle(),
- * cairo_text_path(), cairo_glyph_path(), cairo_stroke_to_path()
+ * cairo_text_path(), cairo_glyph_path(), cairo_stroke_to_path().
*
- * Some functions use and alter the current point but do not otherwise
- * change current path:
- * cairo_show_text(), cairo_show_glyphs().
+ * Some functions use and alter the current point but do not
+ * otherwise change current path:
+ * cairo_show_text().
*
* Some functions unset the current path and as a result, current point:
* cairo_fill(), cairo_stroke().
@@ -3688,6 +3720,7 @@ cairo_get_target (cairo_t *cr)
return _cairo_gstate_get_original_target (cr->gstate);
}
+slim_hidden_def (cairo_get_target);
/**
* cairo_get_group_target:
diff --git a/src/cairo.h b/src/cairo.h
index ee933ab..8b50c04 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -209,7 +209,7 @@ typedef struct _cairo_user_data_key {
* @CAIRO_STATUS_NEGATIVE_COUNT: negative number used where it is not allowed (Since 1.8)
* @CAIRO_STATUS_INVALID_CLUSTERS: input clusters do not represent the accompanying text and glyph array (Since 1.8)
* @CAIRO_STATUS_INVALID_SLANT: invalid value for an input #cairo_font_slant_t (Since 1.8)
- * @CAIRO_STATUS_INVALID_CLUSTERS: input value for an input #cairo_font_weight_t (Since 1.8)
+ * @CAIRO_STATUS_INVALID_WEIGHT: invalid value for an input #cairo_font_weight_t (Since 1.8)
*
* #cairo_status_t is used to indicate errors that can occur when
* using Cairo. In some cases it is returned directly by functions.
@@ -836,6 +836,23 @@ cairo_glyph_allocate (int num_glyphs);
cairo_public void
cairo_glyph_free (cairo_glyph_t *glyphs);
+/**
+ * cairo_text_cluster_t:
+ * @num_bytes: the number of bytes of UTF-8 text covered by cluster
+ * @num_glyphs: the number of glyphs covered by cluster
+ *
+ * The #cairo_text_cluster_t structure holds information about a single
+ * <firstterm>text cluster</firstterm>. A text cluster is a minimal
+ * mapping of some glyphs corresponding to some UTF-8 text.
+ *
+ * For a cluster to be valid, both @num_bytes and @num_glyphs should
+ * be non-negative, and at least one should be non-zero.
+ *
+ * See cairo_show_text_glyphs() for how clusters are used in advanced
+ * text operations.
+ *
+ * Since: 1.8
+ **/
typedef struct {
int num_bytes;
int num_glyphs;
@@ -1417,8 +1434,6 @@ cairo_user_font_face_create (void);
* Returns: %CAIRO_STATUS_SUCCESS upon success, or
* %CAIRO_STATUS_USER_FONT_ERROR or any other error status on error.
*
- * Returns: the status code of the operation
- *
* Since: 1.8
**/
typedef cairo_status_t (*cairo_user_scaled_font_init_func_t) (cairo_scaled_font_t *scaled_font,
@@ -1476,16 +1491,19 @@ typedef cairo_status_t (*cairo_user_scaled_font_render_glyph_func_t) (cairo_scal
/**
* cairo_user_scaled_font_text_to_glyphs_func_t:
* @scaled_font: the scaled-font being created
- * @utf8: input string of text, encoded in UTF-8
- * @glyphs: output array of glyphs, in font space
- * @num_glyphs: number of output glyphs
+ * @utf8: a string of text encoded in UTF-8
+ * @utf8_len: length of @utf8 in bytes
+ * @glyphs: pointer to array of glyphs to fill, in font space
+ * @num_glyphs: pointer to number of glyphs
+ * @clusters: pointer to array of cluster mapping information to fill, or %NULL
+ * @num_clusters: pointer to number of clusters
+ * @backward: pointer to whether the text to glyphs mapping goes backward
*
- * XXXXXXXXXXXXX
* #cairo_user_scaled_font_text_to_glyphs_func_t is the type of function which
* is called to convert input text to an array of glyphs. This is used by the
* cairo_show_text() operation.
*
- * Using this callback the user font has full control on glyphs and their
+ * Using this callback the user-font has full control on glyphs and their
* positions. That means, it allows for features like ligatures and kerning,
* as well as complex <firstterm>shaping</firstterm> required for scripts like
* Arabic and Indic.
@@ -1496,12 +1514,39 @@ typedef cairo_status_t (*cairo_user_scaled_font_render_glyph_func_t) (cairo_scal
* origin. Cairo will free the glyph array when done with it, no matter what
* the return value of the callback is.
*
+ * If @glyphs initially points to a non-%NULL value, that array can be used
+ * as a glyph buffer, and @num_glyphs points to the number of glyph
+ * entries available there. If the provided glyph array is too short for
+ * the conversion (or for convenience), a new glyph array may be allocated
+ * using cairo_glyph_allocate() and placed in @glyphs. Upon return,
+ * @num_glyphs should contain the number of generated glyphs.
+ * If the value @glyphs points at has changed after the call, cairo will
+ * free the allocated glyph array using cairo_glyph_free().
+ *
+ * If @clusters is not %NULL, @num_clusters and @backward are also non-%NULL,
+ * and cluster mapping should be computed.
+ * The semantics of how cluster array allocation works is similar to the glyph
+ * array. That is,
+ * if @clusters initially points to a non-%NULL value, that array may be used
+ * as a cluster buffer, and @num_clusters points to the number of cluster
+ * entries available there. If the provided cluster array is too short for
+ * the conversion (or for convenience), a new cluster array may be allocated
+ * using cairo_text_cluster_allocate() and placed in @clusters. Upon return,
+ * @num_clusters should contain the number of generated clusters.
+ * If the value @clusters points at has changed after the call, cairo will
+ * free the allocated cluster array using cairo_text_cluster_free().
+ *
* The callback is optional. If not set, or if @num_glyphs is negative upon
- * the callback returning (which by default is), the unicode_to_glyph callback
+ * the callback returning, the unicode_to_glyph callback
* is tried. See #cairo_user_scaled_font_unicode_to_glyph_func_t.
*
- * Note: The signature and details of this callback is expected to change
- * before cairo 1.8.0 is released.
+ * Note: While cairo does not impose any limitation on glyph indices,
+ * some applications may assume that a glyph index fits in a 16-bit
+ * unsigned integer. As such, it is advised that user-fonts keep their
+ * glyphs in the 0 to 65535 range. Furthermore, some applications may
+ * assume that glyph 0 is a special glyph-not-found glyph. User-fonts
+ * are advised to use glyph 0 for such purposes and do not use that
+ * glyph value for other purposes.
*
* Returns: %CAIRO_STATUS_SUCCESS upon success, or
* %CAIRO_STATUS_USER_FONT_ERROR or any other error status on error.
@@ -1540,6 +1585,14 @@ typedef cairo_status_t (*cairo_user_scaled_font_text_to_glyphs_func_t) (cairo_sc
* set or fails to return glyphs. If this callback is not set, an identity
* mapping from Unicode code-points to glyph indices is assumed.
*
+ * Note: While cairo does not impose any limitation on glyph indices,
+ * some applications may assume that a glyph index fits in a 16-bit
+ * unsigned integer. As such, it is advised that user-fonts keep their
+ * glyphs in the 0 to 65535 range. Furthermore, some applications may
+ * assume that glyph 0 is a special glyph-not-found glyph. User-fonts
+ * are advised to use glyph 0 for such purposes and do not use that
+ * glyph value for other purposes.
+ *
* Returns: %CAIRO_STATUS_SUCCESS upon success, or
* %CAIRO_STATUS_USER_FONT_ERROR or any other error status on error.
*
diff --git a/src/cairoint.h b/src/cairoint.h
index 2c37035..e333555 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1349,6 +1349,16 @@ _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);
cairo_private unsigned char *
_cairo_lzw_compress (unsigned char *data, unsigned long *size_in_out);
+/* cairo-misc.c */
+cairo_private 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_bool_t backward);
+
/* cairo-path-fixed.c */
cairo_private void
_cairo_path_fixed_init (cairo_path_fixed_t *path);
@@ -2370,7 +2380,11 @@ slim_hidden_proto (cairo_font_options_set_subpixel_order);
slim_hidden_proto (cairo_font_options_status);
slim_hidden_proto (cairo_get_current_point);
slim_hidden_proto (cairo_get_matrix);
+slim_hidden_proto (cairo_get_target);
slim_hidden_proto (cairo_get_tolerance);
+slim_hidden_proto (cairo_has_show_text_glyphs);
+slim_hidden_proto (cairo_glyph_allocate);
+slim_hidden_proto (cairo_glyph_free);
slim_hidden_proto (cairo_image_surface_create);
slim_hidden_proto (cairo_image_surface_create_for_data);
slim_hidden_proto (cairo_image_surface_get_data);
@@ -2419,6 +2433,7 @@ slim_hidden_proto (cairo_scaled_font_get_ctm);
slim_hidden_proto (cairo_scaled_font_get_font_face);
slim_hidden_proto (cairo_scaled_font_get_font_matrix);
slim_hidden_proto (cairo_scaled_font_get_font_options);
+slim_hidden_proto (cairo_scaled_font_text_to_glyphs);
slim_hidden_proto (cairo_scaled_font_glyph_extents);
slim_hidden_proto_no_warn (cairo_scaled_font_reference);
slim_hidden_proto (cairo_scaled_font_status);
@@ -2446,6 +2461,8 @@ slim_hidden_proto (cairo_surface_set_fallback_resolution);
slim_hidden_proto (cairo_surface_copy_page);
slim_hidden_proto (cairo_surface_show_page);
slim_hidden_proto (cairo_surface_status);
+slim_hidden_proto (cairo_text_cluster_allocate);
+slim_hidden_proto (cairo_text_cluster_free);
slim_hidden_proto (cairo_toy_font_face_create);
slim_hidden_proto (cairo_version_string);
commit 08e8a42ea149deea760b94b62d9690393ce7cfcd
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Fri Aug 8 02:22:26 2008 -0400
[test/user-font] Fix comments
diff --git a/test/user-font.c b/test/user-font.c
index ef81978..b0b5fce 100644
--- a/test/user-font.c
+++ b/test/user-font.c
@@ -239,13 +239,13 @@ draw (cairo_t *cr, int width, int height)
cairo_set_line_width (cr, 2);
cairo_stroke (cr);
- /* text in gray */
+ /* text in black */
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
cairo_show_text (cr, text);
- /* filled version of text in light blue */
+ /* filled version of text in blue */
cairo_set_source_rgb (cr, 0, 0, 1);
cairo_move_to (cr, BORDER, BORDER + font_extents.height + 2*BORDER + font_extents.ascent);
cairo_text_path (cr, text);
commit 38c5f0d49b2ce1a6146cbea5ec3376a52cac8e68
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Fri Aug 8 02:18:25 2008 -0400
[scaled-font-subsets] Fix UTF-8 mapping
Prevously all show_text_glyphs() clusters were using ActualText. This
fixes that.
I have a feeling that the following scenario is broken still though:
- show_text_glyphs maps glyph 1 to some utf8 text different from
what index_to_ucs4 will give for glyph 1. This will assign the
utf8 text to glyph 1's ToUnicode.
- show_glyphs shows glyph 1. Since cluster has no utf8 text, we
won't use ActualText and fall back to ToUnicode. But the ToUnicode
value assigned to glyph 1 is non-standard now. We should use
ActualText.
I have not verified this hypothesis though.
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 103e117..2740d63 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -460,9 +460,10 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
if (sub_font_glyph == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph,
- sub_font->scaled_font,
- scaled_font_glyph_index);
+ if (utf8_len < 0)
+ _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph,
+ sub_font->scaled_font,
+ scaled_font_glyph_index);
status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
if (status) {
@@ -491,7 +492,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
subset_glyph->is_composite = sub_font->is_composite;
subset_glyph->x_advance = sub_font_glyph->x_advance;
subset_glyph->y_advance = sub_font_glyph->y_advance;
- subset_glyph->utf8_is_mapped = FALSE;
+ subset_glyph->utf8_is_mapped = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, utf8, utf8_len);
return CAIRO_STATUS_SUCCESS;
}
commit bc4d363e9238da0908ce01d0c08c3f344bd9d34f
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Fri Aug 8 01:27:41 2008 -0400
[pdf-operators] Add note about clusters with no glyphs
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
index 4f39318..d3eddc8 100644
--- a/src/cairo-pdf-operators.c
+++ b/src/cairo-pdf-operators.c
@@ -1287,6 +1287,8 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
_cairo_pdf_operators_flush_glyphs (pdf_operators);
status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len);
cur_glyph = glyphs;
+ /* XXX
+ * If no glyphs, we should put *something* here for the text to be selectable. */
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
scaled_font,
commit 1bc404e3460a32ba94b420725ecff25bda7a0c35
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Fri Aug 8 01:27:12 2008 -0400
Make utf8 handling in font subsets more consistent
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
index d51363a..4f39318 100644
--- a/src/cairo-pdf-operators.c
+++ b/src/cairo-pdf-operators.c
@@ -1266,7 +1266,7 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
scaled_font,
glyphs->index,
utf8,
- utf8_len < 0 ? 0 : utf8_len,
+ utf8_len,
&subset_glyph);
if (status)
return status;
@@ -1291,7 +1291,7 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
scaled_font,
cur_glyph->index,
- NULL, 0,
+ NULL, -1,
&subset_glyph);
if (status)
return status;
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 66200b2..103e117 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -280,7 +280,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
sub_font->next = NULL;
/* Reserve first glyph in subset for the .notdef glyph */
- status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, 0, &subset_glyph);
+ status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &subset_glyph);
if (status) {
_cairo_hash_table_destroy (sub_font->sub_font_glyphs);
free (sub_font);
@@ -355,6 +355,9 @@ _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
const char *utf8,
int utf8_len)
{
+ if (utf8_len < 0)
+ return FALSE;
+
if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
utf8_len--;
@@ -436,7 +439,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
sub_font->num_glyphs_in_current_subset = 0;
/* Reserve first glyph in subset for the .notdef glyph */
- status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, 0, &tmp_subset_glyph);
+ status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &tmp_subset_glyph);
if (status)
return status;
}
commit 849159ddd15b21b4feee05aebe82b3acfd94ba38
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Fri Aug 8 00:54:54 2008 -0400
[truetype] Fix gcc warning about possibly-infinite-loops
diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c
index 53d7232..892ce41 100644
--- a/src/cairo-truetype-subset.c
+++ b/src/cairo-truetype-subset.c
@@ -1245,12 +1245,13 @@ _cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font,
uint16_t g_id_be = cpu_to_be16 (index);
int j;
- for (j = 0; j < range_size; j++) {
- if (glyph_ids[j] == g_id_be) {
- *ucs4 = be16_to_cpu (start_code[i]) + j;
- goto found;
+ if (range_size > 0)
+ for (j = 0; j < range_size; j++) {
+ if (glyph_ids[j] == g_id_be) {
+ *ucs4 = be16_to_cpu (start_code[i]) + j;
+ goto found;
+ }
}
- }
}
}
commit 178789c37a2a6edaba14a453817b3f9338eab1bd
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Fri Aug 8 00:52:47 2008 -0400
[cairo-scaled-font-subsets] Make utf8 handling more robust
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 7e0114e..66200b2 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -355,7 +355,8 @@ _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
const char *utf8,
int utf8_len)
{
- int add_zero_byte = 0;
+ if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
+ utf8_len--;
if (utf8 != NULL && utf8_len != 0) {
if (sub_font_glyph->utf8 != NULL) {
@@ -372,12 +373,9 @@ _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
}
} else {
/* No existing mapping. Use the requested mapping */
- if (utf8[utf8_len - 1] != 0)
- add_zero_byte = 1;
- sub_font_glyph->utf8 = malloc (utf8_len + add_zero_byte);
+ sub_font_glyph->utf8 = malloc (utf8_len + 1);
memcpy (sub_font_glyph->utf8, utf8, utf8_len);
- if (add_zero_byte)
- sub_font_glyph->utf8[utf8_len] = 0;
+ sub_font_glyph->utf8[utf8_len] = 0;
sub_font_glyph->utf8_len = utf8_len;
return TRUE;
}
commit 597bfa922ae28ae4e7aa0ee72b856b5868799d4e
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Thu Aug 7 22:48:38 2008 -0400
[test/user-font] Document glyph-not-found situation
diff --git a/test/user-font.c b/test/user-font.c
index 406bd3a..ef81978 100644
--- a/test/user-font.c
+++ b/test/user-font.c
@@ -97,8 +97,8 @@ test_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
return CAIRO_STATUS_SUCCESS;
}
- /* Fall through and default to undefined glyph. */
- return CAIRO_STATUS_INVALID_INDEX;
+ /* Not found. Default to glyph 0 */
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -114,6 +114,8 @@ test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font,
div_t d;
double x, y;
+ /* FIXME: We simply crash on out-of-bound glyph indices */
+
metrics->x_advance = glyphs[glyph].width / 4.0;
cairo_set_line_width (cr, 0.1);
@@ -160,7 +162,7 @@ get_user_font_face (void)
* 13 14 15
*/
static const test_scaled_font_glyph_t glyphs [] = {
- { '\0', 0, { END_GLYPH } }, /* Poppler has a bug assuming glyph 0 is .notdef */
+ { '\0', 1, { END_GLYPH } }, /* Poppler has a bug assuming glyph 0 is .notdef */
{ ' ', 1, { END_GLYPH } },
{ '-', 2, { 7, 8, STROKE, END_GLYPH } },
{ '.', 1, { 10, 10, STROKE, END_GLYPH } },
commit d9408041aa220c8a61e520de25bce9671ba4d0a9
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Thu Aug 7 22:06:15 2008 -0400
Add cairo_scaled_font_text_to_glyphs()
And update user-font text_to_glyphs() method to match.
Currently disable the win32-font text_to_glyphs(), until that one
is updated. Or better yet, remove it and implement ucs4_to_index().
It's the toy font API afterall.
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 3160d07..bb05446 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1445,12 +1445,16 @@ _cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
}
cairo_status_t
-_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
- const char *utf8,
- double x,
- double y,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
+_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
+ double x,
+ double y,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs,
+ cairo_text_cluster_t **clusters,
+ int *num_clusters,
+ cairo_bool_t *backward)
{
cairo_status_t status;
@@ -1458,8 +1462,11 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
if (status)
return status;
- return _cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y,
- utf8, glyphs, num_glyphs);
+ return cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y,
+ utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ backward);
}
cairo_status_t
@@ -1536,7 +1543,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
if (num_glyphs <= ARRAY_LENGTH (stack_transformed_glyphs)) {
transformed_glyphs = stack_transformed_glyphs;
} else {
- transformed_glyphs = _cairo_malloc_ab (num_glyphs, sizeof(cairo_glyph_t));
+ transformed_glyphs = cairo_glyph_allocate (num_glyphs);
if (transformed_glyphs == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -1551,6 +1558,10 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
if (status)
goto CLEANUP_GLYPHS;
+ /* Just in case */
+ if (!clusters)
+ num_clusters = 0;
+
/* For really huge font sizes, we can just do path;fill instead of
* show_glyphs, as show_glyphs would put excess pressure on the cache,
* and moreover, not all components below us correctly handle huge font
@@ -1598,7 +1609,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
CLEANUP_GLYPHS:
if (transformed_glyphs != stack_transformed_glyphs)
- free (transformed_glyphs);
+ cairo_glyph_free (transformed_glyphs);
return status;
}
@@ -1620,7 +1631,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs))
transformed_glyphs = stack_transformed_glyphs;
else
- transformed_glyphs = _cairo_malloc_ab (num_glyphs, sizeof(cairo_glyph_t));
+ transformed_glyphs = cairo_glyph_allocate (num_glyphs);
if (transformed_glyphs == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -1634,7 +1645,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
CAIRO_MUTEX_UNLOCK (gstate->scaled_font->mutex);
if (transformed_glyphs != stack_transformed_glyphs)
- free (transformed_glyphs);
+ cairo_glyph_free (transformed_glyphs);
return status;
}
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 3fe3332..fa54231 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1109,7 +1109,7 @@ cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font,
cairo_text_extents_t *extents)
{
cairo_status_t status;
- cairo_glyph_t *glyphs;
+ cairo_glyph_t *glyphs = NULL;
int num_glyphs;
if (scaled_font->status)
@@ -1118,7 +1118,11 @@ cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font,
if (utf8 == NULL)
goto ZERO_EXTENTS;
- status = _cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., utf8, &glyphs, &num_glyphs);
+ status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0.,
+ utf8, -1,
+ &glyphs, &num_glyphs,
+ NULL, NULL,
+ NULL);
if (status)
goto ZERO_EXTENTS;
@@ -1265,70 +1269,148 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
slim_hidden_def (cairo_scaled_font_glyph_extents);
cairo_status_t
-_cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
- double x,
- double y,
- const char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
+cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
+ double x,
+ double y,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs,
+ cairo_text_cluster_t **clusters,
+ int *num_clusters,
+ cairo_bool_t *backward)
{
int i;
- uint32_t *ucs4 = NULL;
+ int num_chars = 0;
+ const char *p;
cairo_status_t status;
- cairo_scaled_glyph_t *scaled_glyph;
-
- *num_glyphs = 0;
- *glyphs = NULL;
+ cairo_glyph_t *orig_glyphs;
+ cairo_text_cluster_t *orig_clusters;
status = scaled_font->status;
if (status)
return status;
- if (utf8[0] == '\0')
- return CAIRO_STATUS_SUCCESS;
+ /* A slew of sanity checks */
+
+ /* glyphs and num_glyphs can't be NULL */
+ if (glyphs == NULL ||
+ num_glyphs == NULL) {
+ status = CAIRO_STATUS_NULL_POINTER;
+ goto BAIL;
+ }
+
+ /* No NULLs for non-NULLs! */
+ if ((utf8_len && utf8 == NULL) ||
+ (clusters && num_clusters == NULL) ||
+ (clusters && backward == NULL)) {
+ status = CAIRO_STATUS_NULL_POINTER;
+ goto BAIL;
+ }
+
+ /* A -1 for utf8_len means NUL-terminated */
+ if (utf8_len == -1)
+ utf8_len = strlen (utf8);
+
+ /* A NULL *glyphs means no prealloced glyphs array */
+ if (glyphs && *glyphs == NULL)
+ *num_glyphs = 0;
+
+ /* A NULL *clusters means no prealloced clusters array */
+ if (clusters && *clusters == NULL)
+ *num_clusters = 0;
+
+ if (!clusters && num_clusters) {
+ num_clusters = NULL;
+ }
+
+ if (backward) {
+ *backward = FALSE;
+ }
+
+ if (!clusters && backward) {
+ backward = NULL;
+ }
+
+ /* Apart from that, no negatives */
+ if (utf8_len < 0 ||
+ *num_glyphs < 0 ||
+ (num_clusters && *num_clusters < 0)) {
+ status = CAIRO_STATUS_NEGATIVE_COUNT;
+ goto BAIL;
+ }
+
+ if (utf8_len == 0) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL;
+ }
+
+ /* validate input so backend does not have to */
+ status = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, &num_chars);
+ if (status)
+ goto BAIL;
CAIRO_MUTEX_LOCK (scaled_font->mutex);
_cairo_scaled_font_freeze_cache (scaled_font);
- if (scaled_font->backend->text_to_glyphs) {
+ orig_glyphs = *glyphs;
+ orig_clusters = clusters ? *clusters : NULL;
- /* validate input so backend does not have to */
- status = _cairo_utf8_to_ucs4 (utf8, -1, NULL, NULL);
- if (status)
- goto DONE;
+ if (scaled_font->backend->text_to_glyphs) {
- status = scaled_font->backend->text_to_glyphs (scaled_font,
- x, y, utf8,
- glyphs, num_glyphs);
+ status = scaled_font->backend->text_to_glyphs (scaled_font, x, y,
+ utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ backward);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto DONE;
}
- status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, num_glyphs);
- if (status)
- goto DONE;
-
- *glyphs = (cairo_glyph_t *) _cairo_malloc_ab ((*num_glyphs), sizeof (cairo_glyph_t));
+ if (*num_glyphs < num_chars) {
+ *glyphs = cairo_glyph_allocate (num_chars);
+ if (*glyphs == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto DONE;
+ }
+ }
+ *num_glyphs = num_chars;
- if (*glyphs == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto DONE;
+ if (clusters) {
+ if (*num_clusters < num_chars) {
+ *clusters = cairo_text_cluster_allocate (num_chars);
+ if (*clusters == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto DONE;
+ }
+ }
+ *num_clusters = num_chars;
}
- for (i = 0; i < *num_glyphs; i++) {
- (*glyphs)[i].index = (*scaled_font->backend->
- ucs4_to_index) (scaled_font, ucs4[i]);
+ p = utf8;
+ for (i = 0; i < num_chars; i++) {
+ int num_bytes;
+ uint32_t unicode;
+ cairo_scaled_glyph_t *scaled_glyph;
+
+ num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
+ p += num_bytes;
+
+ (*glyphs)[i].index = (*scaled_font->backend->ucs4_to_index) (scaled_font, unicode);
(*glyphs)[i].x = x;
(*glyphs)[i].y = y;
+ if (clusters) {
+ (*clusters)[i].num_bytes = num_bytes;
+ (*clusters)[i].num_glyphs = 1;
+ }
+
status = _cairo_scaled_glyph_lookup (scaled_font,
(*glyphs)[i].index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
if (status) {
- free (*glyphs);
- *glyphs = NULL;
goto DONE;
}
@@ -1336,14 +1418,37 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
y += scaled_glyph->metrics.y_advance;
}
- DONE:
+ DONE: /* error that should be logged on scaled_font happened */
_cairo_scaled_font_thaw_cache (scaled_font);
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
- if (ucs4)
- free (ucs4);
+ if (status) {
+ *num_glyphs = 0;
+ if (*glyphs != orig_glyphs) {
+ cairo_glyph_free (*glyphs);
+ *glyphs = orig_glyphs;
+ }
+
+ if (clusters) {
+ *num_clusters = 0;
+ if (*clusters != orig_clusters) {
+ cairo_text_cluster_free (*clusters);
+ *clusters = orig_clusters;
+ }
+ }
+ }
return _cairo_scaled_font_set_error (scaled_font, status);
+
+ BAIL: /* error with input arguments */
+
+ if (num_glyphs)
+ *num_glyphs = 0;
+
+ if (num_clusters)
+ *num_clusters = 0;
+
+ return status;
}
/*
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index bcc3cfa..1949269 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -265,12 +265,16 @@ _cairo_user_ucs4_to_index (void *abstract_font,
}
static cairo_int_status_t
-_cairo_user_text_to_glyphs (void *abstract_font,
- double x,
- double y,
- const char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
+_cairo_user_text_to_glyphs (void *abstract_font,
+ double x,
+ double y,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs,
+ cairo_text_cluster_t **clusters,
+ int *num_clusters,
+ cairo_bool_t *backward)
{
cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
@@ -280,25 +284,21 @@ _cairo_user_text_to_glyphs (void *abstract_font,
if (face->scaled_font_methods.text_to_glyphs) {
int i;
+ int orig_num_glyphs = *num_glyphs;
- *glyphs = NULL;
- *num_glyphs = -1;
-
- /* XXX currently user allocs glyphs array but cairo frees it */
status = face->scaled_font_methods.text_to_glyphs (&scaled_font->base,
- utf8, glyphs, num_glyphs);
+ utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ backward);
- if (status != CAIRO_STATUS_SUCCESS) {
- status = _cairo_scaled_font_set_error (&scaled_font->base, status);
- if (*glyphs) {
- free (*glyphs);
- *glyphs = NULL;
- }
+ if (status != CAIRO_STATUS_SUCCESS)
return status;
- }
- if (*num_glyphs < 0)
+ if (*num_glyphs < 0) {
+ *num_glyphs = orig_num_glyphs;
return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
/* Convert from font space to user space and add x,y */
for (i = 0; i < *num_glyphs; i++) {
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 5c68f07..ef2d2f0 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -1780,7 +1780,7 @@ const cairo_scaled_font_backend_t _cairo_win32_scaled_font_backend = {
_cairo_win32_scaled_font_create_toy,
_cairo_win32_scaled_font_fini,
_cairo_win32_scaled_font_glyph_init,
- _cairo_win32_scaled_font_text_to_glyphs,
+ /* _cairo_win32_scaled_font_text_to_glyphs, FIXME */
NULL, /* ucs4_to_index */
_cairo_win32_scaled_font_show_glyphs,
_cairo_win32_scaled_font_load_truetype_table,
diff --git a/src/cairo.c b/src/cairo.c
index e96a3ee..e42fd70 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -3013,16 +3013,18 @@ cairo_text_extents (cairo_t *cr,
cairo_get_current_point (cr, &x, &y);
- status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
+ status = _cairo_gstate_text_to_glyphs (cr->gstate,
x, y,
- &glyphs, &num_glyphs);
+ utf8, strlen (utf8),
+ &glyphs, &num_glyphs,
+ NULL, NULL,
+ NULL);
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_gstate_glyph_extents (cr->gstate,
glyphs, num_glyphs,
extents);
- if (glyphs)
- free (glyphs);
+ cairo_glyph_free (glyphs);
if (status)
_cairo_set_error (cr, status);
@@ -3116,7 +3118,9 @@ cairo_show_text (cairo_t *cr, const char *utf8)
cairo_text_extents_t extents;
cairo_status_t status;
cairo_glyph_t *glyphs = NULL, *last_glyph;
- int num_glyphs;
+ cairo_text_cluster_t *clusters = NULL;
+ int utf8_len, num_glyphs, num_clusters;
+ cairo_bool_t backward;
double x, y;
if (cr->status)
@@ -3127,9 +3131,14 @@ cairo_show_text (cairo_t *cr, const char *utf8)
cairo_get_current_point (cr, &x, &y);
- status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
+ utf8_len = strlen (utf8);
+
+ status = _cairo_gstate_text_to_glyphs (cr->gstate,
x, y,
- &glyphs, &num_glyphs);
+ utf8, utf8_len,
+ &glyphs, &num_glyphs,
+ cairo_has_show_text_glyphs (cr) ? &clusters : NULL, &num_clusters,
+ &backward);
if (status)
goto BAIL;
@@ -3137,10 +3146,10 @@ cairo_show_text (cairo_t *cr, const char *utf8)
return;
status = _cairo_gstate_show_text_glyphs (cr->gstate,
- NULL, 0,
+ utf8, utf8_len,
glyphs, num_glyphs,
- NULL, 0,
- FALSE);
+ clusters, num_clusters,
+ backward);
if (status)
goto BAIL;
@@ -3156,8 +3165,8 @@ cairo_show_text (cairo_t *cr, const char *utf8)
cairo_move_to (cr, x, y);
BAIL:
- if (glyphs)
- free (glyphs);
+ cairo_glyph_free (glyphs);
+ cairo_text_cluster_free (clusters);
if (status)
_cairo_set_error (cr, status);
@@ -3226,6 +3235,14 @@ cairo_show_text_glyphs (cairo_t *cr,
/* A slew of sanity checks */
+ /* No NULLs for non-zeros */
+ if ((num_glyphs && glyphs == NULL) ||
+ (utf8_len && utf8 == NULL) ||
+ (num_clusters && clusters == NULL)) {
+ _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
+ return;
+ }
+
/* A -1 for utf8_len means NUL-terminated */
if (utf8_len == -1)
utf8_len = strlen (utf8);
@@ -3236,14 +3253,6 @@ cairo_show_text_glyphs (cairo_t *cr,
return;
}
- /* And no NULLs for non-zeros */
- if ((num_glyphs && glyphs == NULL) ||
- (utf8_len && utf8 == NULL) ||
- (num_clusters && clusters == NULL)) {
- _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
- return;
- }
-
/* Make sure clusters cover the entire glyphs and utf8 arrays,
* and that cluster boundaries are UTF-8 boundaries. */
{
@@ -3343,9 +3352,12 @@ cairo_text_path (cairo_t *cr, const char *utf8)
cairo_get_current_point (cr, &x, &y);
- status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
+ status = _cairo_gstate_text_to_glyphs (cr->gstate,
x, y,
- &glyphs, &num_glyphs);
+ utf8, strlen (utf8),
+ &glyphs, &num_glyphs,
+ NULL, NULL,
+ NULL);
if (status)
goto BAIL;
@@ -3373,8 +3385,7 @@ cairo_text_path (cairo_t *cr, const char *utf8)
cairo_move_to (cr, x, y);
BAIL:
- if (glyphs)
- free (glyphs);
+ cairo_glyph_free (glyphs);
if (status)
_cairo_set_error (cr, status);
diff --git a/src/cairo.h b/src/cairo.h
index 02d346a..ee933ab 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1330,6 +1330,18 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
int num_glyphs,
cairo_text_extents_t *extents);
+cairo_public cairo_status_t
+cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
+ double x,
+ double y,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs,
+ cairo_text_cluster_t **clusters,
+ int *num_clusters,
+ cairo_bool_t *backward);
+
cairo_public cairo_font_face_t *
cairo_scaled_font_get_font_face (cairo_scaled_font_t *scaled_font);
@@ -1468,6 +1480,7 @@ typedef cairo_status_t (*cairo_user_scaled_font_render_glyph_func_t) (cairo_scal
* @glyphs: output array of glyphs, in font space
* @num_glyphs: number of output glyphs
*
+ * XXXXXXXXXXXXX
* #cairo_user_scaled_font_text_to_glyphs_func_t is the type of function which
* is called to convert input text to an array of glyphs. This is used by the
* cairo_show_text() operation.
@@ -1496,9 +1509,13 @@ typedef cairo_status_t (*cairo_user_scaled_font_render_glyph_func_t) (cairo_scal
* Since: 1.8
**/
typedef cairo_status_t (*cairo_user_scaled_font_text_to_glyphs_func_t) (cairo_scaled_font_t *scaled_font,
- const char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs);
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs,
+ cairo_text_cluster_t **clusters,
+ int *num_clusters,
+ cairo_bool_t *backward);
/**
* cairo_user_scaled_font_unicode_to_glyph_func_t:
diff --git a/src/cairoint.h b/src/cairoint.h
index 8e27eb1..2c37035 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -408,12 +408,16 @@ struct _cairo_scaled_font_backend {
* then just converting characters one by one.
*/
cairo_warn cairo_int_status_t
- (*text_to_glyphs) (void *scaled_font,
- double x,
- double y,
- const char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs);
+ (*text_to_glyphs) (void *scaled_font,
+ double x,
+ double y,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs,
+ cairo_text_cluster_t **clusters,
+ int *num_clusters,
+ cairo_bool_t *backward);
unsigned long
(*ucs4_to_index) (void *scaled_font,
@@ -1219,12 +1223,16 @@ _cairo_gstate_set_font_face (cairo_gstate_t *gstate,
cairo_font_face_t *font_face);
cairo_private cairo_status_t
-_cairo_gstate_text_to_glyphs (cairo_gstate_t *font,
- const char *utf8,
- double x,
- double y,
- cairo_glyph_t **glyphs,
- int *num_glyphs);
+_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
+ double x,
+ double y,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs,
+ cairo_text_cluster_t **clusters,
+ int *num_clusters,
+ cairo_bool_t *backward);
cairo_private cairo_status_t
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
@@ -1529,14 +1537,6 @@ _cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *extents);
cairo_private cairo_status_t
-_cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
- double x,
- double y,
- const char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs);
-
-cairo_private cairo_status_t
_cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
const cairo_glyph_t *glyphs,
int num_glyphs,
diff --git a/test/user-font-proxy.c b/test/user-font-proxy.c
index 8684729..770b0c4 100644
--- a/test/user-font-proxy.c
+++ b/test/user-font-proxy.c
@@ -51,7 +51,7 @@ cairo_test_t test = {
draw
};
-static cairo_user_data_key_t fallback_font_face_key;
+static cairo_user_data_key_t fallback_font_key;
static cairo_status_t
test_scaled_font_init (cairo_scaled_font_t *scaled_font,
@@ -60,7 +60,12 @@ test_scaled_font_init (cairo_scaled_font_t *scaled_font,
{
cairo_set_font_face (cr,
cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
- &fallback_font_face_key));
+ &fallback_font_key));
+
+ cairo_scaled_font_set_user_data (scaled_font,
+ &fallback_font_key,
+ cairo_scaled_font_reference (cairo_get_scaled_font (cr)),
+ (cairo_destroy_func_t) cairo_scaled_font_destroy);
cairo_font_extents (cr, extents);
@@ -73,21 +78,44 @@ test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font,
cairo_t *cr,
cairo_text_extents_t *extents)
{
- char text[2] = "\0";
+ cairo_glyph_t cairo_glyph;
- /* XXX only works for ASCII. need ucs4_to_utf8 :( */
- text[0] = glyph;
+ cairo_glyph.index = glyph;
+ cairo_glyph.x = 0;
+ cairo_glyph.y = 0;
cairo_set_font_face (cr,
cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
- &fallback_font_face_key));
+ &fallback_font_key));
- cairo_show_text (cr, text);
- cairo_text_extents (cr, text, extents);
+ cairo_show_glyphs (cr, &cairo_glyph, 1);
+ cairo_glyph_extents (cr, &cairo_glyph, 1, extents);
return CAIRO_STATUS_SUCCESS;
}
+static cairo_status_t
+test_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs,
+ cairo_text_cluster_t **clusters,
+ int *num_clusters,
+ cairo_bool_t *backward)
+{
+ cairo_scaled_font_t *fallback_scaled_font;
+
+ fallback_scaled_font = cairo_scaled_font_get_user_data (scaled_font,
+ &fallback_font_key);
+
+ return cairo_scaled_font_text_to_glyphs (fallback_scaled_font, 0, 0,
+ utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ backward);
+}
+
static cairo_font_face_t *user_font_face = NULL;
static cairo_font_face_t *
@@ -99,6 +127,7 @@ get_user_font_face (void)
user_font_face = cairo_user_font_face_create ();
cairo_user_font_face_set_init_func (user_font_face, test_scaled_font_init);
cairo_user_font_face_set_render_glyph_func (user_font_face, test_scaled_font_render_glyph);
+ cairo_user_font_face_set_text_to_glyphs_func (user_font_face, test_scaled_font_text_to_glyphs);
/* This also happens to be default font face on cairo_t, so does
* not make much sense here. For demonstration only.
@@ -108,9 +137,9 @@ get_user_font_face (void)
CAIRO_FONT_WEIGHT_NORMAL);
cairo_font_face_set_user_data (user_font_face,
- &fallback_font_face_key,
+ &fallback_font_key,
fallback_font_face,
- cairo_font_face_destroy);
+ (cairo_destroy_func_t) cairo_font_face_destroy);
}
return user_font_face;
commit b8fc845094e07ad2520a2c10f27c532bd3273720
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Thu Aug 7 21:46:36 2008 -0400
[cairo-scaled-font-subsets] Fix bug with utf8 handling
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 94d1cea..7e0114e 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -372,7 +372,7 @@ _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
}
} else {
/* No existing mapping. Use the requested mapping */
- if (sub_font_glyph->utf8[utf8_len - 1] != 0)
+ if (utf8[utf8_len - 1] != 0)
add_zero_byte = 1;
sub_font_glyph->utf8 = malloc (utf8_len + add_zero_byte);
memcpy (sub_font_glyph->utf8, utf8, utf8_len);
commit 6b3f6dc77abbc48d741b92cd62f93da68f00b9a2
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Thu Aug 7 20:45:54 2008 -0400
[unicode] Add _cairo_utf8_get_char_validated()
diff --git a/src/cairo-unicode.c b/src/cairo-unicode.c
index 973ef57..39d37b8 100644
--- a/src/cairo-unicode.c
+++ b/src/cairo-unicode.c
@@ -196,6 +196,40 @@ _utf8_get_char_extended (const unsigned char *p,
}
/**
+ * _cairo_utf8_get_char_validated:
+ * @p: a UTF-8 string
+ * @unicode: location to store one Unicode character
+ *
+ * Decodes the first character of a valid UTF-8 string, and returns
+ * the number of bytes consumed.
+ *
+ * Note that the string should be valid. Do not use this without
+ * validating the string first.
+ *
+ * Returns: the number of bytes forming the character returned.
+ **/
+int
+_cairo_utf8_get_char_validated (const char *p,
+ uint32_t *unicode)
+{
+ int i, mask = 0, len;
+ uint32_t result;
+ unsigned char c = (unsigned char) *p;
+
+ UTF8_COMPUTE (c, mask, len);
+ if (len == -1) {
+ if (unicode)
+ *unicode = (uint32_t)-1;
+ return 1;
+ }
+ UTF8_GET (result, p, i, mask, len);
+
+ if (unicode)
+ *unicode = result;
+ return len;
+}
+
+/**
* _cairo_utf8_to_utf32:
* @str: an UTF-8 string
* @len: length of @str in bytes, or -1 if it is nul-terminated.
@@ -266,7 +300,7 @@ _cairo_utf8_to_ucs4 (const char *str,
* _cairo_ucs4_to_utf8:
* @unicode: a UCS-4 character
* @utf8: buffer to write utf8 string into. Must have at least 4 bytes
- * space available.
+ * space available. Or %NULL.
*
* Return value: Number of bytes in the utf8 string or 0 if an invalid
* unicode character
@@ -279,7 +313,8 @@ _cairo_ucs4_to_utf8 (uint32_t unicode,
char *p;
if (unicode < 0x80) {
- *utf8 = unicode;
+ if (utf8)
+ *utf8 = unicode;
return 1;
} else if (unicode < 0x800) {
bytes = 2;
@@ -291,6 +326,9 @@ _cairo_ucs4_to_utf8 (uint32_t unicode,
return 0;
}
+ if (!utf8)
+ return bytes;
+
p = utf8 + bytes;
while (p > utf8) {
*--p = 0x80 | (unicode & 0x3f);
diff --git a/src/cairoint.h b/src/cairoint.h
index 486a164..8e27eb1 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2316,6 +2316,10 @@ _cairo_gstate_get_antialias (cairo_gstate_t *gstate);
/* cairo-unicode.c */
+cairo_private int
+_cairo_utf8_get_char_validated (const char *p,
+ uint32_t *unicode);
+
cairo_private cairo_status_t
_cairo_utf8_to_ucs4 (const char *str,
int len,
commit 8c514a40b80e11cc904db3ce9ee353839321044e
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Thu Aug 7 20:44:45 2008 -0400
Add cairo_glyph/text_cluster_allocate/free
These are needed by the upcoming cairo_scaled_font_text_to_glyphs()
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 3432e50..1e74c67 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -41,6 +41,8 @@
COMPILE_TIME_ASSERT (CAIRO_STATUS_LAST_STATUS < CAIRO_INT_STATUS_UNSUPPORTED);
COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
+/* Public stuff */
+
/**
* cairo_status_to_string:
* @status: a cairo status
@@ -122,6 +124,108 @@ cairo_status_to_string (cairo_status_t 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));
+}
+
+/**
+ * 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)
+{
+ if (glyphs)
+ free (glyphs);
+}
+
+/**
+ * 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));
+}
+
+/**
+ * cairo_text_cluster_free:
+ * @text_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)
+{
+ if (clusters)
+ free (clusters);
+}
+
+
+/* Private stuff */
+
/**
* _cairo_operator_bounded_by_mask:
* @op: a #cairo_operator_t
diff --git a/src/cairo.h b/src/cairo.h
index e26c257..02d346a 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -830,11 +830,23 @@ typedef struct {
double y;
} cairo_glyph_t;
+cairo_public cairo_glyph_t *
+cairo_glyph_allocate (int num_glyphs);
+
+cairo_public void
+cairo_glyph_free (cairo_glyph_t *glyphs);
+
typedef struct {
int num_bytes;
int num_glyphs;
} cairo_text_cluster_t;
+cairo_public cairo_text_cluster_t *
+cairo_text_cluster_allocate (int num_clusters);
+
+cairo_public void
+cairo_text_cluster_free (cairo_text_cluster_t *clusters);
+
/**
* cairo_text_extents_t:
* @x_bearing: the horizontal distance from the origin to the
commit b01ad0835d25fbee91d037e4484ba652075ffb39
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Thu Aug 7 15:44:11 2008 -0400
[user-font] Add a cairo_t argument to cairo_user_scaled_font_init_func_t
The init func does not actually need to draw anything, but having a cairo_t
similar to that passed to render_glyph is handy for computing font extents.
This is because cairo makes doing some things really hard (if not impossible)
without a cairo_t.
The user-font-proxy test case is a great example of how the added cairo_t
makes life much easier.
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index cb15ca4..bcc3cfa 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -74,6 +74,28 @@ typedef struct _cairo_user_scaled_font {
/* #cairo_user_scaled_font_t */
+static cairo_t *
+_cairo_user_scaled_font_create_meta_context (cairo_user_scaled_font_t *scaled_font)
+{
+ cairo_content_t content;
+ cairo_surface_t *meta_surface;
+ cairo_t *cr;
+
+ content = scaled_font->base.options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ?
+ CAIRO_CONTENT_COLOR_ALPHA :
+ CAIRO_CONTENT_ALPHA;
+
+ meta_surface = _cairo_meta_surface_create (content, -1, -1);
+ cr = cairo_create (meta_surface);
+ cairo_surface_destroy (meta_surface);
+
+ cairo_set_matrix (cr, &scaled_font->base.scale);
+ cairo_set_font_size (cr, 1.0);
+ cairo_set_font_options (cr, &scaled_font->base.options);
+
+ return cr;
+}
+
static const cairo_scaled_font_backend_t cairo_user_scaled_font_backend;
static cairo_int_status_t
@@ -89,17 +111,9 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
cairo_user_font_face_t *face =
(cairo_user_font_face_t *) scaled_font->base.font_face;
cairo_text_extents_t extents = scaled_font->default_glyph_extents;
- cairo_content_t content = scaled_font->base.options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ?
- CAIRO_CONTENT_COLOR_ALPHA :
- CAIRO_CONTENT_ALPHA;
cairo_t *cr;
- meta_surface = _cairo_meta_surface_create (content, -1, -1);
- cr = cairo_create (meta_surface);
-
- cairo_set_matrix (cr, &scaled_font->base.scale);
- cairo_set_font_size (cr, 1.0);
- cairo_set_font_options (cr, &scaled_font->base.options);
+ cr = _cairo_user_scaled_font_create_meta_context (scaled_font);
if (face->scaled_font_methods.render_glyph)
status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font,
@@ -111,6 +125,8 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_status (cr);
+ meta_surface = cairo_surface_reference (cairo_get_target (cr));
+
cairo_destroy (cr);
if (status) {
@@ -377,6 +393,8 @@ _cairo_user_font_face_scaled_font_create (void *abstract_
if (status == CAIRO_STATUS_SUCCESS && font_face->scaled_font_methods.init != NULL) {
+ cairo_t *cr;
+
/* Lock the scaled_font mutex such that user doesn't accidentally try
* to use it just yet. */
CAIRO_MUTEX_LOCK (user_scaled_font->base.mutex);
@@ -384,9 +402,17 @@ _cairo_user_font_face_scaled_font_create (void *abstract_
/* Give away fontmap lock such that user-font can use other fonts */
_cairo_scaled_font_register_placeholder_and_unlock_font_map (&user_scaled_font->base);
+ cr = _cairo_user_scaled_font_create_meta_context (user_scaled_font);
+
status = font_face->scaled_font_methods.init (&user_scaled_font->base,
+ cr,
&font_extents);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = cairo_status (cr);
+
+ cairo_destroy (cr);
+
_cairo_scaled_font_unregister_placeholder_and_lock_font_map (&user_scaled_font->base);
CAIRO_MUTEX_UNLOCK (user_scaled_font->base.mutex);
diff --git a/src/cairo.h b/src/cairo.h
index 1be31ab..e26c257 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1365,11 +1365,18 @@ cairo_user_font_face_create (void);
/**
* cairo_user_scaled_font_init_func_t:
* @scaled_font: the scaled-font being created
+ * @cr: a cairo context, in font space
* @extents: font extents to fill in, in font space
*
* #cairo_user_scaled_font_init_func_t is the type of function which is
* called when a scaled-font needs to be created for a user font-face.
*
+ * The cairo context @cr is not used by the caller, but is prepared in font
+ * space, similar to what the cairo contexts passed to the render_glyph
+ * method will look like. The callback can use this context for extents
+ * computation for example. After the callback is called, @cr is checked
+ * for any error status.
+ *
* The @extents argument is where the user font sets the font extents for
* @scaled_font. It is in font space, which means that for most cases its
* ascent and descent members should add to 1.0. @extents is preset to
@@ -1391,6 +1398,7 @@ cairo_user_font_face_create (void);
* Since: 1.8
**/
typedef cairo_status_t (*cairo_user_scaled_font_init_func_t) (cairo_scaled_font_t *scaled_font,
+ cairo_t *cr,
cairo_font_extents_t *extents);
/**
diff --git a/test/user-font-proxy.c b/test/user-font-proxy.c
index c7b29ab..8684729 100644
--- a/test/user-font-proxy.c
+++ b/test/user-font-proxy.c
@@ -55,40 +55,16 @@ static cairo_user_data_key_t fallback_font_face_key;
static cairo_status_t
test_scaled_font_init (cairo_scaled_font_t *scaled_font,
+ cairo_t *cr,
cairo_font_extents_t *extents)
{
- cairo_font_face_t *font_face;
- cairo_matrix_t font_matrix, ctm;
- cairo_font_options_t *font_options;
- cairo_scaled_font_t *fallback_scaled_font;
-
- font_face = cairo_toy_font_face_create ("",
- CAIRO_FONT_SLANT_NORMAL,
- CAIRO_FONT_WEIGHT_NORMAL);
-
- cairo_matrix_init_identity (&font_matrix);
- cairo_scaled_font_get_scale_matrix (scaled_font, &ctm);
-
- font_options = cairo_font_options_create ();
- cairo_scaled_font_get_font_options (scaled_font, font_options);
-
- fallback_scaled_font = cairo_scaled_font_create (font_face,
- &font_matrix,
- &ctm,
- font_options);
-
- cairo_font_options_destroy (font_options);
-
- cairo_scaled_font_extents (fallback_scaled_font, extents);
-
- cairo_scaled_font_destroy (fallback_scaled_font);
+ cairo_set_font_face (cr,
+ cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
+ &fallback_font_face_key));
- cairo_scaled_font_set_user_data (scaled_font,
- &fallback_font_face_key,
- font_face,
- cairo_font_face_destroy);
+ cairo_font_extents (cr, extents);
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -103,23 +79,38 @@ test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font,
text[0] = glyph;
cairo_set_font_face (cr,
- cairo_scaled_font_get_user_data (scaled_font,
- &fallback_font_face_key));
+ cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
+ &fallback_font_face_key));
+
cairo_show_text (cr, text);
cairo_text_extents (cr, text, extents);
return CAIRO_STATUS_SUCCESS;
}
+static cairo_font_face_t *user_font_face = NULL;
+
static cairo_font_face_t *
get_user_font_face (void)
{
- static cairo_font_face_t *user_font_face = NULL;
-
if (!user_font_face) {
+ cairo_font_face_t *fallback_font_face;
+
user_font_face = cairo_user_font_face_create ();
cairo_user_font_face_set_init_func (user_font_face, test_scaled_font_init);
cairo_user_font_face_set_render_glyph_func (user_font_face, test_scaled_font_render_glyph);
+
+ /* This also happens to be default font face on cairo_t, so does
+ * not make much sense here. For demonstration only.
+ */
+ fallback_font_face = cairo_toy_font_face_create ("",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+
+ cairo_font_face_set_user_data (user_font_face,
+ &fallback_font_face_key,
+ fallback_font_face,
+ cairo_font_face_destroy);
}
return user_font_face;
@@ -181,6 +172,11 @@ draw (cairo_t *cr, int width, int height)
cairo_text_path (cr, text);
cairo_fill (cr);
+ if (user_font_face) {
+ cairo_font_face_destroy (user_font_face);
+ user_font_face = NULL;
+ }
+
return CAIRO_TEST_SUCCESS;
}
diff --git a/test/user-font.c b/test/user-font.c
index c414719..406bd3a 100644
--- a/test/user-font.c
+++ b/test/user-font.c
@@ -74,6 +74,7 @@ static cairo_user_data_key_t test_font_face_glyphs_key;
static cairo_status_t
test_scaled_font_init (cairo_scaled_font_t *scaled_font,
+ cairo_t *cr,
cairo_font_extents_t *metrics)
{
metrics->ascent = .75;
commit d6ae23478ae6bde0714a50b2ed77e788f17cc03d
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Thu Aug 7 15:43:21 2008 -0400
Check for NULL pointer in cairo_set_scaled_font
diff --git a/src/cairo.c b/src/cairo.c
index 4151eed..e96a3ee 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -2905,6 +2905,11 @@ cairo_set_scaled_font (cairo_t *cr,
if (cr->status)
return;
+ if (scaled_font == NULL) {
+ status = CAIRO_STATUS_NULL_POINTER;
+ goto BAIL;
+ }
+
status = scaled_font->status;
if (status)
goto BAIL;
commit b67d34e960fa07cfafb13e3a5b5b4a63cfb024d3
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Thu Aug 7 15:42:58 2008 -0400
[gstate] Check for NULL font_face in _cairo_gstate_set_font_face
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index b23d0b6..3160d07 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1466,7 +1466,10 @@ cairo_status_t
_cairo_gstate_set_font_face (cairo_gstate_t *gstate,
cairo_font_face_t *font_face)
{
- if (font_face && font_face->status)
+ if (font_face == NULL)
+ return CAIRO_STATUS_NULL_POINTER;
+
+ if (font_face->status)
return font_face->status;
if (font_face != gstate->font_face) {
commit 7e57892983bbc639fe4a402a427b255e4d4ab746
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Wed Aug 6 21:37:36 2008 -0400
Add toy font constructor and getters
New public API:
cairo_toy_font_face_create()
cairo_toy_font_face_get_family()
cairo_toy_font_face_get_slant()
cairo_toy_font_face_get_weight()
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 3954c45..4b9cdc5 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -408,6 +408,10 @@ cairo_show_text_glyphs
cairo_font_extents
cairo_text_extents
cairo_glyph_extents
+cairo_toy_font_face_create
+cairo_toy_font_face_get_family
+cairo_toy_font_face_get_slant
+cairo_toy_font_face_get_weight
</SECTION>
<SECTION>
diff --git a/doc/public/tmpl/cairo-status.sgml b/doc/public/tmpl/cairo-status.sgml
index 37b5898..7d65bd5 100644
--- a/doc/public/tmpl/cairo-status.sgml
+++ b/doc/public/tmpl/cairo-status.sgml
@@ -68,6 +68,8 @@ code is required before or after each individual cairo function call.
@CAIRO_STATUS_USER_FONT_ERROR:
@CAIRO_STATUS_NEGATIVE_COUNT:
@CAIRO_STATUS_INVALID_CLUSTERS:
+ at CAIRO_STATUS_INVALID_SLANT:
+ at CAIRO_STATUS_INVALID_WEIGHT:
<!-- ##### FUNCTION cairo_status_to_string ##### -->
<para>
diff --git a/doc/public/tmpl/cairo-text.sgml b/doc/public/tmpl/cairo-text.sgml
index 06e365c..3e5c6bb 100644
--- a/doc/public/tmpl/cairo-text.sgml
+++ b/doc/public/tmpl/cairo-text.sgml
@@ -244,3 +244,41 @@ Cairo has two sets of text rendering capabilities:
@extents:
+<!-- ##### FUNCTION cairo_toy_font_face_create ##### -->
+<para>
+
+</para>
+
+ at family:
+ at slant:
+ at weight:
+ at Returns:
+
+
+<!-- ##### FUNCTION cairo_toy_font_face_get_family ##### -->
+<para>
+
+</para>
+
+ at font_face:
+ at Returns:
+
+
+<!-- ##### FUNCTION cairo_toy_font_face_get_slant ##### -->
+<para>
+
+</para>
+
+ at font_face:
+ at Returns:
+
+
+<!-- ##### FUNCTION cairo_toy_font_face_get_weight ##### -->
+<para>
+
+</para>
+
+ at font_face:
+ at Returns:
+
+
diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c
index 1d67398..4f822a2 100644
--- a/src/cairo-font-face.c
+++ b/src/cairo-font-face.c
@@ -41,19 +41,78 @@
#define _BSD_SOURCE /* for strdup() */
#include "cairoint.h"
-/* Forward declare so we can use it as an arbitrary backend for
- * _cairo_font_face_nil.
- */
static const cairo_font_face_backend_t _cairo_toy_font_face_backend;
/* #cairo_font_face_t */
-const cairo_font_face_t _cairo_font_face_nil = {
- { 0 }, /* hash_entry */
- CAIRO_STATUS_NO_MEMORY, /* status */
+const cairo_toy_font_face_t _cairo_font_face_nil = {
+ {
+ { 0 }, /* hash_entry */
+ CAIRO_STATUS_NO_MEMORY, /* status */
+ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
+ { 0, 0, 0, NULL }, /* user_data */
+ &_cairo_toy_font_face_backend
+ },
+ CAIRO_FONT_FAMILY_DEFAULT, /* family */
+ TRUE, /* owns_family */
+ CAIRO_FONT_SLANT_DEFAULT, /* slant */
+ CAIRO_FONT_WEIGHT_DEFAULT /* weight */
+};
+
+static const cairo_toy_font_face_t _cairo_font_face_null_pointer = {
+ {
+ { 0 }, /* hash_entry */
+ CAIRO_STATUS_NULL_POINTER, /* status */
+ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
+ { 0, 0, 0, NULL }, /* user_data */
+ &_cairo_toy_font_face_backend
+ },
+ CAIRO_FONT_FAMILY_DEFAULT, /* family */
+ TRUE, /* owns_family */
+ CAIRO_FONT_SLANT_DEFAULT, /* slant */
+ CAIRO_FONT_WEIGHT_DEFAULT /* weight */
+};
+
+static const cairo_toy_font_face_t _cairo_font_face_invalid_string = {
+ {
+ { 0 }, /* hash_entry */
+ CAIRO_STATUS_INVALID_STRING, /* status */
+ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
+ { 0, 0, 0, NULL }, /* user_data */
+ &_cairo_toy_font_face_backend
+ },
+ CAIRO_FONT_FAMILY_DEFAULT, /* family */
+ TRUE, /* owns_family */
+ CAIRO_FONT_SLANT_DEFAULT, /* slant */
+ CAIRO_FONT_WEIGHT_DEFAULT /* weight */
+};
+
+static const cairo_toy_font_face_t _cairo_font_face_invalid_slant = {
+ {
+ { 0 }, /* hash_entry */
+ CAIRO_STATUS_INVALID_SLANT, /* status */
+ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
+ { 0, 0, 0, NULL }, /* user_data */
+ &_cairo_toy_font_face_backend
+ },
+ CAIRO_FONT_FAMILY_DEFAULT, /* family */
+ TRUE, /* owns_family */
+ CAIRO_FONT_SLANT_DEFAULT, /* slant */
+ CAIRO_FONT_WEIGHT_DEFAULT /* weight */
+};
+
+static const cairo_toy_font_face_t _cairo_font_face_invalid_weight = {
+ {
+ { 0 }, /* hash_entry */
+ CAIRO_STATUS_INVALID_WEIGHT, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
- { 0, 0, 0, NULL }, /* user_data */
+ { 0, 0, 0, NULL }, /* user_data */
&_cairo_toy_font_face_backend
+ },
+ CAIRO_FONT_FAMILY_DEFAULT, /* family */
+ TRUE, /* owns_family */
+ CAIRO_FONT_SLANT_DEFAULT, /* slant */
+ CAIRO_FONT_WEIGHT_DEFAULT /* weight */
};
cairo_status_t
@@ -371,7 +430,7 @@ _cairo_toy_font_face_keys_equal (const void *key_a,
}
/**
- * _cairo_toy_font_face_create:
+ * cairo_toy_font_face_create:
* @family: a font family name, encoded in UTF-8
* @slant: the slant for the font
* @weight: the weight for the font
@@ -380,18 +439,57 @@ _cairo_toy_font_face_keys_equal (const void *key_a,
* These font faces are used in implementation of the the #cairo_t "toy"
* font API.
*
- * Return value: a newly created #cairo_font_face_t, destroy with
- * cairo_font_face_destroy()
+ * If @family is the zero-length string "", the platform-specific default
+ * family is assumed. The default family then can be queried using
+ * cairo_toy_font_face_get_family().
+ *
+ * The cairo_select_font_face() function uses this to create font faces.
+ * See that function for limitations of toy font faces.
+ *
+ * Return value: a newly created #cairo_font_face_t. Free with
+ * cairo_font_face_destroy() when you are done using it.
+ *
+ * Since: 1.8
**/
cairo_font_face_t *
-_cairo_toy_font_face_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
+cairo_toy_font_face_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
{
cairo_status_t status;
cairo_toy_font_face_t key, *font_face;
cairo_hash_table_t *hash_table;
+ if (family == NULL)
+ return (cairo_font_face_t*) &_cairo_font_face_null_pointer;
+
+ /* Make sure we've got valid UTF-8 for the family */
+ status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL);
+ if (status == CAIRO_STATUS_INVALID_STRING)
+ return (cairo_font_face_t*) &_cairo_font_face_invalid_string;
+ else if (status)
+ return (cairo_font_face_t*) &_cairo_font_face_nil;
+
+ switch (slant) {
+ case CAIRO_FONT_SLANT_NORMAL:
+ case CAIRO_FONT_SLANT_ITALIC:
+ case CAIRO_FONT_SLANT_OBLIQUE:
+ break;
+ default:
+ return (cairo_font_face_t*) &_cairo_font_face_invalid_slant;
+ }
+
+ switch (weight) {
+ case CAIRO_FONT_WEIGHT_NORMAL:
+ case CAIRO_FONT_WEIGHT_BOLD:
+ break;
+ default:
+ return (cairo_font_face_t*) &_cairo_font_face_invalid_weight;
+ }
+
+ if (*family == '\0')
+ family = CAIRO_FONT_FAMILY_DEFAULT;
+
hash_table = _cairo_toy_font_face_hash_table_lock ();
if (hash_table == NULL)
goto UNWIND;
@@ -444,6 +542,7 @@ _cairo_toy_font_face_create (const char *family,
UNWIND:
return (cairo_font_face_t*) &_cairo_font_face_nil;
}
+slim_hidden_def (cairo_toy_font_face_create);
static void
_cairo_toy_font_face_destroy (void *abstract_face)
@@ -493,6 +592,77 @@ _cairo_toy_font_face_scaled_font_create (void *abstract_font_face
scaled_font));
}
+static cairo_bool_t
+_cairo_font_face_is_toy (cairo_font_face_t *font_face)
+{
+ return font_face->backend == &_cairo_toy_font_face_backend;
+}
+
+/**
+ * cairo_toy_font_face_get_family:
+ * @font_face: A toy font face
+ *
+ * Gets the familly name of a toy font.
+ *
+ * Return value: The family name. This string is owned by the font face
+ * and remains valid as long as the font face is alive (referenced).
+ *
+ * Since: 1.8
+ **/
+const char *
+cairo_toy_font_face_get_family (cairo_font_face_t *font_face)
+{
+ cairo_toy_font_face_t *toy_font_face = (cairo_toy_font_face_t *) font_face;
+ if (! _cairo_font_face_is_toy (font_face)) {
+ if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
+ return CAIRO_FONT_FAMILY_DEFAULT;
+ }
+ assert (toy_font_face->owns_family);
+ return toy_font_face->family;
+}
+
+/**
+ * cairo_toy_font_face_get_slant:
+ * @font_face: A toy font face
+ *
+ * Gets the slant a toy font.
+ *
+ * Return value: The slant value
+ *
+ * Since: 1.8
+ **/
+cairo_font_slant_t
+cairo_toy_font_face_get_slant (cairo_font_face_t *font_face)
+{
+ cairo_toy_font_face_t *toy_font_face = (cairo_toy_font_face_t *) font_face;
+ if (! _cairo_font_face_is_toy (font_face)) {
+ if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
+ return CAIRO_FONT_SLANT_DEFAULT;
+ }
+ return toy_font_face->slant;
+}
+
+/**
+ * cairo_toy_font_face_get_weight:
+ * @font_face: A toy font face
+ *
+ * Gets the weight a toy font.
+ *
+ * Return value: The weight value
+ *
+ * Since: 1.8
+ **/
+cairo_font_weight_t
+cairo_toy_font_face_get_weight (cairo_font_face_t *font_face)
+{
+ cairo_toy_font_face_t *toy_font_face = (cairo_toy_font_face_t *) font_face;
+ if (! _cairo_font_face_is_toy (font_face)) {
+ if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
+ return CAIRO_FONT_WEIGHT_DEFAULT;
+ }
+ return toy_font_face->weight;
+}
+
static const cairo_font_face_backend_t _cairo_toy_font_face_backend = {
CAIRO_FONT_TYPE_TOY,
_cairo_toy_font_face_destroy,
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index b9d59d3..b23d0b6 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1215,7 +1215,7 @@ _cairo_gstate_select_font_face (cairo_gstate_t *gstate,
cairo_font_face_t *font_face;
cairo_status_t status;
- font_face = _cairo_toy_font_face_create (family, slant, weight);
+ font_face = cairo_toy_font_face_create (family, slant, weight);
if (font_face->status)
return font_face->status;
@@ -1389,7 +1389,7 @@ _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
return gstate->font_face->status;
- font_face = _cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
+ font_face = cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
CAIRO_FONT_SLANT_DEFAULT,
CAIRO_FONT_WEIGHT_DEFAULT);
if (font_face->status)
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 71338bf..3432e50 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -113,6 +113,10 @@ cairo_status_to_string (cairo_status_t status)
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 "input value for an input #cairo_font_weight_t";
}
return "<unknown error status>";
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index ca703aa..3eca6fc 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2632,6 +2632,8 @@ _cairo_surface_create_in_error (cairo_status_t status)
case CAIRO_STATUS_USER_FONT_ERROR:
case CAIRO_STATUS_NEGATIVE_COUNT:
case CAIRO_STATUS_INVALID_CLUSTERS:
+ case CAIRO_STATUS_INVALID_SLANT:
+ case CAIRO_STATUS_INVALID_WEIGHT:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t *) &_cairo_surface_nil;
diff --git a/src/cairo.c b/src/cairo.c
index 46e587b..4151eed 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -2641,8 +2641,12 @@ cairo_copy_clip_rectangle_list (cairo_t *cr)
*
* If text is drawn without a call to cairo_select_font_face(), (nor
* cairo_set_font_face() nor cairo_set_scaled_font()), the default
- * family is "sans", slant is %CAIRO_FONT_SLANT_NORMAL, and weight is
+ * family is platform-specific, but is essentially "sans-serif".
+ * Default slant is %CAIRO_FONT_SLANT_NORMAL, and default weight is
* %CAIRO_FONT_WEIGHT_NORMAL.
+ *
+ * This function is equivalent to a call to cairo_toy_font_face_create()
+ * followed by cairo_set_font_face().
**/
void
cairo_select_font_face (cairo_t *cr,
diff --git a/src/cairo.h b/src/cairo.h
index 0829591..1be31ab 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -208,6 +208,8 @@ typedef struct _cairo_user_data_key {
* @CAIRO_STATUS_USER_FONT_ERROR: error occurred in a user-font callback function (Since 1.8)
* @CAIRO_STATUS_NEGATIVE_COUNT: negative number used where it is not allowed (Since 1.8)
* @CAIRO_STATUS_INVALID_CLUSTERS: input clusters do not represent the accompanying text and glyph array (Since 1.8)
+ * @CAIRO_STATUS_INVALID_SLANT: invalid value for an input #cairo_font_slant_t (Since 1.8)
+ * @CAIRO_STATUS_INVALID_CLUSTERS: input value for an input #cairo_font_weight_t (Since 1.8)
*
* #cairo_status_t is used to indicate errors that can occur when
* using Cairo. In some cases it is returned directly by functions.
@@ -247,7 +249,9 @@ typedef enum _cairo_status {
CAIRO_STATUS_USER_FONT_IMMUTABLE,
CAIRO_STATUS_USER_FONT_ERROR,
CAIRO_STATUS_NEGATIVE_COUNT,
- CAIRO_STATUS_INVALID_CLUSTERS
+ CAIRO_STATUS_INVALID_CLUSTERS,
+ CAIRO_STATUS_INVALID_SLANT,
+ CAIRO_STATUS_INVALID_WEIGHT
/* after adding a new error: update CAIRO_STATUS_LAST_STATUS in cairoint.h */
} cairo_status_t;
@@ -1333,6 +1337,24 @@ cairo_public void
cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font,
cairo_font_options_t *options);
+
+/* Toy fonts */
+
+cairo_public cairo_font_face_t *
+cairo_toy_font_face_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight);
+
+cairo_public const char *
+cairo_toy_font_face_get_family (cairo_font_face_t *font_face);
+
+cairo_public cairo_font_slant_t
+cairo_toy_font_face_get_slant (cairo_font_face_t *font_face);
+
+cairo_public cairo_font_weight_t
+cairo_toy_font_face_get_weight (cairo_font_face_t *font_face);
+
+
/* User fonts */
cairo_public cairo_font_face_t *
diff --git a/src/cairoint.h b/src/cairoint.h
index 0f21776..486a164 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -110,7 +110,7 @@ _cairo_win32_tmpfile (void);
* a bit of a pain, but it should be easy to always catch as long as
* one adds a new test case to test a trigger of the new status value.
*/
-#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_CLUSTERS
+#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_SLANT
/* Size in bytes of buffer to use off the stack per functions.
@@ -1304,7 +1304,7 @@ _cairo_color_equal (const cairo_color_t *color_a,
/* cairo-font-face.c */
-extern const cairo_private cairo_font_face_t _cairo_font_face_nil;
+extern const cairo_private cairo_toy_font_face_t _cairo_font_face_nil;
cairo_private void
_cairo_font_face_init (cairo_font_face_t *font_face,
@@ -1314,11 +1314,6 @@ cairo_private cairo_status_t
_cairo_font_face_set_error (cairo_font_face_t *font_face,
cairo_status_t status);
-cairo_private cairo_font_face_t *
-_cairo_toy_font_face_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight);
-
cairo_private void
_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
const cairo_unscaled_font_backend_t *backend);
@@ -2447,6 +2442,7 @@ slim_hidden_proto (cairo_surface_set_fallback_resolution);
slim_hidden_proto (cairo_surface_copy_page);
slim_hidden_proto (cairo_surface_show_page);
slim_hidden_proto (cairo_surface_status);
+slim_hidden_proto (cairo_toy_font_face_create);
slim_hidden_proto (cairo_version_string);
#if CAIRO_HAS_PNG_FUNCTIONS
diff --git a/test/.gitignore b/test/.gitignore
index 4a72553..1edaff3 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -197,6 +197,7 @@ text-pattern
text-rotate
text-transform
text-zero-len
+toy-font-face
transforms
translate-show-surface
trap-clip
diff --git a/test/Makefile.am b/test/Makefile.am
index f9ab75d..5af7c08 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -158,6 +158,7 @@ text-pattern$(EXEEXT) \
text-rotate$(EXEEXT) \
text-transform$(EXEEXT) \
text-zero-len$(EXEEXT) \
+toy-font-face$(EXEEXT) \
transforms$(EXEEXT) \
translate-show-surface$(EXEEXT) \
trap-clip$(EXEEXT) \
@@ -715,6 +716,7 @@ REFERENCE_IMAGES = \
user-font-pdf-ref.png \
user-font-svg-ref.png \
user-font-proxy-ref.png \
+ user-font-proxy-pdf-ref.png \
user-font-proxy-ps-ref.png \
user-font-proxy-svg-ref.png \
unbounded-operator-quartz-ref.png \
@@ -764,6 +766,7 @@ png \
ps-features \
svg-clip \
svg-surface \
+toy-font-face \
user-data
# A hook that summarises the failures
diff --git a/test/toy-font-face.c b/test/toy-font-face.c
new file mode 100644
index 0000000..262f7ce
--- /dev/null
+++ b/test/toy-font-face.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright © 2005,2008 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth at cworth.org>
+ * Behdad Esfahbod <behdad at behdad.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <cairo.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_FCFINI
+#include <fontconfig/fontconfig.h>
+#endif
+
+int
+main (void)
+{
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ cairo_font_face_t *font_face;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 0, 0);
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+
+ font_face = cairo_font_face_reference (cairo_get_font_face (cr));
+ assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY);
+ assert (cairo_toy_font_face_get_family (font_face) != NULL);
+ assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_NORMAL);
+ assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_NORMAL);
+ assert (cairo_font_face_status(font_face) == CAIRO_STATUS_SUCCESS);
+ cairo_font_face_destroy (font_face);
+
+ cairo_select_font_face (cr,
+ "bizarre",
+ CAIRO_FONT_SLANT_OBLIQUE,
+ CAIRO_FONT_WEIGHT_BOLD);
+ font_face = cairo_font_face_reference (cairo_get_font_face (cr));
+ assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY);
+ assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), "bizarre"));
+ assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_OBLIQUE);
+ assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_BOLD);
+ assert (cairo_font_face_status(font_face) == CAIRO_STATUS_SUCCESS);
+ cairo_font_face_destroy (font_face);
+
+ font_face = cairo_toy_font_face_create ("bozarre",
+ CAIRO_FONT_SLANT_OBLIQUE,
+ CAIRO_FONT_WEIGHT_BOLD);
+ assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY);
+ assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), "bozarre"));
+ assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_OBLIQUE);
+ assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_BOLD);
+ assert (cairo_font_face_status(font_face) == CAIRO_STATUS_SUCCESS);
+ cairo_font_face_destroy (font_face);
+
+ font_face = cairo_toy_font_face_create (NULL,
+ CAIRO_FONT_SLANT_OBLIQUE,
+ CAIRO_FONT_WEIGHT_BOLD);
+ assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY);
+ assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), ""));
+ assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_NORMAL);
+ assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_NORMAL);
+ assert (cairo_font_face_status(font_face) == CAIRO_STATUS_NULL_POINTER);
+ cairo_font_face_destroy (font_face);
+
+ font_face = cairo_toy_font_face_create ("\xff",
+ CAIRO_FONT_SLANT_OBLIQUE,
+ CAIRO_FONT_WEIGHT_BOLD);
+ assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY);
+ assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), ""));
+ assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_NORMAL);
+ assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_NORMAL);
+ assert (cairo_font_face_status(font_face) == CAIRO_STATUS_INVALID_STRING);
+ cairo_font_face_destroy (font_face);
+
+ font_face = cairo_toy_font_face_create ("sans",
+ -1,
+ CAIRO_FONT_WEIGHT_BOLD);
+ assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY);
+ assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), ""));
+ assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_NORMAL);
+ assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_NORMAL);
+ assert (cairo_font_face_status(font_face) == CAIRO_STATUS_INVALID_SLANT);
+ cairo_font_face_destroy (font_face);
+
+ font_face = cairo_toy_font_face_create ("sans",
+ CAIRO_FONT_SLANT_OBLIQUE,
+ -1);
+ assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY);
+ assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), ""));
+ assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_NORMAL);
+ assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_NORMAL);
+ assert (cairo_font_face_status(font_face) == CAIRO_STATUS_INVALID_WEIGHT);
+ cairo_font_face_destroy (font_face);
+
+ cairo_destroy (cr);
+
+ cairo_debug_reset_static_data ();
+#if HAVE_FCFINI
+ FcFini ();
+#endif
+
+ return 0;
+}
diff --git a/test/user-font-proxy-pdf-ref.png b/test/user-font-proxy-pdf-ref.png
new file mode 100644
index 0000000..0eda0f4
Binary files /dev/null and b/test/user-font-proxy-pdf-ref.png differ
diff --git a/test/user-font-proxy-ps-ref.png b/test/user-font-proxy-ps-ref.png
index 78bee6c..4305411 100644
Binary files a/test/user-font-proxy-ps-ref.png and b/test/user-font-proxy-ps-ref.png differ
diff --git a/test/user-font-proxy.c b/test/user-font-proxy.c
index f54139c..c7b29ab 100644
--- a/test/user-font-proxy.c
+++ b/test/user-font-proxy.c
@@ -51,42 +51,43 @@ cairo_test_t test = {
draw
};
-static cairo_user_data_key_t fallback_scaled_font_key;
+static cairo_user_data_key_t fallback_font_face_key;
static cairo_status_t
test_scaled_font_init (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *extents)
{
- cairo_t *cr;
- cairo_surface_t *surface;
- cairo_matrix_t ctm;
+ cairo_font_face_t *font_face;
+ cairo_matrix_t font_matrix, ctm;
cairo_font_options_t *font_options;
cairo_scaled_font_t *fallback_scaled_font;
- /* painful way to get default font face used by toy api */
- surface = cairo_image_surface_create (CAIRO_FORMAT_A8, 0, 0);
- cr = cairo_create (surface);
- cairo_surface_destroy (surface);
+ font_face = cairo_toy_font_face_create ("",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
- cairo_set_font_size (cr, 1.);
+ cairo_matrix_init_identity (&font_matrix);
cairo_scaled_font_get_scale_matrix (scaled_font, &ctm);
- cairo_set_matrix (cr, &ctm);
font_options = cairo_font_options_create ();
cairo_scaled_font_get_font_options (scaled_font, font_options);
- cairo_set_font_options (cr, font_options);
- cairo_font_options_destroy (font_options);
- fallback_scaled_font = cairo_scaled_font_reference (cairo_get_scaled_font (cr)),
- cairo_scaled_font_set_user_data (scaled_font,
- &fallback_scaled_font_key,
- fallback_scaled_font,
- cairo_scaled_font_destroy);
+ fallback_scaled_font = cairo_scaled_font_create (font_face,
+ &font_matrix,
+ &ctm,
+ font_options);
- cairo_destroy (cr);
+ cairo_font_options_destroy (font_options);
cairo_scaled_font_extents (fallback_scaled_font, extents);
+ cairo_scaled_font_destroy (fallback_scaled_font);
+
+ cairo_scaled_font_set_user_data (scaled_font,
+ &fallback_font_face_key,
+ font_face,
+ cairo_font_face_destroy);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -101,9 +102,9 @@ test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font,
/* XXX only works for ASCII. need ucs4_to_utf8 :( */
text[0] = glyph;
- cairo_set_scaled_font (cr,
- cairo_scaled_font_get_user_data (scaled_font,
- &fallback_scaled_font_key));
+ cairo_set_font_face (cr,
+ cairo_scaled_font_get_user_data (scaled_font,
+ &fallback_font_face_key));
cairo_show_text (cr, text);
cairo_text_extents (cr, text, extents);
commit bca9a21e98c870cdb4695c9155517377757beaea
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Wed Aug 6 20:40:23 2008 -0400
[docs] Update private header list
diff --git a/doc/public/Headers.mk b/doc/public/Headers.mk
index d04e1a9..7b9edff 100644
--- a/doc/public/Headers.mk
+++ b/doc/public/Headers.mk
@@ -48,4 +48,5 @@ PRIVATE_TEST_HFILES = \
cairo-xlib-private.h \
cairo-xlib-surface-private.h \
cairo-xlib-xrender-private.h \
+ cairo-features-win32.h \
cairoint.h
diff --git a/doc/public/Makefile.am b/doc/public/Makefile.am
index 0a570ad..952ded3 100644
--- a/doc/public/Makefile.am
+++ b/doc/public/Makefile.am
@@ -39,6 +39,7 @@ Headers.mk:
-name '*-test.h' | \
sed 's at .*/@ @; s@$$@ \\@' | \
LANG=C sort; \
+ echo ' cairo-features-win32.h \'; \
echo ' cairoint.h' ) > $@.tmp
mv $@.tmp $@
commit 4bb7388b65ea56287f877f8241caa7a189c0c519
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Wed Aug 6 20:38:29 2008 -0400
Remove unnecessary checks for CAIRO_STATUS_INVALID_STRING
We check that all input text is valid UTF-8. Not sure why the code
was being lenient to invalid strings.
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index f58bd7a..22c5dc9 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -2868,7 +2868,7 @@ _cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t *surface,
if (utf8 && *utf8) {
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
- if (status && status != CAIRO_STATUS_INVALID_STRING)
+ if (status)
return status;
}
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 6cfccac..94d1cea 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -944,8 +944,8 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset
utf16_len = 0;
if (utf8 && *utf8) {
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
- if (status && status != CAIRO_STATUS_INVALID_STRING)
- return status; // FIXME
+ if (status)
+ return status; /* FIXME */
}
if (utf16_len == 1) {
More information about the cairo-commit
mailing list