f689fe080be1ee1ab0e35696e2d6c0e696d42608
[framework/graphics/cairo.git] / test / show-glyphs-many.c
1 /*
2  * Copyright © 2006 Red Hat, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software
5  * and its documentation for any purpose is hereby granted without
6  * fee, provided that the above copyright notice appear in all copies
7  * and that both that copyright notice and this permission notice
8  * appear in supporting documentation, and that the name of
9  * Red Hat, Inc. not be used in advertising or publicity pertaining to
10  * distribution of the software without specific, written prior
11  * permission. Red Hat, Inc. makes no representations about the
12  * suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
18  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
21  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author: Carl D. Worth <cworth@cworth.org>
24  */
25
26 #include "cairo-test.h"
27
28 #include <string.h>
29
30 /* Bug history
31  *
32  * 2006-01-07  Jon Hellan  <hellan@acm.org>
33  *
34  *   Jon opened the following bug report:
35  *
36  *      _XError from XRenderCompositeText8
37  *      https://bugs.freedesktop.org/show_bug.cgi?id=5528
38  *
39  * 2006-03-02  Carl Worth  <cworth@cworth.org>
40  *
41  *   I wrote this test case to demonstrate the bug.
42  *
43  *   Approach:
44  *
45  *      Draw 65535 glyphs white-on-white all on top of each other.
46  *
47  *   Rationale:
48  *
49  *      The number 65535 comes from the original bug report.
50  *
51  *      I would use cairo_show_text with a long string of 'x's say,
52  *      but then the surface would need to be enormous to contain
53  *      them. A smaller surface could be used, but I fear that at some
54  *      point the off-surface glyph drawing would be optimized away
55  *      and not exercise the bug.
56  *
57  *      So, to keep the surface size under control, I use
58  *      cairo_show_glyphs which allows me to place the glyphs all on
59  *      top of each other. But, since cairo doesn't provide any
60  *      character-to-glyphs mapping, I can't get a reliable glyph
61  *      index (for character 'x' for example). So I just "guess" a
62  *      glyph index and use white-on-white drawing to ignore the
63  *      result. (I don't care what's drawn---I just want to ensure
64  *      that things don't crash.)
65  *
66  *  Status: I replicated bug. The largest value of NUM_GLYPHS for
67  *      which I saw success is 21842.
68  *
69  * 2008-30-08 Chris Wilson <chris@chris-wilson.co.uk>
70  *   This is also a valid test case for:
71  *
72  *     Bug 5913 crash on overlong string
73  *     https://bugs.freedesktop.org/show_bug.cgi?id=5913
74  *
75  *  which is still causing a crash in the Xlib backend - presumably, just
76  *  a miscalculation of the length of the available request.
77  */
78
79 #define TEXT_SIZE 12
80 #define NUM_GLYPHS 65535
81
82 static cairo_test_status_t
83 get_glyph (const cairo_test_context_t *ctx,
84            cairo_scaled_font_t *scaled_font,
85            const char *utf8,
86            cairo_glyph_t *glyph)
87 {
88     cairo_glyph_t *text_to_glyphs;
89     cairo_status_t status;
90     int i;
91
92     text_to_glyphs = glyph;
93     i = 1;
94     status = cairo_scaled_font_text_to_glyphs (scaled_font,
95                                                0, 0,
96                                                utf8, -1,
97                                                &text_to_glyphs, &i,
98                                                NULL, NULL,
99                                                0);
100     if (status != CAIRO_STATUS_SUCCESS)
101         return cairo_test_status_from_status (ctx, status);
102
103     if (text_to_glyphs != glyph) {
104         *glyph = text_to_glyphs[0];
105         cairo_glyph_free (text_to_glyphs);
106     }
107
108     return CAIRO_TEST_SUCCESS;
109 }
110
111 static cairo_test_status_t
112 draw (cairo_t *cr, int width, int height)
113 {
114     const cairo_test_context_t *ctx = cairo_test_get_context (cr);
115     cairo_glyph_t *glyphs = xmalloc (NUM_GLYPHS * sizeof (cairo_glyph_t));
116     cairo_scaled_font_t *scaled_font;
117     const char *characters[] = { /* try to exercise different widths of index */
118         "m", /* Latin letter m, index=0x50 */
119         "μ", /* Greek letter mu, index=0x349 */
120         NULL,
121     }, **utf8;
122     int i, j;
123     cairo_status_t status;
124
125     /* Paint white background. */
126     cairo_set_source_rgb (cr, 1, 1, 1);
127     cairo_paint (cr);
128
129     cairo_select_font_face (cr, "Sans",
130                             CAIRO_FONT_SLANT_NORMAL,
131                             CAIRO_FONT_WEIGHT_NORMAL);
132     cairo_set_font_size (cr, TEXT_SIZE);
133     scaled_font = cairo_get_scaled_font (cr);
134
135     for (utf8 = characters; *utf8 != NULL; utf8++) {
136         status = get_glyph (ctx, scaled_font, *utf8, &glyphs[0]);
137         if (status)
138             goto BAIL;
139
140         if (glyphs[0].index) {
141             glyphs[0].x = 1.0;
142             glyphs[0].y = height - 1;
143             for (i=1; i < NUM_GLYPHS; i++)
144                 glyphs[i] = glyphs[0];
145
146             cairo_show_glyphs (cr, glyphs, NUM_GLYPHS);
147         }
148     }
149
150     /* we can pack ~21k 1-byte glyphs into a single XRenderCompositeGlyphs8 */
151     status = get_glyph (ctx, scaled_font, "m", &glyphs[0]);
152     if (status)
153         goto BAIL;
154     for (i=1; i < 21500; i++)
155         glyphs[i] = glyphs[0];
156     /* so check expanding the current 1-byte request for 2-byte glyphs */
157     status = get_glyph (ctx, scaled_font, "μ", &glyphs[i]);
158     if (status)
159         goto BAIL;
160     for (j=i+1; j < NUM_GLYPHS; j++)
161         glyphs[j] = glyphs[i];
162
163     cairo_show_glyphs (cr, glyphs, NUM_GLYPHS);
164
165   BAIL:
166     free(glyphs);
167
168     return status;
169 }
170
171 CAIRO_TEST (show_glyphs_many,
172             "Test that cairo_show_glyphs works when handed 'many' glyphs",
173             "text, stress", /* keywords */
174             NULL, /* requirements */
175             9, 11,
176             NULL, draw)