comparison src/redisplay-xlike-inc.c @ 4881:a4322ac49e37

break out common separate-into-runs routines into redisplay-xlike-inc.c -------------------- ChangeLog entries follow: -------------------- src/ChangeLog addition: 2010-01-18 Ben Wing <ben@xemacs.org> * redisplay-xlike-inc.c: * redisplay-xlike-inc.c (separate_textual_runs_nomule): * redisplay-xlike-inc.c (separate_textual_runs_xft_nomule): * redisplay-xlike-inc.c (separate_textual_runs_xft_mule): * redisplay-xlike-inc.c (separate_textual_runs_mule): Break separate_textual_runs_* functions from redisplay-x.c. (Code in redisplay-gtk.c should have been identical but was bit-rotted.) * redisplay-gtk.c: * redisplay-x.c: Delete code, replace with include statement. * depend: Regenerate.
author Ben Wing <ben@xemacs.org>
date Mon, 18 Jan 2010 06:21:05 -0600
parents
children eab9498ecc0e
comparison
equal deleted inserted replaced
4880:ae81a2c00f4f 4881:a4322ac49e37
1 /* Common code between X and GTK.
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1994 Lucid, Inc.
4 Copyright (C) 1995 Sun Microsystems, Inc.
5 Copyright (C) 2002, 2003, 2005 Ben Wing.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24 /* Synched up with: Not in FSF. */
25
26 /* Note: We do not use the Xmb*() functions and XFontSets, nor the
27 Motif XFontLists and CompoundStrings.
28 Those functions are generally losing for a number of reasons.
29 Most important, they only support one locale (e.g. you could
30 display Japanese and ASCII text, but not mixed Japanese/Chinese
31 text). You could maybe call setlocale() frequently to try to deal
32 with this, but that would generally fail because an XFontSet is
33 tied to one locale and won't have the other character sets in it.
34
35 fontconfig (the font database for Xft) has some specifier-like
36 properties, but it's not sufficient (witness the existence of
37 Pango). Pango might do the trick, but it's not a cross-platform
38 solution; it would need significant advantages to be worth the
39 effort.
40 */
41
42 struct textual_run
43 {
44 Lisp_Object charset;
45 unsigned char *ptr;
46 int len;
47 int dimension;
48 };
49
50 /* Separate out the text in STR (an array of Ichars, not a string
51 representation) of length LEN into a series of runs, stored in
52 RUN_STORAGE. RUN_STORAGE is guaranteed to hold enough space for all
53 runs that could be generated from this text. Each run points to the a
54 stretch of text given simply by the position codes TEXT_STORAGE into a
55 series of textual runs of a particular charset. Also convert the
56 characters as necessary into the format needed by XDrawImageString(),
57 XDrawImageString16(), et al. This means converting to one or two byte
58 format, possibly tweaking the high bits, and possibly running a CCL
59 program. You must pre-allocate the space used and pass it in. (This is
60 done so you can ALLOCA () the space.) (2 * len) bytes must be allocated
61 for TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
62 RUN_STORAGE, where LEN is the length of the dynarr.
63
64 bufchar might not be fixed width (in the case of UTF-8).
65
66 Returns the number of runs actually used. */
67
68 /* Notes on Xft implementation
69
70 - With Unicode, we're no longer going to have repertoires reified as
71 charsets. (Not that we ever really did, what with corporate variants,
72 and so on.) So we really should be querying the face for the desired
73 font, rather than the character for the charset, and that's what would
74 determine the separation into runs.
75 - The widechar versions of fontconfig (and therefore Xft) functions
76 seem to be just bigendian Unicode. So there's actually no need to use
77 the 8-bit versions in computing runs and runes, it would seem.
78 */
79
80 #if !defined(USE_XFT) && !defined(MULE)
81 static int
82 separate_textual_runs_nomule (unsigned char *text_storage,
83 struct textual_run *run_storage,
84 const Ichar *str, Charcount len,
85 struct face_cachel *UNUSED(cachel))
86 {
87 if (!len)
88 return 0;
89
90 run_storage[0].ptr = text_storage;
91 run_storage[0].len = len;
92 run_storage[0].dimension = 1;
93 run_storage[0].charset = Qnil;
94
95 while (len--)
96 *text_storage++ = *str++;
97 return 1;
98 }
99 #endif
100
101 #if defined(USE_XFT) && !defined(MULE)
102 /*
103 Note that in this configuration the "Croatian hack" of using an 8-bit,
104 non-Latin-1 font to get localized display without Mule simply isn't
105 available. That's by design -- Unicode does not aid or abet that kind
106 of punning.
107 This means that the cast to XftChar16 gives the correct "conversion" to
108 UCS-2.
109 #### Is there an alignment issue with text_storage?
110 */
111 static int
112 separate_textual_runs_xft_nomule (unsigned char *text_storage,
113 struct textual_run *run_storage,
114 const Ichar *str, Charcount len,
115 struct face_cachel *UNUSED(cachel))
116 {
117 int i;
118 if (!len)
119 return 0;
120
121 run_storage[0].ptr = text_storage;
122 run_storage[0].len = len;
123 run_storage[0].dimension = 2;
124 run_storage[0].charset = Qnil;
125
126 for (i = 0; i < len; i++)
127 {
128 *(XftChar16 *)text_storage = str[i];
129 text_storage += sizeof(XftChar16);
130 }
131 return 1;
132 }
133 #endif
134
135 #if defined(USE_XFT) && defined(MULE)
136 static int
137 separate_textual_runs_xft_mule (unsigned char *text_storage,
138 struct textual_run *run_storage,
139 const Ichar *str, Charcount len,
140 struct face_cachel *UNUSED(cachel))
141 {
142 Lisp_Object prev_charset = Qunbound;
143 int runs_so_far = 0, i;
144
145 run_storage[0].ptr = text_storage;
146 run_storage[0].len = len;
147 run_storage[0].dimension = 2;
148 run_storage[0].charset = Qnil;
149
150 for (i = 0; i < len; i++)
151 {
152 Ichar ch = str[i];
153 Lisp_Object charset = ichar_charset(ch);
154 int ucs = ichar_to_unicode(ch);
155
156 /* If UCS is less than zero or greater than 0xFFFF, set ucs2 to
157 REPLACMENT CHARACTER. */
158 /* That means we can't handle characters outside of the BMP for now */
159 ucs = (ucs & ~0xFFFF) ? 0xFFFD : ucs;
160
161 if (!EQ (charset, prev_charset))
162 {
163 if (runs_so_far)
164 run_storage[runs_so_far-1].len = (text_storage - run_storage[runs_so_far-1].ptr) >> 1;
165 run_storage[runs_so_far].ptr = text_storage;
166 run_storage[runs_so_far].dimension = 2;
167 run_storage[runs_so_far].charset = charset;
168 prev_charset = charset;
169 runs_so_far++;
170 }
171
172 *(XftChar16 *)text_storage = ucs;
173 text_storage += sizeof(XftChar16);
174 }
175
176 if (runs_so_far)
177 run_storage[runs_so_far-1].len = (text_storage - run_storage[runs_so_far-1].ptr) >> 1;
178 return runs_so_far;
179 }
180 #endif
181
182 #if !defined(USE_XFT) && defined(MULE)
183 /*
184 This is the most complex function of this group, due to the various
185 indexing schemes used by different fonts. For our purposes, they
186 fall into three classes. Some fonts are indexed compatibly with ISO
187 2022; those fonts just use the Mule internal representation directly
188 (typically the high bit must be reset; this is determined by the `graphic'
189 flag). Some fonts are indexed by Unicode, specifically by UCS-2. These
190 are all translated using `ichar_to_unicode'. Finally some fonts have
191 irregular indexes, and must be translated ad hoc. In XEmacs ad hoc
192 translations are accomplished with CCL programs. */
193 static int
194 separate_textual_runs_mule (unsigned char *text_storage,
195 struct textual_run *run_storage,
196 const Ichar *str, Charcount len,
197 struct face_cachel *cachel)
198 {
199 Lisp_Object prev_charset = Qunbound;
200 int runs_so_far = 0, i;
201 Ibyte charset_leading_byte = LEADING_BYTE_ASCII;
202 int dimension = 1, graphic = 0, need_ccl_conversion = 0;
203 Lisp_Object ccl_prog;
204 struct ccl_program char_converter;
205
206 int translate_to_ucs_2 = 0;
207
208 for (i = 0; i < len; i++)
209 {
210 Ichar ch = str[i];
211 Lisp_Object charset;
212 int byte1, byte2; /* BREAKUP_ICHAR dereferences the addresses
213 of its arguments as pointer to int. */
214 BREAKUP_ICHAR (ch, charset, byte1, byte2);
215
216 if (!EQ (charset, prev_charset))
217 {
218 /* At this point, dimension' and `prev_charset' refer to just-
219 completed run. `runs_so_far' and `text_storage' refer to the
220 run about to start. */
221 if (runs_so_far)
222 {
223 /* Update metadata for previous run. */
224 run_storage[runs_so_far - 1].len =
225 text_storage - run_storage[runs_so_far - 1].ptr;
226 if (2 == dimension) run_storage[runs_so_far - 1].len >>= 1;
227 }
228
229 /* Compute metadata for current run.
230 First, classify font.
231 If the font is indexed by UCS-2, set `translate_to_ucs_2'.
232 Else if the charset has a CCL program, set `need_ccl_conversion'.
233 Else if the font is indexed by an ISO 2022 "graphic register",
234 set `graphic'.
235 These flags are almost mutually exclusive, but we're sloppy
236 about resetting "shadowed" flags. So the flags must be checked
237 in the proper order in computing byte1 and byte2, below. */
238 charset_leading_byte = XCHARSET_LEADING_BYTE(charset);
239 translate_to_ucs_2 =
240 bit_vector_bit (FACE_CACHEL_FONT_FINAL_STAGE (cachel),
241 charset_leading_byte - MIN_LEADING_BYTE);
242 if (translate_to_ucs_2)
243 {
244 dimension = 2;
245 }
246 else
247 {
248 dimension = XCHARSET_DIMENSION (charset);
249
250 /* Check for CCL charset.
251 If setup_ccl_program fails, we'll get a garbaged display.
252 This should never happen, and even if it does, it should
253 be harmless (unless the X server has buggy handling of
254 characters undefined in the font). It may be marginally
255 more useful to users and debuggers than substituting a
256 fixed replacement character. */
257 ccl_prog = XCHARSET_CCL_PROGRAM (charset);
258 if ((!NILP (ccl_prog))
259 && (setup_ccl_program (&char_converter, ccl_prog) >= 0))
260 {
261 need_ccl_conversion = 1;
262 }
263 else
264 {
265 /* The charset must have an ISO 2022-compatible font index.
266 There are 2 "registers" (what such fonts use as index).
267 GL (graphic == 0) has the high bit of each octet reset,
268 GR (graphic == 1) has it set. */
269 graphic = XCHARSET_GRAPHIC (charset);
270 need_ccl_conversion = 0;
271 }
272 }
273
274 /* Initialize metadata for current run. */
275 run_storage[runs_so_far].ptr = text_storage;
276 run_storage[runs_so_far].charset = charset;
277 run_storage[runs_so_far].dimension = dimension;
278
279 /* Update loop variables. */
280 prev_charset = charset;
281 runs_so_far++;
282 }
283
284 /* Must check flags in this order. See comment above. */
285 if (translate_to_ucs_2)
286 {
287 int ucs = ichar_to_unicode(ch);
288 /* If UCS is less than zero or greater than 0xFFFF, set ucs2 to
289 REPLACMENT CHARACTER. */
290 ucs = (ucs & ~0xFFFF) ? 0xFFFD : ucs;
291
292 byte1 = ucs >> 8;
293 byte2 = ucs;
294 }
295 else if (need_ccl_conversion)
296 {
297 char_converter.reg[0] = charset_leading_byte;
298 char_converter.reg[1] = byte1;
299 char_converter.reg[2] = byte2;
300 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING);
301 byte1 = char_converter.reg[1];
302 byte2 = char_converter.reg[2];
303 }
304 else if (graphic == 0)
305 {
306 byte1 &= 0x7F;
307 byte2 &= 0x7F;
308 }
309 else
310 {
311 byte1 |= 0x80;
312 byte2 |= 0x80;
313 }
314
315 *text_storage++ = (unsigned char)byte1;
316
317 if (2 == dimension) *text_storage++ = (unsigned char)byte2;
318 }
319
320 if (runs_so_far)
321 {
322 run_storage[runs_so_far - 1].len =
323 text_storage - run_storage[runs_so_far - 1].ptr;
324 /* Dimension retains the relevant value for the run before it. */
325 if (2 == dimension)
326 run_storage[runs_so_far - 1].len >>= 1;
327 }
328
329 return runs_so_far;
330 }
331 #endif
332
333 static int
334 separate_textual_runs (unsigned char *text_storage,
335 struct textual_run *run_storage,
336 const Ichar *str, Charcount len,
337 struct face_cachel *cachel)
338 {
339 #if defined(USE_XFT) && defined(MULE)
340 return separate_textual_runs_xft_mule (text_storage, run_storage,
341 str, len, cachel);
342 #endif
343 #if defined(USE_XFT) && !defined(MULE)
344 return separate_textual_runs_xft_nomule (text_storage, run_storage,
345 str, len, cachel);
346 #endif
347 #if !defined(USE_XFT) && defined(MULE)
348 return separate_textual_runs_mule (text_storage, run_storage,
349 str, len, cachel);
350 #endif
351 #if !defined(USE_XFT) && !defined(MULE)
352 return separate_textual_runs_nomule (text_storage, run_storage,
353 str, len, cachel);
354 #endif
355 }