2 * Copyright 2012, 2014-2022 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
;
225 IDWriteFontCollection
*system_collection
;
236 struct dwrite_textformat_data format
;
237 struct list strike_ranges
;
238 struct list underline_ranges
;
239 struct list typographies
;
244 /* lists ready to use by Draw() */
246 struct list inlineobjects
;
247 struct list underlines
;
248 struct list strikethrough
;
251 DWRITE_LINE_BREAKPOINT
*nominal_breakpoints
;
252 DWRITE_LINE_BREAKPOINT
*actual_breakpoints
;
254 struct layout_cluster
*clusters
;
255 DWRITE_CLUSTER_METRICS
*clustermetrics
;
256 UINT32 cluster_count
;
259 struct layout_line
*lines
;
262 DWRITE_TEXT_METRICS1 metrics
;
263 DWRITE_OVERHANG_METRICS overhangs
;
265 DWRITE_MEASURING_MODE measuringmode
;
267 /* gdi-compatible layout specifics */
269 DWRITE_MATRIX transform
;
272 struct dwrite_typography
{
273 IDWriteTypography IDWriteTypography_iface
;
276 DWRITE_FONT_FEATURE
*features
;
281 static inline struct dwrite_textlayout
*impl_from_IDWriteTextLayout4(IDWriteTextLayout4
*iface
)
283 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextLayout4_iface
);
286 static inline struct dwrite_textlayout
*impl_from_IDWriteTextFormat3(IDWriteTextFormat3
*iface
)
288 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextFormat3_iface
);
291 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1
*iface
)
293 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSink1_iface
);
296 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1
*iface
)
298 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSource1_iface
);
301 static inline struct dwrite_typography
*impl_from_IDWriteTypography(IDWriteTypography
*iface
)
303 return CONTAINING_RECORD(iface
, struct dwrite_typography
, IDWriteTypography_iface
);
306 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION
*descr
)
308 return wine_dbg_sprintf("[%u,%u)", descr
->textPosition
, descr
->textPosition
+ descr
->stringLength
);
311 static inline BOOL
is_layout_gdi_compatible(const struct dwrite_textlayout
*layout
)
313 return layout
->measuringmode
!= DWRITE_MEASURING_MODE_NATURAL
;
316 static BOOL
is_run_rtl(const struct layout_effective_run
*run
)
318 return run
->run
->u
.regular
.run
.bidiLevel
& 1;
321 static HRESULT
alloc_layout_run(enum layout_run_kind kind
, unsigned int start_position
,
322 struct layout_run
**run
)
324 if (!(*run
= calloc(1, sizeof(**run
))))
325 return E_OUTOFMEMORY
;
328 (*run
)->start_position
= start_position
;
333 static void free_layout_runs(struct dwrite_textlayout
*layout
)
335 struct layout_run
*cur
, *cur2
;
336 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->runs
, struct layout_run
, entry
)
338 list_remove(&cur
->entry
);
339 if (cur
->kind
== LAYOUT_RUN_REGULAR
)
341 if (cur
->u
.regular
.run
.fontFace
)
342 IDWriteFontFace_Release(cur
->u
.regular
.run
.fontFace
);
343 free(cur
->u
.regular
.glyphs
);
344 free(cur
->u
.regular
.clustermap
);
345 free(cur
->u
.regular
.advances
);
346 free(cur
->u
.regular
.offsets
);
352 static void free_layout_eruns(struct dwrite_textlayout
*layout
)
354 struct layout_effective_inline
*in
, *in2
;
355 struct layout_effective_run
*cur
, *cur2
;
356 struct layout_strikethrough
*s
, *s2
;
357 struct layout_underline
*u
, *u2
;
359 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->eruns
, struct layout_effective_run
, entry
)
361 list_remove(&cur
->entry
);
362 free(cur
->clustermap
);
366 LIST_FOR_EACH_ENTRY_SAFE(in
, in2
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
)
368 list_remove(&in
->entry
);
372 LIST_FOR_EACH_ENTRY_SAFE(u
, u2
, &layout
->underlines
, struct layout_underline
, entry
)
374 list_remove(&u
->entry
);
378 LIST_FOR_EACH_ENTRY_SAFE(s
, s2
, &layout
->strikethrough
, struct layout_strikethrough
, entry
)
380 list_remove(&s
->entry
);
385 /* Used to resolve break condition by forcing stronger condition over weaker. */
386 static inline DWRITE_BREAK_CONDITION
override_break_condition(DWRITE_BREAK_CONDITION existingbreak
, DWRITE_BREAK_CONDITION newbreak
)
388 switch (existingbreak
) {
389 case DWRITE_BREAK_CONDITION_NEUTRAL
:
391 case DWRITE_BREAK_CONDITION_CAN_BREAK
:
392 return newbreak
== DWRITE_BREAK_CONDITION_NEUTRAL
? existingbreak
: newbreak
;
393 /* let's keep stronger conditions as is */
394 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
:
395 case DWRITE_BREAK_CONDITION_MUST_BREAK
:
398 ERR("unknown break condition %d\n", existingbreak
);
401 return existingbreak
;
404 /* This helper should be used to get effective range length, in other words it returns number of text
405 positions from range starting point to the end of the range, limited by layout text length */
406 static inline UINT32
get_clipped_range_length(const struct dwrite_textlayout
*layout
, const struct layout_range
*range
)
408 if (range
->h
.range
.startPosition
+ range
->h
.range
.length
<= layout
->len
)
409 return range
->h
.range
.length
;
410 return layout
->len
- range
->h
.range
.startPosition
;
413 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
414 static HRESULT
layout_update_breakpoints_range(struct dwrite_textlayout
*layout
, const struct layout_range
*cur
)
416 DWRITE_BREAK_CONDITION before
, after
;
420 /* ignore returned conditions if failed */
421 hr
= IDWriteInlineObject_GetBreakConditions(cur
->object
, &before
, &after
);
423 after
= before
= DWRITE_BREAK_CONDITION_NEUTRAL
;
425 if (!layout
->actual_breakpoints
)
427 if (!(layout
->actual_breakpoints
= calloc(layout
->len
, sizeof(*layout
->actual_breakpoints
))))
428 return E_OUTOFMEMORY
;
429 memcpy(layout
->actual_breakpoints
, layout
->nominal_breakpoints
, sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
432 length
= get_clipped_range_length(layout
, cur
);
433 for (i
= cur
->h
.range
.startPosition
; i
< length
+ cur
->h
.range
.startPosition
; i
++) {
434 /* for first codepoint check if there's anything before it and update accordingly */
435 if (i
== cur
->h
.range
.startPosition
) {
437 layout
->actual_breakpoints
[i
].breakConditionBefore
= layout
->actual_breakpoints
[i
-1].breakConditionAfter
=
438 override_break_condition(layout
->actual_breakpoints
[i
-1].breakConditionAfter
, before
);
440 layout
->actual_breakpoints
[i
].breakConditionBefore
= before
;
441 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
443 /* similar check for last codepoint */
444 else if (i
== cur
->h
.range
.startPosition
+ length
- 1) {
445 if (i
== layout
->len
- 1)
446 layout
->actual_breakpoints
[i
].breakConditionAfter
= after
;
448 layout
->actual_breakpoints
[i
].breakConditionAfter
= layout
->actual_breakpoints
[i
+1].breakConditionBefore
=
449 override_break_condition(layout
->actual_breakpoints
[i
+1].breakConditionBefore
, after
);
450 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
452 /* for all positions within a range disable breaks */
454 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
455 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
458 layout
->actual_breakpoints
[i
].isWhitespace
= 0;
459 layout
->actual_breakpoints
[i
].isSoftHyphen
= 0;
465 static struct layout_range
*get_layout_range_by_pos(const struct dwrite_textlayout
*layout
, UINT32 pos
)
467 struct layout_range
*cur
;
469 LIST_FOR_EACH_ENTRY(cur
, &layout
->ranges
, struct layout_range
, h
.entry
)
471 DWRITE_TEXT_RANGE
*r
= &cur
->h
.range
;
472 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
479 static struct layout_range_header
*get_layout_range_header_by_pos(const struct list
*ranges
, UINT32 pos
)
481 struct layout_range_header
*cur
;
483 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
)
485 DWRITE_TEXT_RANGE
*r
= &cur
->range
;
486 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
493 static inline DWRITE_LINE_BREAKPOINT
get_effective_breakpoint(const struct dwrite_textlayout
*layout
, UINT32 pos
)
495 if (layout
->actual_breakpoints
)
496 return layout
->actual_breakpoints
[pos
];
497 return layout
->nominal_breakpoints
[pos
];
500 static inline void init_cluster_metrics(const struct dwrite_textlayout
*layout
, const struct regular_layout_run
*run
,
501 UINT16 start_glyph
, UINT16 stop_glyph
, UINT32 stop_position
, UINT16 length
, DWRITE_CLUSTER_METRICS
*metrics
)
503 UINT8 breakcondition
;
507 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
508 width as well; advances are already computed at this point and are not necessary zero. */
509 metrics
->width
= 0.0f
;
510 if (run
->run
.glyphCount
) {
511 for (j
= start_glyph
; j
< stop_glyph
; j
++)
512 metrics
->width
+= run
->run
.glyphAdvances
[j
];
514 metrics
->length
= length
;
516 position
= run
->descr
.textPosition
+ stop_position
;
517 if (stop_glyph
== run
->glyphcount
)
518 breakcondition
= get_effective_breakpoint(layout
, position
).breakConditionAfter
;
520 breakcondition
= get_effective_breakpoint(layout
, position
).breakConditionBefore
;
521 if (stop_position
) position
-= 1;
524 metrics
->canWrapLineAfter
= breakcondition
== DWRITE_BREAK_CONDITION_CAN_BREAK
||
525 breakcondition
== DWRITE_BREAK_CONDITION_MUST_BREAK
;
526 if (metrics
->length
== 1) {
527 DWRITE_LINE_BREAKPOINT bp
= get_effective_breakpoint(layout
, position
);
528 metrics
->isWhitespace
= bp
.isWhitespace
;
529 metrics
->isNewline
= metrics
->canWrapLineAfter
&& lb_is_newline_char(layout
->str
[position
]);
530 metrics
->isSoftHyphen
= bp
.isSoftHyphen
;
533 metrics
->isWhitespace
= 0;
534 metrics
->isNewline
= 0;
535 metrics
->isSoftHyphen
= 0;
537 metrics
->isRightToLeft
= run
->run
.bidiLevel
& 1;
538 metrics
->padding
= 0;
543 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
544 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
545 Note that there's no need to reallocate anything at this point as we allocate one cluster per
549 static void layout_set_cluster_metrics(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32
*cluster
)
551 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[*cluster
];
552 struct layout_cluster
*c
= &layout
->clusters
[*cluster
];
553 const struct regular_layout_run
*run
= &r
->u
.regular
;
556 assert(r
->kind
== LAYOUT_RUN_REGULAR
);
558 for (i
= 0; i
< run
->descr
.stringLength
; i
++) {
559 BOOL end
= i
== run
->descr
.stringLength
- 1;
561 if (run
->descr
.clusterMap
[start
] != run
->descr
.clusterMap
[i
]) {
562 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->descr
.clusterMap
[i
], i
,
574 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->glyphcount
, i
,
575 i
- start
+ 1, metrics
);
585 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
587 static void layout_get_font_metrics(const struct dwrite_textlayout
*layout
, IDWriteFontFace
*fontface
, float emsize
,
588 DWRITE_FONT_METRICS
*fontmetrics
)
590 if (is_layout_gdi_compatible(layout
)) {
591 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(fontface
, emsize
, layout
->ppdip
, &layout
->transform
, fontmetrics
);
593 WARN("failed to get compat metrics, 0x%08lx\n", hr
);
596 IDWriteFontFace_GetMetrics(fontface
, fontmetrics
);
599 static inline void layout_get_font_height(float emsize
, const DWRITE_FONT_METRICS
*fontmetrics
, float *baseline
, float *height
)
601 *baseline
= SCALE_FONT_METRIC(fontmetrics
->ascent
+ fontmetrics
->lineGap
, emsize
, fontmetrics
);
602 *height
= SCALE_FONT_METRIC(fontmetrics
->ascent
+ fontmetrics
->descent
+ fontmetrics
->lineGap
, emsize
, fontmetrics
);
605 static inline void layout_initialize_text_source(struct dwrite_textlayout
*layout
, unsigned int offset
,
608 layout
->text_source
.offset
= offset
;
609 layout
->text_source
.length
= length
;
612 static HRESULT
layout_itemize(struct dwrite_textlayout
*layout
)
614 IDWriteTextAnalyzer2
*analyzer
;
615 struct layout_range
*range
;
616 struct layout_run
*r
;
619 analyzer
= get_text_analyzer();
621 layout_initialize_text_source(layout
, 0, layout
->len
);
622 LIST_FOR_EACH_ENTRY(range
, &layout
->ranges
, struct layout_range
, h
.entry
) {
623 /* We don't care about ranges that don't contain any text. */
624 if (range
->h
.range
.startPosition
>= layout
->len
)
627 /* Inline objects override actual text in range. */
629 hr
= layout_update_breakpoints_range(layout
, range
);
633 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_INLINE
, range
->h
.range
.startPosition
, &r
)))
636 r
->u
.object
.object
= range
->object
;
637 r
->u
.object
.length
= get_clipped_range_length(layout
, range
);
638 list_add_tail(&layout
->runs
, &r
->entry
);
642 /* Initial splitting by script. */
643 hr
= IDWriteTextAnalyzer2_AnalyzeScript(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
644 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
),
645 (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
649 /* Splitting further by bidi levels. */
650 hr
= IDWriteTextAnalyzer2_AnalyzeBidi(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
651 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
),
652 (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
660 static HRESULT
layout_map_run_characters(struct dwrite_textlayout
*layout
, struct layout_run
*r
,
661 IDWriteFontFallback
*fallback
, struct layout_run
**remaining
)
663 struct regular_layout_run
*run
= &r
->u
.regular
;
664 IDWriteFontCollection
*collection
;
665 struct layout_range
*range
;
671 range
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
);
672 collection
= range
->collection
? range
->collection
: layout
->system_collection
;
674 length
= run
->descr
.stringLength
;
678 unsigned int mapped_length
= 0;
679 IDWriteFont
*font
= NULL
;
684 layout_initialize_text_source(layout
, run
->descr
.textPosition
, run
->descr
.stringLength
);
685 hr
= IDWriteFontFallback_MapCharacters(fallback
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
686 0, run
->descr
.stringLength
, collection
, range
->fontfamily
, range
->weight
, range
->style
, range
->stretch
,
687 &mapped_length
, &font
, &scale
);
690 WARN("%s: failed to map family %s, collection %p, hr %#lx.\n", debugstr_rundescr(&run
->descr
),
691 debugstr_w(range
->fontfamily
), collection
, hr
);
701 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
702 IDWriteFont_Release(font
);
705 WARN("Failed to create a font face, hr %#lx.\n", hr
);
709 run
->run
.fontEmSize
= range
->fontsize
* scale
;
711 if (mapped_length
< length
)
713 struct regular_layout_run
*nextrun
;
714 struct layout_run
*nextr
;
716 /* Keep mapped part for current run, add another run for the rest. */
717 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_REGULAR
, 0, &nextr
)))
721 nextr
->start_position
= run
->descr
.textPosition
+ mapped_length
;
722 nextrun
= &nextr
->u
.regular
;
723 nextrun
->run
.fontFace
= NULL
;
724 nextrun
->descr
.textPosition
= nextr
->start_position
;
725 nextrun
->descr
.stringLength
= run
->descr
.stringLength
- mapped_length
;
726 nextrun
->descr
.string
= &layout
->str
[nextrun
->descr
.textPosition
];
727 run
->descr
.stringLength
= mapped_length
;
728 list_add_after(&r
->entry
, &nextr
->entry
);
732 length
-= min(length
, mapped_length
);
738 static HRESULT
layout_run_get_last_resort_font(const struct dwrite_textlayout
*layout
, const struct layout_range
*range
,
739 IDWriteFontFace
**fontface
, float *size
)
744 if (FAILED(create_matching_font(range
->collection
, range
->fontfamily
, range
->weight
, range
->style
,
745 range
->stretch
, &IID_IDWriteFont3
, (void **)&font
)))
747 if (FAILED(hr
= create_matching_font(layout
->system_collection
, L
"Tahoma", range
->weight
, range
->style
,
748 range
->stretch
, &IID_IDWriteFont3
, (void **)&font
)))
750 WARN("Failed to create last resort font, hr %#lx.\n", hr
);
755 hr
= IDWriteFont_CreateFontFace(font
, fontface
);
756 IDWriteFont_Release(font
);
759 WARN("Failed to create last resort font face, hr %#lx.\n", hr
);
763 *size
= range
->fontsize
;
768 static HRESULT
layout_resolve_fonts(struct dwrite_textlayout
*layout
)
770 IDWriteFontFallback
*system_fallback
;
771 struct layout_run
*r
, *remaining
;
774 if (FAILED(hr
= IDWriteFactory7_GetSystemFontFallback(layout
->factory
, &system_fallback
)))
776 WARN("Failed to get system fallback, hr %#lx.\n", hr
);
780 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
)
782 struct regular_layout_run
*run
= &r
->u
.regular
;
784 if (r
->kind
== LAYOUT_RUN_INLINE
)
787 /* For textual runs use both custom and system fallback. For non-visual ones only use the system fallback,
788 and no hard-coded names in assumption that support for missing control characters could be easily
789 added to bundled fonts. */
791 if (run
->sa
.shapes
== DWRITE_SCRIPT_SHAPES_NO_VISUAL
)
793 if (FAILED(hr
= layout_map_run_characters(layout
, r
, system_fallback
, &remaining
)))
795 WARN("Failed to map fonts for non-visual run, hr %#lx.\n", hr
);
801 if (layout
->format
.fallback
)
802 hr
= layout_map_run_characters(layout
, r
, layout
->format
.fallback
, &remaining
);
807 hr
= layout_map_run_characters(layout
, remaining
, system_fallback
, &remaining
);
812 hr
= layout_run_get_last_resort_font(layout
, get_layout_range_by_pos(layout
, remaining
->u
.regular
.descr
.textPosition
),
813 &remaining
->u
.regular
.run
.fontFace
, &remaining
->u
.regular
.run
.fontEmSize
);
816 if (FAILED(hr
)) break;
819 IDWriteFontFallback_Release(system_fallback
);
824 struct shaping_context
826 IDWriteTextAnalyzer2
*analyzer
;
827 struct regular_layout_run
*run
;
828 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
;
829 DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
;
833 DWRITE_TYPOGRAPHIC_FEATURES
**features
;
834 unsigned int *range_lengths
;
835 unsigned int range_count
;
839 static void layout_shape_clear_user_features_context(struct shaping_context
*context
)
843 for (i
= 0; i
< context
->user_features
.range_count
; ++i
)
845 free(context
->user_features
.features
[i
]->features
);
846 free(context
->user_features
.features
[i
]);
848 free(context
->user_features
.features
);
849 memset(&context
->user_features
, 0, sizeof(context
->user_features
));
852 static void layout_shape_clear_context(struct shaping_context
*context
)
854 layout_shape_clear_user_features_context(context
);
855 free(context
->glyph_props
);
856 free(context
->text_props
);
859 static HRESULT
layout_shape_add_empty_user_features_range(struct shaping_context
*context
, unsigned int length
)
861 DWRITE_TYPOGRAPHIC_FEATURES
*features
;
862 unsigned int r
= context
->user_features
.range_count
;
864 if (!(context
->user_features
.features
[r
] = calloc(1, sizeof(*features
))))
865 return E_OUTOFMEMORY
;
867 context
->user_features
.range_lengths
[r
] = length
;
868 context
->user_features
.range_count
++;
873 static HRESULT
layout_shape_get_user_features(const struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
875 unsigned int i
, f
, start
= 0, r
, covered_length
= 0, length
, feature_count
;
876 struct regular_layout_run
*run
= context
->run
;
877 DWRITE_TYPOGRAPHIC_FEATURES
*features
;
878 struct layout_range_iface
*range
;
879 IDWriteTypography
*typography
;
880 HRESULT hr
= E_OUTOFMEMORY
;
882 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->typographies
, 0);
883 if (range
->h
.range
.length
>= run
->descr
.stringLength
&& !range
->iface
)
886 if (!(context
->user_features
.features
= calloc(run
->descr
.stringLength
, sizeof(*context
->user_features
.features
))))
888 if (!(context
->user_features
.range_lengths
= calloc(run
->descr
.stringLength
, sizeof(*context
->user_features
.range_lengths
))))
891 for (i
= run
->descr
.textPosition
; i
< run
->descr
.textPosition
+ run
->descr
.stringLength
; ++i
)
893 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->typographies
, i
);
894 if (!range
|| !range
->iface
) continue;
896 typography
= (IDWriteTypography
*)range
->iface
;
897 feature_count
= IDWriteTypography_GetFontFeatureCount(typography
);
900 i
= range
->h
.range
.length
- i
+ 1;
906 if (FAILED(hr
= layout_shape_add_empty_user_features_range(context
, i
- start
))) goto failed
;
907 covered_length
+= i
- start
;
908 start
+= range
->h
.range
.length
;
911 r
= context
->user_features
.range_count
;
912 if (!(features
= context
->user_features
.features
[r
] = malloc(sizeof(*features
))))
915 context
->user_features
.range_lengths
[r
] = length
= min(run
->descr
.textPosition
+ run
->descr
.stringLength
,
916 range
->h
.range
.startPosition
+ range
->h
.range
.length
) - i
;
917 features
->featureCount
= feature_count
;
918 if (!(features
->features
= calloc(feature_count
, sizeof(*features
->features
))))
921 for (f
= 0; f
< feature_count
; ++f
)
923 IDWriteTypography_GetFontFeature(typography
, f
, &features
->features
[f
]);
927 covered_length
+= length
;
928 context
->user_features
.range_count
++;
931 if (context
->user_features
.range_count
&& covered_length
< run
->descr
.stringLength
)
933 if (FAILED(hr
= layout_shape_add_empty_user_features_range(context
, run
->descr
.stringLength
- covered_length
)))
941 if (!context
->user_features
.range_count
|| FAILED(hr
))
942 layout_shape_clear_user_features_context(context
);
947 static HRESULT
layout_shape_get_glyphs(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
949 struct regular_layout_run
*run
= context
->run
;
950 unsigned int max_count
;
953 run
->descr
.localeName
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
)->locale
;
954 run
->clustermap
= calloc(run
->descr
.stringLength
, sizeof(*run
->clustermap
));
955 if (!run
->clustermap
)
956 return E_OUTOFMEMORY
;
958 max_count
= 3 * run
->descr
.stringLength
/ 2 + 16;
959 run
->glyphs
= calloc(max_count
, sizeof(*run
->glyphs
));
961 return E_OUTOFMEMORY
;
963 context
->text_props
= calloc(run
->descr
.stringLength
, sizeof(*context
->text_props
));
964 context
->glyph_props
= calloc(max_count
, sizeof(*context
->glyph_props
));
965 if (!context
->text_props
|| !context
->glyph_props
)
966 return E_OUTOFMEMORY
;
968 if (FAILED(hr
= layout_shape_get_user_features(layout
, context
)))
973 hr
= IDWriteTextAnalyzer2_GetGlyphs(context
->analyzer
, run
->descr
.string
, run
->descr
.stringLength
, run
->run
.fontFace
,
974 run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
, NULL
/* FIXME */,
975 (const DWRITE_TYPOGRAPHIC_FEATURES
**)context
->user_features
.features
, context
->user_features
.range_lengths
,
976 context
->user_features
.range_count
, max_count
, run
->clustermap
, context
->text_props
, run
->glyphs
,
977 context
->glyph_props
, &run
->glyphcount
);
978 if (hr
== E_NOT_SUFFICIENT_BUFFER
)
981 free(context
->glyph_props
);
985 run
->glyphs
= calloc(max_count
, sizeof(*run
->glyphs
));
986 context
->glyph_props
= calloc(max_count
, sizeof(*context
->glyph_props
));
987 if (!run
->glyphs
|| !context
->glyph_props
)
1000 WARN("%s: shaping failed, hr %#lx.\n", debugstr_rundescr(&run
->descr
), hr
);
1002 run
->run
.glyphIndices
= run
->glyphs
;
1003 run
->descr
.clusterMap
= run
->clustermap
;
1008 static struct layout_range_spacing
*layout_get_next_spacing_range(const struct dwrite_textlayout
*layout
,
1009 const struct layout_range_spacing
*cur
)
1011 return (struct layout_range_spacing
*)LIST_ENTRY(list_next(&layout
->spacing
, &cur
->h
.entry
),
1012 struct layout_range_header
, entry
);
1015 static HRESULT
layout_shape_apply_character_spacing(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
1017 struct regular_layout_run
*run
= context
->run
;
1018 struct layout_range_spacing
*first
= NULL
, *last
= NULL
, *cur
;
1019 unsigned int i
, length
, pos
, start
, end
, g0
, glyph_count
;
1020 struct layout_range_header
*h
;
1023 LIST_FOR_EACH_ENTRY(h
, &layout
->spacing
, struct layout_range_header
, entry
)
1025 if ((h
->range
.startPosition
>= run
->descr
.textPosition
&&
1026 h
->range
.startPosition
<= run
->descr
.textPosition
+ run
->descr
.stringLength
) ||
1027 (run
->descr
.textPosition
>= h
->range
.startPosition
&&
1028 run
->descr
.textPosition
<= h
->range
.startPosition
+ h
->range
.length
))
1030 if (!first
) first
= last
= (struct layout_range_spacing
*)h
;
1032 else if (last
) break;
1034 if (!first
) return S_OK
;
1036 if (!(clustermap
= calloc(run
->descr
.stringLength
, sizeof(*clustermap
))))
1037 return E_OUTOFMEMORY
;
1039 pos
= run
->descr
.textPosition
;
1041 for (cur
= first
;; cur
= layout_get_next_spacing_range(layout
, cur
))
1043 float leading
, trailing
;
1045 /* The range current spacing settings apply to. */
1046 start
= max(pos
, cur
->h
.range
.startPosition
);
1047 pos
= end
= min(pos
+ run
->descr
.stringLength
, cur
->h
.range
.startPosition
+ cur
->h
.range
.length
);
1049 /* Back to run-relative index. */
1050 start
-= run
->descr
.textPosition
;
1051 end
-= run
->descr
.textPosition
;
1053 length
= end
- start
;
1055 g0
= run
->descr
.clusterMap
[start
];
1057 for (i
= 0; i
< length
; ++i
)
1058 clustermap
[i
] = run
->descr
.clusterMap
[start
+ i
] - run
->descr
.clusterMap
[start
];
1060 glyph_count
= (end
< run
->descr
.stringLength
? run
->descr
.clusterMap
[end
] + 1 : run
->glyphcount
) - g0
;
1062 /* There is no direction argument for spacing interface, we have to swap arguments here to get desired output. */
1063 if (run
->run
.bidiLevel
& 1)
1065 leading
= cur
->trailing
;
1066 trailing
= cur
->leading
;
1070 leading
= cur
->leading
;
1071 trailing
= cur
->trailing
;
1073 IDWriteTextAnalyzer2_ApplyCharacterSpacing(context
->analyzer
, leading
, trailing
, cur
->min_advance
,
1074 length
, glyph_count
, clustermap
, &run
->advances
[g0
], &run
->offsets
[g0
], &context
->glyph_props
[g0
],
1075 &run
->advances
[g0
], &run
->offsets
[g0
]);
1077 if (cur
== last
) break;
1085 static HRESULT
layout_shape_get_positions(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
1087 struct regular_layout_run
*run
= context
->run
;
1090 run
->advances
= calloc(run
->glyphcount
, sizeof(*run
->advances
));
1091 run
->offsets
= calloc(run
->glyphcount
, sizeof(*run
->offsets
));
1092 if (!run
->advances
|| !run
->offsets
)
1093 return E_OUTOFMEMORY
;
1095 /* Get advances and offsets. */
1096 if (is_layout_gdi_compatible(layout
))
1097 hr
= IDWriteTextAnalyzer2_GetGdiCompatibleGlyphPlacements(context
->analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
1098 context
->text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, context
->glyph_props
, run
->glyphcount
,
1099 run
->run
.fontFace
, run
->run
.fontEmSize
, layout
->ppdip
, &layout
->transform
,
1100 layout
->measuringmode
== DWRITE_MEASURING_MODE_GDI_NATURAL
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1,
1101 &run
->sa
, run
->descr
.localeName
, (const DWRITE_TYPOGRAPHIC_FEATURES
**)context
->user_features
.features
,
1102 context
->user_features
.range_lengths
, context
->user_features
.range_count
, run
->advances
, run
->offsets
);
1104 hr
= IDWriteTextAnalyzer2_GetGlyphPlacements(context
->analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
1105 context
->text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, context
->glyph_props
, run
->glyphcount
,
1106 run
->run
.fontFace
, run
->run
.fontEmSize
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
,
1107 run
->descr
.localeName
, (const DWRITE_TYPOGRAPHIC_FEATURES
**)context
->user_features
.features
,
1108 context
->user_features
.range_lengths
, context
->user_features
.range_count
, run
->advances
, run
->offsets
);
1112 memset(run
->advances
, 0, run
->glyphcount
* sizeof(*run
->advances
));
1113 memset(run
->offsets
, 0, run
->glyphcount
* sizeof(*run
->offsets
));
1114 WARN("%s: failed to get glyph placement info, hr %#lx.\n", debugstr_rundescr(&run
->descr
), hr
);
1118 hr
= layout_shape_apply_character_spacing(layout
, context
);
1120 run
->run
.glyphAdvances
= run
->advances
;
1121 run
->run
.glyphOffsets
= run
->offsets
;
1126 static HRESULT
layout_shape_run(struct dwrite_textlayout
*layout
, struct regular_layout_run
*run
)
1128 struct shaping_context context
= { 0 };
1131 context
.analyzer
= get_text_analyzer();
1134 if (SUCCEEDED(hr
= layout_shape_get_glyphs(layout
, &context
)))
1135 hr
= layout_shape_get_positions(layout
, &context
);
1137 layout_shape_clear_context(&context
);
1139 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1140 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero
1142 if (run
->sa
.shapes
== DWRITE_SCRIPT_SHAPES_NO_VISUAL
)
1143 run
->run
.glyphCount
= 0;
1145 run
->run
.glyphCount
= run
->glyphcount
;
1150 static HRESULT
layout_compute_runs(struct dwrite_textlayout
*layout
)
1152 struct layout_run
*r
;
1156 free_layout_eruns(layout
);
1157 free_layout_runs(layout
);
1159 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
1160 if (!layout
->clustermetrics
&& layout
->len
)
1162 layout
->clustermetrics
= calloc(layout
->len
, sizeof(*layout
->clustermetrics
));
1163 layout
->clusters
= calloc(layout
->len
, sizeof(*layout
->clusters
));
1164 if (!layout
->clustermetrics
|| !layout
->clusters
)
1166 free(layout
->clustermetrics
);
1167 free(layout
->clusters
);
1168 return E_OUTOFMEMORY
;
1171 layout
->cluster_count
= 0;
1173 if (FAILED(hr
= layout_itemize(layout
))) {
1174 WARN("Itemization failed, hr %#lx.\n", hr
);
1178 if (FAILED(hr
= layout_resolve_fonts(layout
))) {
1179 WARN("Failed to resolve layout fonts, hr %#lx.\n", hr
);
1184 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
1185 struct regular_layout_run
*run
= &r
->u
.regular
;
1186 DWRITE_FONT_METRICS fontmetrics
= { 0 };
1188 /* we need to do very little in case of inline objects */
1189 if (r
->kind
== LAYOUT_RUN_INLINE
) {
1190 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[cluster
];
1191 struct layout_cluster
*c
= &layout
->clusters
[cluster
];
1192 DWRITE_INLINE_OBJECT_METRICS inlinemetrics
;
1194 metrics
->width
= 0.0f
;
1195 metrics
->length
= r
->u
.object
.length
;
1196 metrics
->canWrapLineAfter
= 0;
1197 metrics
->isWhitespace
= 0;
1198 metrics
->isNewline
= 0;
1199 metrics
->isSoftHyphen
= 0;
1200 metrics
->isRightToLeft
= 0;
1201 metrics
->padding
= 0;
1203 c
->position
= 0; /* there's always one cluster per inline object, so 0 is valid value */
1206 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
1207 hr
= IDWriteInlineObject_GetMetrics(r
->u
.object
.object
, &inlinemetrics
);
1209 memset(&inlinemetrics
, 0, sizeof(inlinemetrics
));
1212 metrics
->width
= inlinemetrics
.width
;
1213 r
->baseline
= inlinemetrics
.baseline
;
1214 r
->height
= inlinemetrics
.height
;
1216 /* FIXME: use resolved breakpoints in this case too */
1221 if (FAILED(hr
= layout_shape_run(layout
, run
)))
1222 WARN("%s: shaping failed, hr %#lx.\n", debugstr_rundescr(&run
->descr
), hr
);
1224 /* baseline derived from font metrics */
1225 layout_get_font_metrics(layout
, run
->run
.fontFace
, run
->run
.fontEmSize
, &fontmetrics
);
1226 layout_get_font_height(run
->run
.fontEmSize
, &fontmetrics
, &r
->baseline
, &r
->height
);
1228 layout_set_cluster_metrics(layout
, r
, &cluster
);
1232 layout
->cluster_count
= cluster
;
1234 layout
->clustermetrics
[cluster
-1].canWrapLineAfter
= 1;
1240 static HRESULT
layout_compute(struct dwrite_textlayout
*layout
)
1244 if (!(layout
->recompute
& RECOMPUTE_CLUSTERS
))
1247 /* nominal breakpoints are evaluated only once, because string never changes */
1248 if (!layout
->nominal_breakpoints
)
1250 IDWriteTextAnalyzer2
*analyzer
;
1252 if (!(layout
->nominal_breakpoints
= calloc(layout
->len
, sizeof(*layout
->nominal_breakpoints
))))
1253 return E_OUTOFMEMORY
;
1255 analyzer
= get_text_analyzer();
1257 layout_initialize_text_source(layout
, 0, layout
->len
);
1258 if (FAILED(hr
= IDWriteTextAnalyzer2_AnalyzeLineBreakpoints(analyzer
,
1259 (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
1260 0, layout
->len
, (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
)))
1261 WARN("Line breakpoints analysis failed, hr %#lx.\n", hr
);
1264 free(layout
->actual_breakpoints
);
1265 layout
->actual_breakpoints
= NULL
;
1267 hr
= layout_compute_runs(layout
);
1269 if (TRACE_ON(dwrite
)) {
1270 struct layout_run
*cur
;
1272 LIST_FOR_EACH_ENTRY(cur
, &layout
->runs
, struct layout_run
, entry
) {
1273 if (cur
->kind
== LAYOUT_RUN_INLINE
)
1274 TRACE("run inline object %p, len %u\n", cur
->u
.object
.object
, cur
->u
.object
.length
);
1276 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur
->u
.regular
.descr
.textPosition
, cur
->u
.regular
.descr
.textPosition
+
1277 cur
->u
.regular
.descr
.stringLength
-1, cur
->u
.regular
.descr
.stringLength
, cur
->u
.regular
.run
.bidiLevel
);
1281 layout
->recompute
&= ~RECOMPUTE_CLUSTERS
;
1285 static inline float get_cluster_range_width(const struct dwrite_textlayout
*layout
, UINT32 start
, UINT32 end
)
1288 for (; start
< end
; start
++)
1289 width
+= layout
->clustermetrics
[start
].width
;
1293 static inline IUnknown
*layout_get_effect_from_pos(const struct dwrite_textlayout
*layout
, UINT32 pos
)
1295 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->effects
, pos
);
1296 return ((struct layout_range_iface
*)h
)->iface
;
1299 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1300 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1301 one of the arguments, but it also happens for decorations, so every effective run has uniform
1302 underline/strikethough/effect tuple. */
1303 struct layout_final_splitting_params
{
1309 static inline BOOL
layout_get_strikethrough_from_pos(const struct dwrite_textlayout
*layout
, UINT32 pos
)
1311 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->strike_ranges
, pos
);
1312 return ((struct layout_range_bool
*)h
)->value
;
1315 static inline BOOL
layout_get_underline_from_pos(const struct dwrite_textlayout
*layout
, UINT32 pos
)
1317 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->underline_ranges
, pos
);
1318 return ((struct layout_range_bool
*)h
)->value
;
1321 static void layout_splitting_params_from_pos(const struct dwrite_textlayout
*layout
, UINT32 pos
,
1322 struct layout_final_splitting_params
*params
)
1324 params
->strikethrough
= layout_get_strikethrough_from_pos(layout
, pos
);
1325 params
->underline
= layout_get_underline_from_pos(layout
, pos
);
1326 params
->effect
= layout_get_effect_from_pos(layout
, pos
);
1329 static BOOL
is_same_splitting_params(const struct layout_final_splitting_params
*left
,
1330 const struct layout_final_splitting_params
*right
)
1332 return left
->strikethrough
== right
->strikethrough
&&
1333 left
->underline
== right
->underline
&&
1334 left
->effect
== right
->effect
;
1337 static void layout_get_erun_font_metrics(const struct dwrite_textlayout
*layout
, const struct layout_effective_run
*erun
,
1338 DWRITE_FONT_METRICS
*metrics
)
1340 memset(metrics
, 0, sizeof(*metrics
));
1341 if (is_layout_gdi_compatible(layout
)) {
1342 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(
1343 erun
->run
->u
.regular
.run
.fontFace
,
1344 erun
->run
->u
.regular
.run
.fontEmSize
,
1349 WARN("failed to get font metrics, 0x%08lx\n", hr
);
1352 IDWriteFontFace_GetMetrics(erun
->run
->u
.regular
.run
.fontFace
, metrics
);
1355 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1356 'cluster_count' indicates how many clusters to add, including first one. */
1357 static HRESULT
layout_add_effective_run(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32 first_cluster
,
1358 UINT32 cluster_count
, UINT32 line
, FLOAT origin_x
, struct layout_final_splitting_params
*params
)
1360 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1361 UINT32 i
, start
, length
, last_cluster
;
1362 struct layout_effective_run
*run
;
1364 if (r
->kind
== LAYOUT_RUN_INLINE
)
1366 struct layout_effective_inline
*inlineobject
;
1368 if (!(inlineobject
= malloc(sizeof(*inlineobject
))))
1369 return E_OUTOFMEMORY
;
1371 inlineobject
->object
= r
->u
.object
.object
;
1372 inlineobject
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1373 inlineobject
->origin
.x
= is_rtl
? origin_x
- inlineobject
->width
: origin_x
;
1374 inlineobject
->origin
.y
= 0.0f
; /* set after line is built */
1375 inlineobject
->align_dx
= 0.0f
;
1376 inlineobject
->baseline
= r
->baseline
;
1378 /* It's not clear how these two are set, possibly directionality
1379 is derived from surrounding text (replaced text could have
1380 different ranges which differ in reading direction). */
1381 inlineobject
->is_sideways
= FALSE
;
1382 inlineobject
->is_rtl
= FALSE
;
1383 inlineobject
->line
= line
;
1385 /* effect assigned from start position and on is used for inline objects */
1386 inlineobject
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[first_cluster
].position
+
1387 layout
->clusters
[first_cluster
].run
->start_position
);
1389 list_add_tail(&layout
->inlineobjects
, &inlineobject
->entry
);
1393 if (!(run
= malloc(sizeof(*run
))))
1394 return E_OUTOFMEMORY
;
1396 /* No need to iterate for that, use simple fact that:
1397 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1398 last_cluster
= first_cluster
+ cluster_count
- 1;
1399 length
= layout
->clusters
[last_cluster
].position
- layout
->clusters
[first_cluster
].position
+
1400 layout
->clustermetrics
[last_cluster
].length
;
1402 if (!(run
->clustermap
= calloc(length
, sizeof(*run
->clustermap
))))
1405 return E_OUTOFMEMORY
;
1409 run
->start
= start
= layout
->clusters
[first_cluster
].position
;
1410 run
->length
= length
;
1411 run
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1412 memset(&run
->bbox
, 0, sizeof(run
->bbox
));
1414 /* Adjust by run width if direction differs. */
1415 if (is_run_rtl(run
) != is_rtl
)
1416 run
->origin
.x
= origin_x
+ (is_rtl
? -run
->width
: run
->width
);
1418 run
->origin
.x
= origin_x
;
1420 run
->origin
.y
= 0.0f
; /* set after line is built */
1421 run
->align_dx
= 0.0f
;
1424 if (r
->u
.regular
.run
.glyphCount
) {
1425 /* Trim leading and trailing clusters. */
1426 run
->glyphcount
= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
];
1427 if (start
+ length
< r
->u
.regular
.descr
.stringLength
)
1428 run
->glyphcount
-= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
+ length
];
1431 run
->glyphcount
= 0;
1433 /* cluster map needs to be shifted */
1434 for (i
= 0; i
< length
; i
++)
1435 run
->clustermap
[i
] = r
->u
.regular
.clustermap
[start
+ i
] - r
->u
.regular
.clustermap
[start
];
1437 run
->effect
= params
->effect
;
1438 run
->underlined
= params
->underline
;
1439 list_add_tail(&layout
->eruns
, &run
->entry
);
1441 /* Strikethrough style is guaranteed to be consistent within effective run,
1442 its width equals to run width, thickness and offset are derived from
1443 font metrics, rest of the values are from layout or run itself */
1444 if (params
->strikethrough
)
1446 struct layout_strikethrough
*s
;
1447 DWRITE_FONT_METRICS metrics
;
1449 if (!(s
= malloc(sizeof(*s
))))
1450 return E_OUTOFMEMORY
;
1452 layout_get_erun_font_metrics(layout
, run
, &metrics
);
1453 s
->s
.width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1454 s
->s
.thickness
= SCALE_FONT_METRIC(metrics
.strikethroughThickness
, r
->u
.regular
.run
.fontEmSize
, &metrics
);
1455 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1456 s
->s
.offset
= -SCALE_FONT_METRIC(metrics
.strikethroughPosition
, r
->u
.regular
.run
.fontEmSize
, &metrics
);
1457 s
->s
.readingDirection
= layout
->format
.readingdir
;
1458 s
->s
.flowDirection
= layout
->format
.flow
;
1459 s
->s
.localeName
= r
->u
.regular
.descr
.localeName
;
1460 s
->s
.measuringMode
= layout
->measuringmode
;
1463 list_add_tail(&layout
->strikethrough
, &s
->entry
);
1469 static void layout_apply_line_spacing(struct dwrite_textlayout
*layout
, UINT32 line
)
1471 switch (layout
->format
.spacing
.method
)
1473 case DWRITE_LINE_SPACING_METHOD_DEFAULT
:
1474 layout
->lines
[line
].metrics
.height
= layout
->lines
[line
].height
;
1475 layout
->lines
[line
].metrics
.baseline
= layout
->lines
[line
].baseline
;
1477 case DWRITE_LINE_SPACING_METHOD_UNIFORM
:
1478 layout
->lines
[line
].metrics
.height
= layout
->format
.spacing
.height
;
1479 layout
->lines
[line
].metrics
.baseline
= layout
->format
.spacing
.baseline
;
1481 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
:
1482 layout
->lines
[line
].metrics
.height
= layout
->lines
[line
].height
* layout
->format
.spacing
.height
;
1483 layout
->lines
[line
].metrics
.baseline
= layout
->lines
[line
].baseline
* layout
->format
.spacing
.baseline
;
1486 ERR("Unknown spacing method %u\n", layout
->format
.spacing
.method
);
1490 static HRESULT
layout_set_line_metrics(struct dwrite_textlayout
*layout
, DWRITE_LINE_METRICS1
*metrics
)
1492 size_t i
= layout
->metrics
.lineCount
;
1494 if (!dwrite_array_reserve((void **)&layout
->lines
, &layout
->lines_size
, layout
->metrics
.lineCount
+ 1,
1495 sizeof(*layout
->lines
)))
1497 return E_OUTOFMEMORY
;
1500 layout
->lines
[i
].metrics
= *metrics
;
1501 layout
->lines
[i
].height
= metrics
->height
;
1502 layout
->lines
[i
].baseline
= metrics
->baseline
;
1504 if (layout
->format
.spacing
.method
!= DWRITE_LINE_SPACING_METHOD_DEFAULT
)
1505 layout_apply_line_spacing(layout
, i
);
1507 layout
->metrics
.lineCount
++;
1511 static inline struct layout_effective_run
*layout_get_next_erun(const struct dwrite_textlayout
*layout
,
1512 const struct layout_effective_run
*cur
)
1517 e
= list_head(&layout
->eruns
);
1519 e
= list_next(&layout
->eruns
, &cur
->entry
);
1522 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1525 static inline struct layout_effective_run
*layout_get_prev_erun(const struct dwrite_textlayout
*layout
,
1526 const struct layout_effective_run
*cur
)
1531 e
= list_tail(&layout
->eruns
);
1533 e
= list_prev(&layout
->eruns
, &cur
->entry
);
1536 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1539 static inline struct layout_effective_inline
*layout_get_next_inline_run(const struct dwrite_textlayout
*layout
,
1540 const struct layout_effective_inline
*cur
)
1545 e
= list_head(&layout
->inlineobjects
);
1547 e
= list_next(&layout
->inlineobjects
, &cur
->entry
);
1550 return LIST_ENTRY(e
, struct layout_effective_inline
, entry
);
1553 static float layout_get_line_width(const struct dwrite_textlayout
*layout
, const struct layout_effective_run
*erun
,
1554 const struct layout_effective_inline
*inrun
, UINT32 line
)
1558 while (erun
&& erun
->line
== line
) {
1559 width
+= erun
->width
;
1560 erun
= layout_get_next_erun(layout
, erun
);
1565 while (inrun
&& inrun
->line
== line
) {
1566 width
+= inrun
->width
;
1567 inrun
= layout_get_next_inline_run(layout
, inrun
);
1575 static inline BOOL
should_skip_transform(const DWRITE_MATRIX
*m
, FLOAT
*det
)
1577 *det
= m
->m11
* m
->m22
- m
->m12
* m
->m21
;
1578 /* on certain conditions we can skip transform */
1579 return (!memcmp(m
, &identity
, sizeof(*m
)) || fabsf(*det
) <= 1e-10f
);
1582 static inline void layout_apply_snapping(D2D1_POINT_2F
*vec
, BOOL skiptransform
, FLOAT ppdip
,
1583 const DWRITE_MATRIX
*m
, FLOAT det
)
1585 if (!skiptransform
) {
1588 /* apply transform */
1592 vec2
.x
= m
->m11
* vec
->x
+ m
->m21
* vec
->y
+ m
->dx
;
1593 vec2
.y
= m
->m12
* vec
->x
+ m
->m22
* vec
->y
+ m
->dy
;
1596 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
1597 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
1599 /* apply inverted transform, we don't care about X component at this point */
1600 vec
->x
= (m
->m22
* vec2
.x
- m
->m21
* vec2
.y
+ m
->m21
* m
->dy
- m
->m22
* m
->dx
) / det
;
1603 vec
->y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
1607 vec
->x
= floorf(vec
->x
* ppdip
+ 0.5f
) / ppdip
;
1608 vec
->y
= floorf(vec
->y
* ppdip
+ 0.5f
) / ppdip
;
1612 static void layout_apply_leading_alignment(struct dwrite_textlayout
*layout
)
1614 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1615 struct layout_effective_inline
*inrun
;
1616 struct layout_effective_run
*erun
;
1618 erun
= layout_get_next_erun(layout
, NULL
);
1619 inrun
= layout_get_next_inline_run(layout
, NULL
);
1622 erun
->align_dx
= 0.0f
;
1623 erun
= layout_get_next_erun(layout
, erun
);
1627 inrun
->align_dx
= 0.0f
;
1628 inrun
= layout_get_next_inline_run(layout
, inrun
);
1631 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
1634 static void layout_apply_trailing_alignment(struct dwrite_textlayout
*layout
)
1636 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1637 struct layout_effective_inline
*inrun
;
1638 struct layout_effective_run
*erun
;
1641 erun
= layout_get_next_erun(layout
, NULL
);
1642 inrun
= layout_get_next_inline_run(layout
, NULL
);
1644 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1645 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1646 FLOAT shift
= layout
->metrics
.layoutWidth
- width
;
1651 while (erun
&& erun
->line
== line
) {
1652 erun
->align_dx
= shift
;
1653 erun
= layout_get_next_erun(layout
, erun
);
1656 while (inrun
&& inrun
->line
== line
) {
1657 inrun
->align_dx
= shift
;
1658 inrun
= layout_get_next_inline_run(layout
, inrun
);
1662 layout
->metrics
.left
= is_rtl
? 0.0f
: layout
->metrics
.layoutWidth
- layout
->metrics
.width
;
1665 static inline float layout_get_centered_shift(const struct dwrite_textlayout
*layout
, BOOL skiptransform
,
1666 FLOAT width
, FLOAT det
)
1668 if (is_layout_gdi_compatible(layout
)) {
1669 D2D1_POINT_2F vec
= { layout
->metrics
.layoutWidth
- width
, 0.0f
};
1670 layout_apply_snapping(&vec
, skiptransform
, layout
->ppdip
, &layout
->transform
, det
);
1671 return floorf(vec
.x
/ 2.0f
);
1674 return (layout
->metrics
.layoutWidth
- width
) / 2.0f
;
1677 static void layout_apply_centered_alignment(struct dwrite_textlayout
*layout
)
1679 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1680 struct layout_effective_inline
*inrun
;
1681 struct layout_effective_run
*erun
;
1686 erun
= layout_get_next_erun(layout
, NULL
);
1687 inrun
= layout_get_next_inline_run(layout
, NULL
);
1689 skiptransform
= should_skip_transform(&layout
->transform
, &det
);
1691 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1692 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1693 FLOAT shift
= layout_get_centered_shift(layout
, skiptransform
, width
, det
);
1698 while (erun
&& erun
->line
== line
) {
1699 erun
->align_dx
= shift
;
1700 erun
= layout_get_next_erun(layout
, erun
);
1703 while (inrun
&& inrun
->line
== line
) {
1704 inrun
->align_dx
= shift
;
1705 inrun
= layout_get_next_inline_run(layout
, inrun
);
1709 layout
->metrics
.left
= (layout
->metrics
.layoutWidth
- layout
->metrics
.width
) / 2.0f
;
1712 static void layout_apply_text_alignment(struct dwrite_textlayout
*layout
)
1714 switch (layout
->format
.textalignment
)
1716 case DWRITE_TEXT_ALIGNMENT_LEADING
:
1717 layout_apply_leading_alignment(layout
);
1719 case DWRITE_TEXT_ALIGNMENT_TRAILING
:
1720 layout_apply_trailing_alignment(layout
);
1722 case DWRITE_TEXT_ALIGNMENT_CENTER
:
1723 layout_apply_centered_alignment(layout
);
1725 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED
:
1726 FIXME("alignment %d not implemented\n", layout
->format
.textalignment
);
1733 static void layout_apply_par_alignment(struct dwrite_textlayout
*layout
)
1735 struct layout_effective_inline
*inrun
;
1736 struct layout_effective_run
*erun
;
1737 FLOAT origin_y
= 0.0f
;
1740 /* alignment mode defines origin, after that all run origins are updated
1743 switch (layout
->format
.paralign
)
1745 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR
:
1748 case DWRITE_PARAGRAPH_ALIGNMENT_FAR
:
1749 origin_y
= layout
->metrics
.layoutHeight
- layout
->metrics
.height
;
1751 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER
:
1752 origin_y
= (layout
->metrics
.layoutHeight
- layout
->metrics
.height
) / 2.0f
;
1758 layout
->metrics
.top
= origin_y
;
1760 erun
= layout_get_next_erun(layout
, NULL
);
1761 inrun
= layout_get_next_inline_run(layout
, NULL
);
1762 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++)
1764 float pos_y
= origin_y
+ layout
->lines
[line
].metrics
.baseline
;
1766 while (erun
&& erun
->line
== line
) {
1767 erun
->origin
.y
= pos_y
;
1768 erun
= layout_get_next_erun(layout
, erun
);
1771 while (inrun
&& inrun
->line
== line
) {
1772 inrun
->origin
.y
= pos_y
- inrun
->baseline
;
1773 inrun
= layout_get_next_inline_run(layout
, inrun
);
1776 origin_y
+= layout
->lines
[line
].metrics
.height
;
1780 struct layout_underline_splitting_params
{
1781 const WCHAR
*locale
; /* points to range data, no additional allocation */
1782 IUnknown
*effect
; /* does not hold another reference */
1785 static void init_u_splitting_params_from_erun(const struct layout_effective_run
*erun
,
1786 struct layout_underline_splitting_params
*params
)
1788 params
->locale
= erun
->run
->u
.regular
.descr
.localeName
;
1789 params
->effect
= erun
->effect
;
1792 static BOOL
is_same_u_splitting(const struct layout_underline_splitting_params
*left
,
1793 const struct layout_underline_splitting_params
*right
)
1795 return left
->effect
== right
->effect
&& !wcsicmp(left
->locale
, right
->locale
);
1798 static HRESULT
layout_add_underline(struct dwrite_textlayout
*layout
, struct layout_effective_run
*first
,
1799 struct layout_effective_run
*last
)
1801 FLOAT thickness
, offset
, runheight
;
1802 struct layout_effective_run
*cur
;
1803 DWRITE_FONT_METRICS metrics
;
1805 if (first
== layout_get_prev_erun(layout
, last
)) {
1806 layout_get_erun_font_metrics(layout
, first
, &metrics
);
1807 thickness
= SCALE_FONT_METRIC(metrics
.underlineThickness
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1808 offset
= SCALE_FONT_METRIC(metrics
.underlinePosition
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1809 runheight
= SCALE_FONT_METRIC(metrics
.capHeight
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1814 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1815 calculated as weighted average, where run width acts as a weight. */
1816 thickness
= offset
= runheight
= 0.0f
;
1819 layout_get_erun_font_metrics(layout
, cur
, &metrics
);
1821 thickness
+= SCALE_FONT_METRIC(metrics
.underlineThickness
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
1822 offset
+= SCALE_FONT_METRIC(metrics
.underlinePosition
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
1823 runheight
= max(SCALE_FONT_METRIC(metrics
.capHeight
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
), runheight
);
1824 width
+= cur
->width
;
1826 cur
= layout_get_next_erun(layout
, cur
);
1827 } while (cur
!= last
);
1835 struct layout_underline_splitting_params params
, prev_params
;
1836 struct layout_effective_run
*next
, *w
;
1837 struct layout_underline
*u
;
1839 init_u_splitting_params_from_erun(cur
, &prev_params
);
1840 while ((next
= layout_get_next_erun(layout
, cur
)) != last
) {
1841 init_u_splitting_params_from_erun(next
, ¶ms
);
1842 if (!is_same_u_splitting(&prev_params
, ¶ms
))
1847 if (!(u
= malloc(sizeof(*u
))))
1848 return E_OUTOFMEMORY
;
1853 u
->u
.width
+= w
->width
;
1854 w
= layout_get_next_erun(layout
, w
);
1857 u
->u
.thickness
= thickness
;
1858 /* Font metrics convention is to have it negative when below baseline, for rendering
1859 however Y grows from baseline down for horizontal baseline. */
1860 u
->u
.offset
= -offset
;
1861 u
->u
.runHeight
= runheight
;
1862 u
->u
.readingDirection
= is_run_rtl(cur
) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
:
1863 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
1864 u
->u
.flowDirection
= layout
->format
.flow
;
1865 u
->u
.localeName
= cur
->run
->u
.regular
.descr
.localeName
;
1866 u
->u
.measuringMode
= layout
->measuringmode
;
1868 list_add_tail(&layout
->underlines
, &u
->entry
);
1871 } while (cur
!= last
);
1876 static inline struct regular_layout_run
* layout_get_last_run(const struct dwrite_textlayout
*layout
)
1878 struct layout_run
*r
;
1881 if (!(e
= list_tail(&layout
->runs
))) return NULL
;
1882 r
= LIST_ENTRY(e
, struct layout_run
, entry
);
1883 if (r
->kind
!= LAYOUT_RUN_REGULAR
) return NULL
;
1884 return &r
->u
.regular
;
1887 /* Adds a dummy line if:
1888 - there's no text, metrics come from first range in this case;
1889 - last ended with a mandatory break, metrics come from last text position.
1891 static HRESULT
layout_set_dummy_line_metrics(struct dwrite_textlayout
*layout
)
1893 DWRITE_LINE_METRICS1 metrics
= { 0 };
1894 DWRITE_FONT_METRICS fontmetrics
;
1895 struct regular_layout_run
*run
;
1896 IDWriteFontFace
*fontface
;
1900 if (layout
->cluster_count
&& !layout
->clustermetrics
[layout
->cluster_count
- 1].isNewline
)
1903 if (!layout
->cluster_count
)
1905 if (FAILED(hr
= layout_run_get_last_resort_font(layout
, get_layout_range_by_pos(layout
, 0), &fontface
, &size
)))
1908 else if (!(run
= layout_get_last_run(layout
)))
1914 fontface
= run
->run
.fontFace
;
1915 IDWriteFontFace_AddRef(fontface
);
1916 size
= run
->run
.fontEmSize
;
1919 layout_get_font_metrics(layout
, fontface
, size
, &fontmetrics
);
1920 layout_get_font_height(size
, &fontmetrics
, &metrics
.baseline
, &metrics
.height
);
1921 IDWriteFontFace_Release(fontface
);
1923 return layout_set_line_metrics(layout
, &metrics
);
1926 static void layout_add_line(struct dwrite_textlayout
*layout
, UINT32 first_cluster
, UINT32 last_cluster
,
1929 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1930 struct layout_final_splitting_params params
, prev_params
;
1931 DWRITE_INLINE_OBJECT_METRICS sign_metrics
= { 0 };
1932 UINT32 line
= layout
->metrics
.lineCount
, i
;
1933 DWRITE_LINE_METRICS1 metrics
= { 0 };
1934 UINT32 index
, start
, pos
= *textpos
;
1935 FLOAT descent
, trailingspacewidth
;
1936 BOOL append_trimming_run
= FALSE
;
1937 const struct layout_run
*run
;
1938 float width
= 0.0f
, origin_x
;
1941 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
1942 for (index
= last_cluster
, trailingspacewidth
= 0.0f
; index
>= first_cluster
; index
--) {
1943 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
1944 struct layout_cluster
*lc
= &layout
->clusters
[index
];
1947 /* This also filters out clusters added from inline objects, those are never
1948 treated as a white space. */
1949 if (!cluster
->isWhitespace
)
1952 /* Every isNewline cluster is also isWhitespace, but not every
1953 newline character cluster has isNewline set, so go back to original string. */
1954 ch
= lc
->run
->u
.regular
.descr
.string
[lc
->position
];
1955 if (cluster
->length
== 1 && lb_is_newline_char(ch
))
1956 metrics
.newlineLength
+= cluster
->length
;
1958 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1959 trailingspacewidth
+= cluster
->width
;
1965 /* Line metrics length includes trailing whitespace length too */
1966 for (i
= first_cluster
; i
<= last_cluster
; i
++)
1967 metrics
.length
+= layout
->clustermetrics
[i
].length
;
1969 /* Ignore trailing whitespaces */
1970 while (last_cluster
> first_cluster
) {
1971 if (!layout
->clustermetrics
[last_cluster
].isWhitespace
)
1977 /* Does not include trailing space width */
1978 if (!layout
->clustermetrics
[last_cluster
].isWhitespace
)
1979 width
= get_cluster_range_width(layout
, first_cluster
, last_cluster
+ 1);
1981 /* Append trimming run if necessary */
1982 if (width
> layout
->metrics
.layoutWidth
&& layout
->format
.trimmingsign
!= NULL
&&
1983 layout
->format
.trimming
.granularity
!= DWRITE_TRIMMING_GRANULARITY_NONE
) {
1984 FLOAT trimmed_width
= width
;
1986 hr
= IDWriteInlineObject_GetMetrics(layout
->format
.trimmingsign
, &sign_metrics
);
1987 if (SUCCEEDED(hr
)) {
1988 while (last_cluster
> first_cluster
) {
1989 if (trimmed_width
+ sign_metrics
.width
<= layout
->metrics
.layoutWidth
)
1991 if (layout
->format
.trimming
.granularity
== DWRITE_TRIMMING_GRANULARITY_CHARACTER
)
1992 trimmed_width
-= layout
->clustermetrics
[last_cluster
--].width
;
1994 while (last_cluster
> first_cluster
) {
1995 trimmed_width
-= layout
->clustermetrics
[last_cluster
].width
;
1996 if (layout
->clustermetrics
[last_cluster
--].canWrapLineAfter
)
2001 append_trimming_run
= TRUE
;
2004 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#lx.\n", hr
);
2006 width
= trimmed_width
+ sign_metrics
.width
;
2009 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
2010 prev_params
= params
;
2011 run
= layout
->clusters
[first_cluster
].run
;
2013 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
2014 origin_x
= is_rtl
? layout
->metrics
.layoutWidth
: 0.0f
;
2015 for (start
= first_cluster
, i
= first_cluster
; i
<= last_cluster
; i
++) {
2016 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
2018 if (run
!= layout
->clusters
[i
].run
|| !is_same_splitting_params(&prev_params
, ¶ms
)) {
2019 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
2023 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) :
2024 get_cluster_range_width(layout
, start
, i
);
2025 run
= layout
->clusters
[i
].run
;
2029 prev_params
= params
;
2030 pos
+= layout
->clustermetrics
[i
].length
;
2033 /* Final run from what's left from cluster range */
2034 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
2038 if (get_cluster_range_width(layout
, start
, i
) + sign_metrics
.width
> layout
->metrics
.layoutWidth
)
2039 append_trimming_run
= FALSE
;
2041 if (append_trimming_run
) {
2042 struct layout_effective_inline
*trimming_sign
;
2044 if (!(trimming_sign
= calloc(1, sizeof(*trimming_sign
))))
2047 trimming_sign
->object
= layout
->format
.trimmingsign
;
2048 trimming_sign
->width
= sign_metrics
.width
;
2049 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) : get_cluster_range_width(layout
, start
, i
);
2050 trimming_sign
->origin
.x
= is_rtl
? origin_x
- trimming_sign
->width
: origin_x
;
2051 trimming_sign
->origin
.y
= 0.0f
; /* set after line is built */
2052 trimming_sign
->align_dx
= 0.0f
;
2053 trimming_sign
->baseline
= sign_metrics
.baseline
;
2055 trimming_sign
->is_sideways
= FALSE
;
2056 trimming_sign
->is_rtl
= FALSE
;
2057 trimming_sign
->line
= line
;
2059 trimming_sign
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[i
].position
+
2060 layout
->clusters
[i
].run
->start_position
);
2062 list_add_tail(&layout
->inlineobjects
, &trimming_sign
->entry
);
2065 /* Look for max baseline and descent for this line */
2066 for (index
= first_cluster
, metrics
.baseline
= 0.0f
, descent
= 0.0f
; index
<= last_cluster
; index
++) {
2067 const struct layout_run
*cur
= layout
->clusters
[index
].run
;
2068 FLOAT cur_descent
= cur
->height
- cur
->baseline
;
2070 if (cur
->baseline
> metrics
.baseline
)
2071 metrics
.baseline
= cur
->baseline
;
2072 if (cur_descent
> descent
)
2073 descent
= cur_descent
;
2076 layout
->metrics
.width
= max(width
, layout
->metrics
.width
);
2077 layout
->metrics
.widthIncludingTrailingWhitespace
= max(width
+ trailingspacewidth
,
2078 layout
->metrics
.widthIncludingTrailingWhitespace
);
2080 metrics
.height
= descent
+ metrics
.baseline
;
2081 metrics
.isTrimmed
= append_trimming_run
|| width
> layout
->metrics
.layoutWidth
;
2082 layout_set_line_metrics(layout
, &metrics
);
2084 *textpos
+= metrics
.length
;
2087 static void layout_set_line_positions(struct dwrite_textlayout
*layout
)
2089 struct layout_effective_inline
*inrun
;
2090 struct layout_effective_run
*erun
;
2094 /* Now all line info is here, update effective runs positions in flow direction */
2095 erun
= layout_get_next_erun(layout
, NULL
);
2096 inrun
= layout_get_next_inline_run(layout
, NULL
);
2098 for (line
= 0, origin_y
= 0.0f
; line
< layout
->metrics
.lineCount
; line
++)
2100 float pos_y
= origin_y
+ layout
->lines
[line
].metrics
.baseline
;
2102 /* For all runs on this line */
2103 while (erun
&& erun
->line
== line
) {
2104 erun
->origin
.y
= pos_y
;
2105 erun
= layout_get_next_erun(layout
, erun
);
2108 /* Same for inline runs */
2109 while (inrun
&& inrun
->line
== line
) {
2110 inrun
->origin
.y
= pos_y
- inrun
->baseline
;
2111 inrun
= layout_get_next_inline_run(layout
, inrun
);
2114 origin_y
+= layout
->lines
[line
].metrics
.height
;
2117 layout
->metrics
.height
= origin_y
;
2119 /* Initial paragraph alignment is always near */
2120 if (layout
->format
.paralign
!= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
)
2121 layout_apply_par_alignment(layout
);
2124 static BOOL
layout_can_wrap_after(const struct dwrite_textlayout
*layout
, UINT32 cluster
)
2126 if (layout
->format
.wrapping
== DWRITE_WORD_WRAPPING_CHARACTER
)
2129 return layout
->clustermetrics
[cluster
].canWrapLineAfter
;
2132 static HRESULT
layout_compute_effective_runs(struct dwrite_textlayout
*layout
)
2134 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
2135 struct layout_effective_run
*erun
, *first_underlined
;
2136 UINT32 i
, start
, textpos
, last_breaking_point
;
2137 DWRITE_LINE_METRICS1 metrics
;
2142 if (!(layout
->recompute
& RECOMPUTE_LINES
))
2145 free_layout_eruns(layout
);
2147 hr
= layout_compute(layout
);
2151 layout
->metrics
.lineCount
= 0;
2152 memset(&metrics
, 0, sizeof(metrics
));
2154 layout
->metrics
.height
= 0.0f
;
2155 layout
->metrics
.width
= 0.0f
;
2156 layout
->metrics
.widthIncludingTrailingWhitespace
= 0.0f
;
2158 last_breaking_point
= ~0u;
2160 for (i
= 0, start
= 0, width
= 0.0f
, textpos
= 0; i
< layout
->cluster_count
; i
++) {
2161 BOOL overflow
= FALSE
;
2163 while (i
< layout
->cluster_count
&& !layout
->clustermetrics
[i
].isNewline
) {
2164 /* Check for overflow */
2165 overflow
= ((width
+ layout
->clustermetrics
[i
].width
> layout
->metrics
.layoutWidth
) &&
2166 (layout
->format
.wrapping
!= DWRITE_WORD_WRAPPING_NO_WRAP
));
2170 if (layout_can_wrap_after(layout
, i
))
2171 last_breaking_point
= i
;
2172 width
+= layout
->clustermetrics
[i
].width
;
2175 i
= min(i
, layout
->cluster_count
- 1);
2177 /* Ignore if overflown on whitespace */
2178 if (overflow
&& !(layout
->clustermetrics
[i
].isWhitespace
&& layout_can_wrap_after(layout
, i
))) {
2179 /* Use most recently found breaking point */
2180 if (last_breaking_point
!= ~0u) {
2181 i
= last_breaking_point
;
2182 last_breaking_point
= ~0u;
2185 /* Otherwise proceed forward to next newline or breaking point */
2186 for (; i
< layout
->cluster_count
; i
++)
2187 if (layout_can_wrap_after(layout
, i
) || layout
->clustermetrics
[i
].isNewline
)
2191 i
= min(i
, layout
->cluster_count
- 1);
2193 layout_add_line(layout
, start
, i
, &textpos
);
2198 if (FAILED(hr
= layout_set_dummy_line_metrics(layout
)))
2201 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
2202 layout
->metrics
.top
= 0.0f
;
2203 layout
->metrics
.maxBidiReorderingDepth
= 1; /* FIXME */
2205 /* Add explicit underlined runs */
2206 erun
= layout_get_next_erun(layout
, NULL
);
2207 first_underlined
= erun
&& erun
->underlined
? erun
: NULL
;
2208 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
2209 while (erun
&& erun
->line
== line
) {
2210 erun
= layout_get_next_erun(layout
, erun
);
2212 if (first_underlined
&& (!erun
|| !erun
->underlined
)) {
2213 layout_add_underline(layout
, first_underlined
, erun
);
2214 first_underlined
= NULL
;
2216 else if (!first_underlined
&& erun
&& erun
->underlined
)
2217 first_underlined
= erun
;
2221 /* Position runs in flow direction */
2222 layout_set_line_positions(layout
);
2224 /* Initial alignment is always leading */
2225 if (layout
->format
.textalignment
!= DWRITE_TEXT_ALIGNMENT_LEADING
)
2226 layout_apply_text_alignment(layout
);
2228 layout
->recompute
&= ~RECOMPUTE_LINES
;
2232 static BOOL
is_same_layout_attrvalue(struct layout_range_header
const *h
, enum layout_range_attr_kind attr
,
2233 struct layout_range_attr_value
*value
)
2235 struct layout_range_spacing
const *range_spacing
= (struct layout_range_spacing
*)h
;
2236 struct layout_range_iface
const *range_iface
= (struct layout_range_iface
*)h
;
2237 struct layout_range_bool
const *range_bool
= (struct layout_range_bool
*)h
;
2238 struct layout_range
const *range
= (struct layout_range
*)h
;
2241 case LAYOUT_RANGE_ATTR_WEIGHT
:
2242 return range
->weight
== value
->u
.weight
;
2243 case LAYOUT_RANGE_ATTR_STYLE
:
2244 return range
->style
== value
->u
.style
;
2245 case LAYOUT_RANGE_ATTR_STRETCH
:
2246 return range
->stretch
== value
->u
.stretch
;
2247 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2248 return range
->fontsize
== value
->u
.fontsize
;
2249 case LAYOUT_RANGE_ATTR_INLINE
:
2250 return range
->object
== value
->u
.object
;
2251 case LAYOUT_RANGE_ATTR_EFFECT
:
2252 return range_iface
->iface
== value
->u
.effect
;
2253 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2254 return range_bool
->value
== value
->u
.underline
;
2255 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2256 return range_bool
->value
== value
->u
.strikethrough
;
2257 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2258 return range
->pair_kerning
== value
->u
.pair_kerning
;
2259 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2260 return range
->collection
== value
->u
.collection
;
2261 case LAYOUT_RANGE_ATTR_LOCALE
:
2262 return !wcsicmp(range
->locale
, value
->u
.locale
);
2263 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2264 return !wcscmp(range
->fontfamily
, value
->u
.fontfamily
);
2265 case LAYOUT_RANGE_ATTR_SPACING
:
2266 return range_spacing
->leading
== value
->u
.spacing
.leading
&&
2267 range_spacing
->trailing
== value
->u
.spacing
.trailing
&&
2268 range_spacing
->min_advance
== value
->u
.spacing
.min_advance
;
2269 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2270 return range_iface
->iface
== (IUnknown
*)value
->u
.typography
;
2278 static inline BOOL
is_same_layout_attributes(struct layout_range_header
const *hleft
, struct layout_range_header
const *hright
)
2280 switch (hleft
->kind
)
2282 case LAYOUT_RANGE_REGULAR
:
2284 struct layout_range
const *left
= (struct layout_range
const*)hleft
;
2285 struct layout_range
const *right
= (struct layout_range
const*)hright
;
2286 return left
->weight
== right
->weight
&&
2287 left
->style
== right
->style
&&
2288 left
->stretch
== right
->stretch
&&
2289 left
->fontsize
== right
->fontsize
&&
2290 left
->object
== right
->object
&&
2291 left
->pair_kerning
== right
->pair_kerning
&&
2292 left
->collection
== right
->collection
&&
2293 !wcsicmp(left
->locale
, right
->locale
) &&
2294 !wcscmp(left
->fontfamily
, right
->fontfamily
);
2296 case LAYOUT_RANGE_UNDERLINE
:
2297 case LAYOUT_RANGE_STRIKETHROUGH
:
2299 struct layout_range_bool
const *left
= (struct layout_range_bool
const*)hleft
;
2300 struct layout_range_bool
const *right
= (struct layout_range_bool
const*)hright
;
2301 return left
->value
== right
->value
;
2303 case LAYOUT_RANGE_EFFECT
:
2304 case LAYOUT_RANGE_TYPOGRAPHY
:
2306 struct layout_range_iface
const *left
= (struct layout_range_iface
const*)hleft
;
2307 struct layout_range_iface
const *right
= (struct layout_range_iface
const*)hright
;
2308 return left
->iface
== right
->iface
;
2310 case LAYOUT_RANGE_SPACING
:
2312 struct layout_range_spacing
const *left
= (struct layout_range_spacing
const*)hleft
;
2313 struct layout_range_spacing
const *right
= (struct layout_range_spacing
const*)hright
;
2314 return left
->leading
== right
->leading
&&
2315 left
->trailing
== right
->trailing
&&
2316 left
->min_advance
== right
->min_advance
;
2319 FIXME("unknown range kind %d\n", hleft
->kind
);
2324 static inline BOOL
is_same_text_range(const DWRITE_TEXT_RANGE
*left
, const DWRITE_TEXT_RANGE
*right
)
2326 return left
->startPosition
== right
->startPosition
&& left
->length
== right
->length
;
2329 /* Allocates range and inits it with default values from text format. */
2330 static struct layout_range_header
*alloc_layout_range(struct dwrite_textlayout
*layout
, const DWRITE_TEXT_RANGE
*r
,
2331 enum layout_range_kind kind
)
2333 struct layout_range_header
*h
;
2337 case LAYOUT_RANGE_REGULAR
:
2339 struct layout_range
*range
;
2341 if (!(range
= calloc(1, sizeof(*range
))))
2344 range
->weight
= layout
->format
.weight
;
2345 range
->style
= layout
->format
.style
;
2346 range
->stretch
= layout
->format
.stretch
;
2347 range
->fontsize
= layout
->format
.fontsize
;
2349 range
->fontfamily
= wcsdup(layout
->format
.family_name
);
2350 if (!range
->fontfamily
)
2356 range
->collection
= layout
->format
.collection
;
2357 if (range
->collection
)
2358 IDWriteFontCollection_AddRef(range
->collection
);
2359 wcscpy(range
->locale
, layout
->format
.locale
);
2364 case LAYOUT_RANGE_UNDERLINE
:
2365 case LAYOUT_RANGE_STRIKETHROUGH
:
2367 struct layout_range_bool
*range
;
2369 if (!(range
= calloc(1, sizeof(*range
))))
2375 case LAYOUT_RANGE_EFFECT
:
2376 case LAYOUT_RANGE_TYPOGRAPHY
:
2378 struct layout_range_iface
*range
;
2380 if (!(range
= calloc(1, sizeof(*range
))))
2386 case LAYOUT_RANGE_SPACING
:
2388 struct layout_range_spacing
*range
;
2390 if (!(range
= calloc(1, sizeof(*range
))))
2397 FIXME("unknown range kind %d\n", kind
);
2406 static struct layout_range_header
*alloc_layout_range_from(struct layout_range_header
*h
, const DWRITE_TEXT_RANGE
*r
)
2408 struct layout_range_header
*ret
;
2412 case LAYOUT_RANGE_REGULAR
:
2414 struct layout_range
*from
= (struct layout_range
*)h
, *range
;
2416 if (!(range
= malloc(sizeof(*range
))))
2420 range
->fontfamily
= wcsdup(from
->fontfamily
);
2421 if (!range
->fontfamily
)
2427 /* update refcounts */
2429 IDWriteInlineObject_AddRef(range
->object
);
2430 if (range
->collection
)
2431 IDWriteFontCollection_AddRef(range
->collection
);
2435 case LAYOUT_RANGE_UNDERLINE
:
2436 case LAYOUT_RANGE_STRIKETHROUGH
:
2438 struct layout_range_bool
*strike
= malloc(sizeof(*strike
));
2439 if (!strike
) return NULL
;
2441 *strike
= *(struct layout_range_bool
*)h
;
2445 case LAYOUT_RANGE_EFFECT
:
2446 case LAYOUT_RANGE_TYPOGRAPHY
:
2448 struct layout_range_iface
*effect
= malloc(sizeof(*effect
));
2449 if (!effect
) return NULL
;
2451 *effect
= *(struct layout_range_iface
*)h
;
2453 IUnknown_AddRef(effect
->iface
);
2457 case LAYOUT_RANGE_SPACING
:
2459 struct layout_range_spacing
*spacing
= malloc(sizeof(*spacing
));
2460 if (!spacing
) return NULL
;
2462 *spacing
= *(struct layout_range_spacing
*)h
;
2467 FIXME("unknown range kind %d\n", h
->kind
);
2475 static void free_layout_range(struct layout_range_header
*h
)
2482 case LAYOUT_RANGE_REGULAR
:
2484 struct layout_range
*range
= (struct layout_range
*)h
;
2487 IDWriteInlineObject_Release(range
->object
);
2488 if (range
->collection
)
2489 IDWriteFontCollection_Release(range
->collection
);
2490 free(range
->fontfamily
);
2493 case LAYOUT_RANGE_EFFECT
:
2494 case LAYOUT_RANGE_TYPOGRAPHY
:
2496 struct layout_range_iface
*range
= (struct layout_range_iface
*)h
;
2498 IUnknown_Release(range
->iface
);
2508 static void free_layout_ranges_list(struct dwrite_textlayout
*layout
)
2510 struct layout_range_header
*cur
, *cur2
;
2512 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->ranges
, struct layout_range_header
, entry
) {
2513 list_remove(&cur
->entry
);
2514 free_layout_range(cur
);
2517 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->underline_ranges
, struct layout_range_header
, entry
) {
2518 list_remove(&cur
->entry
);
2519 free_layout_range(cur
);
2522 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->strike_ranges
, struct layout_range_header
, entry
) {
2523 list_remove(&cur
->entry
);
2524 free_layout_range(cur
);
2527 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->effects
, struct layout_range_header
, entry
) {
2528 list_remove(&cur
->entry
);
2529 free_layout_range(cur
);
2532 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->spacing
, struct layout_range_header
, entry
) {
2533 list_remove(&cur
->entry
);
2534 free_layout_range(cur
);
2537 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->typographies
, struct layout_range_header
, entry
) {
2538 list_remove(&cur
->entry
);
2539 free_layout_range(cur
);
2543 static struct layout_range_header
*find_outer_range(struct list
*ranges
, const DWRITE_TEXT_RANGE
*range
)
2545 struct layout_range_header
*cur
;
2547 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
2549 if (cur
->range
.startPosition
> range
->startPosition
)
2552 if ((cur
->range
.startPosition
+ cur
->range
.length
< range
->startPosition
+ range
->length
) &&
2553 (range
->startPosition
< cur
->range
.startPosition
+ cur
->range
.length
))
2555 if (cur
->range
.startPosition
+ cur
->range
.length
>= range
->startPosition
+ range
->length
)
2562 static inline BOOL
set_layout_range_iface_attr(IUnknown
**dest
, IUnknown
*value
)
2564 if (*dest
== value
) return FALSE
;
2567 IUnknown_Release(*dest
);
2570 IUnknown_AddRef(*dest
);
2575 static BOOL
set_layout_range_attrval(struct layout_range_header
*h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2577 struct layout_range_spacing
*dest_spacing
= (struct layout_range_spacing
*)h
;
2578 struct layout_range_iface
*dest_iface
= (struct layout_range_iface
*)h
;
2579 struct layout_range_bool
*dest_bool
= (struct layout_range_bool
*)h
;
2580 struct layout_range
*dest
= (struct layout_range
*)h
;
2582 BOOL changed
= FALSE
;
2585 case LAYOUT_RANGE_ATTR_WEIGHT
:
2586 changed
= dest
->weight
!= value
->u
.weight
;
2587 dest
->weight
= value
->u
.weight
;
2589 case LAYOUT_RANGE_ATTR_STYLE
:
2590 changed
= dest
->style
!= value
->u
.style
;
2591 dest
->style
= value
->u
.style
;
2593 case LAYOUT_RANGE_ATTR_STRETCH
:
2594 changed
= dest
->stretch
!= value
->u
.stretch
;
2595 dest
->stretch
= value
->u
.stretch
;
2597 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2598 changed
= dest
->fontsize
!= value
->u
.fontsize
;
2599 dest
->fontsize
= value
->u
.fontsize
;
2601 case LAYOUT_RANGE_ATTR_INLINE
:
2602 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->object
, (IUnknown
*)value
->u
.object
);
2604 case LAYOUT_RANGE_ATTR_EFFECT
:
2605 changed
= set_layout_range_iface_attr(&dest_iface
->iface
, value
->u
.effect
);
2607 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2608 changed
= dest_bool
->value
!= value
->u
.underline
;
2609 dest_bool
->value
= value
->u
.underline
;
2611 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2612 changed
= dest_bool
->value
!= value
->u
.strikethrough
;
2613 dest_bool
->value
= value
->u
.strikethrough
;
2615 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2616 changed
= dest
->pair_kerning
!= value
->u
.pair_kerning
;
2617 dest
->pair_kerning
= value
->u
.pair_kerning
;
2619 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2620 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->collection
, (IUnknown
*)value
->u
.collection
);
2622 case LAYOUT_RANGE_ATTR_LOCALE
:
2623 changed
= !!wcsicmp(dest
->locale
, value
->u
.locale
);
2626 wcscpy(dest
->locale
, value
->u
.locale
);
2627 wcslwr(dest
->locale
);
2630 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2631 changed
= !!wcscmp(dest
->fontfamily
, value
->u
.fontfamily
);
2634 free(dest
->fontfamily
);
2635 dest
->fontfamily
= wcsdup(value
->u
.fontfamily
);
2638 case LAYOUT_RANGE_ATTR_SPACING
:
2639 changed
= dest_spacing
->leading
!= value
->u
.spacing
.leading
||
2640 dest_spacing
->trailing
!= value
->u
.spacing
.trailing
||
2641 dest_spacing
->min_advance
!= value
->u
.spacing
.min_advance
;
2642 dest_spacing
->leading
= value
->u
.spacing
.leading
;
2643 dest_spacing
->trailing
= value
->u
.spacing
.trailing
;
2644 dest_spacing
->min_advance
= value
->u
.spacing
.min_advance
;
2646 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2647 changed
= set_layout_range_iface_attr(&dest_iface
->iface
, (IUnknown
*)value
->u
.typography
);
2656 static inline BOOL
is_in_layout_range(const DWRITE_TEXT_RANGE
*outer
, const DWRITE_TEXT_RANGE
*inner
)
2658 return (inner
->startPosition
>= outer
->startPosition
) &&
2659 (inner
->startPosition
+ inner
->length
<= outer
->startPosition
+ outer
->length
);
2662 static inline HRESULT
return_range(const struct layout_range_header
*h
, DWRITE_TEXT_RANGE
*r
)
2664 if (r
) *r
= h
->range
;
2668 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2669 static HRESULT
set_layout_range_attr(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2671 struct layout_range_header
*cur
, *right
, *left
, *outer
;
2672 BOOL changed
= FALSE
;
2673 struct list
*ranges
;
2674 DWRITE_TEXT_RANGE r
;
2676 /* ignore zero length ranges */
2677 if (value
->range
.length
== 0)
2680 if (~0u - value
->range
.startPosition
< value
->range
.length
)
2681 return E_INVALIDARG
;
2683 /* select from ranges lists */
2686 case LAYOUT_RANGE_ATTR_WEIGHT
:
2687 case LAYOUT_RANGE_ATTR_STYLE
:
2688 case LAYOUT_RANGE_ATTR_STRETCH
:
2689 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2690 case LAYOUT_RANGE_ATTR_INLINE
:
2691 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2692 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2693 case LAYOUT_RANGE_ATTR_LOCALE
:
2694 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2695 ranges
= &layout
->ranges
;
2697 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2698 ranges
= &layout
->underline_ranges
;
2700 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2701 ranges
= &layout
->strike_ranges
;
2703 case LAYOUT_RANGE_ATTR_EFFECT
:
2704 ranges
= &layout
->effects
;
2706 case LAYOUT_RANGE_ATTR_SPACING
:
2707 ranges
= &layout
->spacing
;
2709 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2710 ranges
= &layout
->typographies
;
2713 FIXME("unknown attr kind %d\n", attr
);
2717 /* If new range is completely within existing range, split existing range in two */
2718 if ((outer
= find_outer_range(ranges
, &value
->range
))) {
2720 /* no need to add same range */
2721 if (is_same_layout_attrvalue(outer
, attr
, value
))
2724 /* for matching range bounds just replace data */
2725 if (is_same_text_range(&outer
->range
, &value
->range
)) {
2726 changed
= set_layout_range_attrval(outer
, attr
, value
);
2730 /* add new range to the left */
2731 if (value
->range
.startPosition
== outer
->range
.startPosition
) {
2732 left
= alloc_layout_range_from(outer
, &value
->range
);
2733 if (!left
) return E_OUTOFMEMORY
;
2735 changed
= set_layout_range_attrval(left
, attr
, value
);
2736 list_add_before(&outer
->entry
, &left
->entry
);
2737 outer
->range
.startPosition
+= value
->range
.length
;
2738 outer
->range
.length
-= value
->range
.length
;
2742 /* add new range to the right */
2743 if (value
->range
.startPosition
+ value
->range
.length
== outer
->range
.startPosition
+ outer
->range
.length
) {
2744 right
= alloc_layout_range_from(outer
, &value
->range
);
2745 if (!right
) return E_OUTOFMEMORY
;
2747 changed
= set_layout_range_attrval(right
, attr
, value
);
2748 list_add_after(&outer
->entry
, &right
->entry
);
2749 outer
->range
.length
-= value
->range
.length
;
2753 r
.startPosition
= value
->range
.startPosition
+ value
->range
.length
;
2754 r
.length
= outer
->range
.length
+ outer
->range
.startPosition
- r
.startPosition
;
2757 right
= alloc_layout_range_from(outer
, &r
);
2758 /* new range in the middle */
2759 cur
= alloc_layout_range_from(outer
, &value
->range
);
2760 if (!right
|| !cur
) {
2761 free_layout_range(right
);
2762 free_layout_range(cur
);
2763 return E_OUTOFMEMORY
;
2766 /* reuse container range as a left part */
2767 outer
->range
.length
= value
->range
.startPosition
- outer
->range
.startPosition
;
2770 set_layout_range_attrval(cur
, attr
, value
);
2772 list_add_after(&outer
->entry
, &cur
->entry
);
2773 list_add_after(&cur
->entry
, &right
->entry
);
2775 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2779 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2780 Update all of them. */
2781 left
= get_layout_range_header_by_pos(ranges
, value
->range
.startPosition
);
2782 if (left
->range
.startPosition
== value
->range
.startPosition
)
2783 changed
= set_layout_range_attrval(left
, attr
, value
);
2784 else /* need to split */ {
2785 r
.startPosition
= value
->range
.startPosition
;
2786 r
.length
= left
->range
.length
- value
->range
.startPosition
+ left
->range
.startPosition
;
2787 left
->range
.length
-= r
.length
;
2788 cur
= alloc_layout_range_from(left
, &r
);
2789 changed
= set_layout_range_attrval(cur
, attr
, value
);
2790 list_add_after(&left
->entry
, &cur
->entry
);
2792 cur
= LIST_ENTRY(list_next(ranges
, &left
->entry
), struct layout_range_header
, entry
);
2794 /* for all existing ranges covered by new one update value */
2795 while (cur
&& is_in_layout_range(&value
->range
, &cur
->range
)) {
2796 changed
|= set_layout_range_attrval(cur
, attr
, value
);
2797 cur
= LIST_ENTRY(list_next(ranges
, &cur
->entry
), struct layout_range_header
, entry
);
2800 /* it's possible rightmost range intersects */
2801 if (cur
&& (cur
->range
.startPosition
< value
->range
.startPosition
+ value
->range
.length
)) {
2802 r
.startPosition
= cur
->range
.startPosition
;
2803 r
.length
= value
->range
.startPosition
+ value
->range
.length
- cur
->range
.startPosition
;
2804 left
= alloc_layout_range_from(cur
, &r
);
2805 changed
|= set_layout_range_attrval(left
, attr
, value
);
2806 cur
->range
.startPosition
+= left
->range
.length
;
2807 cur
->range
.length
-= left
->range
.length
;
2808 list_add_before(&cur
->entry
, &left
->entry
);
2813 struct list
*next
, *i
;
2815 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2816 i
= list_head(ranges
);
2817 while ((next
= list_next(ranges
, i
))) {
2818 struct layout_range_header
*next_range
= LIST_ENTRY(next
, struct layout_range_header
, entry
);
2820 cur
= LIST_ENTRY(i
, struct layout_range_header
, entry
);
2821 if (is_same_layout_attributes(cur
, next_range
)) {
2822 /* remove similar range */
2823 cur
->range
.length
+= next_range
->range
.length
;
2825 free_layout_range(next_range
);
2828 i
= list_next(ranges
, i
);
2835 static inline const WCHAR
*get_string_attribute_ptr(const struct layout_range
*range
, enum layout_range_attr_kind kind
)
2840 case LAYOUT_RANGE_ATTR_LOCALE
:
2841 str
= range
->locale
;
2843 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2844 str
= range
->fontfamily
;
2853 static HRESULT
get_string_attribute_length(const struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
,
2854 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
2856 struct layout_range
*range
;
2859 range
= get_layout_range_by_pos(layout
, position
);
2865 str
= get_string_attribute_ptr(range
, kind
);
2866 *length
= wcslen(str
);
2867 return return_range(&range
->h
, r
);
2870 static HRESULT
get_string_attribute_value(const struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
,
2871 UINT32 position
, WCHAR
*ret
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2873 struct layout_range
*range
;
2877 return E_INVALIDARG
;
2880 range
= get_layout_range_by_pos(layout
, position
);
2882 return E_INVALIDARG
;
2884 str
= get_string_attribute_ptr(range
, kind
);
2885 if (length
< wcslen(str
) + 1)
2886 return E_NOT_SUFFICIENT_BUFFER
;
2889 return return_range(&range
->h
, r
);
2892 static HRESULT WINAPI
dwritetextlayout_QueryInterface(IDWriteTextLayout4
*iface
, REFIID riid
, void **obj
)
2894 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2896 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
2900 if (IsEqualIID(riid
, &IID_IDWriteTextLayout4
) ||
2901 IsEqualIID(riid
, &IID_IDWriteTextLayout3
) ||
2902 IsEqualIID(riid
, &IID_IDWriteTextLayout2
) ||
2903 IsEqualIID(riid
, &IID_IDWriteTextLayout1
) ||
2904 IsEqualIID(riid
, &IID_IDWriteTextLayout
) ||
2905 IsEqualIID(riid
, &IID_IUnknown
))
2909 else if (IsEqualIID(riid
, &IID_IDWriteTextFormat3
) ||
2910 IsEqualIID(riid
, &IID_IDWriteTextFormat2
) ||
2911 IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
2912 IsEqualIID(riid
, &IID_IDWriteTextFormat
))
2914 *obj
= &layout
->IDWriteTextFormat3_iface
;
2918 IDWriteTextLayout4_AddRef(iface
);
2922 WARN("%s not implemented.\n", debugstr_guid(riid
));
2924 return E_NOINTERFACE
;
2927 static ULONG WINAPI
dwritetextlayout_AddRef(IDWriteTextLayout4
*iface
)
2929 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2930 ULONG refcount
= InterlockedIncrement(&layout
->refcount
);
2932 TRACE("%p, refcount %lu.\n", iface
, refcount
);
2937 static ULONG WINAPI
dwritetextlayout_Release(IDWriteTextLayout4
*iface
)
2939 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2940 ULONG refcount
= InterlockedDecrement(&layout
->refcount
);
2942 TRACE("%p, refcount %lu.\n", iface
, refcount
);
2946 IDWriteFactory7_Release(layout
->factory
);
2947 if (layout
->system_collection
)
2948 IDWriteFontCollection_Release(layout
->system_collection
);
2949 free_layout_ranges_list(layout
);
2950 free_layout_eruns(layout
);
2951 free_layout_runs(layout
);
2952 release_format_data(&layout
->format
);
2953 free(layout
->nominal_breakpoints
);
2954 free(layout
->actual_breakpoints
);
2955 free(layout
->clustermetrics
);
2956 free(layout
->clusters
);
2957 free(layout
->lines
);
2965 static HRESULT WINAPI
dwritetextlayout_SetTextAlignment(IDWriteTextLayout4
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
2967 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2968 return IDWriteTextFormat3_SetTextAlignment(&layout
->IDWriteTextFormat3_iface
, alignment
);
2971 static HRESULT WINAPI
dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout4
*iface
,
2972 DWRITE_PARAGRAPH_ALIGNMENT alignment
)
2974 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2975 return IDWriteTextFormat3_SetParagraphAlignment(&layout
->IDWriteTextFormat3_iface
, alignment
);
2978 static HRESULT WINAPI
dwritetextlayout_SetWordWrapping(IDWriteTextLayout4
*iface
, DWRITE_WORD_WRAPPING wrapping
)
2980 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2981 return IDWriteTextFormat3_SetWordWrapping(&layout
->IDWriteTextFormat3_iface
, wrapping
);
2984 static HRESULT WINAPI
dwritetextlayout_SetReadingDirection(IDWriteTextLayout4
*iface
,
2985 DWRITE_READING_DIRECTION direction
)
2987 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2988 return IDWriteTextFormat3_SetReadingDirection(&layout
->IDWriteTextFormat3_iface
, direction
);
2991 static HRESULT WINAPI
dwritetextlayout_SetFlowDirection(IDWriteTextLayout4
*iface
, DWRITE_FLOW_DIRECTION direction
)
2993 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
2994 return IDWriteTextFormat3_SetFlowDirection(&layout
->IDWriteTextFormat3_iface
, direction
);
2997 static HRESULT WINAPI
dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout4
*iface
, FLOAT tabstop
)
2999 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3000 return IDWriteTextFormat3_SetIncrementalTabStop(&layout
->IDWriteTextFormat3_iface
, tabstop
);
3003 static HRESULT WINAPI
dwritetextlayout_SetTrimming(IDWriteTextLayout4
*iface
, DWRITE_TRIMMING
const *trimming
,
3004 IDWriteInlineObject
*trimming_sign
)
3006 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3007 return IDWriteTextFormat3_SetTrimming(&layout
->IDWriteTextFormat3_iface
, trimming
, trimming_sign
);
3010 static HRESULT WINAPI
dwritetextlayout_SetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
3011 FLOAT line_spacing
, FLOAT baseline
)
3013 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3014 return IDWriteTextFormat1_SetLineSpacing((IDWriteTextFormat1
*)&layout
->IDWriteTextFormat3_iface
, spacing
,
3015 line_spacing
, baseline
);
3018 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextlayout_GetTextAlignment(IDWriteTextLayout4
*iface
)
3020 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3021 return IDWriteTextFormat3_GetTextAlignment(&layout
->IDWriteTextFormat3_iface
);
3024 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout4
*iface
)
3026 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3027 return IDWriteTextFormat3_GetParagraphAlignment(&layout
->IDWriteTextFormat3_iface
);
3030 static DWRITE_WORD_WRAPPING WINAPI
dwritetextlayout_GetWordWrapping(IDWriteTextLayout4
*iface
)
3032 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3033 return IDWriteTextFormat3_GetWordWrapping(&layout
->IDWriteTextFormat3_iface
);
3036 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_GetReadingDirection(IDWriteTextLayout4
*iface
)
3038 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3039 return IDWriteTextFormat3_GetReadingDirection(&layout
->IDWriteTextFormat3_iface
);
3042 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextlayout_GetFlowDirection(IDWriteTextLayout4
*iface
)
3044 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3045 return IDWriteTextFormat3_GetFlowDirection(&layout
->IDWriteTextFormat3_iface
);
3048 static FLOAT WINAPI
dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout4
*iface
)
3050 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3051 return IDWriteTextFormat3_GetIncrementalTabStop(&layout
->IDWriteTextFormat3_iface
);
3054 static HRESULT WINAPI
dwritetextlayout_GetTrimming(IDWriteTextLayout4
*iface
, DWRITE_TRIMMING
*options
,
3055 IDWriteInlineObject
**trimming_sign
)
3057 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3058 return IDWriteTextFormat3_GetTrimming(&layout
->IDWriteTextFormat3_iface
, options
, trimming_sign
);
3061 static HRESULT WINAPI
dwritetextlayout_GetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
3062 FLOAT
*spacing
, FLOAT
*baseline
)
3064 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3065 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat
*)&layout
->IDWriteTextFormat3_iface
, method
,
3069 static HRESULT WINAPI
dwritetextlayout_GetFontCollection(IDWriteTextLayout4
*iface
, IDWriteFontCollection
**collection
)
3071 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3072 return IDWriteTextFormat3_GetFontCollection(&layout
->IDWriteTextFormat3_iface
, collection
);
3075 static UINT32 WINAPI
dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout4
*iface
)
3077 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3078 return IDWriteTextFormat3_GetFontFamilyNameLength(&layout
->IDWriteTextFormat3_iface
);
3081 static HRESULT WINAPI
dwritetextlayout_GetFontFamilyName(IDWriteTextLayout4
*iface
, WCHAR
*name
, UINT32 size
)
3083 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3084 return IDWriteTextFormat3_GetFontFamilyName(&layout
->IDWriteTextFormat3_iface
, name
, size
);
3087 static DWRITE_FONT_WEIGHT WINAPI
dwritetextlayout_GetFontWeight(IDWriteTextLayout4
*iface
)
3089 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3090 return IDWriteTextFormat3_GetFontWeight(&layout
->IDWriteTextFormat3_iface
);
3093 static DWRITE_FONT_STYLE WINAPI
dwritetextlayout_GetFontStyle(IDWriteTextLayout4
*iface
)
3095 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3096 return IDWriteTextFormat3_GetFontStyle(&layout
->IDWriteTextFormat3_iface
);
3099 static DWRITE_FONT_STRETCH WINAPI
dwritetextlayout_GetFontStretch(IDWriteTextLayout4
*iface
)
3101 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3102 return IDWriteTextFormat3_GetFontStretch(&layout
->IDWriteTextFormat3_iface
);
3105 static FLOAT WINAPI
dwritetextlayout_GetFontSize(IDWriteTextLayout4
*iface
)
3107 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3108 return IDWriteTextFormat3_GetFontSize(&layout
->IDWriteTextFormat3_iface
);
3111 static UINT32 WINAPI
dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout4
*iface
)
3113 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3114 return IDWriteTextFormat3_GetLocaleNameLength(&layout
->IDWriteTextFormat3_iface
);
3117 static HRESULT WINAPI
dwritetextlayout_GetLocaleName(IDWriteTextLayout4
*iface
, WCHAR
*name
, UINT32 size
)
3119 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3120 return IDWriteTextFormat3_GetLocaleName(&layout
->IDWriteTextFormat3_iface
, name
, size
);
3123 static HRESULT WINAPI
dwritetextlayout_SetMaxWidth(IDWriteTextLayout4
*iface
, FLOAT maxWidth
)
3125 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3128 TRACE("%p, %.8e.\n", iface
, maxWidth
);
3130 if (maxWidth
< 0.0f
)
3131 return E_INVALIDARG
;
3133 changed
= layout
->metrics
.layoutWidth
!= maxWidth
;
3134 layout
->metrics
.layoutWidth
= maxWidth
;
3137 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3141 static HRESULT WINAPI
dwritetextlayout_SetMaxHeight(IDWriteTextLayout4
*iface
, FLOAT maxHeight
)
3143 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3146 TRACE("%p, %.8e.\n", iface
, maxHeight
);
3148 if (maxHeight
< 0.0f
)
3149 return E_INVALIDARG
;
3151 changed
= layout
->metrics
.layoutHeight
!= maxHeight
;
3152 layout
->metrics
.layoutHeight
= maxHeight
;
3155 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3159 static HRESULT WINAPI
dwritetextlayout_SetFontCollection(IDWriteTextLayout4
*iface
, IDWriteFontCollection
*collection
,
3160 DWRITE_TEXT_RANGE range
)
3162 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3163 struct layout_range_attr_value value
;
3165 TRACE("%p, %p, %s.\n", iface
, collection
, debugstr_range(&range
));
3167 value
.range
= range
;
3168 value
.u
.collection
= collection
;
3169 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_FONTCOLL
, &value
);
3172 static HRESULT WINAPI
dwritetextlayout_SetFontFamilyName(IDWriteTextLayout4
*iface
, WCHAR
const *name
,
3173 DWRITE_TEXT_RANGE range
)
3175 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3176 struct layout_range_attr_value value
;
3178 TRACE("%p, %s, %s.\n", iface
, debugstr_w(name
), debugstr_range(&range
));
3181 return E_INVALIDARG
;
3183 value
.range
= range
;
3184 value
.u
.fontfamily
= name
;
3185 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_FONTFAMILY
, &value
);
3188 static HRESULT WINAPI
dwritetextlayout_SetFontWeight(IDWriteTextLayout4
*iface
, DWRITE_FONT_WEIGHT weight
,
3189 DWRITE_TEXT_RANGE range
)
3191 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3192 struct layout_range_attr_value value
;
3194 TRACE("%p, %d, %s.\n", iface
, weight
, debugstr_range(&range
));
3196 if ((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
3197 return E_INVALIDARG
;
3199 value
.range
= range
;
3200 value
.u
.weight
= weight
;
3201 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_WEIGHT
, &value
);
3204 static HRESULT WINAPI
dwritetextlayout_SetFontStyle(IDWriteTextLayout4
*iface
, DWRITE_FONT_STYLE style
,
3205 DWRITE_TEXT_RANGE range
)
3207 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3208 struct layout_range_attr_value value
;
3210 TRACE("%p, %d, %s.\n", iface
, style
, debugstr_range(&range
));
3212 if ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
)
3213 return E_INVALIDARG
;
3215 value
.range
= range
;
3216 value
.u
.style
= style
;
3217 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_STYLE
, &value
);
3220 static HRESULT WINAPI
dwritetextlayout_SetFontStretch(IDWriteTextLayout4
*iface
, DWRITE_FONT_STRETCH stretch
,
3221 DWRITE_TEXT_RANGE range
)
3223 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3224 struct layout_range_attr_value value
;
3226 TRACE("%p, %d, %s.\n", iface
, stretch
, debugstr_range(&range
));
3228 if (stretch
== DWRITE_FONT_STRETCH_UNDEFINED
|| (UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
3229 return E_INVALIDARG
;
3231 value
.range
= range
;
3232 value
.u
.stretch
= stretch
;
3233 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_STRETCH
, &value
);
3236 static HRESULT WINAPI
dwritetextlayout_SetFontSize(IDWriteTextLayout4
*iface
, FLOAT size
, DWRITE_TEXT_RANGE range
)
3238 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3239 struct layout_range_attr_value value
;
3241 TRACE("%p, %.8e, %s.\n", iface
, size
, debugstr_range(&range
));
3244 return E_INVALIDARG
;
3246 value
.range
= range
;
3247 value
.u
.fontsize
= size
;
3248 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_FONTSIZE
, &value
);
3251 static HRESULT WINAPI
dwritetextlayout_SetUnderline(IDWriteTextLayout4
*iface
, BOOL underline
, DWRITE_TEXT_RANGE range
)
3253 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3254 struct layout_range_attr_value value
;
3256 TRACE("%p, %d, %s.\n", iface
, underline
, debugstr_range(&range
));
3258 value
.range
= range
;
3259 value
.u
.underline
= underline
;
3260 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_UNDERLINE
, &value
);
3263 static HRESULT WINAPI
dwritetextlayout_SetStrikethrough(IDWriteTextLayout4
*iface
, BOOL strikethrough
,
3264 DWRITE_TEXT_RANGE range
)
3266 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3267 struct layout_range_attr_value value
;
3269 TRACE("%p, %d, %s.\n", iface
, strikethrough
, debugstr_range(&range
));
3271 value
.range
= range
;
3272 value
.u
.strikethrough
= strikethrough
;
3273 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_STRIKETHROUGH
, &value
);
3276 static HRESULT WINAPI
dwritetextlayout_SetDrawingEffect(IDWriteTextLayout4
*iface
, IUnknown
* effect
,
3277 DWRITE_TEXT_RANGE range
)
3279 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3280 struct layout_range_attr_value value
;
3282 TRACE("%p, %p, %s.\n", iface
, effect
, debugstr_range(&range
));
3284 value
.range
= range
;
3285 value
.u
.effect
= effect
;
3286 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_EFFECT
, &value
);
3289 static HRESULT WINAPI
dwritetextlayout_SetInlineObject(IDWriteTextLayout4
*iface
, IDWriteInlineObject
*object
,
3290 DWRITE_TEXT_RANGE range
)
3292 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3293 struct layout_range_attr_value value
;
3295 TRACE("%p, %p, %s.\n", iface
, object
, debugstr_range(&range
));
3297 value
.range
= range
;
3298 value
.u
.object
= object
;
3299 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_INLINE
, &value
);
3302 static HRESULT WINAPI
dwritetextlayout_SetTypography(IDWriteTextLayout4
*iface
, IDWriteTypography
*typography
,
3303 DWRITE_TEXT_RANGE range
)
3305 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3306 struct layout_range_attr_value value
;
3308 TRACE("%p, %p, %s.\n", iface
, typography
, debugstr_range(&range
));
3310 value
.range
= range
;
3311 value
.u
.typography
= typography
;
3312 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_TYPOGRAPHY
, &value
);
3315 static HRESULT WINAPI
dwritetextlayout_SetLocaleName(IDWriteTextLayout4
*iface
, WCHAR
const* locale
,
3316 DWRITE_TEXT_RANGE range
)
3318 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3319 struct layout_range_attr_value value
;
3321 TRACE("%p, %s, %s.\n", iface
, debugstr_w(locale
), debugstr_range(&range
));
3323 if (!locale
|| wcslen(locale
) > LOCALE_NAME_MAX_LENGTH
-1)
3324 return E_INVALIDARG
;
3326 value
.range
= range
;
3327 value
.u
.locale
= locale
;
3328 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_LOCALE
, &value
);
3331 static FLOAT WINAPI
dwritetextlayout_GetMaxWidth(IDWriteTextLayout4
*iface
)
3333 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3335 TRACE("%p.\n", iface
);
3337 return layout
->metrics
.layoutWidth
;
3340 static FLOAT WINAPI
dwritetextlayout_GetMaxHeight(IDWriteTextLayout4
*iface
)
3342 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3344 TRACE("%p.\n", iface
);
3346 return layout
->metrics
.layoutHeight
;
3349 static HRESULT WINAPI
dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout4
*iface
, UINT32 position
,
3350 IDWriteFontCollection
**collection
, DWRITE_TEXT_RANGE
*r
)
3352 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3353 struct layout_range
*range
;
3355 TRACE("%p, %u, %p, %p.\n", iface
, position
, collection
, r
);
3357 range
= get_layout_range_by_pos(layout
, position
);
3358 *collection
= range
->collection
;
3360 IDWriteFontCollection_AddRef(*collection
);
3362 return return_range(&range
->h
, r
);
3365 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout4
*iface
,
3366 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3368 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3370 TRACE("%p, %d, %p, %p.\n", iface
, position
, length
, r
);
3372 return get_string_attribute_length(layout
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, length
, r
);
3375 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout4
*iface
,
3376 UINT32 position
, WCHAR
*name
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3378 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3380 TRACE("%p, %u, %p, %u, %p.\n", iface
, position
, name
, length
, r
);
3382 return get_string_attribute_value(layout
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, name
, length
, r
);
3385 static HRESULT WINAPI
dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout4
*iface
,
3386 UINT32 position
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_TEXT_RANGE
*r
)
3388 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3389 struct layout_range
*range
;
3391 TRACE("%p, %u, %p, %p.\n", iface
, position
, weight
, r
);
3393 range
= get_layout_range_by_pos(layout
, position
);
3394 *weight
= range
->weight
;
3396 return return_range(&range
->h
, r
);
3399 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout4
*iface
,
3400 UINT32 position
, DWRITE_FONT_STYLE
*style
, DWRITE_TEXT_RANGE
*r
)
3402 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3403 struct layout_range
*range
;
3405 TRACE("%p, %u, %p, %p.\n", iface
, position
, style
, r
);
3407 range
= get_layout_range_by_pos(layout
, position
);
3408 *style
= range
->style
;
3409 return return_range(&range
->h
, r
);
3412 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout4
*iface
,
3413 UINT32 position
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_TEXT_RANGE
*r
)
3415 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3416 struct layout_range
*range
;
3418 TRACE("%p, %u, %p, %p.\n", iface
, position
, stretch
, r
);
3420 range
= get_layout_range_by_pos(layout
, position
);
3421 *stretch
= range
->stretch
;
3422 return return_range(&range
->h
, r
);
3425 static HRESULT WINAPI
dwritetextlayout_layout_GetFontSize(IDWriteTextLayout4
*iface
,
3426 UINT32 position
, FLOAT
*size
, DWRITE_TEXT_RANGE
*r
)
3428 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3429 struct layout_range
*range
;
3431 TRACE("%p, %u, %p, %p.\n", iface
, position
, size
, r
);
3433 range
= get_layout_range_by_pos(layout
, position
);
3434 *size
= range
->fontsize
;
3435 return return_range(&range
->h
, r
);
3438 static HRESULT WINAPI
dwritetextlayout_GetUnderline(IDWriteTextLayout4
*iface
,
3439 UINT32 position
, BOOL
*underline
, DWRITE_TEXT_RANGE
*r
)
3441 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3442 struct layout_range_bool
*range
;
3444 TRACE("%p, %u, %p, %p.\n", iface
, position
, underline
, r
);
3446 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&layout
->underline_ranges
, position
);
3447 *underline
= range
->value
;
3449 return return_range(&range
->h
, r
);
3452 static HRESULT WINAPI
dwritetextlayout_GetStrikethrough(IDWriteTextLayout4
*iface
,
3453 UINT32 position
, BOOL
*strikethrough
, DWRITE_TEXT_RANGE
*r
)
3455 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3456 struct layout_range_bool
*range
;
3458 TRACE("%p, %u, %p, %p.\n", iface
, position
, strikethrough
, r
);
3460 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&layout
->strike_ranges
, position
);
3461 *strikethrough
= range
->value
;
3463 return return_range(&range
->h
, r
);
3466 static HRESULT WINAPI
dwritetextlayout_GetDrawingEffect(IDWriteTextLayout4
*iface
,
3467 UINT32 position
, IUnknown
**effect
, DWRITE_TEXT_RANGE
*r
)
3469 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3470 struct layout_range_iface
*range
;
3472 TRACE("%p, %u, %p, %p.\n", iface
, position
, effect
, r
);
3474 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->effects
, position
);
3475 *effect
= range
->iface
;
3477 IUnknown_AddRef(*effect
);
3479 return return_range(&range
->h
, r
);
3482 static HRESULT WINAPI
dwritetextlayout_GetInlineObject(IDWriteTextLayout4
*iface
,
3483 UINT32 position
, IDWriteInlineObject
**object
, DWRITE_TEXT_RANGE
*r
)
3485 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3486 struct layout_range
*range
;
3488 TRACE("%p, %u, %p, %p.\n", iface
, position
, object
, r
);
3490 range
= get_layout_range_by_pos(layout
, position
);
3491 *object
= range
->object
;
3493 IDWriteInlineObject_AddRef(*object
);
3495 return return_range(&range
->h
, r
);
3498 static HRESULT WINAPI
dwritetextlayout_GetTypography(IDWriteTextLayout4
*iface
,
3499 UINT32 position
, IDWriteTypography
** typography
, DWRITE_TEXT_RANGE
*r
)
3501 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3502 struct layout_range_iface
*range
;
3504 TRACE("%p, %u, %p, %p.\n", iface
, position
, typography
, r
);
3506 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->typographies
, position
);
3507 *typography
= (IDWriteTypography
*)range
->iface
;
3509 IDWriteTypography_AddRef(*typography
);
3511 return return_range(&range
->h
, r
);
3514 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout4
*iface
,
3515 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3517 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3519 TRACE("%p, %u, %p, %p.\n", iface
, position
, length
, r
);
3521 return get_string_attribute_length(layout
, LAYOUT_RANGE_ATTR_LOCALE
, position
, length
, r
);
3524 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout4
*iface
,
3525 UINT32 position
, WCHAR
*locale
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3527 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3529 TRACE("%p, %u, %p, %u, %p.\n", iface
, position
, locale
, length
, r
);
3531 return get_string_attribute_value(layout
, LAYOUT_RANGE_ATTR_LOCALE
, position
, locale
, length
, r
);
3534 static inline FLOAT
renderer_apply_snapping(FLOAT coord
, BOOL skiptransform
, FLOAT ppdip
, FLOAT det
,
3535 const DWRITE_MATRIX
*m
)
3537 D2D1_POINT_2F vec
, vec2
;
3539 if (!skiptransform
) {
3540 /* apply transform */
3542 vec
.y
= coord
* ppdip
;
3544 vec2
.x
= m
->m11
* vec
.x
+ m
->m21
* vec
.y
+ m
->dx
;
3545 vec2
.y
= m
->m12
* vec
.x
+ m
->m22
* vec
.y
+ m
->dy
;
3548 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
3549 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
3551 /* apply inverted transform, we don't care about X component at this point */
3552 vec
.y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
3556 vec
.y
= floorf(coord
* ppdip
+ 0.5f
) / ppdip
;
3561 static HRESULT WINAPI
dwritetextlayout_Draw(IDWriteTextLayout4
*iface
,
3562 void *context
, IDWriteTextRenderer
* renderer
, FLOAT origin_x
, FLOAT origin_y
)
3564 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3565 BOOL disabled
= FALSE
, skiptransform
= FALSE
;
3566 struct layout_effective_inline
*inlineobject
;
3567 struct layout_effective_run
*run
;
3568 struct layout_strikethrough
*s
;
3569 struct layout_underline
*u
;
3570 FLOAT det
= 0.0f
, ppdip
= 0.0f
;
3571 DWRITE_MATRIX m
= { 0 };
3574 TRACE("%p, %p, %p, %.8e, %.8e.\n", iface
, context
, renderer
, origin_x
, origin_y
);
3576 hr
= layout_compute_effective_runs(layout
);
3580 hr
= IDWriteTextRenderer_IsPixelSnappingDisabled(renderer
, context
, &disabled
);
3585 hr
= IDWriteTextRenderer_GetPixelsPerDip(renderer
, context
, &ppdip
);
3589 hr
= IDWriteTextRenderer_GetCurrentTransform(renderer
, context
, &m
);
3593 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3594 if (ppdip
<= 0.0f
||
3595 (m
.m11
* m
.m22
!= 0.0f
&& (m
.m12
!= 0.0f
|| m
.m21
!= 0.0f
)) ||
3596 (m
.m12
* m
.m21
!= 0.0f
&& (m
.m11
!= 0.0f
|| m
.m22
!= 0.0f
)))
3599 skiptransform
= should_skip_transform(&m
, &det
);
3602 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3603 /* 1. Regular runs */
3604 LIST_FOR_EACH_ENTRY(run
, &layout
->eruns
, struct layout_effective_run
, entry
)
3606 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3607 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3608 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
3609 DWRITE_GLYPH_RUN glyph_run
;
3611 /* Everything but cluster map will be reused from nominal run, as we only need
3612 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3613 it can't be reused because it has to start with 0 index for each reported run. */
3614 glyph_run
= regular
->run
;
3615 glyph_run
.glyphCount
= run
->glyphcount
;
3617 /* fixup glyph data arrays */
3618 glyph_run
.glyphIndices
+= start_glyph
;
3619 glyph_run
.glyphAdvances
+= start_glyph
;
3620 glyph_run
.glyphOffsets
+= start_glyph
;
3623 descr
= regular
->descr
;
3624 descr
.stringLength
= run
->length
;
3625 descr
.string
+= run
->start
;
3626 descr
.clusterMap
= run
->clustermap
;
3627 descr
.textPosition
+= run
->start
;
3629 /* return value is ignored */
3630 IDWriteTextRenderer_DrawGlyphRun(renderer
,
3632 run
->origin
.x
+ run
->align_dx
+ origin_x
,
3633 SNAP_COORD(run
->origin
.y
+ origin_y
),
3634 layout
->measuringmode
,
3640 /* 2. Inline objects */
3641 LIST_FOR_EACH_ENTRY(inlineobject
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
)
3643 IDWriteTextRenderer_DrawInlineObject(renderer
,
3645 inlineobject
->origin
.x
+ inlineobject
->align_dx
+ origin_x
,
3646 SNAP_COORD(inlineobject
->origin
.y
+ origin_y
),
3647 inlineobject
->object
,
3648 inlineobject
->is_sideways
,
3649 inlineobject
->is_rtl
,
3650 inlineobject
->effect
);
3654 LIST_FOR_EACH_ENTRY(u
, &layout
->underlines
, struct layout_underline
, entry
)
3656 IDWriteTextRenderer_DrawUnderline(renderer
,
3658 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3659 (is_run_rtl(u
->run
) ? u
->run
->origin
.x
- u
->run
->width
: u
->run
->origin
.x
) + u
->run
->align_dx
+ origin_x
,
3660 SNAP_COORD(u
->run
->origin
.y
+ origin_y
),
3665 /* 4. Strikethrough */
3666 LIST_FOR_EACH_ENTRY(s
, &layout
->strikethrough
, struct layout_strikethrough
, entry
)
3668 IDWriteTextRenderer_DrawStrikethrough(renderer
,
3670 s
->run
->origin
.x
+ s
->run
->align_dx
+ origin_x
,
3671 SNAP_COORD(s
->run
->origin
.y
+ origin_y
),
3680 static HRESULT WINAPI
dwritetextlayout_GetLineMetrics(IDWriteTextLayout4
*iface
,
3681 DWRITE_LINE_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3683 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3684 unsigned int line_count
;
3688 TRACE("%p, %p, %u, %p.\n", iface
, metrics
, max_count
, count
);
3690 if (FAILED(hr
= layout_compute_effective_runs(layout
)))
3695 line_count
= min(max_count
, layout
->metrics
.lineCount
);
3696 for (i
= 0; i
< line_count
; ++i
)
3697 memcpy(&metrics
[i
], &layout
->lines
[i
].metrics
, sizeof(*metrics
));
3700 *count
= layout
->metrics
.lineCount
;
3701 return max_count
>= layout
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3704 static HRESULT
layout_update_metrics(struct dwrite_textlayout
*layout
)
3706 return layout_compute_effective_runs(layout
);
3709 static HRESULT WINAPI
dwritetextlayout_GetMetrics(IDWriteTextLayout4
*iface
, DWRITE_TEXT_METRICS
*metrics
)
3711 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3714 TRACE("%p, %p.\n", iface
, metrics
);
3716 hr
= layout_update_metrics(layout
);
3718 memcpy(metrics
, &layout
->metrics
, sizeof(*metrics
));
3723 static void d2d_rect_offset(D2D1_RECT_F
*rect
, FLOAT x
, FLOAT y
)
3731 static BOOL
d2d_rect_is_empty(const D2D1_RECT_F
*rect
)
3733 return ((rect
->left
>= rect
->right
) || (rect
->top
>= rect
->bottom
));
3736 static void d2d_rect_union(D2D1_RECT_F
*dst
, const D2D1_RECT_F
*src
)
3738 if (d2d_rect_is_empty(dst
)) {
3739 if (d2d_rect_is_empty(src
)) {
3740 dst
->left
= dst
->right
= dst
->top
= dst
->bottom
= 0.0f
;
3747 if (!d2d_rect_is_empty(src
)) {
3748 dst
->left
= min(dst
->left
, src
->left
);
3749 dst
->right
= max(dst
->right
, src
->right
);
3750 dst
->top
= min(dst
->top
, src
->top
);
3751 dst
->bottom
= max(dst
->bottom
, src
->bottom
);
3756 static void layout_get_erun_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_run
*run
, D2D1_RECT_F
*bbox
)
3758 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3759 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3760 D2D1_POINT_2F baseline_origin
= { 0 }, *origins
;
3761 DWRITE_GLYPH_RUN glyph_run
;
3765 if (run
->bbox
.top
== run
->bbox
.bottom
)
3767 struct dwrite_glyphbitmap glyph_bitmap
;
3770 glyph_run
= regular
->run
;
3771 glyph_run
.glyphCount
= run
->glyphcount
;
3772 glyph_run
.glyphIndices
= ®ular
->run
.glyphIndices
[start_glyph
];
3773 glyph_run
.glyphAdvances
= ®ular
->run
.glyphAdvances
[start_glyph
];
3774 glyph_run
.glyphOffsets
= ®ular
->run
.glyphOffsets
[start_glyph
];
3776 memset(&glyph_bitmap
, 0, sizeof(glyph_bitmap
));
3777 glyph_bitmap
.simulations
= IDWriteFontFace_GetSimulations(glyph_run
.fontFace
);
3778 glyph_bitmap
.emsize
= glyph_run
.fontEmSize
;
3780 bbox
= &glyph_bitmap
.bbox
;
3782 if (!(origins
= calloc(glyph_run
.glyphCount
, sizeof(*origins
))))
3785 if (FAILED(hr
= compute_glyph_origins(&glyph_run
, layout
->measuringmode
, baseline_origin
, &layout
->transform
, origins
)))
3787 WARN("Failed to compute glyph origins, hr %#lx.\n", hr
);
3792 for (i
= 0; i
< glyph_run
.glyphCount
; ++i
)
3794 D2D1_RECT_F glyph_bbox
;
3796 glyph_bitmap
.glyph
= glyph_run
.glyphIndices
[i
];
3797 dwrite_fontface_get_glyph_bbox(glyph_run
.fontFace
, &glyph_bitmap
);
3799 glyph_bbox
.left
= bbox
->left
;
3800 glyph_bbox
.top
= bbox
->top
;
3801 glyph_bbox
.right
= bbox
->right
;
3802 glyph_bbox
.bottom
= bbox
->bottom
;
3804 d2d_rect_offset(&glyph_bbox
, origins
[i
].x
, origins
[i
].y
);
3805 d2d_rect_union(&run
->bbox
, &glyph_bbox
);
3812 d2d_rect_offset(bbox
, run
->origin
.x
+ run
->align_dx
, run
->origin
.y
);
3815 static void layout_get_inlineobj_bbox(const struct layout_effective_inline
*run
, D2D1_RECT_F
*bbox
)
3817 DWRITE_OVERHANG_METRICS overhang_metrics
= { 0 };
3818 DWRITE_INLINE_OBJECT_METRICS metrics
= { 0 };
3821 if (FAILED(hr
= IDWriteInlineObject_GetMetrics(run
->object
, &metrics
))) {
3822 WARN("Failed to get inline object metrics, hr %#lx.\n", hr
);
3823 memset(bbox
, 0, sizeof(*bbox
));
3827 bbox
->left
= run
->origin
.x
+ run
->align_dx
;
3828 bbox
->right
= bbox
->left
+ metrics
.width
;
3829 bbox
->top
= run
->origin
.y
;
3830 bbox
->bottom
= bbox
->top
+ metrics
.height
;
3832 IDWriteInlineObject_GetOverhangMetrics(run
->object
, &overhang_metrics
);
3834 bbox
->left
-= overhang_metrics
.left
;
3835 bbox
->right
+= overhang_metrics
.right
;
3836 bbox
->top
-= overhang_metrics
.top
;
3837 bbox
->bottom
+= overhang_metrics
.bottom
;
3840 static HRESULT WINAPI
dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout4
*iface
,
3841 DWRITE_OVERHANG_METRICS
*overhangs
)
3843 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3844 struct layout_effective_inline
*inline_run
;
3845 struct layout_effective_run
*run
;
3846 D2D1_RECT_F bbox
= { 0 };
3849 TRACE("%p, %p.\n", iface
, overhangs
);
3851 memset(overhangs
, 0, sizeof(*overhangs
));
3853 if (!(layout
->recompute
& RECOMPUTE_OVERHANGS
))
3855 *overhangs
= layout
->overhangs
;
3859 hr
= layout_compute_effective_runs(layout
);
3863 LIST_FOR_EACH_ENTRY(run
, &layout
->eruns
, struct layout_effective_run
, entry
)
3865 D2D1_RECT_F run_bbox
;
3867 layout_get_erun_bbox(layout
, run
, &run_bbox
);
3868 d2d_rect_union(&bbox
, &run_bbox
);
3871 LIST_FOR_EACH_ENTRY(inline_run
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
)
3873 D2D1_RECT_F object_bbox
;
3875 layout_get_inlineobj_bbox(inline_run
, &object_bbox
);
3876 d2d_rect_union(&bbox
, &object_bbox
);
3879 /* Deltas from layout box. */
3880 layout
->overhangs
.left
= -bbox
.left
;
3881 layout
->overhangs
.top
= -bbox
.top
;
3882 layout
->overhangs
.right
= bbox
.right
- layout
->metrics
.layoutWidth
;
3883 layout
->overhangs
.bottom
= bbox
.bottom
- layout
->metrics
.layoutHeight
;
3884 layout
->recompute
&= ~RECOMPUTE_OVERHANGS
;
3886 *overhangs
= layout
->overhangs
;
3891 static HRESULT WINAPI
dwritetextlayout_GetClusterMetrics(IDWriteTextLayout4
*iface
,
3892 DWRITE_CLUSTER_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3894 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3897 TRACE("%p, %p, %u, %p.\n", iface
, metrics
, max_count
, count
);
3899 hr
= layout_compute(layout
);
3904 memcpy(metrics
, layout
->clustermetrics
, sizeof(DWRITE_CLUSTER_METRICS
) * min(max_count
, layout
->cluster_count
));
3906 *count
= layout
->cluster_count
;
3907 return max_count
>= layout
->cluster_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3910 static HRESULT WINAPI
dwritetextlayout_DetermineMinWidth(IDWriteTextLayout4
*iface
, FLOAT
* min_width
)
3912 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3917 TRACE("%p, %p.\n", iface
, min_width
);
3920 return E_INVALIDARG
;
3922 if (!(layout
->recompute
& RECOMPUTE_MINIMAL_WIDTH
))
3926 hr
= layout_compute(layout
);
3930 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3931 preceding breaking point do not contribute to word width. */
3932 for (start
= 0; start
< layout
->cluster_count
;)
3934 UINT32 end
= start
, j
, next
;
3936 /* Last cluster always could be wrapped after. */
3937 while (!layout
->clustermetrics
[end
].canWrapLineAfter
)
3939 /* make is so current cluster range that we can wrap after is [start,end) */
3944 /* Ignore trailing whitespace clusters, in case of single space range will
3945 be reduced to empty range, or [start,start+1). */
3946 while (end
> start
&& layout
->clustermetrics
[end
-1].isWhitespace
)
3949 /* check if cluster range exceeds last minimal width */
3951 for (j
= start
; j
< end
; j
++)
3952 width
+= layout
->clustermetrics
[j
].width
;
3956 if (width
> layout
->minwidth
)
3957 layout
->minwidth
= width
;
3959 layout
->recompute
&= ~RECOMPUTE_MINIMAL_WIDTH
;
3962 *min_width
= layout
->minwidth
;
3966 static HRESULT WINAPI
dwritetextlayout_HitTestPoint(IDWriteTextLayout4
*iface
,
3967 FLOAT pointX
, FLOAT pointY
, BOOL
* is_trailinghit
, BOOL
* is_inside
, DWRITE_HIT_TEST_METRICS
*metrics
)
3969 FIXME("%p, %.8e, %.8e, %p, %p, %p): stub\n", iface
, pointX
, pointY
, is_trailinghit
, is_inside
, metrics
);
3974 static HRESULT WINAPI
dwritetextlayout_HitTestTextPosition(IDWriteTextLayout4
*iface
,
3975 UINT32 textPosition
, BOOL is_trailinghit
, FLOAT
*pointX
, FLOAT
*pointY
, DWRITE_HIT_TEST_METRICS
*metrics
)
3977 FIXME("%p, %u, %d, %p, %p, %p): stub\n", iface
, textPosition
, is_trailinghit
, pointX
, pointY
, metrics
);
3982 static HRESULT WINAPI
dwritetextlayout_HitTestTextRange(IDWriteTextLayout4
*iface
,
3983 UINT32 textPosition
, UINT32 textLength
, FLOAT originX
, FLOAT originY
,
3984 DWRITE_HIT_TEST_METRICS
*metrics
, UINT32 max_metricscount
, UINT32
* actual_metricscount
)
3986 FIXME("%p, %u, %u, %f, %f, %p, %u, %p): stub\n", iface
, textPosition
, textLength
, originX
, originY
, metrics
,
3987 max_metricscount
, actual_metricscount
);
3992 static HRESULT WINAPI
dwritetextlayout1_SetPairKerning(IDWriteTextLayout4
*iface
, BOOL is_pairkerning_enabled
,
3993 DWRITE_TEXT_RANGE range
)
3995 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3996 struct layout_range_attr_value value
;
3998 TRACE("%p, %d, %s.\n", iface
, is_pairkerning_enabled
, debugstr_range(&range
));
4000 value
.range
= range
;
4001 value
.u
.pair_kerning
= !!is_pairkerning_enabled
;
4002 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_PAIR_KERNING
, &value
);
4005 static HRESULT WINAPI
dwritetextlayout1_GetPairKerning(IDWriteTextLayout4
*iface
, UINT32 position
,
4006 BOOL
*is_pairkerning_enabled
, DWRITE_TEXT_RANGE
*r
)
4008 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4009 struct layout_range
*range
;
4011 TRACE("%p, %u, %p, %p.\n", iface
, position
, is_pairkerning_enabled
, r
);
4013 range
= get_layout_range_by_pos(layout
, position
);
4014 *is_pairkerning_enabled
= range
->pair_kerning
;
4016 return return_range(&range
->h
, r
);
4019 static HRESULT WINAPI
dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout4
*iface
, FLOAT leading
, FLOAT trailing
,
4020 FLOAT min_advance
, DWRITE_TEXT_RANGE range
)
4022 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4023 struct layout_range_attr_value value
;
4025 TRACE("%p, %.8e, %.8e, %.8e, %s.\n", iface
, leading
, trailing
, min_advance
, debugstr_range(&range
));
4027 if (min_advance
< 0.0f
)
4028 return E_INVALIDARG
;
4030 value
.range
= range
;
4031 value
.u
.spacing
.leading
= leading
;
4032 value
.u
.spacing
.trailing
= trailing
;
4033 value
.u
.spacing
.min_advance
= min_advance
;
4034 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_SPACING
, &value
);
4037 static HRESULT WINAPI
dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout4
*iface
, UINT32 position
, FLOAT
*leading
,
4038 FLOAT
*trailing
, FLOAT
*min_advance
, DWRITE_TEXT_RANGE
*r
)
4040 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4041 struct layout_range_spacing
*range
;
4043 TRACE("%p, %u, %p, %p, %p, %p.\n", iface
, position
, leading
, trailing
, min_advance
, r
);
4045 range
= (struct layout_range_spacing
*)get_layout_range_header_by_pos(&layout
->spacing
, position
);
4046 *leading
= range
->leading
;
4047 *trailing
= range
->trailing
;
4048 *min_advance
= range
->min_advance
;
4050 return return_range(&range
->h
, r
);
4053 static HRESULT WINAPI
dwritetextlayout2_GetMetrics(IDWriteTextLayout4
*iface
, DWRITE_TEXT_METRICS1
*metrics
)
4055 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4058 TRACE("%p, %p.\n", iface
, metrics
);
4060 if (SUCCEEDED(hr
= layout_update_metrics(layout
)))
4061 *metrics
= layout
->metrics
;
4066 static HRESULT
layout_set_vertical_orientation(struct dwrite_textlayout
*layout
,
4067 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4072 if (FAILED(hr
= format_set_vertical_orientation(&layout
->format
, orientation
, &changed
)))
4076 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4081 static HRESULT WINAPI
dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout4
*iface
,
4082 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4084 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4086 TRACE("%p, %d.\n", iface
, orientation
);
4088 return layout_set_vertical_orientation(layout
, orientation
);
4091 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout4
*iface
)
4093 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4095 TRACE("%p.\n", iface
);
4097 return layout
->format
.vertical_orientation
;
4100 static HRESULT WINAPI
dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout4
*iface
, BOOL lastline_wrapping_enabled
)
4102 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4104 TRACE("%p, %d.\n", iface
, lastline_wrapping_enabled
);
4106 return IDWriteTextFormat3_SetLastLineWrapping(&layout
->IDWriteTextFormat3_iface
, lastline_wrapping_enabled
);
4109 static BOOL WINAPI
dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout4
*iface
)
4111 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4113 TRACE("%p.\n", iface
);
4115 return IDWriteTextFormat3_GetLastLineWrapping(&layout
->IDWriteTextFormat3_iface
);
4118 static HRESULT WINAPI
dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout4
*iface
,
4119 DWRITE_OPTICAL_ALIGNMENT alignment
)
4121 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4123 TRACE("%p, %d.\n", iface
, alignment
);
4125 return IDWriteTextFormat3_SetOpticalAlignment(&layout
->IDWriteTextFormat3_iface
, alignment
);
4128 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout4
*iface
)
4130 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4132 TRACE("%p.\n", iface
);
4134 return IDWriteTextFormat3_GetOpticalAlignment(&layout
->IDWriteTextFormat3_iface
);
4137 static HRESULT WINAPI
dwritetextlayout2_SetFontFallback(IDWriteTextLayout4
*iface
, IDWriteFontFallback
*fallback
)
4139 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4141 TRACE("%p, %p.\n", iface
, fallback
);
4143 return format_set_fontfallback(&layout
->format
, fallback
);
4146 static HRESULT WINAPI
dwritetextlayout2_GetFontFallback(IDWriteTextLayout4
*iface
, IDWriteFontFallback
**fallback
)
4148 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4150 TRACE("%p, %p.\n", iface
, fallback
);
4152 return format_get_fontfallback(&layout
->format
, fallback
);
4155 static HRESULT WINAPI
dwritetextlayout3_InvalidateLayout(IDWriteTextLayout4
*iface
)
4157 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4159 TRACE("%p.\n", iface
);
4161 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4165 static HRESULT WINAPI
dwritetextlayout3_SetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING
const *spacing
)
4167 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4171 TRACE("%p, %p.\n", iface
, spacing
);
4173 hr
= format_set_linespacing(&layout
->format
, spacing
, &changed
);
4179 if (!(layout
->recompute
& RECOMPUTE_LINES
))
4183 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++)
4184 layout_apply_line_spacing(layout
, line
);
4186 layout_set_line_positions(layout
);
4189 layout
->recompute
|= RECOMPUTE_OVERHANGS
;
4195 static HRESULT WINAPI
dwritetextlayout3_GetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING
*spacing
)
4197 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4199 TRACE("%p, %p.\n", iface
, spacing
);
4201 *spacing
= layout
->format
.spacing
;
4205 static HRESULT WINAPI
dwritetextlayout3_GetLineMetrics(IDWriteTextLayout4
*iface
, DWRITE_LINE_METRICS1
*metrics
,
4206 UINT32 max_count
, UINT32
*count
)
4208 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4209 unsigned int line_count
;
4213 TRACE("%p, %p, %u, %p.\n", iface
, metrics
, max_count
, count
);
4215 if (FAILED(hr
= layout_compute_effective_runs(layout
)))
4220 line_count
= min(max_count
, layout
->metrics
.lineCount
);
4221 for (i
= 0; i
< line_count
; ++i
)
4222 metrics
[i
] = layout
->lines
[i
].metrics
;
4225 *count
= layout
->metrics
.lineCount
;
4226 return max_count
>= layout
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
4229 static HRESULT WINAPI
dwritetextlayout4_SetFontAxisValues(IDWriteTextLayout4
*iface
,
4230 DWRITE_FONT_AXIS_VALUE
const *axis_values
, UINT32 num_values
, DWRITE_TEXT_RANGE range
)
4232 FIXME("%p, %p, %u, %s.\n", iface
, axis_values
, num_values
, debugstr_range(&range
));
4237 static UINT32 WINAPI
dwritetextlayout4_GetFontAxisValueCount(IDWriteTextLayout4
*iface
, UINT32 pos
)
4239 FIXME("%p, %u.\n", iface
, pos
);
4244 static HRESULT WINAPI
dwritetextlayout4_GetFontAxisValues(IDWriteTextLayout4
*iface
, UINT32 pos
,
4245 DWRITE_FONT_AXIS_VALUE
*values
, UINT32 num_values
, DWRITE_TEXT_RANGE
*range
)
4247 FIXME("%p, %u, %p, %u, %p.\n", iface
, pos
, values
, num_values
, range
);
4252 static DWRITE_AUTOMATIC_FONT_AXES WINAPI
dwritetextlayout4_GetAutomaticFontAxes(IDWriteTextLayout4
*iface
)
4254 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4256 TRACE("%p.\n", iface
);
4258 return layout
->format
.automatic_axes
;
4261 static HRESULT WINAPI
dwritetextlayout4_SetAutomaticFontAxes(IDWriteTextLayout4
*iface
,
4262 DWRITE_AUTOMATIC_FONT_AXES axes
)
4264 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4266 TRACE("%p, %d.\n", iface
, axes
);
4268 if ((unsigned int)axes
> DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE
)
4269 return E_INVALIDARG
;
4271 layout
->format
.automatic_axes
= axes
;
4275 static const IDWriteTextLayout4Vtbl dwritetextlayoutvtbl
=
4277 dwritetextlayout_QueryInterface
,
4278 dwritetextlayout_AddRef
,
4279 dwritetextlayout_Release
,
4280 dwritetextlayout_SetTextAlignment
,
4281 dwritetextlayout_SetParagraphAlignment
,
4282 dwritetextlayout_SetWordWrapping
,
4283 dwritetextlayout_SetReadingDirection
,
4284 dwritetextlayout_SetFlowDirection
,
4285 dwritetextlayout_SetIncrementalTabStop
,
4286 dwritetextlayout_SetTrimming
,
4287 dwritetextlayout_SetLineSpacing
,
4288 dwritetextlayout_GetTextAlignment
,
4289 dwritetextlayout_GetParagraphAlignment
,
4290 dwritetextlayout_GetWordWrapping
,
4291 dwritetextlayout_GetReadingDirection
,
4292 dwritetextlayout_GetFlowDirection
,
4293 dwritetextlayout_GetIncrementalTabStop
,
4294 dwritetextlayout_GetTrimming
,
4295 dwritetextlayout_GetLineSpacing
,
4296 dwritetextlayout_GetFontCollection
,
4297 dwritetextlayout_GetFontFamilyNameLength
,
4298 dwritetextlayout_GetFontFamilyName
,
4299 dwritetextlayout_GetFontWeight
,
4300 dwritetextlayout_GetFontStyle
,
4301 dwritetextlayout_GetFontStretch
,
4302 dwritetextlayout_GetFontSize
,
4303 dwritetextlayout_GetLocaleNameLength
,
4304 dwritetextlayout_GetLocaleName
,
4305 dwritetextlayout_SetMaxWidth
,
4306 dwritetextlayout_SetMaxHeight
,
4307 dwritetextlayout_SetFontCollection
,
4308 dwritetextlayout_SetFontFamilyName
,
4309 dwritetextlayout_SetFontWeight
,
4310 dwritetextlayout_SetFontStyle
,
4311 dwritetextlayout_SetFontStretch
,
4312 dwritetextlayout_SetFontSize
,
4313 dwritetextlayout_SetUnderline
,
4314 dwritetextlayout_SetStrikethrough
,
4315 dwritetextlayout_SetDrawingEffect
,
4316 dwritetextlayout_SetInlineObject
,
4317 dwritetextlayout_SetTypography
,
4318 dwritetextlayout_SetLocaleName
,
4319 dwritetextlayout_GetMaxWidth
,
4320 dwritetextlayout_GetMaxHeight
,
4321 dwritetextlayout_layout_GetFontCollection
,
4322 dwritetextlayout_layout_GetFontFamilyNameLength
,
4323 dwritetextlayout_layout_GetFontFamilyName
,
4324 dwritetextlayout_layout_GetFontWeight
,
4325 dwritetextlayout_layout_GetFontStyle
,
4326 dwritetextlayout_layout_GetFontStretch
,
4327 dwritetextlayout_layout_GetFontSize
,
4328 dwritetextlayout_GetUnderline
,
4329 dwritetextlayout_GetStrikethrough
,
4330 dwritetextlayout_GetDrawingEffect
,
4331 dwritetextlayout_GetInlineObject
,
4332 dwritetextlayout_GetTypography
,
4333 dwritetextlayout_layout_GetLocaleNameLength
,
4334 dwritetextlayout_layout_GetLocaleName
,
4335 dwritetextlayout_Draw
,
4336 dwritetextlayout_GetLineMetrics
,
4337 dwritetextlayout_GetMetrics
,
4338 dwritetextlayout_GetOverhangMetrics
,
4339 dwritetextlayout_GetClusterMetrics
,
4340 dwritetextlayout_DetermineMinWidth
,
4341 dwritetextlayout_HitTestPoint
,
4342 dwritetextlayout_HitTestTextPosition
,
4343 dwritetextlayout_HitTestTextRange
,
4344 dwritetextlayout1_SetPairKerning
,
4345 dwritetextlayout1_GetPairKerning
,
4346 dwritetextlayout1_SetCharacterSpacing
,
4347 dwritetextlayout1_GetCharacterSpacing
,
4348 dwritetextlayout2_GetMetrics
,
4349 dwritetextlayout2_SetVerticalGlyphOrientation
,
4350 dwritetextlayout2_GetVerticalGlyphOrientation
,
4351 dwritetextlayout2_SetLastLineWrapping
,
4352 dwritetextlayout2_GetLastLineWrapping
,
4353 dwritetextlayout2_SetOpticalAlignment
,
4354 dwritetextlayout2_GetOpticalAlignment
,
4355 dwritetextlayout2_SetFontFallback
,
4356 dwritetextlayout2_GetFontFallback
,
4357 dwritetextlayout3_InvalidateLayout
,
4358 dwritetextlayout3_SetLineSpacing
,
4359 dwritetextlayout3_GetLineSpacing
,
4360 dwritetextlayout3_GetLineMetrics
,
4361 dwritetextlayout4_SetFontAxisValues
,
4362 dwritetextlayout4_GetFontAxisValueCount
,
4363 dwritetextlayout4_GetFontAxisValues
,
4364 dwritetextlayout4_GetAutomaticFontAxes
,
4365 dwritetextlayout4_SetAutomaticFontAxes
,
4368 static HRESULT WINAPI
dwritetextformat_layout_QueryInterface(IDWriteTextFormat3
*iface
, REFIID riid
, void **obj
)
4370 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4372 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
4374 return IDWriteTextLayout4_QueryInterface(&layout
->IDWriteTextLayout4_iface
, riid
, obj
);
4377 static ULONG WINAPI
dwritetextformat_layout_AddRef(IDWriteTextFormat3
*iface
)
4379 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4380 return IDWriteTextLayout4_AddRef(&layout
->IDWriteTextLayout4_iface
);
4383 static ULONG WINAPI
dwritetextformat_layout_Release(IDWriteTextFormat3
*iface
)
4385 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4386 return IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
4389 static HRESULT WINAPI
dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat3
*iface
,
4390 DWRITE_TEXT_ALIGNMENT alignment
)
4392 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4396 TRACE("%p, %d.\n", iface
, alignment
);
4398 hr
= format_set_textalignment(&layout
->format
, alignment
, &changed
);
4404 /* if layout is not ready there's nothing to align */
4405 if (!(layout
->recompute
& RECOMPUTE_LINES
))
4406 layout_apply_text_alignment(layout
);
4407 layout
->recompute
|= RECOMPUTE_OVERHANGS
;
4413 static HRESULT WINAPI
dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat3
*iface
,
4414 DWRITE_PARAGRAPH_ALIGNMENT alignment
)
4416 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4420 TRACE("%p, %d.\n", iface
, alignment
);
4422 hr
= format_set_paralignment(&layout
->format
, alignment
, &changed
);
4428 /* if layout is not ready there's nothing to align */
4429 if (!(layout
->recompute
& RECOMPUTE_LINES
))
4430 layout_apply_par_alignment(layout
);
4431 layout
->recompute
|= RECOMPUTE_OVERHANGS
;
4437 static HRESULT WINAPI
dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat3
*iface
, DWRITE_WORD_WRAPPING wrapping
)
4439 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4443 TRACE("%p, %d.\n", iface
, wrapping
);
4445 hr
= format_set_wordwrapping(&layout
->format
, wrapping
, &changed
);
4450 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4455 static HRESULT WINAPI
dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat3
*iface
,
4456 DWRITE_READING_DIRECTION direction
)
4458 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4462 TRACE("%p, %d.\n", iface
, direction
);
4464 hr
= format_set_readingdirection(&layout
->format
, direction
, &changed
);
4469 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4474 static HRESULT WINAPI
dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat3
*iface
,
4475 DWRITE_FLOW_DIRECTION direction
)
4477 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4481 TRACE("%p, %d.\n", iface
, direction
);
4483 hr
= format_set_flowdirection(&layout
->format
, direction
, &changed
);
4488 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4493 static HRESULT WINAPI
dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat3
*iface
, FLOAT tabstop
)
4495 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4497 TRACE("%p, %.8e.\n", iface
, tabstop
);
4499 if (tabstop
<= 0.0f
)
4500 return E_INVALIDARG
;
4502 layout
->format
.tabstop
= tabstop
;
4506 static HRESULT WINAPI
dwritetextformat_layout_SetTrimming(IDWriteTextFormat3
*iface
, DWRITE_TRIMMING
const *trimming
,
4507 IDWriteInlineObject
*trimming_sign
)
4509 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4513 TRACE("%p, %p, %p.\n", iface
, trimming
, trimming_sign
);
4515 hr
= format_set_trimming(&layout
->format
, trimming
, trimming_sign
, &changed
);
4518 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4523 static HRESULT WINAPI
dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat3
*iface
,
4524 DWRITE_LINE_SPACING_METHOD method
, FLOAT height
, FLOAT baseline
)
4526 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4527 DWRITE_LINE_SPACING spacing
;
4529 TRACE("%p, %d, %.8e, %.8e.\n", iface
, method
, height
, baseline
);
4531 spacing
= layout
->format
.spacing
;
4532 spacing
.method
= method
;
4533 spacing
.height
= height
;
4534 spacing
.baseline
= baseline
;
4535 return IDWriteTextLayout4_SetLineSpacing(&layout
->IDWriteTextLayout4_iface
, &spacing
);
4538 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat3
*iface
)
4540 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4542 TRACE("%p.\n", iface
);
4544 return layout
->format
.textalignment
;
4547 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat3
*iface
)
4549 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4551 TRACE("%p.\n", iface
);
4553 return layout
->format
.paralign
;
4556 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat3
*iface
)
4558 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4560 TRACE("%p.\n", iface
);
4562 return layout
->format
.wrapping
;
4565 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat3
*iface
)
4567 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4569 TRACE("%p.\n", iface
);
4571 return layout
->format
.readingdir
;
4574 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat3
*iface
)
4576 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4578 TRACE("%p.\n", iface
);
4580 return layout
->format
.flow
;
4583 static FLOAT WINAPI
dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat3
*iface
)
4585 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4587 TRACE("%p.\n", iface
);
4589 return layout
->format
.tabstop
;
4592 static HRESULT WINAPI
dwritetextformat_layout_GetTrimming(IDWriteTextFormat3
*iface
, DWRITE_TRIMMING
*options
,
4593 IDWriteInlineObject
**trimming_sign
)
4595 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4597 TRACE("%p, %p, %p.\n", iface
, options
, trimming_sign
);
4599 *options
= layout
->format
.trimming
;
4600 *trimming_sign
= layout
->format
.trimmingsign
;
4602 IDWriteInlineObject_AddRef(*trimming_sign
);
4606 static HRESULT WINAPI
dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat3
*iface
,
4607 DWRITE_LINE_SPACING_METHOD
*method
, FLOAT
*spacing
, FLOAT
*baseline
)
4609 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4611 TRACE("%p, %p, %p, %p.\n", iface
, method
, spacing
, baseline
);
4613 *method
= layout
->format
.spacing
.method
;
4614 *spacing
= layout
->format
.spacing
.height
;
4615 *baseline
= layout
->format
.spacing
.baseline
;
4619 static HRESULT WINAPI
dwritetextformat_layout_GetFontCollection(IDWriteTextFormat3
*iface
,
4620 IDWriteFontCollection
**collection
)
4622 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4624 TRACE("%p, %p.\n", iface
, collection
);
4626 *collection
= layout
->format
.collection
;
4628 IDWriteFontCollection_AddRef(*collection
);
4632 static UINT32 WINAPI
dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat3
*iface
)
4634 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4636 TRACE("%p.\n", iface
);
4638 return layout
->format
.family_len
;
4641 static HRESULT WINAPI
dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat3
*iface
, WCHAR
*name
, UINT32 size
)
4643 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4645 TRACE("%p, %p, %u.\n", iface
, name
, size
);
4647 if (size
<= layout
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
4648 wcscpy(name
, layout
->format
.family_name
);
4652 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_layout_GetFontWeight(IDWriteTextFormat3
*iface
)
4654 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4656 TRACE("%p.\n", iface
);
4658 return layout
->format
.weight
;
4661 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_layout_GetFontStyle(IDWriteTextFormat3
*iface
)
4663 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4665 TRACE("%p.\n", iface
);
4667 return layout
->format
.style
;
4670 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_layout_GetFontStretch(IDWriteTextFormat3
*iface
)
4672 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4674 TRACE("%p.\n", iface
);
4676 return layout
->format
.stretch
;
4679 static FLOAT WINAPI
dwritetextformat_layout_GetFontSize(IDWriteTextFormat3
*iface
)
4681 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4683 TRACE("%p.\n", iface
);
4685 return layout
->format
.fontsize
;
4688 static UINT32 WINAPI
dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat3
*iface
)
4690 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4692 TRACE("%p.\n", iface
);
4694 return layout
->format
.locale_len
;
4697 static HRESULT WINAPI
dwritetextformat_layout_GetLocaleName(IDWriteTextFormat3
*iface
, WCHAR
*name
, UINT32 size
)
4699 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4701 TRACE("%p, %p, %u.\n", iface
, name
, size
);
4703 if (size
<= layout
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
4704 wcscpy(name
, layout
->format
.locale
);
4708 static HRESULT WINAPI
dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat3
*iface
,
4709 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4711 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4713 TRACE("%p, %d.\n", iface
, orientation
);
4715 return layout_set_vertical_orientation(layout
, orientation
);
4718 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat3
*iface
)
4720 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4722 TRACE("%p.\n", iface
);
4724 return layout
->format
.vertical_orientation
;
4727 static HRESULT WINAPI
dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat3
*iface
,
4728 BOOL lastline_wrapping_enabled
)
4730 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4732 TRACE("%p, %d.\n", iface
, lastline_wrapping_enabled
);
4734 layout
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
4738 static BOOL WINAPI
dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat3
*iface
)
4740 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4742 TRACE("%p.\n", iface
);
4744 return layout
->format
.last_line_wrapping
;
4747 static HRESULT WINAPI
dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat3
*iface
,
4748 DWRITE_OPTICAL_ALIGNMENT alignment
)
4750 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4752 TRACE("%p, %d.\n", iface
, alignment
);
4754 return format_set_optical_alignment(&layout
->format
, alignment
);
4757 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat3
*iface
)
4759 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4761 TRACE("%p.\n", iface
);
4763 return layout
->format
.optical_alignment
;
4766 static HRESULT WINAPI
dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat3
*iface
,
4767 IDWriteFontFallback
*fallback
)
4769 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4771 TRACE("%p, %p.\n", iface
, fallback
);
4773 return IDWriteTextLayout4_SetFontFallback(&layout
->IDWriteTextLayout4_iface
, fallback
);
4776 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat3
*iface
,
4777 IDWriteFontFallback
**fallback
)
4779 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4781 TRACE("%p, %p.\n", iface
, fallback
);
4783 return IDWriteTextLayout4_GetFontFallback(&layout
->IDWriteTextLayout4_iface
, fallback
);
4786 static HRESULT WINAPI
dwritetextformat2_layout_SetLineSpacing(IDWriteTextFormat3
*iface
,
4787 DWRITE_LINE_SPACING
const *spacing
)
4789 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4790 return IDWriteTextLayout4_SetLineSpacing(&layout
->IDWriteTextLayout4_iface
, spacing
);
4793 static HRESULT WINAPI
dwritetextformat2_layout_GetLineSpacing(IDWriteTextFormat3
*iface
, DWRITE_LINE_SPACING
*spacing
)
4795 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4796 return IDWriteTextLayout4_GetLineSpacing(&layout
->IDWriteTextLayout4_iface
, spacing
);
4799 static HRESULT WINAPI
dwritetextformat3_layout_SetFontAxisValues(IDWriteTextFormat3
*iface
,
4800 DWRITE_FONT_AXIS_VALUE
const *axis_values
, UINT32 num_values
)
4802 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4804 TRACE("%p, %p, %u.\n", iface
, axis_values
, num_values
);
4806 return format_set_font_axisvalues(&layout
->format
, axis_values
, num_values
);
4809 static UINT32 WINAPI
dwritetextformat3_layout_GetFontAxisValueCount(IDWriteTextFormat3
*iface
)
4811 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4813 TRACE("%p.\n", iface
);
4815 return layout
->format
.axis_values_count
;
4818 static HRESULT WINAPI
dwritetextformat3_layout_GetFontAxisValues(IDWriteTextFormat3
*iface
,
4819 DWRITE_FONT_AXIS_VALUE
*axis_values
, UINT32 num_values
)
4821 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4823 TRACE("%p, %p, %u.\n", iface
, axis_values
, num_values
);
4825 return format_get_font_axisvalues(&layout
->format
, axis_values
, num_values
);
4828 static DWRITE_AUTOMATIC_FONT_AXES WINAPI
dwritetextformat3_layout_GetAutomaticFontAxes(IDWriteTextFormat3
*iface
)
4830 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4831 return IDWriteTextLayout4_GetAutomaticFontAxes(&layout
->IDWriteTextLayout4_iface
);
4834 static HRESULT WINAPI
dwritetextformat3_layout_SetAutomaticFontAxes(IDWriteTextFormat3
*iface
,
4835 DWRITE_AUTOMATIC_FONT_AXES axes
)
4837 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextFormat3(iface
);
4838 return IDWriteTextLayout4_SetAutomaticFontAxes(&layout
->IDWriteTextLayout4_iface
, axes
);
4841 static const IDWriteTextFormat3Vtbl dwritetextformat3_layout_vtbl
=
4843 dwritetextformat_layout_QueryInterface
,
4844 dwritetextformat_layout_AddRef
,
4845 dwritetextformat_layout_Release
,
4846 dwritetextformat_layout_SetTextAlignment
,
4847 dwritetextformat_layout_SetParagraphAlignment
,
4848 dwritetextformat_layout_SetWordWrapping
,
4849 dwritetextformat_layout_SetReadingDirection
,
4850 dwritetextformat_layout_SetFlowDirection
,
4851 dwritetextformat_layout_SetIncrementalTabStop
,
4852 dwritetextformat_layout_SetTrimming
,
4853 dwritetextformat_layout_SetLineSpacing
,
4854 dwritetextformat_layout_GetTextAlignment
,
4855 dwritetextformat_layout_GetParagraphAlignment
,
4856 dwritetextformat_layout_GetWordWrapping
,
4857 dwritetextformat_layout_GetReadingDirection
,
4858 dwritetextformat_layout_GetFlowDirection
,
4859 dwritetextformat_layout_GetIncrementalTabStop
,
4860 dwritetextformat_layout_GetTrimming
,
4861 dwritetextformat_layout_GetLineSpacing
,
4862 dwritetextformat_layout_GetFontCollection
,
4863 dwritetextformat_layout_GetFontFamilyNameLength
,
4864 dwritetextformat_layout_GetFontFamilyName
,
4865 dwritetextformat_layout_GetFontWeight
,
4866 dwritetextformat_layout_GetFontStyle
,
4867 dwritetextformat_layout_GetFontStretch
,
4868 dwritetextformat_layout_GetFontSize
,
4869 dwritetextformat_layout_GetLocaleNameLength
,
4870 dwritetextformat_layout_GetLocaleName
,
4871 dwritetextformat1_layout_SetVerticalGlyphOrientation
,
4872 dwritetextformat1_layout_GetVerticalGlyphOrientation
,
4873 dwritetextformat1_layout_SetLastLineWrapping
,
4874 dwritetextformat1_layout_GetLastLineWrapping
,
4875 dwritetextformat1_layout_SetOpticalAlignment
,
4876 dwritetextformat1_layout_GetOpticalAlignment
,
4877 dwritetextformat1_layout_SetFontFallback
,
4878 dwritetextformat1_layout_GetFontFallback
,
4879 dwritetextformat2_layout_SetLineSpacing
,
4880 dwritetextformat2_layout_GetLineSpacing
,
4881 dwritetextformat3_layout_SetFontAxisValues
,
4882 dwritetextformat3_layout_GetFontAxisValueCount
,
4883 dwritetextformat3_layout_GetFontAxisValues
,
4884 dwritetextformat3_layout_GetAutomaticFontAxes
,
4885 dwritetextformat3_layout_SetAutomaticFontAxes
,
4888 static HRESULT WINAPI
dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1
*iface
,
4889 REFIID riid
, void **obj
)
4891 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink1
) ||
4892 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink
) ||
4893 IsEqualIID(riid
, &IID_IUnknown
))
4896 IDWriteTextAnalysisSink1_AddRef(iface
);
4900 WARN("%s not implemented.\n", debugstr_guid(riid
));
4903 return E_NOINTERFACE
;
4906 static ULONG WINAPI
dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1
*iface
)
4908 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4909 return IDWriteTextLayout4_AddRef(&layout
->IDWriteTextLayout4_iface
);
4912 static ULONG WINAPI
dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1
*iface
)
4914 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4915 return IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
4918 static HRESULT WINAPI
dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1
*iface
,
4919 UINT32 position
, UINT32 length
, DWRITE_SCRIPT_ANALYSIS
const* sa
)
4921 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4922 struct layout_run
*run
;
4925 TRACE("[%u,%u) script=%u:%s\n", position
, position
+ length
, sa
->script
, debugstr_sa_script(sa
->script
));
4927 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
, &run
)))
4930 run
->u
.regular
.descr
.string
= &layout
->str
[position
];
4931 run
->u
.regular
.descr
.stringLength
= length
;
4932 run
->u
.regular
.descr
.textPosition
= position
;
4933 run
->u
.regular
.sa
= *sa
;
4934 list_add_tail(&layout
->runs
, &run
->entry
);
4938 static HRESULT WINAPI
dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1
*iface
,
4939 UINT32 position
, UINT32 length
, DWRITE_LINE_BREAKPOINT
const* breakpoints
)
4941 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4943 if (position
+ length
> layout
->len
)
4946 memcpy(&layout
->nominal_breakpoints
[position
], breakpoints
, length
*sizeof(DWRITE_LINE_BREAKPOINT
));
4950 static HRESULT WINAPI
dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1
*iface
, UINT32 position
,
4951 UINT32 length
, UINT8 explicitLevel
, UINT8 resolvedLevel
)
4953 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4954 struct layout_run
*cur_run
;
4957 TRACE("[%u,%u) %u %u\n", position
, position
+ length
, explicitLevel
, resolvedLevel
);
4959 LIST_FOR_EACH_ENTRY(cur_run
, &layout
->runs
, struct layout_run
, entry
) {
4960 struct regular_layout_run
*cur
= &cur_run
->u
.regular
;
4961 struct layout_run
*run
;
4963 if (cur_run
->kind
== LAYOUT_RUN_INLINE
)
4966 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4967 if (position
< cur
->descr
.textPosition
|| position
>= cur
->descr
.textPosition
+ cur
->descr
.stringLength
)
4970 /* full hit - just set run level */
4971 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
== length
) {
4972 cur
->run
.bidiLevel
= resolvedLevel
;
4976 /* current run is fully covered, move to next one */
4977 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
< length
) {
4978 cur
->run
.bidiLevel
= resolvedLevel
;
4979 position
+= cur
->descr
.stringLength
;
4980 length
-= cur
->descr
.stringLength
;
4984 /* all fully covered runs are processed at this point, reuse existing run for remaining
4985 reported bidi range and add another run for the rest of original one */
4987 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
+ length
, &run
)))
4991 run
->u
.regular
.descr
.textPosition
= position
+ length
;
4992 run
->u
.regular
.descr
.stringLength
= cur
->descr
.stringLength
- length
;
4993 run
->u
.regular
.descr
.string
= &layout
->str
[position
+ length
];
4995 /* reduce existing run */
4996 cur
->run
.bidiLevel
= resolvedLevel
;
4997 cur
->descr
.stringLength
= length
;
4999 list_add_after(&cur_run
->entry
, &run
->entry
);
5006 static HRESULT WINAPI
dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1
*iface
,
5007 UINT32 position
, UINT32 length
, IDWriteNumberSubstitution
* substitution
)
5012 static HRESULT WINAPI
dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1
*iface
,
5013 UINT32 position
, UINT32 length
, DWRITE_GLYPH_ORIENTATION_ANGLE angle
, UINT8 adjusted_bidi_level
,
5014 BOOL is_sideways
, BOOL is_rtl
)
5019 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl
= {
5020 dwritetextlayout_sink_QueryInterface
,
5021 dwritetextlayout_sink_AddRef
,
5022 dwritetextlayout_sink_Release
,
5023 dwritetextlayout_sink_SetScriptAnalysis
,
5024 dwritetextlayout_sink_SetLineBreakpoints
,
5025 dwritetextlayout_sink_SetBidiLevel
,
5026 dwritetextlayout_sink_SetNumberSubstitution
,
5027 dwritetextlayout_sink_SetGlyphOrientation
5030 static HRESULT WINAPI
dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1
*iface
,
5031 REFIID riid
, void **obj
)
5033 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource1
) ||
5034 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource
) ||
5035 IsEqualIID(riid
, &IID_IUnknown
))
5038 IDWriteTextAnalysisSource1_AddRef(iface
);
5042 WARN("%s not implemented.\n", debugstr_guid(riid
));
5045 return E_NOINTERFACE
;
5048 static ULONG WINAPI
dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1
*iface
)
5050 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5051 return IDWriteTextLayout4_AddRef(&layout
->IDWriteTextLayout4_iface
);
5054 static ULONG WINAPI
dwritetextlayout_source_Release(IDWriteTextAnalysisSource1
*iface
)
5056 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5057 return IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
5060 static HRESULT WINAPI
dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1
*iface
,
5061 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
5063 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5065 TRACE("%p, %u, %p, %p.\n", iface
, position
, text
, text_len
);
5067 if (position
< layout
->text_source
.length
)
5069 *text
= &layout
->str
[position
+ layout
->text_source
.offset
];
5070 *text_len
= layout
->text_source
.length
- position
;
5081 static HRESULT WINAPI
dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1
*iface
,
5082 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
5084 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5086 TRACE("%p, %u, %p, %p.\n", iface
, position
, text
, text_len
);
5088 if (position
&& position
< layout
->text_source
.length
)
5090 *text
= &layout
->str
[layout
->text_source
.offset
];
5091 *text_len
= position
;
5102 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1
*iface
)
5104 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5105 return IDWriteTextLayout4_GetReadingDirection(&layout
->IDWriteTextLayout4_iface
);
5108 static HRESULT WINAPI
dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1
*iface
,
5109 UINT32 position
, UINT32
* text_len
, WCHAR
const** locale
)
5111 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5112 struct layout_range
*range
, *next
;
5115 if (position
< layout
->text_source
.length
)
5117 position
+= layout
->text_source
.offset
;
5118 end
= layout
->text_source
.offset
+ layout
->text_source
.length
;
5120 range
= get_layout_range_by_pos(layout
, position
);
5122 *locale
= range
->locale
;
5123 *text_len
= range
->h
.range
.startPosition
+ range
->h
.range
.length
- position
;
5125 next
= LIST_ENTRY(list_next(&layout
->ranges
, &range
->h
.entry
), struct layout_range
, h
.entry
);
5126 while (next
&& next
->h
.range
.startPosition
< end
&& !wcscmp(range
->locale
, next
->locale
))
5128 *text_len
+= next
->h
.range
.length
;
5129 next
= LIST_ENTRY(list_next(&layout
->ranges
, &next
->h
.entry
), struct layout_range
, h
.entry
);
5132 *text_len
= min(*text_len
, layout
->text_source
.length
- position
);
5143 static HRESULT WINAPI
dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1
*iface
,
5144 UINT32 position
, UINT32
* text_len
, IDWriteNumberSubstitution
**substitution
)
5146 FIXME("%u %p %p: stub\n", position
, text_len
, substitution
);
5150 static HRESULT WINAPI
dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1
*iface
,
5151 UINT32 position
, UINT32
*length
, DWRITE_VERTICAL_GLYPH_ORIENTATION
*orientation
, UINT8
*bidi_level
)
5153 FIXME("%u %p %p %p: stub\n", position
, length
, orientation
, bidi_level
);
5157 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl
= {
5158 dwritetextlayout_source_QueryInterface
,
5159 dwritetextlayout_source_AddRef
,
5160 dwritetextlayout_source_Release
,
5161 dwritetextlayout_source_GetTextAtPosition
,
5162 dwritetextlayout_source_GetTextBeforePosition
,
5163 dwritetextlayout_source_GetParagraphReadingDirection
,
5164 dwritetextlayout_source_GetLocaleName
,
5165 dwritetextlayout_source_GetNumberSubstitution
,
5166 dwritetextlayout_source_GetVerticalGlyphOrientation
5169 static HRESULT
layout_format_from_textformat(struct dwrite_textlayout
*layout
, IDWriteTextFormat
*format
)
5171 struct dwrite_textformat
*textformat
;
5172 IDWriteTextFormat1
*format1
;
5173 IDWriteTextFormat3
*format3
;
5177 if ((textformat
= unsafe_impl_from_IDWriteTextFormat(format
))) {
5178 layout
->format
= textformat
->format
;
5180 layout
->format
.locale
= wcsdup(textformat
->format
.locale
);
5181 layout
->format
.family_name
= wcsdup(textformat
->format
.family_name
);
5182 if (!layout
->format
.locale
|| !layout
->format
.family_name
)
5184 free(layout
->format
.locale
);
5185 free(layout
->format
.family_name
);
5186 return E_OUTOFMEMORY
;
5189 if (layout
->format
.trimmingsign
)
5190 IDWriteInlineObject_AddRef(layout
->format
.trimmingsign
);
5191 if (layout
->format
.collection
)
5192 IDWriteFontCollection_AddRef(layout
->format
.collection
);
5193 if (layout
->format
.fallback
)
5194 IDWriteFontFallback_AddRef(layout
->format
.fallback
);
5199 layout
->format
.weight
= IDWriteTextFormat_GetFontWeight(format
);
5200 layout
->format
.style
= IDWriteTextFormat_GetFontStyle(format
);
5201 layout
->format
.stretch
= IDWriteTextFormat_GetFontStretch(format
);
5202 layout
->format
.fontsize
= IDWriteTextFormat_GetFontSize(format
);
5203 layout
->format
.tabstop
= IDWriteTextFormat_GetIncrementalTabStop(format
);
5204 layout
->format
.textalignment
= IDWriteTextFormat_GetTextAlignment(format
);
5205 layout
->format
.paralign
= IDWriteTextFormat_GetParagraphAlignment(format
);
5206 layout
->format
.wrapping
= IDWriteTextFormat_GetWordWrapping(format
);
5207 layout
->format
.readingdir
= IDWriteTextFormat_GetReadingDirection(format
);
5208 layout
->format
.flow
= IDWriteTextFormat_GetFlowDirection(format
);
5209 hr
= IDWriteTextFormat_GetLineSpacing(format
, &layout
->format
.spacing
.method
,
5210 &layout
->format
.spacing
.height
, &layout
->format
.spacing
.baseline
);
5214 hr
= IDWriteTextFormat_GetTrimming(format
, &layout
->format
.trimming
, &layout
->format
.trimmingsign
);
5218 /* locale name and length */
5219 len
= IDWriteTextFormat_GetLocaleNameLength(format
);
5220 if (!(layout
->format
.locale
= malloc((len
+ 1) * sizeof(WCHAR
))))
5221 return E_OUTOFMEMORY
;
5223 hr
= IDWriteTextFormat_GetLocaleName(format
, layout
->format
.locale
, len
+1);
5226 layout
->format
.locale_len
= len
;
5228 /* font family name and length */
5229 len
= IDWriteTextFormat_GetFontFamilyNameLength(format
);
5230 if (!(layout
->format
.family_name
= malloc((len
+ 1) * sizeof(WCHAR
))))
5231 return E_OUTOFMEMORY
;
5233 hr
= IDWriteTextFormat_GetFontFamilyName(format
, layout
->format
.family_name
, len
+1);
5236 layout
->format
.family_len
= len
;
5238 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat1
, (void**)&format1
);
5241 IDWriteTextFormat2
*format2
;
5243 layout
->format
.vertical_orientation
= IDWriteTextFormat1_GetVerticalGlyphOrientation(format1
);
5244 layout
->format
.optical_alignment
= IDWriteTextFormat1_GetOpticalAlignment(format1
);
5245 IDWriteTextFormat1_GetFontFallback(format1
, &layout
->format
.fallback
);
5247 if (IDWriteTextFormat1_QueryInterface(format1
, &IID_IDWriteTextFormat2
, (void**)&format2
) == S_OK
) {
5248 IDWriteTextFormat2_GetLineSpacing(format2
, &layout
->format
.spacing
);
5249 IDWriteTextFormat2_Release(format2
);
5252 IDWriteTextFormat1_Release(format1
);
5255 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat3
, (void **)&format3
);
5258 layout
->format
.automatic_axes
= IDWriteTextFormat3_GetAutomaticFontAxes(format3
);
5259 IDWriteTextFormat3_Release(format3
);
5262 return IDWriteTextFormat_GetFontCollection(format
, &layout
->format
.collection
);
5265 static HRESULT
init_textlayout(const struct textlayout_desc
*desc
, struct dwrite_textlayout
*layout
)
5267 struct layout_range_header
*range
, *strike
, *underline
, *effect
, *spacing
, *typography
;
5268 static const DWRITE_TEXT_RANGE r
= { 0, ~0u };
5271 layout
->IDWriteTextLayout4_iface
.lpVtbl
= &dwritetextlayoutvtbl
;
5272 layout
->IDWriteTextFormat3_iface
.lpVtbl
= &dwritetextformat3_layout_vtbl
;
5273 layout
->IDWriteTextAnalysisSink1_iface
.lpVtbl
= &dwritetextlayoutsinkvtbl
;
5274 layout
->IDWriteTextAnalysisSource1_iface
.lpVtbl
= &dwritetextlayoutsourcevtbl
;
5275 layout
->refcount
= 1;
5276 layout
->len
= desc
->length
;
5277 layout
->recompute
= RECOMPUTE_EVERYTHING
;
5278 list_init(&layout
->eruns
);
5279 list_init(&layout
->inlineobjects
);
5280 list_init(&layout
->underlines
);
5281 list_init(&layout
->strikethrough
);
5282 list_init(&layout
->runs
);
5283 list_init(&layout
->ranges
);
5284 list_init(&layout
->strike_ranges
);
5285 list_init(&layout
->underline_ranges
);
5286 list_init(&layout
->effects
);
5287 list_init(&layout
->spacing
);
5288 list_init(&layout
->typographies
);
5289 layout
->metrics
.layoutWidth
= desc
->max_width
;
5290 layout
->metrics
.layoutHeight
= desc
->max_height
;
5292 layout
->str
= heap_strdupnW(desc
->string
, desc
->length
);
5293 if (desc
->length
&& !layout
->str
) {
5298 hr
= layout_format_from_textformat(layout
, desc
->format
);
5302 range
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_REGULAR
);
5303 strike
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_STRIKETHROUGH
);
5304 underline
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_UNDERLINE
);
5305 effect
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_EFFECT
);
5306 spacing
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_SPACING
);
5307 typography
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_TYPOGRAPHY
);
5308 if (!range
|| !strike
|| !effect
|| !spacing
|| !typography
|| !underline
) {
5309 free_layout_range(range
);
5310 free_layout_range(strike
);
5311 free_layout_range(underline
);
5312 free_layout_range(effect
);
5313 free_layout_range(spacing
);
5314 free_layout_range(typography
);
5319 layout
->measuringmode
= desc
->is_gdi_compatible
? (desc
->use_gdi_natural
? DWRITE_MEASURING_MODE_GDI_NATURAL
:
5320 DWRITE_MEASURING_MODE_GDI_CLASSIC
) : DWRITE_MEASURING_MODE_NATURAL
;
5321 layout
->ppdip
= desc
->ppdip
;
5322 layout
->transform
= desc
->transform
? *desc
->transform
: identity
;
5324 layout
->factory
= desc
->factory
;
5325 IDWriteFactory7_AddRef(layout
->factory
);
5326 list_add_head(&layout
->ranges
, &range
->entry
);
5327 list_add_head(&layout
->strike_ranges
, &strike
->entry
);
5328 list_add_head(&layout
->underline_ranges
, &underline
->entry
);
5329 list_add_head(&layout
->effects
, &effect
->entry
);
5330 list_add_head(&layout
->spacing
, &spacing
->entry
);
5331 list_add_head(&layout
->typographies
, &typography
->entry
);
5333 if (FAILED(hr
= IDWriteFactory5_GetSystemFontCollection((IDWriteFactory5
*)layout
->factory
, FALSE
,
5334 (IDWriteFontCollection1
**)&layout
->system_collection
, FALSE
)))
5342 IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
5346 HRESULT
create_textlayout(const struct textlayout_desc
*desc
, IDWriteTextLayout
**layout
)
5348 struct dwrite_textlayout
*object
;
5353 if (desc
->max_width
< 0.0f
|| desc
->max_height
< 0.0f
)
5354 return E_INVALIDARG
;
5356 if (!desc
->format
|| !desc
->string
)
5357 return E_INVALIDARG
;
5359 if (!(object
= calloc(1, sizeof(*object
))))
5360 return E_OUTOFMEMORY
;
5362 hr
= init_textlayout(desc
, object
);
5364 *layout
= (IDWriteTextLayout
*)&object
->IDWriteTextLayout4_iface
;
5369 static HRESULT WINAPI
dwritetypography_QueryInterface(IDWriteTypography
*iface
, REFIID riid
, void **obj
)
5371 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
5373 if (IsEqualIID(riid
, &IID_IDWriteTypography
) || IsEqualIID(riid
, &IID_IUnknown
)) {
5375 IDWriteTypography_AddRef(iface
);
5379 WARN("%s not implemented.\n", debugstr_guid(riid
));
5383 return E_NOINTERFACE
;
5386 static ULONG WINAPI
dwritetypography_AddRef(IDWriteTypography
*iface
)
5388 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5389 ULONG refcount
= InterlockedIncrement(&typography
->refcount
);
5391 TRACE("%p, refcount %ld.\n", iface
, refcount
);
5396 static ULONG WINAPI
dwritetypography_Release(IDWriteTypography
*iface
)
5398 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5399 ULONG refcount
= InterlockedDecrement(&typography
->refcount
);
5401 TRACE("%p, refcount %ld.\n", iface
, refcount
);
5405 free(typography
->features
);
5412 static HRESULT WINAPI
dwritetypography_AddFontFeature(IDWriteTypography
*iface
, DWRITE_FONT_FEATURE feature
)
5414 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5416 TRACE("%p, %s, %u.\n", iface
, debugstr_tag(feature
.nameTag
), feature
.parameter
);
5418 if (!dwrite_array_reserve((void **)&typography
->features
, &typography
->capacity
, typography
->count
+ 1,
5419 sizeof(*typography
->features
)))
5421 return E_OUTOFMEMORY
;
5424 typography
->features
[typography
->count
++] = feature
;
5429 static UINT32 WINAPI
dwritetypography_GetFontFeatureCount(IDWriteTypography
*iface
)
5431 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5433 TRACE("%p.\n", iface
);
5435 return typography
->count
;
5438 static HRESULT WINAPI
dwritetypography_GetFontFeature(IDWriteTypography
*iface
, UINT32 index
,
5439 DWRITE_FONT_FEATURE
*feature
)
5441 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5443 TRACE("%p, %u, %p.\n", iface
, index
, feature
);
5445 if (index
>= typography
->count
)
5446 return E_INVALIDARG
;
5448 *feature
= typography
->features
[index
];
5452 static const IDWriteTypographyVtbl dwritetypographyvtbl
= {
5453 dwritetypography_QueryInterface
,
5454 dwritetypography_AddRef
,
5455 dwritetypography_Release
,
5456 dwritetypography_AddFontFeature
,
5457 dwritetypography_GetFontFeatureCount
,
5458 dwritetypography_GetFontFeature
5461 HRESULT
create_typography(IDWriteTypography
**ret
)
5463 struct dwrite_typography
*typography
;
5467 if (!(typography
= calloc(1, sizeof(*typography
))))
5468 return E_OUTOFMEMORY
;
5470 typography
->IDWriteTypography_iface
.lpVtbl
= &dwritetypographyvtbl
;
5471 typography
->refcount
= 1;
5473 *ret
= &typography
->IDWriteTypography_iface
;