2 * Text format and layout
4 * Copyright 2012, 2014-2021 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "dwrite_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
35 struct dwrite_textformat_data
42 DWRITE_FONT_WEIGHT weight
;
43 DWRITE_FONT_STYLE style
;
44 DWRITE_FONT_STRETCH stretch
;
46 DWRITE_PARAGRAPH_ALIGNMENT paralign
;
47 DWRITE_READING_DIRECTION readingdir
;
48 DWRITE_WORD_WRAPPING wrapping
;
49 BOOL last_line_wrapping
;
50 DWRITE_TEXT_ALIGNMENT textalignment
;
51 DWRITE_FLOW_DIRECTION flow
;
52 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation
;
53 DWRITE_OPTICAL_ALIGNMENT optical_alignment
;
54 DWRITE_LINE_SPACING spacing
;
55 DWRITE_AUTOMATIC_FONT_AXES automatic_axes
;
60 DWRITE_TRIMMING trimming
;
61 IDWriteInlineObject
*trimmingsign
;
63 IDWriteFontCollection
*collection
;
64 IDWriteFontFallback
*fallback
;
66 DWRITE_FONT_AXIS_VALUE
*axis_values
;
67 unsigned int axis_values_count
;
70 enum layout_range_attr_kind
{
71 LAYOUT_RANGE_ATTR_WEIGHT
,
72 LAYOUT_RANGE_ATTR_STYLE
,
73 LAYOUT_RANGE_ATTR_STRETCH
,
74 LAYOUT_RANGE_ATTR_FONTSIZE
,
75 LAYOUT_RANGE_ATTR_EFFECT
,
76 LAYOUT_RANGE_ATTR_INLINE
,
77 LAYOUT_RANGE_ATTR_UNDERLINE
,
78 LAYOUT_RANGE_ATTR_STRIKETHROUGH
,
79 LAYOUT_RANGE_ATTR_PAIR_KERNING
,
80 LAYOUT_RANGE_ATTR_FONTCOLL
,
81 LAYOUT_RANGE_ATTR_LOCALE
,
82 LAYOUT_RANGE_ATTR_FONTFAMILY
,
83 LAYOUT_RANGE_ATTR_SPACING
,
84 LAYOUT_RANGE_ATTR_TYPOGRAPHY
87 struct layout_range_attr_value
{
88 DWRITE_TEXT_RANGE range
;
90 DWRITE_FONT_WEIGHT weight
;
91 DWRITE_FONT_STYLE style
;
92 DWRITE_FONT_STRETCH stretch
;
94 IDWriteInlineObject
*object
;
99 IDWriteFontCollection
*collection
;
101 const WCHAR
*fontfamily
;
107 IDWriteTypography
*typography
;
111 enum layout_range_kind
{
112 LAYOUT_RANGE_REGULAR
,
113 LAYOUT_RANGE_UNDERLINE
,
114 LAYOUT_RANGE_STRIKETHROUGH
,
116 LAYOUT_RANGE_SPACING
,
117 LAYOUT_RANGE_TYPOGRAPHY
120 struct layout_range_header
{
122 enum layout_range_kind kind
;
123 DWRITE_TEXT_RANGE range
;
126 struct layout_range
{
127 struct layout_range_header h
;
128 DWRITE_FONT_WEIGHT weight
;
129 DWRITE_FONT_STYLE style
;
131 DWRITE_FONT_STRETCH stretch
;
132 IDWriteInlineObject
*object
;
134 IDWriteFontCollection
*collection
;
135 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
139 struct layout_range_bool
{
140 struct layout_range_header h
;
144 struct layout_range_iface
{
145 struct layout_range_header h
;
149 struct layout_range_spacing
{
150 struct layout_range_header h
;
156 enum layout_run_kind
{
161 struct inline_object_run
{
162 IDWriteInlineObject
*object
;
166 struct regular_layout_run
{
167 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
168 DWRITE_GLYPH_RUN run
;
169 DWRITE_SCRIPT_ANALYSIS sa
;
173 DWRITE_GLYPH_OFFSET
*offsets
;
174 UINT32 glyphcount
; /* actual glyph count after shaping, not necessarily the same as reported to Draw() */
180 enum layout_run_kind kind
;
183 struct inline_object_run object
;
184 struct regular_layout_run regular
;
188 unsigned int start_position
; /* run text position in range [0, layout-text-length) */
191 struct layout_effective_run
{
193 const struct layout_run
*run
; /* nominal run this one is based on */
194 UINT32 start
; /* relative text position, 0 means first text position of a nominal run */
195 UINT32 length
; /* length in codepoints that this run covers */
196 UINT32 glyphcount
; /* total glyph count in this run */
197 IUnknown
*effect
; /* original reference is kept only at range level */
198 D2D1_POINT_2F origin
; /* baseline origin */
199 FLOAT align_dx
; /* adjustment from text alignment */
200 FLOAT width
; /* run width */
201 UINT16
*clustermap
; /* effective clustermap, allocated separately, is not reused from nominal map */
202 UINT32 line
; /* 0-based line index in line metrics array */
203 BOOL underlined
; /* set if this run is underlined */
204 D2D1_RECT_F bbox
; /* ink run box, top == bottom means it wasn't estimated yet */
207 struct layout_effective_inline
{
209 IDWriteInlineObject
*object
; /* inline object, set explicitly or added when trimming a line */
210 IUnknown
*effect
; /* original reference is kept only at range level */
212 D2D1_POINT_2F origin
; /* left top corner */
213 FLOAT align_dx
; /* adjustment from text alignment */
214 FLOAT width
; /* object width as it's reported it */
215 BOOL is_sideways
; /* vertical flow direction flag passed to Draw */
216 BOOL is_rtl
; /* bidi flag passed to Draw */
217 UINT32 line
; /* 0-based line index in line metrics array */
220 struct layout_underline
{
222 const struct layout_effective_run
*run
;
226 struct layout_strikethrough
{
228 const struct layout_effective_run
*run
;
229 DWRITE_STRIKETHROUGH s
;
232 struct layout_cluster
{
233 const struct layout_run
*run
; /* link to nominal run this cluster belongs to */
234 UINT32 position
; /* relative to run, first cluster has 0 position */
239 float height
; /* height based on content */
240 float baseline
; /* baseline based on content */
241 DWRITE_LINE_METRICS1 metrics
;
244 enum layout_recompute_mask
{
245 RECOMPUTE_CLUSTERS
= 1 << 0,
246 RECOMPUTE_MINIMAL_WIDTH
= 1 << 1,
247 RECOMPUTE_LINES
= 1 << 2,
248 RECOMPUTE_OVERHANGS
= 1 << 3,
249 RECOMPUTE_LINES_AND_OVERHANGS
= RECOMPUTE_LINES
| RECOMPUTE_OVERHANGS
,
250 RECOMPUTE_EVERYTHING
= 0xffff
253 struct dwrite_textlayout
255 IDWriteTextLayout4 IDWriteTextLayout4_iface
;
256 IDWriteTextFormat3 IDWriteTextFormat3_iface
;
257 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface
;
258 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface
;
261 IDWriteFactory7
*factory
;
265 struct dwrite_textformat_data format
;
266 struct list strike_ranges
;
267 struct list underline_ranges
;
268 struct list typographies
;
273 /* lists ready to use by Draw() */
275 struct list inlineobjects
;
276 struct list underlines
;
277 struct list strikethrough
;
280 DWRITE_LINE_BREAKPOINT
*nominal_breakpoints
;
281 DWRITE_LINE_BREAKPOINT
*actual_breakpoints
;
283 struct layout_cluster
*clusters
;
284 DWRITE_CLUSTER_METRICS
*clustermetrics
;
285 UINT32 cluster_count
;
288 struct layout_line
*lines
;
291 DWRITE_TEXT_METRICS1 metrics
;
292 DWRITE_OVERHANG_METRICS overhangs
;
294 DWRITE_MEASURING_MODE measuringmode
;
296 /* gdi-compatible layout specifics */
298 DWRITE_MATRIX transform
;
301 struct dwrite_textformat
303 IDWriteTextFormat3 IDWriteTextFormat3_iface
;
305 struct dwrite_textformat_data format
;
308 struct dwrite_trimmingsign
310 IDWriteInlineObject IDWriteInlineObject_iface
;
313 IDWriteTextLayout
*layout
;
316 struct dwrite_typography
{
317 IDWriteTypography IDWriteTypography_iface
;
320 DWRITE_FONT_FEATURE
*features
;
325 static const IDWriteTextFormat3Vtbl dwritetextformatvtbl
;
327 static void release_format_data(struct dwrite_textformat_data
*data
)
329 if (data
->collection
) IDWriteFontCollection_Release(data
->collection
);
330 if (data
->fallback
) IDWriteFontFallback_Release(data
->fallback
);
331 if (data
->trimmingsign
) IDWriteInlineObject_Release(data
->trimmingsign
);
332 heap_free(data
->family_name
);
333 heap_free(data
->locale
);
334 heap_free(data
->axis_values
);
337 static inline struct dwrite_textlayout
*impl_from_IDWriteTextLayout4(IDWriteTextLayout4
*iface
)
339 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextLayout4_iface
);
342 static inline struct dwrite_textlayout
*impl_layout_from_IDWriteTextFormat3(IDWriteTextFormat3
*iface
)
344 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextFormat3_iface
);
347 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1
*iface
)
349 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSink1_iface
);
352 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1
*iface
)
354 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSource1_iface
);
357 static inline struct dwrite_textformat
*impl_from_IDWriteTextFormat3(IDWriteTextFormat3
*iface
)
359 return CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat3_iface
);
362 static struct dwrite_textformat
*unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat
*);
364 static inline struct dwrite_trimmingsign
*impl_from_IDWriteInlineObject(IDWriteInlineObject
*iface
)
366 return CONTAINING_RECORD(iface
, struct dwrite_trimmingsign
, IDWriteInlineObject_iface
);
369 static inline struct dwrite_typography
*impl_from_IDWriteTypography(IDWriteTypography
*iface
)
371 return CONTAINING_RECORD(iface
, struct dwrite_typography
, IDWriteTypography_iface
);
374 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION
*descr
)
376 return wine_dbg_sprintf("[%u,%u)", descr
->textPosition
, descr
->textPosition
+ descr
->stringLength
);
379 static inline BOOL
is_layout_gdi_compatible(struct dwrite_textlayout
*layout
)
381 return layout
->measuringmode
!= DWRITE_MEASURING_MODE_NATURAL
;
384 static inline HRESULT
format_set_textalignment(struct dwrite_textformat_data
*format
, DWRITE_TEXT_ALIGNMENT alignment
,
387 if ((UINT32
)alignment
> DWRITE_TEXT_ALIGNMENT_JUSTIFIED
)
389 if (changed
) *changed
= format
->textalignment
!= alignment
;
390 format
->textalignment
= alignment
;
394 static inline HRESULT
format_set_paralignment(struct dwrite_textformat_data
*format
,
395 DWRITE_PARAGRAPH_ALIGNMENT alignment
, BOOL
*changed
)
397 if ((UINT32
)alignment
> DWRITE_PARAGRAPH_ALIGNMENT_CENTER
)
399 if (changed
) *changed
= format
->paralign
!= alignment
;
400 format
->paralign
= alignment
;
404 static inline HRESULT
format_set_readingdirection(struct dwrite_textformat_data
*format
,
405 DWRITE_READING_DIRECTION direction
, BOOL
*changed
)
407 if ((UINT32
)direction
> DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
)
409 if (changed
) *changed
= format
->readingdir
!= direction
;
410 format
->readingdir
= direction
;
414 static inline HRESULT
format_set_wordwrapping(struct dwrite_textformat_data
*format
,
415 DWRITE_WORD_WRAPPING wrapping
, BOOL
*changed
)
417 if ((UINT32
)wrapping
> DWRITE_WORD_WRAPPING_CHARACTER
)
419 if (changed
) *changed
= format
->wrapping
!= wrapping
;
420 format
->wrapping
= wrapping
;
424 static inline HRESULT
format_set_flowdirection(struct dwrite_textformat_data
*format
,
425 DWRITE_FLOW_DIRECTION direction
, BOOL
*changed
)
427 if ((UINT32
)direction
> DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
)
429 if (changed
) *changed
= format
->flow
!= direction
;
430 format
->flow
= direction
;
434 static inline HRESULT
format_set_trimming(struct dwrite_textformat_data
*format
,
435 DWRITE_TRIMMING
const *trimming
, IDWriteInlineObject
*trimming_sign
, BOOL
*changed
)
440 if ((UINT32
)trimming
->granularity
> DWRITE_TRIMMING_GRANULARITY_WORD
)
444 *changed
= !!memcmp(&format
->trimming
, trimming
, sizeof(*trimming
));
445 if (format
->trimmingsign
!= trimming_sign
)
449 format
->trimming
= *trimming
;
450 if (format
->trimmingsign
)
451 IDWriteInlineObject_Release(format
->trimmingsign
);
452 format
->trimmingsign
= trimming_sign
;
453 if (format
->trimmingsign
)
454 IDWriteInlineObject_AddRef(format
->trimmingsign
);
458 static inline HRESULT
format_set_linespacing(struct dwrite_textformat_data
*format
,
459 DWRITE_LINE_SPACING
const *spacing
, BOOL
*changed
)
461 if (spacing
->height
< 0.0f
|| spacing
->leadingBefore
< 0.0f
|| spacing
->leadingBefore
> 1.0f
||
462 (UINT32
)spacing
->method
> DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
)
466 *changed
= memcmp(spacing
, &format
->spacing
, sizeof(*spacing
));
468 format
->spacing
= *spacing
;
472 static HRESULT
format_set_font_axisvalues(struct dwrite_textformat_data
*format
,
473 DWRITE_FONT_AXIS_VALUE
const *axis_values
, unsigned int num_values
)
475 heap_free(format
->axis_values
);
476 format
->axis_values
= NULL
;
477 format
->axis_values_count
= 0;
481 if (!(format
->axis_values
= heap_calloc(num_values
, sizeof(*axis_values
))))
482 return E_OUTOFMEMORY
;
483 memcpy(format
->axis_values
, axis_values
, num_values
* sizeof(*axis_values
));
484 format
->axis_values_count
= num_values
;
490 static HRESULT
format_get_font_axisvalues(struct dwrite_textformat_data
*format
,
491 DWRITE_FONT_AXIS_VALUE
*axis_values
, unsigned int num_values
)
493 if (!format
->axis_values_count
)
495 if (num_values
) memset(axis_values
, 0, num_values
* sizeof(*axis_values
));
499 if (num_values
< format
->axis_values_count
)
500 return E_NOT_SUFFICIENT_BUFFER
;
502 memcpy(axis_values
, format
->axis_values
, min(num_values
, format
->axis_values_count
) * sizeof(*axis_values
));
507 static HRESULT
get_fontfallback_from_format(const struct dwrite_textformat_data
*format
, IDWriteFontFallback
**fallback
)
509 *fallback
= format
->fallback
;
511 IDWriteFontFallback_AddRef(*fallback
);
515 static HRESULT
set_fontfallback_for_format(struct dwrite_textformat_data
*format
, IDWriteFontFallback
*fallback
)
517 if (format
->fallback
)
518 IDWriteFontFallback_Release(format
->fallback
);
519 format
->fallback
= fallback
;
521 IDWriteFontFallback_AddRef(fallback
);
525 static HRESULT
format_set_optical_alignment(struct dwrite_textformat_data
*format
,
526 DWRITE_OPTICAL_ALIGNMENT alignment
)
528 if ((UINT32
)alignment
> DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS
)
530 format
->optical_alignment
= alignment
;
534 static HRESULT
format_set_vertical_orientation(struct dwrite_textformat_data
*format
,
535 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
, BOOL
*changed
)
537 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
541 *changed
= format
->vertical_orientation
!= orientation
;
543 format
->vertical_orientation
= orientation
;
547 static BOOL
is_run_rtl(const struct layout_effective_run
*run
)
549 return run
->run
->u
.regular
.run
.bidiLevel
& 1;
552 static HRESULT
alloc_layout_run(enum layout_run_kind kind
, unsigned int start_position
,
553 struct layout_run
**run
)
555 if (!(*run
= heap_alloc_zero(sizeof(**run
))))
556 return E_OUTOFMEMORY
;
559 (*run
)->start_position
= start_position
;
564 static void free_layout_runs(struct dwrite_textlayout
*layout
)
566 struct layout_run
*cur
, *cur2
;
567 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->runs
, struct layout_run
, entry
) {
568 list_remove(&cur
->entry
);
569 if (cur
->kind
== LAYOUT_RUN_REGULAR
) {
570 if (cur
->u
.regular
.run
.fontFace
)
571 IDWriteFontFace_Release(cur
->u
.regular
.run
.fontFace
);
572 heap_free(cur
->u
.regular
.glyphs
);
573 heap_free(cur
->u
.regular
.clustermap
);
574 heap_free(cur
->u
.regular
.advances
);
575 heap_free(cur
->u
.regular
.offsets
);
581 static void free_layout_eruns(struct dwrite_textlayout
*layout
)
583 struct layout_effective_inline
*in
, *in2
;
584 struct layout_effective_run
*cur
, *cur2
;
585 struct layout_strikethrough
*s
, *s2
;
586 struct layout_underline
*u
, *u2
;
588 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->eruns
, struct layout_effective_run
, entry
) {
589 list_remove(&cur
->entry
);
590 heap_free(cur
->clustermap
);
594 LIST_FOR_EACH_ENTRY_SAFE(in
, in2
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
) {
595 list_remove(&in
->entry
);
599 LIST_FOR_EACH_ENTRY_SAFE(u
, u2
, &layout
->underlines
, struct layout_underline
, entry
) {
600 list_remove(&u
->entry
);
604 LIST_FOR_EACH_ENTRY_SAFE(s
, s2
, &layout
->strikethrough
, struct layout_strikethrough
, entry
) {
605 list_remove(&s
->entry
);
610 /* Used to resolve break condition by forcing stronger condition over weaker. */
611 static inline DWRITE_BREAK_CONDITION
override_break_condition(DWRITE_BREAK_CONDITION existingbreak
, DWRITE_BREAK_CONDITION newbreak
)
613 switch (existingbreak
) {
614 case DWRITE_BREAK_CONDITION_NEUTRAL
:
616 case DWRITE_BREAK_CONDITION_CAN_BREAK
:
617 return newbreak
== DWRITE_BREAK_CONDITION_NEUTRAL
? existingbreak
: newbreak
;
618 /* let's keep stronger conditions as is */
619 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
:
620 case DWRITE_BREAK_CONDITION_MUST_BREAK
:
623 ERR("unknown break condition %d\n", existingbreak
);
626 return existingbreak
;
629 /* This helper should be used to get effective range length, in other words it returns number of text
630 positions from range starting point to the end of the range, limited by layout text length */
631 static inline UINT32
get_clipped_range_length(const struct dwrite_textlayout
*layout
, const struct layout_range
*range
)
633 if (range
->h
.range
.startPosition
+ range
->h
.range
.length
<= layout
->len
)
634 return range
->h
.range
.length
;
635 return layout
->len
- range
->h
.range
.startPosition
;
638 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
639 static HRESULT
layout_update_breakpoints_range(struct dwrite_textlayout
*layout
, const struct layout_range
*cur
)
641 DWRITE_BREAK_CONDITION before
, after
;
645 /* ignore returned conditions if failed */
646 hr
= IDWriteInlineObject_GetBreakConditions(cur
->object
, &before
, &after
);
648 after
= before
= DWRITE_BREAK_CONDITION_NEUTRAL
;
650 if (!layout
->actual_breakpoints
) {
651 layout
->actual_breakpoints
= heap_calloc(layout
->len
, sizeof(*layout
->actual_breakpoints
));
652 if (!layout
->actual_breakpoints
)
653 return E_OUTOFMEMORY
;
654 memcpy(layout
->actual_breakpoints
, layout
->nominal_breakpoints
, sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
657 length
= get_clipped_range_length(layout
, cur
);
658 for (i
= cur
->h
.range
.startPosition
; i
< length
+ cur
->h
.range
.startPosition
; i
++) {
659 /* for first codepoint check if there's anything before it and update accordingly */
660 if (i
== cur
->h
.range
.startPosition
) {
662 layout
->actual_breakpoints
[i
].breakConditionBefore
= layout
->actual_breakpoints
[i
-1].breakConditionAfter
=
663 override_break_condition(layout
->actual_breakpoints
[i
-1].breakConditionAfter
, before
);
665 layout
->actual_breakpoints
[i
].breakConditionBefore
= before
;
666 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
668 /* similar check for last codepoint */
669 else if (i
== cur
->h
.range
.startPosition
+ length
- 1) {
670 if (i
== layout
->len
- 1)
671 layout
->actual_breakpoints
[i
].breakConditionAfter
= after
;
673 layout
->actual_breakpoints
[i
].breakConditionAfter
= layout
->actual_breakpoints
[i
+1].breakConditionBefore
=
674 override_break_condition(layout
->actual_breakpoints
[i
+1].breakConditionBefore
, after
);
675 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
677 /* for all positions within a range disable breaks */
679 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
680 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
683 layout
->actual_breakpoints
[i
].isWhitespace
= 0;
684 layout
->actual_breakpoints
[i
].isSoftHyphen
= 0;
690 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
692 struct layout_range
*cur
;
694 LIST_FOR_EACH_ENTRY(cur
, &layout
->ranges
, struct layout_range
, h
.entry
)
696 DWRITE_TEXT_RANGE
*r
= &cur
->h
.range
;
697 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
704 static struct layout_range_header
*get_layout_range_header_by_pos(struct list
*ranges
, UINT32 pos
)
706 struct layout_range_header
*cur
;
708 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
)
710 DWRITE_TEXT_RANGE
*r
= &cur
->range
;
711 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
718 static inline DWRITE_LINE_BREAKPOINT
get_effective_breakpoint(const struct dwrite_textlayout
*layout
, UINT32 pos
)
720 if (layout
->actual_breakpoints
)
721 return layout
->actual_breakpoints
[pos
];
722 return layout
->nominal_breakpoints
[pos
];
725 static inline void init_cluster_metrics(const struct dwrite_textlayout
*layout
, const struct regular_layout_run
*run
,
726 UINT16 start_glyph
, UINT16 stop_glyph
, UINT32 stop_position
, UINT16 length
, DWRITE_CLUSTER_METRICS
*metrics
)
728 UINT8 breakcondition
;
732 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
733 width as well; advances are already computed at this point and are not necessary zero. */
734 metrics
->width
= 0.0f
;
735 if (run
->run
.glyphCount
) {
736 for (j
= start_glyph
; j
< stop_glyph
; j
++)
737 metrics
->width
+= run
->run
.glyphAdvances
[j
];
739 metrics
->length
= length
;
741 position
= run
->descr
.textPosition
+ stop_position
;
742 if (stop_glyph
== run
->glyphcount
)
743 breakcondition
= get_effective_breakpoint(layout
, position
).breakConditionAfter
;
745 breakcondition
= get_effective_breakpoint(layout
, position
).breakConditionBefore
;
746 if (stop_position
) position
-= 1;
749 metrics
->canWrapLineAfter
= breakcondition
== DWRITE_BREAK_CONDITION_CAN_BREAK
||
750 breakcondition
== DWRITE_BREAK_CONDITION_MUST_BREAK
;
751 if (metrics
->length
== 1) {
752 DWRITE_LINE_BREAKPOINT bp
= get_effective_breakpoint(layout
, position
);
753 metrics
->isWhitespace
= bp
.isWhitespace
;
754 metrics
->isNewline
= metrics
->canWrapLineAfter
&& lb_is_newline_char(layout
->str
[position
]);
755 metrics
->isSoftHyphen
= bp
.isSoftHyphen
;
758 metrics
->isWhitespace
= 0;
759 metrics
->isNewline
= 0;
760 metrics
->isSoftHyphen
= 0;
762 metrics
->isRightToLeft
= run
->run
.bidiLevel
& 1;
763 metrics
->padding
= 0;
768 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
769 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
770 Note that there's no need to reallocate anything at this point as we allocate one cluster per
774 static void layout_set_cluster_metrics(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32
*cluster
)
776 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[*cluster
];
777 struct layout_cluster
*c
= &layout
->clusters
[*cluster
];
778 const struct regular_layout_run
*run
= &r
->u
.regular
;
781 assert(r
->kind
== LAYOUT_RUN_REGULAR
);
783 for (i
= 0; i
< run
->descr
.stringLength
; i
++) {
784 BOOL end
= i
== run
->descr
.stringLength
- 1;
786 if (run
->descr
.clusterMap
[start
] != run
->descr
.clusterMap
[i
]) {
787 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->descr
.clusterMap
[i
], i
,
799 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->glyphcount
, i
,
800 i
- start
+ 1, metrics
);
810 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
812 static void layout_get_font_metrics(struct dwrite_textlayout
*layout
, IDWriteFontFace
*fontface
, FLOAT emsize
,
813 DWRITE_FONT_METRICS
*fontmetrics
)
815 if (is_layout_gdi_compatible(layout
)) {
816 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(fontface
, emsize
, layout
->ppdip
, &layout
->transform
, fontmetrics
);
818 WARN("failed to get compat metrics, 0x%08x\n", hr
);
821 IDWriteFontFace_GetMetrics(fontface
, fontmetrics
);
824 static void layout_get_font_height(FLOAT emsize
, DWRITE_FONT_METRICS
*fontmetrics
, FLOAT
*baseline
, FLOAT
*height
)
826 *baseline
= SCALE_FONT_METRIC(fontmetrics
->ascent
+ fontmetrics
->lineGap
, emsize
, fontmetrics
);
827 *height
= SCALE_FONT_METRIC(fontmetrics
->ascent
+ fontmetrics
->descent
+ fontmetrics
->lineGap
, emsize
, fontmetrics
);
830 static HRESULT
layout_itemize(struct dwrite_textlayout
*layout
)
832 IDWriteTextAnalyzer2
*analyzer
;
833 struct layout_range
*range
;
834 struct layout_run
*r
;
837 analyzer
= get_text_analyzer();
839 LIST_FOR_EACH_ENTRY(range
, &layout
->ranges
, struct layout_range
, h
.entry
) {
840 /* We don't care about ranges that don't contain any text. */
841 if (range
->h
.range
.startPosition
>= layout
->len
)
844 /* Inline objects override actual text in range. */
846 hr
= layout_update_breakpoints_range(layout
, range
);
850 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_INLINE
, range
->h
.range
.startPosition
, &r
)))
853 r
->u
.object
.object
= range
->object
;
854 r
->u
.object
.length
= get_clipped_range_length(layout
, range
);
855 list_add_tail(&layout
->runs
, &r
->entry
);
859 /* Initial splitting by script. */
860 hr
= IDWriteTextAnalyzer2_AnalyzeScript(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
861 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
),
862 (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
866 /* Splitting further by bidi levels. */
867 hr
= IDWriteTextAnalyzer2_AnalyzeBidi(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
868 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
),
869 (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
877 static HRESULT
layout_resolve_fonts(struct dwrite_textlayout
*layout
)
879 IDWriteFontCollection
*sys_collection
;
880 IDWriteFontFallback
*fallback
= NULL
;
881 struct layout_range
*range
;
882 struct layout_run
*r
;
885 if (FAILED(hr
= IDWriteFactory5_GetSystemFontCollection((IDWriteFactory5
*)layout
->factory
, FALSE
,
886 (IDWriteFontCollection1
**)&sys_collection
, FALSE
))) {
887 WARN("Failed to get system collection, hr %#x.\n", hr
);
891 if (layout
->format
.fallback
) {
892 fallback
= layout
->format
.fallback
;
893 IDWriteFontFallback_AddRef(fallback
);
896 if (FAILED(hr
= IDWriteFactory7_GetSystemFontFallback(layout
->factory
, &fallback
))) {
897 WARN("Failed to get system fallback, hr %#x.\n", hr
);
902 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
903 struct regular_layout_run
*run
= &r
->u
.regular
;
907 if (r
->kind
== LAYOUT_RUN_INLINE
)
910 range
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
);
912 if (run
->sa
.shapes
== DWRITE_SCRIPT_SHAPES_NO_VISUAL
) {
913 IDWriteFontCollection
*collection
;
915 collection
= range
->collection
? range
->collection
: sys_collection
;
917 if (FAILED(hr
= create_matching_font(collection
, range
->fontfamily
, range
->weight
, range
->style
,
918 range
->stretch
, &font
))) {
919 WARN("%s: failed to create matching font for non visual run, family %s, collection %p\n",
920 debugstr_rundescr(&run
->descr
), debugstr_w(range
->fontfamily
), range
->collection
);
924 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
925 IDWriteFont_Release(font
);
927 WARN("Failed to create font face, hr %#x.\n", hr
);
931 run
->run
.fontEmSize
= range
->fontsize
;
935 length
= run
->descr
.stringLength
;
938 UINT32 mapped_length
;
943 hr
= IDWriteFontFallback_MapCharacters(fallback
,
944 (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
945 run
->descr
.textPosition
,
946 run
->descr
.stringLength
,
956 WARN("%s: failed to map family %s, collection %p, hr %#x.\n", debugstr_rundescr(&run
->descr
),
957 debugstr_w(range
->fontfamily
), range
->collection
, hr
);
961 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
962 IDWriteFont_Release(font
);
964 WARN("Failed to create font face, hr %#x.\n", hr
);
968 run
->run
.fontEmSize
= range
->fontsize
* scale
;
970 if (mapped_length
< length
)
972 struct regular_layout_run
*nextrun
;
973 struct layout_run
*nextr
;
975 /* keep mapped part for current run, add another run for the rest */
976 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_REGULAR
, 0, &nextr
)))
980 nextr
->start_position
= run
->descr
.textPosition
+ mapped_length
;
981 nextrun
= &nextr
->u
.regular
;
982 nextrun
->descr
.textPosition
= nextr
->start_position
;
983 nextrun
->descr
.stringLength
= run
->descr
.stringLength
- mapped_length
;
984 nextrun
->descr
.string
= &layout
->str
[nextrun
->descr
.textPosition
];
985 run
->descr
.stringLength
= mapped_length
;
986 list_add_after(&r
->entry
, &nextr
->entry
);
990 length
-= mapped_length
;
995 IDWriteFontCollection_Release(sys_collection
);
997 IDWriteFontFallback_Release(fallback
);
1002 struct shaping_context
1004 IDWriteTextAnalyzer2
*analyzer
;
1005 struct regular_layout_run
*run
;
1006 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
;
1007 DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
;
1011 DWRITE_TYPOGRAPHIC_FEATURES
**features
;
1012 unsigned int *range_lengths
;
1013 unsigned int range_count
;
1017 static void layout_shape_clear_user_features_context(struct shaping_context
*context
)
1021 for (i
= 0; i
< context
->user_features
.range_count
; ++i
)
1023 heap_free(context
->user_features
.features
[i
]->features
);
1024 heap_free(context
->user_features
.features
[i
]);
1026 heap_free(context
->user_features
.features
);
1027 memset(&context
->user_features
, 0, sizeof(context
->user_features
));
1030 static void layout_shape_clear_context(struct shaping_context
*context
)
1032 layout_shape_clear_user_features_context(context
);
1033 heap_free(context
->glyph_props
);
1034 heap_free(context
->text_props
);
1037 static HRESULT
layout_shape_add_empty_user_features_range(struct shaping_context
*context
, unsigned int length
)
1039 DWRITE_TYPOGRAPHIC_FEATURES
*features
;
1040 unsigned int r
= context
->user_features
.range_count
;
1042 if (!(context
->user_features
.features
[r
] = heap_alloc_zero(sizeof(*features
))))
1043 return E_OUTOFMEMORY
;
1045 context
->user_features
.range_lengths
[r
] = length
;
1046 context
->user_features
.range_count
++;
1051 static HRESULT
layout_shape_get_user_features(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
1053 unsigned int i
, f
, start
= 0, r
, covered_length
= 0, length
, feature_count
;
1054 struct regular_layout_run
*run
= context
->run
;
1055 DWRITE_TYPOGRAPHIC_FEATURES
*features
;
1056 struct layout_range_iface
*range
;
1057 IDWriteTypography
*typography
;
1058 HRESULT hr
= E_OUTOFMEMORY
;
1060 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->typographies
, 0);
1061 if (range
->h
.range
.length
>= run
->descr
.stringLength
&& !range
->iface
)
1064 if (!(context
->user_features
.features
= heap_calloc(run
->descr
.stringLength
, sizeof(*context
->user_features
.features
))))
1066 if (!(context
->user_features
.range_lengths
= heap_calloc(run
->descr
.stringLength
, sizeof(*context
->user_features
.range_lengths
))))
1069 for (i
= run
->descr
.textPosition
; i
< run
->descr
.textPosition
+ run
->descr
.stringLength
; ++i
)
1071 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->typographies
, i
);
1072 if (!range
|| !range
->iface
) continue;
1074 typography
= (IDWriteTypography
*)range
->iface
;
1075 feature_count
= IDWriteTypography_GetFontFeatureCount(typography
);
1078 i
= range
->h
.range
.length
- i
+ 1;
1084 if (FAILED(hr
= layout_shape_add_empty_user_features_range(context
, i
- start
))) goto failed
;
1085 covered_length
+= i
- start
;
1086 start
+= range
->h
.range
.length
;
1089 r
= context
->user_features
.range_count
;
1090 if (!(features
= context
->user_features
.features
[r
] = heap_alloc(sizeof(*features
))))
1093 context
->user_features
.range_lengths
[r
] = length
= min(run
->descr
.textPosition
+ run
->descr
.stringLength
,
1094 range
->h
.range
.startPosition
+ range
->h
.range
.length
) - i
;
1095 features
->featureCount
= feature_count
;
1096 if (!(features
->features
= heap_calloc(feature_count
, sizeof(*features
->features
))))
1099 for (f
= 0; f
< feature_count
; ++f
)
1101 IDWriteTypography_GetFontFeature(typography
, f
, &features
->features
[f
]);
1105 covered_length
+= length
;
1106 context
->user_features
.range_count
++;
1109 if (context
->user_features
.range_count
&& covered_length
< run
->descr
.stringLength
)
1111 if (FAILED(hr
= layout_shape_add_empty_user_features_range(context
, run
->descr
.stringLength
- covered_length
)))
1119 if (!context
->user_features
.range_count
|| FAILED(hr
))
1120 layout_shape_clear_user_features_context(context
);
1125 static HRESULT
layout_shape_get_glyphs(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
1127 struct regular_layout_run
*run
= context
->run
;
1128 unsigned int max_count
;
1131 run
->descr
.localeName
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
)->locale
;
1132 run
->clustermap
= heap_calloc(run
->descr
.stringLength
, sizeof(*run
->clustermap
));
1133 if (!run
->clustermap
)
1134 return E_OUTOFMEMORY
;
1136 max_count
= 3 * run
->descr
.stringLength
/ 2 + 16;
1137 run
->glyphs
= heap_calloc(max_count
, sizeof(*run
->glyphs
));
1139 return E_OUTOFMEMORY
;
1141 context
->text_props
= heap_calloc(run
->descr
.stringLength
, sizeof(*context
->text_props
));
1142 context
->glyph_props
= heap_calloc(max_count
, sizeof(*context
->glyph_props
));
1143 if (!context
->text_props
|| !context
->glyph_props
)
1144 return E_OUTOFMEMORY
;
1146 if (FAILED(hr
= layout_shape_get_user_features(layout
, context
)))
1151 hr
= IDWriteTextAnalyzer2_GetGlyphs(context
->analyzer
, run
->descr
.string
, run
->descr
.stringLength
, run
->run
.fontFace
,
1152 run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
, NULL
/* FIXME */,
1153 (const DWRITE_TYPOGRAPHIC_FEATURES
**)context
->user_features
.features
, context
->user_features
.range_lengths
,
1154 context
->user_features
.range_count
, max_count
, run
->clustermap
, context
->text_props
, run
->glyphs
,
1155 context
->glyph_props
, &run
->glyphcount
);
1156 if (hr
== E_NOT_SUFFICIENT_BUFFER
)
1158 heap_free(run
->glyphs
);
1159 heap_free(context
->glyph_props
);
1163 run
->glyphs
= heap_calloc(max_count
, sizeof(*run
->glyphs
));
1164 context
->glyph_props
= heap_calloc(max_count
, sizeof(*context
->glyph_props
));
1165 if (!run
->glyphs
|| !context
->glyph_props
)
1178 WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run
->descr
), hr
);
1180 run
->run
.glyphIndices
= run
->glyphs
;
1181 run
->descr
.clusterMap
= run
->clustermap
;
1186 static struct layout_range_spacing
*layout_get_next_spacing_range(struct dwrite_textlayout
*layout
,
1187 struct layout_range_spacing
*cur
)
1189 return (struct layout_range_spacing
*)LIST_ENTRY(list_next(&layout
->spacing
, &cur
->h
.entry
),
1190 struct layout_range_header
, entry
);
1193 static HRESULT
layout_shape_apply_character_spacing(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
1195 struct regular_layout_run
*run
= context
->run
;
1196 struct layout_range_spacing
*first
= NULL
, *last
= NULL
, *cur
;
1197 unsigned int i
, length
, pos
, start
, end
, g0
, glyph_count
;
1198 struct layout_range_header
*h
;
1201 LIST_FOR_EACH_ENTRY(h
, &layout
->spacing
, struct layout_range_header
, entry
)
1203 if ((h
->range
.startPosition
>= run
->descr
.textPosition
&&
1204 h
->range
.startPosition
<= run
->descr
.textPosition
+ run
->descr
.stringLength
) ||
1205 (run
->descr
.textPosition
>= h
->range
.startPosition
&&
1206 run
->descr
.textPosition
<= h
->range
.startPosition
+ h
->range
.length
))
1208 if (!first
) first
= last
= (struct layout_range_spacing
*)h
;
1210 else if (last
) break;
1212 if (!first
) return S_OK
;
1214 if (!(clustermap
= heap_calloc(run
->descr
.stringLength
, sizeof(*clustermap
)))) return E_OUTOFMEMORY
;
1216 pos
= run
->descr
.textPosition
;
1218 for (cur
= first
;; cur
= layout_get_next_spacing_range(layout
, cur
))
1220 float leading
, trailing
;
1222 /* The range current spacing settings apply to. */
1223 start
= max(pos
, cur
->h
.range
.startPosition
);
1224 pos
= end
= min(pos
+ run
->descr
.stringLength
, cur
->h
.range
.startPosition
+ cur
->h
.range
.length
);
1226 /* Back to run-relative index. */
1227 start
-= run
->descr
.textPosition
;
1228 end
-= run
->descr
.textPosition
;
1230 length
= end
- start
;
1232 g0
= run
->descr
.clusterMap
[start
];
1234 for (i
= 0; i
< length
; ++i
)
1235 clustermap
[i
] = run
->descr
.clusterMap
[start
+ i
] - run
->descr
.clusterMap
[start
];
1237 glyph_count
= (end
< run
->descr
.stringLength
? run
->descr
.clusterMap
[end
] + 1 : run
->glyphcount
) - g0
;
1239 /* There is no direction argument for spacing interface, we have to swap arguments here to get desired output. */
1240 if (run
->run
.bidiLevel
& 1)
1242 leading
= cur
->trailing
;
1243 trailing
= cur
->leading
;
1247 leading
= cur
->leading
;
1248 trailing
= cur
->trailing
;
1250 IDWriteTextAnalyzer2_ApplyCharacterSpacing(context
->analyzer
, leading
, trailing
, cur
->min_advance
,
1251 length
, glyph_count
, clustermap
, &run
->advances
[g0
], &run
->offsets
[g0
], &context
->glyph_props
[g0
],
1252 &run
->advances
[g0
], &run
->offsets
[g0
]);
1254 if (cur
== last
) break;
1257 heap_free(clustermap
);
1262 static HRESULT
layout_shape_get_positions(struct dwrite_textlayout
*layout
, struct shaping_context
*context
)
1264 struct regular_layout_run
*run
= context
->run
;
1267 run
->advances
= heap_calloc(run
->glyphcount
, sizeof(*run
->advances
));
1268 run
->offsets
= heap_calloc(run
->glyphcount
, sizeof(*run
->offsets
));
1269 if (!run
->advances
|| !run
->offsets
)
1270 return E_OUTOFMEMORY
;
1272 /* Get advances and offsets. */
1273 if (is_layout_gdi_compatible(layout
))
1274 hr
= IDWriteTextAnalyzer2_GetGdiCompatibleGlyphPlacements(context
->analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
1275 context
->text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, context
->glyph_props
, run
->glyphcount
,
1276 run
->run
.fontFace
, run
->run
.fontEmSize
, layout
->ppdip
, &layout
->transform
,
1277 layout
->measuringmode
== DWRITE_MEASURING_MODE_GDI_NATURAL
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1,
1278 &run
->sa
, run
->descr
.localeName
, (const DWRITE_TYPOGRAPHIC_FEATURES
**)context
->user_features
.features
,
1279 context
->user_features
.range_lengths
, context
->user_features
.range_count
, run
->advances
, run
->offsets
);
1281 hr
= IDWriteTextAnalyzer2_GetGlyphPlacements(context
->analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
1282 context
->text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, context
->glyph_props
, run
->glyphcount
,
1283 run
->run
.fontFace
, run
->run
.fontEmSize
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
,
1284 run
->descr
.localeName
, (const DWRITE_TYPOGRAPHIC_FEATURES
**)context
->user_features
.features
,
1285 context
->user_features
.range_lengths
, context
->user_features
.range_count
, run
->advances
, run
->offsets
);
1289 memset(run
->advances
, 0, run
->glyphcount
* sizeof(*run
->advances
));
1290 memset(run
->offsets
, 0, run
->glyphcount
* sizeof(*run
->offsets
));
1291 WARN("%s: failed to get glyph placement info, hr %#x.\n", debugstr_rundescr(&run
->descr
), hr
);
1295 hr
= layout_shape_apply_character_spacing(layout
, context
);
1297 run
->run
.glyphAdvances
= run
->advances
;
1298 run
->run
.glyphOffsets
= run
->offsets
;
1303 static HRESULT
layout_shape_run(struct dwrite_textlayout
*layout
, struct regular_layout_run
*run
)
1305 struct shaping_context context
= { 0 };
1308 context
.analyzer
= get_text_analyzer();
1311 if (SUCCEEDED(hr
= layout_shape_get_glyphs(layout
, &context
)))
1312 hr
= layout_shape_get_positions(layout
, &context
);
1314 layout_shape_clear_context(&context
);
1316 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1317 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero
1319 if (run
->sa
.shapes
== DWRITE_SCRIPT_SHAPES_NO_VISUAL
)
1320 run
->run
.glyphCount
= 0;
1322 run
->run
.glyphCount
= run
->glyphcount
;
1327 static HRESULT
layout_compute_runs(struct dwrite_textlayout
*layout
)
1329 struct layout_run
*r
;
1333 free_layout_eruns(layout
);
1334 free_layout_runs(layout
);
1336 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
1337 if (!layout
->clustermetrics
&& layout
->len
) {
1338 layout
->clustermetrics
= heap_calloc(layout
->len
, sizeof(*layout
->clustermetrics
));
1339 layout
->clusters
= heap_calloc(layout
->len
, sizeof(*layout
->clusters
));
1340 if (!layout
->clustermetrics
|| !layout
->clusters
) {
1341 heap_free(layout
->clustermetrics
);
1342 heap_free(layout
->clusters
);
1343 return E_OUTOFMEMORY
;
1346 layout
->cluster_count
= 0;
1348 if (FAILED(hr
= layout_itemize(layout
))) {
1349 WARN("Itemization failed, hr %#x.\n", hr
);
1353 if (FAILED(hr
= layout_resolve_fonts(layout
))) {
1354 WARN("Failed to resolve layout fonts, hr %#x.\n", hr
);
1359 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
1360 struct regular_layout_run
*run
= &r
->u
.regular
;
1361 DWRITE_FONT_METRICS fontmetrics
= { 0 };
1363 /* we need to do very little in case of inline objects */
1364 if (r
->kind
== LAYOUT_RUN_INLINE
) {
1365 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[cluster
];
1366 struct layout_cluster
*c
= &layout
->clusters
[cluster
];
1367 DWRITE_INLINE_OBJECT_METRICS inlinemetrics
;
1369 metrics
->width
= 0.0f
;
1370 metrics
->length
= r
->u
.object
.length
;
1371 metrics
->canWrapLineAfter
= 0;
1372 metrics
->isWhitespace
= 0;
1373 metrics
->isNewline
= 0;
1374 metrics
->isSoftHyphen
= 0;
1375 metrics
->isRightToLeft
= 0;
1376 metrics
->padding
= 0;
1378 c
->position
= 0; /* there's always one cluster per inline object, so 0 is valid value */
1381 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
1382 hr
= IDWriteInlineObject_GetMetrics(r
->u
.object
.object
, &inlinemetrics
);
1384 memset(&inlinemetrics
, 0, sizeof(inlinemetrics
));
1387 metrics
->width
= inlinemetrics
.width
;
1388 r
->baseline
= inlinemetrics
.baseline
;
1389 r
->height
= inlinemetrics
.height
;
1391 /* FIXME: use resolved breakpoints in this case too */
1396 if (FAILED(hr
= layout_shape_run(layout
, run
)))
1397 WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run
->descr
), hr
);
1399 /* baseline derived from font metrics */
1400 layout_get_font_metrics(layout
, run
->run
.fontFace
, run
->run
.fontEmSize
, &fontmetrics
);
1401 layout_get_font_height(run
->run
.fontEmSize
, &fontmetrics
, &r
->baseline
, &r
->height
);
1403 layout_set_cluster_metrics(layout
, r
, &cluster
);
1407 layout
->cluster_count
= cluster
;
1409 layout
->clustermetrics
[cluster
-1].canWrapLineAfter
= 1;
1415 static HRESULT
layout_compute(struct dwrite_textlayout
*layout
)
1419 if (!(layout
->recompute
& RECOMPUTE_CLUSTERS
))
1422 /* nominal breakpoints are evaluated only once, because string never changes */
1423 if (!layout
->nominal_breakpoints
)
1425 IDWriteTextAnalyzer2
*analyzer
;
1427 layout
->nominal_breakpoints
= heap_calloc(layout
->len
, sizeof(*layout
->nominal_breakpoints
));
1428 if (!layout
->nominal_breakpoints
)
1429 return E_OUTOFMEMORY
;
1431 analyzer
= get_text_analyzer();
1433 if (FAILED(hr
= IDWriteTextAnalyzer2_AnalyzeLineBreakpoints(analyzer
,
1434 (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
1435 0, layout
->len
, (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
)))
1436 WARN("Line breakpoints analysis failed, hr %#x.\n", hr
);
1439 heap_free(layout
->actual_breakpoints
);
1440 layout
->actual_breakpoints
= NULL
;
1442 hr
= layout_compute_runs(layout
);
1444 if (TRACE_ON(dwrite
)) {
1445 struct layout_run
*cur
;
1447 LIST_FOR_EACH_ENTRY(cur
, &layout
->runs
, struct layout_run
, entry
) {
1448 if (cur
->kind
== LAYOUT_RUN_INLINE
)
1449 TRACE("run inline object %p, len %u\n", cur
->u
.object
.object
, cur
->u
.object
.length
);
1451 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur
->u
.regular
.descr
.textPosition
, cur
->u
.regular
.descr
.textPosition
+
1452 cur
->u
.regular
.descr
.stringLength
-1, cur
->u
.regular
.descr
.stringLength
, cur
->u
.regular
.run
.bidiLevel
);
1456 layout
->recompute
&= ~RECOMPUTE_CLUSTERS
;
1460 static inline FLOAT
get_cluster_range_width(struct dwrite_textlayout
*layout
, UINT32 start
, UINT32 end
)
1463 for (; start
< end
; start
++)
1464 width
+= layout
->clustermetrics
[start
].width
;
1468 static inline IUnknown
*layout_get_effect_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1470 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->effects
, pos
);
1471 return ((struct layout_range_iface
*)h
)->iface
;
1474 static inline BOOL
layout_is_erun_rtl(const struct layout_effective_run
*erun
)
1476 return erun
->run
->u
.regular
.run
.bidiLevel
& 1;
1479 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1480 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1481 one of the arguments, but it also happens for decorations, so every effective run has uniform
1482 underline/strikethough/effect tuple. */
1483 struct layout_final_splitting_params
{
1489 static inline BOOL
layout_get_strikethrough_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1491 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->strike_ranges
, pos
);
1492 return ((struct layout_range_bool
*)h
)->value
;
1495 static inline BOOL
layout_get_underline_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1497 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->underline_ranges
, pos
);
1498 return ((struct layout_range_bool
*)h
)->value
;
1501 static void layout_splitting_params_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
,
1502 struct layout_final_splitting_params
*params
)
1504 params
->strikethrough
= layout_get_strikethrough_from_pos(layout
, pos
);
1505 params
->underline
= layout_get_underline_from_pos(layout
, pos
);
1506 params
->effect
= layout_get_effect_from_pos(layout
, pos
);
1509 static BOOL
is_same_splitting_params(const struct layout_final_splitting_params
*left
,
1510 const struct layout_final_splitting_params
*right
)
1512 return left
->strikethrough
== right
->strikethrough
&&
1513 left
->underline
== right
->underline
&&
1514 left
->effect
== right
->effect
;
1517 static void layout_get_erun_font_metrics(struct dwrite_textlayout
*layout
, struct layout_effective_run
*erun
,
1518 DWRITE_FONT_METRICS
*metrics
)
1520 memset(metrics
, 0, sizeof(*metrics
));
1521 if (is_layout_gdi_compatible(layout
)) {
1522 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(
1523 erun
->run
->u
.regular
.run
.fontFace
,
1524 erun
->run
->u
.regular
.run
.fontEmSize
,
1529 WARN("failed to get font metrics, 0x%08x\n", hr
);
1532 IDWriteFontFace_GetMetrics(erun
->run
->u
.regular
.run
.fontFace
, metrics
);
1535 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1536 'cluster_count' indicates how many clusters to add, including first one. */
1537 static HRESULT
layout_add_effective_run(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32 first_cluster
,
1538 UINT32 cluster_count
, UINT32 line
, FLOAT origin_x
, struct layout_final_splitting_params
*params
)
1540 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1541 UINT32 i
, start
, length
, last_cluster
;
1542 struct layout_effective_run
*run
;
1544 if (r
->kind
== LAYOUT_RUN_INLINE
) {
1545 struct layout_effective_inline
*inlineobject
;
1547 inlineobject
= heap_alloc(sizeof(*inlineobject
));
1549 return E_OUTOFMEMORY
;
1551 inlineobject
->object
= r
->u
.object
.object
;
1552 inlineobject
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1553 inlineobject
->origin
.x
= is_rtl
? origin_x
- inlineobject
->width
: origin_x
;
1554 inlineobject
->origin
.y
= 0.0f
; /* set after line is built */
1555 inlineobject
->align_dx
= 0.0f
;
1556 inlineobject
->baseline
= r
->baseline
;
1558 /* It's not clear how these two are set, possibly directionality
1559 is derived from surrounding text (replaced text could have
1560 different ranges which differ in reading direction). */
1561 inlineobject
->is_sideways
= FALSE
;
1562 inlineobject
->is_rtl
= FALSE
;
1563 inlineobject
->line
= line
;
1565 /* effect assigned from start position and on is used for inline objects */
1566 inlineobject
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[first_cluster
].position
+
1567 layout
->clusters
[first_cluster
].run
->start_position
);
1569 list_add_tail(&layout
->inlineobjects
, &inlineobject
->entry
);
1573 run
= heap_alloc(sizeof(*run
));
1575 return E_OUTOFMEMORY
;
1577 /* No need to iterate for that, use simple fact that:
1578 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1579 last_cluster
= first_cluster
+ cluster_count
- 1;
1580 length
= layout
->clusters
[last_cluster
].position
- layout
->clusters
[first_cluster
].position
+
1581 layout
->clustermetrics
[last_cluster
].length
;
1583 run
->clustermap
= heap_calloc(length
, sizeof(*run
->clustermap
));
1584 if (!run
->clustermap
) {
1586 return E_OUTOFMEMORY
;
1590 run
->start
= start
= layout
->clusters
[first_cluster
].position
;
1591 run
->length
= length
;
1592 run
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1593 memset(&run
->bbox
, 0, sizeof(run
->bbox
));
1595 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1597 if (layout_is_erun_rtl(run
) ^ is_rtl
)
1598 run
->origin
.x
= is_rtl
? origin_x
- run
->width
: origin_x
+ run
->width
;
1600 run
->origin
.x
= origin_x
;
1602 run
->origin
.y
= 0.0f
; /* set after line is built */
1603 run
->align_dx
= 0.0f
;
1606 if (r
->u
.regular
.run
.glyphCount
) {
1607 /* Trim leading and trailing clusters. */
1608 run
->glyphcount
= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
];
1609 if (start
+ length
< r
->u
.regular
.descr
.stringLength
)
1610 run
->glyphcount
-= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
+ length
];
1613 run
->glyphcount
= 0;
1615 /* cluster map needs to be shifted */
1616 for (i
= 0; i
< length
; i
++)
1617 run
->clustermap
[i
] = r
->u
.regular
.clustermap
[start
+ i
] - r
->u
.regular
.clustermap
[start
];
1619 run
->effect
= params
->effect
;
1620 run
->underlined
= params
->underline
;
1621 list_add_tail(&layout
->eruns
, &run
->entry
);
1623 /* Strikethrough style is guaranteed to be consistent within effective run,
1624 its width equals to run width, thickness and offset are derived from
1625 font metrics, rest of the values are from layout or run itself */
1626 if (params
->strikethrough
) {
1627 struct layout_strikethrough
*s
;
1628 DWRITE_FONT_METRICS metrics
;
1630 s
= heap_alloc(sizeof(*s
));
1632 return E_OUTOFMEMORY
;
1634 layout_get_erun_font_metrics(layout
, run
, &metrics
);
1635 s
->s
.width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1636 s
->s
.thickness
= SCALE_FONT_METRIC(metrics
.strikethroughThickness
, r
->u
.regular
.run
.fontEmSize
, &metrics
);
1637 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1638 s
->s
.offset
= -SCALE_FONT_METRIC(metrics
.strikethroughPosition
, r
->u
.regular
.run
.fontEmSize
, &metrics
);
1639 s
->s
.readingDirection
= layout
->format
.readingdir
;
1640 s
->s
.flowDirection
= layout
->format
.flow
;
1641 s
->s
.localeName
= r
->u
.regular
.descr
.localeName
;
1642 s
->s
.measuringMode
= layout
->measuringmode
;
1645 list_add_tail(&layout
->strikethrough
, &s
->entry
);
1651 static void layout_apply_line_spacing(struct dwrite_textlayout
*layout
, UINT32 line
)
1653 switch (layout
->format
.spacing
.method
)
1655 case DWRITE_LINE_SPACING_METHOD_DEFAULT
:
1656 layout
->lines
[line
].metrics
.height
= layout
->lines
[line
].height
;
1657 layout
->lines
[line
].metrics
.baseline
= layout
->lines
[line
].baseline
;
1659 case DWRITE_LINE_SPACING_METHOD_UNIFORM
:
1660 layout
->lines
[line
].metrics
.height
= layout
->format
.spacing
.height
;
1661 layout
->lines
[line
].metrics
.baseline
= layout
->format
.spacing
.baseline
;
1663 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
:
1664 layout
->lines
[line
].metrics
.height
= layout
->lines
[line
].height
* layout
->format
.spacing
.height
;
1665 layout
->lines
[line
].metrics
.baseline
= layout
->lines
[line
].baseline
* layout
->format
.spacing
.baseline
;
1668 ERR("Unknown spacing method %u\n", layout
->format
.spacing
.method
);
1672 static HRESULT
layout_set_line_metrics(struct dwrite_textlayout
*layout
, DWRITE_LINE_METRICS1
*metrics
)
1674 size_t i
= layout
->metrics
.lineCount
;
1676 if (!dwrite_array_reserve((void **)&layout
->lines
, &layout
->lines_size
, layout
->metrics
.lineCount
+ 1,
1677 sizeof(*layout
->lines
)))
1679 return E_OUTOFMEMORY
;
1682 layout
->lines
[i
].metrics
= *metrics
;
1683 layout
->lines
[i
].height
= metrics
->height
;
1684 layout
->lines
[i
].baseline
= metrics
->baseline
;
1686 if (layout
->format
.spacing
.method
!= DWRITE_LINE_SPACING_METHOD_DEFAULT
)
1687 layout_apply_line_spacing(layout
, i
);
1689 layout
->metrics
.lineCount
++;
1693 static inline struct layout_effective_run
*layout_get_next_erun(struct dwrite_textlayout
*layout
,
1694 const struct layout_effective_run
*cur
)
1699 e
= list_head(&layout
->eruns
);
1701 e
= list_next(&layout
->eruns
, &cur
->entry
);
1704 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1707 static inline struct layout_effective_run
*layout_get_prev_erun(struct dwrite_textlayout
*layout
,
1708 const struct layout_effective_run
*cur
)
1713 e
= list_tail(&layout
->eruns
);
1715 e
= list_prev(&layout
->eruns
, &cur
->entry
);
1718 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1721 static inline struct layout_effective_inline
*layout_get_next_inline_run(struct dwrite_textlayout
*layout
,
1722 const struct layout_effective_inline
*cur
)
1727 e
= list_head(&layout
->inlineobjects
);
1729 e
= list_next(&layout
->inlineobjects
, &cur
->entry
);
1732 return LIST_ENTRY(e
, struct layout_effective_inline
, entry
);
1735 static FLOAT
layout_get_line_width(struct dwrite_textlayout
*layout
,
1736 struct layout_effective_run
*erun
, struct layout_effective_inline
*inrun
, UINT32 line
)
1740 while (erun
&& erun
->line
== line
) {
1741 width
+= erun
->width
;
1742 erun
= layout_get_next_erun(layout
, erun
);
1747 while (inrun
&& inrun
->line
== line
) {
1748 width
+= inrun
->width
;
1749 inrun
= layout_get_next_inline_run(layout
, inrun
);
1757 static inline BOOL
should_skip_transform(const DWRITE_MATRIX
*m
, FLOAT
*det
)
1759 *det
= m
->m11
* m
->m22
- m
->m12
* m
->m21
;
1760 /* on certain conditions we can skip transform */
1761 return (!memcmp(m
, &identity
, sizeof(*m
)) || fabsf(*det
) <= 1e-10f
);
1764 static inline void layout_apply_snapping(D2D1_POINT_2F
*vec
, BOOL skiptransform
, FLOAT ppdip
,
1765 const DWRITE_MATRIX
*m
, FLOAT det
)
1767 if (!skiptransform
) {
1770 /* apply transform */
1774 vec2
.x
= m
->m11
* vec
->x
+ m
->m21
* vec
->y
+ m
->dx
;
1775 vec2
.y
= m
->m12
* vec
->x
+ m
->m22
* vec
->y
+ m
->dy
;
1778 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
1779 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
1781 /* apply inverted transform, we don't care about X component at this point */
1782 vec
->x
= (m
->m22
* vec2
.x
- m
->m21
* vec2
.y
+ m
->m21
* m
->dy
- m
->m22
* m
->dx
) / det
;
1785 vec
->y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
1789 vec
->x
= floorf(vec
->x
* ppdip
+ 0.5f
) / ppdip
;
1790 vec
->y
= floorf(vec
->y
* ppdip
+ 0.5f
) / ppdip
;
1794 static void layout_apply_leading_alignment(struct dwrite_textlayout
*layout
)
1796 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1797 struct layout_effective_inline
*inrun
;
1798 struct layout_effective_run
*erun
;
1800 erun
= layout_get_next_erun(layout
, NULL
);
1801 inrun
= layout_get_next_inline_run(layout
, NULL
);
1804 erun
->align_dx
= 0.0f
;
1805 erun
= layout_get_next_erun(layout
, erun
);
1809 inrun
->align_dx
= 0.0f
;
1810 inrun
= layout_get_next_inline_run(layout
, inrun
);
1813 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
1816 static void layout_apply_trailing_alignment(struct dwrite_textlayout
*layout
)
1818 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1819 struct layout_effective_inline
*inrun
;
1820 struct layout_effective_run
*erun
;
1823 erun
= layout_get_next_erun(layout
, NULL
);
1824 inrun
= layout_get_next_inline_run(layout
, NULL
);
1826 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1827 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1828 FLOAT shift
= layout
->metrics
.layoutWidth
- width
;
1833 while (erun
&& erun
->line
== line
) {
1834 erun
->align_dx
= shift
;
1835 erun
= layout_get_next_erun(layout
, erun
);
1838 while (inrun
&& inrun
->line
== line
) {
1839 inrun
->align_dx
= shift
;
1840 inrun
= layout_get_next_inline_run(layout
, inrun
);
1844 layout
->metrics
.left
= is_rtl
? 0.0f
: layout
->metrics
.layoutWidth
- layout
->metrics
.width
;
1847 static inline FLOAT
layout_get_centered_shift(struct dwrite_textlayout
*layout
, BOOL skiptransform
,
1848 FLOAT width
, FLOAT det
)
1850 if (is_layout_gdi_compatible(layout
)) {
1851 D2D1_POINT_2F vec
= { layout
->metrics
.layoutWidth
- width
, 0.0f
};
1852 layout_apply_snapping(&vec
, skiptransform
, layout
->ppdip
, &layout
->transform
, det
);
1853 return floorf(vec
.x
/ 2.0f
);
1856 return (layout
->metrics
.layoutWidth
- width
) / 2.0f
;
1859 static void layout_apply_centered_alignment(struct dwrite_textlayout
*layout
)
1861 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1862 struct layout_effective_inline
*inrun
;
1863 struct layout_effective_run
*erun
;
1868 erun
= layout_get_next_erun(layout
, NULL
);
1869 inrun
= layout_get_next_inline_run(layout
, NULL
);
1871 skiptransform
= should_skip_transform(&layout
->transform
, &det
);
1873 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1874 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1875 FLOAT shift
= layout_get_centered_shift(layout
, skiptransform
, width
, det
);
1880 while (erun
&& erun
->line
== line
) {
1881 erun
->align_dx
= shift
;
1882 erun
= layout_get_next_erun(layout
, erun
);
1885 while (inrun
&& inrun
->line
== line
) {
1886 inrun
->align_dx
= shift
;
1887 inrun
= layout_get_next_inline_run(layout
, inrun
);
1891 layout
->metrics
.left
= (layout
->metrics
.layoutWidth
- layout
->metrics
.width
) / 2.0f
;
1894 static void layout_apply_text_alignment(struct dwrite_textlayout
*layout
)
1896 switch (layout
->format
.textalignment
)
1898 case DWRITE_TEXT_ALIGNMENT_LEADING
:
1899 layout_apply_leading_alignment(layout
);
1901 case DWRITE_TEXT_ALIGNMENT_TRAILING
:
1902 layout_apply_trailing_alignment(layout
);
1904 case DWRITE_TEXT_ALIGNMENT_CENTER
:
1905 layout_apply_centered_alignment(layout
);
1907 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED
:
1908 FIXME("alignment %d not implemented\n", layout
->format
.textalignment
);
1915 static void layout_apply_par_alignment(struct dwrite_textlayout
*layout
)
1917 struct layout_effective_inline
*inrun
;
1918 struct layout_effective_run
*erun
;
1919 FLOAT origin_y
= 0.0f
;
1922 /* alignment mode defines origin, after that all run origins are updated
1925 switch (layout
->format
.paralign
)
1927 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR
:
1930 case DWRITE_PARAGRAPH_ALIGNMENT_FAR
:
1931 origin_y
= layout
->metrics
.layoutHeight
- layout
->metrics
.height
;
1933 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER
:
1934 origin_y
= (layout
->metrics
.layoutHeight
- layout
->metrics
.height
) / 2.0f
;
1940 layout
->metrics
.top
= origin_y
;
1942 erun
= layout_get_next_erun(layout
, NULL
);
1943 inrun
= layout_get_next_inline_run(layout
, NULL
);
1944 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++)
1946 float pos_y
= origin_y
+ layout
->lines
[line
].metrics
.baseline
;
1948 while (erun
&& erun
->line
== line
) {
1949 erun
->origin
.y
= pos_y
;
1950 erun
= layout_get_next_erun(layout
, erun
);
1953 while (inrun
&& inrun
->line
== line
) {
1954 inrun
->origin
.y
= pos_y
- inrun
->baseline
;
1955 inrun
= layout_get_next_inline_run(layout
, inrun
);
1958 origin_y
+= layout
->lines
[line
].metrics
.height
;
1962 struct layout_underline_splitting_params
{
1963 const WCHAR
*locale
; /* points to range data, no additional allocation */
1964 IUnknown
*effect
; /* does not hold another reference */
1967 static void init_u_splitting_params_from_erun(struct layout_effective_run
*erun
,
1968 struct layout_underline_splitting_params
*params
)
1970 params
->locale
= erun
->run
->u
.regular
.descr
.localeName
;
1971 params
->effect
= erun
->effect
;
1974 static BOOL
is_same_u_splitting(struct layout_underline_splitting_params
*left
,
1975 struct layout_underline_splitting_params
*right
)
1977 return left
->effect
== right
->effect
&& !wcsicmp(left
->locale
, right
->locale
);
1980 static HRESULT
layout_add_underline(struct dwrite_textlayout
*layout
, struct layout_effective_run
*first
,
1981 struct layout_effective_run
*last
)
1983 FLOAT thickness
, offset
, runheight
;
1984 struct layout_effective_run
*cur
;
1985 DWRITE_FONT_METRICS metrics
;
1987 if (first
== layout_get_prev_erun(layout
, last
)) {
1988 layout_get_erun_font_metrics(layout
, first
, &metrics
);
1989 thickness
= SCALE_FONT_METRIC(metrics
.underlineThickness
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1990 offset
= SCALE_FONT_METRIC(metrics
.underlinePosition
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1991 runheight
= SCALE_FONT_METRIC(metrics
.capHeight
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1996 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1997 calculated as weighted average, where run width acts as a weight. */
1998 thickness
= offset
= runheight
= 0.0f
;
2001 layout_get_erun_font_metrics(layout
, cur
, &metrics
);
2003 thickness
+= SCALE_FONT_METRIC(metrics
.underlineThickness
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
2004 offset
+= SCALE_FONT_METRIC(metrics
.underlinePosition
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
2005 runheight
= max(SCALE_FONT_METRIC(metrics
.capHeight
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
), runheight
);
2006 width
+= cur
->width
;
2008 cur
= layout_get_next_erun(layout
, cur
);
2009 } while (cur
!= last
);
2017 struct layout_underline_splitting_params params
, prev_params
;
2018 struct layout_effective_run
*next
, *w
;
2019 struct layout_underline
*u
;
2021 init_u_splitting_params_from_erun(cur
, &prev_params
);
2022 while ((next
= layout_get_next_erun(layout
, cur
)) != last
) {
2023 init_u_splitting_params_from_erun(next
, ¶ms
);
2024 if (!is_same_u_splitting(&prev_params
, ¶ms
))
2029 u
= heap_alloc(sizeof(*u
));
2031 return E_OUTOFMEMORY
;
2036 u
->u
.width
+= w
->width
;
2037 w
= layout_get_next_erun(layout
, w
);
2040 u
->u
.thickness
= thickness
;
2041 /* Font metrics convention is to have it negative when below baseline, for rendering
2042 however Y grows from baseline down for horizontal baseline. */
2043 u
->u
.offset
= -offset
;
2044 u
->u
.runHeight
= runheight
;
2045 u
->u
.readingDirection
= is_run_rtl(cur
) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
:
2046 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
2047 u
->u
.flowDirection
= layout
->format
.flow
;
2048 u
->u
.localeName
= cur
->run
->u
.regular
.descr
.localeName
;
2049 u
->u
.measuringMode
= layout
->measuringmode
;
2051 list_add_tail(&layout
->underlines
, &u
->entry
);
2054 } while (cur
!= last
);
2059 /* Adds zero width line, metrics are derived from font at specified text position. */
2060 static HRESULT
layout_set_dummy_line_metrics(struct dwrite_textlayout
*layout
, UINT32 pos
)
2062 DWRITE_LINE_METRICS1 metrics
= { 0 };
2063 DWRITE_FONT_METRICS fontmetrics
;
2064 struct layout_range
*range
;
2065 IDWriteFontFace
*fontface
;
2069 range
= get_layout_range_by_pos(layout
, pos
);
2070 hr
= create_matching_font(range
->collection
,
2078 hr
= IDWriteFont_CreateFontFace(font
, &fontface
);
2079 IDWriteFont_Release(font
);
2083 layout_get_font_metrics(layout
, fontface
, range
->fontsize
, &fontmetrics
);
2084 layout_get_font_height(range
->fontsize
, &fontmetrics
, &metrics
.baseline
, &metrics
.height
);
2085 IDWriteFontFace_Release(fontface
);
2087 return layout_set_line_metrics(layout
, &metrics
);
2090 static void layout_add_line(struct dwrite_textlayout
*layout
, UINT32 first_cluster
, UINT32 last_cluster
,
2093 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
2094 struct layout_final_splitting_params params
, prev_params
;
2095 DWRITE_INLINE_OBJECT_METRICS sign_metrics
= { 0 };
2096 UINT32 line
= layout
->metrics
.lineCount
, i
;
2097 DWRITE_LINE_METRICS1 metrics
= { 0 };
2098 UINT32 index
, start
, pos
= *textpos
;
2099 FLOAT descent
, trailingspacewidth
;
2100 BOOL append_trimming_run
= FALSE
;
2101 const struct layout_run
*run
;
2102 float width
= 0.0f
, origin_x
;
2105 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
2106 for (index
= last_cluster
, trailingspacewidth
= 0.0f
; index
>= first_cluster
; index
--) {
2107 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
2108 struct layout_cluster
*lc
= &layout
->clusters
[index
];
2111 /* This also filters out clusters added from inline objects, those are never
2112 treated as a white space. */
2113 if (!cluster
->isWhitespace
)
2116 /* Every isNewline cluster is also isWhitespace, but not every
2117 newline character cluster has isNewline set, so go back to original string. */
2118 ch
= lc
->run
->u
.regular
.descr
.string
[lc
->position
];
2119 if (cluster
->length
== 1 && lb_is_newline_char(ch
))
2120 metrics
.newlineLength
+= cluster
->length
;
2122 metrics
.trailingWhitespaceLength
+= cluster
->length
;
2123 trailingspacewidth
+= cluster
->width
;
2129 /* Line metrics length includes trailing whitespace length too */
2130 for (i
= first_cluster
; i
<= last_cluster
; i
++)
2131 metrics
.length
+= layout
->clustermetrics
[i
].length
;
2133 /* Ignore trailing whitespaces */
2134 while (last_cluster
> first_cluster
) {
2135 if (!layout
->clustermetrics
[last_cluster
].isWhitespace
)
2141 /* Does not include trailing space width */
2142 if (!layout
->clustermetrics
[last_cluster
].isWhitespace
)
2143 width
= get_cluster_range_width(layout
, first_cluster
, last_cluster
+ 1);
2145 /* Append trimming run if necessary */
2146 if (width
> layout
->metrics
.layoutWidth
&& layout
->format
.trimmingsign
!= NULL
&&
2147 layout
->format
.trimming
.granularity
!= DWRITE_TRIMMING_GRANULARITY_NONE
) {
2148 FLOAT trimmed_width
= width
;
2150 hr
= IDWriteInlineObject_GetMetrics(layout
->format
.trimmingsign
, &sign_metrics
);
2151 if (SUCCEEDED(hr
)) {
2152 while (last_cluster
> first_cluster
) {
2153 if (trimmed_width
+ sign_metrics
.width
<= layout
->metrics
.layoutWidth
)
2155 if (layout
->format
.trimming
.granularity
== DWRITE_TRIMMING_GRANULARITY_CHARACTER
)
2156 trimmed_width
-= layout
->clustermetrics
[last_cluster
--].width
;
2158 while (last_cluster
> first_cluster
) {
2159 trimmed_width
-= layout
->clustermetrics
[last_cluster
].width
;
2160 if (layout
->clustermetrics
[last_cluster
--].canWrapLineAfter
)
2165 append_trimming_run
= TRUE
;
2168 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#x.\n", hr
);
2170 width
= trimmed_width
+ sign_metrics
.width
;
2173 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
2174 prev_params
= params
;
2175 run
= layout
->clusters
[first_cluster
].run
;
2177 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
2178 origin_x
= is_rtl
? layout
->metrics
.layoutWidth
: 0.0f
;
2179 for (start
= first_cluster
, i
= first_cluster
; i
<= last_cluster
; i
++) {
2180 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
2182 if (run
!= layout
->clusters
[i
].run
|| !is_same_splitting_params(&prev_params
, ¶ms
)) {
2183 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
2187 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) :
2188 get_cluster_range_width(layout
, start
, i
);
2189 run
= layout
->clusters
[i
].run
;
2193 prev_params
= params
;
2194 pos
+= layout
->clustermetrics
[i
].length
;
2197 /* Final run from what's left from cluster range */
2198 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
2202 if (get_cluster_range_width(layout
, start
, i
) + sign_metrics
.width
> layout
->metrics
.layoutWidth
)
2203 append_trimming_run
= FALSE
;
2205 if (append_trimming_run
) {
2206 struct layout_effective_inline
*trimming_sign
;
2208 trimming_sign
= heap_alloc(sizeof(*trimming_sign
));
2212 trimming_sign
->object
= layout
->format
.trimmingsign
;
2213 trimming_sign
->width
= sign_metrics
.width
;
2214 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) : get_cluster_range_width(layout
, start
, i
);
2215 trimming_sign
->origin
.x
= is_rtl
? origin_x
- trimming_sign
->width
: origin_x
;
2216 trimming_sign
->origin
.y
= 0.0f
; /* set after line is built */
2217 trimming_sign
->align_dx
= 0.0f
;
2218 trimming_sign
->baseline
= sign_metrics
.baseline
;
2220 trimming_sign
->is_sideways
= FALSE
;
2221 trimming_sign
->is_rtl
= FALSE
;
2222 trimming_sign
->line
= line
;
2224 trimming_sign
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[i
].position
+
2225 layout
->clusters
[i
].run
->start_position
);
2227 list_add_tail(&layout
->inlineobjects
, &trimming_sign
->entry
);
2230 /* Look for max baseline and descent for this line */
2231 for (index
= first_cluster
, metrics
.baseline
= 0.0f
, descent
= 0.0f
; index
<= last_cluster
; index
++) {
2232 const struct layout_run
*cur
= layout
->clusters
[index
].run
;
2233 FLOAT cur_descent
= cur
->height
- cur
->baseline
;
2235 if (cur
->baseline
> metrics
.baseline
)
2236 metrics
.baseline
= cur
->baseline
;
2237 if (cur_descent
> descent
)
2238 descent
= cur_descent
;
2241 layout
->metrics
.width
= max(width
, layout
->metrics
.width
);
2242 layout
->metrics
.widthIncludingTrailingWhitespace
= max(width
+ trailingspacewidth
,
2243 layout
->metrics
.widthIncludingTrailingWhitespace
);
2245 metrics
.height
= descent
+ metrics
.baseline
;
2246 metrics
.isTrimmed
= append_trimming_run
|| width
> layout
->metrics
.layoutWidth
;
2247 layout_set_line_metrics(layout
, &metrics
);
2249 *textpos
+= metrics
.length
;
2252 static void layout_set_line_positions(struct dwrite_textlayout
*layout
)
2254 struct layout_effective_inline
*inrun
;
2255 struct layout_effective_run
*erun
;
2259 /* Now all line info is here, update effective runs positions in flow direction */
2260 erun
= layout_get_next_erun(layout
, NULL
);
2261 inrun
= layout_get_next_inline_run(layout
, NULL
);
2263 for (line
= 0, origin_y
= 0.0f
; line
< layout
->metrics
.lineCount
; line
++)
2265 float pos_y
= origin_y
+ layout
->lines
[line
].metrics
.baseline
;
2267 /* For all runs on this line */
2268 while (erun
&& erun
->line
== line
) {
2269 erun
->origin
.y
= pos_y
;
2270 erun
= layout_get_next_erun(layout
, erun
);
2273 /* Same for inline runs */
2274 while (inrun
&& inrun
->line
== line
) {
2275 inrun
->origin
.y
= pos_y
- inrun
->baseline
;
2276 inrun
= layout_get_next_inline_run(layout
, inrun
);
2279 origin_y
+= layout
->lines
[line
].metrics
.height
;
2282 layout
->metrics
.height
= origin_y
;
2284 /* Initial paragraph alignment is always near */
2285 if (layout
->format
.paralign
!= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
)
2286 layout_apply_par_alignment(layout
);
2289 static BOOL
layout_can_wrap_after(const struct dwrite_textlayout
*layout
, UINT32 cluster
)
2291 if (layout
->format
.wrapping
== DWRITE_WORD_WRAPPING_CHARACTER
)
2294 return layout
->clustermetrics
[cluster
].canWrapLineAfter
;
2297 static HRESULT
layout_compute_effective_runs(struct dwrite_textlayout
*layout
)
2299 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
2300 struct layout_effective_run
*erun
, *first_underlined
;
2301 UINT32 i
, start
, textpos
, last_breaking_point
;
2302 DWRITE_LINE_METRICS1 metrics
;
2307 if (!(layout
->recompute
& RECOMPUTE_LINES
))
2310 free_layout_eruns(layout
);
2312 hr
= layout_compute(layout
);
2316 layout
->metrics
.lineCount
= 0;
2317 memset(&metrics
, 0, sizeof(metrics
));
2319 layout
->metrics
.height
= 0.0f
;
2320 layout
->metrics
.width
= 0.0f
;
2321 layout
->metrics
.widthIncludingTrailingWhitespace
= 0.0f
;
2323 last_breaking_point
= ~0u;
2325 for (i
= 0, start
= 0, width
= 0.0f
, textpos
= 0; i
< layout
->cluster_count
; i
++) {
2326 BOOL overflow
= FALSE
;
2328 while (i
< layout
->cluster_count
&& !layout
->clustermetrics
[i
].isNewline
) {
2329 /* Check for overflow */
2330 overflow
= ((width
+ layout
->clustermetrics
[i
].width
> layout
->metrics
.layoutWidth
) &&
2331 (layout
->format
.wrapping
!= DWRITE_WORD_WRAPPING_NO_WRAP
));
2335 if (layout_can_wrap_after(layout
, i
))
2336 last_breaking_point
= i
;
2337 width
+= layout
->clustermetrics
[i
].width
;
2340 i
= min(i
, layout
->cluster_count
- 1);
2342 /* Ignore if overflown on whitespace */
2343 if (overflow
&& !(layout
->clustermetrics
[i
].isWhitespace
&& layout_can_wrap_after(layout
, i
))) {
2344 /* Use most recently found breaking point */
2345 if (last_breaking_point
!= ~0u) {
2346 i
= last_breaking_point
;
2347 last_breaking_point
= ~0u;
2350 /* Otherwise proceed forward to next newline or breaking point */
2351 for (; i
< layout
->cluster_count
; i
++)
2352 if (layout_can_wrap_after(layout
, i
) || layout
->clustermetrics
[i
].isNewline
)
2356 i
= min(i
, layout
->cluster_count
- 1);
2358 layout_add_line(layout
, start
, i
, &textpos
);
2363 /* Add dummy line if:
2364 - there's no text, metrics come from first range in this case;
2365 - last ended with a mandatory break, metrics come from last text position.
2367 if (layout
->len
== 0)
2368 hr
= layout_set_dummy_line_metrics(layout
, 0);
2369 else if (layout
->cluster_count
&& layout
->clustermetrics
[layout
->cluster_count
- 1].isNewline
)
2370 hr
= layout_set_dummy_line_metrics(layout
, layout
->len
- 1);
2374 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
2375 layout
->metrics
.top
= 0.0f
;
2376 layout
->metrics
.maxBidiReorderingDepth
= 1; /* FIXME */
2378 /* Add explicit underlined runs */
2379 erun
= layout_get_next_erun(layout
, NULL
);
2380 first_underlined
= erun
&& erun
->underlined
? erun
: NULL
;
2381 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
2382 while (erun
&& erun
->line
== line
) {
2383 erun
= layout_get_next_erun(layout
, erun
);
2385 if (first_underlined
&& (!erun
|| !erun
->underlined
)) {
2386 layout_add_underline(layout
, first_underlined
, erun
);
2387 first_underlined
= NULL
;
2389 else if (!first_underlined
&& erun
&& erun
->underlined
)
2390 first_underlined
= erun
;
2394 /* Position runs in flow direction */
2395 layout_set_line_positions(layout
);
2397 /* Initial alignment is always leading */
2398 if (layout
->format
.textalignment
!= DWRITE_TEXT_ALIGNMENT_LEADING
)
2399 layout_apply_text_alignment(layout
);
2401 layout
->recompute
&= ~RECOMPUTE_LINES
;
2405 static BOOL
is_same_layout_attrvalue(struct layout_range_header
const *h
, enum layout_range_attr_kind attr
,
2406 struct layout_range_attr_value
*value
)
2408 struct layout_range_spacing
const *range_spacing
= (struct layout_range_spacing
*)h
;
2409 struct layout_range_iface
const *range_iface
= (struct layout_range_iface
*)h
;
2410 struct layout_range_bool
const *range_bool
= (struct layout_range_bool
*)h
;
2411 struct layout_range
const *range
= (struct layout_range
*)h
;
2414 case LAYOUT_RANGE_ATTR_WEIGHT
:
2415 return range
->weight
== value
->u
.weight
;
2416 case LAYOUT_RANGE_ATTR_STYLE
:
2417 return range
->style
== value
->u
.style
;
2418 case LAYOUT_RANGE_ATTR_STRETCH
:
2419 return range
->stretch
== value
->u
.stretch
;
2420 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2421 return range
->fontsize
== value
->u
.fontsize
;
2422 case LAYOUT_RANGE_ATTR_INLINE
:
2423 return range
->object
== value
->u
.object
;
2424 case LAYOUT_RANGE_ATTR_EFFECT
:
2425 return range_iface
->iface
== value
->u
.effect
;
2426 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2427 return range_bool
->value
== value
->u
.underline
;
2428 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2429 return range_bool
->value
== value
->u
.strikethrough
;
2430 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2431 return range
->pair_kerning
== value
->u
.pair_kerning
;
2432 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2433 return range
->collection
== value
->u
.collection
;
2434 case LAYOUT_RANGE_ATTR_LOCALE
:
2435 return !wcsicmp(range
->locale
, value
->u
.locale
);
2436 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2437 return !wcscmp(range
->fontfamily
, value
->u
.fontfamily
);
2438 case LAYOUT_RANGE_ATTR_SPACING
:
2439 return range_spacing
->leading
== value
->u
.spacing
.leading
&&
2440 range_spacing
->trailing
== value
->u
.spacing
.trailing
&&
2441 range_spacing
->min_advance
== value
->u
.spacing
.min_advance
;
2442 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2443 return range_iface
->iface
== (IUnknown
*)value
->u
.typography
;
2451 static inline BOOL
is_same_layout_attributes(struct layout_range_header
const *hleft
, struct layout_range_header
const *hright
)
2453 switch (hleft
->kind
)
2455 case LAYOUT_RANGE_REGULAR
:
2457 struct layout_range
const *left
= (struct layout_range
const*)hleft
;
2458 struct layout_range
const *right
= (struct layout_range
const*)hright
;
2459 return left
->weight
== right
->weight
&&
2460 left
->style
== right
->style
&&
2461 left
->stretch
== right
->stretch
&&
2462 left
->fontsize
== right
->fontsize
&&
2463 left
->object
== right
->object
&&
2464 left
->pair_kerning
== right
->pair_kerning
&&
2465 left
->collection
== right
->collection
&&
2466 !wcsicmp(left
->locale
, right
->locale
) &&
2467 !wcscmp(left
->fontfamily
, right
->fontfamily
);
2469 case LAYOUT_RANGE_UNDERLINE
:
2470 case LAYOUT_RANGE_STRIKETHROUGH
:
2472 struct layout_range_bool
const *left
= (struct layout_range_bool
const*)hleft
;
2473 struct layout_range_bool
const *right
= (struct layout_range_bool
const*)hright
;
2474 return left
->value
== right
->value
;
2476 case LAYOUT_RANGE_EFFECT
:
2477 case LAYOUT_RANGE_TYPOGRAPHY
:
2479 struct layout_range_iface
const *left
= (struct layout_range_iface
const*)hleft
;
2480 struct layout_range_iface
const *right
= (struct layout_range_iface
const*)hright
;
2481 return left
->iface
== right
->iface
;
2483 case LAYOUT_RANGE_SPACING
:
2485 struct layout_range_spacing
const *left
= (struct layout_range_spacing
const*)hleft
;
2486 struct layout_range_spacing
const *right
= (struct layout_range_spacing
const*)hright
;
2487 return left
->leading
== right
->leading
&&
2488 left
->trailing
== right
->trailing
&&
2489 left
->min_advance
== right
->min_advance
;
2492 FIXME("unknown range kind %d\n", hleft
->kind
);
2497 static inline BOOL
is_same_text_range(const DWRITE_TEXT_RANGE
*left
, const DWRITE_TEXT_RANGE
*right
)
2499 return left
->startPosition
== right
->startPosition
&& left
->length
== right
->length
;
2502 /* Allocates range and inits it with default values from text format. */
2503 static struct layout_range_header
*alloc_layout_range(struct dwrite_textlayout
*layout
, const DWRITE_TEXT_RANGE
*r
,
2504 enum layout_range_kind kind
)
2506 struct layout_range_header
*h
;
2510 case LAYOUT_RANGE_REGULAR
:
2512 struct layout_range
*range
;
2514 range
= heap_alloc_zero(sizeof(*range
));
2515 if (!range
) return NULL
;
2517 range
->weight
= layout
->format
.weight
;
2518 range
->style
= layout
->format
.style
;
2519 range
->stretch
= layout
->format
.stretch
;
2520 range
->fontsize
= layout
->format
.fontsize
;
2522 range
->fontfamily
= heap_strdupW(layout
->format
.family_name
);
2523 if (!range
->fontfamily
)
2529 range
->collection
= layout
->format
.collection
;
2530 if (range
->collection
)
2531 IDWriteFontCollection_AddRef(range
->collection
);
2532 wcscpy(range
->locale
, layout
->format
.locale
);
2537 case LAYOUT_RANGE_UNDERLINE
:
2538 case LAYOUT_RANGE_STRIKETHROUGH
:
2540 struct layout_range_bool
*range
;
2542 range
= heap_alloc_zero(sizeof(*range
));
2543 if (!range
) return NULL
;
2548 case LAYOUT_RANGE_EFFECT
:
2549 case LAYOUT_RANGE_TYPOGRAPHY
:
2551 struct layout_range_iface
*range
;
2553 range
= heap_alloc_zero(sizeof(*range
));
2554 if (!range
) return NULL
;
2559 case LAYOUT_RANGE_SPACING
:
2561 struct layout_range_spacing
*range
;
2563 range
= heap_alloc_zero(sizeof(*range
));
2564 if (!range
) return NULL
;
2570 FIXME("unknown range kind %d\n", kind
);
2579 static struct layout_range_header
*alloc_layout_range_from(struct layout_range_header
*h
, const DWRITE_TEXT_RANGE
*r
)
2581 struct layout_range_header
*ret
;
2585 case LAYOUT_RANGE_REGULAR
:
2587 struct layout_range
*from
= (struct layout_range
*)h
;
2589 struct layout_range
*range
= heap_alloc(sizeof(*range
));
2590 if (!range
) return NULL
;
2593 range
->fontfamily
= heap_strdupW(from
->fontfamily
);
2594 if (!range
->fontfamily
) {
2599 /* update refcounts */
2601 IDWriteInlineObject_AddRef(range
->object
);
2602 if (range
->collection
)
2603 IDWriteFontCollection_AddRef(range
->collection
);
2607 case LAYOUT_RANGE_UNDERLINE
:
2608 case LAYOUT_RANGE_STRIKETHROUGH
:
2610 struct layout_range_bool
*strike
= heap_alloc(sizeof(*strike
));
2611 if (!strike
) return NULL
;
2613 *strike
= *(struct layout_range_bool
*)h
;
2617 case LAYOUT_RANGE_EFFECT
:
2618 case LAYOUT_RANGE_TYPOGRAPHY
:
2620 struct layout_range_iface
*effect
= heap_alloc(sizeof(*effect
));
2621 if (!effect
) return NULL
;
2623 *effect
= *(struct layout_range_iface
*)h
;
2625 IUnknown_AddRef(effect
->iface
);
2629 case LAYOUT_RANGE_SPACING
:
2631 struct layout_range_spacing
*spacing
= heap_alloc(sizeof(*spacing
));
2632 if (!spacing
) return NULL
;
2634 *spacing
= *(struct layout_range_spacing
*)h
;
2639 FIXME("unknown range kind %d\n", h
->kind
);
2647 static void free_layout_range(struct layout_range_header
*h
)
2654 case LAYOUT_RANGE_REGULAR
:
2656 struct layout_range
*range
= (struct layout_range
*)h
;
2659 IDWriteInlineObject_Release(range
->object
);
2660 if (range
->collection
)
2661 IDWriteFontCollection_Release(range
->collection
);
2662 heap_free(range
->fontfamily
);
2665 case LAYOUT_RANGE_EFFECT
:
2666 case LAYOUT_RANGE_TYPOGRAPHY
:
2668 struct layout_range_iface
*range
= (struct layout_range_iface
*)h
;
2670 IUnknown_Release(range
->iface
);
2680 static void free_layout_ranges_list(struct dwrite_textlayout
*layout
)
2682 struct layout_range_header
*cur
, *cur2
;
2684 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->ranges
, struct layout_range_header
, entry
) {
2685 list_remove(&cur
->entry
);
2686 free_layout_range(cur
);
2689 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->underline_ranges
, struct layout_range_header
, entry
) {
2690 list_remove(&cur
->entry
);
2691 free_layout_range(cur
);
2694 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->strike_ranges
, struct layout_range_header
, entry
) {
2695 list_remove(&cur
->entry
);
2696 free_layout_range(cur
);
2699 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->effects
, struct layout_range_header
, entry
) {
2700 list_remove(&cur
->entry
);
2701 free_layout_range(cur
);
2704 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->spacing
, struct layout_range_header
, entry
) {
2705 list_remove(&cur
->entry
);
2706 free_layout_range(cur
);
2709 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->typographies
, struct layout_range_header
, entry
) {
2710 list_remove(&cur
->entry
);
2711 free_layout_range(cur
);
2715 static struct layout_range_header
*find_outer_range(struct list
*ranges
, const DWRITE_TEXT_RANGE
*range
)
2717 struct layout_range_header
*cur
;
2719 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
2721 if (cur
->range
.startPosition
> range
->startPosition
)
2724 if ((cur
->range
.startPosition
+ cur
->range
.length
< range
->startPosition
+ range
->length
) &&
2725 (range
->startPosition
< cur
->range
.startPosition
+ cur
->range
.length
))
2727 if (cur
->range
.startPosition
+ cur
->range
.length
>= range
->startPosition
+ range
->length
)
2734 static inline BOOL
set_layout_range_iface_attr(IUnknown
**dest
, IUnknown
*value
)
2736 if (*dest
== value
) return FALSE
;
2739 IUnknown_Release(*dest
);
2742 IUnknown_AddRef(*dest
);
2747 static BOOL
set_layout_range_attrval(struct layout_range_header
*h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2749 struct layout_range_spacing
*dest_spacing
= (struct layout_range_spacing
*)h
;
2750 struct layout_range_iface
*dest_iface
= (struct layout_range_iface
*)h
;
2751 struct layout_range_bool
*dest_bool
= (struct layout_range_bool
*)h
;
2752 struct layout_range
*dest
= (struct layout_range
*)h
;
2754 BOOL changed
= FALSE
;
2757 case LAYOUT_RANGE_ATTR_WEIGHT
:
2758 changed
= dest
->weight
!= value
->u
.weight
;
2759 dest
->weight
= value
->u
.weight
;
2761 case LAYOUT_RANGE_ATTR_STYLE
:
2762 changed
= dest
->style
!= value
->u
.style
;
2763 dest
->style
= value
->u
.style
;
2765 case LAYOUT_RANGE_ATTR_STRETCH
:
2766 changed
= dest
->stretch
!= value
->u
.stretch
;
2767 dest
->stretch
= value
->u
.stretch
;
2769 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2770 changed
= dest
->fontsize
!= value
->u
.fontsize
;
2771 dest
->fontsize
= value
->u
.fontsize
;
2773 case LAYOUT_RANGE_ATTR_INLINE
:
2774 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->object
, (IUnknown
*)value
->u
.object
);
2776 case LAYOUT_RANGE_ATTR_EFFECT
:
2777 changed
= set_layout_range_iface_attr(&dest_iface
->iface
, value
->u
.effect
);
2779 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2780 changed
= dest_bool
->value
!= value
->u
.underline
;
2781 dest_bool
->value
= value
->u
.underline
;
2783 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2784 changed
= dest_bool
->value
!= value
->u
.strikethrough
;
2785 dest_bool
->value
= value
->u
.strikethrough
;
2787 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2788 changed
= dest
->pair_kerning
!= value
->u
.pair_kerning
;
2789 dest
->pair_kerning
= value
->u
.pair_kerning
;
2791 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2792 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->collection
, (IUnknown
*)value
->u
.collection
);
2794 case LAYOUT_RANGE_ATTR_LOCALE
:
2795 changed
= !!wcsicmp(dest
->locale
, value
->u
.locale
);
2798 wcscpy(dest
->locale
, value
->u
.locale
);
2799 wcslwr(dest
->locale
);
2802 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2803 changed
= !!wcscmp(dest
->fontfamily
, value
->u
.fontfamily
);
2806 heap_free(dest
->fontfamily
);
2807 dest
->fontfamily
= heap_strdupW(value
->u
.fontfamily
);
2810 case LAYOUT_RANGE_ATTR_SPACING
:
2811 changed
= dest_spacing
->leading
!= value
->u
.spacing
.leading
||
2812 dest_spacing
->trailing
!= value
->u
.spacing
.trailing
||
2813 dest_spacing
->min_advance
!= value
->u
.spacing
.min_advance
;
2814 dest_spacing
->leading
= value
->u
.spacing
.leading
;
2815 dest_spacing
->trailing
= value
->u
.spacing
.trailing
;
2816 dest_spacing
->min_advance
= value
->u
.spacing
.min_advance
;
2818 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2819 changed
= set_layout_range_iface_attr(&dest_iface
->iface
, (IUnknown
*)value
->u
.typography
);
2828 static inline BOOL
is_in_layout_range(const DWRITE_TEXT_RANGE
*outer
, const DWRITE_TEXT_RANGE
*inner
)
2830 return (inner
->startPosition
>= outer
->startPosition
) &&
2831 (inner
->startPosition
+ inner
->length
<= outer
->startPosition
+ outer
->length
);
2834 static inline HRESULT
return_range(const struct layout_range_header
*h
, DWRITE_TEXT_RANGE
*r
)
2836 if (r
) *r
= h
->range
;
2840 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2841 static HRESULT
set_layout_range_attr(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2843 struct layout_range_header
*cur
, *right
, *left
, *outer
;
2844 BOOL changed
= FALSE
;
2845 struct list
*ranges
;
2846 DWRITE_TEXT_RANGE r
;
2848 /* ignore zero length ranges */
2849 if (value
->range
.length
== 0)
2852 if (~0u - value
->range
.startPosition
< value
->range
.length
)
2853 return E_INVALIDARG
;
2855 /* select from ranges lists */
2858 case LAYOUT_RANGE_ATTR_WEIGHT
:
2859 case LAYOUT_RANGE_ATTR_STYLE
:
2860 case LAYOUT_RANGE_ATTR_STRETCH
:
2861 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2862 case LAYOUT_RANGE_ATTR_INLINE
:
2863 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2864 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2865 case LAYOUT_RANGE_ATTR_LOCALE
:
2866 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2867 ranges
= &layout
->ranges
;
2869 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2870 ranges
= &layout
->underline_ranges
;
2872 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2873 ranges
= &layout
->strike_ranges
;
2875 case LAYOUT_RANGE_ATTR_EFFECT
:
2876 ranges
= &layout
->effects
;
2878 case LAYOUT_RANGE_ATTR_SPACING
:
2879 ranges
= &layout
->spacing
;
2881 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2882 ranges
= &layout
->typographies
;
2885 FIXME("unknown attr kind %d\n", attr
);
2889 /* If new range is completely within existing range, split existing range in two */
2890 if ((outer
= find_outer_range(ranges
, &value
->range
))) {
2892 /* no need to add same range */
2893 if (is_same_layout_attrvalue(outer
, attr
, value
))
2896 /* for matching range bounds just replace data */
2897 if (is_same_text_range(&outer
->range
, &value
->range
)) {
2898 changed
= set_layout_range_attrval(outer
, attr
, value
);
2902 /* add new range to the left */
2903 if (value
->range
.startPosition
== outer
->range
.startPosition
) {
2904 left
= alloc_layout_range_from(outer
, &value
->range
);
2905 if (!left
) return E_OUTOFMEMORY
;
2907 changed
= set_layout_range_attrval(left
, attr
, value
);
2908 list_add_before(&outer
->entry
, &left
->entry
);
2909 outer
->range
.startPosition
+= value
->range
.length
;
2910 outer
->range
.length
-= value
->range
.length
;
2914 /* add new range to the right */
2915 if (value
->range
.startPosition
+ value
->range
.length
== outer
->range
.startPosition
+ outer
->range
.length
) {
2916 right
= alloc_layout_range_from(outer
, &value
->range
);
2917 if (!right
) return E_OUTOFMEMORY
;
2919 changed
= set_layout_range_attrval(right
, attr
, value
);
2920 list_add_after(&outer
->entry
, &right
->entry
);
2921 outer
->range
.length
-= value
->range
.length
;
2925 r
.startPosition
= value
->range
.startPosition
+ value
->range
.length
;
2926 r
.length
= outer
->range
.length
+ outer
->range
.startPosition
- r
.startPosition
;
2929 right
= alloc_layout_range_from(outer
, &r
);
2930 /* new range in the middle */
2931 cur
= alloc_layout_range_from(outer
, &value
->range
);
2932 if (!right
|| !cur
) {
2933 free_layout_range(right
);
2934 free_layout_range(cur
);
2935 return E_OUTOFMEMORY
;
2938 /* reuse container range as a left part */
2939 outer
->range
.length
= value
->range
.startPosition
- outer
->range
.startPosition
;
2942 set_layout_range_attrval(cur
, attr
, value
);
2944 list_add_after(&outer
->entry
, &cur
->entry
);
2945 list_add_after(&cur
->entry
, &right
->entry
);
2947 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2951 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2952 Update all of them. */
2953 left
= get_layout_range_header_by_pos(ranges
, value
->range
.startPosition
);
2954 if (left
->range
.startPosition
== value
->range
.startPosition
)
2955 changed
= set_layout_range_attrval(left
, attr
, value
);
2956 else /* need to split */ {
2957 r
.startPosition
= value
->range
.startPosition
;
2958 r
.length
= left
->range
.length
- value
->range
.startPosition
+ left
->range
.startPosition
;
2959 left
->range
.length
-= r
.length
;
2960 cur
= alloc_layout_range_from(left
, &r
);
2961 changed
= set_layout_range_attrval(cur
, attr
, value
);
2962 list_add_after(&left
->entry
, &cur
->entry
);
2964 cur
= LIST_ENTRY(list_next(ranges
, &left
->entry
), struct layout_range_header
, entry
);
2966 /* for all existing ranges covered by new one update value */
2967 while (cur
&& is_in_layout_range(&value
->range
, &cur
->range
)) {
2968 changed
|= set_layout_range_attrval(cur
, attr
, value
);
2969 cur
= LIST_ENTRY(list_next(ranges
, &cur
->entry
), struct layout_range_header
, entry
);
2972 /* it's possible rightmost range intersects */
2973 if (cur
&& (cur
->range
.startPosition
< value
->range
.startPosition
+ value
->range
.length
)) {
2974 r
.startPosition
= cur
->range
.startPosition
;
2975 r
.length
= value
->range
.startPosition
+ value
->range
.length
- cur
->range
.startPosition
;
2976 left
= alloc_layout_range_from(cur
, &r
);
2977 changed
|= set_layout_range_attrval(left
, attr
, value
);
2978 cur
->range
.startPosition
+= left
->range
.length
;
2979 cur
->range
.length
-= left
->range
.length
;
2980 list_add_before(&cur
->entry
, &left
->entry
);
2985 struct list
*next
, *i
;
2987 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2988 i
= list_head(ranges
);
2989 while ((next
= list_next(ranges
, i
))) {
2990 struct layout_range_header
*next_range
= LIST_ENTRY(next
, struct layout_range_header
, entry
);
2992 cur
= LIST_ENTRY(i
, struct layout_range_header
, entry
);
2993 if (is_same_layout_attributes(cur
, next_range
)) {
2994 /* remove similar range */
2995 cur
->range
.length
+= next_range
->range
.length
;
2997 free_layout_range(next_range
);
3000 i
= list_next(ranges
, i
);
3007 static inline const WCHAR
*get_string_attribute_ptr(struct layout_range
*range
, enum layout_range_attr_kind kind
)
3012 case LAYOUT_RANGE_ATTR_LOCALE
:
3013 str
= range
->locale
;
3015 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
3016 str
= range
->fontfamily
;
3025 static HRESULT
get_string_attribute_length(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
3026 UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3028 struct layout_range
*range
;
3031 range
= get_layout_range_by_pos(layout
, position
);
3037 str
= get_string_attribute_ptr(range
, kind
);
3038 *length
= wcslen(str
);
3039 return return_range(&range
->h
, r
);
3042 static HRESULT
get_string_attribute_value(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
3043 WCHAR
*ret
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3045 struct layout_range
*range
;
3049 return E_INVALIDARG
;
3052 range
= get_layout_range_by_pos(layout
, position
);
3054 return E_INVALIDARG
;
3056 str
= get_string_attribute_ptr(range
, kind
);
3057 if (length
< wcslen(str
) + 1)
3058 return E_NOT_SUFFICIENT_BUFFER
;
3061 return return_range(&range
->h
, r
);
3064 static HRESULT WINAPI
dwritetextlayout_QueryInterface(IDWriteTextLayout4
*iface
, REFIID riid
, void **obj
)
3066 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3068 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
3072 if (IsEqualIID(riid
, &IID_IDWriteTextLayout4
) ||
3073 IsEqualIID(riid
, &IID_IDWriteTextLayout3
) ||
3074 IsEqualIID(riid
, &IID_IDWriteTextLayout2
) ||
3075 IsEqualIID(riid
, &IID_IDWriteTextLayout1
) ||
3076 IsEqualIID(riid
, &IID_IDWriteTextLayout
) ||
3077 IsEqualIID(riid
, &IID_IUnknown
))
3081 else if (IsEqualIID(riid
, &IID_IDWriteTextFormat3
) ||
3082 IsEqualIID(riid
, &IID_IDWriteTextFormat2
) ||
3083 IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
3084 IsEqualIID(riid
, &IID_IDWriteTextFormat
))
3086 *obj
= &layout
->IDWriteTextFormat3_iface
;
3090 IDWriteTextLayout4_AddRef(iface
);
3094 WARN("%s not implemented.\n", debugstr_guid(riid
));
3096 return E_NOINTERFACE
;
3099 static ULONG WINAPI
dwritetextlayout_AddRef(IDWriteTextLayout4
*iface
)
3101 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3102 ULONG refcount
= InterlockedIncrement(&layout
->refcount
);
3104 TRACE("%p, refcount %u.\n", iface
, refcount
);
3109 static ULONG WINAPI
dwritetextlayout_Release(IDWriteTextLayout4
*iface
)
3111 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3112 ULONG refcount
= InterlockedDecrement(&layout
->refcount
);
3114 TRACE("%p, refcount %u.\n", iface
, refcount
);
3118 IDWriteFactory7_Release(layout
->factory
);
3119 free_layout_ranges_list(layout
);
3120 free_layout_eruns(layout
);
3121 free_layout_runs(layout
);
3122 release_format_data(&layout
->format
);
3123 heap_free(layout
->nominal_breakpoints
);
3124 heap_free(layout
->actual_breakpoints
);
3125 heap_free(layout
->clustermetrics
);
3126 heap_free(layout
->clusters
);
3127 heap_free(layout
->lines
);
3128 heap_free(layout
->str
);
3135 static HRESULT WINAPI
dwritetextlayout_SetTextAlignment(IDWriteTextLayout4
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
3137 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3138 return IDWriteTextFormat3_SetTextAlignment(&layout
->IDWriteTextFormat3_iface
, alignment
);
3141 static HRESULT WINAPI
dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout4
*iface
,
3142 DWRITE_PARAGRAPH_ALIGNMENT alignment
)
3144 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3145 return IDWriteTextFormat3_SetParagraphAlignment(&layout
->IDWriteTextFormat3_iface
, alignment
);
3148 static HRESULT WINAPI
dwritetextlayout_SetWordWrapping(IDWriteTextLayout4
*iface
, DWRITE_WORD_WRAPPING wrapping
)
3150 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3151 return IDWriteTextFormat3_SetWordWrapping(&layout
->IDWriteTextFormat3_iface
, wrapping
);
3154 static HRESULT WINAPI
dwritetextlayout_SetReadingDirection(IDWriteTextLayout4
*iface
,
3155 DWRITE_READING_DIRECTION direction
)
3157 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3158 return IDWriteTextFormat3_SetReadingDirection(&layout
->IDWriteTextFormat3_iface
, direction
);
3161 static HRESULT WINAPI
dwritetextlayout_SetFlowDirection(IDWriteTextLayout4
*iface
, DWRITE_FLOW_DIRECTION direction
)
3163 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3164 return IDWriteTextFormat3_SetFlowDirection(&layout
->IDWriteTextFormat3_iface
, direction
);
3167 static HRESULT WINAPI
dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout4
*iface
, FLOAT tabstop
)
3169 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3170 return IDWriteTextFormat3_SetIncrementalTabStop(&layout
->IDWriteTextFormat3_iface
, tabstop
);
3173 static HRESULT WINAPI
dwritetextlayout_SetTrimming(IDWriteTextLayout4
*iface
, DWRITE_TRIMMING
const *trimming
,
3174 IDWriteInlineObject
*trimming_sign
)
3176 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3177 return IDWriteTextFormat3_SetTrimming(&layout
->IDWriteTextFormat3_iface
, trimming
, trimming_sign
);
3180 static HRESULT WINAPI
dwritetextlayout_SetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
3181 FLOAT line_spacing
, FLOAT baseline
)
3183 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3184 return IDWriteTextFormat1_SetLineSpacing((IDWriteTextFormat1
*)&layout
->IDWriteTextFormat3_iface
, spacing
,
3185 line_spacing
, baseline
);
3188 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextlayout_GetTextAlignment(IDWriteTextLayout4
*iface
)
3190 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3191 return IDWriteTextFormat3_GetTextAlignment(&layout
->IDWriteTextFormat3_iface
);
3194 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout4
*iface
)
3196 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3197 return IDWriteTextFormat3_GetParagraphAlignment(&layout
->IDWriteTextFormat3_iface
);
3200 static DWRITE_WORD_WRAPPING WINAPI
dwritetextlayout_GetWordWrapping(IDWriteTextLayout4
*iface
)
3202 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3203 return IDWriteTextFormat3_GetWordWrapping(&layout
->IDWriteTextFormat3_iface
);
3206 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_GetReadingDirection(IDWriteTextLayout4
*iface
)
3208 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3209 return IDWriteTextFormat3_GetReadingDirection(&layout
->IDWriteTextFormat3_iface
);
3212 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextlayout_GetFlowDirection(IDWriteTextLayout4
*iface
)
3214 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3215 return IDWriteTextFormat3_GetFlowDirection(&layout
->IDWriteTextFormat3_iface
);
3218 static FLOAT WINAPI
dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout4
*iface
)
3220 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3221 return IDWriteTextFormat3_GetIncrementalTabStop(&layout
->IDWriteTextFormat3_iface
);
3224 static HRESULT WINAPI
dwritetextlayout_GetTrimming(IDWriteTextLayout4
*iface
, DWRITE_TRIMMING
*options
,
3225 IDWriteInlineObject
**trimming_sign
)
3227 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3228 return IDWriteTextFormat3_GetTrimming(&layout
->IDWriteTextFormat3_iface
, options
, trimming_sign
);
3231 static HRESULT WINAPI
dwritetextlayout_GetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
3232 FLOAT
*spacing
, FLOAT
*baseline
)
3234 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3235 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat
*)&layout
->IDWriteTextFormat3_iface
, method
,
3239 static HRESULT WINAPI
dwritetextlayout_GetFontCollection(IDWriteTextLayout4
*iface
, IDWriteFontCollection
**collection
)
3241 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3242 return IDWriteTextFormat3_GetFontCollection(&layout
->IDWriteTextFormat3_iface
, collection
);
3245 static UINT32 WINAPI
dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout4
*iface
)
3247 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3248 return IDWriteTextFormat3_GetFontFamilyNameLength(&layout
->IDWriteTextFormat3_iface
);
3251 static HRESULT WINAPI
dwritetextlayout_GetFontFamilyName(IDWriteTextLayout4
*iface
, WCHAR
*name
, UINT32 size
)
3253 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3254 return IDWriteTextFormat3_GetFontFamilyName(&layout
->IDWriteTextFormat3_iface
, name
, size
);
3257 static DWRITE_FONT_WEIGHT WINAPI
dwritetextlayout_GetFontWeight(IDWriteTextLayout4
*iface
)
3259 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3260 return IDWriteTextFormat3_GetFontWeight(&layout
->IDWriteTextFormat3_iface
);
3263 static DWRITE_FONT_STYLE WINAPI
dwritetextlayout_GetFontStyle(IDWriteTextLayout4
*iface
)
3265 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3266 return IDWriteTextFormat3_GetFontStyle(&layout
->IDWriteTextFormat3_iface
);
3269 static DWRITE_FONT_STRETCH WINAPI
dwritetextlayout_GetFontStretch(IDWriteTextLayout4
*iface
)
3271 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3272 return IDWriteTextFormat3_GetFontStretch(&layout
->IDWriteTextFormat3_iface
);
3275 static FLOAT WINAPI
dwritetextlayout_GetFontSize(IDWriteTextLayout4
*iface
)
3277 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3278 return IDWriteTextFormat3_GetFontSize(&layout
->IDWriteTextFormat3_iface
);
3281 static UINT32 WINAPI
dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout4
*iface
)
3283 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3284 return IDWriteTextFormat3_GetLocaleNameLength(&layout
->IDWriteTextFormat3_iface
);
3287 static HRESULT WINAPI
dwritetextlayout_GetLocaleName(IDWriteTextLayout4
*iface
, WCHAR
*name
, UINT32 size
)
3289 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3290 return IDWriteTextFormat3_GetLocaleName(&layout
->IDWriteTextFormat3_iface
, name
, size
);
3293 static HRESULT WINAPI
dwritetextlayout_SetMaxWidth(IDWriteTextLayout4
*iface
, FLOAT maxWidth
)
3295 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3298 TRACE("%p, %.8e.\n", iface
, maxWidth
);
3300 if (maxWidth
< 0.0f
)
3301 return E_INVALIDARG
;
3303 changed
= layout
->metrics
.layoutWidth
!= maxWidth
;
3304 layout
->metrics
.layoutWidth
= maxWidth
;
3307 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3311 static HRESULT WINAPI
dwritetextlayout_SetMaxHeight(IDWriteTextLayout4
*iface
, FLOAT maxHeight
)
3313 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3316 TRACE("%p, %.8e.\n", iface
, maxHeight
);
3318 if (maxHeight
< 0.0f
)
3319 return E_INVALIDARG
;
3321 changed
= layout
->metrics
.layoutHeight
!= maxHeight
;
3322 layout
->metrics
.layoutHeight
= maxHeight
;
3325 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3329 static HRESULT WINAPI
dwritetextlayout_SetFontCollection(IDWriteTextLayout4
*iface
, IDWriteFontCollection
*collection
,
3330 DWRITE_TEXT_RANGE range
)
3332 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3333 struct layout_range_attr_value value
;
3335 TRACE("%p, %p, %s.\n", iface
, collection
, debugstr_range(&range
));
3337 value
.range
= range
;
3338 value
.u
.collection
= collection
;
3339 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_FONTCOLL
, &value
);
3342 static HRESULT WINAPI
dwritetextlayout_SetFontFamilyName(IDWriteTextLayout4
*iface
, WCHAR
const *name
,
3343 DWRITE_TEXT_RANGE range
)
3345 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3346 struct layout_range_attr_value value
;
3348 TRACE("%p, %s, %s.\n", iface
, debugstr_w(name
), debugstr_range(&range
));
3351 return E_INVALIDARG
;
3353 value
.range
= range
;
3354 value
.u
.fontfamily
= name
;
3355 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_FONTFAMILY
, &value
);
3358 static HRESULT WINAPI
dwritetextlayout_SetFontWeight(IDWriteTextLayout4
*iface
, DWRITE_FONT_WEIGHT weight
,
3359 DWRITE_TEXT_RANGE range
)
3361 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3362 struct layout_range_attr_value value
;
3364 TRACE("%p, %d, %s.\n", iface
, weight
, debugstr_range(&range
));
3366 if ((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
3367 return E_INVALIDARG
;
3369 value
.range
= range
;
3370 value
.u
.weight
= weight
;
3371 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_WEIGHT
, &value
);
3374 static HRESULT WINAPI
dwritetextlayout_SetFontStyle(IDWriteTextLayout4
*iface
, DWRITE_FONT_STYLE style
,
3375 DWRITE_TEXT_RANGE range
)
3377 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3378 struct layout_range_attr_value value
;
3380 TRACE("%p, %d, %s.\n", iface
, style
, debugstr_range(&range
));
3382 if ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
)
3383 return E_INVALIDARG
;
3385 value
.range
= range
;
3386 value
.u
.style
= style
;
3387 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_STYLE
, &value
);
3390 static HRESULT WINAPI
dwritetextlayout_SetFontStretch(IDWriteTextLayout4
*iface
, DWRITE_FONT_STRETCH stretch
,
3391 DWRITE_TEXT_RANGE range
)
3393 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3394 struct layout_range_attr_value value
;
3396 TRACE("%p, %d, %s.\n", iface
, stretch
, debugstr_range(&range
));
3398 if (stretch
== DWRITE_FONT_STRETCH_UNDEFINED
|| (UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
3399 return E_INVALIDARG
;
3401 value
.range
= range
;
3402 value
.u
.stretch
= stretch
;
3403 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_STRETCH
, &value
);
3406 static HRESULT WINAPI
dwritetextlayout_SetFontSize(IDWriteTextLayout4
*iface
, FLOAT size
, DWRITE_TEXT_RANGE range
)
3408 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3409 struct layout_range_attr_value value
;
3411 TRACE("%p, %.8e, %s.\n", iface
, size
, debugstr_range(&range
));
3414 return E_INVALIDARG
;
3416 value
.range
= range
;
3417 value
.u
.fontsize
= size
;
3418 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_FONTSIZE
, &value
);
3421 static HRESULT WINAPI
dwritetextlayout_SetUnderline(IDWriteTextLayout4
*iface
, BOOL underline
, DWRITE_TEXT_RANGE range
)
3423 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3424 struct layout_range_attr_value value
;
3426 TRACE("%p, %d, %s.\n", iface
, underline
, debugstr_range(&range
));
3428 value
.range
= range
;
3429 value
.u
.underline
= underline
;
3430 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_UNDERLINE
, &value
);
3433 static HRESULT WINAPI
dwritetextlayout_SetStrikethrough(IDWriteTextLayout4
*iface
, BOOL strikethrough
,
3434 DWRITE_TEXT_RANGE range
)
3436 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3437 struct layout_range_attr_value value
;
3439 TRACE("%p, %d, %s.\n", iface
, strikethrough
, debugstr_range(&range
));
3441 value
.range
= range
;
3442 value
.u
.strikethrough
= strikethrough
;
3443 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_STRIKETHROUGH
, &value
);
3446 static HRESULT WINAPI
dwritetextlayout_SetDrawingEffect(IDWriteTextLayout4
*iface
, IUnknown
* effect
,
3447 DWRITE_TEXT_RANGE range
)
3449 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3450 struct layout_range_attr_value value
;
3452 TRACE("%p, %p, %s.\n", iface
, effect
, debugstr_range(&range
));
3454 value
.range
= range
;
3455 value
.u
.effect
= effect
;
3456 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_EFFECT
, &value
);
3459 static HRESULT WINAPI
dwritetextlayout_SetInlineObject(IDWriteTextLayout4
*iface
, IDWriteInlineObject
*object
,
3460 DWRITE_TEXT_RANGE range
)
3462 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3463 struct layout_range_attr_value value
;
3465 TRACE("%p, %p, %s.\n", iface
, object
, debugstr_range(&range
));
3467 value
.range
= range
;
3468 value
.u
.object
= object
;
3469 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_INLINE
, &value
);
3472 static HRESULT WINAPI
dwritetextlayout_SetTypography(IDWriteTextLayout4
*iface
, IDWriteTypography
*typography
,
3473 DWRITE_TEXT_RANGE range
)
3475 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3476 struct layout_range_attr_value value
;
3478 TRACE("%p, %p, %s.\n", iface
, typography
, debugstr_range(&range
));
3480 value
.range
= range
;
3481 value
.u
.typography
= typography
;
3482 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_TYPOGRAPHY
, &value
);
3485 static HRESULT WINAPI
dwritetextlayout_SetLocaleName(IDWriteTextLayout4
*iface
, WCHAR
const* locale
,
3486 DWRITE_TEXT_RANGE range
)
3488 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3489 struct layout_range_attr_value value
;
3491 TRACE("%p, %s, %s.\n", iface
, debugstr_w(locale
), debugstr_range(&range
));
3493 if (!locale
|| wcslen(locale
) > LOCALE_NAME_MAX_LENGTH
-1)
3494 return E_INVALIDARG
;
3496 value
.range
= range
;
3497 value
.u
.locale
= locale
;
3498 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_LOCALE
, &value
);
3501 static FLOAT WINAPI
dwritetextlayout_GetMaxWidth(IDWriteTextLayout4
*iface
)
3503 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3505 TRACE("%p.\n", iface
);
3507 return layout
->metrics
.layoutWidth
;
3510 static FLOAT WINAPI
dwritetextlayout_GetMaxHeight(IDWriteTextLayout4
*iface
)
3512 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3514 TRACE("%p.\n", iface
);
3516 return layout
->metrics
.layoutHeight
;
3519 static HRESULT WINAPI
dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout4
*iface
, UINT32 position
,
3520 IDWriteFontCollection
**collection
, DWRITE_TEXT_RANGE
*r
)
3522 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3523 struct layout_range
*range
;
3525 TRACE("%p, %u, %p, %p.\n", iface
, position
, collection
, r
);
3527 range
= get_layout_range_by_pos(layout
, position
);
3528 *collection
= range
->collection
;
3530 IDWriteFontCollection_AddRef(*collection
);
3532 return return_range(&range
->h
, r
);
3535 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout4
*iface
,
3536 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3538 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3540 TRACE("%p, %d, %p, %p.\n", iface
, position
, length
, r
);
3542 return get_string_attribute_length(layout
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, length
, r
);
3545 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout4
*iface
,
3546 UINT32 position
, WCHAR
*name
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3548 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3550 TRACE("%p, %u, %p, %u, %p.\n", iface
, position
, name
, length
, r
);
3552 return get_string_attribute_value(layout
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, name
, length
, r
);
3555 static HRESULT WINAPI
dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout4
*iface
,
3556 UINT32 position
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_TEXT_RANGE
*r
)
3558 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3559 struct layout_range
*range
;
3561 TRACE("%p, %u, %p, %p.\n", iface
, position
, weight
, r
);
3563 range
= get_layout_range_by_pos(layout
, position
);
3564 *weight
= range
->weight
;
3566 return return_range(&range
->h
, r
);
3569 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout4
*iface
,
3570 UINT32 position
, DWRITE_FONT_STYLE
*style
, DWRITE_TEXT_RANGE
*r
)
3572 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3573 struct layout_range
*range
;
3575 TRACE("%p, %u, %p, %p.\n", iface
, position
, style
, r
);
3577 range
= get_layout_range_by_pos(layout
, position
);
3578 *style
= range
->style
;
3579 return return_range(&range
->h
, r
);
3582 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout4
*iface
,
3583 UINT32 position
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_TEXT_RANGE
*r
)
3585 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3586 struct layout_range
*range
;
3588 TRACE("%p, %u, %p, %p.\n", iface
, position
, stretch
, r
);
3590 range
= get_layout_range_by_pos(layout
, position
);
3591 *stretch
= range
->stretch
;
3592 return return_range(&range
->h
, r
);
3595 static HRESULT WINAPI
dwritetextlayout_layout_GetFontSize(IDWriteTextLayout4
*iface
,
3596 UINT32 position
, FLOAT
*size
, DWRITE_TEXT_RANGE
*r
)
3598 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3599 struct layout_range
*range
;
3601 TRACE("%p, %u, %p, %p.\n", iface
, position
, size
, r
);
3603 range
= get_layout_range_by_pos(layout
, position
);
3604 *size
= range
->fontsize
;
3605 return return_range(&range
->h
, r
);
3608 static HRESULT WINAPI
dwritetextlayout_GetUnderline(IDWriteTextLayout4
*iface
,
3609 UINT32 position
, BOOL
*underline
, DWRITE_TEXT_RANGE
*r
)
3611 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3612 struct layout_range_bool
*range
;
3614 TRACE("%p, %u, %p, %p.\n", iface
, position
, underline
, r
);
3616 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&layout
->underline_ranges
, position
);
3617 *underline
= range
->value
;
3619 return return_range(&range
->h
, r
);
3622 static HRESULT WINAPI
dwritetextlayout_GetStrikethrough(IDWriteTextLayout4
*iface
,
3623 UINT32 position
, BOOL
*strikethrough
, DWRITE_TEXT_RANGE
*r
)
3625 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3626 struct layout_range_bool
*range
;
3628 TRACE("%p, %u, %p, %p.\n", iface
, position
, strikethrough
, r
);
3630 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&layout
->strike_ranges
, position
);
3631 *strikethrough
= range
->value
;
3633 return return_range(&range
->h
, r
);
3636 static HRESULT WINAPI
dwritetextlayout_GetDrawingEffect(IDWriteTextLayout4
*iface
,
3637 UINT32 position
, IUnknown
**effect
, DWRITE_TEXT_RANGE
*r
)
3639 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3640 struct layout_range_iface
*range
;
3642 TRACE("%p, %u, %p, %p.\n", iface
, position
, effect
, r
);
3644 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->effects
, position
);
3645 *effect
= range
->iface
;
3647 IUnknown_AddRef(*effect
);
3649 return return_range(&range
->h
, r
);
3652 static HRESULT WINAPI
dwritetextlayout_GetInlineObject(IDWriteTextLayout4
*iface
,
3653 UINT32 position
, IDWriteInlineObject
**object
, DWRITE_TEXT_RANGE
*r
)
3655 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3656 struct layout_range
*range
;
3658 TRACE("%p, %u, %p, %p.\n", iface
, position
, object
, r
);
3660 range
= get_layout_range_by_pos(layout
, position
);
3661 *object
= range
->object
;
3663 IDWriteInlineObject_AddRef(*object
);
3665 return return_range(&range
->h
, r
);
3668 static HRESULT WINAPI
dwritetextlayout_GetTypography(IDWriteTextLayout4
*iface
,
3669 UINT32 position
, IDWriteTypography
** typography
, DWRITE_TEXT_RANGE
*r
)
3671 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3672 struct layout_range_iface
*range
;
3674 TRACE("%p, %u, %p, %p.\n", iface
, position
, typography
, r
);
3676 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&layout
->typographies
, position
);
3677 *typography
= (IDWriteTypography
*)range
->iface
;
3679 IDWriteTypography_AddRef(*typography
);
3681 return return_range(&range
->h
, r
);
3684 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout4
*iface
,
3685 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3687 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3689 TRACE("%p, %u, %p, %p.\n", iface
, position
, length
, r
);
3691 return get_string_attribute_length(layout
, LAYOUT_RANGE_ATTR_LOCALE
, position
, length
, r
);
3694 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout4
*iface
,
3695 UINT32 position
, WCHAR
*locale
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3697 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3699 TRACE("%p, %u, %p, %u, %p.\n", iface
, position
, locale
, length
, r
);
3701 return get_string_attribute_value(layout
, LAYOUT_RANGE_ATTR_LOCALE
, position
, locale
, length
, r
);
3704 static inline FLOAT
renderer_apply_snapping(FLOAT coord
, BOOL skiptransform
, FLOAT ppdip
, FLOAT det
,
3705 const DWRITE_MATRIX
*m
)
3707 D2D1_POINT_2F vec
, vec2
;
3709 if (!skiptransform
) {
3710 /* apply transform */
3712 vec
.y
= coord
* ppdip
;
3714 vec2
.x
= m
->m11
* vec
.x
+ m
->m21
* vec
.y
+ m
->dx
;
3715 vec2
.y
= m
->m12
* vec
.x
+ m
->m22
* vec
.y
+ m
->dy
;
3718 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
3719 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
3721 /* apply inverted transform, we don't care about X component at this point */
3722 vec
.y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
3726 vec
.y
= floorf(coord
* ppdip
+ 0.5f
) / ppdip
;
3731 static HRESULT WINAPI
dwritetextlayout_Draw(IDWriteTextLayout4
*iface
,
3732 void *context
, IDWriteTextRenderer
* renderer
, FLOAT origin_x
, FLOAT origin_y
)
3734 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3735 BOOL disabled
= FALSE
, skiptransform
= FALSE
;
3736 struct layout_effective_inline
*inlineobject
;
3737 struct layout_effective_run
*run
;
3738 struct layout_strikethrough
*s
;
3739 struct layout_underline
*u
;
3740 FLOAT det
= 0.0f
, ppdip
= 0.0f
;
3741 DWRITE_MATRIX m
= { 0 };
3744 TRACE("%p, %p, %p, %.8e, %.8e.\n", iface
, context
, renderer
, origin_x
, origin_y
);
3746 hr
= layout_compute_effective_runs(layout
);
3750 hr
= IDWriteTextRenderer_IsPixelSnappingDisabled(renderer
, context
, &disabled
);
3755 hr
= IDWriteTextRenderer_GetPixelsPerDip(renderer
, context
, &ppdip
);
3759 hr
= IDWriteTextRenderer_GetCurrentTransform(renderer
, context
, &m
);
3763 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3764 if (ppdip
<= 0.0f
||
3765 (m
.m11
* m
.m22
!= 0.0f
&& (m
.m12
!= 0.0f
|| m
.m21
!= 0.0f
)) ||
3766 (m
.m12
* m
.m21
!= 0.0f
&& (m
.m11
!= 0.0f
|| m
.m22
!= 0.0f
)))
3769 skiptransform
= should_skip_transform(&m
, &det
);
3772 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3773 /* 1. Regular runs */
3774 LIST_FOR_EACH_ENTRY(run
, &layout
->eruns
, struct layout_effective_run
, entry
)
3776 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3777 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3778 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
3779 DWRITE_GLYPH_RUN glyph_run
;
3781 /* Everything but cluster map will be reused from nominal run, as we only need
3782 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3783 it can't be reused because it has to start with 0 index for each reported run. */
3784 glyph_run
= regular
->run
;
3785 glyph_run
.glyphCount
= run
->glyphcount
;
3787 /* fixup glyph data arrays */
3788 glyph_run
.glyphIndices
+= start_glyph
;
3789 glyph_run
.glyphAdvances
+= start_glyph
;
3790 glyph_run
.glyphOffsets
+= start_glyph
;
3793 descr
= regular
->descr
;
3794 descr
.stringLength
= run
->length
;
3795 descr
.string
+= run
->start
;
3796 descr
.clusterMap
= run
->clustermap
;
3797 descr
.textPosition
+= run
->start
;
3799 /* return value is ignored */
3800 IDWriteTextRenderer_DrawGlyphRun(renderer
,
3802 run
->origin
.x
+ run
->align_dx
+ origin_x
,
3803 SNAP_COORD(run
->origin
.y
+ origin_y
),
3804 layout
->measuringmode
,
3810 /* 2. Inline objects */
3811 LIST_FOR_EACH_ENTRY(inlineobject
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
)
3813 IDWriteTextRenderer_DrawInlineObject(renderer
,
3815 inlineobject
->origin
.x
+ inlineobject
->align_dx
+ origin_x
,
3816 SNAP_COORD(inlineobject
->origin
.y
+ origin_y
),
3817 inlineobject
->object
,
3818 inlineobject
->is_sideways
,
3819 inlineobject
->is_rtl
,
3820 inlineobject
->effect
);
3824 LIST_FOR_EACH_ENTRY(u
, &layout
->underlines
, struct layout_underline
, entry
)
3826 IDWriteTextRenderer_DrawUnderline(renderer
,
3828 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3829 (is_run_rtl(u
->run
) ? u
->run
->origin
.x
- u
->run
->width
: u
->run
->origin
.x
) + u
->run
->align_dx
+ origin_x
,
3830 SNAP_COORD(u
->run
->origin
.y
+ origin_y
),
3835 /* 4. Strikethrough */
3836 LIST_FOR_EACH_ENTRY(s
, &layout
->strikethrough
, struct layout_strikethrough
, entry
)
3838 IDWriteTextRenderer_DrawStrikethrough(renderer
,
3840 s
->run
->origin
.x
+ s
->run
->align_dx
+ origin_x
,
3841 SNAP_COORD(s
->run
->origin
.y
+ origin_y
),
3850 static HRESULT WINAPI
dwritetextlayout_GetLineMetrics(IDWriteTextLayout4
*iface
,
3851 DWRITE_LINE_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3853 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3854 unsigned int line_count
;
3858 TRACE("%p, %p, %u, %p.\n", iface
, metrics
, max_count
, count
);
3860 if (FAILED(hr
= layout_compute_effective_runs(layout
)))
3865 line_count
= min(max_count
, layout
->metrics
.lineCount
);
3866 for (i
= 0; i
< line_count
; ++i
)
3867 memcpy(&metrics
[i
], &layout
->lines
[i
].metrics
, sizeof(*metrics
));
3870 *count
= layout
->metrics
.lineCount
;
3871 return max_count
>= layout
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3874 static HRESULT
layout_update_metrics(struct dwrite_textlayout
*layout
)
3876 return layout_compute_effective_runs(layout
);
3879 static HRESULT WINAPI
dwritetextlayout_GetMetrics(IDWriteTextLayout4
*iface
, DWRITE_TEXT_METRICS
*metrics
)
3881 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
3884 TRACE("%p, %p.\n", iface
, metrics
);
3886 hr
= layout_update_metrics(layout
);
3888 memcpy(metrics
, &layout
->metrics
, sizeof(*metrics
));
3893 static void d2d_rect_offset(D2D1_RECT_F
*rect
, FLOAT x
, FLOAT y
)
3901 static BOOL
d2d_rect_is_empty(const D2D1_RECT_F
*rect
)
3903 return ((rect
->left
>= rect
->right
) || (rect
->top
>= rect
->bottom
));
3906 static void d2d_rect_union(D2D1_RECT_F
*dst
, const D2D1_RECT_F
*src
)
3908 if (d2d_rect_is_empty(dst
)) {
3909 if (d2d_rect_is_empty(src
)) {
3910 dst
->left
= dst
->right
= dst
->top
= dst
->bottom
= 0.0f
;
3917 if (!d2d_rect_is_empty(src
)) {
3918 dst
->left
= min(dst
->left
, src
->left
);
3919 dst
->right
= max(dst
->right
, src
->right
);
3920 dst
->top
= min(dst
->top
, src
->top
);
3921 dst
->bottom
= max(dst
->bottom
, src
->bottom
);
3926 static void layout_get_erun_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_run
*run
, D2D1_RECT_F
*bbox
)
3928 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3929 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3930 D2D1_POINT_2F baseline_origin
= { 0 }, *origins
;
3931 DWRITE_GLYPH_RUN glyph_run
;
3935 if (run
->bbox
.top
== run
->bbox
.bottom
)
3937 struct dwrite_glyphbitmap glyph_bitmap
;
3940 glyph_run
= regular
->run
;
3941 glyph_run
.glyphCount
= run
->glyphcount
;
3942 glyph_run
.glyphIndices
= ®ular
->run
.glyphIndices
[start_glyph
];
3943 glyph_run
.glyphAdvances
= ®ular
->run
.glyphAdvances
[start_glyph
];
3944 glyph_run
.glyphOffsets
= ®ular
->run
.glyphOffsets
[start_glyph
];
3946 memset(&glyph_bitmap
, 0, sizeof(glyph_bitmap
));
3947 glyph_bitmap
.key
= glyph_run
.fontFace
;
3948 glyph_bitmap
.simulations
= IDWriteFontFace_GetSimulations(glyph_run
.fontFace
);
3949 glyph_bitmap
.emsize
= glyph_run
.fontEmSize
;
3950 glyph_bitmap
.nohint
= layout
->measuringmode
== DWRITE_MEASURING_MODE_NATURAL
;
3952 bbox
= &glyph_bitmap
.bbox
;
3954 if (!(origins
= heap_calloc(glyph_run
.glyphCount
, sizeof(*origins
))))
3957 if (FAILED(hr
= compute_glyph_origins(&glyph_run
, layout
->measuringmode
, baseline_origin
, &layout
->transform
, origins
)))
3959 WARN("Failed to compute glyph origins, hr %#x.\n", hr
);
3964 for (i
= 0; i
< glyph_run
.glyphCount
; ++i
)
3966 D2D1_RECT_F glyph_bbox
;
3968 glyph_bitmap
.glyph
= glyph_run
.glyphIndices
[i
];
3969 dwrite_fontface_get_glyph_bbox(&glyph_bitmap
);
3971 glyph_bbox
.left
= bbox
->left
;
3972 glyph_bbox
.top
= bbox
->top
;
3973 glyph_bbox
.right
= bbox
->right
;
3974 glyph_bbox
.bottom
= bbox
->bottom
;
3976 d2d_rect_offset(&glyph_bbox
, origins
[i
].x
, origins
[i
].y
);
3977 d2d_rect_union(&run
->bbox
, &glyph_bbox
);
3984 d2d_rect_offset(bbox
, run
->origin
.x
+ run
->align_dx
, run
->origin
.y
);
3987 static void layout_get_inlineobj_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_inline
*run
,
3990 DWRITE_OVERHANG_METRICS overhang_metrics
= { 0 };
3991 DWRITE_INLINE_OBJECT_METRICS metrics
= { 0 };
3994 if (FAILED(hr
= IDWriteInlineObject_GetMetrics(run
->object
, &metrics
))) {
3995 WARN("Failed to get inline object metrics, hr %#x.\n", hr
);
3996 memset(bbox
, 0, sizeof(*bbox
));
4000 bbox
->left
= run
->origin
.x
+ run
->align_dx
;
4001 bbox
->right
= bbox
->left
+ metrics
.width
;
4002 bbox
->top
= run
->origin
.y
;
4003 bbox
->bottom
= bbox
->top
+ metrics
.height
;
4005 IDWriteInlineObject_GetOverhangMetrics(run
->object
, &overhang_metrics
);
4007 bbox
->left
-= overhang_metrics
.left
;
4008 bbox
->right
+= overhang_metrics
.right
;
4009 bbox
->top
-= overhang_metrics
.top
;
4010 bbox
->bottom
+= overhang_metrics
.bottom
;
4013 static HRESULT WINAPI
dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout4
*iface
,
4014 DWRITE_OVERHANG_METRICS
*overhangs
)
4016 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4017 struct layout_effective_inline
*inline_run
;
4018 struct layout_effective_run
*run
;
4019 D2D1_RECT_F bbox
= { 0 };
4022 TRACE("%p, %p.\n", iface
, overhangs
);
4024 memset(overhangs
, 0, sizeof(*overhangs
));
4026 if (!(layout
->recompute
& RECOMPUTE_OVERHANGS
))
4028 *overhangs
= layout
->overhangs
;
4032 hr
= layout_compute_effective_runs(layout
);
4036 LIST_FOR_EACH_ENTRY(run
, &layout
->eruns
, struct layout_effective_run
, entry
)
4038 D2D1_RECT_F run_bbox
;
4040 layout_get_erun_bbox(layout
, run
, &run_bbox
);
4041 d2d_rect_union(&bbox
, &run_bbox
);
4044 LIST_FOR_EACH_ENTRY(inline_run
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
)
4046 D2D1_RECT_F object_bbox
;
4048 layout_get_inlineobj_bbox(layout
, inline_run
, &object_bbox
);
4049 d2d_rect_union(&bbox
, &object_bbox
);
4052 /* Deltas from layout box. */
4053 layout
->overhangs
.left
= -bbox
.left
;
4054 layout
->overhangs
.top
= -bbox
.top
;
4055 layout
->overhangs
.right
= bbox
.right
- layout
->metrics
.layoutWidth
;
4056 layout
->overhangs
.bottom
= bbox
.bottom
- layout
->metrics
.layoutHeight
;
4057 layout
->recompute
&= ~RECOMPUTE_OVERHANGS
;
4059 *overhangs
= layout
->overhangs
;
4064 static HRESULT WINAPI
dwritetextlayout_GetClusterMetrics(IDWriteTextLayout4
*iface
,
4065 DWRITE_CLUSTER_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
4067 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4070 TRACE("%p, %p, %u, %p.\n", iface
, metrics
, max_count
, count
);
4072 hr
= layout_compute(layout
);
4077 memcpy(metrics
, layout
->clustermetrics
, sizeof(DWRITE_CLUSTER_METRICS
) * min(max_count
, layout
->cluster_count
));
4079 *count
= layout
->cluster_count
;
4080 return max_count
>= layout
->cluster_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
4083 static HRESULT WINAPI
dwritetextlayout_DetermineMinWidth(IDWriteTextLayout4
*iface
, FLOAT
* min_width
)
4085 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4090 TRACE("%p, %p.\n", iface
, min_width
);
4093 return E_INVALIDARG
;
4095 if (!(layout
->recompute
& RECOMPUTE_MINIMAL_WIDTH
))
4099 hr
= layout_compute(layout
);
4103 /* Find widest word without emergency breaking between clusters, trailing whitespaces
4104 preceding breaking point do not contribute to word width. */
4105 for (start
= 0; start
< layout
->cluster_count
;)
4107 UINT32 end
= start
, j
, next
;
4109 /* Last cluster always could be wrapped after. */
4110 while (!layout
->clustermetrics
[end
].canWrapLineAfter
)
4112 /* make is so current cluster range that we can wrap after is [start,end) */
4117 /* Ignore trailing whitespace clusters, in case of single space range will
4118 be reduced to empty range, or [start,start+1). */
4119 while (end
> start
&& layout
->clustermetrics
[end
-1].isWhitespace
)
4122 /* check if cluster range exceeds last minimal width */
4124 for (j
= start
; j
< end
; j
++)
4125 width
+= layout
->clustermetrics
[j
].width
;
4129 if (width
> layout
->minwidth
)
4130 layout
->minwidth
= width
;
4132 layout
->recompute
&= ~RECOMPUTE_MINIMAL_WIDTH
;
4135 *min_width
= layout
->minwidth
;
4139 static HRESULT WINAPI
dwritetextlayout_HitTestPoint(IDWriteTextLayout4
*iface
,
4140 FLOAT pointX
, FLOAT pointY
, BOOL
* is_trailinghit
, BOOL
* is_inside
, DWRITE_HIT_TEST_METRICS
*metrics
)
4142 FIXME("%p, %.8e, %.8e, %p, %p, %p): stub\n", iface
, pointX
, pointY
, is_trailinghit
, is_inside
, metrics
);
4147 static HRESULT WINAPI
dwritetextlayout_HitTestTextPosition(IDWriteTextLayout4
*iface
,
4148 UINT32 textPosition
, BOOL is_trailinghit
, FLOAT
*pointX
, FLOAT
*pointY
, DWRITE_HIT_TEST_METRICS
*metrics
)
4150 FIXME("%p, %u, %d, %p, %p, %p): stub\n", iface
, textPosition
, is_trailinghit
, pointX
, pointY
, metrics
);
4155 static HRESULT WINAPI
dwritetextlayout_HitTestTextRange(IDWriteTextLayout4
*iface
,
4156 UINT32 textPosition
, UINT32 textLength
, FLOAT originX
, FLOAT originY
,
4157 DWRITE_HIT_TEST_METRICS
*metrics
, UINT32 max_metricscount
, UINT32
* actual_metricscount
)
4159 FIXME("%p, %u, %u, %f, %f, %p, %u, %p): stub\n", iface
, textPosition
, textLength
, originX
, originY
, metrics
,
4160 max_metricscount
, actual_metricscount
);
4165 static HRESULT WINAPI
dwritetextlayout1_SetPairKerning(IDWriteTextLayout4
*iface
, BOOL is_pairkerning_enabled
,
4166 DWRITE_TEXT_RANGE range
)
4168 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4169 struct layout_range_attr_value value
;
4171 TRACE("%p, %d, %s.\n", iface
, is_pairkerning_enabled
, debugstr_range(&range
));
4173 value
.range
= range
;
4174 value
.u
.pair_kerning
= !!is_pairkerning_enabled
;
4175 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_PAIR_KERNING
, &value
);
4178 static HRESULT WINAPI
dwritetextlayout1_GetPairKerning(IDWriteTextLayout4
*iface
, UINT32 position
,
4179 BOOL
*is_pairkerning_enabled
, DWRITE_TEXT_RANGE
*r
)
4181 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4182 struct layout_range
*range
;
4184 TRACE("%p, %u, %p, %p.\n", iface
, position
, is_pairkerning_enabled
, r
);
4186 range
= get_layout_range_by_pos(layout
, position
);
4187 *is_pairkerning_enabled
= range
->pair_kerning
;
4189 return return_range(&range
->h
, r
);
4192 static HRESULT WINAPI
dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout4
*iface
, FLOAT leading
, FLOAT trailing
,
4193 FLOAT min_advance
, DWRITE_TEXT_RANGE range
)
4195 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4196 struct layout_range_attr_value value
;
4198 TRACE("%p, %.8e, %.8e, %.8e, %s.\n", iface
, leading
, trailing
, min_advance
, debugstr_range(&range
));
4200 if (min_advance
< 0.0f
)
4201 return E_INVALIDARG
;
4203 value
.range
= range
;
4204 value
.u
.spacing
.leading
= leading
;
4205 value
.u
.spacing
.trailing
= trailing
;
4206 value
.u
.spacing
.min_advance
= min_advance
;
4207 return set_layout_range_attr(layout
, LAYOUT_RANGE_ATTR_SPACING
, &value
);
4210 static HRESULT WINAPI
dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout4
*iface
, UINT32 position
, FLOAT
*leading
,
4211 FLOAT
*trailing
, FLOAT
*min_advance
, DWRITE_TEXT_RANGE
*r
)
4213 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4214 struct layout_range_spacing
*range
;
4216 TRACE("%p, %u, %p, %p, %p, %p.\n", iface
, position
, leading
, trailing
, min_advance
, r
);
4218 range
= (struct layout_range_spacing
*)get_layout_range_header_by_pos(&layout
->spacing
, position
);
4219 *leading
= range
->leading
;
4220 *trailing
= range
->trailing
;
4221 *min_advance
= range
->min_advance
;
4223 return return_range(&range
->h
, r
);
4226 static HRESULT WINAPI
dwritetextlayout2_GetMetrics(IDWriteTextLayout4
*iface
, DWRITE_TEXT_METRICS1
*metrics
)
4228 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4231 TRACE("%p, %p.\n", iface
, metrics
);
4233 if (SUCCEEDED(hr
= layout_update_metrics(layout
)))
4234 *metrics
= layout
->metrics
;
4239 static HRESULT
layout_set_vertical_orientation(struct dwrite_textlayout
*layout
,
4240 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4245 if (FAILED(hr
= format_set_vertical_orientation(&layout
->format
, orientation
, &changed
)))
4249 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4254 static HRESULT WINAPI
dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout4
*iface
,
4255 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4257 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4259 TRACE("%p, %d.\n", iface
, orientation
);
4261 return layout_set_vertical_orientation(layout
, orientation
);
4264 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout4
*iface
)
4266 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4268 TRACE("%p.\n", iface
);
4270 return layout
->format
.vertical_orientation
;
4273 static HRESULT WINAPI
dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout4
*iface
, BOOL lastline_wrapping_enabled
)
4275 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4277 TRACE("%p, %d.\n", iface
, lastline_wrapping_enabled
);
4279 return IDWriteTextFormat3_SetLastLineWrapping(&layout
->IDWriteTextFormat3_iface
, lastline_wrapping_enabled
);
4282 static BOOL WINAPI
dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout4
*iface
)
4284 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4286 TRACE("%p.\n", iface
);
4288 return IDWriteTextFormat3_GetLastLineWrapping(&layout
->IDWriteTextFormat3_iface
);
4291 static HRESULT WINAPI
dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout4
*iface
,
4292 DWRITE_OPTICAL_ALIGNMENT alignment
)
4294 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4296 TRACE("%p, %d.\n", iface
, alignment
);
4298 return IDWriteTextFormat3_SetOpticalAlignment(&layout
->IDWriteTextFormat3_iface
, alignment
);
4301 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout4
*iface
)
4303 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4305 TRACE("%p.\n", iface
);
4307 return IDWriteTextFormat3_GetOpticalAlignment(&layout
->IDWriteTextFormat3_iface
);
4310 static HRESULT WINAPI
dwritetextlayout2_SetFontFallback(IDWriteTextLayout4
*iface
, IDWriteFontFallback
*fallback
)
4312 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4314 TRACE("%p, %p.\n", iface
, fallback
);
4316 return set_fontfallback_for_format(&layout
->format
, fallback
);
4319 static HRESULT WINAPI
dwritetextlayout2_GetFontFallback(IDWriteTextLayout4
*iface
, IDWriteFontFallback
**fallback
)
4321 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4323 TRACE("%p, %p.\n", iface
, fallback
);
4325 return get_fontfallback_from_format(&layout
->format
, fallback
);
4328 static HRESULT WINAPI
dwritetextlayout3_InvalidateLayout(IDWriteTextLayout4
*iface
)
4330 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4332 TRACE("%p.\n", iface
);
4334 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4338 static HRESULT WINAPI
dwritetextlayout3_SetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING
const *spacing
)
4340 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4344 TRACE("%p, %p.\n", iface
, spacing
);
4346 hr
= format_set_linespacing(&layout
->format
, spacing
, &changed
);
4352 if (!(layout
->recompute
& RECOMPUTE_LINES
))
4356 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++)
4357 layout_apply_line_spacing(layout
, line
);
4359 layout_set_line_positions(layout
);
4362 layout
->recompute
|= RECOMPUTE_OVERHANGS
;
4368 static HRESULT WINAPI
dwritetextlayout3_GetLineSpacing(IDWriteTextLayout4
*iface
, DWRITE_LINE_SPACING
*spacing
)
4370 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4372 TRACE("%p, %p.\n", iface
, spacing
);
4374 *spacing
= layout
->format
.spacing
;
4378 static HRESULT WINAPI
dwritetextlayout3_GetLineMetrics(IDWriteTextLayout4
*iface
, DWRITE_LINE_METRICS1
*metrics
,
4379 UINT32 max_count
, UINT32
*count
)
4381 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4382 unsigned int line_count
;
4386 TRACE("%p, %p, %u, %p.\n", iface
, metrics
, max_count
, count
);
4388 if (FAILED(hr
= layout_compute_effective_runs(layout
)))
4393 line_count
= min(max_count
, layout
->metrics
.lineCount
);
4394 for (i
= 0; i
< line_count
; ++i
)
4395 metrics
[i
] = layout
->lines
[i
].metrics
;
4398 *count
= layout
->metrics
.lineCount
;
4399 return max_count
>= layout
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
4402 static HRESULT WINAPI
dwritetextlayout4_SetFontAxisValues(IDWriteTextLayout4
*iface
,
4403 DWRITE_FONT_AXIS_VALUE
const *axis_values
, UINT32 num_values
, DWRITE_TEXT_RANGE range
)
4405 FIXME("%p, %p, %u, %s.\n", iface
, axis_values
, num_values
, debugstr_range(&range
));
4410 static UINT32 WINAPI
dwritetextlayout4_GetFontAxisValueCount(IDWriteTextLayout4
*iface
, UINT32 pos
)
4412 FIXME("%p, %u.\n", iface
, pos
);
4417 static HRESULT WINAPI
dwritetextlayout4_GetFontAxisValues(IDWriteTextLayout4
*iface
, UINT32 pos
,
4418 DWRITE_FONT_AXIS_VALUE
*values
, UINT32 num_values
, DWRITE_TEXT_RANGE
*range
)
4420 FIXME("%p, %u, %p, %u, %p.\n", iface
, pos
, values
, num_values
, range
);
4425 static DWRITE_AUTOMATIC_FONT_AXES WINAPI
dwritetextlayout4_GetAutomaticFontAxes(IDWriteTextLayout4
*iface
)
4427 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4429 TRACE("%p.\n", iface
);
4431 return layout
->format
.automatic_axes
;
4434 static HRESULT WINAPI
dwritetextlayout4_SetAutomaticFontAxes(IDWriteTextLayout4
*iface
,
4435 DWRITE_AUTOMATIC_FONT_AXES axes
)
4437 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextLayout4(iface
);
4439 TRACE("%p, %d.\n", iface
, axes
);
4441 if ((unsigned int)axes
> DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE
)
4442 return E_INVALIDARG
;
4444 layout
->format
.automatic_axes
= axes
;
4448 static const IDWriteTextLayout4Vtbl dwritetextlayoutvtbl
=
4450 dwritetextlayout_QueryInterface
,
4451 dwritetextlayout_AddRef
,
4452 dwritetextlayout_Release
,
4453 dwritetextlayout_SetTextAlignment
,
4454 dwritetextlayout_SetParagraphAlignment
,
4455 dwritetextlayout_SetWordWrapping
,
4456 dwritetextlayout_SetReadingDirection
,
4457 dwritetextlayout_SetFlowDirection
,
4458 dwritetextlayout_SetIncrementalTabStop
,
4459 dwritetextlayout_SetTrimming
,
4460 dwritetextlayout_SetLineSpacing
,
4461 dwritetextlayout_GetTextAlignment
,
4462 dwritetextlayout_GetParagraphAlignment
,
4463 dwritetextlayout_GetWordWrapping
,
4464 dwritetextlayout_GetReadingDirection
,
4465 dwritetextlayout_GetFlowDirection
,
4466 dwritetextlayout_GetIncrementalTabStop
,
4467 dwritetextlayout_GetTrimming
,
4468 dwritetextlayout_GetLineSpacing
,
4469 dwritetextlayout_GetFontCollection
,
4470 dwritetextlayout_GetFontFamilyNameLength
,
4471 dwritetextlayout_GetFontFamilyName
,
4472 dwritetextlayout_GetFontWeight
,
4473 dwritetextlayout_GetFontStyle
,
4474 dwritetextlayout_GetFontStretch
,
4475 dwritetextlayout_GetFontSize
,
4476 dwritetextlayout_GetLocaleNameLength
,
4477 dwritetextlayout_GetLocaleName
,
4478 dwritetextlayout_SetMaxWidth
,
4479 dwritetextlayout_SetMaxHeight
,
4480 dwritetextlayout_SetFontCollection
,
4481 dwritetextlayout_SetFontFamilyName
,
4482 dwritetextlayout_SetFontWeight
,
4483 dwritetextlayout_SetFontStyle
,
4484 dwritetextlayout_SetFontStretch
,
4485 dwritetextlayout_SetFontSize
,
4486 dwritetextlayout_SetUnderline
,
4487 dwritetextlayout_SetStrikethrough
,
4488 dwritetextlayout_SetDrawingEffect
,
4489 dwritetextlayout_SetInlineObject
,
4490 dwritetextlayout_SetTypography
,
4491 dwritetextlayout_SetLocaleName
,
4492 dwritetextlayout_GetMaxWidth
,
4493 dwritetextlayout_GetMaxHeight
,
4494 dwritetextlayout_layout_GetFontCollection
,
4495 dwritetextlayout_layout_GetFontFamilyNameLength
,
4496 dwritetextlayout_layout_GetFontFamilyName
,
4497 dwritetextlayout_layout_GetFontWeight
,
4498 dwritetextlayout_layout_GetFontStyle
,
4499 dwritetextlayout_layout_GetFontStretch
,
4500 dwritetextlayout_layout_GetFontSize
,
4501 dwritetextlayout_GetUnderline
,
4502 dwritetextlayout_GetStrikethrough
,
4503 dwritetextlayout_GetDrawingEffect
,
4504 dwritetextlayout_GetInlineObject
,
4505 dwritetextlayout_GetTypography
,
4506 dwritetextlayout_layout_GetLocaleNameLength
,
4507 dwritetextlayout_layout_GetLocaleName
,
4508 dwritetextlayout_Draw
,
4509 dwritetextlayout_GetLineMetrics
,
4510 dwritetextlayout_GetMetrics
,
4511 dwritetextlayout_GetOverhangMetrics
,
4512 dwritetextlayout_GetClusterMetrics
,
4513 dwritetextlayout_DetermineMinWidth
,
4514 dwritetextlayout_HitTestPoint
,
4515 dwritetextlayout_HitTestTextPosition
,
4516 dwritetextlayout_HitTestTextRange
,
4517 dwritetextlayout1_SetPairKerning
,
4518 dwritetextlayout1_GetPairKerning
,
4519 dwritetextlayout1_SetCharacterSpacing
,
4520 dwritetextlayout1_GetCharacterSpacing
,
4521 dwritetextlayout2_GetMetrics
,
4522 dwritetextlayout2_SetVerticalGlyphOrientation
,
4523 dwritetextlayout2_GetVerticalGlyphOrientation
,
4524 dwritetextlayout2_SetLastLineWrapping
,
4525 dwritetextlayout2_GetLastLineWrapping
,
4526 dwritetextlayout2_SetOpticalAlignment
,
4527 dwritetextlayout2_GetOpticalAlignment
,
4528 dwritetextlayout2_SetFontFallback
,
4529 dwritetextlayout2_GetFontFallback
,
4530 dwritetextlayout3_InvalidateLayout
,
4531 dwritetextlayout3_SetLineSpacing
,
4532 dwritetextlayout3_GetLineSpacing
,
4533 dwritetextlayout3_GetLineMetrics
,
4534 dwritetextlayout4_SetFontAxisValues
,
4535 dwritetextlayout4_GetFontAxisValueCount
,
4536 dwritetextlayout4_GetFontAxisValues
,
4537 dwritetextlayout4_GetAutomaticFontAxes
,
4538 dwritetextlayout4_SetAutomaticFontAxes
,
4541 static HRESULT WINAPI
dwritetextformat_layout_QueryInterface(IDWriteTextFormat3
*iface
, REFIID riid
, void **obj
)
4543 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4545 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
4547 return IDWriteTextLayout4_QueryInterface(&layout
->IDWriteTextLayout4_iface
, riid
, obj
);
4550 static ULONG WINAPI
dwritetextformat_layout_AddRef(IDWriteTextFormat3
*iface
)
4552 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4553 return IDWriteTextLayout4_AddRef(&layout
->IDWriteTextLayout4_iface
);
4556 static ULONG WINAPI
dwritetextformat_layout_Release(IDWriteTextFormat3
*iface
)
4558 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4559 return IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
4562 static HRESULT WINAPI
dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat3
*iface
,
4563 DWRITE_TEXT_ALIGNMENT alignment
)
4565 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4569 TRACE("%p, %d.\n", iface
, alignment
);
4571 hr
= format_set_textalignment(&layout
->format
, alignment
, &changed
);
4577 /* if layout is not ready there's nothing to align */
4578 if (!(layout
->recompute
& RECOMPUTE_LINES
))
4579 layout_apply_text_alignment(layout
);
4580 layout
->recompute
|= RECOMPUTE_OVERHANGS
;
4586 static HRESULT WINAPI
dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat3
*iface
,
4587 DWRITE_PARAGRAPH_ALIGNMENT alignment
)
4589 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4593 TRACE("%p, %d.\n", iface
, alignment
);
4595 hr
= format_set_paralignment(&layout
->format
, alignment
, &changed
);
4601 /* if layout is not ready there's nothing to align */
4602 if (!(layout
->recompute
& RECOMPUTE_LINES
))
4603 layout_apply_par_alignment(layout
);
4604 layout
->recompute
|= RECOMPUTE_OVERHANGS
;
4610 static HRESULT WINAPI
dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat3
*iface
, DWRITE_WORD_WRAPPING wrapping
)
4612 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4616 TRACE("%p, %d.\n", iface
, wrapping
);
4618 hr
= format_set_wordwrapping(&layout
->format
, wrapping
, &changed
);
4623 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4628 static HRESULT WINAPI
dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat3
*iface
,
4629 DWRITE_READING_DIRECTION direction
)
4631 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4635 TRACE("%p, %d.\n", iface
, direction
);
4637 hr
= format_set_readingdirection(&layout
->format
, direction
, &changed
);
4642 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4647 static HRESULT WINAPI
dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat3
*iface
,
4648 DWRITE_FLOW_DIRECTION direction
)
4650 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4654 TRACE("%p, %d.\n", iface
, direction
);
4656 hr
= format_set_flowdirection(&layout
->format
, direction
, &changed
);
4661 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4666 static HRESULT WINAPI
dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat3
*iface
, FLOAT tabstop
)
4668 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4670 TRACE("%p, %.8e.\n", iface
, tabstop
);
4672 if (tabstop
<= 0.0f
)
4673 return E_INVALIDARG
;
4675 layout
->format
.tabstop
= tabstop
;
4679 static HRESULT WINAPI
dwritetextformat_layout_SetTrimming(IDWriteTextFormat3
*iface
, DWRITE_TRIMMING
const *trimming
,
4680 IDWriteInlineObject
*trimming_sign
)
4682 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4686 TRACE("%p, %p, %p.\n", iface
, trimming
, trimming_sign
);
4688 hr
= format_set_trimming(&layout
->format
, trimming
, trimming_sign
, &changed
);
4691 layout
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4696 static HRESULT WINAPI
dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat3
*iface
,
4697 DWRITE_LINE_SPACING_METHOD method
, FLOAT height
, FLOAT baseline
)
4699 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4700 DWRITE_LINE_SPACING spacing
;
4702 TRACE("%p, %d, %.8e, %.8e.\n", iface
, method
, height
, baseline
);
4704 spacing
= layout
->format
.spacing
;
4705 spacing
.method
= method
;
4706 spacing
.height
= height
;
4707 spacing
.baseline
= baseline
;
4708 return IDWriteTextLayout4_SetLineSpacing(&layout
->IDWriteTextLayout4_iface
, &spacing
);
4711 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat3
*iface
)
4713 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4715 TRACE("%p.\n", iface
);
4717 return layout
->format
.textalignment
;
4720 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat3
*iface
)
4722 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4724 TRACE("%p.\n", iface
);
4726 return layout
->format
.paralign
;
4729 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat3
*iface
)
4731 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4733 TRACE("%p.\n", iface
);
4735 return layout
->format
.wrapping
;
4738 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat3
*iface
)
4740 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4742 TRACE("%p.\n", iface
);
4744 return layout
->format
.readingdir
;
4747 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat3
*iface
)
4749 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4751 TRACE("%p.\n", iface
);
4753 return layout
->format
.flow
;
4756 static FLOAT WINAPI
dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat3
*iface
)
4758 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4760 TRACE("%p.\n", iface
);
4762 return layout
->format
.tabstop
;
4765 static HRESULT WINAPI
dwritetextformat_layout_GetTrimming(IDWriteTextFormat3
*iface
, DWRITE_TRIMMING
*options
,
4766 IDWriteInlineObject
**trimming_sign
)
4768 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4770 TRACE("%p, %p, %p.\n", iface
, options
, trimming_sign
);
4772 *options
= layout
->format
.trimming
;
4773 *trimming_sign
= layout
->format
.trimmingsign
;
4775 IDWriteInlineObject_AddRef(*trimming_sign
);
4779 static HRESULT WINAPI
dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat3
*iface
,
4780 DWRITE_LINE_SPACING_METHOD
*method
, FLOAT
*spacing
, FLOAT
*baseline
)
4782 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4784 TRACE("%p, %p, %p, %p.\n", iface
, method
, spacing
, baseline
);
4786 *method
= layout
->format
.spacing
.method
;
4787 *spacing
= layout
->format
.spacing
.height
;
4788 *baseline
= layout
->format
.spacing
.baseline
;
4792 static HRESULT WINAPI
dwritetextformat_layout_GetFontCollection(IDWriteTextFormat3
*iface
,
4793 IDWriteFontCollection
**collection
)
4795 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4797 TRACE("%p, %p.\n", iface
, collection
);
4799 *collection
= layout
->format
.collection
;
4801 IDWriteFontCollection_AddRef(*collection
);
4805 static UINT32 WINAPI
dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat3
*iface
)
4807 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4809 TRACE("%p.\n", iface
);
4811 return layout
->format
.family_len
;
4814 static HRESULT WINAPI
dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat3
*iface
, WCHAR
*name
, UINT32 size
)
4816 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4818 TRACE("%p, %p, %u.\n", iface
, name
, size
);
4820 if (size
<= layout
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
4821 wcscpy(name
, layout
->format
.family_name
);
4825 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_layout_GetFontWeight(IDWriteTextFormat3
*iface
)
4827 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4829 TRACE("%p.\n", iface
);
4831 return layout
->format
.weight
;
4834 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_layout_GetFontStyle(IDWriteTextFormat3
*iface
)
4836 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4838 TRACE("%p.\n", iface
);
4840 return layout
->format
.style
;
4843 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_layout_GetFontStretch(IDWriteTextFormat3
*iface
)
4845 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4847 TRACE("%p.\n", iface
);
4849 return layout
->format
.stretch
;
4852 static FLOAT WINAPI
dwritetextformat_layout_GetFontSize(IDWriteTextFormat3
*iface
)
4854 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4856 TRACE("%p.\n", iface
);
4858 return layout
->format
.fontsize
;
4861 static UINT32 WINAPI
dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat3
*iface
)
4863 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4865 TRACE("%p.\n", iface
);
4867 return layout
->format
.locale_len
;
4870 static HRESULT WINAPI
dwritetextformat_layout_GetLocaleName(IDWriteTextFormat3
*iface
, WCHAR
*name
, UINT32 size
)
4872 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4874 TRACE("%p, %p, %u.\n", iface
, name
, size
);
4876 if (size
<= layout
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
4877 wcscpy(name
, layout
->format
.locale
);
4881 static HRESULT WINAPI
dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat3
*iface
,
4882 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4884 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4886 TRACE("%p, %d.\n", iface
, orientation
);
4888 return layout_set_vertical_orientation(layout
, orientation
);
4891 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat3
*iface
)
4893 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4895 TRACE("%p.\n", iface
);
4897 return layout
->format
.vertical_orientation
;
4900 static HRESULT WINAPI
dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat3
*iface
,
4901 BOOL lastline_wrapping_enabled
)
4903 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4905 TRACE("%p, %d.\n", iface
, lastline_wrapping_enabled
);
4907 layout
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
4911 static BOOL WINAPI
dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat3
*iface
)
4913 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4915 TRACE("%p.\n", iface
);
4917 return layout
->format
.last_line_wrapping
;
4920 static HRESULT WINAPI
dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat3
*iface
,
4921 DWRITE_OPTICAL_ALIGNMENT alignment
)
4923 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4925 TRACE("%p, %d.\n", iface
, alignment
);
4927 return format_set_optical_alignment(&layout
->format
, alignment
);
4930 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat3
*iface
)
4932 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4934 TRACE("%p.\n", iface
);
4936 return layout
->format
.optical_alignment
;
4939 static HRESULT WINAPI
dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat3
*iface
,
4940 IDWriteFontFallback
*fallback
)
4942 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4944 TRACE("%p, %p.\n", iface
, fallback
);
4946 return IDWriteTextLayout4_SetFontFallback(&layout
->IDWriteTextLayout4_iface
, fallback
);
4949 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat3
*iface
,
4950 IDWriteFontFallback
**fallback
)
4952 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4954 TRACE("%p, %p.\n", iface
, fallback
);
4956 return IDWriteTextLayout4_GetFontFallback(&layout
->IDWriteTextLayout4_iface
, fallback
);
4959 static HRESULT WINAPI
dwritetextformat2_layout_SetLineSpacing(IDWriteTextFormat3
*iface
,
4960 DWRITE_LINE_SPACING
const *spacing
)
4962 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4963 return IDWriteTextLayout4_SetLineSpacing(&layout
->IDWriteTextLayout4_iface
, spacing
);
4966 static HRESULT WINAPI
dwritetextformat2_layout_GetLineSpacing(IDWriteTextFormat3
*iface
, DWRITE_LINE_SPACING
*spacing
)
4968 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4969 return IDWriteTextLayout4_GetLineSpacing(&layout
->IDWriteTextLayout4_iface
, spacing
);
4972 static HRESULT WINAPI
dwritetextformat3_layout_SetFontAxisValues(IDWriteTextFormat3
*iface
,
4973 DWRITE_FONT_AXIS_VALUE
const *axis_values
, UINT32 num_values
)
4975 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4977 TRACE("%p, %p, %u.\n", iface
, axis_values
, num_values
);
4979 return format_set_font_axisvalues(&layout
->format
, axis_values
, num_values
);
4982 static UINT32 WINAPI
dwritetextformat3_layout_GetFontAxisValueCount(IDWriteTextFormat3
*iface
)
4984 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4986 TRACE("%p.\n", iface
);
4988 return layout
->format
.axis_values_count
;
4991 static HRESULT WINAPI
dwritetextformat3_layout_GetFontAxisValues(IDWriteTextFormat3
*iface
,
4992 DWRITE_FONT_AXIS_VALUE
*axis_values
, UINT32 num_values
)
4994 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
4996 TRACE("%p, %p, %u.\n", iface
, axis_values
, num_values
);
4998 return format_get_font_axisvalues(&layout
->format
, axis_values
, num_values
);
5001 static DWRITE_AUTOMATIC_FONT_AXES WINAPI
dwritetextformat3_layout_GetAutomaticFontAxes(IDWriteTextFormat3
*iface
)
5003 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
5004 return IDWriteTextLayout4_GetAutomaticFontAxes(&layout
->IDWriteTextLayout4_iface
);
5007 static HRESULT WINAPI
dwritetextformat3_layout_SetAutomaticFontAxes(IDWriteTextFormat3
*iface
,
5008 DWRITE_AUTOMATIC_FONT_AXES axes
)
5010 struct dwrite_textlayout
*layout
= impl_layout_from_IDWriteTextFormat3(iface
);
5011 return IDWriteTextLayout4_SetAutomaticFontAxes(&layout
->IDWriteTextLayout4_iface
, axes
);
5014 static const IDWriteTextFormat3Vtbl dwritetextformat3_layout_vtbl
=
5016 dwritetextformat_layout_QueryInterface
,
5017 dwritetextformat_layout_AddRef
,
5018 dwritetextformat_layout_Release
,
5019 dwritetextformat_layout_SetTextAlignment
,
5020 dwritetextformat_layout_SetParagraphAlignment
,
5021 dwritetextformat_layout_SetWordWrapping
,
5022 dwritetextformat_layout_SetReadingDirection
,
5023 dwritetextformat_layout_SetFlowDirection
,
5024 dwritetextformat_layout_SetIncrementalTabStop
,
5025 dwritetextformat_layout_SetTrimming
,
5026 dwritetextformat_layout_SetLineSpacing
,
5027 dwritetextformat_layout_GetTextAlignment
,
5028 dwritetextformat_layout_GetParagraphAlignment
,
5029 dwritetextformat_layout_GetWordWrapping
,
5030 dwritetextformat_layout_GetReadingDirection
,
5031 dwritetextformat_layout_GetFlowDirection
,
5032 dwritetextformat_layout_GetIncrementalTabStop
,
5033 dwritetextformat_layout_GetTrimming
,
5034 dwritetextformat_layout_GetLineSpacing
,
5035 dwritetextformat_layout_GetFontCollection
,
5036 dwritetextformat_layout_GetFontFamilyNameLength
,
5037 dwritetextformat_layout_GetFontFamilyName
,
5038 dwritetextformat_layout_GetFontWeight
,
5039 dwritetextformat_layout_GetFontStyle
,
5040 dwritetextformat_layout_GetFontStretch
,
5041 dwritetextformat_layout_GetFontSize
,
5042 dwritetextformat_layout_GetLocaleNameLength
,
5043 dwritetextformat_layout_GetLocaleName
,
5044 dwritetextformat1_layout_SetVerticalGlyphOrientation
,
5045 dwritetextformat1_layout_GetVerticalGlyphOrientation
,
5046 dwritetextformat1_layout_SetLastLineWrapping
,
5047 dwritetextformat1_layout_GetLastLineWrapping
,
5048 dwritetextformat1_layout_SetOpticalAlignment
,
5049 dwritetextformat1_layout_GetOpticalAlignment
,
5050 dwritetextformat1_layout_SetFontFallback
,
5051 dwritetextformat1_layout_GetFontFallback
,
5052 dwritetextformat2_layout_SetLineSpacing
,
5053 dwritetextformat2_layout_GetLineSpacing
,
5054 dwritetextformat3_layout_SetFontAxisValues
,
5055 dwritetextformat3_layout_GetFontAxisValueCount
,
5056 dwritetextformat3_layout_GetFontAxisValues
,
5057 dwritetextformat3_layout_GetAutomaticFontAxes
,
5058 dwritetextformat3_layout_SetAutomaticFontAxes
,
5061 static HRESULT WINAPI
dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1
*iface
,
5062 REFIID riid
, void **obj
)
5064 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink1
) ||
5065 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink
) ||
5066 IsEqualIID(riid
, &IID_IUnknown
))
5069 IDWriteTextAnalysisSink1_AddRef(iface
);
5073 WARN("%s not implemented.\n", debugstr_guid(riid
));
5076 return E_NOINTERFACE
;
5079 static ULONG WINAPI
dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1
*iface
)
5081 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
5082 return IDWriteTextLayout4_AddRef(&layout
->IDWriteTextLayout4_iface
);
5085 static ULONG WINAPI
dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1
*iface
)
5087 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
5088 return IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
5091 static HRESULT WINAPI
dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1
*iface
,
5092 UINT32 position
, UINT32 length
, DWRITE_SCRIPT_ANALYSIS
const* sa
)
5094 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
5095 struct layout_run
*run
;
5098 TRACE("[%u,%u) script=%u:%s\n", position
, position
+ length
, sa
->script
, debugstr_sa_script(sa
->script
));
5100 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
, &run
)))
5103 run
->u
.regular
.descr
.string
= &layout
->str
[position
];
5104 run
->u
.regular
.descr
.stringLength
= length
;
5105 run
->u
.regular
.descr
.textPosition
= position
;
5106 run
->u
.regular
.sa
= *sa
;
5107 list_add_tail(&layout
->runs
, &run
->entry
);
5111 static HRESULT WINAPI
dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1
*iface
,
5112 UINT32 position
, UINT32 length
, DWRITE_LINE_BREAKPOINT
const* breakpoints
)
5114 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
5116 if (position
+ length
> layout
->len
)
5119 memcpy(&layout
->nominal_breakpoints
[position
], breakpoints
, length
*sizeof(DWRITE_LINE_BREAKPOINT
));
5123 static HRESULT WINAPI
dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1
*iface
, UINT32 position
,
5124 UINT32 length
, UINT8 explicitLevel
, UINT8 resolvedLevel
)
5126 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
5127 struct layout_run
*cur_run
;
5130 TRACE("[%u,%u) %u %u\n", position
, position
+ length
, explicitLevel
, resolvedLevel
);
5132 LIST_FOR_EACH_ENTRY(cur_run
, &layout
->runs
, struct layout_run
, entry
) {
5133 struct regular_layout_run
*cur
= &cur_run
->u
.regular
;
5134 struct layout_run
*run
;
5136 if (cur_run
->kind
== LAYOUT_RUN_INLINE
)
5139 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
5140 if (position
< cur
->descr
.textPosition
|| position
>= cur
->descr
.textPosition
+ cur
->descr
.stringLength
)
5143 /* full hit - just set run level */
5144 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
== length
) {
5145 cur
->run
.bidiLevel
= resolvedLevel
;
5149 /* current run is fully covered, move to next one */
5150 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
< length
) {
5151 cur
->run
.bidiLevel
= resolvedLevel
;
5152 position
+= cur
->descr
.stringLength
;
5153 length
-= cur
->descr
.stringLength
;
5157 /* all fully covered runs are processed at this point, reuse existing run for remaining
5158 reported bidi range and add another run for the rest of original one */
5160 if (FAILED(hr
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
+ length
, &run
)))
5164 run
->u
.regular
.descr
.textPosition
= position
+ length
;
5165 run
->u
.regular
.descr
.stringLength
= cur
->descr
.stringLength
- length
;
5166 run
->u
.regular
.descr
.string
= &layout
->str
[position
+ length
];
5168 /* reduce existing run */
5169 cur
->run
.bidiLevel
= resolvedLevel
;
5170 cur
->descr
.stringLength
= length
;
5172 list_add_after(&cur_run
->entry
, &run
->entry
);
5179 static HRESULT WINAPI
dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1
*iface
,
5180 UINT32 position
, UINT32 length
, IDWriteNumberSubstitution
* substitution
)
5185 static HRESULT WINAPI
dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1
*iface
,
5186 UINT32 position
, UINT32 length
, DWRITE_GLYPH_ORIENTATION_ANGLE angle
, UINT8 adjusted_bidi_level
,
5187 BOOL is_sideways
, BOOL is_rtl
)
5192 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl
= {
5193 dwritetextlayout_sink_QueryInterface
,
5194 dwritetextlayout_sink_AddRef
,
5195 dwritetextlayout_sink_Release
,
5196 dwritetextlayout_sink_SetScriptAnalysis
,
5197 dwritetextlayout_sink_SetLineBreakpoints
,
5198 dwritetextlayout_sink_SetBidiLevel
,
5199 dwritetextlayout_sink_SetNumberSubstitution
,
5200 dwritetextlayout_sink_SetGlyphOrientation
5203 static HRESULT WINAPI
dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1
*iface
,
5204 REFIID riid
, void **obj
)
5206 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource1
) ||
5207 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource
) ||
5208 IsEqualIID(riid
, &IID_IUnknown
))
5211 IDWriteTextAnalysisSource1_AddRef(iface
);
5215 WARN("%s not implemented.\n", debugstr_guid(riid
));
5218 return E_NOINTERFACE
;
5221 static ULONG WINAPI
dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1
*iface
)
5223 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5224 return IDWriteTextLayout4_AddRef(&layout
->IDWriteTextLayout4_iface
);
5227 static ULONG WINAPI
dwritetextlayout_source_Release(IDWriteTextAnalysisSource1
*iface
)
5229 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5230 return IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
5233 static HRESULT WINAPI
dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1
*iface
,
5234 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
5236 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5238 TRACE("%p, %u, %p, %p.\n", iface
, position
, text
, text_len
);
5240 if (position
< layout
->len
) {
5241 *text
= &layout
->str
[position
];
5242 *text_len
= layout
->len
- position
;
5252 static HRESULT WINAPI
dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1
*iface
,
5253 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
5255 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5257 TRACE("%p, %u, %p, %p.\n", iface
, position
, text
, text_len
);
5259 if (position
> 0 && position
< layout
->len
) {
5260 *text
= layout
->str
;
5261 *text_len
= position
;
5271 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1
*iface
)
5273 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5274 return IDWriteTextLayout4_GetReadingDirection(&layout
->IDWriteTextLayout4_iface
);
5277 static HRESULT WINAPI
dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1
*iface
,
5278 UINT32 position
, UINT32
* text_len
, WCHAR
const** locale
)
5280 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
5281 struct layout_range
*range
= get_layout_range_by_pos(layout
, position
);
5283 if (position
< layout
->len
) {
5284 struct layout_range
*next
;
5286 *locale
= range
->locale
;
5287 *text_len
= range
->h
.range
.length
- position
;
5289 next
= LIST_ENTRY(list_next(&layout
->ranges
, &range
->h
.entry
), struct layout_range
, h
.entry
);
5290 while (next
&& next
->h
.range
.startPosition
< layout
->len
&& !wcscmp(range
->locale
, next
->locale
))
5292 *text_len
+= next
->h
.range
.length
;
5293 next
= LIST_ENTRY(list_next(&layout
->ranges
, &next
->h
.entry
), struct layout_range
, h
.entry
);
5296 *text_len
= min(*text_len
, layout
->len
- position
);
5306 static HRESULT WINAPI
dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1
*iface
,
5307 UINT32 position
, UINT32
* text_len
, IDWriteNumberSubstitution
**substitution
)
5309 FIXME("%u %p %p: stub\n", position
, text_len
, substitution
);
5313 static HRESULT WINAPI
dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1
*iface
,
5314 UINT32 position
, UINT32
*length
, DWRITE_VERTICAL_GLYPH_ORIENTATION
*orientation
, UINT8
*bidi_level
)
5316 FIXME("%u %p %p %p: stub\n", position
, length
, orientation
, bidi_level
);
5320 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl
= {
5321 dwritetextlayout_source_QueryInterface
,
5322 dwritetextlayout_source_AddRef
,
5323 dwritetextlayout_source_Release
,
5324 dwritetextlayout_source_GetTextAtPosition
,
5325 dwritetextlayout_source_GetTextBeforePosition
,
5326 dwritetextlayout_source_GetParagraphReadingDirection
,
5327 dwritetextlayout_source_GetLocaleName
,
5328 dwritetextlayout_source_GetNumberSubstitution
,
5329 dwritetextlayout_source_GetVerticalGlyphOrientation
5332 static HRESULT
layout_format_from_textformat(struct dwrite_textlayout
*layout
, IDWriteTextFormat
*format
)
5334 struct dwrite_textformat
*textformat
;
5335 IDWriteTextFormat1
*format1
;
5336 IDWriteTextFormat3
*format3
;
5340 if ((textformat
= unsafe_impl_from_IDWriteTextFormat(format
))) {
5341 layout
->format
= textformat
->format
;
5343 layout
->format
.locale
= heap_strdupW(textformat
->format
.locale
);
5344 layout
->format
.family_name
= heap_strdupW(textformat
->format
.family_name
);
5345 if (!layout
->format
.locale
|| !layout
->format
.family_name
)
5347 heap_free(layout
->format
.locale
);
5348 heap_free(layout
->format
.family_name
);
5349 return E_OUTOFMEMORY
;
5352 if (layout
->format
.trimmingsign
)
5353 IDWriteInlineObject_AddRef(layout
->format
.trimmingsign
);
5354 if (layout
->format
.collection
)
5355 IDWriteFontCollection_AddRef(layout
->format
.collection
);
5356 if (layout
->format
.fallback
)
5357 IDWriteFontFallback_AddRef(layout
->format
.fallback
);
5362 layout
->format
.weight
= IDWriteTextFormat_GetFontWeight(format
);
5363 layout
->format
.style
= IDWriteTextFormat_GetFontStyle(format
);
5364 layout
->format
.stretch
= IDWriteTextFormat_GetFontStretch(format
);
5365 layout
->format
.fontsize
= IDWriteTextFormat_GetFontSize(format
);
5366 layout
->format
.tabstop
= IDWriteTextFormat_GetIncrementalTabStop(format
);
5367 layout
->format
.textalignment
= IDWriteTextFormat_GetTextAlignment(format
);
5368 layout
->format
.paralign
= IDWriteTextFormat_GetParagraphAlignment(format
);
5369 layout
->format
.wrapping
= IDWriteTextFormat_GetWordWrapping(format
);
5370 layout
->format
.readingdir
= IDWriteTextFormat_GetReadingDirection(format
);
5371 layout
->format
.flow
= IDWriteTextFormat_GetFlowDirection(format
);
5372 hr
= IDWriteTextFormat_GetLineSpacing(format
, &layout
->format
.spacing
.method
,
5373 &layout
->format
.spacing
.height
, &layout
->format
.spacing
.baseline
);
5377 hr
= IDWriteTextFormat_GetTrimming(format
, &layout
->format
.trimming
, &layout
->format
.trimmingsign
);
5381 /* locale name and length */
5382 len
= IDWriteTextFormat_GetLocaleNameLength(format
);
5383 layout
->format
.locale
= heap_alloc((len
+1)*sizeof(WCHAR
));
5384 if (!layout
->format
.locale
)
5385 return E_OUTOFMEMORY
;
5387 hr
= IDWriteTextFormat_GetLocaleName(format
, layout
->format
.locale
, len
+1);
5390 layout
->format
.locale_len
= len
;
5392 /* font family name and length */
5393 len
= IDWriteTextFormat_GetFontFamilyNameLength(format
);
5394 layout
->format
.family_name
= heap_alloc((len
+1)*sizeof(WCHAR
));
5395 if (!layout
->format
.family_name
)
5396 return E_OUTOFMEMORY
;
5398 hr
= IDWriteTextFormat_GetFontFamilyName(format
, layout
->format
.family_name
, len
+1);
5401 layout
->format
.family_len
= len
;
5403 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat1
, (void**)&format1
);
5406 IDWriteTextFormat2
*format2
;
5408 layout
->format
.vertical_orientation
= IDWriteTextFormat1_GetVerticalGlyphOrientation(format1
);
5409 layout
->format
.optical_alignment
= IDWriteTextFormat1_GetOpticalAlignment(format1
);
5410 IDWriteTextFormat1_GetFontFallback(format1
, &layout
->format
.fallback
);
5412 if (IDWriteTextFormat1_QueryInterface(format1
, &IID_IDWriteTextFormat2
, (void**)&format2
) == S_OK
) {
5413 IDWriteTextFormat2_GetLineSpacing(format2
, &layout
->format
.spacing
);
5414 IDWriteTextFormat2_Release(format2
);
5417 IDWriteTextFormat1_Release(format1
);
5420 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat3
, (void **)&format3
);
5423 layout
->format
.automatic_axes
= IDWriteTextFormat3_GetAutomaticFontAxes(format3
);
5424 IDWriteTextFormat3_Release(format3
);
5427 return IDWriteTextFormat_GetFontCollection(format
, &layout
->format
.collection
);
5430 static HRESULT
init_textlayout(const struct textlayout_desc
*desc
, struct dwrite_textlayout
*layout
)
5432 struct layout_range_header
*range
, *strike
, *underline
, *effect
, *spacing
, *typography
;
5433 static const DWRITE_TEXT_RANGE r
= { 0, ~0u };
5436 layout
->IDWriteTextLayout4_iface
.lpVtbl
= &dwritetextlayoutvtbl
;
5437 layout
->IDWriteTextFormat3_iface
.lpVtbl
= &dwritetextformat3_layout_vtbl
;
5438 layout
->IDWriteTextAnalysisSink1_iface
.lpVtbl
= &dwritetextlayoutsinkvtbl
;
5439 layout
->IDWriteTextAnalysisSource1_iface
.lpVtbl
= &dwritetextlayoutsourcevtbl
;
5440 layout
->refcount
= 1;
5441 layout
->len
= desc
->length
;
5442 layout
->recompute
= RECOMPUTE_EVERYTHING
;
5443 list_init(&layout
->eruns
);
5444 list_init(&layout
->inlineobjects
);
5445 list_init(&layout
->underlines
);
5446 list_init(&layout
->strikethrough
);
5447 list_init(&layout
->runs
);
5448 list_init(&layout
->ranges
);
5449 list_init(&layout
->strike_ranges
);
5450 list_init(&layout
->underline_ranges
);
5451 list_init(&layout
->effects
);
5452 list_init(&layout
->spacing
);
5453 list_init(&layout
->typographies
);
5454 layout
->metrics
.layoutWidth
= desc
->max_width
;
5455 layout
->metrics
.layoutHeight
= desc
->max_height
;
5457 layout
->str
= heap_strdupnW(desc
->string
, desc
->length
);
5458 if (desc
->length
&& !layout
->str
) {
5463 hr
= layout_format_from_textformat(layout
, desc
->format
);
5467 range
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_REGULAR
);
5468 strike
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_STRIKETHROUGH
);
5469 underline
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_UNDERLINE
);
5470 effect
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_EFFECT
);
5471 spacing
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_SPACING
);
5472 typography
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_TYPOGRAPHY
);
5473 if (!range
|| !strike
|| !effect
|| !spacing
|| !typography
|| !underline
) {
5474 free_layout_range(range
);
5475 free_layout_range(strike
);
5476 free_layout_range(underline
);
5477 free_layout_range(effect
);
5478 free_layout_range(spacing
);
5479 free_layout_range(typography
);
5484 layout
->measuringmode
= desc
->is_gdi_compatible
? (desc
->use_gdi_natural
? DWRITE_MEASURING_MODE_GDI_NATURAL
:
5485 DWRITE_MEASURING_MODE_GDI_CLASSIC
) : DWRITE_MEASURING_MODE_NATURAL
;
5486 layout
->ppdip
= desc
->ppdip
;
5487 layout
->transform
= desc
->transform
? *desc
->transform
: identity
;
5489 layout
->factory
= desc
->factory
;
5490 IDWriteFactory7_AddRef(layout
->factory
);
5491 list_add_head(&layout
->ranges
, &range
->entry
);
5492 list_add_head(&layout
->strike_ranges
, &strike
->entry
);
5493 list_add_head(&layout
->underline_ranges
, &underline
->entry
);
5494 list_add_head(&layout
->effects
, &effect
->entry
);
5495 list_add_head(&layout
->spacing
, &spacing
->entry
);
5496 list_add_head(&layout
->typographies
, &typography
->entry
);
5500 IDWriteTextLayout4_Release(&layout
->IDWriteTextLayout4_iface
);
5504 HRESULT
create_textlayout(const struct textlayout_desc
*desc
, IDWriteTextLayout
**layout
)
5506 struct dwrite_textlayout
*object
;
5511 if (desc
->max_width
< 0.0f
|| desc
->max_height
< 0.0f
)
5512 return E_INVALIDARG
;
5514 if (!desc
->format
|| !desc
->string
)
5515 return E_INVALIDARG
;
5517 if (!(object
= heap_alloc_zero(sizeof(*object
))))
5518 return E_OUTOFMEMORY
;
5520 hr
= init_textlayout(desc
, object
);
5522 *layout
= (IDWriteTextLayout
*)&object
->IDWriteTextLayout4_iface
;
5527 static HRESULT WINAPI
dwritetrimmingsign_QueryInterface(IDWriteInlineObject
*iface
, REFIID riid
, void **obj
)
5529 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
5531 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteInlineObject
)) {
5533 IDWriteInlineObject_AddRef(iface
);
5537 WARN("%s not implemented.\n", debugstr_guid(riid
));
5540 return E_NOINTERFACE
;
5543 static ULONG WINAPI
dwritetrimmingsign_AddRef(IDWriteInlineObject
*iface
)
5545 struct dwrite_trimmingsign
*sign
= impl_from_IDWriteInlineObject(iface
);
5546 ULONG refcount
= InterlockedIncrement(&sign
->refcount
);
5548 TRACE("%p, refcount %d.\n", iface
, refcount
);
5553 static ULONG WINAPI
dwritetrimmingsign_Release(IDWriteInlineObject
*iface
)
5555 struct dwrite_trimmingsign
*sign
= impl_from_IDWriteInlineObject(iface
);
5556 ULONG refcount
= InterlockedDecrement(&sign
->refcount
);
5558 TRACE("%p, refcount %d.\n", iface
, refcount
);
5562 IDWriteTextLayout_Release(sign
->layout
);
5569 static HRESULT WINAPI
dwritetrimmingsign_Draw(IDWriteInlineObject
*iface
, void *context
, IDWriteTextRenderer
*renderer
,
5570 FLOAT originX
, FLOAT originY
, BOOL is_sideways
, BOOL is_rtl
, IUnknown
*effect
)
5572 struct dwrite_trimmingsign
*sign
= impl_from_IDWriteInlineObject(iface
);
5573 DWRITE_LINE_METRICS line
;
5576 TRACE("%p, %p, %p, %.2f, %.2f, %d, %d, %p.\n", iface
, context
, renderer
, originX
, originY
,
5577 is_sideways
, is_rtl
, effect
);
5579 IDWriteTextLayout_GetLineMetrics(sign
->layout
, &line
, 1, &line_count
);
5580 return IDWriteTextLayout_Draw(sign
->layout
, context
, renderer
, originX
, originY
- line
.baseline
);
5583 static HRESULT WINAPI
dwritetrimmingsign_GetMetrics(IDWriteInlineObject
*iface
, DWRITE_INLINE_OBJECT_METRICS
*ret
)
5585 struct dwrite_trimmingsign
*sign
= impl_from_IDWriteInlineObject(iface
);
5586 DWRITE_TEXT_METRICS metrics
;
5589 TRACE("%p, %p.\n", iface
, ret
);
5591 hr
= IDWriteTextLayout_GetMetrics(sign
->layout
, &metrics
);
5594 memset(ret
, 0, sizeof(*ret
));
5598 ret
->width
= metrics
.width
;
5600 ret
->baseline
= 0.0f
;
5601 ret
->supportsSideways
= FALSE
;
5605 static HRESULT WINAPI
dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
5607 struct dwrite_trimmingsign
*sign
= impl_from_IDWriteInlineObject(iface
);
5609 TRACE("%p, %p.\n", iface
, overhangs
);
5611 return IDWriteTextLayout_GetOverhangMetrics(sign
->layout
, overhangs
);
5614 static HRESULT WINAPI
dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject
*iface
, DWRITE_BREAK_CONDITION
*before
,
5615 DWRITE_BREAK_CONDITION
*after
)
5617 TRACE("%p, %p, %p.\n", iface
, before
, after
);
5619 *before
= *after
= DWRITE_BREAK_CONDITION_NEUTRAL
;
5623 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl
=
5625 dwritetrimmingsign_QueryInterface
,
5626 dwritetrimmingsign_AddRef
,
5627 dwritetrimmingsign_Release
,
5628 dwritetrimmingsign_Draw
,
5629 dwritetrimmingsign_GetMetrics
,
5630 dwritetrimmingsign_GetOverhangMetrics
,
5631 dwritetrimmingsign_GetBreakConditions
5634 static inline BOOL
is_reading_direction_horz(DWRITE_READING_DIRECTION direction
)
5636 return (direction
== DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
) ||
5637 (direction
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
);
5640 static inline BOOL
is_reading_direction_vert(DWRITE_READING_DIRECTION direction
)
5642 return (direction
== DWRITE_READING_DIRECTION_TOP_TO_BOTTOM
) ||
5643 (direction
== DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
);
5646 static inline BOOL
is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction
)
5648 return (direction
== DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
) ||
5649 (direction
== DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
);
5652 static inline BOOL
is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction
)
5654 return (direction
== DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
) ||
5655 (direction
== DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP
);
5658 HRESULT
create_trimmingsign(IDWriteFactory7
*factory
, IDWriteTextFormat
*format
, IDWriteInlineObject
**sign
)
5660 static const WCHAR ellipsisW
= 0x2026;
5661 struct dwrite_trimmingsign
*object
;
5662 DWRITE_READING_DIRECTION reading
;
5663 DWRITE_FLOW_DIRECTION flow
;
5669 return E_INVALIDARG
;
5671 /* Validate reading/flow direction here, layout creation won't complain about
5672 invalid combinations. */
5673 reading
= IDWriteTextFormat_GetReadingDirection(format
);
5674 flow
= IDWriteTextFormat_GetFlowDirection(format
);
5676 if ((is_reading_direction_horz(reading
) && is_flow_direction_horz(flow
)) ||
5677 (is_reading_direction_vert(reading
) && is_flow_direction_vert(flow
)))
5678 return DWRITE_E_FLOWDIRECTIONCONFLICTS
;
5680 if (!(object
= heap_alloc(sizeof(*object
))))
5681 return E_OUTOFMEMORY
;
5683 object
->IDWriteInlineObject_iface
.lpVtbl
= &dwritetrimmingsignvtbl
;
5684 object
->refcount
= 1;
5686 hr
= IDWriteFactory7_CreateTextLayout(factory
, &ellipsisW
, 1, format
, 0.0f
, 0.0f
, &object
->layout
);
5693 IDWriteTextLayout_SetWordWrapping(object
->layout
, DWRITE_WORD_WRAPPING_NO_WRAP
);
5694 IDWriteTextLayout_SetParagraphAlignment(object
->layout
, DWRITE_PARAGRAPH_ALIGNMENT_NEAR
);
5695 IDWriteTextLayout_SetTextAlignment(object
->layout
, DWRITE_TEXT_ALIGNMENT_LEADING
);
5697 *sign
= &object
->IDWriteInlineObject_iface
;
5702 static HRESULT WINAPI
dwritetextformat_QueryInterface(IDWriteTextFormat3
*iface
, REFIID riid
, void **obj
)
5704 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
5706 if (IsEqualIID(riid
, &IID_IDWriteTextFormat3
) ||
5707 IsEqualIID(riid
, &IID_IDWriteTextFormat2
) ||
5708 IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
5709 IsEqualIID(riid
, &IID_IDWriteTextFormat
) ||
5710 IsEqualIID(riid
, &IID_IUnknown
))
5713 IDWriteTextFormat3_AddRef(iface
);
5717 WARN("%s not implemented.\n", debugstr_guid(riid
));
5721 return E_NOINTERFACE
;
5724 static ULONG WINAPI
dwritetextformat_AddRef(IDWriteTextFormat3
*iface
)
5726 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5727 ULONG refcount
= InterlockedIncrement(&format
->refcount
);
5729 TRACE("%p, refcount %d.\n", iface
, refcount
);
5734 static ULONG WINAPI
dwritetextformat_Release(IDWriteTextFormat3
*iface
)
5736 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5737 ULONG refcount
= InterlockedDecrement(&format
->refcount
);
5739 TRACE("%p, refcount %d.\n", iface
, refcount
);
5743 release_format_data(&format
->format
);
5750 static HRESULT WINAPI
dwritetextformat_SetTextAlignment(IDWriteTextFormat3
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
5752 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5754 TRACE("%p, %d.\n", iface
, alignment
);
5756 return format_set_textalignment(&format
->format
, alignment
, NULL
);
5759 static HRESULT WINAPI
dwritetextformat_SetParagraphAlignment(IDWriteTextFormat3
*iface
,
5760 DWRITE_PARAGRAPH_ALIGNMENT alignment
)
5762 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5764 TRACE("%p, %d.\n", iface
, alignment
);
5766 return format_set_paralignment(&format
->format
, alignment
, NULL
);
5769 static HRESULT WINAPI
dwritetextformat_SetWordWrapping(IDWriteTextFormat3
*iface
, DWRITE_WORD_WRAPPING wrapping
)
5771 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5773 TRACE("%p, %d.\n", iface
, wrapping
);
5775 return format_set_wordwrapping(&format
->format
, wrapping
, NULL
);
5778 static HRESULT WINAPI
dwritetextformat_SetReadingDirection(IDWriteTextFormat3
*iface
, DWRITE_READING_DIRECTION direction
)
5780 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5782 TRACE("%p, %d.\n", iface
, direction
);
5784 return format_set_readingdirection(&format
->format
, direction
, NULL
);
5787 static HRESULT WINAPI
dwritetextformat_SetFlowDirection(IDWriteTextFormat3
*iface
, DWRITE_FLOW_DIRECTION direction
)
5789 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5791 TRACE("%p, %d.\n", iface
, direction
);
5793 return format_set_flowdirection(&format
->format
, direction
, NULL
);
5796 static HRESULT WINAPI
dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat3
*iface
, FLOAT tabstop
)
5798 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5800 TRACE("%p, %f.\n", iface
, tabstop
);
5802 if (tabstop
<= 0.0f
)
5803 return E_INVALIDARG
;
5805 format
->format
.tabstop
= tabstop
;
5809 static HRESULT WINAPI
dwritetextformat_SetTrimming(IDWriteTextFormat3
*iface
, DWRITE_TRIMMING
const *trimming
,
5810 IDWriteInlineObject
*trimming_sign
)
5812 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5814 TRACE("%p, %p, %p.\n", iface
, trimming
, trimming_sign
);
5816 return format_set_trimming(&format
->format
, trimming
, trimming_sign
, NULL
);
5819 static HRESULT WINAPI
dwritetextformat_SetLineSpacing(IDWriteTextFormat3
*iface
, DWRITE_LINE_SPACING_METHOD method
,
5820 FLOAT height
, FLOAT baseline
)
5822 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5823 DWRITE_LINE_SPACING spacing
;
5825 TRACE("%p, %d, %f, %f.\n", iface
, method
, height
, baseline
);
5827 spacing
= format
->format
.spacing
;
5828 spacing
.method
= method
;
5829 spacing
.height
= height
;
5830 spacing
.baseline
= baseline
;
5832 return format_set_linespacing(&format
->format
, &spacing
, NULL
);
5835 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_GetTextAlignment(IDWriteTextFormat3
*iface
)
5837 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5839 TRACE("%p.\n", iface
);
5841 return format
->format
.textalignment
;
5844 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_GetParagraphAlignment(IDWriteTextFormat3
*iface
)
5846 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5848 TRACE("%p.\n", iface
);
5850 return format
->format
.paralign
;
5853 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_GetWordWrapping(IDWriteTextFormat3
*iface
)
5855 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5857 TRACE("%p.\n", iface
);
5859 return format
->format
.wrapping
;
5862 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_GetReadingDirection(IDWriteTextFormat3
*iface
)
5864 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5866 TRACE("%p.\n", iface
);
5868 return format
->format
.readingdir
;
5871 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_GetFlowDirection(IDWriteTextFormat3
*iface
)
5873 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5875 TRACE("%p.\n", iface
);
5877 return format
->format
.flow
;
5880 static FLOAT WINAPI
dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat3
*iface
)
5882 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5884 TRACE("%p.\n", iface
);
5886 return format
->format
.tabstop
;
5889 static HRESULT WINAPI
dwritetextformat_GetTrimming(IDWriteTextFormat3
*iface
, DWRITE_TRIMMING
*options
,
5890 IDWriteInlineObject
**trimming_sign
)
5892 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5894 TRACE("%p, %p, %p.\n", iface
, options
, trimming_sign
);
5896 *options
= format
->format
.trimming
;
5897 if ((*trimming_sign
= format
->format
.trimmingsign
))
5898 IDWriteInlineObject_AddRef(*trimming_sign
);
5903 static HRESULT WINAPI
dwritetextformat_GetLineSpacing(IDWriteTextFormat3
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
5904 FLOAT
*spacing
, FLOAT
*baseline
)
5906 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5908 TRACE("%p, %p, %p, %p.\n", iface
, method
, spacing
, baseline
);
5910 *method
= format
->format
.spacing
.method
;
5911 *spacing
= format
->format
.spacing
.height
;
5912 *baseline
= format
->format
.spacing
.baseline
;
5916 static HRESULT WINAPI
dwritetextformat_GetFontCollection(IDWriteTextFormat3
*iface
, IDWriteFontCollection
**collection
)
5918 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5920 TRACE("%p, %p.\n", iface
, collection
);
5922 *collection
= format
->format
.collection
;
5923 IDWriteFontCollection_AddRef(*collection
);
5928 static UINT32 WINAPI
dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat3
*iface
)
5930 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5932 TRACE("%p.\n", iface
);
5934 return format
->format
.family_len
;
5937 static HRESULT WINAPI
dwritetextformat_GetFontFamilyName(IDWriteTextFormat3
*iface
, WCHAR
*name
, UINT32 size
)
5939 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5941 TRACE("%p, %p, %u.\n", iface
, name
, size
);
5943 if (size
<= format
->format
.family_len
)
5944 return E_NOT_SUFFICIENT_BUFFER
;
5945 wcscpy(name
, format
->format
.family_name
);
5949 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_GetFontWeight(IDWriteTextFormat3
*iface
)
5951 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5953 TRACE("%p.\n", iface
);
5955 return format
->format
.weight
;
5958 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_GetFontStyle(IDWriteTextFormat3
*iface
)
5960 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5962 TRACE("%p.\n", iface
);
5964 return format
->format
.style
;
5967 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_GetFontStretch(IDWriteTextFormat3
*iface
)
5969 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5971 TRACE("%p.\n", iface
);
5973 return format
->format
.stretch
;
5976 static FLOAT WINAPI
dwritetextformat_GetFontSize(IDWriteTextFormat3
*iface
)
5978 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5980 TRACE("%p.\n", iface
);
5982 return format
->format
.fontsize
;
5985 static UINT32 WINAPI
dwritetextformat_GetLocaleNameLength(IDWriteTextFormat3
*iface
)
5987 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5989 TRACE("%p.\n", iface
);
5991 return format
->format
.locale_len
;
5994 static HRESULT WINAPI
dwritetextformat_GetLocaleName(IDWriteTextFormat3
*iface
, WCHAR
*name
, UINT32 size
)
5996 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
5998 TRACE("%p, %p %u.\n", iface
, name
, size
);
6000 if (size
<= format
->format
.locale_len
)
6001 return E_NOT_SUFFICIENT_BUFFER
;
6002 wcscpy(name
, format
->format
.locale
);
6006 static HRESULT WINAPI
dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat3
*iface
,
6007 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
6009 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6011 TRACE("%p, %d.\n", iface
, orientation
);
6013 return format_set_vertical_orientation(&format
->format
, orientation
, NULL
);
6016 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat3
*iface
)
6018 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6020 TRACE("%p.\n", iface
);
6022 return format
->format
.vertical_orientation
;
6025 static HRESULT WINAPI
dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat3
*iface
, BOOL lastline_wrapping_enabled
)
6027 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6029 TRACE("%p, %d.\n", iface
, lastline_wrapping_enabled
);
6031 format
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
6035 static BOOL WINAPI
dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat3
*iface
)
6037 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6039 TRACE("%p.\n", iface
);
6041 return format
->format
.last_line_wrapping
;
6044 static HRESULT WINAPI
dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat3
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
6046 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6048 TRACE("%p, %d.\n", iface
, alignment
);
6050 return format_set_optical_alignment(&format
->format
, alignment
);
6053 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat3
*iface
)
6055 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6057 TRACE("%p.\n", iface
);
6059 return format
->format
.optical_alignment
;
6062 static HRESULT WINAPI
dwritetextformat1_SetFontFallback(IDWriteTextFormat3
*iface
, IDWriteFontFallback
*fallback
)
6064 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6066 TRACE("%p, %p.\n", iface
, fallback
);
6068 return set_fontfallback_for_format(&format
->format
, fallback
);
6071 static HRESULT WINAPI
dwritetextformat1_GetFontFallback(IDWriteTextFormat3
*iface
, IDWriteFontFallback
**fallback
)
6073 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6075 TRACE("%p, %p.\n", iface
, fallback
);
6077 return get_fontfallback_from_format(&format
->format
, fallback
);
6080 static HRESULT WINAPI
dwritetextformat2_SetLineSpacing(IDWriteTextFormat3
*iface
, DWRITE_LINE_SPACING
const *spacing
)
6082 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6084 TRACE("%p, %p.\n", iface
, spacing
);
6086 return format_set_linespacing(&format
->format
, spacing
, NULL
);
6089 static HRESULT WINAPI
dwritetextformat2_GetLineSpacing(IDWriteTextFormat3
*iface
, DWRITE_LINE_SPACING
*spacing
)
6091 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6093 TRACE("%p, %p.\n", iface
, spacing
);
6095 *spacing
= format
->format
.spacing
;
6099 static HRESULT WINAPI
dwritetextformat3_SetFontAxisValues(IDWriteTextFormat3
*iface
,
6100 DWRITE_FONT_AXIS_VALUE
const *axis_values
, UINT32 num_values
)
6102 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6104 TRACE("%p, %p, %u.\n", iface
, axis_values
, num_values
);
6106 return format_set_font_axisvalues(&format
->format
, axis_values
, num_values
);
6109 static UINT32 WINAPI
dwritetextformat3_GetFontAxisValueCount(IDWriteTextFormat3
*iface
)
6111 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6113 TRACE("%p.\n", iface
);
6115 return format
->format
.axis_values_count
;
6118 static HRESULT WINAPI
dwritetextformat3_GetFontAxisValues(IDWriteTextFormat3
*iface
,
6119 DWRITE_FONT_AXIS_VALUE
*axis_values
, UINT32 num_values
)
6121 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6123 TRACE("%p, %p, %u.\n", iface
, axis_values
, num_values
);
6125 return format_get_font_axisvalues(&format
->format
, axis_values
, num_values
);
6128 static DWRITE_AUTOMATIC_FONT_AXES WINAPI
dwritetextformat3_GetAutomaticFontAxes(IDWriteTextFormat3
*iface
)
6130 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6132 TRACE("%p.\n", iface
);
6134 return format
->format
.automatic_axes
;
6137 static HRESULT WINAPI
dwritetextformat3_SetAutomaticFontAxes(IDWriteTextFormat3
*iface
, DWRITE_AUTOMATIC_FONT_AXES axes
)
6139 struct dwrite_textformat
*format
= impl_from_IDWriteTextFormat3(iface
);
6141 TRACE("%p, %d.\n", iface
, axes
);
6143 format
->format
.automatic_axes
= axes
;
6148 static const IDWriteTextFormat3Vtbl dwritetextformatvtbl
=
6150 dwritetextformat_QueryInterface
,
6151 dwritetextformat_AddRef
,
6152 dwritetextformat_Release
,
6153 dwritetextformat_SetTextAlignment
,
6154 dwritetextformat_SetParagraphAlignment
,
6155 dwritetextformat_SetWordWrapping
,
6156 dwritetextformat_SetReadingDirection
,
6157 dwritetextformat_SetFlowDirection
,
6158 dwritetextformat_SetIncrementalTabStop
,
6159 dwritetextformat_SetTrimming
,
6160 dwritetextformat_SetLineSpacing
,
6161 dwritetextformat_GetTextAlignment
,
6162 dwritetextformat_GetParagraphAlignment
,
6163 dwritetextformat_GetWordWrapping
,
6164 dwritetextformat_GetReadingDirection
,
6165 dwritetextformat_GetFlowDirection
,
6166 dwritetextformat_GetIncrementalTabStop
,
6167 dwritetextformat_GetTrimming
,
6168 dwritetextformat_GetLineSpacing
,
6169 dwritetextformat_GetFontCollection
,
6170 dwritetextformat_GetFontFamilyNameLength
,
6171 dwritetextformat_GetFontFamilyName
,
6172 dwritetextformat_GetFontWeight
,
6173 dwritetextformat_GetFontStyle
,
6174 dwritetextformat_GetFontStretch
,
6175 dwritetextformat_GetFontSize
,
6176 dwritetextformat_GetLocaleNameLength
,
6177 dwritetextformat_GetLocaleName
,
6178 dwritetextformat1_SetVerticalGlyphOrientation
,
6179 dwritetextformat1_GetVerticalGlyphOrientation
,
6180 dwritetextformat1_SetLastLineWrapping
,
6181 dwritetextformat1_GetLastLineWrapping
,
6182 dwritetextformat1_SetOpticalAlignment
,
6183 dwritetextformat1_GetOpticalAlignment
,
6184 dwritetextformat1_SetFontFallback
,
6185 dwritetextformat1_GetFontFallback
,
6186 dwritetextformat2_SetLineSpacing
,
6187 dwritetextformat2_GetLineSpacing
,
6188 dwritetextformat3_SetFontAxisValues
,
6189 dwritetextformat3_GetFontAxisValueCount
,
6190 dwritetextformat3_GetFontAxisValues
,
6191 dwritetextformat3_GetAutomaticFontAxes
,
6192 dwritetextformat3_SetAutomaticFontAxes
,
6195 static struct dwrite_textformat
*unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat
*iface
)
6197 return (iface
->lpVtbl
== (IDWriteTextFormatVtbl
*)&dwritetextformatvtbl
) ?
6198 CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat3_iface
) : NULL
;
6201 HRESULT
create_textformat(const WCHAR
*family_name
, IDWriteFontCollection
*collection
, DWRITE_FONT_WEIGHT weight
,
6202 DWRITE_FONT_STYLE style
, DWRITE_FONT_STRETCH stretch
, FLOAT size
, const WCHAR
*locale
, IDWriteTextFormat
**format
)
6204 struct dwrite_textformat
*object
;
6209 return E_INVALIDARG
;
6211 if (((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
) ||
6212 ((UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
) ||
6213 ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
))
6214 return E_INVALIDARG
;
6216 if (!(object
= heap_alloc_zero(sizeof(*object
))))
6217 return E_OUTOFMEMORY
;
6219 object
->IDWriteTextFormat3_iface
.lpVtbl
= &dwritetextformatvtbl
;
6220 object
->refcount
= 1;
6221 object
->format
.family_name
= heap_strdupW(family_name
);
6222 object
->format
.family_len
= wcslen(family_name
);
6223 object
->format
.locale
= heap_strdupW(locale
);
6224 object
->format
.locale_len
= wcslen(locale
);
6225 /* Force locale name to lower case, layout will inherit this modified value. */
6226 wcslwr(object
->format
.locale
);
6227 object
->format
.weight
= weight
;
6228 object
->format
.style
= style
;
6229 object
->format
.fontsize
= size
;
6230 object
->format
.tabstop
= 4.0f
* size
;
6231 object
->format
.stretch
= stretch
;
6232 object
->format
.last_line_wrapping
= TRUE
;
6233 object
->format
.collection
= collection
;
6234 IDWriteFontCollection_AddRef(object
->format
.collection
);
6236 *format
= (IDWriteTextFormat
*)&object
->IDWriteTextFormat3_iface
;
6241 static HRESULT WINAPI
dwritetypography_QueryInterface(IDWriteTypography
*iface
, REFIID riid
, void **obj
)
6243 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
6245 if (IsEqualIID(riid
, &IID_IDWriteTypography
) || IsEqualIID(riid
, &IID_IUnknown
)) {
6247 IDWriteTypography_AddRef(iface
);
6251 WARN("%s not implemented.\n", debugstr_guid(riid
));
6255 return E_NOINTERFACE
;
6258 static ULONG WINAPI
dwritetypography_AddRef(IDWriteTypography
*iface
)
6260 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
6261 ULONG refcount
= InterlockedIncrement(&typography
->refcount
);
6263 TRACE("%p, refcount %d.\n", iface
, refcount
);
6268 static ULONG WINAPI
dwritetypography_Release(IDWriteTypography
*iface
)
6270 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
6271 ULONG refcount
= InterlockedDecrement(&typography
->refcount
);
6273 TRACE("%p, refcount %d.\n", iface
, refcount
);
6277 heap_free(typography
->features
);
6278 heap_free(typography
);
6284 static HRESULT WINAPI
dwritetypography_AddFontFeature(IDWriteTypography
*iface
, DWRITE_FONT_FEATURE feature
)
6286 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
6288 TRACE("%p, %s, %u.\n", iface
, debugstr_tag(feature
.nameTag
), feature
.parameter
);
6290 if (!dwrite_array_reserve((void **)&typography
->features
, &typography
->capacity
, typography
->count
+ 1,
6291 sizeof(*typography
->features
)))
6293 return E_OUTOFMEMORY
;
6296 typography
->features
[typography
->count
++] = feature
;
6301 static UINT32 WINAPI
dwritetypography_GetFontFeatureCount(IDWriteTypography
*iface
)
6303 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
6305 TRACE("%p.\n", iface
);
6307 return typography
->count
;
6310 static HRESULT WINAPI
dwritetypography_GetFontFeature(IDWriteTypography
*iface
, UINT32 index
,
6311 DWRITE_FONT_FEATURE
*feature
)
6313 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
6315 TRACE("%p, %u, %p.\n", iface
, index
, feature
);
6317 if (index
>= typography
->count
)
6318 return E_INVALIDARG
;
6320 *feature
= typography
->features
[index
];
6324 static const IDWriteTypographyVtbl dwritetypographyvtbl
= {
6325 dwritetypography_QueryInterface
,
6326 dwritetypography_AddRef
,
6327 dwritetypography_Release
,
6328 dwritetypography_AddFontFeature
,
6329 dwritetypography_GetFontFeatureCount
,
6330 dwritetypography_GetFontFeature
6333 HRESULT
create_typography(IDWriteTypography
**ret
)
6335 struct dwrite_typography
*typography
;
6339 typography
= heap_alloc_zero(sizeof(*typography
));
6341 return E_OUTOFMEMORY
;
6343 typography
->IDWriteTypography_iface
.lpVtbl
= &dwritetypographyvtbl
;
6344 typography
->refcount
= 1;
6346 *ret
= &typography
->IDWriteTypography_iface
;