2 * Copyright 2012, 2014-2021 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "dwrite_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
33 enum layout_range_attr_kind
{
34 LAYOUT_RANGE_ATTR_WEIGHT
,
35 LAYOUT_RANGE_ATTR_STYLE
,
36 LAYOUT_RANGE_ATTR_STRETCH
,
37 LAYOUT_RANGE_ATTR_FONTSIZE
,
38 LAYOUT_RANGE_ATTR_EFFECT
,
39 LAYOUT_RANGE_ATTR_INLINE
,
40 LAYOUT_RANGE_ATTR_UNDERLINE
,
41 LAYOUT_RANGE_ATTR_STRIKETHROUGH
,
42 LAYOUT_RANGE_ATTR_PAIR_KERNING
,
43 LAYOUT_RANGE_ATTR_FONTCOLL
,
44 LAYOUT_RANGE_ATTR_LOCALE
,
45 LAYOUT_RANGE_ATTR_FONTFAMILY
,
46 LAYOUT_RANGE_ATTR_SPACING
,
47 LAYOUT_RANGE_ATTR_TYPOGRAPHY
50 struct layout_range_attr_value
{
51 DWRITE_TEXT_RANGE range
;
53 DWRITE_FONT_WEIGHT weight
;
54 DWRITE_FONT_STYLE style
;
55 DWRITE_FONT_STRETCH stretch
;
57 IDWriteInlineObject
*object
;
62 IDWriteFontCollection
*collection
;
64 const WCHAR
*fontfamily
;
70 IDWriteTypography
*typography
;
74 enum layout_range_kind
{
76 LAYOUT_RANGE_UNDERLINE
,
77 LAYOUT_RANGE_STRIKETHROUGH
,
80 LAYOUT_RANGE_TYPOGRAPHY
83 struct layout_range_header
{
85 enum layout_range_kind kind
;
86 DWRITE_TEXT_RANGE range
;
90 struct layout_range_header h
;
91 DWRITE_FONT_WEIGHT weight
;
92 DWRITE_FONT_STYLE style
;
94 DWRITE_FONT_STRETCH stretch
;
95 IDWriteInlineObject
*object
;
97 IDWriteFontCollection
*collection
;
98 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
102 struct layout_range_bool
{
103 struct layout_range_header h
;
107 struct layout_range_iface
{
108 struct layout_range_header h
;
112 struct layout_range_spacing
{
113 struct layout_range_header h
;
119 enum layout_run_kind
{
124 struct inline_object_run
{
125 IDWriteInlineObject
*object
;
129 struct regular_layout_run
{
130 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
131 DWRITE_GLYPH_RUN run
;
132 DWRITE_SCRIPT_ANALYSIS sa
;
136 DWRITE_GLYPH_OFFSET
*offsets
;
137 UINT32 glyphcount
; /* actual glyph count after shaping, not necessarily the same as reported to Draw() */
143 enum layout_run_kind kind
;
146 struct inline_object_run object
;
147 struct regular_layout_run regular
;
151 unsigned int start_position
; /* run text position in range [0, layout-text-length) */
154 struct layout_effective_run
{
156 const struct layout_run
*run
; /* nominal run this one is based on */
157 UINT32 start
; /* relative text position, 0 means first text position of a nominal run */
158 UINT32 length
; /* length in codepoints that this run covers */
159 UINT32 glyphcount
; /* total glyph count in this run */
160 IUnknown
*effect
; /* original reference is kept only at range level */
161 D2D1_POINT_2F origin
; /* baseline origin */
162 FLOAT align_dx
; /* adjustment from text alignment */
163 FLOAT width
; /* run width */
164 UINT16
*clustermap
; /* effective clustermap, allocated separately, is not reused from nominal map */
165 UINT32 line
; /* 0-based line index in line metrics array */
166 BOOL underlined
; /* set if this run is underlined */
167 D2D1_RECT_F bbox
; /* ink run box, top == bottom means it wasn't estimated yet */
170 struct layout_effective_inline
{
172 IDWriteInlineObject
*object
; /* inline object, set explicitly or added when trimming a line */
173 IUnknown
*effect
; /* original reference is kept only at range level */
175 D2D1_POINT_2F origin
; /* left top corner */
176 FLOAT align_dx
; /* adjustment from text alignment */
177 FLOAT width
; /* object width as it's reported it */
178 BOOL is_sideways
; /* vertical flow direction flag passed to Draw */
179 BOOL is_rtl
; /* bidi flag passed to Draw */
180 UINT32 line
; /* 0-based line index in line metrics array */
183 struct layout_underline
{
185 const struct layout_effective_run
*run
;
189 struct layout_strikethrough
{
191 const struct layout_effective_run
*run
;
192 DWRITE_STRIKETHROUGH s
;
195 struct layout_cluster
{
196 const struct layout_run
*run
; /* link to nominal run this cluster belongs to */
197 UINT32 position
; /* relative to run, first cluster has 0 position */
202 float height
; /* height based on content */
203 float baseline
; /* baseline based on content */
204 DWRITE_LINE_METRICS1 metrics
;
207 enum layout_recompute_mask
{
208 RECOMPUTE_CLUSTERS
= 1 << 0,
209 RECOMPUTE_MINIMAL_WIDTH
= 1 << 1,
210 RECOMPUTE_LINES
= 1 << 2,
211 RECOMPUTE_OVERHANGS
= 1 << 3,
212 RECOMPUTE_LINES_AND_OVERHANGS
= RECOMPUTE_LINES
| RECOMPUTE_OVERHANGS
,
213 RECOMPUTE_EVERYTHING
= 0xffff
216 struct dwrite_textlayout
218 IDWriteTextLayout4 IDWriteTextLayout4_iface
;
219 IDWriteTextFormat3 IDWriteTextFormat3_iface
;
220 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface
;
221 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface
;
224 IDWriteFactory7
*factory
;
228 struct dwrite_textformat_data format
;
229 struct list strike_ranges
;
230 struct list underline_ranges
;
231 struct list typographies
;
236 /* lists ready to use by Draw() */
238 struct list inlineobjects
;
239 struct list underlines
;
240 struct list strikethrough
;
243 DWRITE_LINE_BREAKPOINT
*nominal_breakpoints
;
244 DWRITE_LINE_BREAKPOINT
*actual_breakpoints
;
246 struct layout_cluster
*clusters
;
247 DWRITE_CLUSTER_METRICS
*clustermetrics
;
248 UINT32 cluster_count
;
251 struct layout_line
*lines
;
254 DWRITE_TEXT_METRICS1 metrics
;
255 DWRITE_OVERHANG_METRICS overhangs
;
257 DWRITE_MEASURING_MODE measuringmode
;
259 /* gdi-compatible layout specifics */
261 DWRITE_MATRIX transform
;
264 struct dwrite_typography
{
265 IDWriteTypography IDWriteTypography_iface
;
268 DWRITE_FONT_FEATURE
*features
;
273 static inline struct dwrite_textlayout
*impl_from_IDWriteTextLayout4(IDWriteTextLayout4
*iface
)
275 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextLayout4_iface
);
278 static inline struct dwrite_textlayout
*impl_from_IDWriteTextFormat3(IDWriteTextFormat3
*iface
)
280 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextFormat3_iface
);
283 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1
*iface
)
285 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSink1_iface
);
288 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1
*iface
)
290 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSource1_iface
);
293 static inline struct dwrite_typography
*impl_from_IDWriteTypography(IDWriteTypography
*iface
)
295 return CONTAINING_RECORD(iface
, struct dwrite_typography
, IDWriteTypography_iface
);
298 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION
*descr
)
300 return wine_dbg_sprintf("[%u,%u)", descr
->textPosition
, descr
->textPosition
+ descr
->stringLength
);
303 static inline BOOL
is_layout_gdi_compatible(struct dwrite_textlayout
*layout
)
305 return layout
->measuringmode
!= DWRITE_MEASURING_MODE_NATURAL
;
308 static BOOL
is_run_rtl(const struct layout_effective_run
*run
)
310 return run
->run
->u
.regular
.run
.bidiLevel
& 1;
313 static HRESULT
alloc_layout_run(enum layout_run_kind kind
, unsigned int start_position
,
314 struct layout_run
**run
)
316 if (!(*run
= calloc(1, sizeof(**run
))))
317 return E_OUTOFMEMORY
;
320 (*run
)->start_position
= start_position
;
325 static void free_layout_runs(struct dwrite_textlayout
*layout
)
327 struct layout_run
*cur
, *cur2
;
328 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->runs
, struct layout_run
, entry
)
330 list_remove(&cur
->entry
);
331 if (cur
->kind
== LAYOUT_RUN_REGULAR
)
333 if (cur
->u
.regular
.run
.fontFace
)
334 IDWriteFontFace_Release(cur
->u
.regular
.run
.fontFace
);
335 free(cur
->u
.regular
.glyphs
);
336 free(cur
->u
.regular
.clustermap
);
337 free(cur
->u
.regular
.advances
);
338 free(cur
->u
.regular
.offsets
);
344 static void free_layout_eruns(struct dwrite_textlayout
*layout
)
346 struct layout_effective_inline
*in
, *in2
;
347 struct layout_effective_run
*cur
, *cur2
;
348 struct layout_strikethrough
*s
, *s2
;
349 struct layout_underline
*u
, *u2
;
351 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->eruns
, struct layout_effective_run
, entry
)
353 list_remove(&cur
->entry
);
354 free(cur
->clustermap
);
358 LIST_FOR_EACH_ENTRY_SAFE(in
, in2
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
)
360 list_remove(&in
->entry
);
364 LIST_FOR_EACH_ENTRY_SAFE(u
, u2
, &layout
->underlines
, struct layout_underline
, entry
)
366 list_remove(&u
->entry
);
370 LIST_FOR_EACH_ENTRY_SAFE(s
, s2
, &layout
->strikethrough
, struct layout_strikethrough
, entry
)
372 list_remove(&s
->entry
);
377 /* Used to resolve break condition by forcing stronger condition over weaker. */
378 static inline DWRITE_BREAK_CONDITION
override_break_condition(DWRITE_BREAK_CONDITION existingbreak
, DWRITE_BREAK_CONDITION newbreak
)
380 switch (existingbreak
) {
381 case DWRITE_BREAK_CONDITION_NEUTRAL
:
383 case DWRITE_BREAK_CONDITION_CAN_BREAK
:
384 return newbreak
== DWRITE_BREAK_CONDITION_NEUTRAL
? existingbreak
: newbreak
;
385 /* let's keep stronger conditions as is */
386 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
:
387 case DWRITE_BREAK_CONDITION_MUST_BREAK
:
390 ERR("unknown break condition %d\n", existingbreak
);
393 return existingbreak
;
396 /* This helper should be used to get effective range length, in other words it returns number of text
397 positions from range starting point to the end of the range, limited by layout text length */
398 static inline UINT32
get_clipped_range_length(const struct dwrite_textlayout
*layout
, const struct layout_range
*range
)
400 if (range
->h
.range
.startPosition
+ range
->h
.range
.length
<= layout
->len
)
401 return range
->h
.range
.length
;
402 return layout
->len
- range
->h
.range
.startPosition
;
405 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
406 static HRESULT
layout_update_breakpoints_range(struct dwrite_textlayout
*layout
, const struct layout_range
*cur
)
408 DWRITE_BREAK_CONDITION before
, after
;
412 /* ignore returned conditions if failed */
413 hr
= IDWriteInlineObject_GetBreakConditions(cur
->object
, &before
, &after
);
415 after
= before
= DWRITE_BREAK_CONDITION_NEUTRAL
;
417 if (!layout
->actual_breakpoints
)
419 if (!(layout
->actual_breakpoints
= calloc(layout
->len
, sizeof(*layout
->actual_breakpoints
))))
420 return E_OUTOFMEMORY
;
421 memcpy(layout
->actual_breakpoints
, layout
->nominal_breakpoints
, sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
424 length
= get_clipped_range_length(layout
, cur
);
425 for (i
= cur
->h
.range
.startPosition
; i
< length
+ cur
->h
.range
.startPosition
; i
++) {
426 /* for first codepoint check if there's anything before it and update accordingly */
427 if (i
== cur
->h
.range
.startPosition
) {
429 layout
->actual_breakpoints
[i
].breakConditionBefore
= layout
->actual_breakpoints
[i
-1].breakConditionAfter
=
430 override_break_condition(layout
->actual_breakpoints
[i
-1].breakConditionAfter
, before
);
432 layout
->actual_breakpoints
[i
].breakConditionBefore
= before
;
433 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
435 /* similar check for last codepoint */
436 else if (i
== cur
->h
.range
.startPosition
+ length
- 1) {
437 if (i
== layout
->len
- 1)
438 layout
->actual_breakpoints
[i
].breakConditionAfter
= after
;
440 layout
->actual_breakpoints
[i
].breakConditionAfter
= layout
->actual_breakpoints
[i
+1].breakConditionBefore
=
441 override_break_condition(layout
->actual_breakpoints
[i
+1].breakConditionBefore
, after
);
442 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
444 /* for all positions within a range disable breaks */
446 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
447 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
450 layout
->actual_breakpoints
[i
].isWhitespace
= 0;
451 layout
->actual_breakpoints
[i
].isSoftHyphen
= 0;
457 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
459 struct layout_range
*cur
;
461 LIST_FOR_EACH_ENTRY(cur
, &layout
->ranges
, struct layout_range
, h
.entry
)
463 DWRITE_TEXT_RANGE
*r
= &cur
->h
.range
;
464 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
471 static struct layout_range_header
*get_layout_range_header_by_pos(struct list
*ranges
, UINT32 pos
)
473 struct layout_range_header
*cur
;
475 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
)
477 DWRITE_TEXT_RANGE
*r
= &cur
->range
;
478 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
485 static inline DWRITE_LINE_BREAKPOINT
get_effective_breakpoint(const struct dwrite_textlayout
*layout
, UINT32 pos
)
487 if (layout
->actual_breakpoints
)
488 return layout
->actual_breakpoints
[pos
];
489 return layout
->nominal_breakpoints
[pos
];
492 static inline void init_cluster_metrics(const struct dwrite_textlayout
*layout
, const struct regular_layout_run
*run
,
493 UINT16 start_glyph
, UINT16 stop_glyph
, UINT32 stop_position
, UINT16 length
, DWRITE_CLUSTER_METRICS
*metrics
)
495 UINT8 breakcondition
;
499 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
500 width as well; advances are already computed at this point and are not necessary zero. */
501 metrics
->width
= 0.0f
;
502 if (run
->run
.glyphCount
) {
503 for (j
= start_glyph
; j
< stop_glyph
; j
++)
504 metrics
->width
+= run
->run
.glyphAdvances
[j
];
506 metrics
->length
= length
;
508 position
= run
->descr
.textPosition
+ stop_position
;
509 if (stop_glyph
== run
->glyphcount
)
510 breakcondition
= get_effective_breakpoint(layout
, position
).breakConditionAfter
;
512 breakcondition
= get_effective_breakpoint(layout
, position
).breakConditionBefore
;
513 if (stop_position
) position
-= 1;
516 metrics
->canWrapLineAfter
= breakcondition
== DWRITE_BREAK_CONDITION_CAN_BREAK
||
517 breakcondition
== DWRITE_BREAK_CONDITION_MUST_BREAK
;
518 if (metrics
->length
== 1) {
519 DWRITE_LINE_BREAKPOINT bp
= get_effective_breakpoint(layout
, position
);
520 metrics
->isWhitespace
= bp
.isWhitespace
;
521 metrics
->isNewline
= metrics
->canWrapLineAfter
&& lb_is_newline_char(layout
->str
[position
]);
522 metrics
->isSoftHyphen
= bp
.isSoftHyphen
;
525 metrics
->isWhitespace
= 0;
526 metrics
->isNewline
= 0;
527 metrics
->isSoftHyphen
= 0;
529 metrics
->isRightToLeft
= run
->run
.bidiLevel
& 1;
530 metrics
->padding
= 0;
535 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
536 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
537 Note that there's no need to reallocate anything at this point as we allocate one cluster per
541 static void layout_set_cluster_metrics(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32
*cluster
)
543 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[*cluster
];
544 struct layout_cluster
*c
= &layout
->clusters
[*cluster
];
545 const struct regular_layout_run
*run
= &r
->u
.regular
;
548 assert(r
->kind
== LAYOUT_RUN_REGULAR
);
550 for (i
= 0; i
< run
->descr
.stringLength
; i
++) {
551 BOOL end
= i
== run
->descr
.stringLength
- 1;
553 if (run
->descr
.clusterMap
[start
] != run
->descr
.clusterMap
[i
]) {
554 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->descr
.clusterMap
[i
], i
,
566 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->glyphcount
, i
,
567 i
- start
+ 1, metrics
);
577 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
579 static void layout_get_font_metrics(struct dwrite_textlayout
*layout
, IDWriteFontFace
*fontface
, FLOAT emsize
,
580 DWRITE_FONT_METRICS
*fontmetrics
)
582 if (is_layout_gdi_compatible(layout
)) {
583 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(fontface
, emsize
, layout
->ppdip
, &layout
->transform
, fontmetrics
);
585 WARN("failed to get compat metrics, 0x%08lx\n", hr
);
588 IDWriteFontFace_GetMetrics(fontface
, fontmetrics
);
591 static void layout_get_font_height(FLOAT emsize
, DWRITE_FONT_METRICS
*fontmetrics
, FLOAT
*baseline
, FLOAT
*height
)
593 *baseline
= SCALE_FONT_METRIC(fontmetrics
->ascent
+ fontmetrics
->lineGap
, emsize
, fontmetrics
);
594 *height
= SCALE_FONT_METRIC(fontmetrics
->ascent
+ fontmetrics
->descent
+ fontmetrics
->lineGap
, emsize
, fontmetrics
);
597 static HRESULT
layout_itemize(struct dwrite_textlayout
*layout
)
599 IDWriteTextAnalyzer2
*analyzer
;
600 struct layout_range
*range
;
601 struct layout_run
*r
;
604 analyzer
= get_text_analyzer();
606 LIST_FOR_EACH_ENTRY(range
, &layout
->ranges
, struct layout_range
, h
.entry
) {
607 /* We don't care about ranges that don't contain any text. */
608 if (range
->h
.range
.startPosition
>= layout
->len
)
611 /* Inline objects override actual text in range. */
613 hr
= layout_update_breakpoints_range(layout
, range
);
617 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_INLINE
, range
->h
.range
.startPosition
, &r
)))
620 r
->u
.object
.object
= range
->object
;
621 r
->u
.object
.length
= get_clipped_range_length(layout
, range
);
622 list_add_tail(&layout
->runs
, &r
->entry
);
626 /* Initial splitting by script. */
627 hr
= IDWriteTextAnalyzer2_AnalyzeScript(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
628 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
),
629 (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
633 /* Splitting further by bidi levels. */
634 hr
= IDWriteTextAnalyzer2_AnalyzeBidi(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
635 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
),
636 (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
644 static HRESULT
layout_resolve_fonts(struct dwrite_textlayout
*layout
)
646 IDWriteFontCollection
*sys_collection
;
647 IDWriteFontFallback
*fallback
= NULL
;
648 struct layout_range
*range
;
649 struct layout_run
*r
;
652 if (FAILED(hr
= IDWriteFactory5_GetSystemFontCollection((IDWriteFactory5
*)layout
->factory
, FALSE
,
653 (IDWriteFontCollection1
**)&sys_collection
, FALSE
))) {
654 WARN("Failed to get system collection, hr %#lx.\n", hr
);
658 if (layout
->format
.fallback
) {
659 fallback
= layout
->format
.fallback
;
660 IDWriteFontFallback_AddRef(fallback
);
663 if (FAILED(hr
= IDWriteFactory7_GetSystemFontFallback(layout
->factory
, &fallback
))) {
664 WARN("Failed to get system fallback, hr %#lx.\n", hr
);
669 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
670 struct regular_layout_run
*run
= &r
->u
.regular
;
674 if (r
->kind
== LAYOUT_RUN_INLINE
)
677 range
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
);
679 if (run
->sa
.shapes
== DWRITE_SCRIPT_SHAPES_NO_VISUAL
) {
680 IDWriteFontCollection
*collection
;
682 collection
= range
->collection
? range
->collection
: sys_collection
;
684 if (FAILED(hr
= create_matching_font(collection
, range
->fontfamily
, range
->weight
, range
->style
,
685 range
->stretch
, &font
))) {
686 WARN("%s: failed to create matching font for non visual run, family %s, collection %p\n",
687 debugstr_rundescr(&run
->descr
), debugstr_w(range
->fontfamily
), range
->collection
);
691 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
692 IDWriteFont_Release(font
);
694 WARN("Failed to create font face, hr %#lx.\n", hr
);
698 run
->run
.fontEmSize
= range
->fontsize
;
702 length
= run
->descr
.stringLength
;
705 UINT32 mapped_length
;
710 hr
= IDWriteFontFallback_MapCharacters(fallback
,
711 (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
712 run
->descr
.textPosition
,
713 run
->descr
.stringLength
,
723 WARN("%s: failed to map family %s, collection %p, hr %#lx.\n", debugstr_rundescr(&run
->descr
),
724 debugstr_w(range
->fontfamily
), range
->collection
, hr
);
728 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
729 IDWriteFont_Release(font
);
731 WARN("Failed to create font face, hr %#lx.\n", hr
);
735 run
->run
.fontEmSize
= range
->fontsize
* scale
;
737 if (mapped_length
< length
)
739 struct regular_layout_run
*nextrun
;
740 struct layout_run
*nextr
;
742 /* keep mapped part for current run, add another run for the rest */
743 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_REGULAR
, 0, &nextr
)))
747 nextr
->start_position
= run
->descr
.textPosition
+ mapped_length
;
748 nextrun
= &nextr
->u
.regular
;
749 nextrun
->descr
.textPosition
= nextr
->start_position
;
750 nextrun
->descr
.stringLength
= run
->descr
.stringLength
- mapped_length
;
751 nextrun
->descr
.string
= &layout
->str
[nextrun
->descr
.textPosition
];
752 run
->descr
.stringLength
= mapped_length
;
753 list_add_after(&r
->entry
, &nextr
->entry
);
757 length
-= mapped_length
;
762 IDWriteFontCollection_Release(sys_collection
);
764 IDWriteFontFallback_Release(fallback
);
769 struct shaping_context
771 IDWriteTextAnalyzer2
*analyzer
;
772 struct regular_layout_run
*run
;
773 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
;
774 DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
;
778 DWRITE_TYPOGRAPHIC_FEATURES
**features
;
779 unsigned int *range_lengths
;
780 unsigned int range_count
;
784 static void layout_shape_clear_user_features_context(struct shaping_context
*context
)
788 for (i
= 0; i
< context
->user_features
.range_count
; ++i
)
790 free(context
->user_features
.features
[i
]->features
);
791 free(context
->user_features
.features
[i
]);
793 free(context
->user_features
.features
);
794 memset(&context
->user_features
, 0, sizeof(context
->user_features
));
797 static void layout_shape_clear_context(struct shaping_context
*context
)
799 layout_shape_clear_user_features_context(context
);
800 free(context
->glyph_props
);
801 free(context
->text_props
);
804 static HRESULT
layout_shape_add_empty_user_features_range(struct shaping_context
*context
, unsigned int length
)
806 DWRITE_TYPOGRAPHIC_FEATURES
*features
;
807 unsigned int r
= context
->user_features
.range_count
;
809 if (!(context
->user_features
.features
[r
] = calloc(1, sizeof(*features
))))
810 return E_OUTOFMEMORY
;
812 context
->user_features
.range_lengths
[r
] = length
;
813 context
->user_features
.range_count
++;
818 static HRESULT
layout_shape_get_user_features(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
820 unsigned int i
, f
, start
= 0, r
, covered_length
= 0, length
, feature_count
;
821 struct regular_layout_run
*run
= context
->run
;
822 DWRITE_TYPOGRAPHIC_FEATURES
*features
;
823 struct layout_range_iface
*range
;
824 IDWriteTypography
*typography
;
825 HRESULT hr
= E_OUTOFMEMORY
;
827 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->typographies
, 0);
828 if (range
->h
.range
.length
>= run
->descr
.stringLength
&& !range
->iface
)
831 if (!(context
->user_features
.features
= calloc(run
->descr
.stringLength
, sizeof(*context
->user_features
.features
))))
833 if (!(context
->user_features
.range_lengths
= calloc(run
->descr
.stringLength
, sizeof(*context
->user_features
.range_lengths
))))
836 for (i
= run
->descr
.textPosition
; i
< run
->descr
.textPosition
+ run
->descr
.stringLength
; ++i
)
838 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->typographies
, i
);
839 if (!range
|| !range
->iface
) continue;
841 typography
= (IDWriteTypography
*)range
->iface
;
842 feature_count
= IDWriteTypography_GetFontFeatureCount(typography
);
845 i
= range
->h
.range
.length
- i
+ 1;
851 if (FAILED(hr
= layout_shape_add_empty_user_features_range(context
, i
- start
))) goto failed
;
852 covered_length
+= i
- start
;
853 start
+= range
->h
.range
.length
;
856 r
= context
->user_features
.range_count
;
857 if (!(features
= context
->user_features
.features
[r
] = malloc(sizeof(*features
))))
860 context
->user_features
.range_lengths
[r
] = length
= min(run
->descr
.textPosition
+ run
->descr
.stringLength
,
861 range
->h
.range
.startPosition
+ range
->h
.range
.length
) - i
;
862 features
->featureCount
= feature_count
;
863 if (!(features
->features
= calloc(feature_count
, sizeof(*features
->features
))))
866 for (f
= 0; f
< feature_count
; ++f
)
868 IDWriteTypography_GetFontFeature(typography
, f
, &features
->features
[f
]);
872 covered_length
+= length
;
873 context
->user_features
.range_count
++;
876 if (context
->user_features
.range_count
&& covered_length
< run
->descr
.stringLength
)
878 if (FAILED(hr
= layout_shape_add_empty_user_features_range(context
, run
->descr
.stringLength
- covered_length
)))
886 if (!context
->user_features
.range_count
|| FAILED(hr
))
887 layout_shape_clear_user_features_context(context
);
892 static HRESULT
layout_shape_get_glyphs(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
894 struct regular_layout_run
*run
= context
->run
;
895 unsigned int max_count
;
898 run
->descr
.localeName
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
)->locale
;
899 run
->clustermap
= calloc(run
->descr
.stringLength
, sizeof(*run
->clustermap
));
900 if (!run
->clustermap
)
901 return E_OUTOFMEMORY
;
903 max_count
= 3 * run
->descr
.stringLength
/ 2 + 16;
904 run
->glyphs
= calloc(max_count
, sizeof(*run
->glyphs
));
906 return E_OUTOFMEMORY
;
908 context
->text_props
= calloc(run
->descr
.stringLength
, sizeof(*context
->text_props
));
909 context
->glyph_props
= calloc(max_count
, sizeof(*context
->glyph_props
));
910 if (!context
->text_props
|| !context
->glyph_props
)
911 return E_OUTOFMEMORY
;
913 if (FAILED(hr
= layout_shape_get_user_features(layout
, context
)))
918 hr
= IDWriteTextAnalyzer2_GetGlyphs(context
->analyzer
, run
->descr
.string
, run
->descr
.stringLength
, run
->run
.fontFace
,
919 run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
, NULL
/* FIXME */,
920 (const DWRITE_TYPOGRAPHIC_FEATURES
**)context
->user_features
.features
, context
->user_features
.range_lengths
,
921 context
->user_features
.range_count
, max_count
, run
->clustermap
, context
->text_props
, run
->glyphs
,
922 context
->glyph_props
, &run
->glyphcount
);
923 if (hr
== E_NOT_SUFFICIENT_BUFFER
)
926 free(context
->glyph_props
);
930 run
->glyphs
= calloc(max_count
, sizeof(*run
->glyphs
));
931 context
->glyph_props
= calloc(max_count
, sizeof(*context
->glyph_props
));
932 if (!run
->glyphs
|| !context
->glyph_props
)
945 WARN("%s: shaping failed, hr %#lx.\n", debugstr_rundescr(&run
->descr
), hr
);
947 run
->run
.glyphIndices
= run
->glyphs
;
948 run
->descr
.clusterMap
= run
->clustermap
;
953 static struct layout_range_spacing
*layout_get_next_spacing_range(struct dwrite_textlayout
*layout
,
954 struct layout_range_spacing
*cur
)
956 return (struct layout_range_spacing
*)LIST_ENTRY(list_next(&layout
->spacing
, &cur
->h
.entry
),
957 struct layout_range_header
, entry
);
960 static HRESULT
layout_shape_apply_character_spacing(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
962 struct regular_layout_run
*run
= context
->run
;
963 struct layout_range_spacing
*first
= NULL
, *last
= NULL
, *cur
;
964 unsigned int i
, length
, pos
, start
, end
, g0
, glyph_count
;
965 struct layout_range_header
*h
;
968 LIST_FOR_EACH_ENTRY(h
, &layout
->spacing
, struct layout_range_header
, entry
)
970 if ((h
->range
.startPosition
>= run
->descr
.textPosition
&&
971 h
->range
.startPosition
<= run
->descr
.textPosition
+ run
->descr
.stringLength
) ||
972 (run
->descr
.textPosition
>= h
->range
.startPosition
&&
973 run
->descr
.textPosition
<= h
->range
.startPosition
+ h
->range
.length
))
975 if (!first
) first
= last
= (struct layout_range_spacing
*)h
;
977 else if (last
) break;
979 if (!first
) return S_OK
;
981 if (!(clustermap
= calloc(run
->descr
.stringLength
, sizeof(*clustermap
))))
982 return E_OUTOFMEMORY
;
984 pos
= run
->descr
.textPosition
;
986 for (cur
= first
;; cur
= layout_get_next_spacing_range(layout
, cur
))
988 float leading
, trailing
;
990 /* The range current spacing settings apply to. */
991 start
= max(pos
, cur
->h
.range
.startPosition
);
992 pos
= end
= min(pos
+ run
->descr
.stringLength
, cur
->h
.range
.startPosition
+ cur
->h
.range
.length
);
994 /* Back to run-relative index. */
995 start
-= run
->descr
.textPosition
;
996 end
-= run
->descr
.textPosition
;
998 length
= end
- start
;
1000 g0
= run
->descr
.clusterMap
[start
];
1002 for (i
= 0; i
< length
; ++i
)
1003 clustermap
[i
] = run
->descr
.clusterMap
[start
+ i
] - run
->descr
.clusterMap
[start
];
1005 glyph_count
= (end
< run
->descr
.stringLength
? run
->descr
.clusterMap
[end
] + 1 : run
->glyphcount
) - g0
;
1007 /* There is no direction argument for spacing interface, we have to swap arguments here to get desired output. */
1008 if (run
->run
.bidiLevel
& 1)
1010 leading
= cur
->trailing
;
1011 trailing
= cur
->leading
;
1015 leading
= cur
->leading
;
1016 trailing
= cur
->trailing
;
1018 IDWriteTextAnalyzer2_ApplyCharacterSpacing(context
->analyzer
, leading
, trailing
, cur
->min_advance
,
1019 length
, glyph_count
, clustermap
, &run
->advances
[g0
], &run
->offsets
[g0
], &context
->glyph_props
[g0
],
1020 &run
->advances
[g0
], &run
->offsets
[g0
]);
1022 if (cur
== last
) break;
1030 static HRESULT
layout_shape_get_positions(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
1032 struct regular_layout_run
*run
= context
->run
;
1035 run
->advances
= calloc(run
->glyphcount
, sizeof(*run
->advances
));
1036 run
->offsets
= calloc(run
->glyphcount
, sizeof(*run
->offsets
));
1037 if (!run
->advances
|| !run
->offsets
)
1038 return E_OUTOFMEMORY
;
1040 /* Get advances and offsets. */
1041 if (is_layout_gdi_compatible(layout
))
1042 hr
= IDWriteTextAnalyzer2_GetGdiCompatibleGlyphPlacements(context
->analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
1043 context
->text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, context
->glyph_props
, run
->glyphcount
,
1044 run
->run
.fontFace
, run
->run
.fontEmSize
, layout
->ppdip
, &layout
->transform
,
1045 layout
->measuringmode
== DWRITE_MEASURING_MODE_GDI_NATURAL
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1,
1046 &run
->sa
, run
->descr
.localeName
, (const DWRITE_TYPOGRAPHIC_FEATURES
**)context
->user_features
.features
,
1047 context
->user_features
.range_lengths
, context
->user_features
.range_count
, run
->advances
, run
->offsets
);
1049 hr
= IDWriteTextAnalyzer2_GetGlyphPlacements(context
->analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
1050 context
->text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, context
->glyph_props
, run
->glyphcount
,
1051 run
->run
.fontFace
, run
->run
.fontEmSize
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
,
1052 run
->descr
.localeName
, (const DWRITE_TYPOGRAPHIC_FEATURES
**)context
->user_features
.features
,
1053 context
->user_features
.range_lengths
, context
->user_features
.range_count
, run
->advances
, run
->offsets
);
1057 memset(run
->advances
, 0, run
->glyphcount
* sizeof(*run
->advances
));
1058 memset(run
->offsets
, 0, run
->glyphcount
* sizeof(*run
->offsets
));
1059 WARN("%s: failed to get glyph placement info, hr %#lx.\n", debugstr_rundescr(&run
->descr
), hr
);
1063 hr
= layout_shape_apply_character_spacing(layout
, context
);
1065 run
->run
.glyphAdvances
= run
->advances
;
1066 run
->run
.glyphOffsets
= run
->offsets
;
1071 static HRESULT
layout_shape_run(struct dwrite_textlayout
*layout
, struct regular_layout_run
*run
)
1073 struct shaping_context context
= { 0 };
1076 context
.analyzer
= get_text_analyzer();
1079 if (SUCCEEDED(hr
= layout_shape_get_glyphs(layout
, &context
)))
1080 hr
= layout_shape_get_positions(layout
, &context
);
1082 layout_shape_clear_context(&context
);
1084 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1085 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero
1087 if (run
->sa
.shapes
== DWRITE_SCRIPT_SHAPES_NO_VISUAL
)
1088 run
->run
.glyphCount
= 0;
1090 run
->run
.glyphCount
= run
->glyphcount
;
1095 static HRESULT
layout_compute_runs(struct dwrite_textlayout
*layout
)
1097 struct layout_run
*r
;
1101 free_layout_eruns(layout
);
1102 free_layout_runs(layout
);
1104 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
1105 if (!layout
->clustermetrics
&& layout
->len
)
1107 layout
->clustermetrics
= calloc(layout
->len
, sizeof(*layout
->clustermetrics
));
1108 layout
->clusters
= calloc(layout
->len
, sizeof(*layout
->clusters
));
1109 if (!layout
->clustermetrics
|| !layout
->clusters
)
1111 free(layout
->clustermetrics
);
1112 free(layout
->clusters
);
1113 return E_OUTOFMEMORY
;
1116 layout
->cluster_count
= 0;
1118 if (FAILED(hr
= layout_itemize(layout
))) {
1119 WARN("Itemization failed, hr %#lx.\n", hr
);
1123 if (FAILED(hr
= layout_resolve_fonts(layout
))) {
1124 WARN("Failed to resolve layout fonts, hr %#lx.\n", hr
);
1129 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
1130 struct regular_layout_run
*run
= &r
->u
.regular
;
1131 DWRITE_FONT_METRICS fontmetrics
= { 0 };
1133 /* we need to do very little in case of inline objects */
1134 if (r
->kind
== LAYOUT_RUN_INLINE
) {
1135 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[cluster
];
1136 struct layout_cluster
*c
= &layout
->clusters
[cluster
];
1137 DWRITE_INLINE_OBJECT_METRICS inlinemetrics
;
1139 metrics
->width
= 0.0f
;
1140 metrics
->length
= r
->u
.object
.length
;
1141 metrics
->canWrapLineAfter
= 0;
1142 metrics
->isWhitespace
= 0;
1143 metrics
->isNewline
= 0;
1144 metrics
->isSoftHyphen
= 0;
1145 metrics
->isRightToLeft
= 0;
1146 metrics
->padding
= 0;
1148 c
->position
= 0; /* there's always one cluster per inline object, so 0 is valid value */
1151 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
1152 hr
= IDWriteInlineObject_GetMetrics(r
->u
.object
.object
, &inlinemetrics
);
1154 memset(&inlinemetrics
, 0, sizeof(inlinemetrics
));
1157 metrics
->width
= inlinemetrics
.width
;
1158 r
->baseline
= inlinemetrics
.baseline
;
1159 r
->height
= inlinemetrics
.height
;
1161 /* FIXME: use resolved breakpoints in this case too */
1166 if (FAILED(hr
= layout_shape_run(layout
, run
)))
1167 WARN("%s: shaping failed, hr %#lx.\n", debugstr_rundescr(&run
->descr
), hr
);
1169 /* baseline derived from font metrics */
1170 layout_get_font_metrics(layout
, run
->run
.fontFace
, run
->run
.fontEmSize
, &fontmetrics
);
1171 layout_get_font_height(run
->run
.fontEmSize
, &fontmetrics
, &r
->baseline
, &r
->height
);
1173 layout_set_cluster_metrics(layout
, r
, &cluster
);
1177 layout
->cluster_count
= cluster
;
1179 layout
->clustermetrics
[cluster
-1].canWrapLineAfter
= 1;
1185 static HRESULT
layout_compute(struct dwrite_textlayout
*layout
)
1189 if (!(layout
->recompute
& RECOMPUTE_CLUSTERS
))
1192 /* nominal breakpoints are evaluated only once, because string never changes */
1193 if (!layout
->nominal_breakpoints
)
1195 IDWriteTextAnalyzer2
*analyzer
;
1197 if (!(layout
->nominal_breakpoints
= calloc(layout
->len
, sizeof(*layout
->nominal_breakpoints
))))
1198 return E_OUTOFMEMORY
;
1200 analyzer
= get_text_analyzer();
1202 if (FAILED(hr
= IDWriteTextAnalyzer2_AnalyzeLineBreakpoints(analyzer
,
1203 (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
1204 0, layout
->len
, (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
)))
1205 WARN("Line breakpoints analysis failed, hr %#lx.\n", hr
);
1208 free(layout
->actual_breakpoints
);
1209 layout
->actual_breakpoints
= NULL
;
1211 hr
= layout_compute_runs(layout
);
1213 if (TRACE_ON(dwrite
)) {
1214 struct layout_run
*cur
;
1216 LIST_FOR_EACH_ENTRY(cur
, &layout
->runs
, struct layout_run
, entry
) {
1217 if (cur
->kind
== LAYOUT_RUN_INLINE
)
1218 TRACE("run inline object %p, len %u\n", cur
->u
.object
.object
, cur
->u
.object
.length
);
1220 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur
->u
.regular
.descr
.textPosition
, cur
->u
.regular
.descr
.textPosition
+
1221 cur
->u
.regular
.descr
.stringLength
-1, cur
->u
.regular
.descr
.stringLength
, cur
->u
.regular
.run
.bidiLevel
);
1225 layout
->recompute
&= ~RECOMPUTE_CLUSTERS
;
1229 static inline FLOAT
get_cluster_range_width(struct dwrite_textlayout
*layout
, UINT32 start
, UINT32 end
)
1232 for (; start
< end
; start
++)
1233 width
+= layout
->clustermetrics
[start
].width
;
1237 static inline IUnknown
*layout_get_effect_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1239 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->effects
, pos
);
1240 return ((struct layout_range_iface
*)h
)->iface
;
1243 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1244 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1245 one of the arguments, but it also happens for decorations, so every effective run has uniform
1246 underline/strikethough/effect tuple. */
1247 struct layout_final_splitting_params
{
1253 static inline BOOL
layout_get_strikethrough_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1255 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->strike_ranges
, pos
);
1256 return ((struct layout_range_bool
*)h
)->value
;
1259 static inline BOOL
layout_get_underline_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1261 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->underline_ranges
, pos
);
1262 return ((struct layout_range_bool
*)h
)->value
;
1265 static void layout_splitting_params_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
,
1266 struct layout_final_splitting_params
*params
)
1268 params
->strikethrough
= layout_get_strikethrough_from_pos(layout
, pos
);
1269 params
->underline
= layout_get_underline_from_pos(layout
, pos
);
1270 params
->effect
= layout_get_effect_from_pos(layout
, pos
);
1273 static BOOL
is_same_splitting_params(const struct layout_final_splitting_params
*left
,
1274 const struct layout_final_splitting_params
*right
)
1276 return left
->strikethrough
== right
->strikethrough
&&
1277 left
->underline
== right
->underline
&&
1278 left
->effect
== right
->effect
;
1281 static void layout_get_erun_font_metrics(struct dwrite_textlayout
*layout
, struct layout_effective_run
*erun
,
1282 DWRITE_FONT_METRICS
*metrics
)
1284 memset(metrics
, 0, sizeof(*metrics
));
1285 if (is_layout_gdi_compatible(layout
)) {
1286 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(
1287 erun
->run
->u
.regular
.run
.fontFace
,
1288 erun
->run
->u
.regular
.run
.fontEmSize
,
1293 WARN("failed to get font metrics, 0x%08lx\n", hr
);
1296 IDWriteFontFace_GetMetrics(erun
->run
->u
.regular
.run
.fontFace
, metrics
);
1299 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1300 'cluster_count' indicates how many clusters to add, including first one. */
1301 static HRESULT
layout_add_effective_run(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32 first_cluster
,
1302 UINT32 cluster_count
, UINT32 line
, FLOAT origin_x
, struct layout_final_splitting_params
*params
)
1304 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1305 UINT32 i
, start
, length
, last_cluster
;
1306 struct layout_effective_run
*run
;
1308 if (r
->kind
== LAYOUT_RUN_INLINE
)
1310 struct layout_effective_inline
*inlineobject
;
1312 if (!(inlineobject
= malloc(sizeof(*inlineobject
))))
1313 return E_OUTOFMEMORY
;
1315 inlineobject
->object
= r
->u
.object
.object
;
1316 inlineobject
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1317 inlineobject
->origin
.x
= is_rtl
? origin_x
- inlineobject
->width
: origin_x
;
1318 inlineobject
->origin
.y
= 0.0f
; /* set after line is built */
1319 inlineobject
->align_dx
= 0.0f
;
1320 inlineobject
->baseline
= r
->baseline
;
1322 /* It's not clear how these two are set, possibly directionality
1323 is derived from surrounding text (replaced text could have
1324 different ranges which differ in reading direction). */
1325 inlineobject
->is_sideways
= FALSE
;
1326 inlineobject
->is_rtl
= FALSE
;
1327 inlineobject
->line
= line
;
1329 /* effect assigned from start position and on is used for inline objects */
1330 inlineobject
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[first_cluster
].position
+
1331 layout
->clusters
[first_cluster
].run
->start_position
);
1333 list_add_tail(&layout
->inlineobjects
, &inlineobject
->entry
);
1337 if (!(run
= malloc(sizeof(*run
))))
1338 return E_OUTOFMEMORY
;
1340 /* No need to iterate for that, use simple fact that:
1341 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1342 last_cluster
= first_cluster
+ cluster_count
- 1;
1343 length
= layout
->clusters
[last_cluster
].position
- layout
->clusters
[first_cluster
].position
+
1344 layout
->clustermetrics
[last_cluster
].length
;
1346 if (!(run
->clustermap
= calloc(length
, sizeof(*run
->clustermap
))))
1349 return E_OUTOFMEMORY
;
1353 run
->start
= start
= layout
->clusters
[first_cluster
].position
;
1354 run
->length
= length
;
1355 run
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1356 memset(&run
->bbox
, 0, sizeof(run
->bbox
));
1358 /* Adjust by run width if direction differs. */
1359 if (is_run_rtl(run
) != is_rtl
)
1360 run
->origin
.x
= origin_x
+ (is_rtl
? -run
->width
: run
->width
);
1362 run
->origin
.x
= origin_x
;
1364 run
->origin
.y
= 0.0f
; /* set after line is built */
1365 run
->align_dx
= 0.0f
;
1368 if (r
->u
.regular
.run
.glyphCount
) {
1369 /* Trim leading and trailing clusters. */
1370 run
->glyphcount
= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
];
1371 if (start
+ length
< r
->u
.regular
.descr
.stringLength
)
1372 run
->glyphcount
-= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
+ length
];
1375 run
->glyphcount
= 0;
1377 /* cluster map needs to be shifted */
1378 for (i
= 0; i
< length
; i
++)
1379 run
->clustermap
[i
] = r
->u
.regular
.clustermap
[start
+ i
] - r
->u
.regular
.clustermap
[start
];
1381 run
->effect
= params
->effect
;
1382 run
->underlined
= params
->underline
;
1383 list_add_tail(&layout
->eruns
, &run
->entry
);
1385 /* Strikethrough style is guaranteed to be consistent within effective run,
1386 its width equals to run width, thickness and offset are derived from
1387 font metrics, rest of the values are from layout or run itself */
1388 if (params
->strikethrough
)
1390 struct layout_strikethrough
*s
;
1391 DWRITE_FONT_METRICS metrics
;
1393 if (!(s
= malloc(sizeof(*s
))))
1394 return E_OUTOFMEMORY
;
1396 layout_get_erun_font_metrics(layout
, run
, &metrics
);
1397 s
->s
.width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1398 s
->s
.thickness
= SCALE_FONT_METRIC(metrics
.strikethroughThickness
, r
->u
.regular
.run
.fontEmSize
, &metrics
);
1399 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1400 s
->s
.offset
= -SCALE_FONT_METRIC(metrics
.strikethroughPosition
, r
->u
.regular
.run
.fontEmSize
, &metrics
);
1401 s
->s
.readingDirection
= layout
->format
.readingdir
;
1402 s
->s
.flowDirection
= layout
->format
.flow
;
1403 s
->s
.localeName
= r
->u
.regular
.descr
.localeName
;
1404 s
->s
.measuringMode
= layout
->measuringmode
;
1407 list_add_tail(&layout
->strikethrough
, &s
->entry
);
1413 static void layout_apply_line_spacing(struct dwrite_textlayout
*layout
, UINT32 line
)
1415 switch (layout
->format
.spacing
.method
)
1417 case DWRITE_LINE_SPACING_METHOD_DEFAULT
:
1418 layout
->lines
[line
].metrics
.height
= layout
->lines
[line
].height
;
1419 layout
->lines
[line
].metrics
.baseline
= layout
->lines
[line
].baseline
;
1421 case DWRITE_LINE_SPACING_METHOD_UNIFORM
:
1422 layout
->lines
[line
].metrics
.height
= layout
->format
.spacing
.height
;
1423 layout
->lines
[line
].metrics
.baseline
= layout
->format
.spacing
.baseline
;
1425 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
:
1426 layout
->lines
[line
].metrics
.height
= layout
->lines
[line
].height
* layout
->format
.spacing
.height
;
1427 layout
->lines
[line
].metrics
.baseline
= layout
->lines
[line
].baseline
* layout
->format
.spacing
.baseline
;
1430 ERR("Unknown spacing method %u\n", layout
->format
.spacing
.method
);
1434 static HRESULT
layout_set_line_metrics(struct dwrite_textlayout
*layout
, DWRITE_LINE_METRICS1
*metrics
)
1436 size_t i
= layout
->metrics
.lineCount
;
1438 if (!dwrite_array_reserve((void **)&layout
->lines
, &layout
->lines_size
, layout
->metrics
.lineCount
+ 1,
1439 sizeof(*layout
->lines
)))
1441 return E_OUTOFMEMORY
;
1444 layout
->lines
[i
].metrics
= *metrics
;
1445 layout
->lines
[i
].height
= metrics
->height
;
1446 layout
->lines
[i
].baseline
= metrics
->baseline
;
1448 if (layout
->format
.spacing
.method
!= DWRITE_LINE_SPACING_METHOD_DEFAULT
)
1449 layout_apply_line_spacing(layout
, i
);
1451 layout
->metrics
.lineCount
++;
1455 static inline struct layout_effective_run
*layout_get_next_erun(struct dwrite_textlayout
*layout
,
1456 const struct layout_effective_run
*cur
)
1461 e
= list_head(&layout
->eruns
);
1463 e
= list_next(&layout
->eruns
, &cur
->entry
);
1466 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1469 static inline struct layout_effective_run
*layout_get_prev_erun(struct dwrite_textlayout
*layout
,
1470 const struct layout_effective_run
*cur
)
1475 e
= list_tail(&layout
->eruns
);
1477 e
= list_prev(&layout
->eruns
, &cur
->entry
);
1480 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1483 static inline struct layout_effective_inline
*layout_get_next_inline_run(struct dwrite_textlayout
*layout
,
1484 const struct layout_effective_inline
*cur
)
1489 e
= list_head(&layout
->inlineobjects
);
1491 e
= list_next(&layout
->inlineobjects
, &cur
->entry
);
1494 return LIST_ENTRY(e
, struct layout_effective_inline
, entry
);
1497 static FLOAT
layout_get_line_width(struct dwrite_textlayout
*layout
,
1498 struct layout_effective_run
*erun
, struct layout_effective_inline
*inrun
, UINT32 line
)
1502 while (erun
&& erun
->line
== line
) {
1503 width
+= erun
->width
;
1504 erun
= layout_get_next_erun(layout
, erun
);
1509 while (inrun
&& inrun
->line
== line
) {
1510 width
+= inrun
->width
;
1511 inrun
= layout_get_next_inline_run(layout
, inrun
);
1519 static inline BOOL
should_skip_transform(const DWRITE_MATRIX
*m
, FLOAT
*det
)
1521 *det
= m
->m11
* m
->m22
- m
->m12
* m
->m21
;
1522 /* on certain conditions we can skip transform */
1523 return (!memcmp(m
, &identity
, sizeof(*m
)) || fabsf(*det
) <= 1e-10f
);
1526 static inline void layout_apply_snapping(D2D1_POINT_2F
*vec
, BOOL skiptransform
, FLOAT ppdip
,
1527 const DWRITE_MATRIX
*m
, FLOAT det
)
1529 if (!skiptransform
) {
1532 /* apply transform */
1536 vec2
.x
= m
->m11
* vec
->x
+ m
->m21
* vec
->y
+ m
->dx
;
1537 vec2
.y
= m
->m12
* vec
->x
+ m
->m22
* vec
->y
+ m
->dy
;
1540 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
1541 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
1543 /* apply inverted transform, we don't care about X component at this point */
1544 vec
->x
= (m
->m22
* vec2
.x
- m
->m21
* vec2
.y
+ m
->m21
* m
->dy
- m
->m22
* m
->dx
) / det
;
1547 vec
->y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
1551 vec
->x
= floorf(vec
->x
* ppdip
+ 0.5f
) / ppdip
;
1552 vec
->y
= floorf(vec
->y
* ppdip
+ 0.5f
) / ppdip
;
1556 static void layout_apply_leading_alignment(struct dwrite_textlayout
*layout
)
1558 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1559 struct layout_effective_inline
*inrun
;
1560 struct layout_effective_run
*erun
;
1562 erun
= layout_get_next_erun(layout
, NULL
);
1563 inrun
= layout_get_next_inline_run(layout
, NULL
);
1566 erun
->align_dx
= 0.0f
;
1567 erun
= layout_get_next_erun(layout
, erun
);
1571 inrun
->align_dx
= 0.0f
;
1572 inrun
= layout_get_next_inline_run(layout
, inrun
);
1575 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
1578 static void layout_apply_trailing_alignment(struct dwrite_textlayout
*layout
)
1580 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1581 struct layout_effective_inline
*inrun
;
1582 struct layout_effective_run
*erun
;
1585 erun
= layout_get_next_erun(layout
, NULL
);
1586 inrun
= layout_get_next_inline_run(layout
, NULL
);
1588 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1589 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1590 FLOAT shift
= layout
->metrics
.layoutWidth
- width
;
1595 while (erun
&& erun
->line
== line
) {
1596 erun
->align_dx
= shift
;
1597 erun
= layout_get_next_erun(layout
, erun
);
1600 while (inrun
&& inrun
->line
== line
) {
1601 inrun
->align_dx
= shift
;
1602 inrun
= layout_get_next_inline_run(layout
, inrun
);
1606 layout
->metrics
.left
= is_rtl
? 0.0f
: layout
->metrics
.layoutWidth
- layout
->metrics
.width
;
1609 static inline FLOAT
layout_get_centered_shift(struct dwrite_textlayout
*layout
, BOOL skiptransform
,
1610 FLOAT width
, FLOAT det
)
1612 if (is_layout_gdi_compatible(layout
)) {
1613 D2D1_POINT_2F vec
= { layout
->metrics
.layoutWidth
- width
, 0.0f
};
1614 layout_apply_snapping(&vec
, skiptransform
, layout
->ppdip
, &layout
->transform
, det
);
1615 return floorf(vec
.x
/ 2.0f
);
1618 return (layout
->metrics
.layoutWidth
- width
) / 2.0f
;
1621 static void layout_apply_centered_alignment(struct dwrite_textlayout
*layout
)
1623 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1624 struct layout_effective_inline
*inrun
;
1625 struct layout_effective_run
*erun
;
1630 erun
= layout_get_next_erun(layout
, NULL
);
1631 inrun
= layout_get_next_inline_run(layout
, NULL
);
1633 skiptransform
= should_skip_transform(&layout
->transform
, &det
);
1635 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1636 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1637 FLOAT shift
= layout_get_centered_shift(layout
, skiptransform
, width
, det
);
1642 while (erun
&& erun
->line
== line
) {
1643 erun
->align_dx
= shift
;
1644 erun
= layout_get_next_erun(layout
, erun
);
1647 while (inrun
&& inrun
->line
== line
) {
1648 inrun
->align_dx
= shift
;
1649 inrun
= layout_get_next_inline_run(layout
, inrun
);
1653 layout
->metrics
.left
= (layout
->metrics
.layoutWidth
- layout
->metrics
.width
) / 2.0f
;
1656 static void layout_apply_text_alignment(struct dwrite_textlayout
*layout
)
1658 switch (layout
->format
.textalignment
)
1660 case DWRITE_TEXT_ALIGNMENT_LEADING
:
1661 layout_apply_leading_alignment(layout
);
1663 case DWRITE_TEXT_ALIGNMENT_TRAILING
:
1664 layout_apply_trailing_alignment(layout
);
1666 case DWRITE_TEXT_ALIGNMENT_CENTER
:
1667 layout_apply_centered_alignment(layout
);
1669 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED
:
1670 FIXME("alignment %d not implemented\n", layout
->format
.textalignment
);
1677 static void layout_apply_par_alignment(struct dwrite_textlayout
*layout
)
1679 struct layout_effective_inline
*inrun
;
1680 struct layout_effective_run
*erun
;
1681 FLOAT origin_y
= 0.0f
;
1684 /* alignment mode defines origin, after that all run origins are updated
1687 switch (layout
->format
.paralign
)
1689 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR
:
1692 case DWRITE_PARAGRAPH_ALIGNMENT_FAR
:
1693 origin_y
= layout
->metrics
.layoutHeight
- layout
->metrics
.height
;
1695 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER
:
1696 origin_y
= (layout
->metrics
.layoutHeight
- layout
->metrics
.height
) / 2.0f
;
1702 layout
->metrics
.top
= origin_y
;
1704 erun
= layout_get_next_erun(layout
, NULL
);
1705 inrun
= layout_get_next_inline_run(layout
, NULL
);
1706 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++)
1708 float pos_y
= origin_y
+ layout
->lines
[line
].metrics
.baseline
;
1710 while (erun
&& erun
->line
== line
) {
1711 erun
->origin
.y
= pos_y
;
1712 erun
= layout_get_next_erun(layout
, erun
);
1715 while (inrun
&& inrun
->line
== line
) {
1716 inrun
->origin
.y
= pos_y
- inrun
->baseline
;
1717 inrun
= layout_get_next_inline_run(layout
, inrun
);
1720 origin_y
+= layout
->lines
[line
].metrics
.height
;
1724 struct layout_underline_splitting_params
{
1725 const WCHAR
*locale
; /* points to range data, no additional allocation */
1726 IUnknown
*effect
; /* does not hold another reference */
1729 static void init_u_splitting_params_from_erun(struct layout_effective_run
*erun
,
1730 struct layout_underline_splitting_params
*params
)
1732 params
->locale
= erun
->run
->u
.regular
.descr
.localeName
;
1733 params
->effect
= erun
->effect
;
1736 static BOOL
is_same_u_splitting(struct layout_underline_splitting_params
*left
,
1737 struct layout_underline_splitting_params
*right
)
1739 return left
->effect
== right
->effect
&& !wcsicmp(left
->locale
, right
->locale
);
1742 static HRESULT
layout_add_underline(struct dwrite_textlayout
*layout
, struct layout_effective_run
*first
,
1743 struct layout_effective_run
*last
)
1745 FLOAT thickness
, offset
, runheight
;
1746 struct layout_effective_run
*cur
;
1747 DWRITE_FONT_METRICS metrics
;
1749 if (first
== layout_get_prev_erun(layout
, last
)) {
1750 layout_get_erun_font_metrics(layout
, first
, &metrics
);
1751 thickness
= SCALE_FONT_METRIC(metrics
.underlineThickness
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1752 offset
= SCALE_FONT_METRIC(metrics
.underlinePosition
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1753 runheight
= SCALE_FONT_METRIC(metrics
.capHeight
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1758 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1759 calculated as weighted average, where run width acts as a weight. */
1760 thickness
= offset
= runheight
= 0.0f
;
1763 layout_get_erun_font_metrics(layout
, cur
, &metrics
);
1765 thickness
+= SCALE_FONT_METRIC(metrics
.underlineThickness
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
1766 offset
+= SCALE_FONT_METRIC(metrics
.underlinePosition
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
1767 runheight
= max(SCALE_FONT_METRIC(metrics
.capHeight
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
), runheight
);
1768 width
+= cur
->width
;
1770 cur
= layout_get_next_erun(layout
, cur
);
1771 } while (cur
!= last
);
1779 struct layout_underline_splitting_params params
, prev_params
;
1780 struct layout_effective_run
*next
, *w
;
1781 struct layout_underline
*u
;
1783 init_u_splitting_params_from_erun(cur
, &prev_params
);
1784 while ((next
= layout_get_next_erun(layout
, cur
)) != last
) {
1785 init_u_splitting_params_from_erun(next
, ¶ms
);
1786 if (!is_same_u_splitting(&prev_params
, ¶ms
))
1791 if (!(u
= malloc(sizeof(*u
))))
1792 return E_OUTOFMEMORY
;
1797 u
->u
.width
+= w
->width
;
1798 w
= layout_get_next_erun(layout
, w
);
1801 u
->u
.thickness
= thickness
;
1802 /* Font metrics convention is to have it negative when below baseline, for rendering
1803 however Y grows from baseline down for horizontal baseline. */
1804 u
->u
.offset
= -offset
;
1805 u
->u
.runHeight
= runheight
;
1806 u
->u
.readingDirection
= is_run_rtl(cur
) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
:
1807 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
1808 u
->u
.flowDirection
= layout
->format
.flow
;
1809 u
->u
.localeName
= cur
->run
->u
.regular
.descr
.localeName
;
1810 u
->u
.measuringMode
= layout
->measuringmode
;
1812 list_add_tail(&layout
->underlines
, &u
->entry
);
1815 } while (cur
!= last
);
1820 /* Adds zero width line, metrics are derived from font at specified text position. */
1821 static HRESULT
layout_set_dummy_line_metrics(struct dwrite_textlayout
*layout
, UINT32 pos
)
1823 DWRITE_LINE_METRICS1 metrics
= { 0 };
1824 DWRITE_FONT_METRICS fontmetrics
;
1825 struct layout_range
*range
;
1826 IDWriteFontFace
*fontface
;
1830 range
= get_layout_range_by_pos(layout
, pos
);
1831 hr
= create_matching_font(range
->collection
,
1839 hr
= IDWriteFont_CreateFontFace(font
, &fontface
);
1840 IDWriteFont_Release(font
);
1844 layout_get_font_metrics(layout
, fontface
, range
->fontsize
, &fontmetrics
);
1845 layout_get_font_height(range
->fontsize
, &fontmetrics
, &metrics
.baseline
, &metrics
.height
);
1846 IDWriteFontFace_Release(fontface
);
1848 return layout_set_line_metrics(layout
, &metrics
);
1851 static void layout_add_line(struct dwrite_textlayout
*layout
, UINT32 first_cluster
, UINT32 last_cluster
,
1854 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1855 struct layout_final_splitting_params params
, prev_params
;
1856 DWRITE_INLINE_OBJECT_METRICS sign_metrics
= { 0 };
1857 UINT32 line
= layout
->metrics
.lineCount
, i
;
1858 DWRITE_LINE_METRICS1 metrics
= { 0 };
1859 UINT32 index
, start
, pos
= *textpos
;
1860 FLOAT descent
, trailingspacewidth
;
1861 BOOL append_trimming_run
= FALSE
;
1862 const struct layout_run
*run
;
1863 float width
= 0.0f
, origin_x
;
1866 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
1867 for (index
= last_cluster
, trailingspacewidth
= 0.0f
; index
>= first_cluster
; index
--) {
1868 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
1869 struct layout_cluster
*lc
= &layout
->clusters
[index
];
1872 /* This also filters out clusters added from inline objects, those are never
1873 treated as a white space. */
1874 if (!cluster
->isWhitespace
)
1877 /* Every isNewline cluster is also isWhitespace, but not every
1878 newline character cluster has isNewline set, so go back to original string. */
1879 ch
= lc
->run
->u
.regular
.descr
.string
[lc
->position
];
1880 if (cluster
->length
== 1 && lb_is_newline_char(ch
))
1881 metrics
.newlineLength
+= cluster
->length
;
1883 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1884 trailingspacewidth
+= cluster
->width
;
1890 /* Line metrics length includes trailing whitespace length too */
1891 for (i
= first_cluster
; i
<= last_cluster
; i
++)
1892 metrics
.length
+= layout
->clustermetrics
[i
].length
;
1894 /* Ignore trailing whitespaces */
1895 while (last_cluster
> first_cluster
) {
1896 if (!layout
->clustermetrics
[last_cluster
].isWhitespace
)
1902 /* Does not include trailing space width */
1903 if (!layout
->clustermetrics
[last_cluster
].isWhitespace
)
1904 width
= get_cluster_range_width(layout
, first_cluster
, last_cluster
+ 1);
1906 /* Append trimming run if necessary */
1907 if (width
> layout
->metrics
.layoutWidth
&& layout
->format
.trimmingsign
!= NULL
&&
1908 layout
->format
.trimming
.granularity
!= DWRITE_TRIMMING_GRANULARITY_NONE
) {
1909 FLOAT trimmed_width
= width
;
1911 hr
= IDWriteInlineObject_GetMetrics(layout
->format
.trimmingsign
, &sign_metrics
);
1912 if (SUCCEEDED(hr
)) {
1913 while (last_cluster
> first_cluster
) {
1914 if (trimmed_width
+ sign_metrics
.width
<= layout
->metrics
.layoutWidth
)
1916 if (layout
->format
.trimming
.granularity
== DWRITE_TRIMMING_GRANULARITY_CHARACTER
)
1917 trimmed_width
-= layout
->clustermetrics
[last_cluster
--].width
;
1919 while (last_cluster
> first_cluster
) {
1920 trimmed_width
-= layout
->clustermetrics
[last_cluster
].width
;
1921 if (layout
->clustermetrics
[last_cluster
--].canWrapLineAfter
)
1926 append_trimming_run
= TRUE
;
1929 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#lx.\n", hr
);
1931 width
= trimmed_width
+ sign_metrics
.width
;
1934 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
1935 prev_params
= params
;
1936 run
= layout
->clusters
[first_cluster
].run
;
1938 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
1939 origin_x
= is_rtl
? layout
->metrics
.layoutWidth
: 0.0f
;
1940 for (start
= first_cluster
, i
= first_cluster
; i
<= last_cluster
; i
++) {
1941 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
1943 if (run
!= layout
->clusters
[i
].run
|| !is_same_splitting_params(&prev_params
, ¶ms
)) {
1944 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
1948 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) :
1949 get_cluster_range_width(layout
, start
, i
);
1950 run
= layout
->clusters
[i
].run
;
1954 prev_params
= params
;
1955 pos
+= layout
->clustermetrics
[i
].length
;
1958 /* Final run from what's left from cluster range */
1959 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
1963 if (get_cluster_range_width(layout
, start
, i
) + sign_metrics
.width
> layout
->metrics
.layoutWidth
)
1964 append_trimming_run
= FALSE
;
1966 if (append_trimming_run
) {
1967 struct layout_effective_inline
*trimming_sign
;
1969 if (!(trimming_sign
= calloc(1, sizeof(*trimming_sign
))))
1972 trimming_sign
->object
= layout
->format
.trimmingsign
;
1973 trimming_sign
->width
= sign_metrics
.width
;
1974 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) : get_cluster_range_width(layout
, start
, i
);
1975 trimming_sign
->origin
.x
= is_rtl
? origin_x
- trimming_sign
->width
: origin_x
;
1976 trimming_sign
->origin
.y
= 0.0f
; /* set after line is built */
1977 trimming_sign
->align_dx
= 0.0f
;
1978 trimming_sign
->baseline
= sign_metrics
.baseline
;
1980 trimming_sign
->is_sideways
= FALSE
;
1981 trimming_sign
->is_rtl
= FALSE
;
1982 trimming_sign
->line
= line
;
1984 trimming_sign
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[i
].position
+
1985 layout
->clusters
[i
].run
->start_position
);
1987 list_add_tail(&layout
->inlineobjects
, &trimming_sign
->entry
);
1990 /* Look for max baseline and descent for this line */
1991 for (index
= first_cluster
, metrics
.baseline
= 0.0f
, descent
= 0.0f
; index
<= last_cluster
; index
++) {
1992 const struct layout_run
*cur
= layout
->clusters
[index
].run
;
1993 FLOAT cur_descent
= cur
->height
- cur
->baseline
;
1995 if (cur
->baseline
> metrics
.baseline
)
1996 metrics
.baseline
= cur
->baseline
;
1997 if (cur_descent
> descent
)
1998 descent
= cur_descent
;
2001 layout
->metrics
.width
= max(width
, layout
->metrics
.width
);
2002 layout
->metrics
.widthIncludingTrailingWhitespace
= max(width
+ trailingspacewidth
,
2003 layout
->metrics
.widthIncludingTrailingWhitespace
);
2005 metrics
.height
= descent
+ metrics
.baseline
;
2006 metrics
.isTrimmed
= append_trimming_run
|| width
> layout
->metrics
.layoutWidth
;
2007 layout_set_line_metrics(layout
, &metrics
);
2009 *textpos
+= metrics
.length
;
2012 static void layout_set_line_positions(struct dwrite_textlayout
*layout
)
2014 struct layout_effective_inline
*inrun
;
2015 struct layout_effective_run
*erun
;
2019 /* Now all line info is here, update effective runs positions in flow direction */
2020 erun
= layout_get_next_erun(layout
, NULL
);
2021 inrun
= layout_get_next_inline_run(layout
, NULL
);
2023 for (line
= 0, origin_y
= 0.0f
; line
< layout
->metrics
.lineCount
; line
++)
2025 float pos_y
= origin_y
+ layout
->lines
[line
].metrics
.baseline
;
2027 /* For all runs on this line */
2028 while (erun
&& erun
->line
== line
) {
2029 erun
->origin
.y
= pos_y
;
2030 erun
= layout_get_next_erun(layout
, erun
);
2033 /* Same for inline runs */
2034 while (inrun
&& inrun
->line
== line
) {
2035 inrun
->origin
.y
= pos_y
- inrun
->baseline
;
2036 inrun
= layout_get_next_inline_run(layout
, inrun
);
2039 origin_y
+= layout
->lines
[line
].metrics
.height
;
2042 layout
->metrics
.height
= origin_y
;
2044 /* Initial paragraph alignment is always near */
2045 if (layout
->format
.paralign
!= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
)
2046 layout_apply_par_alignment(layout
);
2049 static BOOL
layout_can_wrap_after(const struct dwrite_textlayout
*layout
, UINT32 cluster
)
2051 if (layout
->format
.wrapping
== DWRITE_WORD_WRAPPING_CHARACTER
)
2054 return layout
->clustermetrics
[cluster
].canWrapLineAfter
;
2057 static HRESULT
layout_compute_effective_runs(struct dwrite_textlayout
*layout
)
2059 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
2060 struct layout_effective_run
*erun
, *first_underlined
;
2061 UINT32 i
, start
, textpos
, last_breaking_point
;
2062 DWRITE_LINE_METRICS1 metrics
;
2067 if (!(layout
->recompute
& RECOMPUTE_LINES
))
2070 free_layout_eruns(layout
);
2072 hr
= layout_compute(layout
);
2076 layout
->metrics
.lineCount
= 0;
2077 memset(&metrics
, 0, sizeof(metrics
));
2079 layout
->metrics
.height
= 0.0f
;
2080 layout
->metrics
.width
= 0.0f
;
2081 layout
->metrics
.widthIncludingTrailingWhitespace
= 0.0f
;
2083 last_breaking_point
= ~0u;
2085 for (i
= 0, start
= 0, width
= 0.0f
, textpos
= 0; i
< layout
->cluster_count
; i
++) {
2086 BOOL overflow
= FALSE
;
2088 while (i
< layout
->cluster_count
&& !layout
->clustermetrics
[i
].isNewline
) {
2089 /* Check for overflow */
2090 overflow
= ((width
+ layout
->clustermetrics
[i
].width
> layout
->metrics
.layoutWidth
) &&
2091 (layout
->format
.wrapping
!= DWRITE_WORD_WRAPPING_NO_WRAP
));
2095 if (layout_can_wrap_after(layout
, i
))
2096 last_breaking_point
= i
;
2097 width
+= layout
->clustermetrics
[i
].width
;
2100 i
= min(i
, layout
->cluster_count
- 1);
2102 /* Ignore if overflown on whitespace */
2103 if (overflow
&& !(layout
->clustermetrics
[i
].isWhitespace
&& layout_can_wrap_after(layout
, i
))) {
2104 /* Use most recently found breaking point */
2105 if (last_breaking_point
!= ~0u) {
2106 i
= last_breaking_point
;
2107 last_breaking_point
= ~0u;
2110 /* Otherwise proceed forward to next newline or breaking point */
2111 for (; i
< layout
->cluster_count
; i
++)
2112 if (layout_can_wrap_after(layout
, i
) || layout
->clustermetrics
[i
].isNewline
)
2116 i
= min(i
, layout
->cluster_count
- 1);
2118 layout_add_line(layout
, start
, i
, &textpos
);
2123 /* Add dummy line if:
2124 - there's no text, metrics come from first range in this case;
2125 - last ended with a mandatory break, metrics come from last text position.
2127 if (layout
->len
== 0)
2128 hr
= layout_set_dummy_line_metrics(layout
, 0);
2129 else if (layout
->cluster_count
&& layout
->clustermetrics
[layout
->cluster_count
- 1].isNewline
)
2130 hr
= layout_set_dummy_line_metrics(layout
, layout
->len
- 1);
2134 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
2135 layout
->metrics
.top
= 0.0f
;
2136 layout
->metrics
.maxBidiReorderingDepth
= 1; /* FIXME */
2138 /* Add explicit underlined runs */
2139 erun
= layout_get_next_erun(layout
, NULL
);
2140 first_underlined
= erun
&& erun
->underlined
? erun
: NULL
;
2141 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
2142 while (erun
&& erun
->line
== line
) {
2143 erun
= layout_get_next_erun(layout
, erun
);
2145 if (first_underlined
&& (!erun
|| !erun
->underlined
)) {
2146 layout_add_underline(layout
, first_underlined
, erun
);
2147 first_underlined
= NULL
;
2149 else if (!first_underlined
&& erun
&& erun
->underlined
)
2150 first_underlined
= erun
;
2154 /* Position runs in flow direction */
2155 layout_set_line_positions(layout
);
2157 /* Initial alignment is always leading */
2158 if (layout
->format
.textalignment
!= DWRITE_TEXT_ALIGNMENT_LEADING
)
2159 layout_apply_text_alignment(layout
);
2161 layout
->recompute
&= ~RECOMPUTE_LINES
;
2165 static BOOL
is_same_layout_attrvalue(struct layout_range_header
const *h
, enum layout_range_attr_kind attr
,
2166 struct layout_range_attr_value
*value
)
2168 struct layout_range_spacing
const *range_spacing
= (struct layout_range_spacing
*)h
;
2169 struct layout_range_iface
const *range_iface
= (struct layout_range_iface
*)h
;
2170 struct layout_range_bool
const *range_bool
= (struct layout_range_bool
*)h
;
2171 struct layout_range
const *range
= (struct layout_range
*)h
;
2174 case LAYOUT_RANGE_ATTR_WEIGHT
:
2175 return range
->weight
== value
->u
.weight
;
2176 case LAYOUT_RANGE_ATTR_STYLE
:
2177 return range
->style
== value
->u
.style
;
2178 case LAYOUT_RANGE_ATTR_STRETCH
:
2179 return range
->stretch
== value
->u
.stretch
;
2180 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2181 return range
->fontsize
== value
->u
.fontsize
;
2182 case LAYOUT_RANGE_ATTR_INLINE
:
2183 return range
->object
== value
->u
.object
;
2184 case LAYOUT_RANGE_ATTR_EFFECT
:
2185 return range_iface
->iface
== value
->u
.effect
;
2186 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2187 return range_bool
->value
== value
->u
.underline
;
2188 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2189 return range_bool
->value
== value
->u
.strikethrough
;
2190 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2191 return range
->pair_kerning
== value
->u
.pair_kerning
;
2192 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2193 return range
->collection
== value
->u
.collection
;
2194 case LAYOUT_RANGE_ATTR_LOCALE
:
2195 return !wcsicmp(range
->locale
, value
->u
.locale
);
2196 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2197 return !wcscmp(range
->fontfamily
, value
->u
.fontfamily
);
2198 case LAYOUT_RANGE_ATTR_SPACING
:
2199 return range_spacing
->leading
== value
->u
.spacing
.leading
&&
2200 range_spacing
->trailing
== value
->u
.spacing
.trailing
&&
2201 range_spacing
->min_advance
== value
->u
.spacing
.min_advance
;
2202 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2203 return range_iface
->iface
== (IUnknown
*)value
->u
.typography
;
2211 static inline BOOL
is_same_layout_attributes(struct layout_range_header
const *hleft
, struct layout_range_header
const *hright
)
2213 switch (hleft
->kind
)
2215 case LAYOUT_RANGE_REGULAR
:
2217 struct layout_range
const *left
= (struct layout_range
const*)hleft
;
2218 struct layout_range
const *right
= (struct layout_range
const*)hright
;
2219 return left
->weight
== right
->weight
&&
2220 left
->style
== right
->style
&&
2221 left
->stretch
== right
->stretch
&&
2222 left
->fontsize
== right
->fontsize
&&
2223 left
->object
== right
->object
&&
2224 left
->pair_kerning
== right
->pair_kerning
&&
2225 left
->collection
== right
->collection
&&
2226 !wcsicmp(left
->locale
, right
->locale
) &&
2227 !wcscmp(left
->fontfamily
, right
->fontfamily
);
2229 case LAYOUT_RANGE_UNDERLINE
:
2230 case LAYOUT_RANGE_STRIKETHROUGH
:
2232 struct layout_range_bool
const *left
= (struct layout_range_bool
const*)hleft
;
2233 struct layout_range_bool
const *right
= (struct layout_range_bool
const*)hright
;
2234 return left
->value
== right
->value
;
2236 case LAYOUT_RANGE_EFFECT
:
2237 case LAYOUT_RANGE_TYPOGRAPHY
:
2239 struct layout_range_iface
const *left
= (struct layout_range_iface
const*)hleft
;
2240 struct layout_range_iface
const *right
= (struct layout_range_iface
const*)hright
;
2241 return left
->iface
== right
->iface
;
2243 case LAYOUT_RANGE_SPACING
:
2245 struct layout_range_spacing
const *left
= (struct layout_range_spacing
const*)hleft
;
2246 struct layout_range_spacing
const *right
= (struct layout_range_spacing
const*)hright
;
2247 return left
->leading
== right
->leading
&&
2248 left
->trailing
== right
->trailing
&&
2249 left
->min_advance
== right
->min_advance
;
2252 FIXME("unknown range kind %d\n", hleft
->kind
);
2257 static inline BOOL
is_same_text_range(const DWRITE_TEXT_RANGE
*left
, const DWRITE_TEXT_RANGE
*right
)
2259 return left
->startPosition
== right
->startPosition
&& left
->length
== right
->length
;
2262 /* Allocates range and inits it with default values from text format. */
2263 static struct layout_range_header
*alloc_layout_range(struct dwrite_textlayout
*layout
, const DWRITE_TEXT_RANGE
*r
,
2264 enum layout_range_kind kind
)
2266 struct layout_range_header
*h
;
2270 case LAYOUT_RANGE_REGULAR
:
2272 struct layout_range
*range
;
2274 if (!(range
= calloc(1, sizeof(*range
))))
2277 range
->weight
= layout
->format
.weight
;
2278 range
->style
= layout
->format
.style
;
2279 range
->stretch
= layout
->format
.stretch
;
2280 range
->fontsize
= layout
->format
.fontsize
;
2282 range
->fontfamily
= wcsdup(layout
->format
.family_name
);
2283 if (!range
->fontfamily
)
2289 range
->collection
= layout
->format
.collection
;
2290 if (range
->collection
)
2291 IDWriteFontCollection_AddRef(range
->collection
);
2292 wcscpy(range
->locale
, layout
->format
.locale
);
2297 case LAYOUT_RANGE_UNDERLINE
:
2298 case LAYOUT_RANGE_STRIKETHROUGH
:
2300 struct layout_range_bool
*range
;
2302 if (!(range
= calloc(1, sizeof(*range
))))
2308 case LAYOUT_RANGE_EFFECT
:
2309 case LAYOUT_RANGE_TYPOGRAPHY
:
2311 struct layout_range_iface
*range
;
2313 if (!(range
= calloc(1, sizeof(*range
))))
2319 case LAYOUT_RANGE_SPACING
:
2321 struct layout_range_spacing
*range
;
2323 if (!(range
= calloc(1, sizeof(*range
))))
2330 FIXME("unknown range kind %d\n", kind
);
2339 static struct layout_range_header
*alloc_layout_range_from(struct layout_range_header
*h
, const DWRITE_TEXT_RANGE
*r
)
2341 struct layout_range_header
*ret
;
2345 case LAYOUT_RANGE_REGULAR
:
2347 struct layout_range
*from
= (struct layout_range
*)h
, *range
;
2349 if (!(range
= malloc(sizeof(*range
))))
2353 range
->fontfamily
= wcsdup(from
->fontfamily
);
2354 if (!range
->fontfamily
)
2360 /* update refcounts */
2362 IDWriteInlineObject_AddRef(range
->object
);
2363 if (range
->collection
)
2364 IDWriteFontCollection_AddRef(range
->collection
);
2368 case LAYOUT_RANGE_UNDERLINE
:
2369 case LAYOUT_RANGE_STRIKETHROUGH
:
2371 struct layout_range_bool
*strike
= malloc(sizeof(*strike
));
2372 if (!strike
) return NULL
;
2374 *strike
= *(struct layout_range_bool
*)h
;
2378 case LAYOUT_RANGE_EFFECT
:
2379 case LAYOUT_RANGE_TYPOGRAPHY
:
2381 struct layout_range_iface
*effect
= malloc(sizeof(*effect
));
2382 if (!effect
) return NULL
;
2384 *effect
= *(struct layout_range_iface
*)h
;
2386 IUnknown_AddRef(effect
->iface
);
2390 case LAYOUT_RANGE_SPACING
:
2392 struct layout_range_spacing
*spacing
= malloc(sizeof(*spacing
));
2393 if (!spacing
) return NULL
;
2395 *spacing
= *(struct layout_range_spacing
*)h
;
2400 FIXME("unknown range kind %d\n", h
->kind
);
2408 static void free_layout_range(struct layout_range_header
*h
)
2415 case LAYOUT_RANGE_REGULAR
:
2417 struct layout_range
*range
= (struct layout_range
*)h
;
2420 IDWriteInlineObject_Release(range
->object
);
2421 if (range
->collection
)
2422 IDWriteFontCollection_Release(range
->collection
);
2423 free(range
->fontfamily
);
2426 case LAYOUT_RANGE_EFFECT
:
2427 case LAYOUT_RANGE_TYPOGRAPHY
:
2429 struct layout_range_iface
*range
= (struct layout_range_iface
*)h
;
2431 IUnknown_Release(range
->iface
);
2441 static void free_layout_ranges_list(struct dwrite_textlayout
*layout
)
2443 struct layout_range_header
*cur
, *cur2
;
2445 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->ranges
, struct layout_range_header
, entry
) {
2446 list_remove(&cur
->entry
);
2447 free_layout_range(cur
);
2450 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->underline_ranges
, struct layout_range_header
, entry
) {
2451 list_remove(&cur
->entry
);
2452 free_layout_range(cur
);
2455 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->strike_ranges
, struct layout_range_header
, entry
) {
2456 list_remove(&cur
->entry
);
2457 free_layout_range(cur
);
2460 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->effects
, struct layout_range_header
, entry
) {
2461 list_remove(&cur
->entry
);
2462 free_layout_range(cur
);
2465 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->spacing
, struct layout_range_header
, entry
) {
2466 list_remove(&cur
->entry
);
2467 free_layout_range(cur
);
2470 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->typographies
, struct layout_range_header
, entry
) {
2471 list_remove(&cur
->entry
);
2472 free_layout_range(cur
);
2476 static struct layout_range_header
*find_outer_range(struct list
*ranges
, const DWRITE_TEXT_RANGE
*range
)
2478 struct layout_range_header
*cur
;
2480 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
2482 if (cur
->range
.startPosition
> range
->startPosition
)
2485 if ((cur
->range
.startPosition
+ cur
->range
.length
< range
->startPosition
+ range
->length
) &&
2486 (range
->startPosition
< cur
->range
.startPosition
+ cur
->range
.length
))
2488 if (cur
->range
.startPosition
+ cur
->range
.length
>= range
->startPosition
+ range
->length
)
2495 static inline BOOL
set_layout_range_iface_attr(IUnknown
**dest
, IUnknown
*value
)
2497 if (*dest
== value
) return FALSE
;
2500 IUnknown_Release(*dest
);
2503 IUnknown_AddRef(*dest
);
2508 static BOOL
set_layout_range_attrval(struct layout_range_header
*h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2510 struct layout_range_spacing
*dest_spacing
= (struct layout_range_spacing
*)h
;
2511 struct layout_range_iface
*dest_iface
= (struct layout_range_iface
*)h
;
2512 struct layout_range_bool
*dest_bool
= (struct layout_range_bool
*)h
;
2513 struct layout_range
*dest
= (struct layout_range
*)h
;
2515 BOOL changed
= FALSE
;
2518 case LAYOUT_RANGE_ATTR_WEIGHT
:
2519 changed
= dest
->weight
!= value
->u
.weight
;
2520 dest
->weight
= value
->u
.weight
;
2522 case LAYOUT_RANGE_ATTR_STYLE
:
2523 changed
= dest
->style
!= value
->u
.style
;
2524 dest
->style
= value
->u
.style
;
2526 case LAYOUT_RANGE_ATTR_STRETCH
:
2527 changed
= dest
->stretch
!= value
->u
.stretch
;
2528 dest
->stretch
= value
->u
.stretch
;
2530 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2531 changed
= dest
->fontsize
!= value
->u
.fontsize
;
2532 dest
->fontsize
= value
->u
.fontsize
;
2534 case LAYOUT_RANGE_ATTR_INLINE
:
2535 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->object
, (IUnknown
*)value
->u
.object
);
2537 case LAYOUT_RANGE_ATTR_EFFECT
:
2538 changed
= set_layout_range_iface_attr(&dest_iface
->iface
, value
->u
.effect
);
2540 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2541 changed
= dest_bool
->value
!= value
->u
.underline
;
2542 dest_bool
->value
= value
->u
.underline
;
2544 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2545 changed
= dest_bool
->value
!= value
->u
.strikethrough
;
2546 dest_bool
->value
= value
->u
.strikethrough
;
2548 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2549 changed
= dest
->pair_kerning
!= value
->u
.pair_kerning
;
2550 dest
->pair_kerning
= value
->u
.pair_kerning
;
2552 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2553 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->collection
, (IUnknown
*)value
->u
.collection
);
2555 case LAYOUT_RANGE_ATTR_LOCALE
:
2556 changed
= !!wcsicmp(dest
->locale
, value
->u
.locale
);
2559 wcscpy(dest
->locale
, value
->u
.locale
);
2560 wcslwr(dest
->locale
);
2563 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2564 changed
= !!wcscmp(dest
->fontfamily
, value
->u
.fontfamily
);
2567 free(dest
->fontfamily
);
2568 dest
->fontfamily
= wcsdup(value
->u
.fontfamily
);
2571 case LAYOUT_RANGE_ATTR_SPACING
:
2572 changed
= dest_spacing
->leading
!= value
->u
.spacing
.leading
||
2573 dest_spacing
->trailing
!= value
->u
.spacing
.trailing
||
2574 dest_spacing
->min_advance
!= value
->u
.spacing
.min_advance
;
2575 dest_spacing
->leading
= value
->u
.spacing
.leading
;
2576 dest_spacing
->trailing
= value
->u
.spacing
.trailing
;
2577 dest_spacing
->min_advance
= value
->u
.spacing
.min_advance
;
2579 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2580 changed
= set_layout_range_iface_attr(&dest_iface
->iface
, (IUnknown
*)value
->u
.typography
);
2589 static inline BOOL
is_in_layout_range(const DWRITE_TEXT_RANGE
*outer
, const DWRITE_TEXT_RANGE
*inner
)
2591 return (inner
->startPosition
>= outer
->startPosition
) &&
2592 (inner
->startPosition
+ inner
->length
<= outer
->startPosition
+ outer
->length
);
2595 static inline HRESULT
return_range(const struct layout_range_header
*h
, DWRITE_TEXT_RANGE
*r
)
2597 if (r
) *r
= h
->range
;
2601 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2602 static HRESULT
set_layout_range_attr(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2604 struct layout_range_header
*cur
, *right
, *left
, *outer
;
2605 BOOL changed
= FALSE
;
2606 struct list
*ranges
;
2607 DWRITE_TEXT_RANGE r
;
2609 /* ignore zero length ranges */
2610 if (value
->range
.length
== 0)
2613 if (~0u - value
->range
.startPosition
< value
->range
.length
)
2614 return E_INVALIDARG
;
2616 /* select from ranges lists */
2619 case LAYOUT_RANGE_ATTR_WEIGHT
:
2620 case LAYOUT_RANGE_ATTR_STYLE
:
2621 case LAYOUT_RANGE_ATTR_STRETCH
:
2622 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2623 case LAYOUT_RANGE_ATTR_INLINE
:
2624 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2625 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2626 case LAYOUT_RANGE_ATTR_LOCALE
:
2627 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2628 ranges
= &layout
->ranges
;
2630 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2631 ranges
= &layout
->underline_ranges
;
2633 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2634 ranges
= &layout
->strike_ranges
;
2636 case LAYOUT_RANGE_ATTR_EFFECT
:
2637 ranges
= &layout
->effects
;
2639 case LAYOUT_RANGE_ATTR_SPACING
:
2640 ranges
= &layout
->spacing
;
2642 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2643 ranges
= &layout
->typographies
;
2646 FIXME("unknown attr kind %d\n", attr
);
2650 /* If new range is completely within existing range, split existing range in two */
2651 if ((outer
= find_outer_range(ranges
, &value
->range
))) {
2653 /* no need to add same range */
2654 if (is_same_layout_attrvalue(outer
, attr
, value
))
2657 /* for matching range bounds just replace data */
2658 if (is_same_text_range(&outer
->range
, &value
->range
)) {
2659 changed
= set_layout_range_attrval(outer
, attr
, value
);
2663 /* add new range to the left */
2664 if (value
->range
.startPosition
== outer
->range
.startPosition
) {
2665 left
= alloc_layout_range_from(outer
, &value
->range
);
2666 if (!left
) return E_OUTOFMEMORY
;
2668 changed
= set_layout_range_attrval(left
, attr
, value
);
2669 list_add_before(&outer
->entry
, &left
->entry
);
2670 outer
->range
.startPosition
+= value
->range
.length
;
2671 outer
->range
.length
-= value
->range
.length
;
2675 /* add new range to the right */
2676 if (value
->range
.startPosition
+ value
->range
.length
== outer
->range
.startPosition
+ outer
->range
.length
) {
2677 right
= alloc_layout_range_from(outer
, &value
->range
);
2678 if (!right
) return E_OUTOFMEMORY
;
2680 changed
= set_layout_range_attrval(right
, attr
, value
);
2681 list_add_after(&outer
->entry
, &right
->entry
);
2682 outer
->range
.length
-= value
->range
.length
;
2686 r
.startPosition
= value
->range
.startPosition
+ value
->range
.length
;
2687 r
.length
= outer
->range
.length
+ outer
->range
.startPosition
- r
.startPosition
;
2690 right
= alloc_layout_range_from(outer
, &r
);
2691 /* new range in the middle */
2692 cur
= alloc_layout_range_from(outer
, &value
->range
);
2693 if (!right
|| !cur
) {
2694 free_layout_range(right
);
2695 free_layout_range(cur
);
2696 return E_OUTOFMEMORY
;
2699 /* reuse container range as a left part */
2700 outer
->range
.length
= value
->range
.startPosition
- outer
->range
.startPosition
;
2703 set_layout_range_attrval(cur
, attr
, value
);
2705 list_add_after(&outer
->entry
, &cur
->entry
);
2706 list_add_after(&cur
->entry
, &right
->entry
);
2708 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2712 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2713 Update all of them. */
2714 left
= get_layout_range_header_by_pos(ranges
, value
->range
.startPosition
);
2715 if (left
->range
.startPosition
== value
->range
.startPosition
)
2716 changed
= set_layout_range_attrval(left
, attr
, value
);
2717 else /* need to split */ {
2718 r
.startPosition
= value
->range
.startPosition
;
2719 r
.length
= left
->range
.length
- value
->range
.startPosition
+ left
->range
.startPosition
;
2720 left
->range
.length
-= r
.length
;
2721 cur
= alloc_layout_range_from(left
, &r
);
2722 changed
= set_layout_range_attrval(cur
, attr
, value
);
2723 list_add_after(&left
->entry
, &cur
->entry
);
2725 cur
= LIST_ENTRY(list_next(ranges
, &left
->entry
), struct layout_range_header
, entry
);
2727 /* for all existing ranges covered by new one update value */
2728 while (cur
&& is_in_layout_range(&value
->range
, &cur
->range
)) {
2729 changed
|= set_layout_range_attrval(cur
, attr
, value
);
2730 cur
= LIST_ENTRY(list_next(ranges
, &cur
->entry
), struct layout_range_header
, entry
);
2733 /* it's possible rightmost range intersects */
2734 if (cur
&& (cur
->range
.startPosition
< value
->range
.startPosition
+ value
->range
.length
)) {
2735 r
.startPosition
= cur
->range
.startPosition
;
2736 r
.length
= value
->range
.startPosition
+ value
->range
.length
- cur
->range
.startPosition
;
2737 left
= alloc_layout_range_from(cur
, &r
);
2738 changed
|= set_layout_range_attrval(left
, attr
, value
);
2739 cur
->range
.startPosition
+= left
->range
.length
;
2740 cur
->range
.length
-= left
->range
.length
;
2741 list_add_before(&cur
->entry
, &left
->entry
);
2746 struct list
*next
, *i
;
2748 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2749 i
= list_head(ranges
);
2750 while ((next
= list_next(ranges
, i
))) {
2751 struct layout_range_header
*next_range
= LIST_ENTRY(next
, struct layout_range_header
, entry
);
2753 cur
= LIST_ENTRY(i
, struct layout_range_header
, entry
);
2754 if (is_same_layout_attributes(cur
, next_range
)) {
2755 /* remove similar range */
2756 cur
->range
.length
+= next_range
->range
.length
;
2758 free_layout_range(next_range
);
2761 i
= list_next(ranges
, i
);
2768 static inline const WCHAR
*get_string_attribute_ptr(struct layout_range
*range
, enum layout_range_attr_kind kind
)
2773 case LAYOUT_RANGE_ATTR_LOCALE
:
2774 str
= range
->locale
;
2776 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2777 str
= range
->fontfamily
;
2786 static HRESULT
get_string_attribute_length(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2787 UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
2789 struct layout_range
*range
;
2792 range
= get_layout_range_by_pos(layout
, position
);
2798 str
= get_string_attribute_ptr(range
, kind
);
2799 *length
= wcslen(str
);
2800 return return_range(&range
->h
, r
);
2803 static HRESULT
get_string_attribute_value(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2804 WCHAR
*ret
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2806 struct layout_range
*range
;
2810 return E_INVALIDARG
;
2813 range
= get_layout_range_by_pos(layout
, position
);
2815 return E_INVALIDARG
;
2817 str
= get_string_attribute_ptr(range
, kind
);
2818 if (length
< wcslen(str
) + 1)
2819 return E_NOT_SUFFICIENT_BUFFER
;
2822 return return_range(&range
->h
, r
);
2825 static HRESULT WINAPI
dwritetextlayout_QueryInterface(IDWriteTextLayout4
*iface
, REFIID riid
, void **obj
)
2827 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2829 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
2833 if (IsEqualIID(riid
, &IID_IDWriteTextLayout4
) ||
2834 IsEqualIID(riid
, &IID_IDWriteTextLayout3
) ||
2835 IsEqualIID(riid
, &IID_IDWriteTextLayout2
) ||
2836 IsEqualIID(riid
, &IID_IDWriteTextLayout1
) ||
2837 IsEqualIID(riid
, &IID_IDWriteTextLayout
) ||
2838 IsEqualIID(riid
, &IID_IUnknown
))
2842 else if (IsEqualIID(riid
, &IID_IDWriteTextFormat3
) ||
2843 IsEqualIID(riid
, &IID_IDWriteTextFormat2
) ||
2844 IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
2845 IsEqualIID(riid
, &IID_IDWriteTextFormat
))
2847 *obj
= &layout
->IDWriteTextFormat3_iface
;
2851 IDWriteTextLayout4_AddRef(iface
);
2855 WARN("%s not implemented.\n", debugstr_guid(riid
));
2857 return E_NOINTERFACE
;
2860 static ULONG WINAPI
dwritetextlayout_AddRef(IDWriteTextLayout4
*iface
)
2862 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2863 ULONG refcount
= InterlockedIncrement(&layout
->refcount
);
2865 TRACE("%p, refcount %lu.\n", iface
, refcount
);
2870 static ULONG WINAPI
dwritetextlayout_Release(IDWriteTextLayout4
*iface
)
2872 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2873 ULONG refcount
= InterlockedDecrement(&layout
->refcount
);
2875 TRACE("%p, refcount %lu.\n", iface
, refcount
);
2879 IDWriteFactory7_Release(layout
->factory
);
2880 free_layout_ranges_list(layout
);
2881 free_layout_eruns(layout
);
2882 free_layout_runs(layout
);
2883 release_format_data(&layout
->format
);
2884 free(layout
->nominal_breakpoints
);
2885 free(layout
->actual_breakpoints
);
2886 free(layout
->clustermetrics
);
2887 free(layout
->clusters
);
2888 free(layout
->lines
);
2896 static HRESULT WINAPI
dwritetextlayout_SetTextAlignment(IDWriteTextLayout4
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
2898 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2899 return IDWriteTextFormat3_SetTextAlignment(&layout
->IDWriteTextFormat3_iface
, alignment
);
2902 static HRESULT WINAPI
dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout4
*iface
,
2903 DWRITE_PARAGRAPH_ALIGNMENT alignment
)
2905 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2906 return IDWriteTextFormat3_SetParagraphAlignment(&layout
->IDWriteTextFormat3_iface
, alignment
);
2909 static HRESULT WINAPI
dwritetextlayout_SetWordWrapping(IDWriteTextLayout4
*iface
, DWRITE_WORD_WRAPPING wrapping
)
2911 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2912 return IDWriteTextFormat3_SetWordWrapping(&layout
->IDWriteTextFormat3_iface
, wrapping
);
2915 static HRESULT WINAPI
dwritetextlayout_SetReadingDirection(IDWriteTextLayout4
*iface
,
2916 DWRITE_READING_DIRECTION direction
)
2918 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2919 return IDWriteTextFormat3_SetReadingDirection(&layout
->IDWriteTextFormat3_iface
, direction
);
2922 static HRESULT WINAPI
dwritetextlayout_SetFlowDirection(IDWriteTextLayout4
*iface
, DWRITE_FLOW_DIRECTION direction
)
2924 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2925 return IDWriteTextFormat3_SetFlowDirection(&layout
->IDWriteTextFormat3_iface
, direction
);
2928 static HRESULT WINAPI
dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout4
*iface
, FLOAT tabstop
)
2930 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2931 return IDWriteTextFormat3_SetIncrementalTabStop(&layout
->IDWriteTextFormat3_iface
, tabstop
);
2934 static HRESULT WINAPI
dwritetextlayout_SetTrimming(IDWriteTextLayout4
*iface
, DWRITE_TRIMMING
const *trimming
,
2935 IDWriteInlineObject
*trimming_sign
)
2937 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2938 return IDWriteTextFormat3_SetTrimming(&layout
->IDWriteTextFormat3_iface
, trimming
, trimming_sign
);
2941 static HRESULT WINAPI
dwritetextlayout_SetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
2942 FLOAT line_spacing
, FLOAT baseline
)
2944 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2945 return IDWriteTextFormat1_SetLineSpacing((IDWriteTextFormat1
*)&layout
->IDWriteTextFormat3_iface
, spacing
,
2946 line_spacing
, baseline
);
2949 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextlayout_GetTextAlignment(IDWriteTextLayout4
*iface
)
2951 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2952 return IDWriteTextFormat3_GetTextAlignment(&layout
->IDWriteTextFormat3_iface
);
2955 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout4
*iface
)
2957 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2958 return IDWriteTextFormat3_GetParagraphAlignment(&layout
->IDWriteTextFormat3_iface
);
2961 static DWRITE_WORD_WRAPPING WINAPI
dwritetextlayout_GetWordWrapping(IDWriteTextLayout4
*iface
)
2963 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2964 return IDWriteTextFormat3_GetWordWrapping(&layout
->IDWriteTextFormat3_iface
);
2967 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_GetReadingDirection(IDWriteTextLayout4
*iface
)
2969 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2970 return IDWriteTextFormat3_GetReadingDirection(&layout
->IDWriteTextFormat3_iface
);
2973 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextlayout_GetFlowDirection(IDWriteTextLayout4
*iface
)
2975 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2976 return IDWriteTextFormat3_GetFlowDirection(&layout
->IDWriteTextFormat3_iface
);
2979 static FLOAT WINAPI
dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout4
*iface
)
2981 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2982 return IDWriteTextFormat3_GetIncrementalTabStop(&layout
->IDWriteTextFormat3_iface
);
2985 static HRESULT WINAPI
dwritetextlayout_GetTrimming(IDWriteTextLayout4
*iface
, DWRITE_TRIMMING
*options
,
2986 IDWriteInlineObject
**trimming_sign
)
2988 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2989 return IDWriteTextFormat3_GetTrimming(&layout
->IDWriteTextFormat3_iface
, options
, trimming_sign
);
2992 static HRESULT WINAPI
dwritetextlayout_GetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
2993 FLOAT
*spacing
, FLOAT
*baseline
)
2995 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2996 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat
*)&layout
->IDWriteTextFormat3_iface
, method
,
3000 static HRESULT WINAPI
dwritetextlayout_GetFontCollection(IDWriteTextLayout4
*iface
, IDWriteFontCollection
**collection
)
3002 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3003 return IDWriteTextFormat3_GetFontCollection(&layout
->IDWriteTextFormat3_iface
, collection
);
3006 static UINT32 WINAPI
dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout4
*iface
)
3008 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3009 return IDWriteTextFormat3_GetFontFamilyNameLength(&layout
->IDWriteTextFormat3_iface
);
3012 static HRESULT WINAPI
dwritetextlayout_GetFontFamilyName(IDWriteTextLayout4
*iface
, WCHAR
*name
, UINT32 size
)
3014 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3015 return IDWriteTextFormat3_GetFontFamilyName(&layout
->IDWriteTextFormat3_iface
, name
, size
);
3018 static DWRITE_FONT_WEIGHT WINAPI
dwritetextlayout_GetFontWeight(IDWriteTextLayout4
*iface
)
3020 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3021 return IDWriteTextFormat3_GetFontWeight(&layout
->IDWriteTextFormat3_iface
);
3024 static DWRITE_FONT_STYLE WINAPI
dwritetextlayout_GetFontStyle(IDWriteTextLayout4
*iface
)
3026 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3027 return IDWriteTextFormat3_GetFontStyle(&layout
->IDWriteTextFormat3_iface
);
3030 static DWRITE_FONT_STRETCH WINAPI
dwritetextlayout_GetFontStretch(IDWriteTextLayout4
*iface
)
3032 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3033 return IDWriteTextFormat3_GetFontStretch(&layout
->IDWriteTextFormat3_iface
);
3036 static FLOAT WINAPI
dwritetextlayout_GetFontSize(IDWriteTextLayout4
*iface
)
3038 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3039 return IDWriteTextFormat3_GetFontSize(&layout
->IDWriteTextFormat3_iface
);
3042 static UINT32 WINAPI
dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout4
*iface
)
3044 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3045 return IDWriteTextFormat3_GetLocaleNameLength(&layout
->IDWriteTextFormat3_iface
);
3048 static HRESULT WINAPI
dwritetextlayout_GetLocaleName(IDWriteTextLayout4
*iface
, WCHAR
*name
, UINT32 size
)
3050 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3051 return IDWriteTextFormat3_GetLocaleName(&layout
->IDWriteTextFormat3_iface
, name
, size
);
3054 static HRESULT WINAPI
dwritetextlayout_SetMaxWidth(IDWriteTextLayout4
*iface
, FLOAT maxWidth
)
3056 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3059 TRACE("%p, %.8e.\n", iface
, maxWidth
);
3061 if (maxWidth
< 0.0f
)
3062 return E_INVALIDARG
;
3064 changed
= layout
->metrics
.layoutWidth
!= maxWidth
;
3065 layout
->metrics
.layoutWidth
= maxWidth
;
3068 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3072 static HRESULT WINAPI
dwritetextlayout_SetMaxHeight(IDWriteTextLayout4
*iface
, FLOAT maxHeight
)
3074 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3077 TRACE("%p, %.8e.\n", iface
, maxHeight
);
3079 if (maxHeight
< 0.0f
)
3080 return E_INVALIDARG
;
3082 changed
= layout
->metrics
.layoutHeight
!= maxHeight
;
3083 layout
->metrics
.layoutHeight
= maxHeight
;
3086 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3090 static HRESULT WINAPI
dwritetextlayout_SetFontCollection(IDWriteTextLayout4
*iface
, IDWriteFontCollection
*collection
,
3091 DWRITE_TEXT_RANGE range
)
3093 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3094 struct layout_range_attr_value value
;
3096 TRACE("%p, %p, %s.\n", iface
, collection
, debugstr_range(&range
));
3098 value
.range
= range
;
3099 value
.u
.collection
= collection
;
3100 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_FONTCOLL
, &value
);
3103 static HRESULT WINAPI
dwritetextlayout_SetFontFamilyName(IDWriteTextLayout4
*iface
, WCHAR
const *name
,
3104 DWRITE_TEXT_RANGE range
)
3106 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3107 struct layout_range_attr_value value
;
3109 TRACE("%p, %s, %s.\n", iface
, debugstr_w(name
), debugstr_range(&range
));
3112 return E_INVALIDARG
;
3114 value
.range
= range
;
3115 value
.u
.fontfamily
= name
;
3116 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_FONTFAMILY
, &value
);
3119 static HRESULT WINAPI
dwritetextlayout_SetFontWeight(IDWriteTextLayout4
*iface
, DWRITE_FONT_WEIGHT weight
,
3120 DWRITE_TEXT_RANGE range
)
3122 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3123 struct layout_range_attr_value value
;
3125 TRACE("%p, %d, %s.\n", iface
, weight
, debugstr_range(&range
));
3127 if ((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
3128 return E_INVALIDARG
;
3130 value
.range
= range
;
3131 value
.u
.weight
= weight
;
3132 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_WEIGHT
, &value
);
3135 static HRESULT WINAPI
dwritetextlayout_SetFontStyle(IDWriteTextLayout4
*iface
, DWRITE_FONT_STYLE style
,
3136 DWRITE_TEXT_RANGE range
)
3138 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3139 struct layout_range_attr_value value
;
3141 TRACE("%p, %d, %s.\n", iface
, style
, debugstr_range(&range
));
3143 if ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
)
3144 return E_INVALIDARG
;
3146 value
.range
= range
;
3147 value
.u
.style
= style
;
3148 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_STYLE
, &value
);
3151 static HRESULT WINAPI
dwritetextlayout_SetFontStretch(IDWriteTextLayout4
*iface
, DWRITE_FONT_STRETCH stretch
,
3152 DWRITE_TEXT_RANGE range
)
3154 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3155 struct layout_range_attr_value value
;
3157 TRACE("%p, %d, %s.\n", iface
, stretch
, debugstr_range(&range
));
3159 if (stretch
== DWRITE_FONT_STRETCH_UNDEFINED
|| (UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
3160 return E_INVALIDARG
;
3162 value
.range
= range
;
3163 value
.u
.stretch
= stretch
;
3164 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_STRETCH
, &value
);
3167 static HRESULT WINAPI
dwritetextlayout_SetFontSize(IDWriteTextLayout4
*iface
, FLOAT size
, DWRITE_TEXT_RANGE range
)
3169 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3170 struct layout_range_attr_value value
;
3172 TRACE("%p, %.8e, %s.\n", iface
, size
, debugstr_range(&range
));
3175 return E_INVALIDARG
;
3177 value
.range
= range
;
3178 value
.u
.fontsize
= size
;
3179 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_FONTSIZE
, &value
);
3182 static HRESULT WINAPI
dwritetextlayout_SetUnderline(IDWriteTextLayout4
*iface
, BOOL underline
, DWRITE_TEXT_RANGE range
)
3184 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3185 struct layout_range_attr_value value
;
3187 TRACE("%p, %d, %s.\n", iface
, underline
, debugstr_range(&range
));
3189 value
.range
= range
;
3190 value
.u
.underline
= underline
;
3191 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_UNDERLINE
, &value
);
3194 static HRESULT WINAPI
dwritetextlayout_SetStrikethrough(IDWriteTextLayout4
*iface
, BOOL strikethrough
,
3195 DWRITE_TEXT_RANGE range
)
3197 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3198 struct layout_range_attr_value value
;
3200 TRACE("%p, %d, %s.\n", iface
, strikethrough
, debugstr_range(&range
));
3202 value
.range
= range
;
3203 value
.u
.strikethrough
= strikethrough
;
3204 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_STRIKETHROUGH
, &value
);
3207 static HRESULT WINAPI
dwritetextlayout_SetDrawingEffect(IDWriteTextLayout4
*iface
, IUnknown
* effect
,
3208 DWRITE_TEXT_RANGE range
)
3210 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3211 struct layout_range_attr_value value
;
3213 TRACE("%p, %p, %s.\n", iface
, effect
, debugstr_range(&range
));
3215 value
.range
= range
;
3216 value
.u
.effect
= effect
;
3217 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_EFFECT
, &value
);
3220 static HRESULT WINAPI
dwritetextlayout_SetInlineObject(IDWriteTextLayout4
*iface
, IDWriteInlineObject
*object
,
3221 DWRITE_TEXT_RANGE range
)
3223 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3224 struct layout_range_attr_value value
;
3226 TRACE("%p, %p, %s.\n", iface
, object
, debugstr_range(&range
));
3228 value
.range
= range
;
3229 value
.u
.object
= object
;
3230 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_INLINE
, &value
);
3233 static HRESULT WINAPI
dwritetextlayout_SetTypography(IDWriteTextLayout4
*iface
, IDWriteTypography
*typography
,
3234 DWRITE_TEXT_RANGE range
)
3236 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3237 struct layout_range_attr_value value
;
3239 TRACE("%p, %p, %s.\n", iface
, typography
, debugstr_range(&range
));
3241 value
.range
= range
;
3242 value
.u
.typography
= typography
;
3243 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_TYPOGRAPHY
, &value
);
3246 static HRESULT WINAPI
dwritetextlayout_SetLocaleName(IDWriteTextLayout4
*iface
, WCHAR
const* locale
,
3247 DWRITE_TEXT_RANGE range
)
3249 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3250 struct layout_range_attr_value value
;
3252 TRACE("%p, %s, %s.\n", iface
, debugstr_w(locale
), debugstr_range(&range
));
3254 if (!locale
|| wcslen(locale
) > LOCALE_NAME_MAX_LENGTH
-1)
3255 return E_INVALIDARG
;
3257 value
.range
= range
;
3258 value
.u
.locale
= locale
;
3259 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_LOCALE
, &value
);
3262 static FLOAT WINAPI
dwritetextlayout_GetMaxWidth(IDWriteTextLayout4
*iface
)
3264 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3266 TRACE("%p.\n", iface
);
3268 return layout
->metrics
.layoutWidth
;
3271 static FLOAT WINAPI
dwritetextlayout_GetMaxHeight(IDWriteTextLayout4
*iface
)
3273 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3275 TRACE("%p.\n", iface
);
3277 return layout
->metrics
.layoutHeight
;
3280 static HRESULT WINAPI
dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout4
*iface
, UINT32 position
,
3281 IDWriteFontCollection
**collection
, DWRITE_TEXT_RANGE
*r
)
3283 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3284 struct layout_range
*range
;
3286 TRACE("%p, %u, %p, %p.\n", iface
, position
, collection
, r
);
3288 range
= get_layout_range_by_pos(layout
, position
);
3289 *collection
= range
->collection
;
3291 IDWriteFontCollection_AddRef(*collection
);
3293 return return_range(&range
->h
, r
);
3296 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout4
*iface
,
3297 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3299 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3301 TRACE("%p, %d, %p, %p.\n", iface
, position
, length
, r
);
3303 return get_string_attribute_length(layout
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, length
, r
);
3306 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout4
*iface
,
3307 UINT32 position
, WCHAR
*name
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3309 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3311 TRACE("%p, %u, %p, %u, %p.\n", iface
, position
, name
, length
, r
);
3313 return get_string_attribute_value(layout
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, name
, length
, r
);
3316 static HRESULT WINAPI
dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout4
*iface
,
3317 UINT32 position
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_TEXT_RANGE
*r
)
3319 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3320 struct layout_range
*range
;
3322 TRACE("%p, %u, %p, %p.\n", iface
, position
, weight
, r
);
3324 range
= get_layout_range_by_pos(layout
, position
);
3325 *weight
= range
->weight
;
3327 return return_range(&range
->h
, r
);
3330 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout4
*iface
,
3331 UINT32 position
, DWRITE_FONT_STYLE
*style
, DWRITE_TEXT_RANGE
*r
)
3333 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3334 struct layout_range
*range
;
3336 TRACE("%p, %u, %p, %p.\n", iface
, position
, style
, r
);
3338 range
= get_layout_range_by_pos(layout
, position
);
3339 *style
= range
->style
;
3340 return return_range(&range
->h
, r
);
3343 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout4
*iface
,
3344 UINT32 position
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_TEXT_RANGE
*r
)
3346 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3347 struct layout_range
*range
;
3349 TRACE("%p, %u, %p, %p.\n", iface
, position
, stretch
, r
);
3351 range
= get_layout_range_by_pos(layout
, position
);
3352 *stretch
= range
->stretch
;
3353 return return_range(&range
->h
, r
);
3356 static HRESULT WINAPI
dwritetextlayout_layout_GetFontSize(IDWriteTextLayout4
*iface
,
3357 UINT32 position
, FLOAT
*size
, DWRITE_TEXT_RANGE
*r
)
3359 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3360 struct layout_range
*range
;
3362 TRACE("%p, %u, %p, %p.\n", iface
, position
, size
, r
);
3364 range
= get_layout_range_by_pos(layout
, position
);
3365 *size
= range
->fontsize
;
3366 return return_range(&range
->h
, r
);
3369 static HRESULT WINAPI
dwritetextlayout_GetUnderline(IDWriteTextLayout4
*iface
,
3370 UINT32 position
, BOOL
*underline
, DWRITE_TEXT_RANGE
*r
)
3372 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3373 struct layout_range_bool
*range
;
3375 TRACE("%p, %u, %p, %p.\n", iface
, position
, underline
, r
);
3377 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&layout
->underline_ranges
, position
);
3378 *underline
= range
->value
;
3380 return return_range(&range
->h
, r
);
3383 static HRESULT WINAPI
dwritetextlayout_GetStrikethrough(IDWriteTextLayout4
*iface
,
3384 UINT32 position
, BOOL
*strikethrough
, DWRITE_TEXT_RANGE
*r
)
3386 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3387 struct layout_range_bool
*range
;
3389 TRACE("%p, %u, %p, %p.\n", iface
, position
, strikethrough
, r
);
3391 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&layout
->strike_ranges
, position
);
3392 *strikethrough
= range
->value
;
3394 return return_range(&range
->h
, r
);
3397 static HRESULT WINAPI
dwritetextlayout_GetDrawingEffect(IDWriteTextLayout4
*iface
,
3398 UINT32 position
, IUnknown
**effect
, DWRITE_TEXT_RANGE
*r
)
3400 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3401 struct layout_range_iface
*range
;
3403 TRACE("%p, %u, %p, %p.\n", iface
, position
, effect
, r
);
3405 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->effects
, position
);
3406 *effect
= range
->iface
;
3408 IUnknown_AddRef(*effect
);
3410 return return_range(&range
->h
, r
);
3413 static HRESULT WINAPI
dwritetextlayout_GetInlineObject(IDWriteTextLayout4
*iface
,
3414 UINT32 position
, IDWriteInlineObject
**object
, DWRITE_TEXT_RANGE
*r
)
3416 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3417 struct layout_range
*range
;
3419 TRACE("%p, %u, %p, %p.\n", iface
, position
, object
, r
);
3421 range
= get_layout_range_by_pos(layout
, position
);
3422 *object
= range
->object
;
3424 IDWriteInlineObject_AddRef(*object
);
3426 return return_range(&range
->h
, r
);
3429 static HRESULT WINAPI
dwritetextlayout_GetTypography(IDWriteTextLayout4
*iface
,
3430 UINT32 position
, IDWriteTypography
** typography
, DWRITE_TEXT_RANGE
*r
)
3432 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3433 struct layout_range_iface
*range
;
3435 TRACE("%p, %u, %p, %p.\n", iface
, position
, typography
, r
);
3437 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->typographies
, position
);
3438 *typography
= (IDWriteTypography
*)range
->iface
;
3440 IDWriteTypography_AddRef(*typography
);
3442 return return_range(&range
->h
, r
);
3445 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout4
*iface
,
3446 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3448 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3450 TRACE("%p, %u, %p, %p.\n", iface
, position
, length
, r
);
3452 return get_string_attribute_length(layout
, LAYOUT_RANGE_ATTR_LOCALE
, position
, length
, r
);
3455 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout4
*iface
,
3456 UINT32 position
, WCHAR
*locale
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3458 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3460 TRACE("%p, %u, %p, %u, %p.\n", iface
, position
, locale
, length
, r
);
3462 return get_string_attribute_value(layout
, LAYOUT_RANGE_ATTR_LOCALE
, position
, locale
, length
, r
);
3465 static inline FLOAT
renderer_apply_snapping(FLOAT coord
, BOOL skiptransform
, FLOAT ppdip
, FLOAT det
,
3466 const DWRITE_MATRIX
*m
)
3468 D2D1_POINT_2F vec
, vec2
;
3470 if (!skiptransform
) {
3471 /* apply transform */
3473 vec
.y
= coord
* ppdip
;
3475 vec2
.x
= m
->m11
* vec
.x
+ m
->m21
* vec
.y
+ m
->dx
;
3476 vec2
.y
= m
->m12
* vec
.x
+ m
->m22
* vec
.y
+ m
->dy
;
3479 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
3480 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
3482 /* apply inverted transform, we don't care about X component at this point */
3483 vec
.y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
3487 vec
.y
= floorf(coord
* ppdip
+ 0.5f
) / ppdip
;
3492 static HRESULT WINAPI
dwritetextlayout_Draw(IDWriteTextLayout4
*iface
,
3493 void *context
, IDWriteTextRenderer
* renderer
, FLOAT origin_x
, FLOAT origin_y
)
3495 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3496 BOOL disabled
= FALSE
, skiptransform
= FALSE
;
3497 struct layout_effective_inline
*inlineobject
;
3498 struct layout_effective_run
*run
;
3499 struct layout_strikethrough
*s
;
3500 struct layout_underline
*u
;
3501 FLOAT det
= 0.0f
, ppdip
= 0.0f
;
3502 DWRITE_MATRIX m
= { 0 };
3505 TRACE("%p, %p, %p, %.8e, %.8e.\n", iface
, context
, renderer
, origin_x
, origin_y
);
3507 hr
= layout_compute_effective_runs(layout
);
3511 hr
= IDWriteTextRenderer_IsPixelSnappingDisabled(renderer
, context
, &disabled
);
3516 hr
= IDWriteTextRenderer_GetPixelsPerDip(renderer
, context
, &ppdip
);
3520 hr
= IDWriteTextRenderer_GetCurrentTransform(renderer
, context
, &m
);
3524 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3525 if (ppdip
<= 0.0f
||
3526 (m
.m11
* m
.m22
!= 0.0f
&& (m
.m12
!= 0.0f
|| m
.m21
!= 0.0f
)) ||
3527 (m
.m12
* m
.m21
!= 0.0f
&& (m
.m11
!= 0.0f
|| m
.m22
!= 0.0f
)))
3530 skiptransform
= should_skip_transform(&m
, &det
);
3533 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3534 /* 1. Regular runs */
3535 LIST_FOR_EACH_ENTRY(run
, &layout
->eruns
, struct layout_effective_run
, entry
)
3537 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3538 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3539 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
3540 DWRITE_GLYPH_RUN glyph_run
;
3542 /* Everything but cluster map will be reused from nominal run, as we only need
3543 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3544 it can't be reused because it has to start with 0 index for each reported run. */
3545 glyph_run
= regular
->run
;
3546 glyph_run
.glyphCount
= run
->glyphcount
;
3548 /* fixup glyph data arrays */
3549 glyph_run
.glyphIndices
+= start_glyph
;
3550 glyph_run
.glyphAdvances
+= start_glyph
;
3551 glyph_run
.glyphOffsets
+= start_glyph
;
3554 descr
= regular
->descr
;
3555 descr
.stringLength
= run
->length
;
3556 descr
.string
+= run
->start
;
3557 descr
.clusterMap
= run
->clustermap
;
3558 descr
.textPosition
+= run
->start
;
3560 /* return value is ignored */
3561 IDWriteTextRenderer_DrawGlyphRun(renderer
,
3563 run
->origin
.x
+ run
->align_dx
+ origin_x
,
3564 SNAP_COORD(run
->origin
.y
+ origin_y
),
3565 layout
->measuringmode
,
3571 /* 2. Inline objects */
3572 LIST_FOR_EACH_ENTRY(inlineobject
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
)
3574 IDWriteTextRenderer_DrawInlineObject(renderer
,
3576 inlineobject
->origin
.x
+ inlineobject
->align_dx
+ origin_x
,
3577 SNAP_COORD(inlineobject
->origin
.y
+ origin_y
),
3578 inlineobject
->object
,
3579 inlineobject
->is_sideways
,
3580 inlineobject
->is_rtl
,
3581 inlineobject
->effect
);
3585 LIST_FOR_EACH_ENTRY(u
, &layout
->underlines
, struct layout_underline
, entry
)
3587 IDWriteTextRenderer_DrawUnderline(renderer
,
3589 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3590 (is_run_rtl(u
->run
) ? u
->run
->origin
.x
- u
->run
->width
: u
->run
->origin
.x
) + u
->run
->align_dx
+ origin_x
,
3591 SNAP_COORD(u
->run
->origin
.y
+ origin_y
),
3596 /* 4. Strikethrough */
3597 LIST_FOR_EACH_ENTRY(s
, &layout
->strikethrough
, struct layout_strikethrough
, entry
)
3599 IDWriteTextRenderer_DrawStrikethrough(renderer
,
3601 s
->run
->origin
.x
+ s
->run
->align_dx
+ origin_x
,
3602 SNAP_COORD(s
->run
->origin
.y
+ origin_y
),
3611 static HRESULT WINAPI
dwritetextlayout_GetLineMetrics(IDWriteTextLayout4
*iface
,
3612 DWRITE_LINE_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3614 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3615 unsigned int line_count
;
3619 TRACE("%p, %p, %u, %p.\n", iface
, metrics
, max_count
, count
);
3621 if (FAILED(hr
= layout_compute_effective_runs(layout
)))
3626 line_count
= min(max_count
, layout
->metrics
.lineCount
);
3627 for (i
= 0; i
< line_count
; ++i
)
3628 memcpy(&metrics
[i
], &layout
->lines
[i
].metrics
, sizeof(*metrics
));
3631 *count
= layout
->metrics
.lineCount
;
3632 return max_count
>= layout
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3635 static HRESULT
layout_update_metrics(struct dwrite_textlayout
*layout
)
3637 return layout_compute_effective_runs(layout
);
3640 static HRESULT WINAPI
dwritetextlayout_GetMetrics(IDWriteTextLayout4
*iface
, DWRITE_TEXT_METRICS
*metrics
)
3642 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3645 TRACE("%p, %p.\n", iface
, metrics
);
3647 hr
= layout_update_metrics(layout
);
3649 memcpy(metrics
, &layout
->metrics
, sizeof(*metrics
));
3654 static void d2d_rect_offset(D2D1_RECT_F
*rect
, FLOAT x
, FLOAT y
)
3662 static BOOL
d2d_rect_is_empty(const D2D1_RECT_F
*rect
)
3664 return ((rect
->left
>= rect
->right
) || (rect
->top
>= rect
->bottom
));
3667 static void d2d_rect_union(D2D1_RECT_F
*dst
, const D2D1_RECT_F
*src
)
3669 if (d2d_rect_is_empty(dst
)) {
3670 if (d2d_rect_is_empty(src
)) {
3671 dst
->left
= dst
->right
= dst
->top
= dst
->bottom
= 0.0f
;
3678 if (!d2d_rect_is_empty(src
)) {
3679 dst
->left
= min(dst
->left
, src
->left
);
3680 dst
->right
= max(dst
->right
, src
->right
);
3681 dst
->top
= min(dst
->top
, src
->top
);
3682 dst
->bottom
= max(dst
->bottom
, src
->bottom
);
3687 static void layout_get_erun_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_run
*run
, D2D1_RECT_F
*bbox
)
3689 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3690 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3691 D2D1_POINT_2F baseline_origin
= { 0 }, *origins
;
3692 DWRITE_GLYPH_RUN glyph_run
;
3696 if (run
->bbox
.top
== run
->bbox
.bottom
)
3698 struct dwrite_glyphbitmap glyph_bitmap
;
3701 glyph_run
= regular
->run
;
3702 glyph_run
.glyphCount
= run
->glyphcount
;
3703 glyph_run
.glyphIndices
= ®ular
->run
.glyphIndices
[start_glyph
];
3704 glyph_run
.glyphAdvances
= ®ular
->run
.glyphAdvances
[start_glyph
];
3705 glyph_run
.glyphOffsets
= ®ular
->run
.glyphOffsets
[start_glyph
];
3707 memset(&glyph_bitmap
, 0, sizeof(glyph_bitmap
));
3708 glyph_bitmap
.simulations
= IDWriteFontFace_GetSimulations(glyph_run
.fontFace
);
3709 glyph_bitmap
.emsize
= glyph_run
.fontEmSize
;
3711 bbox
= &glyph_bitmap
.bbox
;
3713 if (!(origins
= calloc(glyph_run
.glyphCount
, sizeof(*origins
))))
3716 if (FAILED(hr
= compute_glyph_origins(&glyph_run
, layout
->measuringmode
, baseline_origin
, &layout
->transform
, origins
)))
3718 WARN("Failed to compute glyph origins, hr %#lx.\n", hr
);
3723 for (i
= 0; i
< glyph_run
.glyphCount
; ++i
)
3725 D2D1_RECT_F glyph_bbox
;
3727 glyph_bitmap
.glyph
= glyph_run
.glyphIndices
[i
];
3728 dwrite_fontface_get_glyph_bbox(glyph_run
.fontFace
, &glyph_bitmap
);
3730 glyph_bbox
.left
= bbox
->left
;
3731 glyph_bbox
.top
= bbox
->top
;
3732 glyph_bbox
.right
= bbox
->right
;
3733 glyph_bbox
.bottom
= bbox
->bottom
;
3735 d2d_rect_offset(&glyph_bbox
, origins
[i
].x
, origins
[i
].y
);
3736 d2d_rect_union(&run
->bbox
, &glyph_bbox
);
3743 d2d_rect_offset(bbox
, run
->origin
.x
+ run
->align_dx
, run
->origin
.y
);
3746 static void layout_get_inlineobj_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_inline
*run
,
3749 DWRITE_OVERHANG_METRICS overhang_metrics
= { 0 };
3750 DWRITE_INLINE_OBJECT_METRICS metrics
= { 0 };
3753 if (FAILED(hr
= IDWriteInlineObject_GetMetrics(run
->object
, &metrics
))) {
3754 WARN("Failed to get inline object metrics, hr %#lx.\n", hr
);
3755 memset(bbox
, 0, sizeof(*bbox
));
3759 bbox
->left
= run
->origin
.x
+ run
->align_dx
;
3760 bbox
->right
= bbox
->left
+ metrics
.width
;
3761 bbox
->top
= run
->origin
.y
;
3762 bbox
->bottom
= bbox
->top
+ metrics
.height
;
3764 IDWriteInlineObject_GetOverhangMetrics(run
->object
, &overhang_metrics
);
3766 bbox
->left
-= overhang_metrics
.left
;
3767 bbox
->right
+= overhang_metrics
.right
;
3768 bbox
->top
-= overhang_metrics
.top
;
3769 bbox
->bottom
+= overhang_metrics
.bottom
;
3772 static HRESULT WINAPI
dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout4
*iface
,
3773 DWRITE_OVERHANG_METRICS
*overhangs
)
3775 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3776 struct layout_effective_inline
*inline_run
;
3777 struct layout_effective_run
*run
;
3778 D2D1_RECT_F bbox
= { 0 };
3781 TRACE("%p, %p.\n", iface
, overhangs
);
3783 memset(overhangs
, 0, sizeof(*overhangs
));
3785 if (!(layout
->recompute
& RECOMPUTE_OVERHANGS
))
3787 *overhangs
= layout
->overhangs
;
3791 hr
= layout_compute_effective_runs(layout
);
3795 LIST_FOR_EACH_ENTRY(run
, &layout
->eruns
, struct layout_effective_run
, entry
)
3797 D2D1_RECT_F run_bbox
;
3799 layout_get_erun_bbox(layout
, run
, &run_bbox
);
3800 d2d_rect_union(&bbox
, &run_bbox
);
3803 LIST_FOR_EACH_ENTRY(inline_run
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
)
3805 D2D1_RECT_F object_bbox
;
3807 layout_get_inlineobj_bbox(layout
, inline_run
, &object_bbox
);
3808 d2d_rect_union(&bbox
, &object_bbox
);
3811 /* Deltas from layout box. */
3812 layout
->overhangs
.left
= -bbox
.left
;
3813 layout
->overhangs
.top
= -bbox
.top
;
3814 layout
->overhangs
.right
= bbox
.right
- layout
->metrics
.layoutWidth
;
3815 layout
->overhangs
.bottom
= bbox
.bottom
- layout
->metrics
.layoutHeight
;
3816 layout
->recompute
&= ~RECOMPUTE_OVERHANGS
;
3818 *overhangs
= layout
->overhangs
;
3823 static HRESULT WINAPI
dwritetextlayout_GetClusterMetrics(IDWriteTextLayout4
*iface
,
3824 DWRITE_CLUSTER_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3826 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3829 TRACE("%p, %p, %u, %p.\n", iface
, metrics
, max_count
, count
);
3831 hr
= layout_compute(layout
);
3836 memcpy(metrics
, layout
->clustermetrics
, sizeof(DWRITE_CLUSTER_METRICS
) * min(max_count
, layout
->cluster_count
));
3838 *count
= layout
->cluster_count
;
3839 return max_count
>= layout
->cluster_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3842 static HRESULT WINAPI
dwritetextlayout_DetermineMinWidth(IDWriteTextLayout4
*iface
, FLOAT
* min_width
)
3844 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3849 TRACE("%p, %p.\n", iface
, min_width
);
3852 return E_INVALIDARG
;
3854 if (!(layout
->recompute
& RECOMPUTE_MINIMAL_WIDTH
))
3858 hr
= layout_compute(layout
);
3862 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3863 preceding breaking point do not contribute to word width. */
3864 for (start
= 0; start
< layout
->cluster_count
;)
3866 UINT32 end
= start
, j
, next
;
3868 /* Last cluster always could be wrapped after. */
3869 while (!layout
->clustermetrics
[end
].canWrapLineAfter
)
3871 /* make is so current cluster range that we can wrap after is [start,end) */
3876 /* Ignore trailing whitespace clusters, in case of single space range will
3877 be reduced to empty range, or [start,start+1). */
3878 while (end
> start
&& layout
->clustermetrics
[end
-1].isWhitespace
)
3881 /* check if cluster range exceeds last minimal width */
3883 for (j
= start
; j
< end
; j
++)
3884 width
+= layout
->clustermetrics
[j
].width
;
3888 if (width
> layout
->minwidth
)
3889 layout
->minwidth
= width
;
3891 layout
->recompute
&= ~RECOMPUTE_MINIMAL_WIDTH
;
3894 *min_width
= layout
->minwidth
;
3898 static HRESULT WINAPI
dwritetextlayout_HitTestPoint(IDWriteTextLayout4
*iface
,
3899 FLOAT pointX
, FLOAT pointY
, BOOL
* is_trailinghit
, BOOL
* is_inside
, DWRITE_HIT_TEST_METRICS
*metrics
)
3901 FIXME("%p, %.8e, %.8e, %p, %p, %p): stub\n", iface
, pointX
, pointY
, is_trailinghit
, is_inside
, metrics
);
3906 static HRESULT WINAPI
dwritetextlayout_HitTestTextPosition(IDWriteTextLayout4
*iface
,
3907 UINT32 textPosition
, BOOL is_trailinghit
, FLOAT
*pointX
, FLOAT
*pointY
, DWRITE_HIT_TEST_METRICS
*metrics
)
3909 FIXME("%p, %u, %d, %p, %p, %p): stub\n", iface
, textPosition
, is_trailinghit
, pointX
, pointY
, metrics
);
3914 static HRESULT WINAPI
dwritetextlayout_HitTestTextRange(IDWriteTextLayout4
*iface
,
3915 UINT32 textPosition
, UINT32 textLength
, FLOAT originX
, FLOAT originY
,
3916 DWRITE_HIT_TEST_METRICS
*metrics
, UINT32 max_metricscount
, UINT32
* actual_metricscount
)
3918 FIXME("%p, %u, %u, %f, %f, %p, %u, %p): stub\n", iface
, textPosition
, textLength
, originX
, originY
, metrics
,
3919 max_metricscount
, actual_metricscount
);
3924 static HRESULT WINAPI
dwritetextlayout1_SetPairKerning(IDWriteTextLayout4
*iface
, BOOL is_pairkerning_enabled
,
3925 DWRITE_TEXT_RANGE range
)
3927 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3928 struct layout_range_attr_value value
;
3930 TRACE("%p, %d, %s.\n", iface
, is_pairkerning_enabled
, debugstr_range(&range
));
3932 value
.range
= range
;
3933 value
.u
.pair_kerning
= !!is_pairkerning_enabled
;
3934 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_PAIR_KERNING
, &value
);
3937 static HRESULT WINAPI
dwritetextlayout1_GetPairKerning(IDWriteTextLayout4
*iface
, UINT32 position
,
3938 BOOL
*is_pairkerning_enabled
, DWRITE_TEXT_RANGE
*r
)
3940 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3941 struct layout_range
*range
;
3943 TRACE("%p, %u, %p, %p.\n", iface
, position
, is_pairkerning_enabled
, r
);
3945 range
= get_layout_range_by_pos(layout
, position
);
3946 *is_pairkerning_enabled
= range
->pair_kerning
;
3948 return return_range(&range
->h
, r
);
3951 static HRESULT WINAPI
dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout4
*iface
, FLOAT leading
, FLOAT trailing
,
3952 FLOAT min_advance
, DWRITE_TEXT_RANGE range
)
3954 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3955 struct layout_range_attr_value value
;
3957 TRACE("%p, %.8e, %.8e, %.8e, %s.\n", iface
, leading
, trailing
, min_advance
, debugstr_range(&range
));
3959 if (min_advance
< 0.0f
)
3960 return E_INVALIDARG
;
3962 value
.range
= range
;
3963 value
.u
.spacing
.leading
= leading
;
3964 value
.u
.spacing
.trailing
= trailing
;
3965 value
.u
.spacing
.min_advance
= min_advance
;
3966 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_SPACING
, &value
);
3969 static HRESULT WINAPI
dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout4
*iface
, UINT32 position
, FLOAT
*leading
,
3970 FLOAT
*trailing
, FLOAT
*min_advance
, DWRITE_TEXT_RANGE
*r
)
3972 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3973 struct layout_range_spacing
*range
;
3975 TRACE("%p, %u, %p, %p, %p, %p.\n", iface
, position
, leading
, trailing
, min_advance
, r
);
3977 range
= (struct layout_range_spacing
*)get_layout_range_header_by_pos(&layout
->spacing
, position
);
3978 *leading
= range
->leading
;
3979 *trailing
= range
->trailing
;
3980 *min_advance
= range
->min_advance
;
3982 return return_range(&range
->h
, r
);
3985 static HRESULT WINAPI
dwritetextlayout2_GetMetrics(IDWriteTextLayout4
*iface
, DWRITE_TEXT_METRICS1
*metrics
)
3987 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3990 TRACE("%p, %p.\n", iface
, metrics
);
3992 if (SUCCEEDED(hr
= layout_update_metrics(layout
)))
3993 *metrics
= layout
->metrics
;
3998 static HRESULT
layout_set_vertical_orientation(struct dwrite_textlayout
*layout
,
3999 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4004 if (FAILED(hr
= format_set_vertical_orientation(&layout
->format
, orientation
, &changed
)))
4008 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4013 static HRESULT WINAPI
dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout4
*iface
,
4014 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4016 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4018 TRACE("%p, %d.\n", iface
, orientation
);
4020 return layout_set_vertical_orientation(layout
, orientation
);
4023 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout4
*iface
)
4025 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4027 TRACE("%p.\n", iface
);
4029 return layout
->format
.vertical_orientation
;
4032 static HRESULT WINAPI
dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout4
*iface
, BOOL lastline_wrapping_enabled
)
4034 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4036 TRACE("%p, %d.\n", iface
, lastline_wrapping_enabled
);
4038 return IDWriteTextFormat3_SetLastLineWrapping(&layout
->IDWriteTextFormat3_iface
, lastline_wrapping_enabled
);
4041 static BOOL WINAPI
dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout4
*iface
)
4043 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4045 TRACE("%p.\n", iface
);
4047 return IDWriteTextFormat3_GetLastLineWrapping(&layout
->IDWriteTextFormat3_iface
);
4050 static HRESULT WINAPI
dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout4
*iface
,
4051 DWRITE_OPTICAL_ALIGNMENT alignment
)
4053 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4055 TRACE("%p, %d.\n", iface
, alignment
);
4057 return IDWriteTextFormat3_SetOpticalAlignment(&layout
->IDWriteTextFormat3_iface
, alignment
);
4060 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout4
*iface
)
4062 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4064 TRACE("%p.\n", iface
);
4066 return IDWriteTextFormat3_GetOpticalAlignment(&layout
->IDWriteTextFormat3_iface
);
4069 static HRESULT WINAPI
dwritetextlayout2_SetFontFallback(IDWriteTextLayout4
*iface
, IDWriteFontFallback
*fallback
)
4071 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4073 TRACE("%p, %p.\n", iface
, fallback
);
4075 return format_set_fontfallback(&layout
->format
, fallback
);
4078 static HRESULT WINAPI
dwritetextlayout2_GetFontFallback(IDWriteTextLayout4
*iface
, IDWriteFontFallback
**fallback
)
4080 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4082 TRACE("%p, %p.\n", iface
, fallback
);
4084 return format_get_fontfallback(&layout
->format
, fallback
);
4087 static HRESULT WINAPI
dwritetextlayout3_InvalidateLayout(IDWriteTextLayout4
*iface
)
4089 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4091 TRACE("%p.\n", iface
);
4093 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4097 static HRESULT WINAPI
dwritetextlayout3_SetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING
const *spacing
)
4099 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4103 TRACE("%p, %p.\n", iface
, spacing
);
4105 hr
= format_set_linespacing(&layout
->format
, spacing
, &changed
);
4111 if (!(layout
->recompute
& RECOMPUTE_LINES
))
4115 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++)
4116 layout_apply_line_spacing(layout
, line
);
4118 layout_set_line_positions(layout
);
4121 layout
->recompute
|= RECOMPUTE_OVERHANGS
;
4127 static HRESULT WINAPI
dwritetextlayout3_GetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING
*spacing
)
4129 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4131 TRACE("%p, %p.\n", iface
, spacing
);
4133 *spacing
= layout
->format
.spacing
;
4137 static HRESULT WINAPI
dwritetextlayout3_GetLineMetrics(IDWriteTextLayout4
*iface
, DWRITE_LINE_METRICS1
*metrics
,
4138 UINT32 max_count
, UINT32
*count
)
4140 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4141 unsigned int line_count
;
4145 TRACE("%p, %p, %u, %p.\n", iface
, metrics
, max_count
, count
);
4147 if (FAILED(hr
= layout_compute_effective_runs(layout
)))
4152 line_count
= min(max_count
, layout
->metrics
.lineCount
);
4153 for (i
= 0; i
< line_count
; ++i
)
4154 metrics
[i
] = layout
->lines
[i
].metrics
;
4157 *count
= layout
->metrics
.lineCount
;
4158 return max_count
>= layout
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
4161 static HRESULT WINAPI
dwritetextlayout4_SetFontAxisValues(IDWriteTextLayout4
*iface
,
4162 DWRITE_FONT_AXIS_VALUE
const *axis_values
, UINT32 num_values
, DWRITE_TEXT_RANGE range
)
4164 FIXME("%p, %p, %u, %s.\n", iface
, axis_values
, num_values
, debugstr_range(&range
));
4169 static UINT32 WINAPI
dwritetextlayout4_GetFontAxisValueCount(IDWriteTextLayout4
*iface
, UINT32 pos
)
4171 FIXME("%p, %u.\n", iface
, pos
);
4176 static HRESULT WINAPI
dwritetextlayout4_GetFontAxisValues(IDWriteTextLayout4
*iface
, UINT32 pos
,
4177 DWRITE_FONT_AXIS_VALUE
*values
, UINT32 num_values
, DWRITE_TEXT_RANGE
*range
)
4179 FIXME("%p, %u, %p, %u, %p.\n", iface
, pos
, values
, num_values
, range
);
4184 static DWRITE_AUTOMATIC_FONT_AXES WINAPI
dwritetextlayout4_GetAutomaticFontAxes(IDWriteTextLayout4
*iface
)
4186 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4188 TRACE("%p.\n", iface
);
4190 return layout
->format
.automatic_axes
;
4193 static HRESULT WINAPI
dwritetextlayout4_SetAutomaticFontAxes(IDWriteTextLayout4
*iface
,
4194 DWRITE_AUTOMATIC_FONT_AXES axes
)
4196 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4198 TRACE("%p, %d.\n", iface
, axes
);
4200 if ((unsigned int)axes
> DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE
)
4201 return E_INVALIDARG
;
4203 layout
->format
.automatic_axes
= axes
;
4207 static const IDWriteTextLayout4Vtbl dwritetextlayoutvtbl
=
4209 dwritetextlayout_QueryInterface
,
4210 dwritetextlayout_AddRef
,
4211 dwritetextlayout_Release
,
4212 dwritetextlayout_SetTextAlignment
,
4213 dwritetextlayout_SetParagraphAlignment
,
4214 dwritetextlayout_SetWordWrapping
,
4215 dwritetextlayout_SetReadingDirection
,
4216 dwritetextlayout_SetFlowDirection
,
4217 dwritetextlayout_SetIncrementalTabStop
,
4218 dwritetextlayout_SetTrimming
,
4219 dwritetextlayout_SetLineSpacing
,
4220 dwritetextlayout_GetTextAlignment
,
4221 dwritetextlayout_GetParagraphAlignment
,
4222 dwritetextlayout_GetWordWrapping
,
4223 dwritetextlayout_GetReadingDirection
,
4224 dwritetextlayout_GetFlowDirection
,
4225 dwritetextlayout_GetIncrementalTabStop
,
4226 dwritetextlayout_GetTrimming
,
4227 dwritetextlayout_GetLineSpacing
,
4228 dwritetextlayout_GetFontCollection
,
4229 dwritetextlayout_GetFontFamilyNameLength
,
4230 dwritetextlayout_GetFontFamilyName
,
4231 dwritetextlayout_GetFontWeight
,
4232 dwritetextlayout_GetFontStyle
,
4233 dwritetextlayout_GetFontStretch
,
4234 dwritetextlayout_GetFontSize
,
4235 dwritetextlayout_GetLocaleNameLength
,
4236 dwritetextlayout_GetLocaleName
,
4237 dwritetextlayout_SetMaxWidth
,
4238 dwritetextlayout_SetMaxHeight
,
4239 dwritetextlayout_SetFontCollection
,
4240 dwritetextlayout_SetFontFamilyName
,
4241 dwritetextlayout_SetFontWeight
,
4242 dwritetextlayout_SetFontStyle
,
4243 dwritetextlayout_SetFontStretch
,
4244 dwritetextlayout_SetFontSize
,
4245 dwritetextlayout_SetUnderline
,
4246 dwritetextlayout_SetStrikethrough
,
4247 dwritetextlayout_SetDrawingEffect
,
4248 dwritetextlayout_SetInlineObject
,
4249 dwritetextlayout_SetTypography
,
4250 dwritetextlayout_SetLocaleName
,
4251 dwritetextlayout_GetMaxWidth
,
4252 dwritetextlayout_GetMaxHeight
,
4253 dwritetextlayout_layout_GetFontCollection
,
4254 dwritetextlayout_layout_GetFontFamilyNameLength
,
4255 dwritetextlayout_layout_GetFontFamilyName
,
4256 dwritetextlayout_layout_GetFontWeight
,
4257 dwritetextlayout_layout_GetFontStyle
,
4258 dwritetextlayout_layout_GetFontStretch
,
4259 dwritetextlayout_layout_GetFontSize
,
4260 dwritetextlayout_GetUnderline
,
4261 dwritetextlayout_GetStrikethrough
,
4262 dwritetextlayout_GetDrawingEffect
,
4263 dwritetextlayout_GetInlineObject
,
4264 dwritetextlayout_GetTypography
,
4265 dwritetextlayout_layout_GetLocaleNameLength
,
4266 dwritetextlayout_layout_GetLocaleName
,
4267 dwritetextlayout_Draw
,
4268 dwritetextlayout_GetLineMetrics
,
4269 dwritetextlayout_GetMetrics
,
4270 dwritetextlayout_GetOverhangMetrics
,
4271 dwritetextlayout_GetClusterMetrics
,
4272 dwritetextlayout_DetermineMinWidth
,
4273 dwritetextlayout_HitTestPoint
,
4274 dwritetextlayout_HitTestTextPosition
,
4275 dwritetextlayout_HitTestTextRange
,
4276 dwritetextlayout1_SetPairKerning
,
4277 dwritetextlayout1_GetPairKerning
,
4278 dwritetextlayout1_SetCharacterSpacing
,
4279 dwritetextlayout1_GetCharacterSpacing
,
4280 dwritetextlayout2_GetMetrics
,
4281 dwritetextlayout2_SetVerticalGlyphOrientation
,
4282 dwritetextlayout2_GetVerticalGlyphOrientation
,
4283 dwritetextlayout2_SetLastLineWrapping
,
4284 dwritetextlayout2_GetLastLineWrapping
,
4285 dwritetextlayout2_SetOpticalAlignment
,
4286 dwritetextlayout2_GetOpticalAlignment
,
4287 dwritetextlayout2_SetFontFallback
,
4288 dwritetextlayout2_GetFontFallback
,
4289 dwritetextlayout3_InvalidateLayout
,
4290 dwritetextlayout3_SetLineSpacing
,
4291 dwritetextlayout3_GetLineSpacing
,
4292 dwritetextlayout3_GetLineMetrics
,
4293 dwritetextlayout4_SetFontAxisValues
,
4294 dwritetextlayout4_GetFontAxisValueCount
,
4295 dwritetextlayout4_GetFontAxisValues
,
4296 dwritetextlayout4_GetAutomaticFontAxes
,
4297 dwritetextlayout4_SetAutomaticFontAxes
,
4300 static HRESULT WINAPI
dwritetextformat_layout_QueryInterface(IDWriteTextFormat3
*iface
, REFIID riid
, void **obj
)
4302 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4304 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
4306 return IDWriteTextLayout4_QueryInterface(&layout
->IDWriteTextLayout4_iface
, riid
, obj
);
4309 static ULONG WINAPI
dwritetextformat_layout_AddRef(IDWriteTextFormat3
*iface
)
4311 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4312 return IDWriteTextLayout4_AddRef(&layout
->IDWriteTextLayout4_iface
);
4315 static ULONG WINAPI
dwritetextformat_layout_Release(IDWriteTextFormat3
*iface
)
4317 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4318 return IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
4321 static HRESULT WINAPI
dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat3
*iface
,
4322 DWRITE_TEXT_ALIGNMENT alignment
)
4324 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4328 TRACE("%p, %d.\n", iface
, alignment
);
4330 hr
= format_set_textalignment(&layout
->format
, alignment
, &changed
);
4336 /* if layout is not ready there's nothing to align */
4337 if (!(layout
->recompute
& RECOMPUTE_LINES
))
4338 layout_apply_text_alignment(layout
);
4339 layout
->recompute
|= RECOMPUTE_OVERHANGS
;
4345 static HRESULT WINAPI
dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat3
*iface
,
4346 DWRITE_PARAGRAPH_ALIGNMENT alignment
)
4348 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4352 TRACE("%p, %d.\n", iface
, alignment
);
4354 hr
= format_set_paralignment(&layout
->format
, alignment
, &changed
);
4360 /* if layout is not ready there's nothing to align */
4361 if (!(layout
->recompute
& RECOMPUTE_LINES
))
4362 layout_apply_par_alignment(layout
);
4363 layout
->recompute
|= RECOMPUTE_OVERHANGS
;
4369 static HRESULT WINAPI
dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat3
*iface
, DWRITE_WORD_WRAPPING wrapping
)
4371 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4375 TRACE("%p, %d.\n", iface
, wrapping
);
4377 hr
= format_set_wordwrapping(&layout
->format
, wrapping
, &changed
);
4382 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4387 static HRESULT WINAPI
dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat3
*iface
,
4388 DWRITE_READING_DIRECTION direction
)
4390 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4394 TRACE("%p, %d.\n", iface
, direction
);
4396 hr
= format_set_readingdirection(&layout
->format
, direction
, &changed
);
4401 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4406 static HRESULT WINAPI
dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat3
*iface
,
4407 DWRITE_FLOW_DIRECTION direction
)
4409 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4413 TRACE("%p, %d.\n", iface
, direction
);
4415 hr
= format_set_flowdirection(&layout
->format
, direction
, &changed
);
4420 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4425 static HRESULT WINAPI
dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat3
*iface
, FLOAT tabstop
)
4427 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4429 TRACE("%p, %.8e.\n", iface
, tabstop
);
4431 if (tabstop
<= 0.0f
)
4432 return E_INVALIDARG
;
4434 layout
->format
.tabstop
= tabstop
;
4438 static HRESULT WINAPI
dwritetextformat_layout_SetTrimming(IDWriteTextFormat3
*iface
, DWRITE_TRIMMING
const *trimming
,
4439 IDWriteInlineObject
*trimming_sign
)
4441 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4445 TRACE("%p, %p, %p.\n", iface
, trimming
, trimming_sign
);
4447 hr
= format_set_trimming(&layout
->format
, trimming
, trimming_sign
, &changed
);
4450 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4455 static HRESULT WINAPI
dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat3
*iface
,
4456 DWRITE_LINE_SPACING_METHOD method
, FLOAT height
, FLOAT baseline
)
4458 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4459 DWRITE_LINE_SPACING spacing
;
4461 TRACE("%p, %d, %.8e, %.8e.\n", iface
, method
, height
, baseline
);
4463 spacing
= layout
->format
.spacing
;
4464 spacing
.method
= method
;
4465 spacing
.height
= height
;
4466 spacing
.baseline
= baseline
;
4467 return IDWriteTextLayout4_SetLineSpacing(&layout
->IDWriteTextLayout4_iface
, &spacing
);
4470 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat3
*iface
)
4472 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4474 TRACE("%p.\n", iface
);
4476 return layout
->format
.textalignment
;
4479 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat3
*iface
)
4481 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4483 TRACE("%p.\n", iface
);
4485 return layout
->format
.paralign
;
4488 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat3
*iface
)
4490 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4492 TRACE("%p.\n", iface
);
4494 return layout
->format
.wrapping
;
4497 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat3
*iface
)
4499 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4501 TRACE("%p.\n", iface
);
4503 return layout
->format
.readingdir
;
4506 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat3
*iface
)
4508 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4510 TRACE("%p.\n", iface
);
4512 return layout
->format
.flow
;
4515 static FLOAT WINAPI
dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat3
*iface
)
4517 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4519 TRACE("%p.\n", iface
);
4521 return layout
->format
.tabstop
;
4524 static HRESULT WINAPI
dwritetextformat_layout_GetTrimming(IDWriteTextFormat3
*iface
, DWRITE_TRIMMING
*options
,
4525 IDWriteInlineObject
**trimming_sign
)
4527 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4529 TRACE("%p, %p, %p.\n", iface
, options
, trimming_sign
);
4531 *options
= layout
->format
.trimming
;
4532 *trimming_sign
= layout
->format
.trimmingsign
;
4534 IDWriteInlineObject_AddRef(*trimming_sign
);
4538 static HRESULT WINAPI
dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat3
*iface
,
4539 DWRITE_LINE_SPACING_METHOD
*method
, FLOAT
*spacing
, FLOAT
*baseline
)
4541 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4543 TRACE("%p, %p, %p, %p.\n", iface
, method
, spacing
, baseline
);
4545 *method
= layout
->format
.spacing
.method
;
4546 *spacing
= layout
->format
.spacing
.height
;
4547 *baseline
= layout
->format
.spacing
.baseline
;
4551 static HRESULT WINAPI
dwritetextformat_layout_GetFontCollection(IDWriteTextFormat3
*iface
,
4552 IDWriteFontCollection
**collection
)
4554 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4556 TRACE("%p, %p.\n", iface
, collection
);
4558 *collection
= layout
->format
.collection
;
4560 IDWriteFontCollection_AddRef(*collection
);
4564 static UINT32 WINAPI
dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat3
*iface
)
4566 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4568 TRACE("%p.\n", iface
);
4570 return layout
->format
.family_len
;
4573 static HRESULT WINAPI
dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat3
*iface
, WCHAR
*name
, UINT32 size
)
4575 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4577 TRACE("%p, %p, %u.\n", iface
, name
, size
);
4579 if (size
<= layout
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
4580 wcscpy(name
, layout
->format
.family_name
);
4584 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_layout_GetFontWeight(IDWriteTextFormat3
*iface
)
4586 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4588 TRACE("%p.\n", iface
);
4590 return layout
->format
.weight
;
4593 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_layout_GetFontStyle(IDWriteTextFormat3
*iface
)
4595 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4597 TRACE("%p.\n", iface
);
4599 return layout
->format
.style
;
4602 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_layout_GetFontStretch(IDWriteTextFormat3
*iface
)
4604 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4606 TRACE("%p.\n", iface
);
4608 return layout
->format
.stretch
;
4611 static FLOAT WINAPI
dwritetextformat_layout_GetFontSize(IDWriteTextFormat3
*iface
)
4613 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4615 TRACE("%p.\n", iface
);
4617 return layout
->format
.fontsize
;
4620 static UINT32 WINAPI
dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat3
*iface
)
4622 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4624 TRACE("%p.\n", iface
);
4626 return layout
->format
.locale_len
;
4629 static HRESULT WINAPI
dwritetextformat_layout_GetLocaleName(IDWriteTextFormat3
*iface
, WCHAR
*name
, UINT32 size
)
4631 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4633 TRACE("%p, %p, %u.\n", iface
, name
, size
);
4635 if (size
<= layout
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
4636 wcscpy(name
, layout
->format
.locale
);
4640 static HRESULT WINAPI
dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat3
*iface
,
4641 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4643 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4645 TRACE("%p, %d.\n", iface
, orientation
);
4647 return layout_set_vertical_orientation(layout
, orientation
);
4650 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat3
*iface
)
4652 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4654 TRACE("%p.\n", iface
);
4656 return layout
->format
.vertical_orientation
;
4659 static HRESULT WINAPI
dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat3
*iface
,
4660 BOOL lastline_wrapping_enabled
)
4662 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4664 TRACE("%p, %d.\n", iface
, lastline_wrapping_enabled
);
4666 layout
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
4670 static BOOL WINAPI
dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat3
*iface
)
4672 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4674 TRACE("%p.\n", iface
);
4676 return layout
->format
.last_line_wrapping
;
4679 static HRESULT WINAPI
dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat3
*iface
,
4680 DWRITE_OPTICAL_ALIGNMENT alignment
)
4682 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4684 TRACE("%p, %d.\n", iface
, alignment
);
4686 return format_set_optical_alignment(&layout
->format
, alignment
);
4689 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat3
*iface
)
4691 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4693 TRACE("%p.\n", iface
);
4695 return layout
->format
.optical_alignment
;
4698 static HRESULT WINAPI
dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat3
*iface
,
4699 IDWriteFontFallback
*fallback
)
4701 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4703 TRACE("%p, %p.\n", iface
, fallback
);
4705 return IDWriteTextLayout4_SetFontFallback(&layout
->IDWriteTextLayout4_iface
, fallback
);
4708 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat3
*iface
,
4709 IDWriteFontFallback
**fallback
)
4711 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4713 TRACE("%p, %p.\n", iface
, fallback
);
4715 return IDWriteTextLayout4_GetFontFallback(&layout
->IDWriteTextLayout4_iface
, fallback
);
4718 static HRESULT WINAPI
dwritetextformat2_layout_SetLineSpacing(IDWriteTextFormat3
*iface
,
4719 DWRITE_LINE_SPACING
const *spacing
)
4721 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4722 return IDWriteTextLayout4_SetLineSpacing(&layout
->IDWriteTextLayout4_iface
, spacing
);
4725 static HRESULT WINAPI
dwritetextformat2_layout_GetLineSpacing(IDWriteTextFormat3
*iface
, DWRITE_LINE_SPACING
*spacing
)
4727 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4728 return IDWriteTextLayout4_GetLineSpacing(&layout
->IDWriteTextLayout4_iface
, spacing
);
4731 static HRESULT WINAPI
dwritetextformat3_layout_SetFontAxisValues(IDWriteTextFormat3
*iface
,
4732 DWRITE_FONT_AXIS_VALUE
const *axis_values
, UINT32 num_values
)
4734 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4736 TRACE("%p, %p, %u.\n", iface
, axis_values
, num_values
);
4738 return format_set_font_axisvalues(&layout
->format
, axis_values
, num_values
);
4741 static UINT32 WINAPI
dwritetextformat3_layout_GetFontAxisValueCount(IDWriteTextFormat3
*iface
)
4743 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4745 TRACE("%p.\n", iface
);
4747 return layout
->format
.axis_values_count
;
4750 static HRESULT WINAPI
dwritetextformat3_layout_GetFontAxisValues(IDWriteTextFormat3
*iface
,
4751 DWRITE_FONT_AXIS_VALUE
*axis_values
, UINT32 num_values
)
4753 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4755 TRACE("%p, %p, %u.\n", iface
, axis_values
, num_values
);
4757 return format_get_font_axisvalues(&layout
->format
, axis_values
, num_values
);
4760 static DWRITE_AUTOMATIC_FONT_AXES WINAPI
dwritetextformat3_layout_GetAutomaticFontAxes(IDWriteTextFormat3
*iface
)
4762 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4763 return IDWriteTextLayout4_GetAutomaticFontAxes(&layout
->IDWriteTextLayout4_iface
);
4766 static HRESULT WINAPI
dwritetextformat3_layout_SetAutomaticFontAxes(IDWriteTextFormat3
*iface
,
4767 DWRITE_AUTOMATIC_FONT_AXES axes
)
4769 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4770 return IDWriteTextLayout4_SetAutomaticFontAxes(&layout
->IDWriteTextLayout4_iface
, axes
);
4773 static const IDWriteTextFormat3Vtbl dwritetextformat3_layout_vtbl
=
4775 dwritetextformat_layout_QueryInterface
,
4776 dwritetextformat_layout_AddRef
,
4777 dwritetextformat_layout_Release
,
4778 dwritetextformat_layout_SetTextAlignment
,
4779 dwritetextformat_layout_SetParagraphAlignment
,
4780 dwritetextformat_layout_SetWordWrapping
,
4781 dwritetextformat_layout_SetReadingDirection
,
4782 dwritetextformat_layout_SetFlowDirection
,
4783 dwritetextformat_layout_SetIncrementalTabStop
,
4784 dwritetextformat_layout_SetTrimming
,
4785 dwritetextformat_layout_SetLineSpacing
,
4786 dwritetextformat_layout_GetTextAlignment
,
4787 dwritetextformat_layout_GetParagraphAlignment
,
4788 dwritetextformat_layout_GetWordWrapping
,
4789 dwritetextformat_layout_GetReadingDirection
,
4790 dwritetextformat_layout_GetFlowDirection
,
4791 dwritetextformat_layout_GetIncrementalTabStop
,
4792 dwritetextformat_layout_GetTrimming
,
4793 dwritetextformat_layout_GetLineSpacing
,
4794 dwritetextformat_layout_GetFontCollection
,
4795 dwritetextformat_layout_GetFontFamilyNameLength
,
4796 dwritetextformat_layout_GetFontFamilyName
,
4797 dwritetextformat_layout_GetFontWeight
,
4798 dwritetextformat_layout_GetFontStyle
,
4799 dwritetextformat_layout_GetFontStretch
,
4800 dwritetextformat_layout_GetFontSize
,
4801 dwritetextformat_layout_GetLocaleNameLength
,
4802 dwritetextformat_layout_GetLocaleName
,
4803 dwritetextformat1_layout_SetVerticalGlyphOrientation
,
4804 dwritetextformat1_layout_GetVerticalGlyphOrientation
,
4805 dwritetextformat1_layout_SetLastLineWrapping
,
4806 dwritetextformat1_layout_GetLastLineWrapping
,
4807 dwritetextformat1_layout_SetOpticalAlignment
,
4808 dwritetextformat1_layout_GetOpticalAlignment
,
4809 dwritetextformat1_layout_SetFontFallback
,
4810 dwritetextformat1_layout_GetFontFallback
,
4811 dwritetextformat2_layout_SetLineSpacing
,
4812 dwritetextformat2_layout_GetLineSpacing
,
4813 dwritetextformat3_layout_SetFontAxisValues
,
4814 dwritetextformat3_layout_GetFontAxisValueCount
,
4815 dwritetextformat3_layout_GetFontAxisValues
,
4816 dwritetextformat3_layout_GetAutomaticFontAxes
,
4817 dwritetextformat3_layout_SetAutomaticFontAxes
,
4820 static HRESULT WINAPI
dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1
*iface
,
4821 REFIID riid
, void **obj
)
4823 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink1
) ||
4824 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink
) ||
4825 IsEqualIID(riid
, &IID_IUnknown
))
4828 IDWriteTextAnalysisSink1_AddRef(iface
);
4832 WARN("%s not implemented.\n", debugstr_guid(riid
));
4835 return E_NOINTERFACE
;
4838 static ULONG WINAPI
dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1
*iface
)
4840 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4841 return IDWriteTextLayout4_AddRef(&layout
->IDWriteTextLayout4_iface
);
4844 static ULONG WINAPI
dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1
*iface
)
4846 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4847 return IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
4850 static HRESULT WINAPI
dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1
*iface
,
4851 UINT32 position
, UINT32 length
, DWRITE_SCRIPT_ANALYSIS
const* sa
)
4853 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4854 struct layout_run
*run
;
4857 TRACE("[%u,%u) script=%u:%s\n", position
, position
+ length
, sa
->script
, debugstr_sa_script(sa
->script
));
4859 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
, &run
)))
4862 run
->u
.regular
.descr
.string
= &layout
->str
[position
];
4863 run
->u
.regular
.descr
.stringLength
= length
;
4864 run
->u
.regular
.descr
.textPosition
= position
;
4865 run
->u
.regular
.sa
= *sa
;
4866 list_add_tail(&layout
->runs
, &run
->entry
);
4870 static HRESULT WINAPI
dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1
*iface
,
4871 UINT32 position
, UINT32 length
, DWRITE_LINE_BREAKPOINT
const* breakpoints
)
4873 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4875 if (position
+ length
> layout
->len
)
4878 memcpy(&layout
->nominal_breakpoints
[position
], breakpoints
, length
*sizeof(DWRITE_LINE_BREAKPOINT
));
4882 static HRESULT WINAPI
dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1
*iface
, UINT32 position
,
4883 UINT32 length
, UINT8 explicitLevel
, UINT8 resolvedLevel
)
4885 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4886 struct layout_run
*cur_run
;
4889 TRACE("[%u,%u) %u %u\n", position
, position
+ length
, explicitLevel
, resolvedLevel
);
4891 LIST_FOR_EACH_ENTRY(cur_run
, &layout
->runs
, struct layout_run
, entry
) {
4892 struct regular_layout_run
*cur
= &cur_run
->u
.regular
;
4893 struct layout_run
*run
;
4895 if (cur_run
->kind
== LAYOUT_RUN_INLINE
)
4898 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4899 if (position
< cur
->descr
.textPosition
|| position
>= cur
->descr
.textPosition
+ cur
->descr
.stringLength
)
4902 /* full hit - just set run level */
4903 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
== length
) {
4904 cur
->run
.bidiLevel
= resolvedLevel
;
4908 /* current run is fully covered, move to next one */
4909 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
< length
) {
4910 cur
->run
.bidiLevel
= resolvedLevel
;
4911 position
+= cur
->descr
.stringLength
;
4912 length
-= cur
->descr
.stringLength
;
4916 /* all fully covered runs are processed at this point, reuse existing run for remaining
4917 reported bidi range and add another run for the rest of original one */
4919 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
+ length
, &run
)))
4923 run
->u
.regular
.descr
.textPosition
= position
+ length
;
4924 run
->u
.regular
.descr
.stringLength
= cur
->descr
.stringLength
- length
;
4925 run
->u
.regular
.descr
.string
= &layout
->str
[position
+ length
];
4927 /* reduce existing run */
4928 cur
->run
.bidiLevel
= resolvedLevel
;
4929 cur
->descr
.stringLength
= length
;
4931 list_add_after(&cur_run
->entry
, &run
->entry
);
4938 static HRESULT WINAPI
dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1
*iface
,
4939 UINT32 position
, UINT32 length
, IDWriteNumberSubstitution
* substitution
)
4944 static HRESULT WINAPI
dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1
*iface
,
4945 UINT32 position
, UINT32 length
, DWRITE_GLYPH_ORIENTATION_ANGLE angle
, UINT8 adjusted_bidi_level
,
4946 BOOL is_sideways
, BOOL is_rtl
)
4951 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl
= {
4952 dwritetextlayout_sink_QueryInterface
,
4953 dwritetextlayout_sink_AddRef
,
4954 dwritetextlayout_sink_Release
,
4955 dwritetextlayout_sink_SetScriptAnalysis
,
4956 dwritetextlayout_sink_SetLineBreakpoints
,
4957 dwritetextlayout_sink_SetBidiLevel
,
4958 dwritetextlayout_sink_SetNumberSubstitution
,
4959 dwritetextlayout_sink_SetGlyphOrientation
4962 static HRESULT WINAPI
dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1
*iface
,
4963 REFIID riid
, void **obj
)
4965 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource1
) ||
4966 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource
) ||
4967 IsEqualIID(riid
, &IID_IUnknown
))
4970 IDWriteTextAnalysisSource1_AddRef(iface
);
4974 WARN("%s not implemented.\n", debugstr_guid(riid
));
4977 return E_NOINTERFACE
;
4980 static ULONG WINAPI
dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1
*iface
)
4982 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4983 return IDWriteTextLayout4_AddRef(&layout
->IDWriteTextLayout4_iface
);
4986 static ULONG WINAPI
dwritetextlayout_source_Release(IDWriteTextAnalysisSource1
*iface
)
4988 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4989 return IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
4992 static HRESULT WINAPI
dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1
*iface
,
4993 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
4995 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4997 TRACE("%p, %u, %p, %p.\n", iface
, position
, text
, text_len
);
4999 if (position
< layout
->len
) {
5000 *text
= &layout
->str
[position
];
5001 *text_len
= layout
->len
- position
;
5011 static HRESULT WINAPI
dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1
*iface
,
5012 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
5014 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5016 TRACE("%p, %u, %p, %p.\n", iface
, position
, text
, text_len
);
5018 if (position
> 0 && position
< layout
->len
) {
5019 *text
= layout
->str
;
5020 *text_len
= position
;
5030 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1
*iface
)
5032 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5033 return IDWriteTextLayout4_GetReadingDirection(&layout
->IDWriteTextLayout4_iface
);
5036 static HRESULT WINAPI
dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1
*iface
,
5037 UINT32 position
, UINT32
* text_len
, WCHAR
const** locale
)
5039 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5040 struct layout_range
*range
= get_layout_range_by_pos(layout
, position
);
5042 if (position
< layout
->len
) {
5043 struct layout_range
*next
;
5045 *locale
= range
->locale
;
5046 *text_len
= range
->h
.range
.length
- position
;
5048 next
= LIST_ENTRY(list_next(&layout
->ranges
, &range
->h
.entry
), struct layout_range
, h
.entry
);
5049 while (next
&& next
->h
.range
.startPosition
< layout
->len
&& !wcscmp(range
->locale
, next
->locale
))
5051 *text_len
+= next
->h
.range
.length
;
5052 next
= LIST_ENTRY(list_next(&layout
->ranges
, &next
->h
.entry
), struct layout_range
, h
.entry
);
5055 *text_len
= min(*text_len
, layout
->len
- position
);
5065 static HRESULT WINAPI
dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1
*iface
,
5066 UINT32 position
, UINT32
* text_len
, IDWriteNumberSubstitution
**substitution
)
5068 FIXME("%u %p %p: stub\n", position
, text_len
, substitution
);
5072 static HRESULT WINAPI
dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1
*iface
,
5073 UINT32 position
, UINT32
*length
, DWRITE_VERTICAL_GLYPH_ORIENTATION
*orientation
, UINT8
*bidi_level
)
5075 FIXME("%u %p %p %p: stub\n", position
, length
, orientation
, bidi_level
);
5079 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl
= {
5080 dwritetextlayout_source_QueryInterface
,
5081 dwritetextlayout_source_AddRef
,
5082 dwritetextlayout_source_Release
,
5083 dwritetextlayout_source_GetTextAtPosition
,
5084 dwritetextlayout_source_GetTextBeforePosition
,
5085 dwritetextlayout_source_GetParagraphReadingDirection
,
5086 dwritetextlayout_source_GetLocaleName
,
5087 dwritetextlayout_source_GetNumberSubstitution
,
5088 dwritetextlayout_source_GetVerticalGlyphOrientation
5091 static HRESULT
layout_format_from_textformat(struct dwrite_textlayout
*layout
, IDWriteTextFormat
*format
)
5093 struct dwrite_textformat
*textformat
;
5094 IDWriteTextFormat1
*format1
;
5095 IDWriteTextFormat3
*format3
;
5099 if ((textformat
= unsafe_impl_from_IDWriteTextFormat(format
))) {
5100 layout
->format
= textformat
->format
;
5102 layout
->format
.locale
= wcsdup(textformat
->format
.locale
);
5103 layout
->format
.family_name
= wcsdup(textformat
->format
.family_name
);
5104 if (!layout
->format
.locale
|| !layout
->format
.family_name
)
5106 free(layout
->format
.locale
);
5107 free(layout
->format
.family_name
);
5108 return E_OUTOFMEMORY
;
5111 if (layout
->format
.trimmingsign
)
5112 IDWriteInlineObject_AddRef(layout
->format
.trimmingsign
);
5113 if (layout
->format
.collection
)
5114 IDWriteFontCollection_AddRef(layout
->format
.collection
);
5115 if (layout
->format
.fallback
)
5116 IDWriteFontFallback_AddRef(layout
->format
.fallback
);
5121 layout
->format
.weight
= IDWriteTextFormat_GetFontWeight(format
);
5122 layout
->format
.style
= IDWriteTextFormat_GetFontStyle(format
);
5123 layout
->format
.stretch
= IDWriteTextFormat_GetFontStretch(format
);
5124 layout
->format
.fontsize
= IDWriteTextFormat_GetFontSize(format
);
5125 layout
->format
.tabstop
= IDWriteTextFormat_GetIncrementalTabStop(format
);
5126 layout
->format
.textalignment
= IDWriteTextFormat_GetTextAlignment(format
);
5127 layout
->format
.paralign
= IDWriteTextFormat_GetParagraphAlignment(format
);
5128 layout
->format
.wrapping
= IDWriteTextFormat_GetWordWrapping(format
);
5129 layout
->format
.readingdir
= IDWriteTextFormat_GetReadingDirection(format
);
5130 layout
->format
.flow
= IDWriteTextFormat_GetFlowDirection(format
);
5131 hr
= IDWriteTextFormat_GetLineSpacing(format
, &layout
->format
.spacing
.method
,
5132 &layout
->format
.spacing
.height
, &layout
->format
.spacing
.baseline
);
5136 hr
= IDWriteTextFormat_GetTrimming(format
, &layout
->format
.trimming
, &layout
->format
.trimmingsign
);
5140 /* locale name and length */
5141 len
= IDWriteTextFormat_GetLocaleNameLength(format
);
5142 if (!(layout
->format
.locale
= malloc((len
+ 1) * sizeof(WCHAR
))))
5143 return E_OUTOFMEMORY
;
5145 hr
= IDWriteTextFormat_GetLocaleName(format
, layout
->format
.locale
, len
+1);
5148 layout
->format
.locale_len
= len
;
5150 /* font family name and length */
5151 len
= IDWriteTextFormat_GetFontFamilyNameLength(format
);
5152 if (!(layout
->format
.family_name
= malloc((len
+ 1) * sizeof(WCHAR
))))
5153 return E_OUTOFMEMORY
;
5155 hr
= IDWriteTextFormat_GetFontFamilyName(format
, layout
->format
.family_name
, len
+1);
5158 layout
->format
.family_len
= len
;
5160 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat1
, (void**)&format1
);
5163 IDWriteTextFormat2
*format2
;
5165 layout
->format
.vertical_orientation
= IDWriteTextFormat1_GetVerticalGlyphOrientation(format1
);
5166 layout
->format
.optical_alignment
= IDWriteTextFormat1_GetOpticalAlignment(format1
);
5167 IDWriteTextFormat1_GetFontFallback(format1
, &layout
->format
.fallback
);
5169 if (IDWriteTextFormat1_QueryInterface(format1
, &IID_IDWriteTextFormat2
, (void**)&format2
) == S_OK
) {
5170 IDWriteTextFormat2_GetLineSpacing(format2
, &layout
->format
.spacing
);
5171 IDWriteTextFormat2_Release(format2
);
5174 IDWriteTextFormat1_Release(format1
);
5177 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat3
, (void **)&format3
);
5180 layout
->format
.automatic_axes
= IDWriteTextFormat3_GetAutomaticFontAxes(format3
);
5181 IDWriteTextFormat3_Release(format3
);
5184 return IDWriteTextFormat_GetFontCollection(format
, &layout
->format
.collection
);
5187 static HRESULT
init_textlayout(const struct textlayout_desc
*desc
, struct dwrite_textlayout
*layout
)
5189 struct layout_range_header
*range
, *strike
, *underline
, *effect
, *spacing
, *typography
;
5190 static const DWRITE_TEXT_RANGE r
= { 0, ~0u };
5193 layout
->IDWriteTextLayout4_iface
.lpVtbl
= &dwritetextlayoutvtbl
;
5194 layout
->IDWriteTextFormat3_iface
.lpVtbl
= &dwritetextformat3_layout_vtbl
;
5195 layout
->IDWriteTextAnalysisSink1_iface
.lpVtbl
= &dwritetextlayoutsinkvtbl
;
5196 layout
->IDWriteTextAnalysisSource1_iface
.lpVtbl
= &dwritetextlayoutsourcevtbl
;
5197 layout
->refcount
= 1;
5198 layout
->len
= desc
->length
;
5199 layout
->recompute
= RECOMPUTE_EVERYTHING
;
5200 list_init(&layout
->eruns
);
5201 list_init(&layout
->inlineobjects
);
5202 list_init(&layout
->underlines
);
5203 list_init(&layout
->strikethrough
);
5204 list_init(&layout
->runs
);
5205 list_init(&layout
->ranges
);
5206 list_init(&layout
->strike_ranges
);
5207 list_init(&layout
->underline_ranges
);
5208 list_init(&layout
->effects
);
5209 list_init(&layout
->spacing
);
5210 list_init(&layout
->typographies
);
5211 layout
->metrics
.layoutWidth
= desc
->max_width
;
5212 layout
->metrics
.layoutHeight
= desc
->max_height
;
5214 layout
->str
= heap_strdupnW(desc
->string
, desc
->length
);
5215 if (desc
->length
&& !layout
->str
) {
5220 hr
= layout_format_from_textformat(layout
, desc
->format
);
5224 range
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_REGULAR
);
5225 strike
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_STRIKETHROUGH
);
5226 underline
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_UNDERLINE
);
5227 effect
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_EFFECT
);
5228 spacing
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_SPACING
);
5229 typography
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_TYPOGRAPHY
);
5230 if (!range
|| !strike
|| !effect
|| !spacing
|| !typography
|| !underline
) {
5231 free_layout_range(range
);
5232 free_layout_range(strike
);
5233 free_layout_range(underline
);
5234 free_layout_range(effect
);
5235 free_layout_range(spacing
);
5236 free_layout_range(typography
);
5241 layout
->measuringmode
= desc
->is_gdi_compatible
? (desc
->use_gdi_natural
? DWRITE_MEASURING_MODE_GDI_NATURAL
:
5242 DWRITE_MEASURING_MODE_GDI_CLASSIC
) : DWRITE_MEASURING_MODE_NATURAL
;
5243 layout
->ppdip
= desc
->ppdip
;
5244 layout
->transform
= desc
->transform
? *desc
->transform
: identity
;
5246 layout
->factory
= desc
->factory
;
5247 IDWriteFactory7_AddRef(layout
->factory
);
5248 list_add_head(&layout
->ranges
, &range
->entry
);
5249 list_add_head(&layout
->strike_ranges
, &strike
->entry
);
5250 list_add_head(&layout
->underline_ranges
, &underline
->entry
);
5251 list_add_head(&layout
->effects
, &effect
->entry
);
5252 list_add_head(&layout
->spacing
, &spacing
->entry
);
5253 list_add_head(&layout
->typographies
, &typography
->entry
);
5257 IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
5261 HRESULT
create_textlayout(const struct textlayout_desc
*desc
, IDWriteTextLayout
**layout
)
5263 struct dwrite_textlayout
*object
;
5268 if (desc
->max_width
< 0.0f
|| desc
->max_height
< 0.0f
)
5269 return E_INVALIDARG
;
5271 if (!desc
->format
|| !desc
->string
)
5272 return E_INVALIDARG
;
5274 if (!(object
= calloc(1, sizeof(*object
))))
5275 return E_OUTOFMEMORY
;
5277 hr
= init_textlayout(desc
, object
);
5279 *layout
= (IDWriteTextLayout
*)&object
->IDWriteTextLayout4_iface
;
5284 static HRESULT WINAPI
dwritetypography_QueryInterface(IDWriteTypography
*iface
, REFIID riid
, void **obj
)
5286 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
5288 if (IsEqualIID(riid
, &IID_IDWriteTypography
) || IsEqualIID(riid
, &IID_IUnknown
)) {
5290 IDWriteTypography_AddRef(iface
);
5294 WARN("%s not implemented.\n", debugstr_guid(riid
));
5298 return E_NOINTERFACE
;
5301 static ULONG WINAPI
dwritetypography_AddRef(IDWriteTypography
*iface
)
5303 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5304 ULONG refcount
= InterlockedIncrement(&typography
->refcount
);
5306 TRACE("%p, refcount %ld.\n", iface
, refcount
);
5311 static ULONG WINAPI
dwritetypography_Release(IDWriteTypography
*iface
)
5313 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5314 ULONG refcount
= InterlockedDecrement(&typography
->refcount
);
5316 TRACE("%p, refcount %ld.\n", iface
, refcount
);
5320 free(typography
->features
);
5327 static HRESULT WINAPI
dwritetypography_AddFontFeature(IDWriteTypography
*iface
, DWRITE_FONT_FEATURE feature
)
5329 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5331 TRACE("%p, %s, %u.\n", iface
, debugstr_tag(feature
.nameTag
), feature
.parameter
);
5333 if (!dwrite_array_reserve((void **)&typography
->features
, &typography
->capacity
, typography
->count
+ 1,
5334 sizeof(*typography
->features
)))
5336 return E_OUTOFMEMORY
;
5339 typography
->features
[typography
->count
++] = feature
;
5344 static UINT32 WINAPI
dwritetypography_GetFontFeatureCount(IDWriteTypography
*iface
)
5346 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5348 TRACE("%p.\n", iface
);
5350 return typography
->count
;
5353 static HRESULT WINAPI
dwritetypography_GetFontFeature(IDWriteTypography
*iface
, UINT32 index
,
5354 DWRITE_FONT_FEATURE
*feature
)
5356 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5358 TRACE("%p, %u, %p.\n", iface
, index
, feature
);
5360 if (index
>= typography
->count
)
5361 return E_INVALIDARG
;
5363 *feature
= typography
->features
[index
];
5367 static const IDWriteTypographyVtbl dwritetypographyvtbl
= {
5368 dwritetypography_QueryInterface
,
5369 dwritetypography_AddRef
,
5370 dwritetypography_Release
,
5371 dwritetypography_AddFontFeature
,
5372 dwritetypography_GetFontFeatureCount
,
5373 dwritetypography_GetFontFeature
5376 HRESULT
create_typography(IDWriteTypography
**ret
)
5378 struct dwrite_typography
*typography
;
5382 if (!(typography
= calloc(1, sizeof(*typography
))))
5383 return E_OUTOFMEMORY
;
5385 typography
->IDWriteTypography_iface
.lpVtbl
= &dwritetypographyvtbl
;
5386 typography
->refcount
= 1;
5388 *ret
= &typography
->IDWriteTypography_iface
;