Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
wine
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Package Registry
Container Registry
Model registry
Operate
Terraform modules
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Alexey Alyaev
wine
Commits
38775875
Commit
38775875
authored
9 years ago
by
Nikolay Sivov
Committed by
Alexandre Julliard
9 years ago
Browse files
Options
Downloads
Patches
Plain Diff
dwrite: Initial implementation of Draw().
parent
40a311c8
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
dlls/dwrite/layout.c
+269
-20
269 additions, 20 deletions
dlls/dwrite/layout.c
dlls/dwrite/tests/layout.c
+0
-1
0 additions, 1 deletion
dlls/dwrite/tests/layout.c
with
269 additions
and
21 deletions
dlls/dwrite/layout.c
+
269
−
20
View file @
38775875
...
...
@@ -139,15 +139,27 @@ struct layout_run {
}
u
;
};
struct
layout_effective_run
{
struct
list
entry
;
const
struct
layout_run
*
run
;
/* nominal run this one is based on */
UINT32
start
;
/* relative text position, 0 means first text position of a nominal run */
UINT32
length
;
/* length in codepoints that this run covers */
UINT32
glyphcount
;
/* total glyph count in this run */
FLOAT
origin_x
;
/* baseline X position */
FLOAT
origin_y
;
/* baseline Y position */
UINT16
*
clustermap
;
/* effective clustermap, allocated separately, is not reused from nominal map */
};
struct
layout_cluster
{
const
struct
layout_run
*
run
;
/* link to run this cluster belongs to */
const
struct
layout_run
*
run
;
/* link to
nominal
run this cluster belongs to */
UINT32
position
;
/* relative to run, first cluster has 0 position */
};
enum
layout_recompute_mask
{
RECOMPUTE_NOMINAL_RUNS
=
1
<<
0
,
RECOMPUTE_MINIMAL_WIDTH
=
1
<<
1
,
RECOMPUTE_EVERYTHING
=
0xffff
RECOMPUTE_NOMINAL_RUNS
=
1
<<
0
,
RECOMPUTE_MINIMAL_WIDTH
=
1
<<
1
,
RECOMPUTE_EFFECTIVE_RUNS
=
1
<<
2
,
RECOMPUTE_EVERYTHING
=
0xffff
};
struct
dwrite_textlayout
{
...
...
@@ -163,6 +175,7 @@ struct dwrite_textlayout {
FLOAT
maxwidth
;
FLOAT
maxheight
;
struct
list
ranges
;
struct
list
eruns
;
struct
list
runs
;
USHORT
recompute
;
...
...
@@ -171,9 +184,13 @@ struct dwrite_textlayout {
struct
layout_cluster
*
clusters
;
DWRITE_CLUSTER_METRICS
*
clustermetrics
;
UINT32
cluster
s
_count
;
UINT32
cluster_count
;
FLOAT
minwidth
;
DWRITE_LINE_METRICS
*
lines
;
UINT32
line_count
;
UINT32
line_alloc
;
/* gdi-compatible layout specifics */
BOOL
gdicompatible
;
FLOAT
pixels_per_dip
;
...
...
@@ -305,6 +322,16 @@ static void free_layout_runs(struct dwrite_textlayout *layout)
}
}
static
void
free_layout_eruns
(
struct
dwrite_textlayout
*
layout
)
{
struct
layout_effective_run
*
cur
,
*
cur2
;
LIST_FOR_EACH_ENTRY_SAFE
(
cur
,
cur2
,
&
layout
->
eruns
,
struct
layout_effective_run
,
entry
)
{
list_remove
(
&
cur
->
entry
);
heap_free
(
cur
->
clustermap
);
heap_free
(
cur
);
}
}
/* Used to resolve break condition by forcing stronger condition over weaker. */
static
inline
DWRITE_BREAK_CONDITION
override_break_condition
(
DWRITE_BREAK_CONDITION
existingbreak
,
DWRITE_BREAK_CONDITION
newbreak
)
{
...
...
@@ -480,7 +507,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
return
E_OUTOFMEMORY
;
}
}
layout
->
cluster
s
_count
=
0
;
layout
->
cluster_count
=
0
;
hr
=
get_textanalyzer
(
&
analyzer
);
if
(
FAILED
(
hr
))
...
...
@@ -672,7 +699,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
}
if
(
hr
==
S_OK
)
layout
->
cluster
s
_count
=
cluster
;
layout
->
cluster_count
=
cluster
;
IDWriteTextAnalyzer_Release
(
analyzer
);
return
hr
;
...
...
@@ -725,6 +752,163 @@ static HRESULT layout_compute(struct dwrite_textlayout *layout)
return
hr
;
}
static
HRESULT
layout_add_effective_run
(
struct
dwrite_textlayout
*
layout
,
const
struct
layout_run
*
r
,
UINT32
start
,
UINT32
length
,
FLOAT
origin_x
)
{
struct
layout_effective_run
*
run
;
UINT32
i
;
run
=
heap_alloc
(
sizeof
(
*
run
));
if
(
!
run
)
return
E_OUTOFMEMORY
;
run
->
clustermap
=
heap_alloc
(
sizeof
(
UINT16
)
*
length
);
if
(
!
run
->
clustermap
)
{
heap_free
(
run
);
return
E_OUTOFMEMORY
;
}
run
->
run
=
r
;
run
->
start
=
start
;
run
->
length
=
length
;
run
->
origin_x
=
origin_x
;
run
->
origin_y
=
0
.
0
;
/* FIXME: set after line is built */
/* trim from the left */
run
->
glyphcount
=
r
->
u
.
regular
.
run
.
glyphCount
-
r
->
u
.
regular
.
clustermap
[
start
];
/* trim from the right */
if
(
length
<
r
->
u
.
regular
.
descr
.
stringLength
)
run
->
glyphcount
-=
r
->
u
.
regular
.
clustermap
[
start
+
length
];
/* cluster map needs to be shifted */
for
(
i
=
0
;
i
<
length
;
i
++
)
run
->
clustermap
[
i
]
=
r
->
u
.
regular
.
clustermap
[
start
]
-
start
;
list_add_tail
(
&
layout
->
eruns
,
&
run
->
entry
);
return
S_OK
;
}
static
HRESULT
layout_set_line_metrics
(
struct
dwrite_textlayout
*
layout
,
DWRITE_LINE_METRICS
*
metrics
,
UINT32
*
line
)
{
if
(
!
layout
->
line_alloc
)
{
layout
->
line_alloc
=
5
;
layout
->
lines
=
heap_alloc
(
layout
->
line_alloc
*
sizeof
(
*
layout
->
lines
));
if
(
!
layout
->
lines
)
return
E_OUTOFMEMORY
;
}
if
(
layout
->
line_count
==
layout
->
line_alloc
)
{
DWRITE_LINE_METRICS
*
l
=
heap_realloc
(
layout
->
lines
,
layout
->
line_alloc
*
2
*
sizeof
(
*
layout
->
lines
));
if
(
!
l
)
return
E_OUTOFMEMORY
;
layout
->
lines
=
l
;
layout
->
line_alloc
*=
2
;
}
layout
->
lines
[
*
line
]
=
*
metrics
;
*
line
+=
1
;
return
S_OK
;
}
static
inline
FLOAT
get_cluster_range_width
(
struct
dwrite_textlayout
*
layout
,
UINT32
start
,
UINT32
end
)
{
FLOAT
width
=
0
.
0
;
for
(;
start
<
end
;
start
++
)
width
+=
layout
->
clustermetrics
[
start
].
width
;
return
width
;
}
static
HRESULT
layout_compute_effective_runs
(
struct
dwrite_textlayout
*
layout
)
{
DWRITE_LINE_METRICS
metrics
;
const
struct
layout_run
*
run
;
FLOAT
width
,
origin_x
;
UINT32
i
,
start
,
line
;
BOOL
can_wrap_after
;
HRESULT
hr
;
if
(
!
(
layout
->
recompute
&
RECOMPUTE_EFFECTIVE_RUNS
))
return
S_OK
;
hr
=
layout_compute
(
layout
);
if
(
FAILED
(
hr
))
return
hr
;
layout
->
line_count
=
0
;
origin_x
=
0
.
0
;
line
=
0
;
run
=
layout
->
clusters
[
0
].
run
;
can_wrap_after
=
layout
->
clustermetrics
[
0
].
canWrapLineAfter
;
memset
(
&
metrics
,
0
,
sizeof
(
metrics
));
for
(
i
=
0
,
start
=
0
,
width
=
0
.
0
;
i
<
layout
->
cluster_count
;
i
++
)
{
if
(
run
!=
layout
->
clusters
[
i
].
run
)
{
/* switched to next nominal run */
hr
=
layout_add_effective_run
(
layout
,
run
,
start
,
i
-
start
,
origin_x
);
if
(
FAILED
(
hr
))
return
hr
;
origin_x
+=
get_cluster_range_width
(
layout
,
start
,
i
);
start
=
i
;
}
/* check if we got new line */
if
(((
can_wrap_after
&&
(
width
+
layout
->
clustermetrics
[
i
].
width
>
layout
->
maxwidth
))
||
layout
->
clustermetrics
[
i
].
isNewline
||
/* always wrap on new line */
i
==
layout
->
cluster_count
-
1
))
/* end of the text */
{
UINT32
strlength
=
metrics
.
length
,
index
=
i
;
if
(
i
>
start
)
{
hr
=
layout_add_effective_run
(
layout
,
run
,
start
,
i
-
start
,
origin_x
);
if
(
FAILED
(
hr
))
return
hr
;
/* we don't need to update origin for next run as we're going to wrap */
}
/* take a look at clusters we got for this line in reverse order */
while
(
strlength
)
{
DWRITE_CLUSTER_METRICS
*
cluster
=
&
layout
->
clustermetrics
[
index
];
if
(
!
cluster
->
isNewline
&&
!
cluster
->
isWhitespace
)
break
;
if
(
cluster
->
isNewline
)
{
metrics
.
trailingWhitespaceLength
+=
cluster
->
length
;
metrics
.
newlineLength
+=
cluster
->
length
;
}
if
(
cluster
->
isWhitespace
)
metrics
.
trailingWhitespaceLength
+=
cluster
->
length
;
strlength
-=
cluster
->
length
;
index
--
;
}
metrics
.
height
=
0
.
0
;
/* FIXME */
metrics
.
baseline
=
0
.
0
;
/* FIXME */
metrics
.
isTrimmed
=
width
>
layout
->
maxwidth
;
hr
=
layout_set_line_metrics
(
layout
,
&
metrics
,
&
line
);
if
(
FAILED
(
hr
))
return
hr
;
width
=
layout
->
clustermetrics
[
i
].
width
;
memset
(
&
metrics
,
0
,
sizeof
(
metrics
));
origin_x
=
0
.
0
;
start
=
i
;
}
else
{
metrics
.
length
+=
layout
->
clustermetrics
[
i
].
length
;
width
+=
layout
->
clustermetrics
[
i
].
width
;
}
can_wrap_after
=
layout
->
clustermetrics
[
i
].
canWrapLineAfter
;
}
layout
->
line_count
=
line
;
layout
->
recompute
&=
~
RECOMPUTE_EFFECTIVE_RUNS
;
return
hr
;
}
/* To be used in IDWriteTextLayout methods to validate and fix passed range */
static
inline
BOOL
validate_text_range
(
struct
dwrite_textlayout
*
layout
,
DWRITE_TEXT_RANGE
*
r
)
{
...
...
@@ -1222,12 +1406,14 @@ static ULONG WINAPI dwritetextlayout_Release(IDWriteTextLayout2 *iface)
if
(
!
ref
)
{
free_layout_ranges_list
(
This
);
free_layout_eruns
(
This
);
free_layout_runs
(
This
);
release_format_data
(
&
This
->
format
);
heap_free
(
This
->
nominal_breakpoints
);
heap_free
(
This
->
actual_breakpoints
);
heap_free
(
This
->
clustermetrics
);
heap_free
(
This
->
clusters
);
heap_free
(
This
->
lines
);
heap_free
(
This
->
str
);
heap_free
(
This
);
}
...
...
@@ -1791,19 +1977,78 @@ static HRESULT WINAPI dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout2 *
}
static
HRESULT
WINAPI
dwritetextlayout_Draw
(
IDWriteTextLayout2
*
iface
,
void
*
context
,
IDWriteTextRenderer
*
renderer
,
FLOAT
origin
X
,
FLOAT
origin
Y
)
void
*
context
,
IDWriteTextRenderer
*
renderer
,
FLOAT
origin
_x
,
FLOAT
origin
_y
)
{
struct
dwrite_textlayout
*
This
=
impl_from_IDWriteTextLayout2
(
iface
);
FIXME
(
"(%p)->(%p %p %f %f): stub
\n
"
,
This
,
context
,
renderer
,
originX
,
originY
);
return
E_NOTIMPL
;
struct
layout_effective_run
*
run
;
HRESULT
hr
;
TRACE
(
"(%p)->(%p %p %.2f %.2f)
\n
"
,
This
,
context
,
renderer
,
origin_x
,
origin_y
);
hr
=
layout_compute_effective_runs
(
This
);
if
(
FAILED
(
hr
))
return
hr
;
/* 1. Regular runs */
LIST_FOR_EACH_ENTRY
(
run
,
&
This
->
eruns
,
struct
layout_effective_run
,
entry
)
{
const
struct
regular_layout_run
*
regular
=
&
run
->
run
->
u
.
regular
;
UINT32
start_glyph
=
regular
->
clustermap
[
run
->
start
];
DWRITE_GLYPH_RUN_DESCRIPTION
descr
;
DWRITE_GLYPH_RUN
glyph_run
;
/* Everything but cluster map will be reused from nominal run, as we only need
to adjust some pointers. Cluster map however is rebuilt when effective run is added,
it can't be reused because it has to start with 0 index for each reported run. */
glyph_run
=
regular
->
run
;
glyph_run
.
glyphCount
=
run
->
glyphcount
;
/* fixup glyph data arrays */
glyph_run
.
glyphIndices
+=
start_glyph
;
glyph_run
.
glyphAdvances
+=
start_glyph
;
glyph_run
.
glyphOffsets
+=
start_glyph
;
/* description */
descr
=
regular
->
descr
;
descr
.
stringLength
=
run
->
length
;
descr
.
string
+=
run
->
start
;
descr
.
clusterMap
=
run
->
clustermap
;
descr
.
textPosition
+=
run
->
start
;
/* return value is ignored */
IDWriteTextRenderer_DrawGlyphRun
(
renderer
,
context
,
run
->
origin_x
+
origin_x
,
run
->
origin_y
+
origin_y
,
DWRITE_MEASURING_MODE_NATURAL
,
&
glyph_run
,
&
descr
,
NULL
/* FIXME */
);
}
/* TODO: 2. Inline objects */
/* TODO: 3. Underlines */
/* TODO: 4. Strikethrough */
return
S_OK
;
}
static
HRESULT
WINAPI
dwritetextlayout_GetLineMetrics
(
IDWriteTextLayout2
*
iface
,
DWRITE_LINE_METRICS
*
metrics
,
UINT32
max_count
,
UINT32
*
actual_
count
)
DWRITE_LINE_METRICS
*
metrics
,
UINT32
max_count
,
UINT32
*
count
)
{
struct
dwrite_textlayout
*
This
=
impl_from_IDWriteTextLayout2
(
iface
);
FIXME
(
"(%p)->(%p %u %p): stub
\n
"
,
This
,
metrics
,
max_count
,
actual_count
);
return
E_NOTIMPL
;
HRESULT
hr
;
TRACE
(
"(%p)->(%p %u %p)
\n
"
,
This
,
metrics
,
max_count
,
count
);
hr
=
layout_compute_effective_runs
(
This
);
if
(
FAILED
(
hr
))
return
hr
;
if
(
metrics
)
memcpy
(
metrics
,
This
->
lines
,
sizeof
(
DWRITE_LINE_METRICS
)
*
min
(
max_count
,
This
->
line_count
));
*
count
=
This
->
line_count
;
return
max_count
>=
This
->
line_count
?
S_OK
:
E_NOT_SUFFICIENT_BUFFER
;
}
static
HRESULT
WINAPI
dwritetextlayout_GetMetrics
(
IDWriteTextLayout2
*
iface
,
DWRITE_TEXT_METRICS
*
metrics
)
...
...
@@ -1841,10 +2086,10 @@ static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *ifa
return
hr
;
if
(
metrics
)
memcpy
(
metrics
,
This
->
clustermetrics
,
sizeof
(
DWRITE_CLUSTER_METRICS
)
*
min
(
max_count
,
This
->
cluster
s
_count
));
memcpy
(
metrics
,
This
->
clustermetrics
,
sizeof
(
DWRITE_CLUSTER_METRICS
)
*
min
(
max_count
,
This
->
cluster_count
));
*
count
=
This
->
cluster
s
_count
;
return
max_count
>=
This
->
cluster
s
_count
?
S_OK
:
E_NOT_SUFFICIENT_BUFFER
;
*
count
=
This
->
cluster_count
;
return
max_count
>=
This
->
cluster_count
?
S_OK
:
E_NOT_SUFFICIENT_BUFFER
;
}
/* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
...
...
@@ -1852,10 +2097,10 @@ static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *ifa
static
inline
BOOL
is_terminal_cluster
(
struct
dwrite_textlayout
*
layout
,
UINT32
index
)
{
if
(
layout
->
clustermetrics
[
index
].
isWhitespace
||
layout
->
clustermetrics
[
index
].
isNewline
||
(
index
==
layout
->
cluster
s
_count
-
1
))
(
index
==
layout
->
cluster_count
-
1
))
return
TRUE
;
/* check next one */
return
(
index
<
layout
->
cluster
s
_count
-
1
)
&&
layout
->
clustermetrics
[
index
+
1
].
isWhitespace
;
return
(
index
<
layout
->
cluster_count
-
1
)
&&
layout
->
clustermetrics
[
index
+
1
].
isWhitespace
;
}
static
HRESULT
WINAPI
dwritetextlayout_DetermineMinWidth
(
IDWriteTextLayout2
*
iface
,
FLOAT
*
min_width
)
...
...
@@ -1878,7 +2123,7 @@ static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *ifa
if
(
FAILED
(
hr
))
return
hr
;
for
(
i
=
0
;
i
<
This
->
cluster
s
_count
;)
{
for
(
i
=
0
;
i
<
This
->
cluster_count
;)
{
if
(
is_terminal_cluster
(
This
,
i
))
{
width
=
This
->
clustermetrics
[
i
].
width
;
i
++
;
...
...
@@ -2739,10 +2984,14 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *
layout
->
recompute
=
RECOMPUTE_EVERYTHING
;
layout
->
nominal_breakpoints
=
NULL
;
layout
->
actual_breakpoints
=
NULL
;
layout
->
cluster
s
_count
=
0
;
layout
->
cluster_count
=
0
;
layout
->
clustermetrics
=
NULL
;
layout
->
clusters
=
NULL
;
layout
->
lines
=
NULL
;
layout
->
line_count
=
0
;
layout
->
line_alloc
=
0
;
layout
->
minwidth
=
0
.
0
;
list_init
(
&
layout
->
eruns
);
list_init
(
&
layout
->
runs
);
list_init
(
&
layout
->
ranges
);
memset
(
&
layout
->
format
,
0
,
sizeof
(
layout
->
format
));
...
...
This diff is collapsed.
Click to expand it.
dlls/dwrite/tests/layout.c
+
0
−
1
View file @
38775875
...
...
@@ -931,7 +931,6 @@ todo_wine
ok
(
hr
==
S_OK
,
"got 0x%08x
\n
"
,
hr
);
flush_sequence
(
sequences
,
RENDERER_ID
);
hr
=
IDWriteTextLayout_Draw
(
layout
,
NULL
,
&
testrenderer
,
0
.
0
,
0
.
0
);
todo_wine
ok
(
hr
==
S_OK
,
"got 0x%08x
\n
"
,
hr
);
ok_sequence
(
sequences
,
RENDERER_ID
,
draw_seq2
,
"draw test 2"
,
TRUE
);
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment