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
34 #include "wine/debug.h"
35 #include "usp10_internal.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
39 extern const unsigned short wine_linebreak_table[];
41 enum breaking_types { 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, 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};
43 enum breaking_class {b_r=1, b_s, b_x};
45 static void debug_output_breaks(const short* breaks, int count)
47 if (TRACE_ON(uniscribe))
51 for (i = 0; i < count && i < 200; i++)
55 case b_x: TRACE("x"); break;
56 case b_r: TRACE("!"); break;
57 case b_s: TRACE("+"); break;
67 static inline void else_break(short* before, short class)
69 if (*before == 0) *before = class;
72 void BREAK_line(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
78 TRACE("In %s\n",debugstr_wn(chars,count));
80 break_class = HeapAlloc(GetProcessHeap(),0, count * sizeof(short));
81 break_before = HeapAlloc(GetProcessHeap(),0, count * sizeof(short));
83 for (i = 0; i < count; i++)
85 break_class[i] = get_table_entry( wine_linebreak_table, chars[i] );
88 memset(&la[i],0,sizeof(SCRIPT_LOGATTR));
90 la[i].fCharStop = TRUE;
91 switch (break_class[i])
96 la[i].fWhiteSpace = TRUE;
99 la[i].fCharStop = FALSE;
104 /* TODO: Have outside algorithms for these scripts */
105 for (i = 0; i < count; i++)
107 switch(break_class[i])
113 break_class[i] = b_AL;
118 break_before[0] = b_x;
119 for (i = 0; i < count; i++)
121 switch(break_class[i])
125 if (i < count-1 && break_class[i+1] == b_LF)
127 else_break(&break_before[i],b_x);
128 else_break(&break_before[i+1],b_x);
134 if (i < count-1) else_break(&break_before[i+1],b_r);
135 else_break(&break_before[i],b_x);
139 else_break(&break_before[i],b_x);
142 else_break(&break_before[i],b_x);
144 while (i < count-1 && break_class[i+1] == b_SP)
146 else_break(&break_before[i],b_s);
151 debug_output_breaks(break_before,count);
154 for (i = 0; i < count; i++)
156 if (break_class[i] == b_CM)
160 switch (break_class[i-1])
168 break_class[i] = b_AL;
171 break_class[i] = break_class[i-1];
174 else break_class[i] = b_AL;
178 for (i = 0; i < count; i++)
180 switch(break_class[i])
184 else_break(&break_before[i],b_x);
186 else_break(&break_before[i+1],b_x);
191 else_break(&break_before[i+1],b_x);
195 if (break_class[i-1] != b_SP &&
196 break_class[i-1] != b_BA &&
197 break_class[i-1] != b_HY)
198 else_break(&break_before[i],b_x);
207 else_break(&break_before[i],b_x);
211 while (i < count-1 && break_class[i+1] == b_SP)
213 else_break(&break_before[i+1],b_x);
216 else_break(&break_before[i+1],b_x);
221 while (j < count-1 && break_class[j] == b_SP)
223 if (break_class[j] == b_OP)
226 else_break(&break_before[j],b_x);
232 while(j > 0 && break_class[j] == b_SP)
234 if (break_class[j] == b_CL || break_class[j] == b_CP)
236 for (j++; j <= i; j++)
237 else_break(&break_before[j],b_x);
243 while (j < count && break_class[j] == b_SP)
245 if (break_class[j] == b_B2)
248 else_break(&break_before[j],b_x);
254 debug_output_breaks(break_before,count);
256 for (i = 0; i < count; i++)
258 switch(break_class[i])
263 else_break(&break_before[i+1],b_s);
267 else_break(&break_before[i],b_x);
269 else_break(&break_before[i+1],b_x);
273 else_break(&break_before[i],b_s);
275 else_break(&break_before[i+1],b_s);
280 else_break(&break_before[i],b_x);
284 else_break(&break_before[i+1],b_x);
290 switch (break_class[i-1])
296 else_break(&break_before[i], b_x);
305 if ((break_class[i] == b_ID && break_class[i+1] == b_PO) ||
306 (break_class[i] == b_AL && break_class[i+1] == b_NU) ||
307 (break_class[i] == b_NU && break_class[i+1] == b_AL))
308 else_break(&break_before[i+1],b_x);
310 if ((break_class[i] == b_PR && break_class[i+1] == b_ID) ||
311 (break_class[i] == b_PR && break_class[i+1] == b_AL) ||
312 (break_class[i] == b_PO && break_class[i+1] == b_AL))
313 else_break(&break_before[i+1],b_x);
316 if ((break_class[i] == b_CL && break_class[i+1] == b_PO) ||
317 (break_class[i] == b_CP && break_class[i+1] == b_PO) ||
318 (break_class[i] == b_CL && break_class[i+1] == b_PR) ||
319 (break_class[i] == b_CP && break_class[i+1] == b_PR) ||
320 (break_class[i] == b_NU && break_class[i+1] == b_PO) ||
321 (break_class[i] == b_NU && break_class[i+1] == b_PR) ||
322 (break_class[i] == b_PO && break_class[i+1] == b_OP) ||
323 (break_class[i] == b_PO && break_class[i+1] == b_NU) ||
324 (break_class[i] == b_PR && break_class[i+1] == b_OP) ||
325 (break_class[i] == b_PR && break_class[i+1] == b_NU) ||
326 (break_class[i] == b_HY && break_class[i+1] == b_NU) ||
327 (break_class[i] == b_IS && break_class[i+1] == b_NU) ||
328 (break_class[i] == b_NU && break_class[i+1] == b_NU) ||
329 (break_class[i] == b_SY && break_class[i+1] == b_NU))
330 else_break(&break_before[i+1],b_x);
333 if (break_class[i] == b_JL)
335 switch (break_class[i+1])
341 else_break(&break_before[i+1],b_x);
344 if ((break_class[i] == b_JV || break_class[i] == b_H2) &&
345 (break_class[i+1] == b_JV || break_class[i+1] == b_JT))
346 else_break(&break_before[i+1],b_x);
347 if ((break_class[i] == b_JT || break_class[i] == b_H3) &&
348 break_class[i+1] == b_JT)
349 else_break(&break_before[i+1],b_x);
352 switch (break_class[i])
359 if (break_class[i+1] == b_IN || break_class[i+1] == b_PO)
360 else_break(&break_before[i+1],b_x);
362 if (break_class[i] == b_PO)
364 switch (break_class[i+1])
371 else_break(&break_before[i+1],b_x);
376 if (break_class[i] == b_AL && break_class[i+1] == b_AL)
377 else_break(&break_before[i+1],b_x);
380 if (break_class[i] == b_IS && break_class[i+1] == b_AL)
381 else_break(&break_before[i+1],b_x);
384 if ((break_class[i] == b_AL || break_class[i] == b_NU) &&
385 break_class[i+1] == b_OP)
386 else_break(&break_before[i+1],b_x);
387 if (break_class[i] == b_CP &&
388 (break_class[i+1] == b_AL || break_class[i] == b_NU))
389 else_break(&break_before[i+1],b_x);
392 debug_output_breaks(break_before,count);
395 for (i = 0; i < count-1; i++)
396 else_break(&break_before[i+1],b_s);
398 debug_output_breaks(break_before,count);
399 for (i = 0; i < count; i++)
401 if (break_before[i] != b_x)
403 la[i].fSoftBreak = TRUE;
404 la[i].fWordStop = TRUE;
408 HeapFree(GetProcessHeap(), 0, break_before);
409 HeapFree(GetProcessHeap(), 0, break_class);