Nikolay Sivov : dwrite: Split runs according to BiDi levels.
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Dec 29 15:42:42 CST 2014
Module: wine
Branch: master
Commit: ac4c85ea87b97f7a498514a8b658238daa25c7c2
URL: http://source.winehq.org/git/wine.git/?a=commit;h=ac4c85ea87b97f7a498514a8b658238daa25c7c2
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Thu Dec 25 13:34:35 2014 +0300
dwrite: Split runs according to BiDi levels.
---
dlls/dwrite/layout.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 86 insertions(+), 1 deletion(-)
diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 583f2eb..5b23a0c 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -26,6 +26,7 @@
#include "winbase.h"
#include "wingdi.h"
#include "dwrite_private.h"
+#include "scripts.h"
#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
@@ -101,6 +102,7 @@ struct layout_range {
struct layout_run {
struct list entry;
DWRITE_GLYPH_RUN_DESCRIPTION descr;
+ DWRITE_GLYPH_RUN run;
DWRITE_SCRIPT_ANALYSIS sa;
};
@@ -198,6 +200,18 @@ static struct layout_run *alloc_layout_run(void)
ret->descr.clusterMap = NULL;
ret->descr.textPosition = 0;
+ ret->run.fontFace = NULL;
+ ret->run.fontEmSize = 0.0;
+ ret->run.glyphCount = 0;
+ ret->run.glyphIndices = NULL;
+ ret->run.glyphAdvances = NULL;
+ ret->run.glyphOffsets = NULL;
+ ret->run.isSideways = FALSE;
+ ret->run.bidiLevel = 0;
+
+ ret->sa.script = Script_Unknown;
+ ret->sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
+
return ret;
}
@@ -227,10 +241,17 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
if (cur->object)
continue;
+ /* initial splitting by script */
hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &layout->IDWriteTextAnalysisSource_iface,
cur->range.startPosition, cur->range.length, &layout->IDWriteTextAnalysisSink_iface);
if (FAILED(hr))
break;
+
+ /* this splits it further */
+ hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, &layout->IDWriteTextAnalysisSource_iface,
+ cur->range.startPosition, cur->range.length, &layout->IDWriteTextAnalysisSink_iface);
+ if (FAILED(hr))
+ break;
}
IDWriteTextAnalyzer_Release(analyzer);
@@ -245,6 +266,16 @@ static HRESULT layout_compute(struct dwrite_textlayout *layout)
return S_OK;
hr = layout_compute_runs(layout);
+
+ if (TRACE_ON(dwrite)) {
+ struct layout_run *cur;
+
+ LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
+ TRACE("run [%u,%u], len %u, bidilevel %u\n", cur->descr.textPosition, cur->descr.textPosition+cur->descr.stringLength-1,
+ cur->descr.stringLength, cur->run.bidiLevel);
+ }
+ }
+
layout->recompute = FALSE;
return hr;
}
@@ -1550,7 +1581,61 @@ static HRESULT WINAPI dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalys
static HRESULT WINAPI dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink *iface, UINT32 position,
UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
{
- return E_NOTIMPL;
+ struct dwrite_textlayout *layout = impl_from_IDWriteTextAnalysisSink(iface);
+ struct layout_run *cur;
+
+ LIST_FOR_EACH_ENTRY(cur, &layout->runs, struct layout_run, entry) {
+ struct layout_run *run, *run2;
+
+ /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
+ if (position < cur->descr.textPosition || position > cur->descr.textPosition + cur->descr.stringLength)
+ continue;
+
+ /* full hit - just set run level */
+ if (cur->descr.textPosition == position && cur->descr.stringLength == length) {
+ cur->run.bidiLevel = resolvedLevel;
+ break;
+ }
+
+ /* current run is fully covered, move to next one */
+ if (cur->descr.textPosition == position && cur->descr.stringLength < length) {
+ cur->run.bidiLevel = resolvedLevel;
+ position += cur->descr.stringLength;
+ length -= cur->descr.stringLength;
+ continue;
+ }
+
+ /* now starting point is in a run, so it splits it */
+ run = alloc_layout_run();
+ if (!run)
+ return E_OUTOFMEMORY;
+
+ *run = *cur;
+ run->descr.textPosition = position;
+ run->descr.stringLength = cur->descr.stringLength - position + cur->descr.textPosition;
+ run->run.bidiLevel = resolvedLevel;
+ cur->descr.stringLength -= position - cur->descr.textPosition;
+
+ list_add_after(&cur->entry, &run->entry);
+
+ if (position + length == run->descr.textPosition + run->descr.stringLength)
+ break;
+
+ /* split second time */
+ run2 = alloc_layout_run();
+ if (!run2)
+ return E_OUTOFMEMORY;
+
+ *run2 = *cur;
+ run2->descr.textPosition = run->descr.textPosition + run->descr.stringLength;
+ run2->descr.stringLength = cur->descr.textPosition + cur->descr.stringLength - position - length;
+ run->descr.stringLength -= run2->descr.stringLength;
+
+ list_add_after(&run->entry, &run2->entry);
+ break;
+ }
+
+ return S_OK;
}
static HRESULT WINAPI dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
More information about the wine-cvs
mailing list