2 * Text format and layout
4 * Copyright 2012, 2014-2017 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
29 #include "dwrite_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
34 struct dwrite_textformat_data
{
40 DWRITE_FONT_WEIGHT weight
;
41 DWRITE_FONT_STYLE style
;
42 DWRITE_FONT_STRETCH stretch
;
44 DWRITE_PARAGRAPH_ALIGNMENT paralign
;
45 DWRITE_READING_DIRECTION readingdir
;
46 DWRITE_WORD_WRAPPING wrapping
;
47 BOOL last_line_wrapping
;
48 DWRITE_TEXT_ALIGNMENT textalignment
;
49 DWRITE_FLOW_DIRECTION flow
;
50 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation
;
51 DWRITE_OPTICAL_ALIGNMENT optical_alignment
;
52 DWRITE_LINE_SPACING spacing
;
56 DWRITE_TRIMMING trimming
;
57 IDWriteInlineObject
*trimmingsign
;
59 IDWriteFontCollection
*collection
;
60 IDWriteFontFallback
*fallback
;
63 enum layout_range_attr_kind
{
64 LAYOUT_RANGE_ATTR_WEIGHT
,
65 LAYOUT_RANGE_ATTR_STYLE
,
66 LAYOUT_RANGE_ATTR_STRETCH
,
67 LAYOUT_RANGE_ATTR_FONTSIZE
,
68 LAYOUT_RANGE_ATTR_EFFECT
,
69 LAYOUT_RANGE_ATTR_INLINE
,
70 LAYOUT_RANGE_ATTR_UNDERLINE
,
71 LAYOUT_RANGE_ATTR_STRIKETHROUGH
,
72 LAYOUT_RANGE_ATTR_PAIR_KERNING
,
73 LAYOUT_RANGE_ATTR_FONTCOLL
,
74 LAYOUT_RANGE_ATTR_LOCALE
,
75 LAYOUT_RANGE_ATTR_FONTFAMILY
,
76 LAYOUT_RANGE_ATTR_SPACING
,
77 LAYOUT_RANGE_ATTR_TYPOGRAPHY
80 struct layout_range_attr_value
{
81 DWRITE_TEXT_RANGE range
;
83 DWRITE_FONT_WEIGHT weight
;
84 DWRITE_FONT_STYLE style
;
85 DWRITE_FONT_STRETCH stretch
;
87 IDWriteInlineObject
*object
;
92 IDWriteFontCollection
*collection
;
94 const WCHAR
*fontfamily
;
95 FLOAT spacing
[3]; /* in arguments order - leading, trailing, advance */
96 IDWriteTypography
*typography
;
100 enum layout_range_kind
{
101 LAYOUT_RANGE_REGULAR
,
102 LAYOUT_RANGE_UNDERLINE
,
103 LAYOUT_RANGE_STRIKETHROUGH
,
105 LAYOUT_RANGE_SPACING
,
106 LAYOUT_RANGE_TYPOGRAPHY
109 struct layout_range_header
{
111 enum layout_range_kind kind
;
112 DWRITE_TEXT_RANGE range
;
115 struct layout_range
{
116 struct layout_range_header h
;
117 DWRITE_FONT_WEIGHT weight
;
118 DWRITE_FONT_STYLE style
;
120 DWRITE_FONT_STRETCH stretch
;
121 IDWriteInlineObject
*object
;
123 IDWriteFontCollection
*collection
;
124 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
128 struct layout_range_bool
{
129 struct layout_range_header h
;
133 struct layout_range_iface
{
134 struct layout_range_header h
;
138 struct layout_range_spacing
{
139 struct layout_range_header h
;
145 enum layout_run_kind
{
150 struct inline_object_run
{
151 IDWriteInlineObject
*object
;
155 struct regular_layout_run
{
156 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
157 DWRITE_GLYPH_RUN run
;
158 DWRITE_SCRIPT_ANALYSIS sa
;
162 DWRITE_GLYPH_OFFSET
*offsets
;
163 /* this is actual glyph count after shaping, it's not necessary the same as reported to Draw() */
169 enum layout_run_kind kind
;
171 struct inline_object_run object
;
172 struct regular_layout_run regular
;
178 struct layout_effective_run
{
180 const struct layout_run
*run
; /* nominal run this one is based on */
181 UINT32 start
; /* relative text position, 0 means first text position of a nominal run */
182 UINT32 length
; /* length in codepoints that this run covers */
183 UINT32 glyphcount
; /* total glyph count in this run */
184 IUnknown
*effect
; /* original reference is kept only at range level */
185 FLOAT origin_x
; /* baseline X position */
186 FLOAT origin_y
; /* baseline Y position */
187 FLOAT align_dx
; /* adjustment from text alignment */
188 FLOAT width
; /* run width */
189 UINT16
*clustermap
; /* effective clustermap, allocated separately, is not reused from nominal map */
190 UINT32 line
; /* 0-based line index in line metrics array */
191 BOOL underlined
; /* set if this run is underlined */
194 struct layout_effective_inline
{
196 IDWriteInlineObject
*object
; /* inline object, set explicitly or added when trimming a line */
197 IUnknown
*effect
; /* original reference is kept only at range level */
199 FLOAT origin_x
; /* left X position */
200 FLOAT origin_y
; /* left top corner Y position */
201 FLOAT align_dx
; /* adjustment from text alignment */
202 FLOAT width
; /* object width as it's reported it */
203 BOOL is_sideways
; /* vertical flow direction flag passed to Draw */
204 BOOL is_rtl
; /* bidi flag passed to Draw */
205 UINT32 line
; /* 0-based line index in line metrics array */
208 struct layout_underline
{
210 const struct layout_effective_run
*run
;
214 struct layout_strikethrough
{
216 const struct layout_effective_run
*run
;
217 DWRITE_STRIKETHROUGH s
;
220 struct layout_cluster
{
221 const struct layout_run
*run
; /* link to nominal run this cluster belongs to */
222 UINT32 position
; /* relative to run, first cluster has 0 position */
226 FLOAT height
; /* height based on content */
227 FLOAT baseline
; /* baseline based on content */
230 enum layout_recompute_mask
{
231 RECOMPUTE_CLUSTERS
= 1 << 0,
232 RECOMPUTE_MINIMAL_WIDTH
= 1 << 1,
233 RECOMPUTE_LINES
= 1 << 2,
234 RECOMPUTE_OVERHANGS
= 1 << 3,
235 RECOMPUTE_LINES_AND_OVERHANGS
= RECOMPUTE_LINES
| RECOMPUTE_OVERHANGS
,
236 RECOMPUTE_EVERYTHING
= 0xffff
239 struct dwrite_textlayout
{
240 IDWriteTextLayout3 IDWriteTextLayout3_iface
;
241 IDWriteTextFormat1 IDWriteTextFormat1_iface
;
242 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface
;
243 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface
;
246 IDWriteFactory4
*factory
;
250 struct dwrite_textformat_data format
;
251 struct list strike_ranges
;
252 struct list underline_ranges
;
253 struct list typographies
;
258 /* lists ready to use by Draw() */
260 struct list inlineobjects
;
261 struct list underlines
;
262 struct list strikethrough
;
265 DWRITE_LINE_BREAKPOINT
*nominal_breakpoints
;
266 DWRITE_LINE_BREAKPOINT
*actual_breakpoints
;
268 struct layout_cluster
*clusters
;
269 DWRITE_CLUSTER_METRICS
*clustermetrics
;
270 UINT32 cluster_count
;
273 struct layout_line
*lines
;
274 DWRITE_LINE_METRICS1
*linemetrics
;
277 DWRITE_TEXT_METRICS1 metrics
;
278 DWRITE_OVERHANG_METRICS overhangs
;
280 DWRITE_MEASURING_MODE measuringmode
;
282 /* gdi-compatible layout specifics */
284 DWRITE_MATRIX transform
;
287 struct dwrite_textformat
{
288 IDWriteTextFormat2 IDWriteTextFormat2_iface
;
290 struct dwrite_textformat_data format
;
293 struct dwrite_trimmingsign
{
294 IDWriteInlineObject IDWriteInlineObject_iface
;
297 IDWriteTextLayout
*layout
;
300 struct dwrite_typography
{
301 IDWriteTypography IDWriteTypography_iface
;
304 DWRITE_FONT_FEATURE
*features
;
314 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl
;
316 static void release_format_data(struct dwrite_textformat_data
*data
)
318 if (data
->collection
) IDWriteFontCollection_Release(data
->collection
);
319 if (data
->fallback
) IDWriteFontFallback_Release(data
->fallback
);
320 if (data
->trimmingsign
) IDWriteInlineObject_Release(data
->trimmingsign
);
321 heap_free(data
->family_name
);
322 heap_free(data
->locale
);
325 static inline struct dwrite_textlayout
*impl_from_IDWriteTextLayout3(IDWriteTextLayout3
*iface
)
327 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextLayout3_iface
);
330 static inline struct dwrite_textlayout
*impl_layout_from_IDWriteTextFormat1(IDWriteTextFormat1
*iface
)
332 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextFormat1_iface
);
335 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1
*iface
)
337 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSink1_iface
);
340 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1
*iface
)
342 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSource1_iface
);
345 static inline struct dwrite_textformat
*impl_from_IDWriteTextFormat2(IDWriteTextFormat2
*iface
)
347 return CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat2_iface
);
350 static struct dwrite_textformat
*unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat
*);
352 static inline struct dwrite_trimmingsign
*impl_from_IDWriteInlineObject(IDWriteInlineObject
*iface
)
354 return CONTAINING_RECORD(iface
, struct dwrite_trimmingsign
, IDWriteInlineObject_iface
);
357 static inline struct dwrite_typography
*impl_from_IDWriteTypography(IDWriteTypography
*iface
)
359 return CONTAINING_RECORD(iface
, struct dwrite_typography
, IDWriteTypography_iface
);
362 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION
*descr
)
364 return wine_dbg_sprintf("[%u,%u)", descr
->textPosition
, descr
->textPosition
+ descr
->stringLength
);
367 static inline BOOL
is_layout_gdi_compatible(struct dwrite_textlayout
*layout
)
369 return layout
->measuringmode
!= DWRITE_MEASURING_MODE_NATURAL
;
372 static inline HRESULT
format_set_textalignment(struct dwrite_textformat_data
*format
, DWRITE_TEXT_ALIGNMENT alignment
,
375 if ((UINT32
)alignment
> DWRITE_TEXT_ALIGNMENT_JUSTIFIED
)
377 if (changed
) *changed
= format
->textalignment
!= alignment
;
378 format
->textalignment
= alignment
;
382 static inline HRESULT
format_set_paralignment(struct dwrite_textformat_data
*format
,
383 DWRITE_PARAGRAPH_ALIGNMENT alignment
, BOOL
*changed
)
385 if ((UINT32
)alignment
> DWRITE_PARAGRAPH_ALIGNMENT_CENTER
)
387 if (changed
) *changed
= format
->paralign
!= alignment
;
388 format
->paralign
= alignment
;
392 static inline HRESULT
format_set_readingdirection(struct dwrite_textformat_data
*format
,
393 DWRITE_READING_DIRECTION direction
, BOOL
*changed
)
395 if ((UINT32
)direction
> DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
)
397 if (changed
) *changed
= format
->readingdir
!= direction
;
398 format
->readingdir
= direction
;
402 static inline HRESULT
format_set_wordwrapping(struct dwrite_textformat_data
*format
,
403 DWRITE_WORD_WRAPPING wrapping
, BOOL
*changed
)
405 if ((UINT32
)wrapping
> DWRITE_WORD_WRAPPING_CHARACTER
)
407 if (changed
) *changed
= format
->wrapping
!= wrapping
;
408 format
->wrapping
= wrapping
;
412 static inline HRESULT
format_set_flowdirection(struct dwrite_textformat_data
*format
,
413 DWRITE_FLOW_DIRECTION direction
, BOOL
*changed
)
415 if ((UINT32
)direction
> DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
)
417 if (changed
) *changed
= format
->flow
!= direction
;
418 format
->flow
= direction
;
422 static inline HRESULT
format_set_trimming(struct dwrite_textformat_data
*format
,
423 DWRITE_TRIMMING
const *trimming
, IDWriteInlineObject
*trimming_sign
, BOOL
*changed
)
428 if ((UINT32
)trimming
->granularity
> DWRITE_TRIMMING_GRANULARITY_WORD
)
432 *changed
= !!memcmp(&format
->trimming
, trimming
, sizeof(*trimming
));
433 if (format
->trimmingsign
!= trimming_sign
)
437 format
->trimming
= *trimming
;
438 if (format
->trimmingsign
)
439 IDWriteInlineObject_Release(format
->trimmingsign
);
440 format
->trimmingsign
= trimming_sign
;
441 if (format
->trimmingsign
)
442 IDWriteInlineObject_AddRef(format
->trimmingsign
);
446 static inline HRESULT
format_set_linespacing(struct dwrite_textformat_data
*format
,
447 DWRITE_LINE_SPACING
const *spacing
, BOOL
*changed
)
449 if (spacing
->height
< 0.0f
|| spacing
->leadingBefore
< 0.0f
|| spacing
->leadingBefore
> 1.0f
||
450 (UINT32
)spacing
->method
> DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
)
454 *changed
= memcmp(spacing
, &format
->spacing
, sizeof(*spacing
));
456 format
->spacing
= *spacing
;
460 static HRESULT
get_fontfallback_from_format(const struct dwrite_textformat_data
*format
, IDWriteFontFallback
**fallback
)
462 *fallback
= format
->fallback
;
464 IDWriteFontFallback_AddRef(*fallback
);
468 static HRESULT
set_fontfallback_for_format(struct dwrite_textformat_data
*format
, IDWriteFontFallback
*fallback
)
470 if (format
->fallback
)
471 IDWriteFontFallback_Release(format
->fallback
);
472 format
->fallback
= fallback
;
474 IDWriteFontFallback_AddRef(fallback
);
478 static HRESULT
format_set_optical_alignment(struct dwrite_textformat_data
*format
,
479 DWRITE_OPTICAL_ALIGNMENT alignment
)
481 if ((UINT32
)alignment
> DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS
)
483 format
->optical_alignment
= alignment
;
487 static BOOL
is_run_rtl(const struct layout_effective_run
*run
)
489 return run
->run
->u
.regular
.run
.bidiLevel
& 1;
492 static struct layout_run
*alloc_layout_run(enum layout_run_kind kind
)
494 struct layout_run
*ret
;
496 ret
= heap_alloc(sizeof(*ret
));
497 if (!ret
) return NULL
;
499 memset(ret
, 0, sizeof(*ret
));
501 if (kind
== LAYOUT_RUN_REGULAR
) {
502 ret
->u
.regular
.sa
.script
= Script_Unknown
;
503 ret
->u
.regular
.sa
.shapes
= DWRITE_SCRIPT_SHAPES_DEFAULT
;
509 static void free_layout_runs(struct dwrite_textlayout
*layout
)
511 struct layout_run
*cur
, *cur2
;
512 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->runs
, struct layout_run
, entry
) {
513 list_remove(&cur
->entry
);
514 if (cur
->kind
== LAYOUT_RUN_REGULAR
) {
515 if (cur
->u
.regular
.run
.fontFace
)
516 IDWriteFontFace_Release(cur
->u
.regular
.run
.fontFace
);
517 heap_free(cur
->u
.regular
.glyphs
);
518 heap_free(cur
->u
.regular
.clustermap
);
519 heap_free(cur
->u
.regular
.advances
);
520 heap_free(cur
->u
.regular
.offsets
);
526 static void free_layout_eruns(struct dwrite_textlayout
*layout
)
528 struct layout_effective_inline
*in
, *in2
;
529 struct layout_effective_run
*cur
, *cur2
;
530 struct layout_strikethrough
*s
, *s2
;
531 struct layout_underline
*u
, *u2
;
533 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->eruns
, struct layout_effective_run
, entry
) {
534 list_remove(&cur
->entry
);
535 heap_free(cur
->clustermap
);
539 LIST_FOR_EACH_ENTRY_SAFE(in
, in2
, &layout
->inlineobjects
, struct layout_effective_inline
, entry
) {
540 list_remove(&in
->entry
);
544 LIST_FOR_EACH_ENTRY_SAFE(u
, u2
, &layout
->underlines
, struct layout_underline
, entry
) {
545 list_remove(&u
->entry
);
549 LIST_FOR_EACH_ENTRY_SAFE(s
, s2
, &layout
->strikethrough
, struct layout_strikethrough
, entry
) {
550 list_remove(&s
->entry
);
555 /* Used to resolve break condition by forcing stronger condition over weaker. */
556 static inline DWRITE_BREAK_CONDITION
override_break_condition(DWRITE_BREAK_CONDITION existingbreak
, DWRITE_BREAK_CONDITION newbreak
)
558 switch (existingbreak
) {
559 case DWRITE_BREAK_CONDITION_NEUTRAL
:
561 case DWRITE_BREAK_CONDITION_CAN_BREAK
:
562 return newbreak
== DWRITE_BREAK_CONDITION_NEUTRAL
? existingbreak
: newbreak
;
563 /* let's keep stronger conditions as is */
564 case DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
:
565 case DWRITE_BREAK_CONDITION_MUST_BREAK
:
568 ERR("unknown break condition %d\n", existingbreak
);
571 return existingbreak
;
574 /* This helper should be used to get effective range length, in other words it returns number of text
575 positions from range starting point to the end of the range, limited by layout text length */
576 static inline UINT32
get_clipped_range_length(const struct dwrite_textlayout
*layout
, const struct layout_range
*range
)
578 if (range
->h
.range
.startPosition
+ range
->h
.range
.length
<= layout
->len
)
579 return range
->h
.range
.length
;
580 return layout
->len
- range
->h
.range
.startPosition
;
583 /* Actual breakpoint data gets updated with break condition required by inline object set for range 'cur'. */
584 static HRESULT
layout_update_breakpoints_range(struct dwrite_textlayout
*layout
, const struct layout_range
*cur
)
586 DWRITE_BREAK_CONDITION before
, after
;
590 /* ignore returned conditions if failed */
591 hr
= IDWriteInlineObject_GetBreakConditions(cur
->object
, &before
, &after
);
593 after
= before
= DWRITE_BREAK_CONDITION_NEUTRAL
;
595 if (!layout
->actual_breakpoints
) {
596 layout
->actual_breakpoints
= heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
597 if (!layout
->actual_breakpoints
)
598 return E_OUTOFMEMORY
;
599 memcpy(layout
->actual_breakpoints
, layout
->nominal_breakpoints
, sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
602 length
= get_clipped_range_length(layout
, cur
);
603 for (i
= cur
->h
.range
.startPosition
; i
< length
+ cur
->h
.range
.startPosition
; i
++) {
604 /* for first codepoint check if there's anything before it and update accordingly */
605 if (i
== cur
->h
.range
.startPosition
) {
607 layout
->actual_breakpoints
[i
].breakConditionBefore
= layout
->actual_breakpoints
[i
-1].breakConditionAfter
=
608 override_break_condition(layout
->actual_breakpoints
[i
-1].breakConditionAfter
, before
);
610 layout
->actual_breakpoints
[i
].breakConditionBefore
= before
;
611 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
613 /* similar check for last codepoint */
614 else if (i
== cur
->h
.range
.startPosition
+ length
- 1) {
615 if (i
== layout
->len
- 1)
616 layout
->actual_breakpoints
[i
].breakConditionAfter
= after
;
618 layout
->actual_breakpoints
[i
].breakConditionAfter
= layout
->actual_breakpoints
[i
+1].breakConditionBefore
=
619 override_break_condition(layout
->actual_breakpoints
[i
+1].breakConditionBefore
, after
);
620 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
622 /* for all positions within a range disable breaks */
624 layout
->actual_breakpoints
[i
].breakConditionBefore
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
625 layout
->actual_breakpoints
[i
].breakConditionAfter
= DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
;
628 layout
->actual_breakpoints
[i
].isWhitespace
= 0;
629 layout
->actual_breakpoints
[i
].isSoftHyphen
= 0;
635 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
);
637 static inline DWRITE_LINE_BREAKPOINT
get_effective_breakpoint(const struct dwrite_textlayout
*layout
, UINT32 pos
)
639 if (layout
->actual_breakpoints
)
640 return layout
->actual_breakpoints
[pos
];
641 return layout
->nominal_breakpoints
[pos
];
644 static inline void init_cluster_metrics(const struct dwrite_textlayout
*layout
, const struct regular_layout_run
*run
,
645 UINT16 start_glyph
, UINT16 stop_glyph
, UINT32 stop_position
, UINT16 length
, DWRITE_CLUSTER_METRICS
*metrics
)
647 UINT8 breakcondition
;
651 /* For clusters made of control chars we report zero glyphs, and we need zero cluster
652 width as well; advances are already computed at this point and are not necessary zero. */
653 metrics
->width
= 0.0f
;
654 if (run
->run
.glyphCount
) {
655 for (j
= start_glyph
; j
< stop_glyph
; j
++)
656 metrics
->width
+= run
->run
.glyphAdvances
[j
];
658 metrics
->length
= length
;
660 position
= run
->descr
.textPosition
+ stop_position
;
661 if (stop_glyph
== run
->glyphcount
)
662 breakcondition
= get_effective_breakpoint(layout
, position
).breakConditionAfter
;
664 breakcondition
= get_effective_breakpoint(layout
, position
).breakConditionBefore
;
665 if (stop_position
) position
-= 1;
668 metrics
->canWrapLineAfter
= breakcondition
== DWRITE_BREAK_CONDITION_CAN_BREAK
||
669 breakcondition
== DWRITE_BREAK_CONDITION_MUST_BREAK
;
670 if (metrics
->length
== 1) {
671 DWRITE_LINE_BREAKPOINT bp
= get_effective_breakpoint(layout
, position
);
672 metrics
->isWhitespace
= bp
.isWhitespace
;
673 metrics
->isNewline
= metrics
->canWrapLineAfter
&& lb_is_newline_char(layout
->str
[position
]);
674 metrics
->isSoftHyphen
= bp
.isSoftHyphen
;
677 metrics
->isWhitespace
= 0;
678 metrics
->isNewline
= 0;
679 metrics
->isSoftHyphen
= 0;
681 metrics
->isRightToLeft
= run
->run
.bidiLevel
& 1;
682 metrics
->padding
= 0;
687 All clusters in a 'run' will be added to 'layout' data, starting at index pointed to by 'cluster'.
688 On return 'cluster' is updated to point to next metrics struct to be filled in on next call.
689 Note that there's no need to reallocate anything at this point as we allocate one cluster per
693 static void layout_set_cluster_metrics(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32
*cluster
)
695 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[*cluster
];
696 struct layout_cluster
*c
= &layout
->clusters
[*cluster
];
697 const struct regular_layout_run
*run
= &r
->u
.regular
;
700 for (i
= 0; i
< run
->descr
.stringLength
; i
++) {
701 BOOL end
= i
== run
->descr
.stringLength
- 1;
703 if (run
->descr
.clusterMap
[start
] != run
->descr
.clusterMap
[i
]) {
704 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->descr
.clusterMap
[i
], i
,
716 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->glyphcount
, i
,
717 i
- start
+ 1, metrics
);
727 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
729 static void layout_get_font_metrics(struct dwrite_textlayout
*layout
, IDWriteFontFace
*fontface
, FLOAT emsize
,
730 DWRITE_FONT_METRICS
*fontmetrics
)
732 if (is_layout_gdi_compatible(layout
)) {
733 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(fontface
, emsize
, layout
->ppdip
, &layout
->transform
, fontmetrics
);
735 WARN("failed to get compat metrics, 0x%08x\n", hr
);
738 IDWriteFontFace_GetMetrics(fontface
, fontmetrics
);
741 static void layout_get_font_height(FLOAT emsize
, DWRITE_FONT_METRICS
*fontmetrics
, FLOAT
*baseline
, FLOAT
*height
)
743 *baseline
= SCALE_FONT_METRIC(fontmetrics
->ascent
+ fontmetrics
->lineGap
, emsize
, fontmetrics
);
744 *height
= SCALE_FONT_METRIC(fontmetrics
->ascent
+ fontmetrics
->descent
+ fontmetrics
->lineGap
, emsize
, fontmetrics
);
747 static HRESULT
layout_compute_runs(struct dwrite_textlayout
*layout
)
749 IDWriteFontFallback
*fallback
;
750 IDWriteTextAnalyzer
*analyzer
;
751 struct layout_range
*range
;
752 struct layout_run
*r
;
756 free_layout_eruns(layout
);
757 free_layout_runs(layout
);
759 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
760 if (!layout
->clustermetrics
&& layout
->len
) {
761 layout
->clustermetrics
= heap_alloc(layout
->len
*sizeof(*layout
->clustermetrics
));
762 layout
->clusters
= heap_alloc(layout
->len
*sizeof(*layout
->clusters
));
763 if (!layout
->clustermetrics
|| !layout
->clusters
) {
764 heap_free(layout
->clustermetrics
);
765 heap_free(layout
->clusters
);
766 return E_OUTOFMEMORY
;
769 layout
->cluster_count
= 0;
771 hr
= get_textanalyzer(&analyzer
);
775 LIST_FOR_EACH_ENTRY(range
, &layout
->ranges
, struct layout_range
, h
.entry
) {
776 /* we don't care about ranges that don't contain any text */
777 if (range
->h
.range
.startPosition
>= layout
->len
)
780 /* inline objects override actual text in a range */
782 hr
= layout_update_breakpoints_range(layout
, range
);
786 r
= alloc_layout_run(LAYOUT_RUN_INLINE
);
788 return E_OUTOFMEMORY
;
790 r
->u
.object
.object
= range
->object
;
791 r
->u
.object
.length
= get_clipped_range_length(layout
, range
);
792 list_add_tail(&layout
->runs
, &r
->entry
);
796 /* initial splitting by script */
797 hr
= IDWriteTextAnalyzer_AnalyzeScript(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
798 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
), (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
802 /* this splits it further */
803 hr
= IDWriteTextAnalyzer_AnalyzeBidi(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
804 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
), (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
809 if (layout
->format
.fallback
) {
810 fallback
= layout
->format
.fallback
;
811 IDWriteFontFallback_AddRef(fallback
);
814 hr
= IDWriteFactory4_GetSystemFontFallback(layout
->factory
, &fallback
);
819 /* resolve run fonts */
820 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
821 struct regular_layout_run
*run
= &r
->u
.regular
;
825 if (r
->kind
== LAYOUT_RUN_INLINE
)
828 range
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
);
830 if (run
->sa
.shapes
== DWRITE_SCRIPT_SHAPES_NO_VISUAL
) {
831 IDWriteFontCollection
*collection
;
833 if (range
->collection
) {
834 collection
= range
->collection
;
835 IDWriteFontCollection_AddRef(collection
);
838 IDWriteFactory4_GetSystemFontCollection(layout
->factory
, FALSE
, (IDWriteFontCollection1
**)&collection
, FALSE
);
840 hr
= create_matching_font(collection
, range
->fontfamily
, range
->weight
,
841 range
->style
, range
->stretch
, &font
);
843 IDWriteFontCollection_Release(collection
);
846 WARN("%s: failed to create a font for non visual run, %s, collection %p\n", debugstr_rundescr(&run
->descr
),
847 debugstr_w(range
->fontfamily
), range
->collection
);
851 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
852 IDWriteFont_Release(font
);
856 run
->run
.fontEmSize
= range
->fontsize
;
860 length
= run
->descr
.stringLength
;
863 UINT32 mapped_length
;
868 hr
= IDWriteFontFallback_MapCharacters(fallback
,
869 (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
870 run
->descr
.textPosition
,
871 run
->descr
.stringLength
,
881 WARN("%s: failed to map family %s, collection %p\n", debugstr_rundescr(&run
->descr
), debugstr_w(range
->fontfamily
), range
->collection
);
885 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
886 IDWriteFont_Release(font
);
889 run
->run
.fontEmSize
= range
->fontsize
* scale
;
891 if (mapped_length
< length
) {
892 struct regular_layout_run
*nextrun
;
893 struct layout_run
*nextr
;
895 /* keep mapped part for current run, add another run for the rest */
896 nextr
= alloc_layout_run(LAYOUT_RUN_REGULAR
);
898 return E_OUTOFMEMORY
;
901 nextrun
= &nextr
->u
.regular
;
902 nextrun
->descr
.textPosition
= run
->descr
.textPosition
+ mapped_length
;
903 nextrun
->descr
.stringLength
= run
->descr
.stringLength
- mapped_length
;
904 nextrun
->descr
.string
= &layout
->str
[nextrun
->descr
.textPosition
];
905 run
->descr
.stringLength
= mapped_length
;
906 list_add_after(&r
->entry
, &nextr
->entry
);
910 length
-= mapped_length
;
914 IDWriteFontFallback_Release(fallback
);
917 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
918 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
= NULL
;
919 DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
= NULL
;
920 struct regular_layout_run
*run
= &r
->u
.regular
;
921 DWRITE_FONT_METRICS fontmetrics
= { 0 };
924 /* we need to do very little in case of inline objects */
925 if (r
->kind
== LAYOUT_RUN_INLINE
) {
926 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[cluster
];
927 struct layout_cluster
*c
= &layout
->clusters
[cluster
];
928 DWRITE_INLINE_OBJECT_METRICS inlinemetrics
;
930 metrics
->width
= 0.0f
;
931 metrics
->length
= r
->u
.object
.length
;
932 metrics
->canWrapLineAfter
= 0;
933 metrics
->isWhitespace
= 0;
934 metrics
->isNewline
= 0;
935 metrics
->isSoftHyphen
= 0;
936 metrics
->isRightToLeft
= 0;
937 metrics
->padding
= 0;
939 c
->position
= 0; /* there's always one cluster per inline object, so 0 is valid value */
942 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
943 hr
= IDWriteInlineObject_GetMetrics(r
->u
.object
.object
, &inlinemetrics
);
945 memset(&inlinemetrics
, 0, sizeof(inlinemetrics
));
948 metrics
->width
= inlinemetrics
.width
;
949 r
->baseline
= inlinemetrics
.baseline
;
950 r
->height
= inlinemetrics
.height
;
952 /* FIXME: use resolved breakpoints in this case too */
957 range
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
);
958 run
->descr
.localeName
= range
->locale
;
959 run
->clustermap
= heap_alloc(run
->descr
.stringLength
*sizeof(UINT16
));
961 max_count
= 3*run
->descr
.stringLength
/2 + 16;
962 run
->glyphs
= heap_alloc(max_count
*sizeof(UINT16
));
963 if (!run
->clustermap
|| !run
->glyphs
)
966 text_props
= heap_alloc(run
->descr
.stringLength
*sizeof(DWRITE_SHAPING_TEXT_PROPERTIES
));
967 glyph_props
= heap_alloc(max_count
*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES
));
968 if (!text_props
|| !glyph_props
)
972 hr
= IDWriteTextAnalyzer_GetGlyphs(analyzer
, run
->descr
.string
, run
->descr
.stringLength
,
973 run
->run
.fontFace
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
,
974 NULL
/* FIXME */, NULL
, NULL
, 0, max_count
, run
->clustermap
, text_props
, run
->glyphs
, glyph_props
,
976 if (hr
== E_NOT_SUFFICIENT_BUFFER
) {
977 heap_free(run
->glyphs
);
978 heap_free(glyph_props
);
980 max_count
= run
->glyphcount
;
982 run
->glyphs
= heap_alloc(max_count
*sizeof(UINT16
));
983 glyph_props
= heap_alloc(max_count
*sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES
));
984 if (!run
->glyphs
|| !glyph_props
)
994 heap_free(text_props
);
995 heap_free(glyph_props
);
996 WARN("%s: shaping failed 0x%08x\n", debugstr_rundescr(&run
->descr
), hr
);
1000 run
->run
.glyphIndices
= run
->glyphs
;
1001 run
->descr
.clusterMap
= run
->clustermap
;
1003 run
->advances
= heap_alloc(run
->glyphcount
*sizeof(FLOAT
));
1004 run
->offsets
= heap_alloc(run
->glyphcount
*sizeof(DWRITE_GLYPH_OFFSET
));
1005 if (!run
->advances
|| !run
->offsets
)
1008 /* now set advances and offsets */
1009 if (is_layout_gdi_compatible(layout
))
1010 hr
= IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
1011 text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, glyph_props
, run
->glyphcount
,
1012 run
->run
.fontFace
, run
->run
.fontEmSize
, layout
->ppdip
, &layout
->transform
,
1013 layout
->measuringmode
== DWRITE_MEASURING_MODE_GDI_NATURAL
, run
->run
.isSideways
,
1014 run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
, NULL
, NULL
, 0, run
->advances
, run
->offsets
);
1016 hr
= IDWriteTextAnalyzer_GetGlyphPlacements(analyzer
, run
->descr
.string
, run
->descr
.clusterMap
, text_props
,
1017 run
->descr
.stringLength
, run
->run
.glyphIndices
, glyph_props
, run
->glyphcount
, run
->run
.fontFace
,
1018 run
->run
.fontEmSize
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
,
1019 NULL
, NULL
, 0, run
->advances
, run
->offsets
);
1021 heap_free(text_props
);
1022 heap_free(glyph_props
);
1024 WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_rundescr(&run
->descr
), hr
);
1026 run
->run
.glyphAdvances
= run
->advances
;
1027 run
->run
.glyphOffsets
= run
->offsets
;
1029 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1030 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero width clusters. */
1031 if (run
->sa
.shapes
== DWRITE_SCRIPT_SHAPES_NO_VISUAL
)
1032 run
->run
.glyphCount
= 0;
1034 run
->run
.glyphCount
= run
->glyphcount
;
1036 /* baseline derived from font metrics */
1037 layout_get_font_metrics(layout
, run
->run
.fontFace
, run
->run
.fontEmSize
, &fontmetrics
);
1038 layout_get_font_height(run
->run
.fontEmSize
, &fontmetrics
, &r
->baseline
, &r
->height
);
1040 layout_set_cluster_metrics(layout
, r
, &cluster
);
1044 heap_free(text_props
);
1045 heap_free(glyph_props
);
1046 heap_free(run
->clustermap
);
1047 heap_free(run
->glyphs
);
1048 heap_free(run
->advances
);
1049 heap_free(run
->offsets
);
1050 run
->advances
= NULL
;
1051 run
->offsets
= NULL
;
1052 run
->clustermap
= run
->glyphs
= NULL
;
1058 layout
->cluster_count
= cluster
;
1060 layout
->clustermetrics
[cluster
-1].canWrapLineAfter
= 1;
1063 IDWriteTextAnalyzer_Release(analyzer
);
1067 static HRESULT
layout_compute(struct dwrite_textlayout
*layout
)
1071 if (!(layout
->recompute
& RECOMPUTE_CLUSTERS
))
1074 /* nominal breakpoints are evaluated only once, because string never changes */
1075 if (!layout
->nominal_breakpoints
) {
1076 IDWriteTextAnalyzer
*analyzer
;
1079 layout
->nominal_breakpoints
= heap_alloc(sizeof(DWRITE_LINE_BREAKPOINT
)*layout
->len
);
1080 if (!layout
->nominal_breakpoints
)
1081 return E_OUTOFMEMORY
;
1083 hr
= get_textanalyzer(&analyzer
);
1087 hr
= IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
1088 0, layout
->len
, (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
1089 IDWriteTextAnalyzer_Release(analyzer
);
1091 if (layout
->actual_breakpoints
) {
1092 heap_free(layout
->actual_breakpoints
);
1093 layout
->actual_breakpoints
= NULL
;
1096 hr
= layout_compute_runs(layout
);
1098 if (TRACE_ON(dwrite
)) {
1099 struct layout_run
*cur
;
1101 LIST_FOR_EACH_ENTRY(cur
, &layout
->runs
, struct layout_run
, entry
) {
1102 if (cur
->kind
== LAYOUT_RUN_INLINE
)
1103 TRACE("run inline object %p, len %u\n", cur
->u
.object
.object
, cur
->u
.object
.length
);
1105 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur
->u
.regular
.descr
.textPosition
, cur
->u
.regular
.descr
.textPosition
+
1106 cur
->u
.regular
.descr
.stringLength
-1, cur
->u
.regular
.descr
.stringLength
, cur
->u
.regular
.run
.bidiLevel
);
1110 layout
->recompute
&= ~RECOMPUTE_CLUSTERS
;
1114 static inline FLOAT
get_cluster_range_width(struct dwrite_textlayout
*layout
, UINT32 start
, UINT32 end
)
1117 for (; start
< end
; start
++)
1118 width
+= layout
->clustermetrics
[start
].width
;
1122 static struct layout_range_header
*get_layout_range_header_by_pos(struct list
*ranges
, UINT32 pos
)
1124 struct layout_range_header
*cur
;
1126 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
1127 DWRITE_TEXT_RANGE
*r
= &cur
->range
;
1128 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
1135 static inline IUnknown
*layout_get_effect_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1137 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->effects
, pos
);
1138 return ((struct layout_range_iface
*)h
)->iface
;
1141 static inline BOOL
layout_is_erun_rtl(const struct layout_effective_run
*erun
)
1143 return erun
->run
->u
.regular
.run
.bidiLevel
& 1;
1146 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1147 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1148 one of the arguments, but it also happens for decorations, so every effective run has uniform
1149 underline/strikethough/effect tuple. */
1150 struct layout_final_splitting_params
{
1156 static inline BOOL
layout_get_strikethrough_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1158 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->strike_ranges
, pos
);
1159 return ((struct layout_range_bool
*)h
)->value
;
1162 static inline BOOL
layout_get_underline_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1164 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->underline_ranges
, pos
);
1165 return ((struct layout_range_bool
*)h
)->value
;
1168 static void layout_splitting_params_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
,
1169 struct layout_final_splitting_params
*params
)
1171 params
->strikethrough
= layout_get_strikethrough_from_pos(layout
, pos
);
1172 params
->underline
= layout_get_underline_from_pos(layout
, pos
);
1173 params
->effect
= layout_get_effect_from_pos(layout
, pos
);
1176 static BOOL
is_same_splitting_params(const struct layout_final_splitting_params
*left
,
1177 const struct layout_final_splitting_params
*right
)
1179 return left
->strikethrough
== right
->strikethrough
&&
1180 left
->underline
== right
->underline
&&
1181 left
->effect
== right
->effect
;
1184 static void layout_get_erun_font_metrics(struct dwrite_textlayout
*layout
, struct layout_effective_run
*erun
,
1185 DWRITE_FONT_METRICS
*metrics
)
1187 memset(metrics
, 0, sizeof(*metrics
));
1188 if (is_layout_gdi_compatible(layout
)) {
1189 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(
1190 erun
->run
->u
.regular
.run
.fontFace
,
1191 erun
->run
->u
.regular
.run
.fontEmSize
,
1196 WARN("failed to get font metrics, 0x%08x\n", hr
);
1199 IDWriteFontFace_GetMetrics(erun
->run
->u
.regular
.run
.fontFace
, metrics
);
1202 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1203 'cluster_count' indicates how many clusters to add, including first one. */
1204 static HRESULT
layout_add_effective_run(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32 first_cluster
,
1205 UINT32 cluster_count
, UINT32 line
, FLOAT origin_x
, struct layout_final_splitting_params
*params
)
1207 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1208 UINT32 i
, start
, length
, last_cluster
;
1209 struct layout_effective_run
*run
;
1211 if (r
->kind
== LAYOUT_RUN_INLINE
) {
1212 struct layout_effective_inline
*inlineobject
;
1214 inlineobject
= heap_alloc(sizeof(*inlineobject
));
1216 return E_OUTOFMEMORY
;
1218 inlineobject
->object
= r
->u
.object
.object
;
1219 inlineobject
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1220 inlineobject
->origin_x
= is_rtl
? origin_x
- inlineobject
->width
: origin_x
;
1221 inlineobject
->origin_y
= 0.0f
; /* set after line is built */
1222 inlineobject
->align_dx
= 0.0f
;
1223 inlineobject
->baseline
= r
->baseline
;
1225 /* It's not clear how these two are set, possibly directionality
1226 is derived from surrounding text (replaced text could have
1227 different ranges which differ in reading direction). */
1228 inlineobject
->is_sideways
= FALSE
;
1229 inlineobject
->is_rtl
= FALSE
;
1230 inlineobject
->line
= line
;
1232 /* effect assigned from start position and on is used for inline objects */
1233 inlineobject
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[first_cluster
].position
);
1235 list_add_tail(&layout
->inlineobjects
, &inlineobject
->entry
);
1239 run
= heap_alloc(sizeof(*run
));
1241 return E_OUTOFMEMORY
;
1243 /* No need to iterate for that, use simple fact that:
1244 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1245 last_cluster
= first_cluster
+ cluster_count
- 1;
1246 length
= layout
->clusters
[last_cluster
].position
- layout
->clusters
[first_cluster
].position
+
1247 layout
->clustermetrics
[last_cluster
].length
;
1249 run
->clustermap
= heap_alloc(sizeof(UINT16
)*length
);
1250 if (!run
->clustermap
) {
1252 return E_OUTOFMEMORY
;
1256 run
->start
= start
= layout
->clusters
[first_cluster
].position
;
1257 run
->length
= length
;
1258 run
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1260 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1262 if (layout_is_erun_rtl(run
) ^ is_rtl
)
1263 run
->origin_x
= is_rtl
? origin_x
- run
->width
: origin_x
+ run
->width
;
1265 run
->origin_x
= origin_x
;
1267 run
->origin_y
= 0.0f
; /* set after line is built */
1268 run
->align_dx
= 0.0f
;
1271 if (r
->u
.regular
.run
.glyphCount
) {
1272 /* trim from the left */
1273 run
->glyphcount
= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
];
1274 /* trim from the right */
1275 if (start
+ length
< r
->u
.regular
.descr
.stringLength
- 1)
1276 run
->glyphcount
-= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
+ length
];
1279 run
->glyphcount
= 0;
1281 /* cluster map needs to be shifted */
1282 for (i
= 0; i
< length
; i
++)
1283 run
->clustermap
[i
] = r
->u
.regular
.clustermap
[start
+ i
] - r
->u
.regular
.clustermap
[start
];
1285 run
->effect
= params
->effect
;
1286 run
->underlined
= params
->underline
;
1287 list_add_tail(&layout
->eruns
, &run
->entry
);
1289 /* Strikethrough style is guaranteed to be consistent within effective run,
1290 its width equals to run width, thickness and offset are derived from
1291 font metrics, rest of the values are from layout or run itself */
1292 if (params
->strikethrough
) {
1293 struct layout_strikethrough
*s
;
1294 DWRITE_FONT_METRICS metrics
;
1296 s
= heap_alloc(sizeof(*s
));
1298 return E_OUTOFMEMORY
;
1300 layout_get_erun_font_metrics(layout
, run
, &metrics
);
1301 s
->s
.width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1302 s
->s
.thickness
= SCALE_FONT_METRIC(metrics
.strikethroughThickness
, r
->u
.regular
.run
.fontEmSize
, &metrics
);
1303 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1304 s
->s
.offset
= -SCALE_FONT_METRIC(metrics
.strikethroughPosition
, r
->u
.regular
.run
.fontEmSize
, &metrics
);
1305 s
->s
.readingDirection
= layout
->format
.readingdir
;
1306 s
->s
.flowDirection
= layout
->format
.flow
;
1307 s
->s
.localeName
= r
->u
.regular
.descr
.localeName
;
1308 s
->s
.measuringMode
= layout
->measuringmode
;
1311 list_add_tail(&layout
->strikethrough
, &s
->entry
);
1317 static HRESULT
layout_set_line_metrics(struct dwrite_textlayout
*layout
, DWRITE_LINE_METRICS1
*metrics
)
1319 UINT32 i
= layout
->metrics
.lineCount
;
1321 if (!layout
->line_alloc
) {
1322 layout
->line_alloc
= 5;
1323 layout
->linemetrics
= heap_alloc(layout
->line_alloc
* sizeof(*layout
->linemetrics
));
1324 layout
->lines
= heap_alloc(layout
->line_alloc
* sizeof(*layout
->lines
));
1325 if (!layout
->linemetrics
|| !layout
->lines
) {
1326 heap_free(layout
->linemetrics
);
1327 heap_free(layout
->lines
);
1328 layout
->linemetrics
= NULL
;
1329 layout
->lines
= NULL
;
1330 return E_OUTOFMEMORY
;
1334 if (layout
->metrics
.lineCount
== layout
->line_alloc
) {
1335 DWRITE_LINE_METRICS1
*metrics
;
1336 struct layout_line
*lines
;
1338 if ((metrics
= heap_realloc(layout
->linemetrics
, layout
->line_alloc
* 2 * sizeof(*layout
->linemetrics
))))
1339 layout
->linemetrics
= metrics
;
1340 if ((lines
= heap_realloc(layout
->lines
, layout
->line_alloc
* 2 * sizeof(*layout
->lines
))))
1341 layout
->lines
= lines
;
1343 if (!metrics
|| !lines
)
1344 return E_OUTOFMEMORY
;
1346 layout
->line_alloc
*= 2;
1349 layout
->linemetrics
[i
] = *metrics
;
1351 switch (layout
->format
.spacing
.method
)
1353 case DWRITE_LINE_SPACING_METHOD_UNIFORM
:
1354 if (layout
->format
.spacing
.method
== DWRITE_LINE_SPACING_METHOD_UNIFORM
) {
1355 layout
->linemetrics
[i
].height
= layout
->format
.spacing
.height
;
1356 layout
->linemetrics
[i
].baseline
= layout
->format
.spacing
.baseline
;
1359 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
:
1360 if (layout
->format
.spacing
.method
== DWRITE_LINE_SPACING_METHOD_UNIFORM
) {
1361 layout
->linemetrics
[i
].height
= layout
->format
.spacing
.height
* metrics
->height
;
1362 layout
->linemetrics
[i
].baseline
= layout
->format
.spacing
.baseline
* metrics
->baseline
;
1366 /* using content values */;
1369 layout
->lines
[i
].height
= metrics
->height
;
1370 layout
->lines
[i
].baseline
= metrics
->baseline
;
1372 layout
->metrics
.lineCount
++;
1376 static inline struct layout_effective_run
*layout_get_next_erun(struct dwrite_textlayout
*layout
,
1377 const struct layout_effective_run
*cur
)
1382 e
= list_head(&layout
->eruns
);
1384 e
= list_next(&layout
->eruns
, &cur
->entry
);
1387 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1390 static inline struct layout_effective_run
*layout_get_prev_erun(struct dwrite_textlayout
*layout
,
1391 const struct layout_effective_run
*cur
)
1396 e
= list_tail(&layout
->eruns
);
1398 e
= list_prev(&layout
->eruns
, &cur
->entry
);
1401 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1404 static inline struct layout_effective_inline
*layout_get_next_inline_run(struct dwrite_textlayout
*layout
,
1405 const struct layout_effective_inline
*cur
)
1410 e
= list_head(&layout
->inlineobjects
);
1412 e
= list_next(&layout
->inlineobjects
, &cur
->entry
);
1415 return LIST_ENTRY(e
, struct layout_effective_inline
, entry
);
1418 static FLOAT
layout_get_line_width(struct dwrite_textlayout
*layout
,
1419 struct layout_effective_run
*erun
, struct layout_effective_inline
*inrun
, UINT32 line
)
1423 while (erun
&& erun
->line
== line
) {
1424 width
+= erun
->width
;
1425 erun
= layout_get_next_erun(layout
, erun
);
1430 while (inrun
&& inrun
->line
== line
) {
1431 width
+= inrun
->width
;
1432 inrun
= layout_get_next_inline_run(layout
, inrun
);
1440 static inline BOOL
should_skip_transform(const DWRITE_MATRIX
*m
, FLOAT
*det
)
1442 *det
= m
->m11
* m
->m22
- m
->m12
* m
->m21
;
1443 /* on certain conditions we can skip transform */
1444 return (!memcmp(m
, &identity
, sizeof(*m
)) || fabsf(*det
) <= 1e-10f
);
1447 static inline void layout_apply_snapping(struct dwrite_vec
*vec
, BOOL skiptransform
, FLOAT ppdip
,
1448 const DWRITE_MATRIX
*m
, FLOAT det
)
1450 if (!skiptransform
) {
1453 /* apply transform */
1457 vec2
[0] = m
->m11
* vec
->x
+ m
->m21
* vec
->y
+ m
->dx
;
1458 vec2
[1] = m
->m12
* vec
->x
+ m
->m22
* vec
->y
+ m
->dy
;
1461 vec2
[0] = floorf(vec2
[0] + 0.5f
);
1462 vec2
[1] = floorf(vec2
[1] + 0.5f
);
1464 /* apply inverted transform, we don't care about X component at this point */
1465 vec
->x
= (m
->m22
* vec2
[0] - m
->m21
* vec2
[1] + m
->m21
* m
->dy
- m
->m22
* m
->dx
) / det
;
1468 vec
->y
= (-m
->m12
* vec2
[0] + m
->m11
* vec2
[1] - (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
1472 vec
->x
= floorf(vec
->x
* ppdip
+ 0.5f
) / ppdip
;
1473 vec
->y
= floorf(vec
->y
* ppdip
+ 0.5f
) / ppdip
;
1477 static void layout_apply_leading_alignment(struct dwrite_textlayout
*layout
)
1479 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1480 struct layout_effective_inline
*inrun
;
1481 struct layout_effective_run
*erun
;
1483 erun
= layout_get_next_erun(layout
, NULL
);
1484 inrun
= layout_get_next_inline_run(layout
, NULL
);
1487 erun
->align_dx
= 0.0f
;
1488 erun
= layout_get_next_erun(layout
, erun
);
1492 inrun
->align_dx
= 0.0f
;
1493 inrun
= layout_get_next_inline_run(layout
, inrun
);
1496 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
1499 static void layout_apply_trailing_alignment(struct dwrite_textlayout
*layout
)
1501 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1502 struct layout_effective_inline
*inrun
;
1503 struct layout_effective_run
*erun
;
1506 erun
= layout_get_next_erun(layout
, NULL
);
1507 inrun
= layout_get_next_inline_run(layout
, NULL
);
1509 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1510 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1511 FLOAT shift
= layout
->metrics
.layoutWidth
- width
;
1516 while (erun
&& erun
->line
== line
) {
1517 erun
->align_dx
= shift
;
1518 erun
= layout_get_next_erun(layout
, erun
);
1521 while (inrun
&& inrun
->line
== line
) {
1522 inrun
->align_dx
= shift
;
1523 inrun
= layout_get_next_inline_run(layout
, inrun
);
1527 layout
->metrics
.left
= is_rtl
? 0.0f
: layout
->metrics
.layoutWidth
- layout
->metrics
.width
;
1530 static inline FLOAT
layout_get_centered_shift(struct dwrite_textlayout
*layout
, BOOL skiptransform
,
1531 FLOAT width
, FLOAT det
)
1533 if (is_layout_gdi_compatible(layout
)) {
1534 struct dwrite_vec vec
= { layout
->metrics
.layoutWidth
- width
, 0.0f
};
1535 layout_apply_snapping(&vec
, skiptransform
, layout
->ppdip
, &layout
->transform
, det
);
1536 return floorf(vec
.x
/ 2.0f
);
1539 return (layout
->metrics
.layoutWidth
- width
) / 2.0f
;
1542 static void layout_apply_centered_alignment(struct dwrite_textlayout
*layout
)
1544 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1545 struct layout_effective_inline
*inrun
;
1546 struct layout_effective_run
*erun
;
1551 erun
= layout_get_next_erun(layout
, NULL
);
1552 inrun
= layout_get_next_inline_run(layout
, NULL
);
1554 skiptransform
= should_skip_transform(&layout
->transform
, &det
);
1556 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1557 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1558 FLOAT shift
= layout_get_centered_shift(layout
, skiptransform
, width
, det
);
1563 while (erun
&& erun
->line
== line
) {
1564 erun
->align_dx
= shift
;
1565 erun
= layout_get_next_erun(layout
, erun
);
1568 while (inrun
&& inrun
->line
== line
) {
1569 inrun
->align_dx
= shift
;
1570 inrun
= layout_get_next_inline_run(layout
, inrun
);
1574 layout
->metrics
.left
= (layout
->metrics
.layoutWidth
- layout
->metrics
.width
) / 2.0f
;
1577 static void layout_apply_text_alignment(struct dwrite_textlayout
*layout
)
1579 switch (layout
->format
.textalignment
)
1581 case DWRITE_TEXT_ALIGNMENT_LEADING
:
1582 layout_apply_leading_alignment(layout
);
1584 case DWRITE_TEXT_ALIGNMENT_TRAILING
:
1585 layout_apply_trailing_alignment(layout
);
1587 case DWRITE_TEXT_ALIGNMENT_CENTER
:
1588 layout_apply_centered_alignment(layout
);
1590 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED
:
1591 FIXME("alignment %d not implemented\n", layout
->format
.textalignment
);
1598 static void layout_apply_par_alignment(struct dwrite_textlayout
*layout
)
1600 struct layout_effective_inline
*inrun
;
1601 struct layout_effective_run
*erun
;
1602 FLOAT origin_y
= 0.0f
;
1605 /* alignment mode defines origin, after that all run origins are updated
1608 switch (layout
->format
.paralign
)
1610 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR
:
1613 case DWRITE_PARAGRAPH_ALIGNMENT_FAR
:
1614 origin_y
= layout
->metrics
.layoutHeight
- layout
->metrics
.height
;
1616 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER
:
1617 origin_y
= (layout
->metrics
.layoutHeight
- layout
->metrics
.height
) / 2.0f
;
1623 layout
->metrics
.top
= origin_y
;
1625 erun
= layout_get_next_erun(layout
, NULL
);
1626 inrun
= layout_get_next_inline_run(layout
, NULL
);
1627 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1628 FLOAT pos_y
= origin_y
+ layout
->linemetrics
[line
].baseline
;
1630 while (erun
&& erun
->line
== line
) {
1631 erun
->origin_y
= pos_y
;
1632 erun
= layout_get_next_erun(layout
, erun
);
1635 while (inrun
&& inrun
->line
== line
) {
1636 inrun
->origin_y
= pos_y
- inrun
->baseline
;
1637 inrun
= layout_get_next_inline_run(layout
, inrun
);
1640 origin_y
+= layout
->linemetrics
[line
].height
;
1644 struct layout_underline_splitting_params
{
1645 const WCHAR
*locale
; /* points to range data, no additional allocation */
1646 IUnknown
*effect
; /* does not hold another reference */
1649 static void init_u_splitting_params_from_erun(struct layout_effective_run
*erun
,
1650 struct layout_underline_splitting_params
*params
)
1652 params
->locale
= erun
->run
->u
.regular
.descr
.localeName
;
1653 params
->effect
= erun
->effect
;
1656 static BOOL
is_same_u_splitting(struct layout_underline_splitting_params
*left
,
1657 struct layout_underline_splitting_params
*right
)
1659 return left
->effect
== right
->effect
&& !strcmpiW(left
->locale
, right
->locale
);
1662 static HRESULT
layout_add_underline(struct dwrite_textlayout
*layout
, struct layout_effective_run
*first
,
1663 struct layout_effective_run
*last
)
1665 FLOAT thickness
, offset
, runheight
;
1666 struct layout_effective_run
*cur
;
1667 DWRITE_FONT_METRICS metrics
;
1669 if (first
== layout_get_prev_erun(layout
, last
)) {
1670 layout_get_erun_font_metrics(layout
, first
, &metrics
);
1671 thickness
= SCALE_FONT_METRIC(metrics
.underlineThickness
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1672 offset
= SCALE_FONT_METRIC(metrics
.underlinePosition
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1673 runheight
= SCALE_FONT_METRIC(metrics
.capHeight
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1678 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1679 calculated as weighted average, where run width acts as a weight. */
1680 thickness
= offset
= runheight
= 0.0f
;
1683 layout_get_erun_font_metrics(layout
, cur
, &metrics
);
1685 thickness
+= SCALE_FONT_METRIC(metrics
.underlineThickness
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
1686 offset
+= SCALE_FONT_METRIC(metrics
.underlinePosition
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
1687 runheight
= max(SCALE_FONT_METRIC(metrics
.capHeight
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
), runheight
);
1688 width
+= cur
->width
;
1690 cur
= layout_get_next_erun(layout
, cur
);
1691 } while (cur
!= last
);
1699 struct layout_underline_splitting_params params
, prev_params
;
1700 struct layout_effective_run
*next
, *w
;
1701 struct layout_underline
*u
;
1703 init_u_splitting_params_from_erun(cur
, &prev_params
);
1704 while ((next
= layout_get_next_erun(layout
, cur
)) != last
) {
1705 init_u_splitting_params_from_erun(next
, ¶ms
);
1706 if (!is_same_u_splitting(&prev_params
, ¶ms
))
1711 u
= heap_alloc(sizeof(*u
));
1713 return E_OUTOFMEMORY
;
1718 u
->u
.width
+= w
->width
;
1719 w
= layout_get_next_erun(layout
, w
);
1722 u
->u
.thickness
= thickness
;
1723 /* Font metrics convention is to have it negative when below baseline, for rendering
1724 however Y grows from baseline down for horizontal baseline. */
1725 u
->u
.offset
= -offset
;
1726 u
->u
.runHeight
= runheight
;
1727 u
->u
.readingDirection
= is_run_rtl(cur
) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
:
1728 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
1729 u
->u
.flowDirection
= layout
->format
.flow
;
1730 u
->u
.localeName
= cur
->run
->u
.regular
.descr
.localeName
;
1731 u
->u
.measuringMode
= layout
->measuringmode
;
1733 list_add_tail(&layout
->underlines
, &u
->entry
);
1736 } while (cur
!= last
);
1741 /* Adds zero width line, metrics are derived from font at specified text position. */
1742 static HRESULT
layout_set_dummy_line_metrics(struct dwrite_textlayout
*layout
, UINT32 pos
)
1744 DWRITE_LINE_METRICS1 metrics
= { 0 };
1745 DWRITE_FONT_METRICS fontmetrics
;
1746 struct layout_range
*range
;
1747 IDWriteFontFace
*fontface
;
1751 range
= get_layout_range_by_pos(layout
, pos
);
1752 hr
= create_matching_font(range
->collection
,
1760 hr
= IDWriteFont_CreateFontFace(font
, &fontface
);
1761 IDWriteFont_Release(font
);
1765 layout_get_font_metrics(layout
, fontface
, range
->fontsize
, &fontmetrics
);
1766 layout_get_font_height(range
->fontsize
, &fontmetrics
, &metrics
.baseline
, &metrics
.height
);
1767 IDWriteFontFace_Release(fontface
);
1769 return layout_set_line_metrics(layout
, &metrics
);
1772 static void layout_add_line(struct dwrite_textlayout
*layout
, UINT32 first_cluster
, UINT32 last_cluster
,
1775 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1776 struct layout_final_splitting_params params
, prev_params
;
1777 DWRITE_INLINE_OBJECT_METRICS sign_metrics
= { 0 };
1778 UINT32 line
= layout
->metrics
.lineCount
, i
;
1779 DWRITE_LINE_METRICS1 metrics
= { 0 };
1780 UINT32 index
, start
, pos
= *textpos
;
1781 FLOAT descent
, trailingspacewidth
;
1782 BOOL append_trimming_run
= FALSE
;
1783 const struct layout_run
*run
;
1784 FLOAT width
, origin_x
;
1787 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
1788 for (index
= last_cluster
, trailingspacewidth
= 0.0f
; index
>= first_cluster
; index
--) {
1789 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
1790 struct layout_cluster
*lc
= &layout
->clusters
[index
];
1793 /* This also filters out clusters added from inline objects, those are never
1794 treated as a white space. */
1795 if (!cluster
->isWhitespace
)
1798 /* Every isNewline cluster is also isWhitespace, but not every
1799 newline character cluster has isNewline set, so go back to original string. */
1800 ch
= lc
->run
->u
.regular
.descr
.string
[lc
->position
];
1801 if (cluster
->length
== 1 && lb_is_newline_char(ch
))
1802 metrics
.newlineLength
+= cluster
->length
;
1804 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1805 trailingspacewidth
+= cluster
->width
;
1808 /* Line metrics length includes trailing whitespace length too */
1809 for (i
= first_cluster
; i
<= last_cluster
; i
++)
1810 metrics
.length
+= layout
->clustermetrics
[i
].length
;
1812 /* Ignore trailing whitespaces */
1813 while (last_cluster
> first_cluster
) {
1814 if (!layout
->clustermetrics
[last_cluster
].isWhitespace
)
1820 /* Does not include trailing space width */
1821 width
= get_cluster_range_width(layout
, first_cluster
, last_cluster
+ 1);
1823 /* Append trimming run if necessary */
1824 if (width
> layout
->metrics
.layoutWidth
&& layout
->format
.trimmingsign
!= NULL
&&
1825 layout
->format
.trimming
.granularity
!= DWRITE_TRIMMING_GRANULARITY_NONE
) {
1826 FLOAT trimmed_width
= width
;
1828 hr
= IDWriteInlineObject_GetMetrics(layout
->format
.trimmingsign
, &sign_metrics
);
1829 if (SUCCEEDED(hr
)) {
1830 while (last_cluster
> first_cluster
) {
1831 if (trimmed_width
+ sign_metrics
.width
<= layout
->metrics
.layoutWidth
)
1833 trimmed_width
-= layout
->clustermetrics
[last_cluster
--].width
;
1835 append_trimming_run
= TRUE
;
1838 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#x.\n", hr
);
1840 width
= trimmed_width
+ sign_metrics
.width
;
1843 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
1844 prev_params
= params
;
1845 run
= layout
->clusters
[first_cluster
].run
;
1847 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
1848 origin_x
= is_rtl
? layout
->metrics
.layoutWidth
: 0.0f
;
1849 for (start
= first_cluster
, i
= first_cluster
; i
<= last_cluster
; i
++) {
1850 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
1852 if (run
!= layout
->clusters
[i
].run
|| !is_same_splitting_params(&prev_params
, ¶ms
)) {
1853 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
1857 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) :
1858 get_cluster_range_width(layout
, start
, i
);
1859 run
= layout
->clusters
[i
].run
;
1863 prev_params
= params
;
1864 pos
+= layout
->clustermetrics
[i
].length
;
1867 /* Final run from what's left from cluster range */
1868 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
1872 if (append_trimming_run
) {
1873 struct layout_effective_inline
*trimming_sign
;
1875 trimming_sign
= heap_alloc(sizeof(*trimming_sign
));
1879 trimming_sign
->object
= layout
->format
.trimmingsign
;
1880 trimming_sign
->width
= sign_metrics
.width
;
1881 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) : get_cluster_range_width(layout
, start
, i
);
1882 trimming_sign
->origin_x
= is_rtl
? origin_x
- trimming_sign
->width
: origin_x
;
1883 trimming_sign
->origin_y
= 0.0f
; /* set after line is built */
1884 trimming_sign
->align_dx
= 0.0f
;
1885 trimming_sign
->baseline
= sign_metrics
.baseline
;
1887 trimming_sign
->is_sideways
= FALSE
;
1888 trimming_sign
->is_rtl
= FALSE
;
1889 trimming_sign
->line
= line
;
1891 trimming_sign
->effect
= NULL
; /* FIXME */
1893 list_add_tail(&layout
->inlineobjects
, &trimming_sign
->entry
);
1896 /* Look for max baseline and descent for this line */
1897 for (index
= first_cluster
, metrics
.baseline
= 0.0f
, descent
= 0.0f
; index
<= last_cluster
; index
++) {
1898 const struct layout_run
*cur
= layout
->clusters
[index
].run
;
1899 FLOAT cur_descent
= cur
->height
- cur
->baseline
;
1901 if (cur
->baseline
> metrics
.baseline
)
1902 metrics
.baseline
= cur
->baseline
;
1903 if (cur_descent
> descent
)
1904 descent
= cur_descent
;
1907 layout
->metrics
.width
= max(width
, layout
->metrics
.width
);
1908 layout
->metrics
.widthIncludingTrailingWhitespace
= max(width
+ trailingspacewidth
,
1909 layout
->metrics
.widthIncludingTrailingWhitespace
);
1911 metrics
.height
= descent
+ metrics
.baseline
;
1912 metrics
.isTrimmed
= append_trimming_run
|| width
> layout
->metrics
.layoutWidth
;
1913 layout_set_line_metrics(layout
, &metrics
);
1915 *textpos
+= metrics
.length
;
1918 static void layout_set_line_positions(struct dwrite_textlayout
*layout
)
1920 struct layout_effective_inline
*inrun
;
1921 struct layout_effective_run
*erun
;
1925 /* Now all line info is here, update effective runs positions in flow direction */
1926 erun
= layout_get_next_erun(layout
, NULL
);
1927 inrun
= layout_get_next_inline_run(layout
, NULL
);
1929 for (line
= 0, origin_y
= 0.0f
; line
< layout
->metrics
.lineCount
; line
++) {
1930 FLOAT pos_y
= origin_y
+ layout
->linemetrics
[line
].baseline
;
1932 /* For all runs on this line */
1933 while (erun
&& erun
->line
== line
) {
1934 erun
->origin_y
= pos_y
;
1935 erun
= layout_get_next_erun(layout
, erun
);
1938 /* Same for inline runs */
1939 while (inrun
&& inrun
->line
== line
) {
1940 inrun
->origin_y
= pos_y
- inrun
->baseline
;
1941 inrun
= layout_get_next_inline_run(layout
, inrun
);
1944 origin_y
+= layout
->linemetrics
[line
].height
;
1947 layout
->metrics
.height
= origin_y
;
1949 /* Initial paragraph alignment is always near */
1950 if (layout
->format
.paralign
!= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
)
1951 layout_apply_par_alignment(layout
);
1954 static BOOL
layout_can_wrap_after(const struct dwrite_textlayout
*layout
, UINT32 cluster
)
1956 if (layout
->format
.wrapping
== DWRITE_WORD_WRAPPING_CHARACTER
)
1959 return layout
->clustermetrics
[cluster
].canWrapLineAfter
;
1962 static HRESULT
layout_compute_effective_runs(struct dwrite_textlayout
*layout
)
1964 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1965 struct layout_effective_run
*erun
, *first_underlined
;
1966 UINT32 i
, start
, textpos
, last_breaking_point
;
1967 DWRITE_LINE_METRICS1 metrics
;
1972 if (!(layout
->recompute
& RECOMPUTE_LINES
))
1975 free_layout_eruns(layout
);
1977 hr
= layout_compute(layout
);
1981 layout
->metrics
.lineCount
= 0;
1982 memset(&metrics
, 0, sizeof(metrics
));
1984 layout
->metrics
.height
= 0.0f
;
1985 layout
->metrics
.width
= 0.0f
;
1986 layout
->metrics
.widthIncludingTrailingWhitespace
= 0.0f
;
1988 last_breaking_point
= ~0u;
1990 for (i
= 0, start
= 0, width
= 0.0f
, textpos
= 0; i
< layout
->cluster_count
; i
++) {
1991 BOOL overflow
= FALSE
;
1993 while (i
< layout
->cluster_count
&& !layout
->clustermetrics
[i
].isNewline
) {
1994 /* Check for overflow */
1995 overflow
= ((width
+ layout
->clustermetrics
[i
].width
> layout
->metrics
.layoutWidth
) &&
1996 (layout
->format
.wrapping
!= DWRITE_WORD_WRAPPING_NO_WRAP
));
2000 if (layout_can_wrap_after(layout
, i
))
2001 last_breaking_point
= i
;
2002 width
+= layout
->clustermetrics
[i
].width
;
2005 i
= min(i
, layout
->cluster_count
- 1);
2007 /* Ignore if overflown on whitespace */
2008 if (overflow
&& !(layout
->clustermetrics
[i
].isWhitespace
&& layout_can_wrap_after(layout
, i
))) {
2009 /* Use most recently found breaking point */
2010 if (last_breaking_point
!= ~0u) {
2011 i
= last_breaking_point
;
2012 last_breaking_point
= ~0u;
2015 /* Otherwise proceed forward to next newline or breaking point */
2016 for (; i
< layout
->cluster_count
; i
++)
2017 if (layout_can_wrap_after(layout
, i
) || layout
->clustermetrics
[i
].isNewline
)
2021 i
= min(i
, layout
->cluster_count
- 1);
2023 layout_add_line(layout
, start
, i
, &textpos
);
2028 /* Add dummy line if:
2029 - there's no text, metrics come from first range in this case;
2030 - last ended with a mandatory break, metrics come from last text position.
2032 if (layout
->len
== 0)
2033 hr
= layout_set_dummy_line_metrics(layout
, 0);
2034 else if (layout
->clustermetrics
[layout
->cluster_count
- 1].isNewline
)
2035 hr
= layout_set_dummy_line_metrics(layout
, layout
->len
- 1);
2039 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
2040 layout
->metrics
.top
= 0.0f
;
2041 layout
->metrics
.maxBidiReorderingDepth
= 1; /* FIXME */
2043 /* Add explicit underlined runs */
2044 erun
= layout_get_next_erun(layout
, NULL
);
2045 first_underlined
= erun
&& erun
->underlined
? erun
: NULL
;
2046 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
2047 while (erun
&& erun
->line
== line
) {
2048 erun
= layout_get_next_erun(layout
, erun
);
2050 if (first_underlined
&& (!erun
|| !erun
->underlined
)) {
2051 layout_add_underline(layout
, first_underlined
, erun
);
2052 first_underlined
= NULL
;
2054 else if (!first_underlined
&& erun
&& erun
->underlined
)
2055 first_underlined
= erun
;
2059 /* Position runs in flow direction */
2060 layout_set_line_positions(layout
);
2062 /* Initial alignment is always leading */
2063 if (layout
->format
.textalignment
!= DWRITE_TEXT_ALIGNMENT_LEADING
)
2064 layout_apply_text_alignment(layout
);
2066 layout
->recompute
&= ~RECOMPUTE_LINES
;
2070 static BOOL
is_same_layout_attrvalue(struct layout_range_header
const *h
, enum layout_range_attr_kind attr
,
2071 struct layout_range_attr_value
*value
)
2073 struct layout_range_spacing
const *range_spacing
= (struct layout_range_spacing
*)h
;
2074 struct layout_range_iface
const *range_iface
= (struct layout_range_iface
*)h
;
2075 struct layout_range_bool
const *range_bool
= (struct layout_range_bool
*)h
;
2076 struct layout_range
const *range
= (struct layout_range
*)h
;
2079 case LAYOUT_RANGE_ATTR_WEIGHT
:
2080 return range
->weight
== value
->u
.weight
;
2081 case LAYOUT_RANGE_ATTR_STYLE
:
2082 return range
->style
== value
->u
.style
;
2083 case LAYOUT_RANGE_ATTR_STRETCH
:
2084 return range
->stretch
== value
->u
.stretch
;
2085 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2086 return range
->fontsize
== value
->u
.fontsize
;
2087 case LAYOUT_RANGE_ATTR_INLINE
:
2088 return range
->object
== value
->u
.object
;
2089 case LAYOUT_RANGE_ATTR_EFFECT
:
2090 return range_iface
->iface
== value
->u
.effect
;
2091 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2092 return range_bool
->value
== value
->u
.underline
;
2093 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2094 return range_bool
->value
== value
->u
.strikethrough
;
2095 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2096 return range
->pair_kerning
== value
->u
.pair_kerning
;
2097 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2098 return range
->collection
== value
->u
.collection
;
2099 case LAYOUT_RANGE_ATTR_LOCALE
:
2100 return strcmpiW(range
->locale
, value
->u
.locale
) == 0;
2101 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2102 return strcmpW(range
->fontfamily
, value
->u
.fontfamily
) == 0;
2103 case LAYOUT_RANGE_ATTR_SPACING
:
2104 return range_spacing
->leading
== value
->u
.spacing
[0] &&
2105 range_spacing
->trailing
== value
->u
.spacing
[1] &&
2106 range_spacing
->min_advance
== value
->u
.spacing
[2];
2107 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2108 return range_iface
->iface
== (IUnknown
*)value
->u
.typography
;
2116 static inline BOOL
is_same_layout_attributes(struct layout_range_header
const *hleft
, struct layout_range_header
const *hright
)
2118 switch (hleft
->kind
)
2120 case LAYOUT_RANGE_REGULAR
:
2122 struct layout_range
const *left
= (struct layout_range
const*)hleft
;
2123 struct layout_range
const *right
= (struct layout_range
const*)hright
;
2124 return left
->weight
== right
->weight
&&
2125 left
->style
== right
->style
&&
2126 left
->stretch
== right
->stretch
&&
2127 left
->fontsize
== right
->fontsize
&&
2128 left
->object
== right
->object
&&
2129 left
->pair_kerning
== right
->pair_kerning
&&
2130 left
->collection
== right
->collection
&&
2131 !strcmpiW(left
->locale
, right
->locale
) &&
2132 !strcmpW(left
->fontfamily
, right
->fontfamily
);
2134 case LAYOUT_RANGE_UNDERLINE
:
2135 case LAYOUT_RANGE_STRIKETHROUGH
:
2137 struct layout_range_bool
const *left
= (struct layout_range_bool
const*)hleft
;
2138 struct layout_range_bool
const *right
= (struct layout_range_bool
const*)hright
;
2139 return left
->value
== right
->value
;
2141 case LAYOUT_RANGE_EFFECT
:
2142 case LAYOUT_RANGE_TYPOGRAPHY
:
2144 struct layout_range_iface
const *left
= (struct layout_range_iface
const*)hleft
;
2145 struct layout_range_iface
const *right
= (struct layout_range_iface
const*)hright
;
2146 return left
->iface
== right
->iface
;
2148 case LAYOUT_RANGE_SPACING
:
2150 struct layout_range_spacing
const *left
= (struct layout_range_spacing
const*)hleft
;
2151 struct layout_range_spacing
const *right
= (struct layout_range_spacing
const*)hright
;
2152 return left
->leading
== right
->leading
&&
2153 left
->trailing
== right
->trailing
&&
2154 left
->min_advance
== right
->min_advance
;
2157 FIXME("unknown range kind %d\n", hleft
->kind
);
2162 static inline BOOL
is_same_text_range(const DWRITE_TEXT_RANGE
*left
, const DWRITE_TEXT_RANGE
*right
)
2164 return left
->startPosition
== right
->startPosition
&& left
->length
== right
->length
;
2167 /* Allocates range and inits it with default values from text format. */
2168 static struct layout_range_header
*alloc_layout_range(struct dwrite_textlayout
*layout
, const DWRITE_TEXT_RANGE
*r
,
2169 enum layout_range_kind kind
)
2171 struct layout_range_header
*h
;
2175 case LAYOUT_RANGE_REGULAR
:
2177 struct layout_range
*range
;
2179 range
= heap_alloc(sizeof(*range
));
2180 if (!range
) return NULL
;
2182 range
->weight
= layout
->format
.weight
;
2183 range
->style
= layout
->format
.style
;
2184 range
->stretch
= layout
->format
.stretch
;
2185 range
->fontsize
= layout
->format
.fontsize
;
2186 range
->object
= NULL
;
2187 range
->pair_kerning
= FALSE
;
2189 range
->fontfamily
= heap_strdupW(layout
->format
.family_name
);
2190 if (!range
->fontfamily
) {
2195 range
->collection
= layout
->format
.collection
;
2196 if (range
->collection
)
2197 IDWriteFontCollection_AddRef(range
->collection
);
2198 strcpyW(range
->locale
, layout
->format
.locale
);
2203 case LAYOUT_RANGE_UNDERLINE
:
2204 case LAYOUT_RANGE_STRIKETHROUGH
:
2206 struct layout_range_bool
*range
;
2208 range
= heap_alloc(sizeof(*range
));
2209 if (!range
) return NULL
;
2211 range
->value
= FALSE
;
2215 case LAYOUT_RANGE_EFFECT
:
2216 case LAYOUT_RANGE_TYPOGRAPHY
:
2218 struct layout_range_iface
*range
;
2220 range
= heap_alloc(sizeof(*range
));
2221 if (!range
) return NULL
;
2223 range
->iface
= NULL
;
2227 case LAYOUT_RANGE_SPACING
:
2229 struct layout_range_spacing
*range
;
2231 range
= heap_alloc(sizeof(*range
));
2232 if (!range
) return NULL
;
2234 range
->leading
= 0.0f
;
2235 range
->trailing
= 0.0f
;
2236 range
->min_advance
= 0.0f
;
2241 FIXME("unknown range kind %d\n", kind
);
2250 static struct layout_range_header
*alloc_layout_range_from(struct layout_range_header
*h
, const DWRITE_TEXT_RANGE
*r
)
2252 struct layout_range_header
*ret
;
2256 case LAYOUT_RANGE_REGULAR
:
2258 struct layout_range
*from
= (struct layout_range
*)h
;
2260 struct layout_range
*range
= heap_alloc(sizeof(*range
));
2261 if (!range
) return NULL
;
2264 range
->fontfamily
= heap_strdupW(from
->fontfamily
);
2265 if (!range
->fontfamily
) {
2270 /* update refcounts */
2272 IDWriteInlineObject_AddRef(range
->object
);
2273 if (range
->collection
)
2274 IDWriteFontCollection_AddRef(range
->collection
);
2278 case LAYOUT_RANGE_UNDERLINE
:
2279 case LAYOUT_RANGE_STRIKETHROUGH
:
2281 struct layout_range_bool
*strike
= heap_alloc(sizeof(*strike
));
2282 if (!strike
) return NULL
;
2284 *strike
= *(struct layout_range_bool
*)h
;
2288 case LAYOUT_RANGE_EFFECT
:
2289 case LAYOUT_RANGE_TYPOGRAPHY
:
2291 struct layout_range_iface
*effect
= heap_alloc(sizeof(*effect
));
2292 if (!effect
) return NULL
;
2294 *effect
= *(struct layout_range_iface
*)h
;
2296 IUnknown_AddRef(effect
->iface
);
2300 case LAYOUT_RANGE_SPACING
:
2302 struct layout_range_spacing
*spacing
= heap_alloc(sizeof(*spacing
));
2303 if (!spacing
) return NULL
;
2305 *spacing
= *(struct layout_range_spacing
*)h
;
2310 FIXME("unknown range kind %d\n", h
->kind
);
2318 static void free_layout_range(struct layout_range_header
*h
)
2325 case LAYOUT_RANGE_REGULAR
:
2327 struct layout_range
*range
= (struct layout_range
*)h
;
2330 IDWriteInlineObject_Release(range
->object
);
2331 if (range
->collection
)
2332 IDWriteFontCollection_Release(range
->collection
);
2333 heap_free(range
->fontfamily
);
2336 case LAYOUT_RANGE_EFFECT
:
2337 case LAYOUT_RANGE_TYPOGRAPHY
:
2339 struct layout_range_iface
*range
= (struct layout_range_iface
*)h
;
2341 IUnknown_Release(range
->iface
);
2351 static void free_layout_ranges_list(struct dwrite_textlayout
*layout
)
2353 struct layout_range_header
*cur
, *cur2
;
2355 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->ranges
, struct layout_range_header
, entry
) {
2356 list_remove(&cur
->entry
);
2357 free_layout_range(cur
);
2360 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->underline_ranges
, struct layout_range_header
, entry
) {
2361 list_remove(&cur
->entry
);
2362 free_layout_range(cur
);
2365 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->strike_ranges
, struct layout_range_header
, entry
) {
2366 list_remove(&cur
->entry
);
2367 free_layout_range(cur
);
2370 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->effects
, struct layout_range_header
, entry
) {
2371 list_remove(&cur
->entry
);
2372 free_layout_range(cur
);
2375 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->spacing
, struct layout_range_header
, entry
) {
2376 list_remove(&cur
->entry
);
2377 free_layout_range(cur
);
2380 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->typographies
, struct layout_range_header
, entry
) {
2381 list_remove(&cur
->entry
);
2382 free_layout_range(cur
);
2386 static struct layout_range_header
*find_outer_range(struct list
*ranges
, const DWRITE_TEXT_RANGE
*range
)
2388 struct layout_range_header
*cur
;
2390 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
2392 if (cur
->range
.startPosition
> range
->startPosition
)
2395 if ((cur
->range
.startPosition
+ cur
->range
.length
< range
->startPosition
+ range
->length
) &&
2396 (range
->startPosition
< cur
->range
.startPosition
+ cur
->range
.length
))
2398 if (cur
->range
.startPosition
+ cur
->range
.length
>= range
->startPosition
+ range
->length
)
2405 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
2407 struct layout_range
*cur
;
2409 LIST_FOR_EACH_ENTRY(cur
, &layout
->ranges
, struct layout_range
, h
.entry
) {
2410 DWRITE_TEXT_RANGE
*r
= &cur
->h
.range
;
2411 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
2418 static inline BOOL
set_layout_range_iface_attr(IUnknown
**dest
, IUnknown
*value
)
2420 if (*dest
== value
) return FALSE
;
2423 IUnknown_Release(*dest
);
2426 IUnknown_AddRef(*dest
);
2431 static BOOL
set_layout_range_attrval(struct layout_range_header
*h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2433 struct layout_range_spacing
*dest_spacing
= (struct layout_range_spacing
*)h
;
2434 struct layout_range_iface
*dest_iface
= (struct layout_range_iface
*)h
;
2435 struct layout_range_bool
*dest_bool
= (struct layout_range_bool
*)h
;
2436 struct layout_range
*dest
= (struct layout_range
*)h
;
2438 BOOL changed
= FALSE
;
2441 case LAYOUT_RANGE_ATTR_WEIGHT
:
2442 changed
= dest
->weight
!= value
->u
.weight
;
2443 dest
->weight
= value
->u
.weight
;
2445 case LAYOUT_RANGE_ATTR_STYLE
:
2446 changed
= dest
->style
!= value
->u
.style
;
2447 dest
->style
= value
->u
.style
;
2449 case LAYOUT_RANGE_ATTR_STRETCH
:
2450 changed
= dest
->stretch
!= value
->u
.stretch
;
2451 dest
->stretch
= value
->u
.stretch
;
2453 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2454 changed
= dest
->fontsize
!= value
->u
.fontsize
;
2455 dest
->fontsize
= value
->u
.fontsize
;
2457 case LAYOUT_RANGE_ATTR_INLINE
:
2458 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->object
, (IUnknown
*)value
->u
.object
);
2460 case LAYOUT_RANGE_ATTR_EFFECT
:
2461 changed
= set_layout_range_iface_attr((IUnknown
**)&dest_iface
->iface
, (IUnknown
*)value
->u
.effect
);
2463 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2464 changed
= dest_bool
->value
!= value
->u
.underline
;
2465 dest_bool
->value
= value
->u
.underline
;
2467 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2468 changed
= dest_bool
->value
!= value
->u
.strikethrough
;
2469 dest_bool
->value
= value
->u
.strikethrough
;
2471 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2472 changed
= dest
->pair_kerning
!= value
->u
.pair_kerning
;
2473 dest
->pair_kerning
= value
->u
.pair_kerning
;
2475 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2476 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->collection
, (IUnknown
*)value
->u
.collection
);
2478 case LAYOUT_RANGE_ATTR_LOCALE
:
2479 changed
= strcmpiW(dest
->locale
, value
->u
.locale
) != 0;
2481 strcpyW(dest
->locale
, value
->u
.locale
);
2482 strlwrW(dest
->locale
);
2485 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2486 changed
= strcmpW(dest
->fontfamily
, value
->u
.fontfamily
) != 0;
2488 heap_free(dest
->fontfamily
);
2489 dest
->fontfamily
= heap_strdupW(value
->u
.fontfamily
);
2492 case LAYOUT_RANGE_ATTR_SPACING
:
2493 changed
= dest_spacing
->leading
!= value
->u
.spacing
[0] ||
2494 dest_spacing
->trailing
!= value
->u
.spacing
[1] ||
2495 dest_spacing
->min_advance
!= value
->u
.spacing
[2];
2496 dest_spacing
->leading
= value
->u
.spacing
[0];
2497 dest_spacing
->trailing
= value
->u
.spacing
[1];
2498 dest_spacing
->min_advance
= value
->u
.spacing
[2];
2500 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2501 changed
= set_layout_range_iface_attr((IUnknown
**)&dest_iface
->iface
, (IUnknown
*)value
->u
.typography
);
2510 static inline BOOL
is_in_layout_range(const DWRITE_TEXT_RANGE
*outer
, const DWRITE_TEXT_RANGE
*inner
)
2512 return (inner
->startPosition
>= outer
->startPosition
) &&
2513 (inner
->startPosition
+ inner
->length
<= outer
->startPosition
+ outer
->length
);
2516 static inline HRESULT
return_range(const struct layout_range_header
*h
, DWRITE_TEXT_RANGE
*r
)
2518 if (r
) *r
= h
->range
;
2522 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2523 static HRESULT
set_layout_range_attr(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2525 struct layout_range_header
*cur
, *right
, *left
, *outer
;
2526 BOOL changed
= FALSE
;
2527 struct list
*ranges
;
2528 DWRITE_TEXT_RANGE r
;
2530 /* ignore zero length ranges */
2531 if (value
->range
.length
== 0)
2534 /* select from ranges lists */
2537 case LAYOUT_RANGE_ATTR_WEIGHT
:
2538 case LAYOUT_RANGE_ATTR_STYLE
:
2539 case LAYOUT_RANGE_ATTR_STRETCH
:
2540 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2541 case LAYOUT_RANGE_ATTR_INLINE
:
2542 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2543 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2544 case LAYOUT_RANGE_ATTR_LOCALE
:
2545 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2546 ranges
= &layout
->ranges
;
2548 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2549 ranges
= &layout
->underline_ranges
;
2551 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2552 ranges
= &layout
->strike_ranges
;
2554 case LAYOUT_RANGE_ATTR_EFFECT
:
2555 ranges
= &layout
->effects
;
2557 case LAYOUT_RANGE_ATTR_SPACING
:
2558 ranges
= &layout
->spacing
;
2560 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2561 ranges
= &layout
->typographies
;
2564 FIXME("unknown attr kind %d\n", attr
);
2568 /* If new range is completely within existing range, split existing range in two */
2569 if ((outer
= find_outer_range(ranges
, &value
->range
))) {
2571 /* no need to add same range */
2572 if (is_same_layout_attrvalue(outer
, attr
, value
))
2575 /* for matching range bounds just replace data */
2576 if (is_same_text_range(&outer
->range
, &value
->range
)) {
2577 changed
= set_layout_range_attrval(outer
, attr
, value
);
2581 /* add new range to the left */
2582 if (value
->range
.startPosition
== outer
->range
.startPosition
) {
2583 left
= alloc_layout_range_from(outer
, &value
->range
);
2584 if (!left
) return E_OUTOFMEMORY
;
2586 changed
= set_layout_range_attrval(left
, attr
, value
);
2587 list_add_before(&outer
->entry
, &left
->entry
);
2588 outer
->range
.startPosition
+= value
->range
.length
;
2589 outer
->range
.length
-= value
->range
.length
;
2593 /* add new range to the right */
2594 if (value
->range
.startPosition
+ value
->range
.length
== outer
->range
.startPosition
+ outer
->range
.length
) {
2595 right
= alloc_layout_range_from(outer
, &value
->range
);
2596 if (!right
) return E_OUTOFMEMORY
;
2598 changed
= set_layout_range_attrval(right
, attr
, value
);
2599 list_add_after(&outer
->entry
, &right
->entry
);
2600 outer
->range
.length
-= value
->range
.length
;
2604 r
.startPosition
= value
->range
.startPosition
+ value
->range
.length
;
2605 r
.length
= outer
->range
.length
+ outer
->range
.startPosition
- r
.startPosition
;
2608 right
= alloc_layout_range_from(outer
, &r
);
2609 /* new range in the middle */
2610 cur
= alloc_layout_range_from(outer
, &value
->range
);
2611 if (!right
|| !cur
) {
2612 free_layout_range(right
);
2613 free_layout_range(cur
);
2614 return E_OUTOFMEMORY
;
2617 /* reuse container range as a left part */
2618 outer
->range
.length
= value
->range
.startPosition
- outer
->range
.startPosition
;
2621 set_layout_range_attrval(cur
, attr
, value
);
2623 list_add_after(&outer
->entry
, &cur
->entry
);
2624 list_add_after(&cur
->entry
, &right
->entry
);
2626 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2630 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2631 Update all of them. */
2632 left
= get_layout_range_header_by_pos(ranges
, value
->range
.startPosition
);
2633 if (left
->range
.startPosition
== value
->range
.startPosition
)
2634 changed
= set_layout_range_attrval(left
, attr
, value
);
2635 else /* need to split */ {
2636 r
.startPosition
= value
->range
.startPosition
;
2637 r
.length
= left
->range
.length
- value
->range
.startPosition
+ left
->range
.startPosition
;
2638 left
->range
.length
-= r
.length
;
2639 cur
= alloc_layout_range_from(left
, &r
);
2640 changed
= set_layout_range_attrval(cur
, attr
, value
);
2641 list_add_after(&left
->entry
, &cur
->entry
);
2643 cur
= LIST_ENTRY(list_next(ranges
, &left
->entry
), struct layout_range_header
, entry
);
2645 /* for all existing ranges covered by new one update value */
2646 while (cur
&& is_in_layout_range(&value
->range
, &cur
->range
)) {
2647 changed
|= set_layout_range_attrval(cur
, attr
, value
);
2648 cur
= LIST_ENTRY(list_next(ranges
, &cur
->entry
), struct layout_range_header
, entry
);
2651 /* it's possible rightmost range intersects */
2652 if (cur
&& (cur
->range
.startPosition
< value
->range
.startPosition
+ value
->range
.length
)) {
2653 r
.startPosition
= cur
->range
.startPosition
;
2654 r
.length
= value
->range
.startPosition
+ value
->range
.length
- cur
->range
.startPosition
;
2655 left
= alloc_layout_range_from(cur
, &r
);
2656 changed
|= set_layout_range_attrval(left
, attr
, value
);
2657 cur
->range
.startPosition
+= left
->range
.length
;
2658 cur
->range
.length
-= left
->range
.length
;
2659 list_add_before(&cur
->entry
, &left
->entry
);
2664 struct list
*next
, *i
;
2666 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2667 i
= list_head(ranges
);
2668 while ((next
= list_next(ranges
, i
))) {
2669 struct layout_range_header
*next_range
= LIST_ENTRY(next
, struct layout_range_header
, entry
);
2671 cur
= LIST_ENTRY(i
, struct layout_range_header
, entry
);
2672 if (is_same_layout_attributes(cur
, next_range
)) {
2673 /* remove similar range */
2674 cur
->range
.length
+= next_range
->range
.length
;
2676 free_layout_range(next_range
);
2679 i
= list_next(ranges
, i
);
2686 static inline const WCHAR
*get_string_attribute_ptr(struct layout_range
*range
, enum layout_range_attr_kind kind
)
2691 case LAYOUT_RANGE_ATTR_LOCALE
:
2692 str
= range
->locale
;
2694 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2695 str
= range
->fontfamily
;
2704 static HRESULT
get_string_attribute_length(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2705 UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
2707 struct layout_range
*range
;
2710 range
= get_layout_range_by_pos(layout
, position
);
2716 str
= get_string_attribute_ptr(range
, kind
);
2717 *length
= strlenW(str
);
2718 return return_range(&range
->h
, r
);
2721 static HRESULT
get_string_attribute_value(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2722 WCHAR
*ret
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2724 struct layout_range
*range
;
2728 return E_INVALIDARG
;
2731 range
= get_layout_range_by_pos(layout
, position
);
2733 return E_INVALIDARG
;
2735 str
= get_string_attribute_ptr(range
, kind
);
2736 if (length
< strlenW(str
) + 1)
2737 return E_NOT_SUFFICIENT_BUFFER
;
2740 return return_range(&range
->h
, r
);
2743 static HRESULT WINAPI
dwritetextlayout_QueryInterface(IDWriteTextLayout3
*iface
, REFIID riid
, void **obj
)
2745 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2747 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
2751 if (IsEqualIID(riid
, &IID_IDWriteTextLayout3
) ||
2752 IsEqualIID(riid
, &IID_IDWriteTextLayout2
) ||
2753 IsEqualIID(riid
, &IID_IDWriteTextLayout1
) ||
2754 IsEqualIID(riid
, &IID_IDWriteTextLayout
) ||
2755 IsEqualIID(riid
, &IID_IUnknown
))
2759 else if (IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
2760 IsEqualIID(riid
, &IID_IDWriteTextFormat
))
2761 *obj
= &This
->IDWriteTextFormat1_iface
;
2764 IDWriteTextLayout3_AddRef(iface
);
2768 return E_NOINTERFACE
;
2771 static ULONG WINAPI
dwritetextlayout_AddRef(IDWriteTextLayout3
*iface
)
2773 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2774 ULONG ref
= InterlockedIncrement(&This
->ref
);
2775 TRACE("(%p)->(%d)\n", This
, ref
);
2779 static ULONG WINAPI
dwritetextlayout_Release(IDWriteTextLayout3
*iface
)
2781 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2782 ULONG ref
= InterlockedDecrement(&This
->ref
);
2784 TRACE("(%p)->(%d)\n", This
, ref
);
2787 IDWriteFactory4_Release(This
->factory
);
2788 free_layout_ranges_list(This
);
2789 free_layout_eruns(This
);
2790 free_layout_runs(This
);
2791 release_format_data(&This
->format
);
2792 heap_free(This
->nominal_breakpoints
);
2793 heap_free(This
->actual_breakpoints
);
2794 heap_free(This
->clustermetrics
);
2795 heap_free(This
->clusters
);
2796 heap_free(This
->linemetrics
);
2797 heap_free(This
->lines
);
2798 heap_free(This
->str
);
2805 static HRESULT WINAPI
dwritetextlayout_SetTextAlignment(IDWriteTextLayout3
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
2807 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2808 return IDWriteTextFormat1_SetTextAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
2811 static HRESULT WINAPI
dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout3
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
2813 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2814 return IDWriteTextFormat1_SetParagraphAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
2817 static HRESULT WINAPI
dwritetextlayout_SetWordWrapping(IDWriteTextLayout3
*iface
, DWRITE_WORD_WRAPPING wrapping
)
2819 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2820 return IDWriteTextFormat1_SetWordWrapping(&This
->IDWriteTextFormat1_iface
, wrapping
);
2823 static HRESULT WINAPI
dwritetextlayout_SetReadingDirection(IDWriteTextLayout3
*iface
, DWRITE_READING_DIRECTION direction
)
2825 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2826 return IDWriteTextFormat1_SetReadingDirection(&This
->IDWriteTextFormat1_iface
, direction
);
2829 static HRESULT WINAPI
dwritetextlayout_SetFlowDirection(IDWriteTextLayout3
*iface
, DWRITE_FLOW_DIRECTION direction
)
2831 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2832 TRACE("(%p)->(%d)\n", This
, direction
);
2833 return IDWriteTextFormat1_SetFlowDirection(&This
->IDWriteTextFormat1_iface
, direction
);
2836 static HRESULT WINAPI
dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout3
*iface
, FLOAT tabstop
)
2838 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2839 TRACE("(%p)->(%.2f)\n", This
, tabstop
);
2840 return IDWriteTextFormat1_SetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
, tabstop
);
2843 static HRESULT WINAPI
dwritetextlayout_SetTrimming(IDWriteTextLayout3
*iface
, DWRITE_TRIMMING
const *trimming
,
2844 IDWriteInlineObject
*trimming_sign
)
2846 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2847 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
2848 return IDWriteTextFormat1_SetTrimming(&This
->IDWriteTextFormat1_iface
, trimming
, trimming_sign
);
2851 static HRESULT WINAPI
dwritetextlayout_SetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
2852 FLOAT line_spacing
, FLOAT baseline
)
2854 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2855 TRACE("(%p)->(%d %.2f %.2f)\n", This
, spacing
, line_spacing
, baseline
);
2856 return IDWriteTextFormat1_SetLineSpacing(&This
->IDWriteTextFormat1_iface
, spacing
, line_spacing
, baseline
);
2859 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextlayout_GetTextAlignment(IDWriteTextLayout3
*iface
)
2861 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2862 return IDWriteTextFormat1_GetTextAlignment(&This
->IDWriteTextFormat1_iface
);
2865 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout3
*iface
)
2867 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2868 return IDWriteTextFormat1_GetParagraphAlignment(&This
->IDWriteTextFormat1_iface
);
2871 static DWRITE_WORD_WRAPPING WINAPI
dwritetextlayout_GetWordWrapping(IDWriteTextLayout3
*iface
)
2873 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2874 return IDWriteTextFormat1_GetWordWrapping(&This
->IDWriteTextFormat1_iface
);
2877 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_GetReadingDirection(IDWriteTextLayout3
*iface
)
2879 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2880 return IDWriteTextFormat1_GetReadingDirection(&This
->IDWriteTextFormat1_iface
);
2883 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextlayout_GetFlowDirection(IDWriteTextLayout3
*iface
)
2885 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2886 return IDWriteTextFormat1_GetFlowDirection(&This
->IDWriteTextFormat1_iface
);
2889 static FLOAT WINAPI
dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout3
*iface
)
2891 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2892 return IDWriteTextFormat1_GetIncrementalTabStop(&This
->IDWriteTextFormat1_iface
);
2895 static HRESULT WINAPI
dwritetextlayout_GetTrimming(IDWriteTextLayout3
*iface
, DWRITE_TRIMMING
*options
,
2896 IDWriteInlineObject
**trimming_sign
)
2898 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2899 return IDWriteTextFormat1_GetTrimming(&This
->IDWriteTextFormat1_iface
, options
, trimming_sign
);
2902 static HRESULT WINAPI
dwritetextlayout_GetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
2903 FLOAT
*spacing
, FLOAT
*baseline
)
2905 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2906 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat
*)&This
->IDWriteTextFormat1_iface
, method
, spacing
, baseline
);
2909 static HRESULT WINAPI
dwritetextlayout_GetFontCollection(IDWriteTextLayout3
*iface
, IDWriteFontCollection
**collection
)
2911 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2912 return IDWriteTextFormat1_GetFontCollection(&This
->IDWriteTextFormat1_iface
, collection
);
2915 static UINT32 WINAPI
dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout3
*iface
)
2917 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2918 return IDWriteTextFormat1_GetFontFamilyNameLength(&This
->IDWriteTextFormat1_iface
);
2921 static HRESULT WINAPI
dwritetextlayout_GetFontFamilyName(IDWriteTextLayout3
*iface
, WCHAR
*name
, UINT32 size
)
2923 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2924 return IDWriteTextFormat1_GetFontFamilyName(&This
->IDWriteTextFormat1_iface
, name
, size
);
2927 static DWRITE_FONT_WEIGHT WINAPI
dwritetextlayout_GetFontWeight(IDWriteTextLayout3
*iface
)
2929 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2930 return IDWriteTextFormat1_GetFontWeight(&This
->IDWriteTextFormat1_iface
);
2933 static DWRITE_FONT_STYLE WINAPI
dwritetextlayout_GetFontStyle(IDWriteTextLayout3
*iface
)
2935 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2936 return IDWriteTextFormat1_GetFontStyle(&This
->IDWriteTextFormat1_iface
);
2939 static DWRITE_FONT_STRETCH WINAPI
dwritetextlayout_GetFontStretch(IDWriteTextLayout3
*iface
)
2941 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2942 return IDWriteTextFormat1_GetFontStretch(&This
->IDWriteTextFormat1_iface
);
2945 static FLOAT WINAPI
dwritetextlayout_GetFontSize(IDWriteTextLayout3
*iface
)
2947 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2948 return IDWriteTextFormat1_GetFontSize(&This
->IDWriteTextFormat1_iface
);
2951 static UINT32 WINAPI
dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout3
*iface
)
2953 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2954 return IDWriteTextFormat1_GetLocaleNameLength(&This
->IDWriteTextFormat1_iface
);
2957 static HRESULT WINAPI
dwritetextlayout_GetLocaleName(IDWriteTextLayout3
*iface
, WCHAR
*name
, UINT32 size
)
2959 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2960 return IDWriteTextFormat1_GetLocaleName(&This
->IDWriteTextFormat1_iface
, name
, size
);
2963 static HRESULT WINAPI
dwritetextlayout_SetMaxWidth(IDWriteTextLayout3
*iface
, FLOAT maxWidth
)
2965 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2968 TRACE("(%p)->(%.2f)\n", This
, maxWidth
);
2970 if (maxWidth
< 0.0f
)
2971 return E_INVALIDARG
;
2973 changed
= This
->metrics
.layoutWidth
!= maxWidth
;
2974 This
->metrics
.layoutWidth
= maxWidth
;
2977 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
2981 static HRESULT WINAPI
dwritetextlayout_SetMaxHeight(IDWriteTextLayout3
*iface
, FLOAT maxHeight
)
2983 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2986 TRACE("(%p)->(%.2f)\n", This
, maxHeight
);
2988 if (maxHeight
< 0.0f
)
2989 return E_INVALIDARG
;
2991 changed
= This
->metrics
.layoutHeight
!= maxHeight
;
2992 This
->metrics
.layoutHeight
= maxHeight
;
2995 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
2999 static HRESULT WINAPI
dwritetextlayout_SetFontCollection(IDWriteTextLayout3
*iface
, IDWriteFontCollection
* collection
, DWRITE_TEXT_RANGE range
)
3001 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3002 struct layout_range_attr_value value
;
3004 TRACE("(%p)->(%p %s)\n", This
, collection
, debugstr_range(&range
));
3006 value
.range
= range
;
3007 value
.u
.collection
= collection
;
3008 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTCOLL
, &value
);
3011 static HRESULT WINAPI
dwritetextlayout_SetFontFamilyName(IDWriteTextLayout3
*iface
, WCHAR
const *name
, DWRITE_TEXT_RANGE range
)
3013 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3014 struct layout_range_attr_value value
;
3016 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(name
), debugstr_range(&range
));
3019 return E_INVALIDARG
;
3021 value
.range
= range
;
3022 value
.u
.fontfamily
= name
;
3023 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, &value
);
3026 static HRESULT WINAPI
dwritetextlayout_SetFontWeight(IDWriteTextLayout3
*iface
, DWRITE_FONT_WEIGHT weight
, DWRITE_TEXT_RANGE range
)
3028 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3029 struct layout_range_attr_value value
;
3031 TRACE("(%p)->(%d %s)\n", This
, weight
, debugstr_range(&range
));
3033 if ((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
3034 return E_INVALIDARG
;
3036 value
.range
= range
;
3037 value
.u
.weight
= weight
;
3038 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_WEIGHT
, &value
);
3041 static HRESULT WINAPI
dwritetextlayout_SetFontStyle(IDWriteTextLayout3
*iface
, DWRITE_FONT_STYLE style
, DWRITE_TEXT_RANGE range
)
3043 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3044 struct layout_range_attr_value value
;
3046 TRACE("(%p)->(%d %s)\n", This
, style
, debugstr_range(&range
));
3048 if ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
)
3049 return E_INVALIDARG
;
3051 value
.range
= range
;
3052 value
.u
.style
= style
;
3053 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STYLE
, &value
);
3056 static HRESULT WINAPI
dwritetextlayout_SetFontStretch(IDWriteTextLayout3
*iface
, DWRITE_FONT_STRETCH stretch
, DWRITE_TEXT_RANGE range
)
3058 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3059 struct layout_range_attr_value value
;
3061 TRACE("(%p)->(%d %s)\n", This
, stretch
, debugstr_range(&range
));
3063 if (stretch
== DWRITE_FONT_STRETCH_UNDEFINED
|| (UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
3064 return E_INVALIDARG
;
3066 value
.range
= range
;
3067 value
.u
.stretch
= stretch
;
3068 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRETCH
, &value
);
3071 static HRESULT WINAPI
dwritetextlayout_SetFontSize(IDWriteTextLayout3
*iface
, FLOAT size
, DWRITE_TEXT_RANGE range
)
3073 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3074 struct layout_range_attr_value value
;
3076 TRACE("(%p)->(%.2f %s)\n", This
, size
, debugstr_range(&range
));
3079 return E_INVALIDARG
;
3081 value
.range
= range
;
3082 value
.u
.fontsize
= size
;
3083 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTSIZE
, &value
);
3086 static HRESULT WINAPI
dwritetextlayout_SetUnderline(IDWriteTextLayout3
*iface
, BOOL underline
, DWRITE_TEXT_RANGE range
)
3088 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3089 struct layout_range_attr_value value
;
3091 TRACE("(%p)->(%d %s)\n", This
, underline
, debugstr_range(&range
));
3093 value
.range
= range
;
3094 value
.u
.underline
= underline
;
3095 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_UNDERLINE
, &value
);
3098 static HRESULT WINAPI
dwritetextlayout_SetStrikethrough(IDWriteTextLayout3
*iface
, BOOL strikethrough
, DWRITE_TEXT_RANGE range
)
3100 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3101 struct layout_range_attr_value value
;
3103 TRACE("(%p)->(%d %s)\n", This
, strikethrough
, debugstr_range(&range
));
3105 value
.range
= range
;
3106 value
.u
.strikethrough
= strikethrough
;
3107 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRIKETHROUGH
, &value
);
3110 static HRESULT WINAPI
dwritetextlayout_SetDrawingEffect(IDWriteTextLayout3
*iface
, IUnknown
* effect
, DWRITE_TEXT_RANGE range
)
3112 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3113 struct layout_range_attr_value value
;
3115 TRACE("(%p)->(%p %s)\n", This
, effect
, debugstr_range(&range
));
3117 value
.range
= range
;
3118 value
.u
.effect
= effect
;
3119 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_EFFECT
, &value
);
3122 static HRESULT WINAPI
dwritetextlayout_SetInlineObject(IDWriteTextLayout3
*iface
, IDWriteInlineObject
*object
, DWRITE_TEXT_RANGE range
)
3124 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3125 struct layout_range_attr_value value
;
3127 TRACE("(%p)->(%p %s)\n", This
, object
, debugstr_range(&range
));
3129 value
.range
= range
;
3130 value
.u
.object
= object
;
3131 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_INLINE
, &value
);
3134 static HRESULT WINAPI
dwritetextlayout_SetTypography(IDWriteTextLayout3
*iface
, IDWriteTypography
* typography
, DWRITE_TEXT_RANGE range
)
3136 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3137 struct layout_range_attr_value value
;
3139 TRACE("(%p)->(%p %s)\n", This
, typography
, debugstr_range(&range
));
3141 value
.range
= range
;
3142 value
.u
.typography
= typography
;
3143 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_TYPOGRAPHY
, &value
);
3146 static HRESULT WINAPI
dwritetextlayout_SetLocaleName(IDWriteTextLayout3
*iface
, WCHAR
const* locale
, DWRITE_TEXT_RANGE range
)
3148 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3149 struct layout_range_attr_value value
;
3151 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(locale
), debugstr_range(&range
));
3153 if (!locale
|| strlenW(locale
) > LOCALE_NAME_MAX_LENGTH
-1)
3154 return E_INVALIDARG
;
3156 value
.range
= range
;
3157 value
.u
.locale
= locale
;
3158 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_LOCALE
, &value
);
3161 static FLOAT WINAPI
dwritetextlayout_GetMaxWidth(IDWriteTextLayout3
*iface
)
3163 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3164 TRACE("(%p)\n", This
);
3165 return This
->metrics
.layoutWidth
;
3168 static FLOAT WINAPI
dwritetextlayout_GetMaxHeight(IDWriteTextLayout3
*iface
)
3170 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3171 TRACE("(%p)\n", This
);
3172 return This
->metrics
.layoutHeight
;
3175 static HRESULT WINAPI
dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout3
*iface
, UINT32 position
,
3176 IDWriteFontCollection
** collection
, DWRITE_TEXT_RANGE
*r
)
3178 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3179 struct layout_range
*range
;
3181 TRACE("(%p)->(%u %p %p)\n", This
, position
, collection
, r
);
3183 if (position
>= This
->len
)
3186 range
= get_layout_range_by_pos(This
, position
);
3187 *collection
= range
->collection
;
3189 IDWriteFontCollection_AddRef(*collection
);
3191 return return_range(&range
->h
, r
);
3194 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout3
*iface
,
3195 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3197 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3198 TRACE("(%p)->(%d %p %p)\n", This
, position
, length
, r
);
3199 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, length
, r
);
3202 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout3
*iface
,
3203 UINT32 position
, WCHAR
*name
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3205 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3206 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, name
, length
, r
);
3207 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, name
, length
, r
);
3210 static HRESULT WINAPI
dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout3
*iface
,
3211 UINT32 position
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_TEXT_RANGE
*r
)
3213 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3214 struct layout_range
*range
;
3216 TRACE("(%p)->(%u %p %p)\n", This
, position
, weight
, r
);
3218 if (position
>= This
->len
)
3221 range
= get_layout_range_by_pos(This
, position
);
3222 *weight
= range
->weight
;
3224 return return_range(&range
->h
, r
);
3227 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout3
*iface
,
3228 UINT32 position
, DWRITE_FONT_STYLE
*style
, DWRITE_TEXT_RANGE
*r
)
3230 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3231 struct layout_range
*range
;
3233 TRACE("(%p)->(%u %p %p)\n", This
, position
, style
, r
);
3235 range
= get_layout_range_by_pos(This
, position
);
3236 *style
= range
->style
;
3237 return return_range(&range
->h
, r
);
3240 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout3
*iface
,
3241 UINT32 position
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_TEXT_RANGE
*r
)
3243 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3244 struct layout_range
*range
;
3246 TRACE("(%p)->(%u %p %p)\n", This
, position
, stretch
, r
);
3248 range
= get_layout_range_by_pos(This
, position
);
3249 *stretch
= range
->stretch
;
3250 return return_range(&range
->h
, r
);
3253 static HRESULT WINAPI
dwritetextlayout_layout_GetFontSize(IDWriteTextLayout3
*iface
,
3254 UINT32 position
, FLOAT
*size
, DWRITE_TEXT_RANGE
*r
)
3256 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3257 struct layout_range
*range
;
3259 TRACE("(%p)->(%u %p %p)\n", This
, position
, size
, r
);
3261 range
= get_layout_range_by_pos(This
, position
);
3262 *size
= range
->fontsize
;
3263 return return_range(&range
->h
, r
);
3266 static HRESULT WINAPI
dwritetextlayout_GetUnderline(IDWriteTextLayout3
*iface
,
3267 UINT32 position
, BOOL
*underline
, DWRITE_TEXT_RANGE
*r
)
3269 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3270 struct layout_range_bool
*range
;
3272 TRACE("(%p)->(%u %p %p)\n", This
, position
, underline
, r
);
3274 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->underline_ranges
, position
);
3275 *underline
= range
->value
;
3277 return return_range(&range
->h
, r
);
3280 static HRESULT WINAPI
dwritetextlayout_GetStrikethrough(IDWriteTextLayout3
*iface
,
3281 UINT32 position
, BOOL
*strikethrough
, DWRITE_TEXT_RANGE
*r
)
3283 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3284 struct layout_range_bool
*range
;
3286 TRACE("(%p)->(%u %p %p)\n", This
, position
, strikethrough
, r
);
3288 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->strike_ranges
, position
);
3289 *strikethrough
= range
->value
;
3291 return return_range(&range
->h
, r
);
3294 static HRESULT WINAPI
dwritetextlayout_GetDrawingEffect(IDWriteTextLayout3
*iface
,
3295 UINT32 position
, IUnknown
**effect
, DWRITE_TEXT_RANGE
*r
)
3297 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3298 struct layout_range_iface
*range
;
3300 TRACE("(%p)->(%u %p %p)\n", This
, position
, effect
, r
);
3302 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&This
->effects
, position
);
3303 *effect
= range
->iface
;
3305 IUnknown_AddRef(*effect
);
3307 return return_range(&range
->h
, r
);
3310 static HRESULT WINAPI
dwritetextlayout_GetInlineObject(IDWriteTextLayout3
*iface
,
3311 UINT32 position
, IDWriteInlineObject
**object
, DWRITE_TEXT_RANGE
*r
)
3313 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3314 struct layout_range
*range
;
3316 TRACE("(%p)->(%u %p %p)\n", This
, position
, object
, r
);
3318 if (position
>= This
->len
)
3321 range
= get_layout_range_by_pos(This
, position
);
3322 *object
= range
->object
;
3324 IDWriteInlineObject_AddRef(*object
);
3326 return return_range(&range
->h
, r
);
3329 static HRESULT WINAPI
dwritetextlayout_GetTypography(IDWriteTextLayout3
*iface
,
3330 UINT32 position
, IDWriteTypography
** typography
, DWRITE_TEXT_RANGE
*r
)
3332 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3333 struct layout_range_iface
*range
;
3335 TRACE("(%p)->(%u %p %p)\n", This
, position
, typography
, r
);
3337 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&This
->typographies
, position
);
3338 *typography
= (IDWriteTypography
*)range
->iface
;
3340 IDWriteTypography_AddRef(*typography
);
3342 return return_range(&range
->h
, r
);
3345 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout3
*iface
,
3346 UINT32 position
, UINT32
* length
, DWRITE_TEXT_RANGE
*r
)
3348 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3349 TRACE("(%p)->(%u %p %p)\n", This
, position
, length
, r
);
3350 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, length
, r
);
3353 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout3
*iface
,
3354 UINT32 position
, WCHAR
* locale
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3356 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3357 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, locale
, length
, r
);
3358 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, locale
, length
, r
);
3361 static inline FLOAT
renderer_apply_snapping(FLOAT coord
, BOOL skiptransform
, FLOAT ppdip
, FLOAT det
,
3362 const DWRITE_MATRIX
*m
)
3364 FLOAT vec
[2], vec2
[2];
3366 if (!skiptransform
) {
3367 /* apply transform */
3369 vec
[1] = coord
* ppdip
;
3371 vec2
[0] = m
->m11
* vec
[0] + m
->m21
* vec
[1] + m
->dx
;
3372 vec2
[1] = m
->m12
* vec
[0] + m
->m22
* vec
[1] + m
->dy
;
3375 vec2
[0] = floorf(vec2
[0] + 0.5f
);
3376 vec2
[1] = floorf(vec2
[1] + 0.5f
);
3378 /* apply inverted transform, we don't care about X component at this point */
3379 vec
[1] = (-m
->m12
* vec2
[0] + m
->m11
* vec2
[1] - (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
3383 vec
[1] = floorf(coord
* ppdip
+ 0.5f
) / ppdip
;
3388 static HRESULT WINAPI
dwritetextlayout_Draw(IDWriteTextLayout3
*iface
,
3389 void *context
, IDWriteTextRenderer
* renderer
, FLOAT origin_x
, FLOAT origin_y
)
3391 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3392 BOOL disabled
= FALSE
, skiptransform
= FALSE
;
3393 struct layout_effective_inline
*inlineobject
;
3394 struct layout_effective_run
*run
;
3395 struct layout_strikethrough
*s
;
3396 struct layout_underline
*u
;
3397 FLOAT det
= 0.0f
, ppdip
= 0.0f
;
3398 DWRITE_MATRIX m
= { 0 };
3401 TRACE("(%p)->(%p %p %.2f %.2f)\n", This
, context
, renderer
, origin_x
, origin_y
);
3403 hr
= layout_compute_effective_runs(This
);
3407 hr
= IDWriteTextRenderer_IsPixelSnappingDisabled(renderer
, context
, &disabled
);
3412 hr
= IDWriteTextRenderer_GetPixelsPerDip(renderer
, context
, &ppdip
);
3416 hr
= IDWriteTextRenderer_GetCurrentTransform(renderer
, context
, &m
);
3420 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3421 if (ppdip
<= 0.0f
||
3422 (m
.m11
* m
.m22
!= 0.0f
&& (m
.m12
!= 0.0f
|| m
.m21
!= 0.0f
)) ||
3423 (m
.m12
* m
.m21
!= 0.0f
&& (m
.m11
!= 0.0f
|| m
.m22
!= 0.0f
)))
3426 skiptransform
= should_skip_transform(&m
, &det
);
3429 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3430 /* 1. Regular runs */
3431 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
3432 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3433 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3434 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
3435 DWRITE_GLYPH_RUN glyph_run
;
3437 /* Everything but cluster map will be reused from nominal run, as we only need
3438 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3439 it can't be reused because it has to start with 0 index for each reported run. */
3440 glyph_run
= regular
->run
;
3441 glyph_run
.glyphCount
= run
->glyphcount
;
3443 /* fixup glyph data arrays */
3444 glyph_run
.glyphIndices
+= start_glyph
;
3445 glyph_run
.glyphAdvances
+= start_glyph
;
3446 glyph_run
.glyphOffsets
+= start_glyph
;
3449 descr
= regular
->descr
;
3450 descr
.stringLength
= run
->length
;
3451 descr
.string
+= run
->start
;
3452 descr
.clusterMap
= run
->clustermap
;
3453 descr
.textPosition
+= run
->start
;
3455 /* return value is ignored */
3456 IDWriteTextRenderer_DrawGlyphRun(renderer
,
3458 run
->origin_x
+ run
->align_dx
+ origin_x
,
3459 SNAP_COORD(run
->origin_y
+ origin_y
),
3460 This
->measuringmode
,
3466 /* 2. Inline objects */
3467 LIST_FOR_EACH_ENTRY(inlineobject
, &This
->inlineobjects
, struct layout_effective_inline
, entry
) {
3468 IDWriteTextRenderer_DrawInlineObject(renderer
,
3470 inlineobject
->origin_x
+ inlineobject
->align_dx
+ origin_x
,
3471 SNAP_COORD(inlineobject
->origin_y
+ origin_y
),
3472 inlineobject
->object
,
3473 inlineobject
->is_sideways
,
3474 inlineobject
->is_rtl
,
3475 inlineobject
->effect
);
3479 LIST_FOR_EACH_ENTRY(u
, &This
->underlines
, struct layout_underline
, entry
) {
3480 IDWriteTextRenderer_DrawUnderline(renderer
,
3482 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3483 (is_run_rtl(u
->run
) ? u
->run
->origin_x
- u
->run
->width
: u
->run
->origin_x
) + u
->run
->align_dx
+ origin_x
,
3484 SNAP_COORD(u
->run
->origin_y
+ origin_y
),
3489 /* 4. Strikethrough */
3490 LIST_FOR_EACH_ENTRY(s
, &This
->strikethrough
, struct layout_strikethrough
, entry
) {
3491 IDWriteTextRenderer_DrawStrikethrough(renderer
,
3493 s
->run
->origin_x
+ s
->run
->align_dx
+ origin_x
,
3494 SNAP_COORD(s
->run
->origin_y
+ origin_y
),
3503 static HRESULT WINAPI
dwritetextlayout_GetLineMetrics(IDWriteTextLayout3
*iface
,
3504 DWRITE_LINE_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3506 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3509 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
3511 hr
= layout_compute_effective_runs(This
);
3516 UINT32 i
, c
= min(max_count
, This
->metrics
.lineCount
);
3517 for (i
= 0; i
< c
; i
++)
3518 memcpy(metrics
+ i
, This
->linemetrics
+ i
, sizeof(*metrics
));
3521 *count
= This
->metrics
.lineCount
;
3522 return max_count
>= This
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3525 static HRESULT WINAPI
dwritetextlayout_GetMetrics(IDWriteTextLayout3
*iface
, DWRITE_TEXT_METRICS
*metrics
)
3527 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3528 DWRITE_TEXT_METRICS1 metrics1
;
3531 TRACE("(%p)->(%p)\n", This
, metrics
);
3533 hr
= IDWriteTextLayout3_GetMetrics(iface
, &metrics1
);
3535 memcpy(metrics
, &metrics1
, sizeof(*metrics
));
3540 static void scale_glyph_bbox(RECT
*bbox
, FLOAT emSize
, UINT16 units_per_em
, D2D_RECT_F
*ret
)
3542 #define SCALE(x) ((FLOAT)x * emSize / (FLOAT)units_per_em)
3543 ret
->left
= SCALE(bbox
->left
);
3544 ret
->right
= SCALE(bbox
->right
);
3545 ret
->top
= SCALE(bbox
->top
);
3546 ret
->bottom
= SCALE(bbox
->bottom
);
3550 static void d2d_rect_offset(D2D_RECT_F
*rect
, FLOAT x
, FLOAT y
)
3558 static BOOL
d2d_rect_is_empty(const D2D_RECT_F
*rect
)
3560 return ((rect
->left
>= rect
->right
) || (rect
->top
>= rect
->bottom
));
3563 static void d2d_rect_union(D2D_RECT_F
*dst
, const D2D_RECT_F
*src
)
3565 if (d2d_rect_is_empty(dst
)) {
3566 if (d2d_rect_is_empty(src
)) {
3567 dst
->left
= dst
->right
= dst
->top
= dst
->bottom
= 0.0f
;
3574 if (!d2d_rect_is_empty(src
)) {
3575 dst
->left
= min(dst
->left
, src
->left
);
3576 dst
->right
= max(dst
->right
, src
->right
);
3577 dst
->top
= min(dst
->top
, src
->top
);
3578 dst
->bottom
= max(dst
->bottom
, src
->bottom
);
3583 static void layout_get_erun_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_run
*run
, D2D_RECT_F
*bbox
)
3585 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3586 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3587 const DWRITE_GLYPH_RUN
*glyph_run
= ®ular
->run
;
3588 DWRITE_FONT_METRICS font_metrics
;
3589 D2D_POINT_2F origin
= { 0 };
3592 IDWriteFontFace_GetMetrics(glyph_run
->fontFace
, &font_metrics
);
3594 origin
.x
= run
->origin_x
+ run
->align_dx
;
3595 origin
.y
= run
->origin_y
;
3596 for (i
= 0; i
< run
->glyphcount
; i
++) {
3597 D2D_RECT_F glyph_bbox
;
3600 freetype_get_design_glyph_bbox((IDWriteFontFace4
*)glyph_run
->fontFace
, font_metrics
.designUnitsPerEm
,
3601 glyph_run
->glyphIndices
[i
+ start_glyph
], &design_bbox
);
3603 scale_glyph_bbox(&design_bbox
, glyph_run
->fontEmSize
, font_metrics
.designUnitsPerEm
, &glyph_bbox
);
3604 d2d_rect_offset(&glyph_bbox
, origin
.x
+ glyph_run
->glyphOffsets
[i
+ start_glyph
].advanceOffset
,
3605 origin
.y
+ glyph_run
->glyphOffsets
[i
+ start_glyph
].ascenderOffset
);
3606 d2d_rect_union(bbox
, &glyph_bbox
);
3608 /* FIXME: take care of vertical/rtl */
3609 origin
.x
+= glyph_run
->glyphAdvances
[i
+ start_glyph
];
3613 static HRESULT WINAPI
dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3
*iface
,
3614 DWRITE_OVERHANG_METRICS
*overhangs
)
3616 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3617 struct layout_effective_run
*run
;
3618 D2D_RECT_F bbox
= { 0 };
3621 TRACE("(%p)->(%p)\n", This
, overhangs
);
3623 memset(overhangs
, 0, sizeof(*overhangs
));
3625 if (!(This
->recompute
& RECOMPUTE_OVERHANGS
)) {
3626 *overhangs
= This
->overhangs
;
3630 hr
= layout_compute_effective_runs(This
);
3634 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
3635 D2D_RECT_F run_bbox
;
3637 layout_get_erun_bbox(This
, run
, &run_bbox
);
3638 d2d_rect_union(&bbox
, &run_bbox
);
3641 /* FIXME: iterate over inline objects too */
3643 /* deltas from text content metrics */
3644 This
->overhangs
.left
= -bbox
.left
;
3645 This
->overhangs
.top
= -bbox
.top
;
3646 This
->overhangs
.right
= bbox
.right
- This
->metrics
.layoutWidth
;
3647 This
->overhangs
.bottom
= bbox
.bottom
- This
->metrics
.layoutHeight
;
3648 This
->recompute
&= ~RECOMPUTE_OVERHANGS
;
3650 *overhangs
= This
->overhangs
;
3655 static HRESULT WINAPI
dwritetextlayout_GetClusterMetrics(IDWriteTextLayout3
*iface
,
3656 DWRITE_CLUSTER_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3658 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3661 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
3663 hr
= layout_compute(This
);
3668 memcpy(metrics
, This
->clustermetrics
, sizeof(DWRITE_CLUSTER_METRICS
)*min(max_count
, This
->cluster_count
));
3670 *count
= This
->cluster_count
;
3671 return max_count
>= This
->cluster_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3674 static HRESULT WINAPI
dwritetextlayout_DetermineMinWidth(IDWriteTextLayout3
*iface
, FLOAT
* min_width
)
3676 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3681 TRACE("(%p)->(%p)\n", This
, min_width
);
3684 return E_INVALIDARG
;
3686 if (!(This
->recompute
& RECOMPUTE_MINIMAL_WIDTH
))
3690 hr
= layout_compute(This
);
3694 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3695 preceding breaking point do not contribute to word width. */
3696 for (start
= 0; start
< This
->cluster_count
;) {
3697 UINT32 end
= start
, j
, next
;
3699 /* Last cluster always could be wrapped after. */
3700 while (!This
->clustermetrics
[end
].canWrapLineAfter
)
3702 /* make is so current cluster range that we can wrap after is [start,end) */
3707 /* Ignore trailing whitespace clusters, in case of single space range will
3708 be reduced to empty range, or [start,start+1). */
3709 while (end
> start
&& This
->clustermetrics
[end
-1].isWhitespace
)
3712 /* check if cluster range exceeds last minimal width */
3714 for (j
= start
; j
< end
; j
++)
3715 width
+= This
->clustermetrics
[j
].width
;
3719 if (width
> This
->minwidth
)
3720 This
->minwidth
= width
;
3722 This
->recompute
&= ~RECOMPUTE_MINIMAL_WIDTH
;
3725 *min_width
= This
->minwidth
;
3729 static HRESULT WINAPI
dwritetextlayout_HitTestPoint(IDWriteTextLayout3
*iface
,
3730 FLOAT pointX
, FLOAT pointY
, BOOL
* is_trailinghit
, BOOL
* is_inside
, DWRITE_HIT_TEST_METRICS
*metrics
)
3732 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3733 FIXME("(%p)->(%f %f %p %p %p): stub\n", This
, pointX
, pointY
, is_trailinghit
, is_inside
, metrics
);
3737 static HRESULT WINAPI
dwritetextlayout_HitTestTextPosition(IDWriteTextLayout3
*iface
,
3738 UINT32 textPosition
, BOOL is_trailinghit
, FLOAT
* pointX
, FLOAT
* pointY
, DWRITE_HIT_TEST_METRICS
*metrics
)
3740 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3741 FIXME("(%p)->(%u %d %p %p %p): stub\n", This
, textPosition
, is_trailinghit
, pointX
, pointY
, metrics
);
3745 static HRESULT WINAPI
dwritetextlayout_HitTestTextRange(IDWriteTextLayout3
*iface
,
3746 UINT32 textPosition
, UINT32 textLength
, FLOAT originX
, FLOAT originY
,
3747 DWRITE_HIT_TEST_METRICS
*metrics
, UINT32 max_metricscount
, UINT32
* actual_metricscount
)
3749 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3750 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This
, textPosition
, textLength
, originX
, originY
, metrics
,
3751 max_metricscount
, actual_metricscount
);
3755 static HRESULT WINAPI
dwritetextlayout1_SetPairKerning(IDWriteTextLayout3
*iface
, BOOL is_pairkerning_enabled
,
3756 DWRITE_TEXT_RANGE range
)
3758 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3759 struct layout_range_attr_value value
;
3761 TRACE("(%p)->(%d %s)\n", This
, is_pairkerning_enabled
, debugstr_range(&range
));
3763 value
.range
= range
;
3764 value
.u
.pair_kerning
= !!is_pairkerning_enabled
;
3765 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_PAIR_KERNING
, &value
);
3768 static HRESULT WINAPI
dwritetextlayout1_GetPairKerning(IDWriteTextLayout3
*iface
, UINT32 position
, BOOL
*is_pairkerning_enabled
,
3769 DWRITE_TEXT_RANGE
*r
)
3771 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3772 struct layout_range
*range
;
3774 TRACE("(%p)->(%u %p %p)\n", This
, position
, is_pairkerning_enabled
, r
);
3776 if (position
>= This
->len
)
3779 range
= get_layout_range_by_pos(This
, position
);
3780 *is_pairkerning_enabled
= range
->pair_kerning
;
3782 return return_range(&range
->h
, r
);
3785 static HRESULT WINAPI
dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout3
*iface
, FLOAT leading
, FLOAT trailing
,
3786 FLOAT min_advance
, DWRITE_TEXT_RANGE range
)
3788 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3789 struct layout_range_attr_value value
;
3791 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This
, leading
, trailing
, min_advance
, debugstr_range(&range
));
3793 if (min_advance
< 0.0f
)
3794 return E_INVALIDARG
;
3796 value
.range
= range
;
3797 value
.u
.spacing
[0] = leading
;
3798 value
.u
.spacing
[1] = trailing
;
3799 value
.u
.spacing
[2] = min_advance
;
3800 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_SPACING
, &value
);
3803 static HRESULT WINAPI
dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout3
*iface
, UINT32 position
, FLOAT
*leading
,
3804 FLOAT
*trailing
, FLOAT
*min_advance
, DWRITE_TEXT_RANGE
*r
)
3806 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3807 struct layout_range_spacing
*range
;
3809 TRACE("(%p)->(%u %p %p %p %p)\n", This
, position
, leading
, trailing
, min_advance
, r
);
3811 range
= (struct layout_range_spacing
*)get_layout_range_header_by_pos(&This
->spacing
, position
);
3812 *leading
= range
->leading
;
3813 *trailing
= range
->trailing
;
3814 *min_advance
= range
->min_advance
;
3816 return return_range(&range
->h
, r
);
3819 static HRESULT WINAPI
dwritetextlayout2_GetMetrics(IDWriteTextLayout3
*iface
, DWRITE_TEXT_METRICS1
*metrics
)
3821 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3824 TRACE("(%p)->(%p)\n", This
, metrics
);
3826 hr
= layout_compute_effective_runs(This
);
3830 *metrics
= This
->metrics
;
3834 static HRESULT WINAPI
dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout3
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
3836 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3838 TRACE("(%p)->(%d)\n", This
, orientation
);
3840 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
3841 return E_INVALIDARG
;
3843 This
->format
.vertical_orientation
= orientation
;
3847 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout3
*iface
)
3849 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3850 TRACE("(%p)\n", This
);
3851 return This
->format
.vertical_orientation
;
3854 static HRESULT WINAPI
dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout3
*iface
, BOOL lastline_wrapping_enabled
)
3856 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3857 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
3858 return IDWriteTextFormat1_SetLastLineWrapping(&This
->IDWriteTextFormat1_iface
, lastline_wrapping_enabled
);
3861 static BOOL WINAPI
dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout3
*iface
)
3863 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3864 TRACE("(%p)\n", This
);
3865 return IDWriteTextFormat1_GetLastLineWrapping(&This
->IDWriteTextFormat1_iface
);
3868 static HRESULT WINAPI
dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout3
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
3870 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3871 TRACE("(%p)->(%d)\n", This
, alignment
);
3872 return IDWriteTextFormat1_SetOpticalAlignment(&This
->IDWriteTextFormat1_iface
, alignment
);
3875 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout3
*iface
)
3877 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3878 TRACE("(%p)\n", This
);
3879 return IDWriteTextFormat1_GetOpticalAlignment(&This
->IDWriteTextFormat1_iface
);
3882 static HRESULT WINAPI
dwritetextlayout2_SetFontFallback(IDWriteTextLayout3
*iface
, IDWriteFontFallback
*fallback
)
3884 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3885 TRACE("(%p)->(%p)\n", This
, fallback
);
3886 return set_fontfallback_for_format(&This
->format
, fallback
);
3889 static HRESULT WINAPI
dwritetextlayout2_GetFontFallback(IDWriteTextLayout3
*iface
, IDWriteFontFallback
**fallback
)
3891 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3892 TRACE("(%p)->(%p)\n", This
, fallback
);
3893 return get_fontfallback_from_format(&This
->format
, fallback
);
3896 static HRESULT WINAPI
dwritetextlayout3_InvalidateLayout(IDWriteTextLayout3
*iface
)
3898 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3900 TRACE("(%p)\n", This
);
3902 This
->recompute
= RECOMPUTE_EVERYTHING
;
3906 static HRESULT WINAPI
dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING
const *spacing
)
3908 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3912 TRACE("(%p)->(%p)\n", This
, spacing
);
3914 hr
= format_set_linespacing(&This
->format
, spacing
, &changed
);
3919 if (!(This
->recompute
& RECOMPUTE_LINES
)) {
3922 switch (This
->format
.spacing
.method
)
3924 case DWRITE_LINE_SPACING_METHOD_DEFAULT
:
3925 for (line
= 0; line
< This
->metrics
.lineCount
; line
++) {
3926 This
->linemetrics
[line
].height
= This
->lines
[line
].height
;
3927 This
->linemetrics
[line
].baseline
= This
->lines
[line
].baseline
;
3930 case DWRITE_LINE_SPACING_METHOD_UNIFORM
:
3931 for (line
= 0; line
< This
->metrics
.lineCount
; line
++) {
3932 This
->linemetrics
[line
].height
= This
->format
.spacing
.height
;
3933 This
->linemetrics
[line
].baseline
= This
->format
.spacing
.baseline
;
3936 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
:
3937 for (line
= 0; line
< This
->metrics
.lineCount
; line
++) {
3938 This
->linemetrics
[line
].height
= This
->format
.spacing
.height
* This
->lines
[line
].height
;
3939 This
->linemetrics
[line
].baseline
= This
->format
.spacing
.baseline
* This
->lines
[line
].baseline
;
3946 layout_set_line_positions(This
);
3949 This
->recompute
|= RECOMPUTE_OVERHANGS
;
3955 static HRESULT WINAPI
dwritetextlayout3_GetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING
*spacing
)
3957 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3959 TRACE("(%p)->(%p)\n", This
, spacing
);
3961 *spacing
= This
->format
.spacing
;
3965 static HRESULT WINAPI
dwritetextlayout3_GetLineMetrics(IDWriteTextLayout3
*iface
, DWRITE_LINE_METRICS1
*metrics
,
3966 UINT32 max_count
, UINT32
*count
)
3968 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3971 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
3973 hr
= layout_compute_effective_runs(This
);
3978 memcpy(metrics
, This
->linemetrics
, sizeof(*metrics
) * min(max_count
, This
->metrics
.lineCount
));
3980 *count
= This
->metrics
.lineCount
;
3981 return max_count
>= This
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3984 static const IDWriteTextLayout3Vtbl dwritetextlayoutvtbl
= {
3985 dwritetextlayout_QueryInterface
,
3986 dwritetextlayout_AddRef
,
3987 dwritetextlayout_Release
,
3988 dwritetextlayout_SetTextAlignment
,
3989 dwritetextlayout_SetParagraphAlignment
,
3990 dwritetextlayout_SetWordWrapping
,
3991 dwritetextlayout_SetReadingDirection
,
3992 dwritetextlayout_SetFlowDirection
,
3993 dwritetextlayout_SetIncrementalTabStop
,
3994 dwritetextlayout_SetTrimming
,
3995 dwritetextlayout_SetLineSpacing
,
3996 dwritetextlayout_GetTextAlignment
,
3997 dwritetextlayout_GetParagraphAlignment
,
3998 dwritetextlayout_GetWordWrapping
,
3999 dwritetextlayout_GetReadingDirection
,
4000 dwritetextlayout_GetFlowDirection
,
4001 dwritetextlayout_GetIncrementalTabStop
,
4002 dwritetextlayout_GetTrimming
,
4003 dwritetextlayout_GetLineSpacing
,
4004 dwritetextlayout_GetFontCollection
,
4005 dwritetextlayout_GetFontFamilyNameLength
,
4006 dwritetextlayout_GetFontFamilyName
,
4007 dwritetextlayout_GetFontWeight
,
4008 dwritetextlayout_GetFontStyle
,
4009 dwritetextlayout_GetFontStretch
,
4010 dwritetextlayout_GetFontSize
,
4011 dwritetextlayout_GetLocaleNameLength
,
4012 dwritetextlayout_GetLocaleName
,
4013 dwritetextlayout_SetMaxWidth
,
4014 dwritetextlayout_SetMaxHeight
,
4015 dwritetextlayout_SetFontCollection
,
4016 dwritetextlayout_SetFontFamilyName
,
4017 dwritetextlayout_SetFontWeight
,
4018 dwritetextlayout_SetFontStyle
,
4019 dwritetextlayout_SetFontStretch
,
4020 dwritetextlayout_SetFontSize
,
4021 dwritetextlayout_SetUnderline
,
4022 dwritetextlayout_SetStrikethrough
,
4023 dwritetextlayout_SetDrawingEffect
,
4024 dwritetextlayout_SetInlineObject
,
4025 dwritetextlayout_SetTypography
,
4026 dwritetextlayout_SetLocaleName
,
4027 dwritetextlayout_GetMaxWidth
,
4028 dwritetextlayout_GetMaxHeight
,
4029 dwritetextlayout_layout_GetFontCollection
,
4030 dwritetextlayout_layout_GetFontFamilyNameLength
,
4031 dwritetextlayout_layout_GetFontFamilyName
,
4032 dwritetextlayout_layout_GetFontWeight
,
4033 dwritetextlayout_layout_GetFontStyle
,
4034 dwritetextlayout_layout_GetFontStretch
,
4035 dwritetextlayout_layout_GetFontSize
,
4036 dwritetextlayout_GetUnderline
,
4037 dwritetextlayout_GetStrikethrough
,
4038 dwritetextlayout_GetDrawingEffect
,
4039 dwritetextlayout_GetInlineObject
,
4040 dwritetextlayout_GetTypography
,
4041 dwritetextlayout_layout_GetLocaleNameLength
,
4042 dwritetextlayout_layout_GetLocaleName
,
4043 dwritetextlayout_Draw
,
4044 dwritetextlayout_GetLineMetrics
,
4045 dwritetextlayout_GetMetrics
,
4046 dwritetextlayout_GetOverhangMetrics
,
4047 dwritetextlayout_GetClusterMetrics
,
4048 dwritetextlayout_DetermineMinWidth
,
4049 dwritetextlayout_HitTestPoint
,
4050 dwritetextlayout_HitTestTextPosition
,
4051 dwritetextlayout_HitTestTextRange
,
4052 dwritetextlayout1_SetPairKerning
,
4053 dwritetextlayout1_GetPairKerning
,
4054 dwritetextlayout1_SetCharacterSpacing
,
4055 dwritetextlayout1_GetCharacterSpacing
,
4056 dwritetextlayout2_GetMetrics
,
4057 dwritetextlayout2_SetVerticalGlyphOrientation
,
4058 dwritetextlayout2_GetVerticalGlyphOrientation
,
4059 dwritetextlayout2_SetLastLineWrapping
,
4060 dwritetextlayout2_GetLastLineWrapping
,
4061 dwritetextlayout2_SetOpticalAlignment
,
4062 dwritetextlayout2_GetOpticalAlignment
,
4063 dwritetextlayout2_SetFontFallback
,
4064 dwritetextlayout2_GetFontFallback
,
4065 dwritetextlayout3_InvalidateLayout
,
4066 dwritetextlayout3_SetLineSpacing
,
4067 dwritetextlayout3_GetLineSpacing
,
4068 dwritetextlayout3_GetLineMetrics
4071 static HRESULT WINAPI
dwritetextformat_layout_QueryInterface(IDWriteTextFormat1
*iface
, REFIID riid
, void **obj
)
4073 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4074 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
4075 return IDWriteTextLayout3_QueryInterface(&This
->IDWriteTextLayout3_iface
, riid
, obj
);
4078 static ULONG WINAPI
dwritetextformat_layout_AddRef(IDWriteTextFormat1
*iface
)
4080 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4081 return IDWriteTextLayout3_AddRef(&This
->IDWriteTextLayout3_iface
);
4084 static ULONG WINAPI
dwritetextformat_layout_Release(IDWriteTextFormat1
*iface
)
4086 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4087 return IDWriteTextLayout3_Release(&This
->IDWriteTextLayout3_iface
);
4090 static HRESULT WINAPI
dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat1
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
4092 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4096 TRACE("(%p)->(%d)\n", This
, alignment
);
4098 hr
= format_set_textalignment(&This
->format
, alignment
, &changed
);
4102 /* if layout is not ready there's nothing to align */
4103 if (changed
&& !(This
->recompute
& RECOMPUTE_LINES
))
4104 layout_apply_text_alignment(This
);
4109 static HRESULT WINAPI
dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat1
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
4111 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4115 TRACE("(%p)->(%d)\n", This
, alignment
);
4117 hr
= format_set_paralignment(&This
->format
, alignment
, &changed
);
4121 /* if layout is not ready there's nothing to align */
4122 if (changed
&& !(This
->recompute
& RECOMPUTE_LINES
))
4123 layout_apply_par_alignment(This
);
4128 static HRESULT WINAPI
dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat1
*iface
, DWRITE_WORD_WRAPPING wrapping
)
4130 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4134 TRACE("(%p)->(%d)\n", This
, wrapping
);
4136 hr
= format_set_wordwrapping(&This
->format
, wrapping
, &changed
);
4141 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4146 static HRESULT WINAPI
dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat1
*iface
, DWRITE_READING_DIRECTION direction
)
4148 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4152 TRACE("(%p)->(%d)\n", This
, direction
);
4154 hr
= format_set_readingdirection(&This
->format
, direction
, &changed
);
4159 This
->recompute
= RECOMPUTE_EVERYTHING
;
4164 static HRESULT WINAPI
dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat1
*iface
, DWRITE_FLOW_DIRECTION direction
)
4166 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4170 TRACE("(%p)->(%d)\n", This
, direction
);
4172 hr
= format_set_flowdirection(&This
->format
, direction
, &changed
);
4177 This
->recompute
= RECOMPUTE_EVERYTHING
;
4182 static HRESULT WINAPI
dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat1
*iface
, FLOAT tabstop
)
4184 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4185 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
4189 static HRESULT WINAPI
dwritetextformat_layout_SetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
const *trimming
,
4190 IDWriteInlineObject
*trimming_sign
)
4192 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4196 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
4198 hr
= format_set_trimming(&This
->format
, trimming
, trimming_sign
, &changed
);
4201 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4206 static HRESULT WINAPI
dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD method
,
4207 FLOAT height
, FLOAT baseline
)
4209 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4210 DWRITE_LINE_SPACING spacing
;
4212 TRACE("(%p)->(%d %f %f)\n", This
, method
, height
, baseline
);
4214 spacing
= This
->format
.spacing
;
4215 spacing
.method
= method
;
4216 spacing
.height
= height
;
4217 spacing
.baseline
= baseline
;
4218 return IDWriteTextLayout3_SetLineSpacing(&This
->IDWriteTextLayout3_iface
, &spacing
);
4221 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat1
*iface
)
4223 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4224 TRACE("(%p)\n", This
);
4225 return This
->format
.textalignment
;
4228 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat1
*iface
)
4230 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4231 TRACE("(%p)\n", This
);
4232 return This
->format
.paralign
;
4235 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat1
*iface
)
4237 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4238 TRACE("(%p)\n", This
);
4239 return This
->format
.wrapping
;
4242 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat1
*iface
)
4244 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4245 TRACE("(%p)\n", This
);
4246 return This
->format
.readingdir
;
4249 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat1
*iface
)
4251 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4252 TRACE("(%p)\n", This
);
4253 return This
->format
.flow
;
4256 static FLOAT WINAPI
dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat1
*iface
)
4258 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4259 FIXME("(%p): stub\n", This
);
4263 static HRESULT WINAPI
dwritetextformat_layout_GetTrimming(IDWriteTextFormat1
*iface
, DWRITE_TRIMMING
*options
,
4264 IDWriteInlineObject
**trimming_sign
)
4266 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4268 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
4270 *options
= This
->format
.trimming
;
4271 *trimming_sign
= This
->format
.trimmingsign
;
4273 IDWriteInlineObject_AddRef(*trimming_sign
);
4277 static HRESULT WINAPI
dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat1
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
4278 FLOAT
*spacing
, FLOAT
*baseline
)
4280 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4282 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
4284 *method
= This
->format
.spacing
.method
;
4285 *spacing
= This
->format
.spacing
.height
;
4286 *baseline
= This
->format
.spacing
.baseline
;
4290 static HRESULT WINAPI
dwritetextformat_layout_GetFontCollection(IDWriteTextFormat1
*iface
, IDWriteFontCollection
**collection
)
4292 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4294 TRACE("(%p)->(%p)\n", This
, collection
);
4296 *collection
= This
->format
.collection
;
4298 IDWriteFontCollection_AddRef(*collection
);
4302 static UINT32 WINAPI
dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat1
*iface
)
4304 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4305 TRACE("(%p)\n", This
);
4306 return This
->format
.family_len
;
4309 static HRESULT WINAPI
dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
4311 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4313 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4315 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
4316 strcpyW(name
, This
->format
.family_name
);
4320 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_layout_GetFontWeight(IDWriteTextFormat1
*iface
)
4322 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4323 TRACE("(%p)\n", This
);
4324 return This
->format
.weight
;
4327 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_layout_GetFontStyle(IDWriteTextFormat1
*iface
)
4329 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4330 TRACE("(%p)\n", This
);
4331 return This
->format
.style
;
4334 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_layout_GetFontStretch(IDWriteTextFormat1
*iface
)
4336 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4337 TRACE("(%p)\n", This
);
4338 return This
->format
.stretch
;
4341 static FLOAT WINAPI
dwritetextformat_layout_GetFontSize(IDWriteTextFormat1
*iface
)
4343 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4344 TRACE("(%p)\n", This
);
4345 return This
->format
.fontsize
;
4348 static UINT32 WINAPI
dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat1
*iface
)
4350 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4351 TRACE("(%p)\n", This
);
4352 return This
->format
.locale_len
;
4355 static HRESULT WINAPI
dwritetextformat_layout_GetLocaleName(IDWriteTextFormat1
*iface
, WCHAR
*name
, UINT32 size
)
4357 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4359 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4361 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
4362 strcpyW(name
, This
->format
.locale
);
4366 static HRESULT WINAPI
dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4368 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4369 FIXME("(%p)->(%d): stub\n", This
, orientation
);
4373 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat1
*iface
)
4375 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4376 FIXME("(%p): stub\n", This
);
4377 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
4380 static HRESULT WINAPI
dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat1
*iface
, BOOL lastline_wrapping_enabled
)
4382 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4384 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
4386 This
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
4390 static BOOL WINAPI
dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat1
*iface
)
4392 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4393 TRACE("(%p)\n", This
);
4394 return This
->format
.last_line_wrapping
;
4397 static HRESULT WINAPI
dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat1
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
4399 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4400 TRACE("(%p)->(%d)\n", This
, alignment
);
4401 return format_set_optical_alignment(&This
->format
, alignment
);
4404 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat1
*iface
)
4406 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4407 TRACE("(%p)\n", This
);
4408 return This
->format
.optical_alignment
;
4411 static HRESULT WINAPI
dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
*fallback
)
4413 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4414 TRACE("(%p)->(%p)\n", This
, fallback
);
4415 return IDWriteTextLayout3_SetFontFallback(&This
->IDWriteTextLayout3_iface
, fallback
);
4418 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat1
*iface
, IDWriteFontFallback
**fallback
)
4420 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat1(iface
);
4421 TRACE("(%p)->(%p)\n", This
, fallback
);
4422 return IDWriteTextLayout3_GetFontFallback(&This
->IDWriteTextLayout3_iface
, fallback
);
4425 static const IDWriteTextFormat1Vtbl dwritetextformat1_layout_vtbl
= {
4426 dwritetextformat_layout_QueryInterface
,
4427 dwritetextformat_layout_AddRef
,
4428 dwritetextformat_layout_Release
,
4429 dwritetextformat_layout_SetTextAlignment
,
4430 dwritetextformat_layout_SetParagraphAlignment
,
4431 dwritetextformat_layout_SetWordWrapping
,
4432 dwritetextformat_layout_SetReadingDirection
,
4433 dwritetextformat_layout_SetFlowDirection
,
4434 dwritetextformat_layout_SetIncrementalTabStop
,
4435 dwritetextformat_layout_SetTrimming
,
4436 dwritetextformat_layout_SetLineSpacing
,
4437 dwritetextformat_layout_GetTextAlignment
,
4438 dwritetextformat_layout_GetParagraphAlignment
,
4439 dwritetextformat_layout_GetWordWrapping
,
4440 dwritetextformat_layout_GetReadingDirection
,
4441 dwritetextformat_layout_GetFlowDirection
,
4442 dwritetextformat_layout_GetIncrementalTabStop
,
4443 dwritetextformat_layout_GetTrimming
,
4444 dwritetextformat_layout_GetLineSpacing
,
4445 dwritetextformat_layout_GetFontCollection
,
4446 dwritetextformat_layout_GetFontFamilyNameLength
,
4447 dwritetextformat_layout_GetFontFamilyName
,
4448 dwritetextformat_layout_GetFontWeight
,
4449 dwritetextformat_layout_GetFontStyle
,
4450 dwritetextformat_layout_GetFontStretch
,
4451 dwritetextformat_layout_GetFontSize
,
4452 dwritetextformat_layout_GetLocaleNameLength
,
4453 dwritetextformat_layout_GetLocaleName
,
4454 dwritetextformat1_layout_SetVerticalGlyphOrientation
,
4455 dwritetextformat1_layout_GetVerticalGlyphOrientation
,
4456 dwritetextformat1_layout_SetLastLineWrapping
,
4457 dwritetextformat1_layout_GetLastLineWrapping
,
4458 dwritetextformat1_layout_SetOpticalAlignment
,
4459 dwritetextformat1_layout_GetOpticalAlignment
,
4460 dwritetextformat1_layout_SetFontFallback
,
4461 dwritetextformat1_layout_GetFontFallback
,
4464 static HRESULT WINAPI
dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1
*iface
,
4465 REFIID riid
, void **obj
)
4467 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink1
) ||
4468 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink
) ||
4469 IsEqualIID(riid
, &IID_IUnknown
))
4472 IDWriteTextAnalysisSink1_AddRef(iface
);
4477 return E_NOINTERFACE
;
4480 static ULONG WINAPI
dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1
*iface
)
4482 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4483 return IDWriteTextLayout3_AddRef(&layout
->IDWriteTextLayout3_iface
);
4486 static ULONG WINAPI
dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1
*iface
)
4488 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4489 return IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
4492 static HRESULT WINAPI
dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1
*iface
,
4493 UINT32 position
, UINT32 length
, DWRITE_SCRIPT_ANALYSIS
const* sa
)
4495 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4496 struct layout_run
*run
;
4498 TRACE("[%u,%u) script=%u:%s\n", position
, position
+ length
, sa
->script
, debugstr_sa_script(sa
->script
));
4500 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
);
4502 return E_OUTOFMEMORY
;
4504 run
->u
.regular
.descr
.string
= &layout
->str
[position
];
4505 run
->u
.regular
.descr
.stringLength
= length
;
4506 run
->u
.regular
.descr
.textPosition
= position
;
4507 run
->u
.regular
.sa
= *sa
;
4508 list_add_tail(&layout
->runs
, &run
->entry
);
4512 static HRESULT WINAPI
dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1
*iface
,
4513 UINT32 position
, UINT32 length
, DWRITE_LINE_BREAKPOINT
const* breakpoints
)
4515 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4517 if (position
+ length
> layout
->len
)
4520 memcpy(&layout
->nominal_breakpoints
[position
], breakpoints
, length
*sizeof(DWRITE_LINE_BREAKPOINT
));
4524 static HRESULT WINAPI
dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1
*iface
, UINT32 position
,
4525 UINT32 length
, UINT8 explicitLevel
, UINT8 resolvedLevel
)
4527 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4528 struct layout_run
*cur_run
;
4530 TRACE("[%u,%u) %u %u\n", position
, position
+ length
, explicitLevel
, resolvedLevel
);
4532 LIST_FOR_EACH_ENTRY(cur_run
, &layout
->runs
, struct layout_run
, entry
) {
4533 struct regular_layout_run
*cur
= &cur_run
->u
.regular
;
4534 struct layout_run
*run
;
4536 if (cur_run
->kind
== LAYOUT_RUN_INLINE
)
4539 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4540 if (position
< cur
->descr
.textPosition
|| position
>= cur
->descr
.textPosition
+ cur
->descr
.stringLength
)
4543 /* full hit - just set run level */
4544 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
== length
) {
4545 cur
->run
.bidiLevel
= resolvedLevel
;
4549 /* current run is fully covered, move to next one */
4550 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
< length
) {
4551 cur
->run
.bidiLevel
= resolvedLevel
;
4552 position
+= cur
->descr
.stringLength
;
4553 length
-= cur
->descr
.stringLength
;
4557 /* all fully covered runs are processed at this point, reuse existing run for remaining
4558 reported bidi range and add another run for the rest of original one */
4560 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
);
4562 return E_OUTOFMEMORY
;
4565 run
->u
.regular
.descr
.textPosition
= position
+ length
;
4566 run
->u
.regular
.descr
.stringLength
= cur
->descr
.stringLength
- length
;
4567 run
->u
.regular
.descr
.string
= &layout
->str
[position
+ length
];
4569 /* reduce existing run */
4570 cur
->run
.bidiLevel
= resolvedLevel
;
4571 cur
->descr
.stringLength
= length
;
4573 list_add_after(&cur_run
->entry
, &run
->entry
);
4580 static HRESULT WINAPI
dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1
*iface
,
4581 UINT32 position
, UINT32 length
, IDWriteNumberSubstitution
* substitution
)
4586 static HRESULT WINAPI
dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1
*iface
,
4587 UINT32 position
, UINT32 length
, DWRITE_GLYPH_ORIENTATION_ANGLE angle
, UINT8 adjusted_bidi_level
,
4588 BOOL is_sideways
, BOOL is_rtl
)
4593 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl
= {
4594 dwritetextlayout_sink_QueryInterface
,
4595 dwritetextlayout_sink_AddRef
,
4596 dwritetextlayout_sink_Release
,
4597 dwritetextlayout_sink_SetScriptAnalysis
,
4598 dwritetextlayout_sink_SetLineBreakpoints
,
4599 dwritetextlayout_sink_SetBidiLevel
,
4600 dwritetextlayout_sink_SetNumberSubstitution
,
4601 dwritetextlayout_sink_SetGlyphOrientation
4604 static HRESULT WINAPI
dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1
*iface
,
4605 REFIID riid
, void **obj
)
4607 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource1
) ||
4608 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource
) ||
4609 IsEqualIID(riid
, &IID_IUnknown
))
4612 IDWriteTextAnalysisSource1_AddRef(iface
);
4617 return E_NOINTERFACE
;
4620 static ULONG WINAPI
dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1
*iface
)
4622 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4623 return IDWriteTextLayout3_AddRef(&layout
->IDWriteTextLayout3_iface
);
4626 static ULONG WINAPI
dwritetextlayout_source_Release(IDWriteTextAnalysisSource1
*iface
)
4628 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4629 return IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
4632 static HRESULT WINAPI
dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1
*iface
,
4633 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
4635 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4637 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
4639 if (position
< layout
->len
) {
4640 *text
= &layout
->str
[position
];
4641 *text_len
= layout
->len
- position
;
4651 static HRESULT WINAPI
dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1
*iface
,
4652 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
4654 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4656 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
4658 if (position
> 0 && position
< layout
->len
) {
4659 *text
= layout
->str
;
4660 *text_len
= position
;
4670 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1
*iface
)
4672 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4673 return IDWriteTextLayout3_GetReadingDirection(&layout
->IDWriteTextLayout3_iface
);
4676 static HRESULT WINAPI
dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1
*iface
,
4677 UINT32 position
, UINT32
* text_len
, WCHAR
const** locale
)
4679 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4680 struct layout_range
*range
= get_layout_range_by_pos(layout
, position
);
4682 if (position
< layout
->len
) {
4683 struct layout_range
*next
;
4685 *locale
= range
->locale
;
4686 *text_len
= range
->h
.range
.length
- position
;
4688 next
= LIST_ENTRY(list_next(&layout
->ranges
, &range
->h
.entry
), struct layout_range
, h
.entry
);
4689 while (next
&& next
->h
.range
.startPosition
< layout
->len
&& !strcmpW(range
->locale
, next
->locale
)) {
4690 *text_len
+= next
->h
.range
.length
;
4691 next
= LIST_ENTRY(list_next(&layout
->ranges
, &next
->h
.entry
), struct layout_range
, h
.entry
);
4694 *text_len
= min(*text_len
, layout
->len
- position
);
4704 static HRESULT WINAPI
dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1
*iface
,
4705 UINT32 position
, UINT32
* text_len
, IDWriteNumberSubstitution
**substitution
)
4707 FIXME("%u %p %p: stub\n", position
, text_len
, substitution
);
4711 static HRESULT WINAPI
dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1
*iface
,
4712 UINT32 position
, UINT32
*length
, DWRITE_VERTICAL_GLYPH_ORIENTATION
*orientation
, UINT8
*bidi_level
)
4714 FIXME("%u %p %p %p: stub\n", position
, length
, orientation
, bidi_level
);
4718 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl
= {
4719 dwritetextlayout_source_QueryInterface
,
4720 dwritetextlayout_source_AddRef
,
4721 dwritetextlayout_source_Release
,
4722 dwritetextlayout_source_GetTextAtPosition
,
4723 dwritetextlayout_source_GetTextBeforePosition
,
4724 dwritetextlayout_source_GetParagraphReadingDirection
,
4725 dwritetextlayout_source_GetLocaleName
,
4726 dwritetextlayout_source_GetNumberSubstitution
,
4727 dwritetextlayout_source_GetVerticalGlyphOrientation
4730 static HRESULT
layout_format_from_textformat(struct dwrite_textlayout
*layout
, IDWriteTextFormat
*format
)
4732 struct dwrite_textformat
*textformat
;
4733 IDWriteTextFormat1
*format1
;
4737 if ((textformat
= unsafe_impl_from_IDWriteTextFormat(format
))) {
4738 layout
->format
= textformat
->format
;
4740 layout
->format
.locale
= heap_strdupW(textformat
->format
.locale
);
4741 layout
->format
.family_name
= heap_strdupW(textformat
->format
.family_name
);
4742 if (!layout
->format
.locale
|| !layout
->format
.family_name
)
4744 heap_free(layout
->format
.locale
);
4745 heap_free(layout
->format
.family_name
);
4746 return E_OUTOFMEMORY
;
4749 if (layout
->format
.trimmingsign
)
4750 IDWriteInlineObject_AddRef(layout
->format
.trimmingsign
);
4751 if (layout
->format
.collection
)
4752 IDWriteFontCollection_AddRef(layout
->format
.collection
);
4753 if (layout
->format
.fallback
)
4754 IDWriteFontFallback_AddRef(layout
->format
.fallback
);
4759 layout
->format
.weight
= IDWriteTextFormat_GetFontWeight(format
);
4760 layout
->format
.style
= IDWriteTextFormat_GetFontStyle(format
);
4761 layout
->format
.stretch
= IDWriteTextFormat_GetFontStretch(format
);
4762 layout
->format
.fontsize
= IDWriteTextFormat_GetFontSize(format
);
4763 layout
->format
.textalignment
= IDWriteTextFormat_GetTextAlignment(format
);
4764 layout
->format
.paralign
= IDWriteTextFormat_GetParagraphAlignment(format
);
4765 layout
->format
.wrapping
= IDWriteTextFormat_GetWordWrapping(format
);
4766 layout
->format
.readingdir
= IDWriteTextFormat_GetReadingDirection(format
);
4767 layout
->format
.flow
= IDWriteTextFormat_GetFlowDirection(format
);
4768 layout
->format
.fallback
= NULL
;
4769 layout
->format
.spacing
.leadingBefore
= 0.0f
;
4770 layout
->format
.spacing
.fontLineGapUsage
= DWRITE_FONT_LINE_GAP_USAGE_DEFAULT
;
4771 hr
= IDWriteTextFormat_GetLineSpacing(format
, &layout
->format
.spacing
.method
,
4772 &layout
->format
.spacing
.height
, &layout
->format
.spacing
.baseline
);
4776 hr
= IDWriteTextFormat_GetTrimming(format
, &layout
->format
.trimming
, &layout
->format
.trimmingsign
);
4780 /* locale name and length */
4781 len
= IDWriteTextFormat_GetLocaleNameLength(format
);
4782 layout
->format
.locale
= heap_alloc((len
+1)*sizeof(WCHAR
));
4783 if (!layout
->format
.locale
)
4784 return E_OUTOFMEMORY
;
4786 hr
= IDWriteTextFormat_GetLocaleName(format
, layout
->format
.locale
, len
+1);
4789 layout
->format
.locale_len
= len
;
4791 /* font family name and length */
4792 len
= IDWriteTextFormat_GetFontFamilyNameLength(format
);
4793 layout
->format
.family_name
= heap_alloc((len
+1)*sizeof(WCHAR
));
4794 if (!layout
->format
.family_name
)
4795 return E_OUTOFMEMORY
;
4797 hr
= IDWriteTextFormat_GetFontFamilyName(format
, layout
->format
.family_name
, len
+1);
4800 layout
->format
.family_len
= len
;
4802 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat1
, (void**)&format1
);
4804 IDWriteTextFormat2
*format2
;
4806 layout
->format
.vertical_orientation
= IDWriteTextFormat1_GetVerticalGlyphOrientation(format1
);
4807 layout
->format
.optical_alignment
= IDWriteTextFormat1_GetOpticalAlignment(format1
);
4808 IDWriteTextFormat1_GetFontFallback(format1
, &layout
->format
.fallback
);
4810 if (IDWriteTextFormat1_QueryInterface(format1
, &IID_IDWriteTextFormat2
, (void**)&format2
) == S_OK
) {
4811 IDWriteTextFormat2_GetLineSpacing(format2
, &layout
->format
.spacing
);
4812 IDWriteTextFormat2_Release(format2
);
4815 IDWriteTextFormat1_Release(format1
);
4818 layout
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
4819 layout
->format
.optical_alignment
= DWRITE_OPTICAL_ALIGNMENT_NONE
;
4822 return IDWriteTextFormat_GetFontCollection(format
, &layout
->format
.collection
);
4825 static HRESULT
init_textlayout(const struct textlayout_desc
*desc
, struct dwrite_textlayout
*layout
)
4827 struct layout_range_header
*range
, *strike
, *underline
, *effect
, *spacing
, *typography
;
4828 static const DWRITE_TEXT_RANGE r
= { 0, ~0u };
4831 layout
->IDWriteTextLayout3_iface
.lpVtbl
= &dwritetextlayoutvtbl
;
4832 layout
->IDWriteTextFormat1_iface
.lpVtbl
= &dwritetextformat1_layout_vtbl
;
4833 layout
->IDWriteTextAnalysisSink1_iface
.lpVtbl
= &dwritetextlayoutsinkvtbl
;
4834 layout
->IDWriteTextAnalysisSource1_iface
.lpVtbl
= &dwritetextlayoutsourcevtbl
;
4836 layout
->len
= desc
->length
;
4837 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4838 layout
->nominal_breakpoints
= NULL
;
4839 layout
->actual_breakpoints
= NULL
;
4840 layout
->cluster_count
= 0;
4841 layout
->clustermetrics
= NULL
;
4842 layout
->clusters
= NULL
;
4843 layout
->linemetrics
= NULL
;
4844 layout
->lines
= NULL
;
4845 layout
->line_alloc
= 0;
4846 layout
->minwidth
= 0.0f
;
4847 list_init(&layout
->eruns
);
4848 list_init(&layout
->inlineobjects
);
4849 list_init(&layout
->underlines
);
4850 list_init(&layout
->strikethrough
);
4851 list_init(&layout
->runs
);
4852 list_init(&layout
->ranges
);
4853 list_init(&layout
->strike_ranges
);
4854 list_init(&layout
->underline_ranges
);
4855 list_init(&layout
->effects
);
4856 list_init(&layout
->spacing
);
4857 list_init(&layout
->typographies
);
4858 memset(&layout
->format
, 0, sizeof(layout
->format
));
4859 memset(&layout
->metrics
, 0, sizeof(layout
->metrics
));
4860 layout
->metrics
.layoutWidth
= desc
->max_width
;
4861 layout
->metrics
.layoutHeight
= desc
->max_height
;
4862 layout
->measuringmode
= DWRITE_MEASURING_MODE_NATURAL
;
4864 layout
->ppdip
= 0.0f
;
4865 memset(&layout
->transform
, 0, sizeof(layout
->transform
));
4867 layout
->str
= heap_strdupnW(desc
->string
, desc
->length
);
4868 if (desc
->length
&& !layout
->str
) {
4873 hr
= layout_format_from_textformat(layout
, desc
->format
);
4877 range
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_REGULAR
);
4878 strike
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_STRIKETHROUGH
);
4879 underline
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_UNDERLINE
);
4880 effect
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_EFFECT
);
4881 spacing
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_SPACING
);
4882 typography
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_TYPOGRAPHY
);
4883 if (!range
|| !strike
|| !effect
|| !spacing
|| !typography
|| !underline
) {
4884 free_layout_range(range
);
4885 free_layout_range(strike
);
4886 free_layout_range(underline
);
4887 free_layout_range(effect
);
4888 free_layout_range(spacing
);
4889 free_layout_range(typography
);
4894 if (desc
->is_gdi_compatible
)
4895 layout
->measuringmode
= desc
->use_gdi_natural
? DWRITE_MEASURING_MODE_GDI_NATURAL
: DWRITE_MEASURING_MODE_GDI_CLASSIC
;
4897 layout
->measuringmode
= DWRITE_MEASURING_MODE_NATURAL
;
4898 layout
->ppdip
= desc
->ppdip
;
4899 layout
->transform
= desc
->transform
? *desc
->transform
: identity
;
4901 layout
->factory
= desc
->factory
;
4902 IDWriteFactory4_AddRef(layout
->factory
);
4903 list_add_head(&layout
->ranges
, &range
->entry
);
4904 list_add_head(&layout
->strike_ranges
, &strike
->entry
);
4905 list_add_head(&layout
->underline_ranges
, &underline
->entry
);
4906 list_add_head(&layout
->effects
, &effect
->entry
);
4907 list_add_head(&layout
->spacing
, &spacing
->entry
);
4908 list_add_head(&layout
->typographies
, &typography
->entry
);
4912 IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
4916 HRESULT
create_textlayout(const struct textlayout_desc
*desc
, IDWriteTextLayout
**ret
)
4918 struct dwrite_textlayout
*layout
;
4923 if (!desc
->format
|| !desc
->string
)
4924 return E_INVALIDARG
;
4926 layout
= heap_alloc(sizeof(struct dwrite_textlayout
));
4927 if (!layout
) return E_OUTOFMEMORY
;
4929 hr
= init_textlayout(desc
, layout
);
4931 *ret
= (IDWriteTextLayout
*)&layout
->IDWriteTextLayout3_iface
;
4936 static HRESULT WINAPI
dwritetrimmingsign_QueryInterface(IDWriteInlineObject
*iface
, REFIID riid
, void **obj
)
4938 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4940 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
4942 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteInlineObject
)) {
4944 IDWriteInlineObject_AddRef(iface
);
4949 return E_NOINTERFACE
;
4952 static ULONG WINAPI
dwritetrimmingsign_AddRef(IDWriteInlineObject
*iface
)
4954 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4955 ULONG ref
= InterlockedIncrement(&This
->ref
);
4956 TRACE("(%p)->(%d)\n", This
, ref
);
4960 static ULONG WINAPI
dwritetrimmingsign_Release(IDWriteInlineObject
*iface
)
4962 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4963 ULONG ref
= InterlockedDecrement(&This
->ref
);
4965 TRACE("(%p)->(%d)\n", This
, ref
);
4968 IDWriteTextLayout_Release(This
->layout
);
4975 static HRESULT WINAPI
dwritetrimmingsign_Draw(IDWriteInlineObject
*iface
, void *context
, IDWriteTextRenderer
*renderer
,
4976 FLOAT originX
, FLOAT originY
, BOOL is_sideways
, BOOL is_rtl
, IUnknown
*effect
)
4978 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4979 DWRITE_TEXT_RANGE range
= { 0, ~0u };
4980 DWRITE_TEXT_METRICS metrics
;
4981 DWRITE_LINE_METRICS line
;
4985 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This
, context
, renderer
, originX
, originY
, is_sideways
, is_rtl
, effect
);
4987 IDWriteTextLayout_SetDrawingEffect(This
->layout
, effect
, range
);
4988 IDWriteTextLayout_GetLineMetrics(This
->layout
, &line
, 1, &line_count
);
4989 IDWriteTextLayout_GetMetrics(This
->layout
, &metrics
);
4990 hr
= IDWriteTextLayout_Draw(This
->layout
, context
, renderer
, originX
, originY
- line
.baseline
);
4991 IDWriteTextLayout_SetDrawingEffect(This
->layout
, NULL
, range
);
4995 static HRESULT WINAPI
dwritetrimmingsign_GetMetrics(IDWriteInlineObject
*iface
, DWRITE_INLINE_OBJECT_METRICS
*ret
)
4997 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
4998 DWRITE_TEXT_METRICS metrics
;
5001 TRACE("(%p)->(%p)\n", This
, ret
);
5003 hr
= IDWriteTextLayout_GetMetrics(This
->layout
, &metrics
);
5005 memset(ret
, 0, sizeof(*ret
));
5009 ret
->width
= metrics
.width
;
5011 ret
->baseline
= 0.0f
;
5012 ret
->supportsSideways
= FALSE
;
5016 static HRESULT WINAPI
dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
5018 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5019 TRACE("(%p)->(%p)\n", This
, overhangs
);
5020 return IDWriteTextLayout_GetOverhangMetrics(This
->layout
, overhangs
);
5023 static HRESULT WINAPI
dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject
*iface
, DWRITE_BREAK_CONDITION
*before
,
5024 DWRITE_BREAK_CONDITION
*after
)
5026 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5028 TRACE("(%p)->(%p %p)\n", This
, before
, after
);
5030 *before
= *after
= DWRITE_BREAK_CONDITION_NEUTRAL
;
5034 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl
= {
5035 dwritetrimmingsign_QueryInterface
,
5036 dwritetrimmingsign_AddRef
,
5037 dwritetrimmingsign_Release
,
5038 dwritetrimmingsign_Draw
,
5039 dwritetrimmingsign_GetMetrics
,
5040 dwritetrimmingsign_GetOverhangMetrics
,
5041 dwritetrimmingsign_GetBreakConditions
5044 static inline BOOL
is_reading_direction_horz(DWRITE_READING_DIRECTION direction
)
5046 return (direction
== DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
) ||
5047 (direction
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
);
5050 static inline BOOL
is_reading_direction_vert(DWRITE_READING_DIRECTION direction
)
5052 return (direction
== DWRITE_READING_DIRECTION_TOP_TO_BOTTOM
) ||
5053 (direction
== DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
);
5056 static inline BOOL
is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction
)
5058 return (direction
== DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
) ||
5059 (direction
== DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
);
5062 static inline BOOL
is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction
)
5064 return (direction
== DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
) ||
5065 (direction
== DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP
);
5068 HRESULT
create_trimmingsign(IDWriteFactory4
*factory
, IDWriteTextFormat
*format
, IDWriteInlineObject
**sign
)
5070 static const WCHAR ellipsisW
= 0x2026;
5071 struct dwrite_trimmingsign
*This
;
5072 DWRITE_READING_DIRECTION reading
;
5073 DWRITE_FLOW_DIRECTION flow
;
5078 /* Validate reading/flow direction here, layout creation won't complain about
5079 invalid combinations. */
5080 reading
= IDWriteTextFormat_GetReadingDirection(format
);
5081 flow
= IDWriteTextFormat_GetFlowDirection(format
);
5083 if ((is_reading_direction_horz(reading
) && is_flow_direction_horz(flow
)) ||
5084 (is_reading_direction_vert(reading
) && is_flow_direction_vert(flow
)))
5085 return DWRITE_E_FLOWDIRECTIONCONFLICTS
;
5087 This
= heap_alloc(sizeof(*This
));
5089 return E_OUTOFMEMORY
;
5091 This
->IDWriteInlineObject_iface
.lpVtbl
= &dwritetrimmingsignvtbl
;
5094 hr
= IDWriteFactory4_CreateTextLayout(factory
, &ellipsisW
, 1, format
, 0.0f
, 0.0f
, &This
->layout
);
5100 IDWriteTextLayout_SetWordWrapping(This
->layout
, DWRITE_WORD_WRAPPING_NO_WRAP
);
5101 IDWriteTextLayout_SetParagraphAlignment(This
->layout
, DWRITE_PARAGRAPH_ALIGNMENT_NEAR
);
5102 *sign
= &This
->IDWriteInlineObject_iface
;
5107 static HRESULT WINAPI
dwritetextformat_QueryInterface(IDWriteTextFormat2
*iface
, REFIID riid
, void **obj
)
5109 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5111 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
5113 if (IsEqualIID(riid
, &IID_IDWriteTextFormat2
) ||
5114 IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
5115 IsEqualIID(riid
, &IID_IDWriteTextFormat
) ||
5116 IsEqualIID(riid
, &IID_IUnknown
))
5119 IDWriteTextFormat2_AddRef(iface
);
5125 return E_NOINTERFACE
;
5128 static ULONG WINAPI
dwritetextformat_AddRef(IDWriteTextFormat2
*iface
)
5130 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5131 ULONG ref
= InterlockedIncrement(&This
->ref
);
5132 TRACE("(%p)->(%d)\n", This
, ref
);
5136 static ULONG WINAPI
dwritetextformat_Release(IDWriteTextFormat2
*iface
)
5138 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5139 ULONG ref
= InterlockedDecrement(&This
->ref
);
5141 TRACE("(%p)->(%d)\n", This
, ref
);
5145 release_format_data(&This
->format
);
5152 static HRESULT WINAPI
dwritetextformat_SetTextAlignment(IDWriteTextFormat2
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
5154 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5155 TRACE("(%p)->(%d)\n", This
, alignment
);
5156 return format_set_textalignment(&This
->format
, alignment
, NULL
);
5159 static HRESULT WINAPI
dwritetextformat_SetParagraphAlignment(IDWriteTextFormat2
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
5161 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5162 TRACE("(%p)->(%d)\n", This
, alignment
);
5163 return format_set_paralignment(&This
->format
, alignment
, NULL
);
5166 static HRESULT WINAPI
dwritetextformat_SetWordWrapping(IDWriteTextFormat2
*iface
, DWRITE_WORD_WRAPPING wrapping
)
5168 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5169 TRACE("(%p)->(%d)\n", This
, wrapping
);
5170 return format_set_wordwrapping(&This
->format
, wrapping
, NULL
);
5173 static HRESULT WINAPI
dwritetextformat_SetReadingDirection(IDWriteTextFormat2
*iface
, DWRITE_READING_DIRECTION direction
)
5175 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5176 TRACE("(%p)->(%d)\n", This
, direction
);
5177 return format_set_readingdirection(&This
->format
, direction
, NULL
);
5180 static HRESULT WINAPI
dwritetextformat_SetFlowDirection(IDWriteTextFormat2
*iface
, DWRITE_FLOW_DIRECTION direction
)
5182 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5183 TRACE("(%p)->(%d)\n", This
, direction
);
5184 return format_set_flowdirection(&This
->format
, direction
, NULL
);
5187 static HRESULT WINAPI
dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat2
*iface
, FLOAT tabstop
)
5189 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5190 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
5194 static HRESULT WINAPI
dwritetextformat_SetTrimming(IDWriteTextFormat2
*iface
, DWRITE_TRIMMING
const *trimming
,
5195 IDWriteInlineObject
*trimming_sign
)
5197 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5198 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
5199 return format_set_trimming(&This
->format
, trimming
, trimming_sign
, NULL
);
5202 static HRESULT WINAPI
dwritetextformat_SetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING_METHOD method
,
5203 FLOAT height
, FLOAT baseline
)
5205 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5206 DWRITE_LINE_SPACING spacing
;
5208 TRACE("(%p)->(%d %f %f)\n", This
, method
, height
, baseline
);
5210 spacing
= This
->format
.spacing
;
5211 spacing
.method
= method
;
5212 spacing
.height
= height
;
5213 spacing
.baseline
= baseline
;
5215 return format_set_linespacing(&This
->format
, &spacing
, NULL
);
5218 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_GetTextAlignment(IDWriteTextFormat2
*iface
)
5220 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5221 TRACE("(%p)\n", This
);
5222 return This
->format
.textalignment
;
5225 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_GetParagraphAlignment(IDWriteTextFormat2
*iface
)
5227 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5228 TRACE("(%p)\n", This
);
5229 return This
->format
.paralign
;
5232 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_GetWordWrapping(IDWriteTextFormat2
*iface
)
5234 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5235 TRACE("(%p)\n", This
);
5236 return This
->format
.wrapping
;
5239 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_GetReadingDirection(IDWriteTextFormat2
*iface
)
5241 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5242 TRACE("(%p)\n", This
);
5243 return This
->format
.readingdir
;
5246 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_GetFlowDirection(IDWriteTextFormat2
*iface
)
5248 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5249 TRACE("(%p)\n", This
);
5250 return This
->format
.flow
;
5253 static FLOAT WINAPI
dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat2
*iface
)
5255 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5256 FIXME("(%p): stub\n", This
);
5260 static HRESULT WINAPI
dwritetextformat_GetTrimming(IDWriteTextFormat2
*iface
, DWRITE_TRIMMING
*options
,
5261 IDWriteInlineObject
**trimming_sign
)
5263 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5264 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
5266 *options
= This
->format
.trimming
;
5267 if ((*trimming_sign
= This
->format
.trimmingsign
))
5268 IDWriteInlineObject_AddRef(*trimming_sign
);
5273 static HRESULT WINAPI
dwritetextformat_GetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
5274 FLOAT
*spacing
, FLOAT
*baseline
)
5276 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5277 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
5279 *method
= This
->format
.spacing
.method
;
5280 *spacing
= This
->format
.spacing
.height
;
5281 *baseline
= This
->format
.spacing
.baseline
;
5285 static HRESULT WINAPI
dwritetextformat_GetFontCollection(IDWriteTextFormat2
*iface
, IDWriteFontCollection
**collection
)
5287 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5289 TRACE("(%p)->(%p)\n", This
, collection
);
5291 *collection
= This
->format
.collection
;
5292 IDWriteFontCollection_AddRef(*collection
);
5297 static UINT32 WINAPI
dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat2
*iface
)
5299 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5300 TRACE("(%p)\n", This
);
5301 return This
->format
.family_len
;
5304 static HRESULT WINAPI
dwritetextformat_GetFontFamilyName(IDWriteTextFormat2
*iface
, WCHAR
*name
, UINT32 size
)
5306 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5308 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
5310 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
5311 strcpyW(name
, This
->format
.family_name
);
5315 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_GetFontWeight(IDWriteTextFormat2
*iface
)
5317 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5318 TRACE("(%p)\n", This
);
5319 return This
->format
.weight
;
5322 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_GetFontStyle(IDWriteTextFormat2
*iface
)
5324 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5325 TRACE("(%p)\n", This
);
5326 return This
->format
.style
;
5329 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_GetFontStretch(IDWriteTextFormat2
*iface
)
5331 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5332 TRACE("(%p)\n", This
);
5333 return This
->format
.stretch
;
5336 static FLOAT WINAPI
dwritetextformat_GetFontSize(IDWriteTextFormat2
*iface
)
5338 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5339 TRACE("(%p)\n", This
);
5340 return This
->format
.fontsize
;
5343 static UINT32 WINAPI
dwritetextformat_GetLocaleNameLength(IDWriteTextFormat2
*iface
)
5345 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5346 TRACE("(%p)\n", This
);
5347 return This
->format
.locale_len
;
5350 static HRESULT WINAPI
dwritetextformat_GetLocaleName(IDWriteTextFormat2
*iface
, WCHAR
*name
, UINT32 size
)
5352 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5354 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
5356 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
5357 strcpyW(name
, This
->format
.locale
);
5361 static HRESULT WINAPI
dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat2
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
5363 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5365 TRACE("(%p)->(%d)\n", This
, orientation
);
5367 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
5368 return E_INVALIDARG
;
5370 This
->format
.vertical_orientation
= orientation
;
5374 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat2
*iface
)
5376 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5377 TRACE("(%p)\n", This
);
5378 return This
->format
.vertical_orientation
;
5381 static HRESULT WINAPI
dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat2
*iface
, BOOL lastline_wrapping_enabled
)
5383 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5385 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
5387 This
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
5391 static BOOL WINAPI
dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat2
*iface
)
5393 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5394 TRACE("(%p)\n", This
);
5395 return This
->format
.last_line_wrapping
;
5398 static HRESULT WINAPI
dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat2
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
5400 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5401 TRACE("(%p)->(%d)\n", This
, alignment
);
5402 return format_set_optical_alignment(&This
->format
, alignment
);
5405 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat2
*iface
)
5407 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5408 TRACE("(%p)\n", This
);
5409 return This
->format
.optical_alignment
;
5412 static HRESULT WINAPI
dwritetextformat1_SetFontFallback(IDWriteTextFormat2
*iface
, IDWriteFontFallback
*fallback
)
5414 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5415 TRACE("(%p)->(%p)\n", This
, fallback
);
5416 return set_fontfallback_for_format(&This
->format
, fallback
);
5419 static HRESULT WINAPI
dwritetextformat1_GetFontFallback(IDWriteTextFormat2
*iface
, IDWriteFontFallback
**fallback
)
5421 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5422 TRACE("(%p)->(%p)\n", This
, fallback
);
5423 return get_fontfallback_from_format(&This
->format
, fallback
);
5426 static HRESULT WINAPI
dwritetextformat2_SetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING
const *spacing
)
5428 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5429 TRACE("(%p)->(%p)\n", This
, spacing
);
5430 return format_set_linespacing(&This
->format
, spacing
, NULL
);
5433 static HRESULT WINAPI
dwritetextformat2_GetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING
*spacing
)
5435 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5437 TRACE("(%p)->(%p)\n", This
, spacing
);
5439 *spacing
= This
->format
.spacing
;
5443 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl
= {
5444 dwritetextformat_QueryInterface
,
5445 dwritetextformat_AddRef
,
5446 dwritetextformat_Release
,
5447 dwritetextformat_SetTextAlignment
,
5448 dwritetextformat_SetParagraphAlignment
,
5449 dwritetextformat_SetWordWrapping
,
5450 dwritetextformat_SetReadingDirection
,
5451 dwritetextformat_SetFlowDirection
,
5452 dwritetextformat_SetIncrementalTabStop
,
5453 dwritetextformat_SetTrimming
,
5454 dwritetextformat_SetLineSpacing
,
5455 dwritetextformat_GetTextAlignment
,
5456 dwritetextformat_GetParagraphAlignment
,
5457 dwritetextformat_GetWordWrapping
,
5458 dwritetextformat_GetReadingDirection
,
5459 dwritetextformat_GetFlowDirection
,
5460 dwritetextformat_GetIncrementalTabStop
,
5461 dwritetextformat_GetTrimming
,
5462 dwritetextformat_GetLineSpacing
,
5463 dwritetextformat_GetFontCollection
,
5464 dwritetextformat_GetFontFamilyNameLength
,
5465 dwritetextformat_GetFontFamilyName
,
5466 dwritetextformat_GetFontWeight
,
5467 dwritetextformat_GetFontStyle
,
5468 dwritetextformat_GetFontStretch
,
5469 dwritetextformat_GetFontSize
,
5470 dwritetextformat_GetLocaleNameLength
,
5471 dwritetextformat_GetLocaleName
,
5472 dwritetextformat1_SetVerticalGlyphOrientation
,
5473 dwritetextformat1_GetVerticalGlyphOrientation
,
5474 dwritetextformat1_SetLastLineWrapping
,
5475 dwritetextformat1_GetLastLineWrapping
,
5476 dwritetextformat1_SetOpticalAlignment
,
5477 dwritetextformat1_GetOpticalAlignment
,
5478 dwritetextformat1_SetFontFallback
,
5479 dwritetextformat1_GetFontFallback
,
5480 dwritetextformat2_SetLineSpacing
,
5481 dwritetextformat2_GetLineSpacing
5484 static struct dwrite_textformat
*unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat
*iface
)
5486 return (iface
->lpVtbl
== (IDWriteTextFormatVtbl
*)&dwritetextformatvtbl
) ?
5487 CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat2_iface
) : NULL
;
5490 HRESULT
create_textformat(const WCHAR
*family_name
, IDWriteFontCollection
*collection
, DWRITE_FONT_WEIGHT weight
, DWRITE_FONT_STYLE style
,
5491 DWRITE_FONT_STRETCH stretch
, FLOAT size
, const WCHAR
*locale
, IDWriteTextFormat
**format
)
5493 struct dwrite_textformat
*This
;
5498 return E_INVALIDARG
;
5500 if (((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
) ||
5501 ((UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
) ||
5502 ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
))
5503 return E_INVALIDARG
;
5505 This
= heap_alloc(sizeof(struct dwrite_textformat
));
5506 if (!This
) return E_OUTOFMEMORY
;
5508 This
->IDWriteTextFormat2_iface
.lpVtbl
= &dwritetextformatvtbl
;
5510 This
->format
.family_name
= heap_strdupW(family_name
);
5511 This
->format
.family_len
= strlenW(family_name
);
5512 This
->format
.locale
= heap_strdupW(locale
);
5513 This
->format
.locale_len
= strlenW(locale
);
5514 /* force locale name to lower case, layout will inherit this modified value */
5515 strlwrW(This
->format
.locale
);
5516 This
->format
.weight
= weight
;
5517 This
->format
.style
= style
;
5518 This
->format
.fontsize
= size
;
5519 This
->format
.stretch
= stretch
;
5520 This
->format
.textalignment
= DWRITE_TEXT_ALIGNMENT_LEADING
;
5521 This
->format
.optical_alignment
= DWRITE_OPTICAL_ALIGNMENT_NONE
;
5522 This
->format
.paralign
= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
;
5523 This
->format
.wrapping
= DWRITE_WORD_WRAPPING_WRAP
;
5524 This
->format
.last_line_wrapping
= TRUE
;
5525 This
->format
.readingdir
= DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
5526 This
->format
.flow
= DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
;
5527 This
->format
.spacing
.method
= DWRITE_LINE_SPACING_METHOD_DEFAULT
;
5528 This
->format
.spacing
.height
= 0.0f
;
5529 This
->format
.spacing
.baseline
= 0.0f
;
5530 This
->format
.spacing
.leadingBefore
= 0.0f
;
5531 This
->format
.spacing
.fontLineGapUsage
= DWRITE_FONT_LINE_GAP_USAGE_DEFAULT
;
5532 This
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
5533 This
->format
.trimming
.granularity
= DWRITE_TRIMMING_GRANULARITY_NONE
;
5534 This
->format
.trimming
.delimiter
= 0;
5535 This
->format
.trimming
.delimiterCount
= 0;
5536 This
->format
.trimmingsign
= NULL
;
5537 This
->format
.collection
= collection
;
5538 This
->format
.fallback
= NULL
;
5539 IDWriteFontCollection_AddRef(collection
);
5541 *format
= (IDWriteTextFormat
*)&This
->IDWriteTextFormat2_iface
;
5546 static HRESULT WINAPI
dwritetypography_QueryInterface(IDWriteTypography
*iface
, REFIID riid
, void **obj
)
5548 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5550 TRACE("(%p)->(%s %p)\n", typography
, debugstr_guid(riid
), obj
);
5552 if (IsEqualIID(riid
, &IID_IDWriteTypography
) || IsEqualIID(riid
, &IID_IUnknown
)) {
5554 IDWriteTypography_AddRef(iface
);
5560 return E_NOINTERFACE
;
5563 static ULONG WINAPI
dwritetypography_AddRef(IDWriteTypography
*iface
)
5565 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5566 ULONG ref
= InterlockedIncrement(&typography
->ref
);
5567 TRACE("(%p)->(%d)\n", typography
, ref
);
5571 static ULONG WINAPI
dwritetypography_Release(IDWriteTypography
*iface
)
5573 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5574 ULONG ref
= InterlockedDecrement(&typography
->ref
);
5576 TRACE("(%p)->(%d)\n", typography
, ref
);
5579 heap_free(typography
->features
);
5580 heap_free(typography
);
5586 static HRESULT WINAPI
dwritetypography_AddFontFeature(IDWriteTypography
*iface
, DWRITE_FONT_FEATURE feature
)
5588 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5590 TRACE("(%p)->(%x %u)\n", typography
, feature
.nameTag
, feature
.parameter
);
5592 if (typography
->count
== typography
->allocated
) {
5593 DWRITE_FONT_FEATURE
*ptr
= heap_realloc(typography
->features
, 2*typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
5595 return E_OUTOFMEMORY
;
5597 typography
->features
= ptr
;
5598 typography
->allocated
*= 2;
5601 typography
->features
[typography
->count
++] = feature
;
5605 static UINT32 WINAPI
dwritetypography_GetFontFeatureCount(IDWriteTypography
*iface
)
5607 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5608 TRACE("(%p)\n", typography
);
5609 return typography
->count
;
5612 static HRESULT WINAPI
dwritetypography_GetFontFeature(IDWriteTypography
*iface
, UINT32 index
, DWRITE_FONT_FEATURE
*feature
)
5614 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5616 TRACE("(%p)->(%u %p)\n", typography
, index
, feature
);
5618 if (index
>= typography
->count
)
5619 return E_INVALIDARG
;
5621 *feature
= typography
->features
[index
];
5625 static const IDWriteTypographyVtbl dwritetypographyvtbl
= {
5626 dwritetypography_QueryInterface
,
5627 dwritetypography_AddRef
,
5628 dwritetypography_Release
,
5629 dwritetypography_AddFontFeature
,
5630 dwritetypography_GetFontFeatureCount
,
5631 dwritetypography_GetFontFeature
5634 HRESULT
create_typography(IDWriteTypography
**ret
)
5636 struct dwrite_typography
*typography
;
5640 typography
= heap_alloc(sizeof(*typography
));
5642 return E_OUTOFMEMORY
;
5644 typography
->IDWriteTypography_iface
.lpVtbl
= &dwritetypographyvtbl
;
5645 typography
->ref
= 1;
5646 typography
->allocated
= 2;
5647 typography
->count
= 0;
5649 typography
->features
= heap_alloc(typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
5650 if (!typography
->features
) {
5651 heap_free(typography
);
5652 return E_OUTOFMEMORY
;
5655 *ret
= &typography
->IDWriteTypography_iface
;