1 | /* Pango |
2 | * pango-impl-utils.h: Macros for get_type() functions |
3 | * Inspired by Jody Goldberg's gsf-impl-utils.h |
4 | * |
5 | * Copyright (C) 2003 Red Hat Software |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Library General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Library General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Library General Public |
18 | * License along with this library; if not, write to the |
19 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
20 | * Boston, MA 02111-1307, USA. |
21 | */ |
22 | |
23 | #ifndef __PANGO_IMPL_UTILS_H__ |
24 | #define __PANGO_IMPL_UTILS_H__ |
25 | |
26 | #include <glib.h> |
27 | #include <glib-object.h> |
28 | #include <pango/pango.h> |
29 | |
30 | G_BEGIN_DECLS |
31 | |
32 | |
33 | /* String interning for static strings */ |
34 | #define I_(string) g_intern_static_string (string) |
35 | |
36 | |
37 | /* Some functions for handling PANGO_ATTR_SHAPE */ |
38 | void _pango_shape_shape (const char *text, |
39 | unsigned int n_chars, |
40 | PangoRectangle *shape_ink, |
41 | PangoRectangle *shape_logical, |
42 | PangoGlyphString *glyphs); |
43 | |
44 | void _pango_shape_get_extents (gint n_chars, |
45 | PangoRectangle *shape_ink, |
46 | PangoRectangle *shape_logical, |
47 | PangoRectangle *ink_rect, |
48 | PangoRectangle *logical_rect); |
49 | |
50 | |
51 | /* We define these functions static here because we don't want to add public API |
52 | * for them (if anything, it belongs to glib, but glib found it trivial enough |
53 | * not to add API for). At some point metrics calculations will be |
54 | * centralized and this mess can be minimized. Or so I hope. |
55 | */ |
56 | |
57 | static inline G_GNUC_UNUSED int |
58 | pango_unichar_width (gunichar c) |
59 | { |
60 | return G_UNLIKELY (g_unichar_iszerowidth (c)) ? 0 : |
61 | G_UNLIKELY (g_unichar_iswide (c)) ? 2 : 1; |
62 | } |
63 | |
64 | static G_GNUC_UNUSED glong |
65 | pango_utf8_strwidth (const gchar *p) |
66 | { |
67 | glong len = 0; |
68 | g_return_val_if_fail (p != NULL, 0); |
69 | |
70 | while (*p) |
71 | { |
72 | len += pango_unichar_width (c: g_utf8_get_char (p)); |
73 | p = g_utf8_next_char (p); |
74 | } |
75 | |
76 | return len; |
77 | } |
78 | |
79 | /* Glib's g_utf8_strlen() is broken and stops at embedded NUL's. |
80 | * Wrap it here. */ |
81 | static G_GNUC_UNUSED glong |
82 | pango_utf8_strlen (const gchar *p, gssize max) |
83 | { |
84 | glong len = 0; |
85 | const gchar *start = p; |
86 | g_return_val_if_fail (p != NULL || max == 0, 0); |
87 | |
88 | if (max <= 0) |
89 | return g_utf8_strlen (p, max); |
90 | |
91 | p = g_utf8_next_char (p); |
92 | while (p - start < max) |
93 | { |
94 | ++len; |
95 | p = g_utf8_next_char (p); |
96 | } |
97 | |
98 | /* only do the last len increment if we got a complete |
99 | * char (don't count partial chars) |
100 | */ |
101 | if (p - start <= max) |
102 | ++len; |
103 | |
104 | return len; |
105 | } |
106 | |
107 | |
108 | /* To be made public at some point */ |
109 | |
110 | static G_GNUC_UNUSED void |
111 | pango_glyph_string_reverse_range (PangoGlyphString *glyphs, |
112 | int start, int end) |
113 | { |
114 | int i, j; |
115 | |
116 | for (i = start, j = end - 1; i < j; i++, j--) |
117 | { |
118 | PangoGlyphInfo glyph_info; |
119 | gint log_cluster; |
120 | |
121 | glyph_info = glyphs->glyphs[i]; |
122 | glyphs->glyphs[i] = glyphs->glyphs[j]; |
123 | glyphs->glyphs[j] = glyph_info; |
124 | |
125 | log_cluster = glyphs->log_clusters[i]; |
126 | glyphs->log_clusters[i] = glyphs->log_clusters[j]; |
127 | glyphs->log_clusters[j] = log_cluster; |
128 | } |
129 | } |
130 | |
131 | static inline gboolean |
132 | pango_is_default_ignorable (gunichar ch) |
133 | { |
134 | int plane = ch >> 16; |
135 | |
136 | if (G_LIKELY (plane == 0)) |
137 | { |
138 | int page = ch >> 8; |
139 | switch (page) |
140 | { |
141 | case 0x00: return ch == 0x00ad; |
142 | case 0x03: return ch == 0x034f; |
143 | case 0x06: return ch == 0x061c; |
144 | case 0x17: return (0x17b4 <= ch && ch <= 0x17b5); |
145 | case 0x18: return (0x180b <= ch && ch <= 0x180e); |
146 | case 0x20: return (0x200b <= ch && ch <= 0x200f) || |
147 | (0x202a <= ch && ch <= 0x202e) || |
148 | (0x2060 <= ch && ch <= 0x206f); |
149 | case 0xfe: return (0xfe00 <= ch && ch <= 0xfe0f) || ch == 0xfeff; |
150 | case 0xff: return (0xfff0 <= ch && ch <= 0xfff8); |
151 | default: return FALSE; |
152 | } |
153 | } |
154 | else |
155 | { |
156 | /* Other planes */ |
157 | switch (plane) |
158 | { |
159 | case 0x01: return (0x1d173 <= ch && ch <= 0x1d17a); |
160 | case 0x0e: return (0xe0000 <= ch && ch <= 0xe0fff); |
161 | default: return FALSE; |
162 | } |
163 | } |
164 | } |
165 | |
166 | /* These are the default ignorables that we render as hexboxes |
167 | * with nicks if PANGO_SHOW_IGNORABLES is used. |
168 | * |
169 | * The cairo hexbox drawing code assumes that these nicks are |
170 | * 1-6 ASCII chars |
171 | */ |
172 | static struct { |
173 | gunichar ch; |
174 | const char *nick; |
175 | } ignorables[] = { |
176 | { 0x00ad, "SHY" }, /* SOFT HYPHEN */ |
177 | { 0x034f, "CGJ" }, /* COMBINING GRAPHEME JOINER */ |
178 | { 0x061c, "ALM" }, /* ARABIC LETTER MARK */ |
179 | { 0x200b, "ZWS" }, /* ZERO WIDTH SPACE */ |
180 | { 0x200c, "ZWNJ" }, /* ZERO WIDTH NON-JOINER */ |
181 | { 0x200d, "ZWJ" }, /* ZERO WIDTH JOINER */ |
182 | { 0x200e, "LRM" }, /* LEFT-TO-RIGHT MARK */ |
183 | { 0x200f, "RLM" }, /* RIGHT-TO-LEFT MARK */ |
184 | { 0x2028, "LS" }, /* LINE SEPARATOR */ |
185 | { 0x2029, "PS" }, /* PARAGRAPH SEPARATOR */ |
186 | { 0x202a, "LRE" }, /* LEFT-TO-RIGHT EMBEDDING */ |
187 | { 0x202b, "RLE" }, /* RIGHT-TO-LEFT EMBEDDING */ |
188 | { 0x202c, "PDF" }, /* POP DIRECTIONAL FORMATTING */ |
189 | { 0x202d, "LRO" }, /* LEFT-TO-RIGHT OVERRIDE */ |
190 | { 0x202e, "RLO" }, /* RIGHT-TO-LEFT OVERRIDE */ |
191 | { 0x2060, "WJ" }, /* WORD JOINER */ |
192 | { 0x2061, "FA" }, /* FUNCTION APPLICATION */ |
193 | { 0x2062, "IT" }, /* INVISIBLE TIMES */ |
194 | { 0x2063, "IS" }, /* INVISIBLE SEPARATOR */ |
195 | { 0x2066, "LRI" }, /* LEFT-TO-RIGHT ISOLATE */ |
196 | { 0x2067, "RLI" }, /* RIGHT-TO-LEFT ISOLATE */ |
197 | { 0x2068, "FSI" }, /* FIRST STRONG ISOLATE */ |
198 | { 0x2069, "PDI" }, /* POP DIRECTIONAL ISOLATE */ |
199 | { 0xfeff, "ZWNBS" }, /* ZERO WIDTH NO-BREAK SPACE */ |
200 | }; |
201 | |
202 | static inline G_GNUC_UNUSED const char * |
203 | pango_get_ignorable (gunichar ch) |
204 | { |
205 | int i; |
206 | |
207 | for (i = 0; i < G_N_ELEMENTS (ignorables); i++) |
208 | { |
209 | if (ch < ignorables[i].ch) |
210 | return NULL; |
211 | |
212 | if (ch == ignorables[i].ch) |
213 | return ignorables[i].nick; |
214 | } |
215 | return NULL; |
216 | } |
217 | |
218 | static inline G_GNUC_UNUSED const char * |
219 | pango_get_ignorable_size (gunichar ch, |
220 | int *rows, |
221 | int *cols) |
222 | { |
223 | const char *nick; |
224 | int len; |
225 | |
226 | nick = pango_get_ignorable (ch); |
227 | if (nick) |
228 | { |
229 | len = strlen (s: nick); |
230 | if (len < 4) |
231 | { |
232 | *rows = 1; |
233 | *cols = len; |
234 | } |
235 | else if (len > 4) |
236 | { |
237 | *rows = 2; |
238 | *cols = 3; |
239 | } |
240 | else |
241 | { |
242 | *rows = 2; |
243 | *cols = 2; |
244 | } |
245 | } |
246 | |
247 | return nick; |
248 | } |
249 | |
250 | /* Backward compatibility shim, to avoid bumping up the minimum |
251 | * required version of GLib; most of our uses of g_memdup() are |
252 | * safe, and those that aren't have been fixed |
253 | */ |
254 | #if !GLIB_CHECK_VERSION (2, 67, 3) |
255 | # define g_memdup2(mem,size) g_memdup((mem),(size)) |
256 | #endif |
257 | |
258 | G_END_DECLS |
259 | |
260 | #endif /* __PANGO_IMPL_UTILS_H__ */ |
261 | |