Commit dc919db2 authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

kernel32: Implement canonical reordering.

parent e4a9e2ff
......@@ -5374,6 +5374,7 @@ INT WINAPI NormalizeString(NORM_FORM form, const WCHAR *src, INT src_len, WCHAR
if (form == NormalizationKC || form == NormalizationKD) flags |= WINE_DECOMPOSE_COMPAT;
if (form == NormalizationC || form == NormalizationKC) compose = 1;
if (compose || dst_len) flags |= WINE_DECOMPOSE_REORDER;
if (!compose && dst_len)
{
......
......@@ -5696,10 +5696,10 @@ static void test_NormalizeString(void)
{ part0_str2, { part0_nfc2, part0_str2, part0_nfc2, part0_str2 }, { 1, 0, 1, 0 } },
{ part0_str3, { part0_nfc3, part0_str3, part0_nfc3, part0_str3 }, { 1, 0, 1, 0 } },
{ part0_str4, { part0_nfc4, part0_str4, part0_nfc4, part0_str4 }, { 1, 0, 1, 0 } },
{ part0_str5, { part0_nfc5, part0_nfc5, part0_nfc5, part0_nfc5 }, { 1, 1, 1, 1 } },
{ part0_str6, { part0_nfc6, part0_nfc6, part0_nfc6, part0_nfc6 }, { 1, 1, 1, 1 } },
{ part0_str5, { part0_nfc5, part0_nfc5, part0_nfc5, part0_nfc5 }, { 1, 0, 1, 0 } },
{ part0_str6, { part0_nfc6, part0_nfc6, part0_nfc6, part0_nfc6 }, { 1, 0, 1, 0 } },
{ part0_str8, { part0_str8, part0_nfd8, part0_str8, part0_nfd8 }, { 1, 0, 1, 0 } },
{ part0_str9, { part0_nfc9, part0_nfd9, part0_nfc9, part0_nfd9 }, { 1, 1, 1, 1 } },
{ part0_str9, { part0_nfc9, part0_nfd9, part0_nfc9, part0_nfd9 }, { 1, 0, 1, 0 } },
{ part0_str10, { part0_str10, part0_nfd10, part0_str10, part0_nfd10 }, { 1, 0, 1, 0 } },
{ part0_str11, { part0_str11, part0_nfd11, part0_str11, part0_nfd11 }, { 1, 0, 1, 0 } },
{ part0_str12, { part0_nfc12, part0_nfd12, part0_nfc12, part0_nfd12 }, { 1, 0, 1, 0 } },
......
......@@ -73,6 +73,7 @@ C_SRCS = \
c_936.c \
c_949.c \
c_950.c \
combclass.c \
compose.c \
cpsymbol.c \
cptable.c \
......
......@@ -21,6 +21,72 @@
#include "wine/unicode.h"
extern unsigned int wine_decompose( int flags, WCHAR ch, WCHAR *dst, unsigned int dstlen ) DECLSPEC_HIDDEN;
extern const unsigned short combining_class_table[] DECLSPEC_HIDDEN;
static BYTE get_combining_class( WCHAR c )
{
return combining_class_table[combining_class_table[combining_class_table[c >> 8] + ((c >> 4) & 0xf)] + (c & 0xf)];
}
static BOOL is_starter( WCHAR c )
{
return !get_combining_class( c );
}
static BOOL reorderable_pair( WCHAR c1, WCHAR c2 )
{
BYTE ccc1, ccc2;
/* reorderable if ccc1 > ccc2 > 0 */
ccc1 = get_combining_class( c1 );
if (ccc1 < 2) return FALSE;
ccc2 = get_combining_class( c2 );
return ccc2 && (ccc1 > ccc2);
}
static void canonical_order_substring( WCHAR *str, unsigned int len )
{
unsigned int i;
BOOL swapped;
do
{
swapped = FALSE;
for (i = 0; i < len - 1; i++)
{
if (reorderable_pair( str[i], str[i + 1] ))
{
WCHAR tmp = str[i];
str[i] = str[i + 1];
str[i + 1] = tmp;
swapped = TRUE;
}
}
} while (swapped);
}
/****************************************************************************
* canonical_order_string
*
* Reorder the string into canonical order - D108/D109.
*
* Starters (chars with combining class == 0) don't move, so look for continuous
* substrings of non-starters and only reorder those.
*/
static void canonical_order_string( WCHAR *str, unsigned int len )
{
unsigned int i, next = 0;
for (i = 1; i <= len; i++)
{
if (i == len || is_starter( str[i] ))
{
if (i > next + 1) /* at least two successive non-starters */
canonical_order_substring( str + next, i - next );
next = i + 1;
}
}
}
unsigned int wine_decompose_string( int flags, const WCHAR *src, unsigned int src_len,
WCHAR *dst, unsigned int dst_len )
......@@ -34,5 +100,7 @@ unsigned int wine_decompose_string( int flags, const WCHAR *src, unsigned int sr
if (decomp_len == 0) return 0;
dst_pos += decomp_len;
}
if (flags & WINE_DECOMPOSE_REORDER) canonical_order_string( dst, dst_pos );
return dst_pos;
}
......@@ -360,6 +360,7 @@ my @joining_table = ();
my @direction_table = ();
my @decomp_table = ();
my @compose_table = ();
my @combining_class_table = ();
my $default_char;
my $default_wchar;
......@@ -457,6 +458,10 @@ sub READ_DEFAULTS($)
{
$digitmap_table[$src] = ord $dig;
}
if ($comb ne "")
{
$combining_class_table[$src] = $comb;
}
# copy the category and direction for everything between First/Last pairs
if ($name =~ /, First>/) { $start = $src; }
......@@ -2371,6 +2376,24 @@ EOF
}
################################################################
# dump the combining class table
sub dump_combining_class($)
{
my $filename = shift;
open OUTPUT,">$filename.new" or die "Cannot create $filename";
print "Building $filename\n";
print OUTPUT "/* Unicode Combining Classes */\n";
print OUTPUT "/* generated from $UNIDATA/UnicodeData.txt */\n";
print OUTPUT "/* DO NOT EDIT!! */\n\n";
print OUTPUT "#include \"wine/unicode.h\"\n\n";
dump_two_level_mapping( "combining_class_table", 0, @combining_class_table );
close OUTPUT;
save_file($filename);
}
################################################################
# output a codepage definition file from the global tables
sub output_codepage_file($$$$)
{
......@@ -2604,6 +2627,7 @@ dump_compose_table( "libs/port/compose.c" );
dump_decompose_table( "libs/port/decompose.c" );
DUMP_CTYPE_TABLES( "libs/wine/wctype.c" );
dump_digit_folding( "libs/port/digitmap.c" );
dump_combining_class( "libs/port/combclass.c" );
dump_mirroring( "dlls/usp10/mirror.c" );
dump_mirroring( "dlls/dwrite/mirror.c" );
dump_bracket( "dlls/usp10/bracket.c" );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment