mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 08:39:34 +00:00
dwrite: Handle higher planes characters in line breaking logic.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
This commit is contained in:
parent
4a7a979e79
commit
28efff3855
|
@ -732,8 +732,16 @@ static HRESULT analyze_script(struct text_source_context *context, IDWriteTextAn
|
|||
return IDWriteTextAnalysisSink_SetScriptAnalysis(sink, pos, length, &sa);
|
||||
}
|
||||
|
||||
struct linebreaking_state {
|
||||
struct break_index
|
||||
{
|
||||
unsigned int index;
|
||||
UINT8 length;
|
||||
};
|
||||
|
||||
struct linebreaking_state
|
||||
{
|
||||
DWRITE_LINE_BREAKPOINT *breakpoints;
|
||||
struct break_index *breaks;
|
||||
UINT32 count;
|
||||
};
|
||||
|
||||
|
@ -804,19 +812,36 @@ static BOOL has_strong_condition(DWRITE_BREAK_CONDITION old_condition, DWRITE_BR
|
|||
static inline void set_break_condition(UINT32 pos, enum BreakConditionLocation location, DWRITE_BREAK_CONDITION condition,
|
||||
struct linebreaking_state *state)
|
||||
{
|
||||
if (location == BreakConditionBefore) {
|
||||
if (has_strong_condition(state->breakpoints[pos].breakConditionBefore, condition))
|
||||
unsigned int index = state->breaks[pos].index;
|
||||
|
||||
if (location == BreakConditionBefore)
|
||||
{
|
||||
if (has_strong_condition(state->breakpoints[index].breakConditionBefore, condition))
|
||||
return;
|
||||
state->breakpoints[pos].breakConditionBefore = condition;
|
||||
if (pos > 0)
|
||||
state->breakpoints[pos-1].breakConditionAfter = condition;
|
||||
state->breakpoints[index].breakConditionBefore = condition;
|
||||
if (pos)
|
||||
{
|
||||
--pos;
|
||||
|
||||
index = state->breaks[pos].index;
|
||||
if (state->breaks[pos].length > 1) index++;
|
||||
|
||||
state->breakpoints[index].breakConditionAfter = condition;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (has_strong_condition(state->breakpoints[pos].breakConditionAfter, condition))
|
||||
else
|
||||
{
|
||||
if (state->breaks[pos].length > 1) index++;
|
||||
|
||||
if (has_strong_condition(state->breakpoints[index].breakConditionAfter, condition))
|
||||
return;
|
||||
state->breakpoints[pos].breakConditionAfter = condition;
|
||||
state->breakpoints[index].breakConditionAfter = condition;
|
||||
|
||||
if (pos + 1 < state->count)
|
||||
state->breakpoints[pos+1].breakConditionBefore = condition;
|
||||
{
|
||||
index = state->breaks[pos + 1].index;
|
||||
state->breakpoints[index].breakConditionBefore = condition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -826,43 +851,72 @@ BOOL lb_is_newline_char(WCHAR ch)
|
|||
return c == b_LF || c == b_NL || c == b_CR || c == b_BK;
|
||||
}
|
||||
|
||||
static HRESULT analyze_linebreaks(const WCHAR *text, UINT32 count, DWRITE_LINE_BREAKPOINT *breakpoints)
|
||||
static HRESULT analyze_linebreaks(IDWriteTextAnalysisSource *source, UINT32 position,
|
||||
UINT32 length, DWRITE_LINE_BREAKPOINT *breakpoints)
|
||||
{
|
||||
struct text_source_context context;
|
||||
struct linebreaking_state state;
|
||||
struct break_index *breaks;
|
||||
unsigned int count, index;
|
||||
short *break_class;
|
||||
int i, j;
|
||||
int i = 0, j;
|
||||
HRESULT hr;
|
||||
|
||||
if (!(break_class = calloc(count, sizeof(*break_class))))
|
||||
if (FAILED(hr = text_source_context_init(&context, source, position, length))) return hr;
|
||||
|
||||
if (!(breaks = calloc(length, sizeof(*breaks))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
state.breakpoints = breakpoints;
|
||||
state.count = count;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (!(break_class = calloc(length, sizeof(*break_class))))
|
||||
{
|
||||
break_class[i] = get_table_entry_32(wine_linebreak_table, text[i]);
|
||||
free(breaks);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
breakpoints[i].breakConditionBefore = DWRITE_BREAK_CONDITION_NEUTRAL;
|
||||
breakpoints[i].breakConditionAfter = DWRITE_BREAK_CONDITION_NEUTRAL;
|
||||
breakpoints[i].isWhitespace = !!iswspace(text[i]);
|
||||
breakpoints[i].isSoftHyphen = text[i] == 0x00ad /* Unicode Soft Hyphen */;
|
||||
breakpoints[i].padding = 0;
|
||||
count = index = 0;
|
||||
while (!text_source_get_next_u32_char(&context))
|
||||
{
|
||||
break_class[count] = get_table_entry_32(wine_linebreak_table, context.ch);
|
||||
breaks[count].length = text_source_get_char_length(&context);
|
||||
breaks[count].index = index;
|
||||
|
||||
/* LB1 - resolve some classes. TODO: use external algorithms for these classes. */
|
||||
switch (break_class[i])
|
||||
switch (break_class[count])
|
||||
{
|
||||
case b_AI:
|
||||
case b_SA:
|
||||
case b_SG:
|
||||
case b_XX:
|
||||
break_class[i] = b_AL;
|
||||
break_class[count] = b_AL;
|
||||
break;
|
||||
case b_CJ:
|
||||
break_class[i] = b_NS;
|
||||
break_class[count] = b_NS;
|
||||
break;
|
||||
}
|
||||
|
||||
breakpoints[index].breakConditionBefore = DWRITE_BREAK_CONDITION_NEUTRAL;
|
||||
breakpoints[index].breakConditionAfter = DWRITE_BREAK_CONDITION_NEUTRAL;
|
||||
breakpoints[index].isWhitespace = context.ch < 0xffff ? !!iswspace(context.ch) : 0;
|
||||
breakpoints[index].isSoftHyphen = context.ch == 0x00ad /* Unicode Soft Hyphen */;
|
||||
breakpoints[index].padding = 0;
|
||||
++index;
|
||||
|
||||
if (breaks[count].length > 1)
|
||||
{
|
||||
breakpoints[index] = breakpoints[index - 1];
|
||||
/* Never break in surrogate pairs. */
|
||||
breakpoints[index - 1].breakConditionAfter = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
|
||||
breakpoints[index].breakConditionBefore = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
|
||||
++index;
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
state.breakpoints = breakpoints;
|
||||
state.breaks = breaks;
|
||||
state.count = count;
|
||||
|
||||
/* LB2 - never break at the start */
|
||||
set_break_condition(0, BreakConditionBefore, DWRITE_BREAK_CONDITION_MAY_NOT_BREAK, &state);
|
||||
/* LB3 - always break at the end. */
|
||||
|
@ -1193,6 +1247,8 @@ static HRESULT analyze_linebreaks(const WCHAR *text, UINT32 count, DWRITE_LINE_B
|
|||
}
|
||||
|
||||
free(break_class);
|
||||
free(breaks);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -1332,64 +1388,23 @@ static HRESULT WINAPI dwritetextanalyzer_AnalyzeNumberSubstitution(IDWriteTextAn
|
|||
}
|
||||
|
||||
static HRESULT WINAPI dwritetextanalyzer_AnalyzeLineBreakpoints(IDWriteTextAnalyzer2 *iface,
|
||||
IDWriteTextAnalysisSource* source, UINT32 position, UINT32 length, IDWriteTextAnalysisSink* sink)
|
||||
IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length, IDWriteTextAnalysisSink *sink)
|
||||
{
|
||||
DWRITE_LINE_BREAKPOINT *breakpoints = NULL;
|
||||
WCHAR *buff = NULL;
|
||||
const WCHAR *text;
|
||||
DWRITE_LINE_BREAKPOINT *breakpoints;
|
||||
HRESULT hr;
|
||||
UINT32 len;
|
||||
|
||||
TRACE("%p, %u, %u, %p.\n", source, position, length, sink);
|
||||
|
||||
if (length == 0)
|
||||
if (!length)
|
||||
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;
|
||||
|
||||
if (!(buff = calloc(length, sizeof(*buff))))
|
||||
return E_OUTOFMEMORY;
|
||||
if (text)
|
||||
memcpy(buff, text, len*sizeof(WCHAR));
|
||||
read = len;
|
||||
|
||||
while (read < length && text) {
|
||||
text = NULL;
|
||||
len = 0;
|
||||
hr = IDWriteTextAnalysisSource_GetTextAtPosition(source, position+read, &text, &len);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
if (!text)
|
||||
break;
|
||||
memcpy(&buff[read], text, min(len, length-read)*sizeof(WCHAR));
|
||||
read += len;
|
||||
}
|
||||
|
||||
text = buff;
|
||||
}
|
||||
|
||||
if (!(breakpoints = calloc(length, sizeof(*breakpoints))))
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
hr = analyze_linebreaks(text, length, breakpoints);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
if (SUCCEEDED(hr = analyze_linebreaks(source, position, length, breakpoints)))
|
||||
hr = IDWriteTextAnalysisSink_SetLineBreakpoints(sink, position, length, breakpoints);
|
||||
|
||||
hr = IDWriteTextAnalysisSink_SetLineBreakpoints(sink, position, length, breakpoints);
|
||||
|
||||
done:
|
||||
free(breakpoints);
|
||||
free(buff);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue