From fdd8454ef8fe41a1e695f8b9640d8b3f77a8e6da Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 30 Sep 2014 09:56:39 +0400 Subject: [PATCH] dwrite: Implement AnalyzeBidi(). --- dlls/dwrite/Makefile.in | 2 + dlls/dwrite/analyzer.c | 83 ++- dlls/dwrite/bidi.c | 1130 ++++++++++++++++++++++++++++++++++ dlls/dwrite/bracket.c | 106 ++++ dlls/dwrite/dwrite_private.h | 7 + tools/make_unicode | 1 + 6 files changed, 1322 insertions(+), 7 deletions(-) create mode 100644 dlls/dwrite/bidi.c create mode 100644 dlls/dwrite/bracket.c diff --git a/dlls/dwrite/Makefile.in b/dlls/dwrite/Makefile.in index 32ec602ccfb..5c990a6c114 100644 --- a/dlls/dwrite/Makefile.in +++ b/dlls/dwrite/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = user32 gdi32 C_SRCS = \ analyzer.c \ + bidi.c \ + bracket.c \ font.c \ gdiinterop.c \ layout.c \ diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 3bf546c4a45..2470fa23d7f 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -165,11 +165,6 @@ static const struct dwritescript_properties dwritescripts_properties[Script_Last { /* Yiii */ { 0x69696959, 460, 1, 0x0020, 0, 0, 1, 1, 0, 0, 0 }, TRUE } }; -static inline unsigned short get_table_entry(const unsigned short *table, WCHAR ch) -{ - return table[table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + (ch & 0xf)]; -} - static inline UINT16 get_char_script(WCHAR c) { UINT16 script = get_table_entry(wine_scripts_table, c); @@ -671,8 +666,82 @@ static HRESULT WINAPI dwritetextanalyzer_AnalyzeScript(IDWriteTextAnalyzer2 *ifa static HRESULT WINAPI dwritetextanalyzer_AnalyzeBidi(IDWriteTextAnalyzer2 *iface, IDWriteTextAnalysisSource* source, UINT32 position, UINT32 length, IDWriteTextAnalysisSink* sink) { - FIXME("(%p %u %u %p): stub\n", source, position, length, sink); - return E_NOTIMPL; + UINT8 *levels = NULL, *explicit = NULL; + UINT8 baselevel, level, explicit_level; + WCHAR *buff = NULL; + const WCHAR *text; + UINT32 len, pos, i; + HRESULT hr; + + TRACE("(%p %u %u %p)\n", source, position, length, sink); + + if (length == 0) + return S_OK; + + /* get some, check for length */ + text = NULL; + len = 0; + hr = IDWriteTextAnalysisSource_GetTextAtPosition(source, position, &text, &len); + if (FAILED(hr)) return hr; + + if (len < length) { + UINT32 read; + + buff = heap_alloc(length*sizeof(WCHAR)); + if (!buff) + return E_OUTOFMEMORY; + memcpy(buff, text, len*sizeof(WCHAR)); + read = len; + + while (read < length && text) { + text = NULL; + len = 0; + hr = IDWriteTextAnalysisSource_GetTextAtPosition(source, read, &text, &len); + if (FAILED(hr)) + goto done; + memcpy(&buff[read], text, min(len, length-read)*sizeof(WCHAR)); + read += len; + } + + text = buff; + } + + levels = heap_alloc(length*sizeof(*levels)); + explicit = heap_alloc(length*sizeof(*explicit)); + + if (!levels || !explicit) { + hr = E_OUTOFMEMORY; + goto done; + } + + baselevel = IDWriteTextAnalysisSource_GetParagraphReadingDirection(source); + hr = bidi_computelevels(text, length, baselevel, explicit, levels); + if (FAILED(hr)) + goto done; + + level = levels[0]; + explicit_level = explicit[0]; + pos = 0; + for (i = 1; i < length; i++) { + if (levels[i] != level || explicit[i] != explicit_level) { + hr = IDWriteTextAnalysisSink_SetBidiLevel(sink, pos, i - pos, explicit_level, level); + if (FAILED(hr)) + break; + level = levels[i]; + explicit_level = explicit[i]; + pos = i; + } + + if (i == length - 1) + hr = IDWriteTextAnalysisSink_SetBidiLevel(sink, pos, length - pos, explicit_level, level); + } + +done: + heap_free(explicit); + heap_free(levels); + heap_free(buff); + + return hr; } static HRESULT WINAPI dwritetextanalyzer_AnalyzeNumberSubstitution(IDWriteTextAnalyzer2 *iface, diff --git a/dlls/dwrite/bidi.c b/dlls/dwrite/bidi.c new file mode 100644 index 00000000000..df06bf10a8f --- /dev/null +++ b/dlls/dwrite/bidi.c @@ -0,0 +1,1130 @@ +/* + * Unicode Bidirectional Algorithm implementation + * + * Copyright 2003 Shachar Shemesh + * Copyright 2007 Maarten Lankhorst + * Copyright 2010 CodeWeavers, Aric Stewart + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Code derived from the modified reference implementation + * that was found in revision 17 of http://unicode.org/reports/tr9/ + * "Unicode Standard Annex #9: THE BIDIRECTIONAL ALGORITHM" + * + * -- Copyright (C) 1999-2005, ASMUS, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of the Unicode data files and any associated documentation (the + * "Data Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, + * and to permit persons to whom the Data Files or Software are furnished + * to do so, provided that (a) the above copyright notice(s) and this + * permission notice appear with all copies of the Data Files or Software, + * (b) both the above copyright notice(s) and this permission notice appear + * in associated documentation, and (c) there is clear notice in each + * modified Data File or in the Software as well as in the documentation + * associated with the Data File(s) or Software that the data or software + * has been modified. + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" +#include "wine/list.h" + +#include "dwrite.h" +#include "dwrite_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(bidi); + +extern const unsigned short bidi_bracket_table[]; + +#define ASSERT(x) do { if (!(x)) FIXME("assert failed: %s\n", #x); } while(0) +#define MAX_DEPTH 125 + +#define odd(x) ((x) & 1) + +/*------------------------------------------------------------------------ + Bidirectional Character Types + + as defined by the Unicode Bidirectional Algorithm Table 3-7. + + Note: + + The list of bidirectional character types here is not grouped the + same way as the table 3-7, since the numberic values for the types + are chosen to keep the state and action tables compact. +------------------------------------------------------------------------*/ +enum directions +{ + /* input types */ + /* ON MUST be zero, code relies on ON = NI = 0 */ + ON = 0, /* Other Neutral */ + L, /* Left Letter */ + R, /* Right Letter */ + AN, /* Arabic Number */ + EN, /* European Number */ + AL, /* Arabic Letter (Right-to-left) */ + NSM, /* Non-spacing Mark */ + CS, /* Common Separator */ + ES, /* European Separator */ + ET, /* European Terminator (post/prefix e.g. $ and %) */ + + /* resolved types */ + BN, /* Boundary neutral (type of RLE etc after explicit levels) */ + + /* input types, */ + S, /* Segment Separator (TAB) // used only in L1 */ + WS, /* White space // used only in L1 */ + B, /* Paragraph Separator (aka as PS) */ + + /* types for explicit controls */ + RLO, /* these are used only in X1-X9 */ + RLE, + LRO, + LRE, + PDF, + + LRI, /* Isolate formatting characters new with 6.3 */ + RLI, + FSI, + PDI, + + /* resolved types, also resolved directions */ + NI = ON, /* alias, where ON, WS, S and Isolates are treated the same */ +}; + +static const char debug_type[][4] = +{ + "ON", /* Other Neutral */ + "L", /* Left Letter */ + "R", /* Right Letter */ + "AN", /* Arabic Number */ + "EN", /* European Number */ + "AL", /* Arabic Letter (Right-to-left) */ + "NSM", /* Non-spacing Mark */ + "CS", /* Common Separator */ + "ES", /* European Separator */ + "ET", /* European Terminator (post/prefix e.g. $ and %) */ + "BN", /* Boundary neutral (type of RLE etc after explicit levels) */ + "S", /* Segment Separator (TAB) used only in L1 */ + "WS", /* White space used only in L1 */ + "B", /* Paragraph Separator (aka as PS) */ + "RLO", /* these are used only in X1-X9 */ + "RLE", + "LRO", + "LRE", + "PDF", + "LRI", /* Isolate formatting characters new with 6.3 */ + "RLI", + "FSI", + "PDI", +}; + +static inline void bidi_dump_types(const char* header, const UINT8 *types, UINT32 start, UINT32 end) +{ + int i, len = 0; + TRACE("%s:", header); + for (i = start; i < end && len < 200; i++) { + TRACE(" %s", debug_type[types[i]]); + len += strlen(debug_type[types[i]])+1; + } + if (i != end) + TRACE("..."); + TRACE("\n"); +} + +/* Convert the libwine information to the direction enum */ +static void bidi_classify(const WCHAR *string, UINT8 *chartype, UINT32 count) +{ + static const enum directions dir_map[16] = + { + L, /* unassigned defaults to L */ + L, + R, + EN, + ES, + ET, + AN, + CS, + B, + S, + WS, + ON, + AL, + NSM, + BN, + PDF /* also LRE, LRO, RLE, RLO */ + }; + + UINT32 i; + + for (i = 0; i < count; ++i) { + chartype[i] = dir_map[get_char_typeW(string[i]) >> 12]; + + switch (chartype[i]) { + case ES: + break; + case PDF: + switch (string[i]) { + case 0x202a: chartype[i] = LRE; break; + case 0x202b: chartype[i] = RLE; break; + case 0x202c: chartype[i] = PDF; break; + case 0x202d: chartype[i] = LRO; break; + case 0x202e: chartype[i] = RLO; break; + case 0x2066: chartype[i] = LRI; break; + case 0x2067: chartype[i] = RLI; break; + case 0x2068: chartype[i] = FSI; break; + case 0x2069: chartype[i] = PDI; break; + } + break; + } + } +} + +/* RESOLVE EXPLICIT */ + +static inline UINT8 get_greater_even_level(UINT8 level) +{ + return odd(level) ? level + 1 : level + 2; +} + +static inline UINT8 get_greater_odd_level(UINT8 level) +{ + return odd(level) ? level + 2 : level + 1; +} + +static inline UINT8 get_embedding_direction(UINT8 level) +{ + return odd(level) ? R : L; +} + +/*------------------------------------------------------------------------ + Function: bidi_resolve_explicit + + Recursively resolves explicit embedding levels and overrides. + Implements rules X1-X9, of the Unicode Bidirectional Algorithm. + + Input: Base embedding level and direction + Character count + + Output: Array of embedding levels + + In/Out: Array of direction classes + + + Note: The function uses two simple counters to keep track of + matching explicit codes and PDF. Use the default argument for + the outermost call. The nesting counter counts the recursion + depth and not the embedding level. +------------------------------------------------------------------------*/ +typedef struct tagStackItem +{ + UINT8 level; + UINT8 override; + BOOL isolate; +} StackItem; + +#define push_stack(l,o,i) \ + do { stack_top--; \ + stack[stack_top].level = l; \ + stack[stack_top].override = o; \ + stack[stack_top].isolate = i;} while(0) + +#define pop_stack() do { stack_top++; } while(0) + +#define valid_level(x) (x <= MAX_DEPTH && overflow_isolate_count == 0 && overflow_embedding_count == 0) + +static void bidi_resolve_explicit(UINT8 baselevel, UINT8 *classes, UINT8 *levels, UINT32 count) +{ + /* X1 */ + int overflow_isolate_count = 0; + int overflow_embedding_count = 0; + int valid_isolate_count = 0; + UINT32 i; + + StackItem stack[MAX_DEPTH+2]; + int stack_top = MAX_DEPTH+1; + + stack[stack_top].level = baselevel; + stack[stack_top].override = NI; + stack[stack_top].isolate = FALSE; + + for (i = 0; i < count; i++) { + UINT8 least_odd, least_even; + + switch (classes[i]) { + + /* X2 */ + case RLE: + least_odd = get_greater_odd_level(stack[stack_top].level); + levels[i] = stack[stack_top].level; + if (valid_level(least_odd)) + push_stack(least_odd, NI, FALSE); + else if (overflow_isolate_count == 0) + overflow_embedding_count++; + break; + + /* X3 */ + case LRE: + least_even = get_greater_even_level(stack[stack_top].level); + levels[i] = stack[stack_top].level; + if (valid_level(least_even)) + push_stack(least_even, NI, FALSE); + else if (overflow_isolate_count == 0) + overflow_embedding_count++; + break; + + /* X4 */ + case RLO: + least_odd = get_greater_odd_level(stack[stack_top].level); + levels[i] = stack[stack_top].level; + if (valid_level(least_odd)) + push_stack(least_odd, R, FALSE); + else if (overflow_isolate_count == 0) + overflow_embedding_count++; + break; + + /* X5 */ + case LRO: + least_even = get_greater_even_level(stack[stack_top].level); + levels[i] = stack[stack_top].level; + if (valid_level(least_even)) + push_stack(least_even, L, FALSE); + else if (overflow_isolate_count == 0) + overflow_embedding_count++; + break; + + /* X5a */ + case RLI: + least_odd = get_greater_odd_level(stack[stack_top].level); + levels[i] = stack[stack_top].level; + if (valid_level(least_odd)) + { + valid_isolate_count++; + push_stack(least_odd, NI, TRUE); + } + else + overflow_isolate_count++; + break; + + /* X5b */ + case LRI: + least_even = get_greater_even_level(stack[stack_top].level); + levels[i] = stack[stack_top].level; + if (valid_level(least_even)) + { + valid_isolate_count++; + push_stack(least_even, NI, TRUE); + } + else + overflow_isolate_count++; + break; + + /* X5c */ + case FSI: + { + UINT8 new_level = 0; + int skipping = 0; + int j; + + levels[i] = stack[stack_top].level; + for (j = i+1; j < count; j++) + { + if (classes[j] == LRI || classes[j] == RLI || classes[j] == FSI) + { + skipping++; + continue; + } + else if (classes[j] == PDI) + { + if (skipping) + skipping --; + else + break; + continue; + } + + if (skipping) continue; + + if (classes[j] == L) + { + new_level = 0; + break; + } + else if (classes[j] == R || classes[j] == AL) + { + new_level = 1; + break; + } + } + if (odd(new_level)) + { + least_odd = get_greater_odd_level(stack[stack_top].level); + if (valid_level(least_odd)) + { + valid_isolate_count++; + push_stack(least_odd, NI, TRUE); + } + else + overflow_isolate_count++; + } + else + { + least_even = get_greater_even_level(stack[stack_top].level); + if (valid_level(least_even)) + { + valid_isolate_count++; + push_stack(least_even, NI, TRUE); + } + else + overflow_isolate_count++; + } + break; + } + + /* X6 */ + case ON: + case L: + case R: + case AN: + case EN: + case AL: + case NSM: + case CS: + case ES: + case ET: + case S: + case WS: + levels[i] = stack[stack_top].level; + if (stack[stack_top].override != NI) + classes[i] = stack[stack_top].override; + break; + + /* X6a */ + case PDI: + if (overflow_isolate_count) overflow_isolate_count--; + else if (!valid_isolate_count) {/* do nothing */} + else + { + overflow_embedding_count = 0; + while (!stack[stack_top].isolate) pop_stack(); + pop_stack(); + valid_isolate_count--; + } + levels[i] = stack[stack_top].level; + break; + + /* X7 */ + case PDF: + levels[i] = stack[stack_top].level; + if (overflow_isolate_count) {/* do nothing */} + else if (overflow_embedding_count) overflow_embedding_count--; + else if (!stack[stack_top].isolate && stack_top < (MAX_DEPTH+1)) + pop_stack(); + break; + + /* X8: Nothing */ + default: + break; + } + } + /* X9: Based on 5.2 Retaining Explicit Formatting Characters */ + for (i = 0; i < count ; i++) + if (classes[i] == RLE || classes[i] == LRE || classes[i] == RLO || classes[i] == LRO || classes[i] == PDF) + classes[i] = BN; +} + +static inline int get_prev_valid_char_index(const UINT8 *classes, int index, int back_fence) +{ + if (index == -1 || index == back_fence) return index; + index--; + while (index > back_fence && classes[index] == BN) index--; + return index; +} + +static inline int get_next_valid_char_index(const UINT8 *classes, int index, int front_fence) +{ + if (index == front_fence) return index; + index++; + while (index < front_fence && classes[index] == BN) index++; + return index; +} + +typedef struct tagRun +{ + int start; + int end; + UINT8 e; +} Run; + +typedef struct tagRunChar +{ + WCHAR ch; + UINT8 *class; +} RunChar; + +typedef struct tagIsolatedRun +{ + struct list entry; + int length; + UINT8 sos; + UINT8 eos; + UINT8 e; + + RunChar item[1]; +} IsolatedRun; + +static inline int get_next_valid_char_from_run(IsolatedRun *run, int index) +{ + if (index >= (run->length-1)) return -1; + index++; + while (index < run->length && *run->item[index].class == BN) index++; + if (index == run->length) return -1; + return index; +} + +static inline int get_prev_valid_char_from_run(IsolatedRun *run, int index) +{ + if (index <= 0) return -1; + index--; + while (index > -1 && *run->item[index].class == BN) index--; + return index; +} + +static inline int iso_previousChar(IsolatedRun *run, int index) +{ + if (index <= 0) return -1; + return index--; +} + +static inline void iso_dump_types(const char* header, IsolatedRun *run) +{ + int i, len = 0; + TRACE("%s:",header); + TRACE("[ "); + for (i = 0; i < run->length && len < 200; i++) { + TRACE(" %s", debug_type[*run->item[i].class]); + len += strlen(debug_type[*run->item[i].class])+1; + } + if (i != run->length) + TRACE("..."); + TRACE(" ]\n"); +} + +/*------------------------------------------------------------------------ + Function: bidi_resolve_weak + + Resolves the directionality of numeric and other weak character types + + Implements rules X10 and W1-W6 of the Unicode Bidirectional Algorithm. + + Input: Array of embedding levels + Character count + + In/Out: Array of directional classes + + Note: On input only these directional classes are expected + AL, HL, R, L, ON, BN, NSM, AN, EN, ES, ET, CS, +------------------------------------------------------------------------*/ +static void bidi_resolve_weak(IsolatedRun *iso_run) +{ + int i; + + /* W1 */ + for (i=0; i < iso_run->length; i++) { + if (*iso_run->item[i].class == NSM) { + int j = get_prev_valid_char_from_run(iso_run, i); + if (j == -1) + *iso_run->item[i].class = iso_run->sos; + else if (*iso_run->item[j].class >= LRI) + *iso_run->item[i].class = ON; + else + *iso_run->item[i].class = *iso_run->item[j].class; + } + } + + /* W2 */ + for (i = 0; i < iso_run->length; i++) { + if (*iso_run->item[i].class == EN) { + int j = get_prev_valid_char_from_run(iso_run, i); + while (j > -1) { + if (*iso_run->item[j].class == R || *iso_run->item[j].class == L || *iso_run->item[j].class == AL) { + if (*iso_run->item[j].class == AL) + *iso_run->item[i].class = AN; + break; + } + j = get_prev_valid_char_from_run(iso_run, j); + } + } + } + + /* W3 */ + for (i = 0; i < iso_run->length; i++) { + if (*iso_run->item[i].class == AL) + *iso_run->item[i].class = R; + } + + /* W4 */ + for (i = 0; i < iso_run->length; i++) { + if (*iso_run->item[i].class == ES) { + int b = get_prev_valid_char_from_run(iso_run, i); + int f = get_next_valid_char_from_run(iso_run, i); + + if (b > -1 && f > -1 && *iso_run->item[b].class == EN && *iso_run->item[f].class == EN) + *iso_run->item[i].class = EN; + } + else if (*iso_run->item[i].class == CS) { + int b = get_prev_valid_char_from_run(iso_run, i); + int f = get_next_valid_char_from_run(iso_run, i); + + if (b > -1 && f > -1 && *iso_run->item[b].class == EN && *iso_run->item[f].class == EN) + *iso_run->item[i].class = EN; + else if (b > -1 && f > -1 && *iso_run->item[b].class == AN && *iso_run->item[f].class == AN) + *iso_run->item[i].class = AN; + } + } + + /* W5 */ + for (i = 0; i < iso_run->length; i++) { + if (*iso_run->item[i].class == ET) { + int j; + for (j = i-1 ; j > -1; j--) { + if (*iso_run->item[j].class == BN) continue; + if (*iso_run->item[j].class == ET) continue; + else if (*iso_run->item[j].class == EN) *iso_run->item[i].class = EN; + else break; + } + if (*iso_run->item[i].class == ET) { + for (j = i+1; j < iso_run->length; j++) { + if (*iso_run->item[j].class == BN) continue; + if (*iso_run->item[j].class == ET) continue; + else if (*iso_run->item[j].class == EN) *iso_run->item[i].class = EN; + else break; + } + } + } + } + + /* W6 */ + for (i = 0; i < iso_run->length; i++) { + if (*iso_run->item[i].class == ET || *iso_run->item[i].class == ES || *iso_run->item[i].class == CS || *iso_run->item[i].class == ON) + { + int b = i-1; + int f = i+1; + if (b > -1 && *iso_run->item[b].class == BN) + *iso_run->item[b].class = ON; + if (f < iso_run->length && *iso_run->item[f].class == BN) + *iso_run->item[f].class = ON; + + *iso_run->item[i].class = ON; + } + } + + /* W7 */ + for (i = 0; i < iso_run->length; i++) { + if (*iso_run->item[i].class == EN) { + int j; + for (j = get_prev_valid_char_from_run(iso_run, i); j > -1; j = get_prev_valid_char_from_run(iso_run, j)) + if (*iso_run->item[j].class == R || *iso_run->item[j].class == L) { + if (*iso_run->item[j].class == L) + *iso_run->item[i].class = L; + break; + } + if (iso_run->sos == L && j == -1) + *iso_run->item[i].class = L; + } + } +} + +typedef struct tagBracketPair +{ + int start; + int end; +} BracketPair; + +static int bracketpair_compr(const void *a, const void* b) +{ + return ((BracketPair*)a)->start - ((BracketPair*)b)->start; +} + +static BracketPair *bidi_compute_bracket_pairs(IsolatedRun *iso_run) +{ + WCHAR *open_stack; + int *stack_index; + int stack_top = iso_run->length; + BracketPair *out = NULL; + int pair_count = 0; + int i; + + open_stack = heap_alloc(sizeof(WCHAR) * iso_run->length); + stack_index = heap_alloc(sizeof(int) * iso_run->length); + + for (i = 0; i < iso_run->length; i++) { + unsigned short ubv = get_table_entry(bidi_bracket_table, iso_run->item[i].ch); + if (ubv) { + if (!out) { + out = heap_alloc(sizeof(BracketPair)); + out[0].start = -1; + } + + if ((ubv >> 8) == 0) { + stack_top--; + open_stack[stack_top] = iso_run->item[i].ch + (signed char)(ubv & 0xff); + /* deal with canonical equivalent U+2329/232A and U+3008/3009 */ + if (open_stack[stack_top] == 0x232A) + open_stack[stack_top] = 0x3009; + stack_index[stack_top] = i; + } + else if ((ubv >> 8) == 1) { + int j; + + if (stack_top == iso_run->length) continue; + for (j = stack_top; j < iso_run->length; j++) { + WCHAR c = iso_run->item[i].ch; + if (c == 0x232A) c = 0x3009; + if (c == open_stack[j]) { + out[pair_count].start = stack_index[j]; + out[pair_count].end = i; + pair_count++; + out = heap_realloc(out, sizeof(BracketPair) * (pair_count+1)); + out[pair_count].start = -1; + stack_top = j+1; + break; + } + } + } + } + } + if (pair_count == 0) { + heap_free(out); + out = NULL; + } + else if (pair_count > 1) + qsort(out, pair_count, sizeof(BracketPair), bracketpair_compr); + + heap_free(open_stack); + heap_free(stack_index); + return out; +} + +static inline UINT8 get_rule_N0_class(UINT8 class) +{ + return (class == AN || class == EN) ? R : class; +} + +/*------------------------------------------------------------------------ + Function: bidi_resolve_neutrals + + Resolves the directionality of neutral character types. + + Implements rules N1 and N2 of the Unicode Bidi Algorithm. + + Input: Array of embedding levels + Character count + Baselevel + + In/Out: Array of directional classes + + Note: On input only these directional classes are expected + R, L, NI, AN, EN and BN + + W8 resolves a number of ENs to L +------------------------------------------------------------------------*/ +static void bidi_resolve_neutrals(IsolatedRun *run) +{ + BracketPair *pairs; + int i; + + /* Translate isolates into NI */ + for (i = 0; i < run->length; i++) { + if (*run->item[i].class >= LRI) + *run->item[i].class = NI; + + switch (*run->item[i].class) { + case B: + case S: + case WS: *run->item[i].class = NI; + } + + ASSERT(*run->item[i].class < 5 || *run->item[i].class == BN); /* "Only NI, L, R, AN, EN and BN are allowed" */ + } + + /* N0: Skipping bracketed pairs for now */ + pairs = bidi_compute_bracket_pairs(run); + if (pairs) { + BracketPair *p = pairs; + int i = 0; + while (p->start >= 0) { + UINT8 e = get_embedding_direction(run->e); + UINT8 o = get_embedding_direction(run->e + 1); + BOOL flag_o = FALSE; + int j; + + TRACE("Bracket Pair [%i - %i]\n", p->start, p->end); + + /* N0.b */ + for (j = p->start+1; j < p->end; j++) { + if (get_rule_N0_class(*run->item[j].class) == e) { + *run->item[p->start].class = e; + *run->item[p->end].class = e; + break; + } + else if (get_rule_N0_class(*run->item[j].class) == o) + flag_o = TRUE; + } + /* N0.c */ + if (j == p->end && flag_o) { + for (j = p->start; j >= 0; j--) { + if (get_rule_N0_class(*run->item[j].class) == o) { + *run->item[p->start].class = o; + *run->item[p->end].class = o; + break; + } + else if (get_rule_N0_class(*run->item[j].class) == e) { + *run->item[p->start].class = e; + *run->item[p->end].class = e; + break; + } + } + if (j < 0) { + *run->item[p->start].class = run->sos; + *run->item[p->end].class = run->sos; + } + } + + i++; + p = &pairs[i]; + } + heap_free(pairs); + } + + /* N1 */ + for (i = 0; i < run->length; i++) { + UINT8 l, r; + + if (*run->item[i].class == NI) { + int b = get_prev_valid_char_from_run(run, i); + int j; + + if (b == -1) { + l = run->sos; + b = 0; + } + else { + if (*run->item[b].class == R || *run->item[b].class == AN || *run->item[b].class == EN) + l = R; + else if (*run->item[b].class == L) + l = L; + else /* No string type */ + continue; + } + j = get_next_valid_char_from_run(run, i); + while (j > -1 && *run->item[j].class == NI) j = get_next_valid_char_from_run(run, j); + if (j == -1) { + r = run->eos; + j = run->length; + } + else if (*run->item[j].class == R || *run->item[j].class == AN || *run->item[j].class == EN) + r = R; + else if (*run->item[j].class == L) + r = L; + else /* No string type */ + continue; + + if (r == l) { + for (b = i; b < j && b < run->length; b++) + *run->item[b].class = r; + } + } + } + + /* N2 */ + for (i = 0; i < run->length; i++) { + if (*run->item[i].class == NI) { + int b = i-1; + int f = i+1; + + *run->item[i].class = get_embedding_direction(run->e); + if (b > -1 && *run->item[b].class == BN) + *run->item[b].class = get_embedding_direction(run->e); + if (f < run->length && *run->item[f].class == BN) + *run->item[f].class = get_embedding_direction(run->e); + } + } +} + +/*------------------------------------------------------------------------ + Function: bidi_resolve_implicit + + Recursively resolves implicit embedding levels. + Implements rules I1 and I2 of the Unicode Bidirectional Algorithm. + + Input: Array of direction classes + Character count + Base level + + In/Out: Array of embedding levels + + Note: levels may exceed 15 on output. + Accepted subset of direction classes + R, L, AN, EN +------------------------------------------------------------------------*/ +static void bidi_resolve_implicit(const UINT8 *classes, UINT8 *levels, int sos, int eos) +{ + int i; + + /* I1/2 */ + for (i = sos; i <= eos; i++) { + if (classes[i] == BN) + continue; + + ASSERT(classes[i] > 0); /* "No Neutrals allowed to survive here." */ + ASSERT(classes[i] < 5); /* "Out of range." */ + + if (odd(levels[i]) && (classes[i] == L || classes[i] == EN || classes[i] == AN)) + levels[i]++; + else if (!odd(levels[i]) && classes[i] == R) + levels[i]++; + else if (!odd(levels[i]) && (classes[i] == EN || classes[i] == AN)) + levels[i] += 2; + } +} + +static inline BOOL is_rule_L1_reset_class(UINT8 class) +{ + switch (class) { + case WS: + case FSI: + case LRI: + case RLI: + case PDI: + case LRE: + case RLE: + case LRO: + case RLO: + case PDF: + case BN: + return TRUE; + default: + return FALSE; + } +} + +static void bidi_resolve_resolved(UINT8 baselevel, const UINT8 *classes, UINT8 *levels, int sos, int eos) +{ + int i; + + /* L1 */ + for (i = sos; i <= eos; i++) { + if (classes[i] == B || classes[i] == S) { + int j = i - 1; + while (i > sos && j >= sos && is_rule_L1_reset_class(classes[j])) + levels[j--] = baselevel; + levels[i] = baselevel; + } + if (i == eos && is_rule_L1_reset_class(classes[i])) { + int j = i; + while (j >= sos && is_rule_L1_reset_class(classes[j])) + levels[j--] = baselevel; + } + } +} + +static HRESULT bidi_compute_isolating_runs_set(UINT8 baselevel, UINT8 *classes, UINT8 *levels, const WCHAR *string, UINT32 count, struct list *set) +{ + int run_start, run_end, i; + int run_count = 0; + HRESULT hr = S_OK; + Run *runs; + + runs = heap_alloc(count * sizeof(Run)); + if (!runs) + return E_OUTOFMEMORY; + + list_init(set); + + /* Build Runs */ + run_start = 0; + while (run_start < count) { + run_end = get_next_valid_char_index(classes, run_start, count); + while (run_end < count && levels[run_end] == levels[run_start]) + run_end = get_next_valid_char_index(classes, run_end, count); + run_end--; + runs[run_count].start = run_start; + runs[run_count].end = run_end; + runs[run_count].e = levels[run_start]; + run_start = get_next_valid_char_index(classes, run_end, count); + run_count++; + } + + /* Build Isolating Runs */ + i = 0; + while (i < run_count) { + int k = i; + if (runs[k].start >= 0) { + IsolatedRun *current_isolated; + int type_fence, real_end; + int j; + + current_isolated = heap_alloc(sizeof(IsolatedRun) + sizeof(RunChar)*count); + if (!current_isolated) { + hr = E_OUTOFMEMORY; + break; + } + + run_start = runs[k].start; + current_isolated->e = runs[k].e; + current_isolated->length = (runs[k].end - runs[k].start)+1; + + for (j = 0; j < current_isolated->length; j++) { + current_isolated->item[j].class = &classes[runs[k].start+j]; + current_isolated->item[j].ch = string[runs[k].start+j]; + } + + run_end = runs[k].end; + + TRACE("{ [%i -- %i]",run_start, run_end); + + if (classes[run_end] == BN) + run_end = get_prev_valid_char_index(classes, run_end, runs[k].start); + + while (run_end < count && (classes[run_end] == RLI || classes[run_end] == LRI || classes[run_end] == FSI)) { + j = k+1; +search: + while (j < run_count && classes[runs[j].start] != PDI) j++; + if (j < run_count && runs[i].e != runs[j].e) { + j++; + goto search; + } + + if (j != run_count) { + int l = current_isolated->length; + int m; + + current_isolated->length += (runs[j].end - runs[j].start)+1; + for (m = 0; l < current_isolated->length; l++, m++) { + current_isolated->item[l].class = &classes[runs[j].start+m]; + current_isolated->item[l].ch = string[runs[j].start+m]; + } + + TRACE("[%i -- %i]", runs[j].start, runs[j].end); + + run_end = runs[j].end; + if (classes[run_end] == BN) + run_end = get_prev_valid_char_index(classes, run_end, runs[i].start); + runs[j].start = -1; + k = j; + } + else { + run_end = count; + break; + } + } + + type_fence = get_prev_valid_char_index(classes, run_start, -1); + + if (type_fence == -1) + current_isolated->sos = (baselevel > levels[run_start]) ? baselevel : levels[run_start]; + else + current_isolated->sos = (levels[type_fence] > levels[run_start]) ? levels[type_fence] : levels[run_start]; + + current_isolated->sos = get_embedding_direction(current_isolated->sos); + + if (run_end == count) + current_isolated->eos = current_isolated->sos; + else { + /* eos could be an BN */ + if (classes[run_end] == BN) { + real_end = get_prev_valid_char_index(classes, run_end, run_start-1); + if (real_end < run_start) + real_end = run_start; + } + else + real_end = run_end; + + type_fence = get_next_valid_char_index(classes, run_end, count); + if (type_fence == count) + current_isolated->eos = (baselevel > levels[real_end]) ? baselevel : levels[real_end]; + else + current_isolated->eos = (levels[type_fence] > levels[real_end]) ? levels[type_fence] : levels[real_end]; + + current_isolated->eos = get_embedding_direction(current_isolated->eos); + } + + list_add_tail(set, ¤t_isolated->entry); + TRACE(" } level %i {%s <--> %s}\n", current_isolated->e, debug_type[current_isolated->sos], debug_type[current_isolated->eos]); + } + i++; + } + + heap_free(runs); + return hr; +} + +HRESULT bidi_computelevels(const WCHAR *string, UINT32 count, UINT8 baselevel, UINT8 *explicit, UINT8 *levels) +{ + IsolatedRun *iso_run, *next; + struct list IsolatingRuns; + UINT8 *chartype; + HRESULT hr; + + TRACE("%s, %u\n", debugstr_wn(string, count), count); + + chartype = heap_alloc(count*sizeof(*chartype)); + if (!chartype) + return E_OUTOFMEMORY; + + bidi_classify(string, chartype, count); + if (TRACE_ON(bidi)) bidi_dump_types("start ", chartype, 0, count); + + bidi_resolve_explicit(baselevel, chartype, levels, count); + memcpy(explicit, levels, count*sizeof(*explicit)); + + if (TRACE_ON(bidi)) bidi_dump_types("after explicit", chartype, 0, count); + + /* X10/BD13: Compute Isolating runs */ + hr = bidi_compute_isolating_runs_set(baselevel, chartype, levels, string, count, &IsolatingRuns); + if (FAILED(hr)) + goto done; + + LIST_FOR_EACH_ENTRY_SAFE(iso_run, next, &IsolatingRuns, IsolatedRun, entry) + { + if (TRACE_ON(bidi)) iso_dump_types("run", iso_run); + + bidi_resolve_weak(iso_run); + if (TRACE_ON(bidi)) iso_dump_types("after weak", iso_run); + + bidi_resolve_neutrals(iso_run); + if (TRACE_ON(bidi)) iso_dump_types("after neutrals", iso_run); + + list_remove(&iso_run->entry); + heap_free(iso_run); + } + + if (TRACE_ON(bidi)) bidi_dump_types("before implicit", chartype, 0, count); + bidi_resolve_implicit(chartype, levels, 0, count-1); + + bidi_classify(string, chartype, count); + bidi_resolve_resolved(baselevel, chartype, levels, 0, count-1); + +done: + heap_free(chartype); + return hr; +} diff --git a/dlls/dwrite/bracket.c b/dlls/dwrite/bracket.c new file mode 100644 index 00000000000..20df6fa11f2 --- /dev/null +++ b/dlls/dwrite/bracket.c @@ -0,0 +1,106 @@ +/* Unicode Bidirectional Bracket table */ +/* generated from http://www.unicode.org/Public/7.0.0/ucd/BidiBrackets.txt */ +/* DO NOT EDIT!! */ + +const unsigned short bidi_bracket_table[768] = +{ + /* level 1 offsets */ + 0x0100, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0120, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0130, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0140, 0x0110, 0x0110, 0x0150, 0x0110, 0x0110, 0x0110, 0x0160, + 0x0110, 0x0170, 0x0110, 0x0110, 0x0110, 0x0110, 0x0180, 0x0110, + 0x0190, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x01a0, 0x01b0, + /* level 2 offsets */ + 0x01c0, 0x01c0, 0x01d0, 0x01c0, 0x01c0, 0x01e0, 0x01c0, 0x01e0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01f0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x0200, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x0210, 0x01c0, 0x01c0, 0x0220, + 0x0220, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x0230, 0x01c0, 0x0240, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x0250, 0x0260, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x0210, 0x01c0, 0x0270, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x0280, 0x0290, 0x01c0, 0x01c0, 0x01c0, 0x0230, 0x01c0, 0x02a0, + 0x01c0, 0x01c0, 0x02b0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x0250, 0x02c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x02d0, 0x01c0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + 0x01d0, 0x01c0, 0x01c0, 0x01e0, 0x01c0, 0x02e0, 0x02f0, 0x01c0, + 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, 0x01c0, + /* values */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x01fe, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0002, 0x0000, 0x01fd, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0001, 0x01fe, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x01fe, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x01fe, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0001, 0x01fe, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0001, 0x01fe, + 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x01fe, + 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0001, 0x01fe, + 0x0000, 0x0000, 0x0000, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0001, + 0x01fe, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0003, 0x0101, 0x00fe, + 0x01fc, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0001, + 0x01fe, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x01fe, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0001, 0x01fe, + 0x0001, 0x01fe, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x01fe, 0x0000, 0x0000, 0x0001, 0x01fe, 0x0001, 0x01fe, + 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0001, 0x01fe, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0002, 0x0000, 0x01fd, 0x0000, 0x0001, + 0x01fe, 0x0000, 0x0001, 0x01fe, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 626230e03a6..ccad5a83b4d 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -82,6 +82,11 @@ static inline const char *debugstr_range(const DWRITE_TEXT_RANGE *range) return wine_dbg_sprintf("%u:%u", range->startPosition, range->length); } +static inline unsigned short get_table_entry(const unsigned short *table, WCHAR ch) +{ + return table[table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + (ch & 0xf)]; +} + extern HRESULT create_font_from_logfont(const LOGFONTW*, IDWriteFont**) DECLSPEC_HIDDEN; extern HRESULT convert_fontface_to_logfont(IDWriteFontFace*, LOGFONTW*) DECLSPEC_HIDDEN; extern HRESULT create_textformat(const WCHAR*,IDWriteFontCollection*,DWRITE_FONT_WEIGHT,DWRITE_FONT_STYLE,DWRITE_FONT_STRETCH, @@ -104,3 +109,5 @@ extern HRESULT analyze_opentype_font(const void* font_data, UINT32* font_count, extern HRESULT find_font_table(IDWriteFontFileStream *stream, UINT32 font_index, UINT32 tag, const void** table_data, void** table_context, UINT32 *table_size, BOOL* found) DECLSPEC_HIDDEN; extern VOID OpenType_CMAP_GetGlyphIndex(LPVOID data, DWORD utf32c, LPWORD pgi, DWORD flags) DECLSPEC_HIDDEN; extern VOID get_font_properties(LPCVOID os2, LPCVOID head, LPCVOID post, DWRITE_FONT_METRICS *metrics, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style) DECLSPEC_HIDDEN; + +extern HRESULT bidi_computelevels(const WCHAR*,UINT32,UINT8,UINT8*,UINT8*); diff --git a/tools/make_unicode b/tools/make_unicode index 8e8bccc74d3..f63ee77d058 100755 --- a/tools/make_unicode +++ b/tools/make_unicode @@ -2384,6 +2384,7 @@ DUMP_COMPOSE_TABLES( "libs/wine/compose.c" ); DUMP_CTYPE_TABLES( "libs/wine/wctype.c" ); dump_mirroring( "dlls/usp10/mirror.c" ); dump_bracket( "dlls/usp10/bracket.c" ); +dump_bracket( "dlls/dwrite/bracket.c" ); dump_shaping( "dlls/usp10/shaping.c" ); dump_linebreak( "dlls/usp10/linebreak.c" ); dump_linebreak( "dlls/dwrite/linebreak.c" );