[cairo-commit] 4 commits - src/cairo-quartz-font.c src/cairo-unicode.c src/cairoint.h test/Makefile.sources test/reference test/smp-glyph.c

Andrea Canciani ranma42 at kemper.freedesktop.org
Tue Apr 25 16:06:57 UTC 2017


 dev/null                                       |binary
 src/cairo-quartz-font.c                        |   25 +++++------
 src/cairo-unicode.c                            |   39 ++++++++++++++---
 src/cairoint.h                                 |    4 +
 test/Makefile.sources                          |    1 
 test/reference/smp-glyph.ref.png               |binary
 test/reference/smp-glyph.script.ref.png        |binary
 test/reference/text-glyph-range.quartz.ref.png |binary
 test/smp-glyph.c                               |   56 +++++++++++++++++++++++++
 9 files changed, 107 insertions(+), 18 deletions(-)

New commits:
commit a3cc46d2ccba44a538d05f0c5870b1a82f046350
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Sun Mar 19 21:48:11 2017 +0100

    quartz-font: Fix text-glyph-range
    
    The index 0 is a legitimate index used for character codes that do not
    correspond to any glyph in the font.  Instead, the API reserves 0xFFFF
    (kCGFontIndexInvalid) as the invalid index and defines 0xFFFE
    (kCGFontIndexMax = kCGGlyphMax) as the maximum legal index.
    
    Fixes text-glyph-range.

diff --git a/src/cairo-quartz-font.c b/src/cairo-quartz-font.c
index 34ae87e7..47221421 100644
--- a/src/cairo-quartz-font.c
+++ b/src/cairo-quartz-font.c
@@ -106,6 +106,10 @@ static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL;
 static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
 static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
 
+/* Defined in 10.11 */
+#define CGGLYPH_MAX ((CGGlyph) 0xFFFE) /* kCGFontIndexMax */
+#define CGGLYPH_INVALID ((CGGlyph) 0xFFFF) /* kCGFontIndexInvalid */
+
 static void
 quartz_font_ensure_symbols(void)
 {
@@ -403,14 +407,10 @@ _cairo_quartz_scaled_font_fini(void *abstract_font)
 {
 }
 
-#define INVALID_GLYPH 0x00
-
 static inline CGGlyph
 _cairo_quartz_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) {
     unsigned long index = _cairo_scaled_glyph_index (scaled_glyph);
-    if (index > 0xffff)
-	return INVALID_GLYPH;
-    return (CGGlyph) index;
+    return index <= CGGLYPH_MAX ? index : CGGLYPH_INVALID;
 }
 
 static cairo_int_status_t
@@ -427,7 +427,7 @@ _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font,
     double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont);
     double xmin, ymin, xmax, ymax;
 
-    if (glyph == INVALID_GLYPH)
+    if (unlikely (glyph == CGGLYPH_INVALID))
 	goto FAIL;
 
     if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
@@ -561,7 +561,7 @@ _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
     CGPathRef glyphPath;
     cairo_path_fixed_t *path;
 
-    if (glyph == INVALID_GLYPH) {
+    if (unlikely (glyph == CGGLYPH_INVALID)) {
 	_cairo_scaled_glyph_set_path (scaled_glyph, &font->base, _cairo_path_fixed_create());
 	return CAIRO_STATUS_SUCCESS;
     }
@@ -627,7 +627,7 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
      * Maybe we should draw a better missing-glyph slug or something,
      * but this is ok for now.
      */
-    if (glyph == INVALID_GLYPH) {
+    if (unlikely (glyph == CGGLYPH_INVALID)) {
 	surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2);
 	status = cairo_surface_status ((cairo_surface_t *) surface);
 	if (status)
diff --git a/test/reference/text-glyph-range.quartz.ref.png b/test/reference/text-glyph-range.quartz.ref.png
new file mode 100644
index 00000000..31d2a941
Binary files /dev/null and b/test/reference/text-glyph-range.quartz.ref.png differ
diff --git a/test/reference/text-glyph-range.quartz.xfail.png b/test/reference/text-glyph-range.quartz.xfail.png
deleted file mode 100644
index 9dcc7562..00000000
Binary files a/test/reference/text-glyph-range.quartz.xfail.png and /dev/null differ
commit fcb0a8ef36c9a84f586d38bd409d6a0e881890a7
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Sat Mar 18 10:20:07 2017 +0100

    quartz-font: Correct handling of SMP Unicode characters
    
    Truncating the UCS4 representation to 16 bits only works for the Basic
    Multilingual Plane, the other characters must be translated to a
    surrogate pair.
    
    Fixes smp-glyph.
    
    Reported-by: Clerk Ma <clerkma at gmail.com>

diff --git a/src/cairo-quartz-font.c b/src/cairo-quartz-font.c
index 897b2d01..34ae87e7 100644
--- a/src/cairo-quartz-font.c
+++ b/src/cairo-quartz-font.c
@@ -766,12 +766,13 @@ _cairo_quartz_ucs4_to_index (void *abstract_font,
 {
     cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;
     cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(font);
-    UniChar u = (UniChar) ucs4;
-    CGGlyph glyph;
+    CGGlyph glyph[2];
+    UniChar utf16[2];
 
-    CGFontGetGlyphsForUnicharsPtr (ffont->cgFont, &u, &glyph, 1);
+    int len = _cairo_ucs4_to_utf16 (ucs4, utf16);
+    CGFontGetGlyphsForUnicharsPtr (ffont->cgFont, utf16, glyph, len);
 
-    return glyph;
+    return glyph[0];
 }
 
 static cairo_int_status_t
commit 5584bf755c98703653eef06670abaeb4873f9ee5
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Sat Mar 18 08:55:11 2017 +0100

    unicode: Extract the UCS4 to UTF-16 conversion to a separate function
    
    Reuse the function for the UTF-8 to UTF-16 conversion, but also make
    it available for internal use by cairo.

diff --git a/src/cairo-unicode.c b/src/cairo-unicode.c
index 88de3951..7933d12a 100644
--- a/src/cairo-unicode.c
+++ b/src/cairo-unicode.c
@@ -342,6 +342,38 @@ _cairo_ucs4_to_utf8 (uint32_t  unicode,
     return bytes;
 }
 
+/**
+ * _cairo_ucs4_to_utf16:
+ * @unicode: a UCS-4 character
+ * @utf16: buffer to write utf16 string into. Must have at least 2
+ * elements. Or %NULL.
+ *
+ * This space left intentionally blank.
+ *
+ * Return value: Number of elements in the utf16 string or 0 if an
+ * invalid unicode character
+ **/
+int
+_cairo_ucs4_to_utf16 (uint32_t  unicode,
+		      uint16_t *utf16)
+{
+    int len;
+
+    if (unicode < 0x10000) {
+	if (utf16)
+	    utf16[0] = unicode;
+	return 1;
+    } else if (unicode < 0x110000) {
+	if (utf16) {
+	    utf16[0] = (unicode - 0x10000) / 0x400 + 0xd800;
+	    utf16[1] = (unicode - 0x10000) % 0x400 + 0xdc00;
+	}
+	return 2;
+    } else {
+	return 0;
+    }
+}
+
 #if CAIRO_HAS_UTF8_TO_UTF16
 /**
  * _cairo_utf8_to_utf16:
@@ -401,12 +433,7 @@ _cairo_utf8_to_utf16 (const char *str,
     for (i = 0; i < n16;) {
 	uint32_t wc = _utf8_get_char (in);
 
-	if (wc < 0x10000) {
-	    str16[i++] = wc;
-	} else {
-	    str16[i++] = (wc - 0x10000) / 0x400 + 0xd800;
-	    str16[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
-	}
+	i += _cairo_ucs4_to_utf16 (wc, str16 + i);
 
 	in = UTF8_NEXT_CHAR (in);
     }
diff --git a/src/cairoint.h b/src/cairoint.h
index 493d4610..1ae045c9 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1872,6 +1872,10 @@ cairo_private int
 _cairo_ucs4_to_utf8 (uint32_t    unicode,
 		     char       *utf8);
 
+cairo_private int
+_cairo_ucs4_to_utf16 (uint32_t    unicode,
+		      uint16_t   *utf16);
+
 #if CAIRO_HAS_WIN32_FONT || CAIRO_HAS_QUARTZ_FONT || CAIRO_HAS_PDF_OPERATORS
 # define CAIRO_HAS_UTF8_TO_UTF16 1
 #endif
commit cb9f6273780bb2ffc710d2efdd4224d9096972cb
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Sun Mar 19 10:37:36 2017 +0100

    test: Add a test for characters in the SMP
    
    Unicode characters in the Supplementary Multilingual Plane are encoded
    as surrogate pairs in UTF-16. This test tries to verify that backends
    do not perform UCS4 to UTF-16 conversion by truncation.

diff --git a/test/Makefile.sources b/test/Makefile.sources
index 5ead2316..1ae62464 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -323,6 +323,7 @@ test_sources = \
 	smask-paint.c					\
 	smask-stroke.c					\
 	smask-text.c					\
+	smp-glyph.c					\
 	solid-pattern-cache-stress.c			\
 	source-clip.c					\
 	source-clip-scale.c				\
diff --git a/test/reference/smp-glyph.ref.png b/test/reference/smp-glyph.ref.png
new file mode 100644
index 00000000..260332d3
Binary files /dev/null and b/test/reference/smp-glyph.ref.png differ
diff --git a/test/reference/smp-glyph.script.ref.png b/test/reference/smp-glyph.script.ref.png
new file mode 100644
index 00000000..d15848ce
Binary files /dev/null and b/test/reference/smp-glyph.script.ref.png differ
diff --git a/test/smp-glyph.c b/test/smp-glyph.c
new file mode 100644
index 00000000..486c43eb
--- /dev/null
+++ b/test/smp-glyph.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2017 Andrea Canciani
+ *
+ * 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
+ * Andrea Canciani not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Andrea Canciani makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * ANDREA CANCIANI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL ANDREA CANCIANI 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: Andrea Canciani <ranma42 at gmail.com>
+ */
+
+#include "cairo-test.h"
+
+#define TEXT_SIZE 42
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+    cairo_paint (cr);
+
+    cairo_set_source_rgb (cr, 0, 0, 0); /* black */
+
+    cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans",
+			    CAIRO_FONT_SLANT_NORMAL,
+			    CAIRO_FONT_WEIGHT_NORMAL);
+
+    cairo_set_font_size (cr, TEXT_SIZE);
+    cairo_translate (cr, 0, TEXT_SIZE);
+
+    /* U+1F030, DOMINO TILE HORIZONTAL BACK */
+    cairo_show_text (cr, "\xf0\x9f\x80\xb0");
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (smp_glyph,
+	    "Test glyphs for symbols in the Supplementary Multilingual Plane",
+	    "text, glyphs", /* keywords */
+	    NULL, /* requirements */
+	    64, 64,
+	    NULL, draw)


More information about the cairo-commit mailing list