ddraw/tests: Rewrite LimitTest().
[wine.git] / dlls / usp10 / breaking.c
blobf5e40ac27b2289e4701825a6e24887e6dc2a23db
1 /*
2 * Implementation of line breaking algorithm for the Uniscribe Script Processor
4 * Copyright 2011 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <stdlib.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "wingdi.h"
30 #include "winnls.h"
31 #include "usp10.h"
32 #include "winternl.h"
34 #include "wine/debug.h"
35 #include "usp10_internal.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
39 extern const unsigned short wine_linebreak_table[] DECLSPEC_HIDDEN;
41 enum breaking_types {
42 b_BK=1, b_CR, b_LF, b_CM, b_SG, b_GL, b_CB, b_SP, b_ZW, b_NL, b_WJ, b_JL, b_JV, b_JT, b_H2, b_H3, b_XX, b_OP, b_CL,
43 b_CP, b_QU, b_NS, b_EX, b_SY, b_IS, b_PR, b_PO, b_NU, b_AL, b_ID, b_IN, b_HY, b_BB, b_BA, b_SA, b_AI, b_B2, b_HL,
44 b_CJ, b_RI, b_EB, b_EM, b_ZWJ
47 enum breaking_class {b_r=1, b_s, b_x};
49 static void debug_output_breaks(const short* breaks, int count)
51 if (TRACE_ON(uniscribe))
53 int i;
54 TRACE("[");
55 for (i = 0; i < count && i < 200; i++)
57 switch (breaks[i])
59 case b_x: TRACE("x"); break;
60 case b_r: TRACE("!"); break;
61 case b_s: TRACE("+"); break;
62 default: TRACE("*");
65 if (i == 200)
66 TRACE("...");
67 TRACE("]\n");
71 static inline void else_break(short* before, short class)
73 if (*before == 0) *before = class;
76 void BREAK_line(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
78 int i,j;
79 short *break_class;
80 short *break_before;
82 TRACE("In %s\n",debugstr_wn(chars,count));
84 break_class = heap_alloc(count * sizeof(*break_class));
85 break_before = heap_alloc(count * sizeof(*break_before));
87 for (i = 0; i < count; i++)
89 break_class[i] = get_table_entry( wine_linebreak_table, chars[i] );
90 break_before[i] = 0;
92 memset(&la[i],0,sizeof(SCRIPT_LOGATTR));
94 la[i].fCharStop = TRUE;
95 switch (break_class[i])
97 case b_BK:
98 case b_ZW:
99 case b_SP:
100 la[i].fWhiteSpace = TRUE;
101 break;
102 case b_CM:
103 la[i].fCharStop = FALSE;
104 break;
108 /* LB1 */
109 /* TODO: Have outside algorithms for these scripts */
110 for (i = 0; i < count; i++)
112 switch(break_class[i])
114 case b_AI:
115 case b_SA:
116 case b_SG:
117 case b_XX:
118 break_class[i] = b_AL;
119 break;
120 case b_CJ:
121 break_class[i] = b_NS;
122 break;
126 /* LB2 - LB3 */
127 break_before[0] = b_x;
128 for (i = 0; i < count; i++)
130 switch(break_class[i])
132 /* LB4 - LB6 */
133 case b_CR:
134 if (i < count-1 && break_class[i+1] == b_LF)
136 else_break(&break_before[i],b_x);
137 else_break(&break_before[i+1],b_x);
138 break;
140 case b_LF:
141 case b_NL:
142 case b_BK:
143 if (i < count-1) else_break(&break_before[i+1],b_r);
144 else_break(&break_before[i],b_x);
145 break;
146 /* LB7 */
147 case b_SP:
148 else_break(&break_before[i],b_x);
149 break;
150 case b_ZW:
151 else_break(&break_before[i],b_x);
152 /* LB8 */
153 while (i < count-1 && break_class[i+1] == b_SP)
154 i++;
155 else_break(&break_before[i],b_s);
156 break;
160 debug_output_breaks(break_before,count);
162 /* LB9 - LB10 */
163 for (i = 0; i < count; i++)
165 if (break_class[i] == b_CM)
167 if (i > 0)
169 switch (break_class[i-1])
171 case b_SP:
172 case b_BK:
173 case b_CR:
174 case b_LF:
175 case b_NL:
176 case b_ZW:
177 break_class[i] = b_AL;
178 break;
179 default:
180 break_class[i] = break_class[i-1];
183 else break_class[i] = b_AL;
187 for (i = 0; i < count; i++)
189 switch(break_class[i])
191 /* LB11 */
192 case b_WJ:
193 else_break(&break_before[i],b_x);
194 if (i < count-1)
195 else_break(&break_before[i+1],b_x);
196 break;
197 /* LB12 */
198 case b_GL:
199 if (i < count-1)
200 else_break(&break_before[i+1],b_x);
201 /* LB12a */
202 if (i > 0)
204 if (break_class[i-1] != b_SP &&
205 break_class[i-1] != b_BA &&
206 break_class[i-1] != b_HY)
207 else_break(&break_before[i],b_x);
209 break;
210 /* LB13 */
211 case b_CL:
212 case b_CP:
213 case b_EX:
214 case b_IS:
215 case b_SY:
216 else_break(&break_before[i],b_x);
217 break;
218 /* LB14 */
219 case b_OP:
220 while (i < count-1 && break_class[i+1] == b_SP)
222 else_break(&break_before[i+1],b_x);
223 i++;
225 else_break(&break_before[i+1],b_x);
226 break;
227 /* LB15 */
228 case b_QU:
229 j = i+1;
230 while (j < count-1 && break_class[j] == b_SP)
231 j++;
232 if (break_class[j] == b_OP)
234 for (; j > i; j--)
235 else_break(&break_before[j],b_x);
237 break;
238 /* LB16 */
239 case b_NS:
240 j = i-1;
241 while(j > 0 && break_class[j] == b_SP)
242 j--;
243 if (break_class[j] == b_CL || break_class[j] == b_CP)
245 for (j++; j <= i; j++)
246 else_break(&break_before[j],b_x);
248 break;
249 /* LB17 */
250 case b_B2:
251 j = i+1;
252 while (j < count && break_class[j] == b_SP)
253 j++;
254 if (break_class[j] == b_B2)
256 for (; j > i; j--)
257 else_break(&break_before[j],b_x);
259 break;
263 debug_output_breaks(break_before,count);
265 for (i = 0; i < count; i++)
267 switch(break_class[i])
269 /* LB18 */
270 case b_SP:
271 if (i < count-1)
272 else_break(&break_before[i+1],b_s);
273 break;
274 /* LB19 */
275 case b_QU:
276 else_break(&break_before[i],b_x);
277 if (i < count-1)
278 else_break(&break_before[i+1],b_x);
279 break;
280 /* LB20 */
281 case b_CB:
282 else_break(&break_before[i],b_s);
283 if (i < count-1)
284 else_break(&break_before[i+1],b_s);
285 break;
286 /* LB21 */
287 case b_BA:
288 case b_HY:
289 case b_NS:
290 else_break(&break_before[i],b_x);
291 break;
292 case b_BB:
293 if (i < count-1)
294 else_break(&break_before[i+1],b_x);
295 break;
296 /* LB21a */
297 case b_HL:
298 if (i < count-2)
299 switch (break_class[i+1])
301 case b_HY:
302 case b_BA:
303 else_break(&break_before[i+2], b_x);
305 break;
306 /* LB22 */
307 case b_IN:
308 if (i > 0)
310 switch (break_class[i-1])
312 case b_AL:
313 case b_HL:
314 case b_ID:
315 case b_IN:
316 case b_NU:
317 else_break(&break_before[i], b_x);
320 break;
323 if (i < count-1)
325 /* LB23 */
326 if ((break_class[i] == b_ID && break_class[i+1] == b_PO) ||
327 (break_class[i] == b_AL && break_class[i+1] == b_NU) ||
328 (break_class[i] == b_HL && break_class[i+1] == b_NU) ||
329 (break_class[i] == b_NU && break_class[i+1] == b_AL) ||
330 (break_class[i] == b_NU && break_class[i+1] == b_HL))
331 else_break(&break_before[i+1],b_x);
332 /* LB24 */
333 if ((break_class[i] == b_PR && break_class[i+1] == b_ID) ||
334 (break_class[i] == b_PR && break_class[i+1] == b_AL) ||
335 (break_class[i] == b_PR && break_class[i+1] == b_HL) ||
336 (break_class[i] == b_PO && break_class[i+1] == b_AL) ||
337 (break_class[i] == b_PO && break_class[i+1] == b_HL))
338 else_break(&break_before[i+1],b_x);
340 /* LB25 */
341 if ((break_class[i] == b_CL && break_class[i+1] == b_PO) ||
342 (break_class[i] == b_CP && break_class[i+1] == b_PO) ||
343 (break_class[i] == b_CL && break_class[i+1] == b_PR) ||
344 (break_class[i] == b_CP && break_class[i+1] == b_PR) ||
345 (break_class[i] == b_NU && break_class[i+1] == b_PO) ||
346 (break_class[i] == b_NU && break_class[i+1] == b_PR) ||
347 (break_class[i] == b_PO && break_class[i+1] == b_OP) ||
348 (break_class[i] == b_PO && break_class[i+1] == b_NU) ||
349 (break_class[i] == b_PR && break_class[i+1] == b_OP) ||
350 (break_class[i] == b_PR && break_class[i+1] == b_NU) ||
351 (break_class[i] == b_HY && break_class[i+1] == b_NU) ||
352 (break_class[i] == b_IS && break_class[i+1] == b_NU) ||
353 (break_class[i] == b_NU && break_class[i+1] == b_NU) ||
354 (break_class[i] == b_SY && break_class[i+1] == b_NU))
355 else_break(&break_before[i+1],b_x);
357 /* LB26 */
358 if (break_class[i] == b_JL)
360 switch (break_class[i+1])
362 case b_JL:
363 case b_JV:
364 case b_H2:
365 case b_H3:
366 else_break(&break_before[i+1],b_x);
369 if ((break_class[i] == b_JV || break_class[i] == b_H2) &&
370 (break_class[i+1] == b_JV || break_class[i+1] == b_JT))
371 else_break(&break_before[i+1],b_x);
372 if ((break_class[i] == b_JT || break_class[i] == b_H3) &&
373 break_class[i+1] == b_JT)
374 else_break(&break_before[i+1],b_x);
376 /* LB27 */
377 switch (break_class[i])
379 case b_JL:
380 case b_JV:
381 case b_JT:
382 case b_H2:
383 case b_H3:
384 if (break_class[i+1] == b_IN || break_class[i+1] == b_PO)
385 else_break(&break_before[i+1],b_x);
387 if (break_class[i] == b_PR)
389 switch (break_class[i+1])
391 case b_JL:
392 case b_JV:
393 case b_JT:
394 case b_H2:
395 case b_H3:
396 else_break(&break_before[i+1],b_x);
400 /* LB28 */
401 if ((break_class[i] == b_AL && break_class[i+1] == b_AL) ||
402 (break_class[i] == b_AL && break_class[i+1] == b_HL) ||
403 (break_class[i] == b_HL && break_class[i+1] == b_AL) ||
404 (break_class[i] == b_HL && break_class[i+1] == b_HL))
405 else_break(&break_before[i+1],b_x);
407 /* LB29 */
408 if ((break_class[i] == b_IS && break_class[i+1] == b_AL) ||
409 (break_class[i] == b_IS && break_class[i+1] == b_HL))
410 else_break(&break_before[i+1],b_x);
412 /* LB30 */
413 if ((break_class[i] == b_AL || break_class[i] == b_HL || break_class[i] == b_NU) &&
414 break_class[i+1] == b_OP)
415 else_break(&break_before[i+1],b_x);
416 if (break_class[i] == b_CP &&
417 (break_class[i+1] == b_AL || break_class[i+1] == b_HL || break_class[i+1] == b_NU))
418 else_break(&break_before[i+1],b_x);
420 /* LB30a */
421 if (break_class[i] == b_RI && break_class[i+1] == b_RI)
422 else_break(&break_before[i+1],b_x);
425 debug_output_breaks(break_before,count);
427 /* LB31 */
428 for (i = 0; i < count-1; i++)
429 else_break(&break_before[i+1],b_s);
431 debug_output_breaks(break_before,count);
432 for (i = 0; i < count; i++)
434 if (break_before[i] != b_x)
436 la[i].fSoftBreak = TRUE;
437 la[i].fWordStop = TRUE;
441 heap_free(break_before);
442 heap_free(break_class);