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
30 #include "dwrite_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
35 struct dwrite_textformat_data
{
41 DWRITE_FONT_WEIGHT weight
;
42 DWRITE_FONT_STYLE style
;
43 DWRITE_FONT_STRETCH stretch
;
45 DWRITE_PARAGRAPH_ALIGNMENT paralign
;
46 DWRITE_READING_DIRECTION readingdir
;
47 DWRITE_WORD_WRAPPING wrapping
;
48 BOOL last_line_wrapping
;
49 DWRITE_TEXT_ALIGNMENT textalignment
;
50 DWRITE_FLOW_DIRECTION flow
;
51 DWRITE_VERTICAL_GLYPH_ORIENTATION vertical_orientation
;
52 DWRITE_OPTICAL_ALIGNMENT optical_alignment
;
53 DWRITE_LINE_SPACING spacing
;
57 DWRITE_TRIMMING trimming
;
58 IDWriteInlineObject
*trimmingsign
;
60 IDWriteFontCollection
*collection
;
61 IDWriteFontFallback
*fallback
;
64 enum layout_range_attr_kind
{
65 LAYOUT_RANGE_ATTR_WEIGHT
,
66 LAYOUT_RANGE_ATTR_STYLE
,
67 LAYOUT_RANGE_ATTR_STRETCH
,
68 LAYOUT_RANGE_ATTR_FONTSIZE
,
69 LAYOUT_RANGE_ATTR_EFFECT
,
70 LAYOUT_RANGE_ATTR_INLINE
,
71 LAYOUT_RANGE_ATTR_UNDERLINE
,
72 LAYOUT_RANGE_ATTR_STRIKETHROUGH
,
73 LAYOUT_RANGE_ATTR_PAIR_KERNING
,
74 LAYOUT_RANGE_ATTR_FONTCOLL
,
75 LAYOUT_RANGE_ATTR_LOCALE
,
76 LAYOUT_RANGE_ATTR_FONTFAMILY
,
77 LAYOUT_RANGE_ATTR_SPACING
,
78 LAYOUT_RANGE_ATTR_TYPOGRAPHY
81 struct layout_range_attr_value
{
82 DWRITE_TEXT_RANGE range
;
84 DWRITE_FONT_WEIGHT weight
;
85 DWRITE_FONT_STYLE style
;
86 DWRITE_FONT_STRETCH stretch
;
88 IDWriteInlineObject
*object
;
93 IDWriteFontCollection
*collection
;
95 const WCHAR
*fontfamily
;
101 IDWriteTypography
*typography
;
105 enum layout_range_kind
{
106 LAYOUT_RANGE_REGULAR
,
107 LAYOUT_RANGE_UNDERLINE
,
108 LAYOUT_RANGE_STRIKETHROUGH
,
110 LAYOUT_RANGE_SPACING
,
111 LAYOUT_RANGE_TYPOGRAPHY
114 struct layout_range_header
{
116 enum layout_range_kind kind
;
117 DWRITE_TEXT_RANGE range
;
120 struct layout_range
{
121 struct layout_range_header h
;
122 DWRITE_FONT_WEIGHT weight
;
123 DWRITE_FONT_STYLE style
;
125 DWRITE_FONT_STRETCH stretch
;
126 IDWriteInlineObject
*object
;
128 IDWriteFontCollection
*collection
;
129 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
133 struct layout_range_bool
{
134 struct layout_range_header h
;
138 struct layout_range_iface
{
139 struct layout_range_header h
;
143 struct layout_range_spacing
{
144 struct layout_range_header h
;
150 enum layout_run_kind
{
155 struct inline_object_run
{
156 IDWriteInlineObject
*object
;
160 struct regular_layout_run
{
161 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
162 DWRITE_GLYPH_RUN run
;
163 DWRITE_SCRIPT_ANALYSIS sa
;
167 DWRITE_GLYPH_OFFSET
*offsets
;
168 UINT32 glyphcount
; /* actual glyph count after shaping, not necessarily the same as reported to Draw() */
173 enum layout_run_kind kind
;
175 struct inline_object_run object
;
176 struct regular_layout_run regular
;
180 UINT32 start_position
; /* run text position in range [0, layout-text-length) */
183 struct layout_effective_run
{
185 const struct layout_run
*run
; /* nominal run this one is based on */
186 UINT32 start
; /* relative text position, 0 means first text position of a nominal run */
187 UINT32 length
; /* length in codepoints that this run covers */
188 UINT32 glyphcount
; /* total glyph count in this run */
189 IUnknown
*effect
; /* original reference is kept only at range level */
190 D2D1_POINT_2F origin
; /* baseline origin */
191 FLOAT align_dx
; /* adjustment from text alignment */
192 FLOAT width
; /* run width */
193 UINT16
*clustermap
; /* effective clustermap, allocated separately, is not reused from nominal map */
194 UINT32 line
; /* 0-based line index in line metrics array */
195 BOOL underlined
; /* set if this run is underlined */
196 D2D1_RECT_F bbox
; /* ink run box, top == bottom means it wasn't estimated yet */
199 struct layout_effective_inline
{
201 IDWriteInlineObject
*object
; /* inline object, set explicitly or added when trimming a line */
202 IUnknown
*effect
; /* original reference is kept only at range level */
204 D2D1_POINT_2F origin
; /* left top corner */
205 FLOAT align_dx
; /* adjustment from text alignment */
206 FLOAT width
; /* object width as it's reported it */
207 BOOL is_sideways
; /* vertical flow direction flag passed to Draw */
208 BOOL is_rtl
; /* bidi flag passed to Draw */
209 UINT32 line
; /* 0-based line index in line metrics array */
212 struct layout_underline
{
214 const struct layout_effective_run
*run
;
218 struct layout_strikethrough
{
220 const struct layout_effective_run
*run
;
221 DWRITE_STRIKETHROUGH s
;
224 struct layout_cluster
{
225 const struct layout_run
*run
; /* link to nominal run this cluster belongs to */
226 UINT32 position
; /* relative to run, first cluster has 0 position */
230 FLOAT height
; /* height based on content */
231 FLOAT baseline
; /* baseline based on content */
234 enum layout_recompute_mask
{
235 RECOMPUTE_CLUSTERS
= 1 << 0,
236 RECOMPUTE_MINIMAL_WIDTH
= 1 << 1,
237 RECOMPUTE_LINES
= 1 << 2,
238 RECOMPUTE_OVERHANGS
= 1 << 3,
239 RECOMPUTE_LINES_AND_OVERHANGS
= RECOMPUTE_LINES
| RECOMPUTE_OVERHANGS
,
240 RECOMPUTE_EVERYTHING
= 0xffff
243 struct dwrite_textlayout
{
244 IDWriteTextLayout3 IDWriteTextLayout3_iface
;
245 IDWriteTextFormat2 IDWriteTextFormat2_iface
;
246 IDWriteTextAnalysisSink1 IDWriteTextAnalysisSink1_iface
;
247 IDWriteTextAnalysisSource1 IDWriteTextAnalysisSource1_iface
;
250 IDWriteFactory5
*factory
;
254 struct dwrite_textformat_data format
;
255 struct list strike_ranges
;
256 struct list underline_ranges
;
257 struct list typographies
;
262 /* lists ready to use by Draw() */
264 struct list inlineobjects
;
265 struct list underlines
;
266 struct list strikethrough
;
269 DWRITE_LINE_BREAKPOINT
*nominal_breakpoints
;
270 DWRITE_LINE_BREAKPOINT
*actual_breakpoints
;
272 struct layout_cluster
*clusters
;
273 DWRITE_CLUSTER_METRICS
*clustermetrics
;
274 UINT32 cluster_count
;
277 struct layout_line
*lines
;
278 DWRITE_LINE_METRICS1
*linemetrics
;
281 DWRITE_TEXT_METRICS1 metrics
;
282 DWRITE_OVERHANG_METRICS overhangs
;
284 DWRITE_MEASURING_MODE measuringmode
;
286 /* gdi-compatible layout specifics */
288 DWRITE_MATRIX transform
;
291 struct dwrite_textformat
{
292 IDWriteTextFormat2 IDWriteTextFormat2_iface
;
294 struct dwrite_textformat_data format
;
297 struct dwrite_trimmingsign
{
298 IDWriteInlineObject IDWriteInlineObject_iface
;
301 IDWriteTextLayout
*layout
;
304 struct dwrite_typography
{
305 IDWriteTypography IDWriteTypography_iface
;
308 DWRITE_FONT_FEATURE
*features
;
313 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl
;
315 static void release_format_data(struct dwrite_textformat_data
*data
)
317 if (data
->collection
) IDWriteFontCollection_Release(data
->collection
);
318 if (data
->fallback
) IDWriteFontFallback_Release(data
->fallback
);
319 if (data
->trimmingsign
) IDWriteInlineObject_Release(data
->trimmingsign
);
320 heap_free(data
->family_name
);
321 heap_free(data
->locale
);
324 static inline struct dwrite_textlayout
*impl_from_IDWriteTextLayout3(IDWriteTextLayout3
*iface
)
326 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextLayout3_iface
);
329 static inline struct dwrite_textlayout
*impl_layout_from_IDWriteTextFormat2(IDWriteTextFormat2
*iface
)
331 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextFormat2_iface
);
334 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1
*iface
)
336 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSink1_iface
);
339 static inline struct dwrite_textlayout
*impl_from_IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1
*iface
)
341 return CONTAINING_RECORD(iface
, struct dwrite_textlayout
, IDWriteTextAnalysisSource1_iface
);
344 static inline struct dwrite_textformat
*impl_from_IDWriteTextFormat2(IDWriteTextFormat2
*iface
)
346 return CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat2_iface
);
349 static struct dwrite_textformat
*unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat
*);
351 static inline struct dwrite_trimmingsign
*impl_from_IDWriteInlineObject(IDWriteInlineObject
*iface
)
353 return CONTAINING_RECORD(iface
, struct dwrite_trimmingsign
, IDWriteInlineObject_iface
);
356 static inline struct dwrite_typography
*impl_from_IDWriteTypography(IDWriteTypography
*iface
)
358 return CONTAINING_RECORD(iface
, struct dwrite_typography
, IDWriteTypography_iface
);
361 static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION
*descr
)
363 return wine_dbg_sprintf("[%u,%u)", descr
->textPosition
, descr
->textPosition
+ descr
->stringLength
);
366 static inline BOOL
is_layout_gdi_compatible(struct dwrite_textlayout
*layout
)
368 return layout
->measuringmode
!= DWRITE_MEASURING_MODE_NATURAL
;
371 static inline HRESULT
format_set_textalignment(struct dwrite_textformat_data
*format
, DWRITE_TEXT_ALIGNMENT alignment
,
374 if ((UINT32
)alignment
> DWRITE_TEXT_ALIGNMENT_JUSTIFIED
)
376 if (changed
) *changed
= format
->textalignment
!= alignment
;
377 format
->textalignment
= alignment
;
381 static inline HRESULT
format_set_paralignment(struct dwrite_textformat_data
*format
,
382 DWRITE_PARAGRAPH_ALIGNMENT alignment
, BOOL
*changed
)
384 if ((UINT32
)alignment
> DWRITE_PARAGRAPH_ALIGNMENT_CENTER
)
386 if (changed
) *changed
= format
->paralign
!= alignment
;
387 format
->paralign
= alignment
;
391 static inline HRESULT
format_set_readingdirection(struct dwrite_textformat_data
*format
,
392 DWRITE_READING_DIRECTION direction
, BOOL
*changed
)
394 if ((UINT32
)direction
> DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
)
396 if (changed
) *changed
= format
->readingdir
!= direction
;
397 format
->readingdir
= direction
;
401 static inline HRESULT
format_set_wordwrapping(struct dwrite_textformat_data
*format
,
402 DWRITE_WORD_WRAPPING wrapping
, BOOL
*changed
)
404 if ((UINT32
)wrapping
> DWRITE_WORD_WRAPPING_CHARACTER
)
406 if (changed
) *changed
= format
->wrapping
!= wrapping
;
407 format
->wrapping
= wrapping
;
411 static inline HRESULT
format_set_flowdirection(struct dwrite_textformat_data
*format
,
412 DWRITE_FLOW_DIRECTION direction
, BOOL
*changed
)
414 if ((UINT32
)direction
> DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
)
416 if (changed
) *changed
= format
->flow
!= direction
;
417 format
->flow
= direction
;
421 static inline HRESULT
format_set_trimming(struct dwrite_textformat_data
*format
,
422 DWRITE_TRIMMING
const *trimming
, IDWriteInlineObject
*trimming_sign
, BOOL
*changed
)
427 if ((UINT32
)trimming
->granularity
> DWRITE_TRIMMING_GRANULARITY_WORD
)
431 *changed
= !!memcmp(&format
->trimming
, trimming
, sizeof(*trimming
));
432 if (format
->trimmingsign
!= trimming_sign
)
436 format
->trimming
= *trimming
;
437 if (format
->trimmingsign
)
438 IDWriteInlineObject_Release(format
->trimmingsign
);
439 format
->trimmingsign
= trimming_sign
;
440 if (format
->trimmingsign
)
441 IDWriteInlineObject_AddRef(format
->trimmingsign
);
445 static inline HRESULT
format_set_linespacing(struct dwrite_textformat_data
*format
,
446 DWRITE_LINE_SPACING
const *spacing
, BOOL
*changed
)
448 if (spacing
->height
< 0.0f
|| spacing
->leadingBefore
< 0.0f
|| spacing
->leadingBefore
> 1.0f
||
449 (UINT32
)spacing
->method
> DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
)
453 *changed
= memcmp(spacing
, &format
->spacing
, sizeof(*spacing
));
455 format
->spacing
= *spacing
;
459 static HRESULT
get_fontfallback_from_format(const struct dwrite_textformat_data
*format
, IDWriteFontFallback
**fallback
)
461 *fallback
= format
->fallback
;
463 IDWriteFontFallback_AddRef(*fallback
);
467 static HRESULT
set_fontfallback_for_format(struct dwrite_textformat_data
*format
, IDWriteFontFallback
*fallback
)
469 if (format
->fallback
)
470 IDWriteFontFallback_Release(format
->fallback
);
471 format
->fallback
= fallback
;
473 IDWriteFontFallback_AddRef(fallback
);
477 static HRESULT
format_set_optical_alignment(struct dwrite_textformat_data
*format
,
478 DWRITE_OPTICAL_ALIGNMENT alignment
)
480 if ((UINT32
)alignment
> DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS
)
482 format
->optical_alignment
= alignment
;
486 static BOOL
is_run_rtl(const struct layout_effective_run
*run
)
488 return run
->run
->u
.regular
.run
.bidiLevel
& 1;
491 static struct layout_run
*alloc_layout_run(enum layout_run_kind kind
, UINT32 start_position
)
493 struct layout_run
*ret
;
495 ret
= heap_alloc(sizeof(*ret
));
496 if (!ret
) return NULL
;
498 memset(ret
, 0, sizeof(*ret
));
500 if (kind
== LAYOUT_RUN_REGULAR
) {
501 ret
->u
.regular
.sa
.script
= Script_Unknown
;
502 ret
->u
.regular
.sa
.shapes
= DWRITE_SCRIPT_SHAPES_DEFAULT
;
504 ret
->start_position
= start_position
;
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 assert(r
->kind
== LAYOUT_RUN_REGULAR
);
702 for (i
= 0; i
< run
->descr
.stringLength
; i
++) {
703 BOOL end
= i
== run
->descr
.stringLength
- 1;
705 if (run
->descr
.clusterMap
[start
] != run
->descr
.clusterMap
[i
]) {
706 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->descr
.clusterMap
[i
], i
,
718 init_cluster_metrics(layout
, run
, run
->descr
.clusterMap
[start
], run
->glyphcount
, i
,
719 i
- start
+ 1, metrics
);
729 #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
731 static void layout_get_font_metrics(struct dwrite_textlayout
*layout
, IDWriteFontFace
*fontface
, FLOAT emsize
,
732 DWRITE_FONT_METRICS
*fontmetrics
)
734 if (is_layout_gdi_compatible(layout
)) {
735 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(fontface
, emsize
, layout
->ppdip
, &layout
->transform
, fontmetrics
);
737 WARN("failed to get compat metrics, 0x%08x\n", hr
);
740 IDWriteFontFace_GetMetrics(fontface
, fontmetrics
);
743 static void layout_get_font_height(FLOAT emsize
, DWRITE_FONT_METRICS
*fontmetrics
, FLOAT
*baseline
, FLOAT
*height
)
745 *baseline
= SCALE_FONT_METRIC(fontmetrics
->ascent
+ fontmetrics
->lineGap
, emsize
, fontmetrics
);
746 *height
= SCALE_FONT_METRIC(fontmetrics
->ascent
+ fontmetrics
->descent
+ fontmetrics
->lineGap
, emsize
, fontmetrics
);
749 static HRESULT
layout_itemize(struct dwrite_textlayout
*layout
)
751 IDWriteTextAnalyzer
*analyzer
;
752 struct layout_range
*range
;
753 struct layout_run
*r
;
756 analyzer
= get_text_analyzer();
758 LIST_FOR_EACH_ENTRY(range
, &layout
->ranges
, struct layout_range
, h
.entry
) {
759 /* We don't care about ranges that don't contain any text. */
760 if (range
->h
.range
.startPosition
>= layout
->len
)
763 /* Inline objects override actual text in range. */
765 hr
= layout_update_breakpoints_range(layout
, range
);
769 r
= alloc_layout_run(LAYOUT_RUN_INLINE
, range
->h
.range
.startPosition
);
771 return E_OUTOFMEMORY
;
773 r
->u
.object
.object
= range
->object
;
774 r
->u
.object
.length
= get_clipped_range_length(layout
, range
);
775 list_add_tail(&layout
->runs
, &r
->entry
);
779 /* Initial splitting by script. */
780 hr
= IDWriteTextAnalyzer_AnalyzeScript(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
781 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
),
782 (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
786 /* Splitting further by bidi levels. */
787 hr
= IDWriteTextAnalyzer_AnalyzeBidi(analyzer
, (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
788 range
->h
.range
.startPosition
, get_clipped_range_length(layout
, range
),
789 (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
);
797 static HRESULT
layout_resolve_fonts(struct dwrite_textlayout
*layout
)
799 IDWriteFontCollection
*sys_collection
;
800 IDWriteFontFallback
*fallback
= NULL
;
801 struct layout_range
*range
;
802 struct layout_run
*r
;
805 if (FAILED(hr
= IDWriteFactory5_GetSystemFontCollection(layout
->factory
, FALSE
,
806 (IDWriteFontCollection1
**)&sys_collection
, FALSE
))) {
807 WARN("Failed to get system collection, hr %#x.\n", hr
);
811 if (layout
->format
.fallback
) {
812 fallback
= layout
->format
.fallback
;
813 IDWriteFontFallback_AddRef(fallback
);
816 if (FAILED(hr
= IDWriteFactory5_GetSystemFontFallback(layout
->factory
, &fallback
))) {
817 WARN("Failed to get system fallback, hr %#x.\n", hr
);
822 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
823 struct regular_layout_run
*run
= &r
->u
.regular
;
827 if (r
->kind
== LAYOUT_RUN_INLINE
)
830 range
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
);
832 if (run
->sa
.shapes
== DWRITE_SCRIPT_SHAPES_NO_VISUAL
) {
833 IDWriteFontCollection
*collection
;
835 collection
= range
->collection
? range
->collection
: sys_collection
;
837 if (FAILED(hr
= create_matching_font(collection
, range
->fontfamily
, range
->weight
, range
->style
,
838 range
->stretch
, &font
))) {
839 WARN("%s: failed to create matching font for non visual run, family %s, collection %p\n",
840 debugstr_rundescr(&run
->descr
), debugstr_w(range
->fontfamily
), range
->collection
);
844 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
845 IDWriteFont_Release(font
);
847 WARN("Failed to create font face, hr %#x.\n", hr
);
851 run
->run
.fontEmSize
= range
->fontsize
;
855 length
= run
->descr
.stringLength
;
858 UINT32 mapped_length
;
863 hr
= IDWriteFontFallback_MapCharacters(fallback
,
864 (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
865 run
->descr
.textPosition
,
866 run
->descr
.stringLength
,
876 WARN("%s: failed to map family %s, collection %p, hr %#x.\n", debugstr_rundescr(&run
->descr
),
877 debugstr_w(range
->fontfamily
), range
->collection
, hr
);
881 hr
= IDWriteFont_CreateFontFace(font
, &run
->run
.fontFace
);
882 IDWriteFont_Release(font
);
884 WARN("Failed to create font face, hr %#x.\n", hr
);
888 run
->run
.fontEmSize
= range
->fontsize
* scale
;
890 if (mapped_length
< length
) {
891 struct regular_layout_run
*nextrun
;
892 struct layout_run
*nextr
;
894 /* keep mapped part for current run, add another run for the rest */
895 nextr
= alloc_layout_run(LAYOUT_RUN_REGULAR
, 0);
902 nextr
->start_position
= run
->descr
.textPosition
+ mapped_length
;
903 nextrun
= &nextr
->u
.regular
;
904 nextrun
->descr
.textPosition
= nextr
->start_position
;
905 nextrun
->descr
.stringLength
= run
->descr
.stringLength
- mapped_length
;
906 nextrun
->descr
.string
= &layout
->str
[nextrun
->descr
.textPosition
];
907 run
->descr
.stringLength
= mapped_length
;
908 list_add_after(&r
->entry
, &nextr
->entry
);
912 length
-= mapped_length
;
917 IDWriteFontCollection_Release(sys_collection
);
919 IDWriteFontFallback_Release(fallback
);
924 static HRESULT
layout_shape_run(struct dwrite_textlayout
*layout
, struct regular_layout_run
*run
)
926 DWRITE_SHAPING_GLYPH_PROPERTIES
*glyph_props
;
927 DWRITE_SHAPING_TEXT_PROPERTIES
*text_props
;
928 IDWriteTextAnalyzer
*analyzer
;
929 struct layout_range
*range
;
933 range
= get_layout_range_by_pos(layout
, run
->descr
.textPosition
);
934 run
->descr
.localeName
= range
->locale
;
935 run
->clustermap
= heap_alloc(run
->descr
.stringLength
* sizeof(*run
->clustermap
));
937 max_count
= 3 * run
->descr
.stringLength
/ 2 + 16;
938 run
->glyphs
= heap_alloc(max_count
* sizeof(*run
->glyphs
));
939 if (!run
->clustermap
|| !run
->glyphs
)
940 return E_OUTOFMEMORY
;
942 text_props
= heap_alloc(run
->descr
.stringLength
* sizeof(*text_props
));
943 glyph_props
= heap_alloc(max_count
* sizeof(*glyph_props
));
944 if (!text_props
|| !glyph_props
) {
945 heap_free(text_props
);
946 heap_free(glyph_props
);
947 return E_OUTOFMEMORY
;
950 analyzer
= get_text_analyzer();
953 hr
= IDWriteTextAnalyzer_GetGlyphs(analyzer
, run
->descr
.string
, run
->descr
.stringLength
, run
->run
.fontFace
,
954 run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
, NULL
/* FIXME */, NULL
,
955 NULL
, 0, max_count
, run
->clustermap
, text_props
, run
->glyphs
, glyph_props
, &run
->glyphcount
);
956 if (hr
== E_NOT_SUFFICIENT_BUFFER
) {
957 heap_free(run
->glyphs
);
958 heap_free(glyph_props
);
960 max_count
= run
->glyphcount
;
962 run
->glyphs
= heap_alloc(max_count
* sizeof(*run
->glyphs
));
963 glyph_props
= heap_alloc(max_count
* sizeof(*glyph_props
));
964 if (!run
->glyphs
|| !glyph_props
) {
976 heap_free(text_props
);
977 heap_free(glyph_props
);
978 WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run
->descr
), hr
);
982 run
->run
.glyphIndices
= run
->glyphs
;
983 run
->descr
.clusterMap
= run
->clustermap
;
985 run
->advances
= heap_alloc(run
->glyphcount
* sizeof(*run
->advances
));
986 run
->offsets
= heap_alloc(run
->glyphcount
* sizeof(*run
->offsets
));
987 if (!run
->advances
|| !run
->offsets
)
988 return E_OUTOFMEMORY
;
990 /* Get advances and offsets. */
991 if (is_layout_gdi_compatible(layout
))
992 hr
= IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer
, run
->descr
.string
, run
->descr
.clusterMap
,
993 text_props
, run
->descr
.stringLength
, run
->run
.glyphIndices
, glyph_props
, run
->glyphcount
,
994 run
->run
.fontFace
, run
->run
.fontEmSize
, layout
->ppdip
, &layout
->transform
,
995 layout
->measuringmode
== DWRITE_MEASURING_MODE_GDI_NATURAL
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1,
996 &run
->sa
, run
->descr
.localeName
, NULL
, NULL
, 0, run
->advances
, run
->offsets
);
998 hr
= IDWriteTextAnalyzer_GetGlyphPlacements(analyzer
, run
->descr
.string
, run
->descr
.clusterMap
, text_props
,
999 run
->descr
.stringLength
, run
->run
.glyphIndices
, glyph_props
, run
->glyphcount
, run
->run
.fontFace
,
1000 run
->run
.fontEmSize
, run
->run
.isSideways
, run
->run
.bidiLevel
& 1, &run
->sa
, run
->descr
.localeName
,
1001 NULL
, NULL
, 0, run
->advances
, run
->offsets
);
1003 heap_free(text_props
);
1004 heap_free(glyph_props
);
1006 memset(run
->advances
, 0, run
->glyphcount
* sizeof(*run
->advances
));
1007 memset(run
->offsets
, 0, run
->glyphcount
* sizeof(*run
->offsets
));
1008 WARN("%s: failed to get glyph placement info, hr %#x.\n", debugstr_rundescr(&run
->descr
), hr
);
1011 run
->run
.glyphAdvances
= run
->advances
;
1012 run
->run
.glyphOffsets
= run
->offsets
;
1014 /* Special treatment for runs that don't produce visual output, shaping code adds normal glyphs for them,
1015 with valid cluster map and potentially with non-zero advances; layout code exposes those as zero
1017 if (run
->sa
.shapes
== DWRITE_SCRIPT_SHAPES_NO_VISUAL
)
1018 run
->run
.glyphCount
= 0;
1020 run
->run
.glyphCount
= run
->glyphcount
;
1025 static HRESULT
layout_compute_runs(struct dwrite_textlayout
*layout
)
1027 struct layout_run
*r
;
1031 free_layout_eruns(layout
);
1032 free_layout_runs(layout
);
1034 /* Cluster data arrays are allocated once, assuming one text position per cluster. */
1035 if (!layout
->clustermetrics
&& layout
->len
) {
1036 layout
->clustermetrics
= heap_alloc(layout
->len
*sizeof(*layout
->clustermetrics
));
1037 layout
->clusters
= heap_alloc(layout
->len
*sizeof(*layout
->clusters
));
1038 if (!layout
->clustermetrics
|| !layout
->clusters
) {
1039 heap_free(layout
->clustermetrics
);
1040 heap_free(layout
->clusters
);
1041 return E_OUTOFMEMORY
;
1044 layout
->cluster_count
= 0;
1046 if (FAILED(hr
= layout_itemize(layout
))) {
1047 WARN("Itemization failed, hr %#x.\n", hr
);
1051 if (FAILED(hr
= layout_resolve_fonts(layout
))) {
1052 WARN("Failed to resolve layout fonts, hr %#x.\n", hr
);
1057 LIST_FOR_EACH_ENTRY(r
, &layout
->runs
, struct layout_run
, entry
) {
1058 struct regular_layout_run
*run
= &r
->u
.regular
;
1059 DWRITE_FONT_METRICS fontmetrics
= { 0 };
1061 /* we need to do very little in case of inline objects */
1062 if (r
->kind
== LAYOUT_RUN_INLINE
) {
1063 DWRITE_CLUSTER_METRICS
*metrics
= &layout
->clustermetrics
[cluster
];
1064 struct layout_cluster
*c
= &layout
->clusters
[cluster
];
1065 DWRITE_INLINE_OBJECT_METRICS inlinemetrics
;
1067 metrics
->width
= 0.0f
;
1068 metrics
->length
= r
->u
.object
.length
;
1069 metrics
->canWrapLineAfter
= 0;
1070 metrics
->isWhitespace
= 0;
1071 metrics
->isNewline
= 0;
1072 metrics
->isSoftHyphen
= 0;
1073 metrics
->isRightToLeft
= 0;
1074 metrics
->padding
= 0;
1076 c
->position
= 0; /* there's always one cluster per inline object, so 0 is valid value */
1079 /* it's not fatal if GetMetrics() fails, all returned metrics are ignored */
1080 hr
= IDWriteInlineObject_GetMetrics(r
->u
.object
.object
, &inlinemetrics
);
1082 memset(&inlinemetrics
, 0, sizeof(inlinemetrics
));
1085 metrics
->width
= inlinemetrics
.width
;
1086 r
->baseline
= inlinemetrics
.baseline
;
1087 r
->height
= inlinemetrics
.height
;
1089 /* FIXME: use resolved breakpoints in this case too */
1094 if (FAILED(hr
= layout_shape_run(layout
, run
)))
1095 WARN("%s: shaping failed, hr %#x.\n", debugstr_rundescr(&run
->descr
), hr
);
1097 /* baseline derived from font metrics */
1098 layout_get_font_metrics(layout
, run
->run
.fontFace
, run
->run
.fontEmSize
, &fontmetrics
);
1099 layout_get_font_height(run
->run
.fontEmSize
, &fontmetrics
, &r
->baseline
, &r
->height
);
1101 layout_set_cluster_metrics(layout
, r
, &cluster
);
1105 layout
->cluster_count
= cluster
;
1107 layout
->clustermetrics
[cluster
-1].canWrapLineAfter
= 1;
1113 static HRESULT
layout_compute(struct dwrite_textlayout
*layout
)
1117 if (!(layout
->recompute
& RECOMPUTE_CLUSTERS
))
1120 /* nominal breakpoints are evaluated only once, because string never changes */
1121 if (!layout
->nominal_breakpoints
) {
1122 IDWriteTextAnalyzer
*analyzer
;
1124 layout
->nominal_breakpoints
= heap_alloc(layout
->len
* sizeof(*layout
->nominal_breakpoints
));
1125 if (!layout
->nominal_breakpoints
)
1126 return E_OUTOFMEMORY
;
1128 analyzer
= get_text_analyzer();
1130 if (FAILED(hr
= IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer
,
1131 (IDWriteTextAnalysisSource
*)&layout
->IDWriteTextAnalysisSource1_iface
,
1132 0, layout
->len
, (IDWriteTextAnalysisSink
*)&layout
->IDWriteTextAnalysisSink1_iface
)))
1133 WARN("Line breakpoints analysis failed, hr %#x.\n", hr
);
1136 heap_free(layout
->actual_breakpoints
);
1137 layout
->actual_breakpoints
= NULL
;
1139 hr
= layout_compute_runs(layout
);
1141 if (TRACE_ON(dwrite
)) {
1142 struct layout_run
*cur
;
1144 LIST_FOR_EACH_ENTRY(cur
, &layout
->runs
, struct layout_run
, entry
) {
1145 if (cur
->kind
== LAYOUT_RUN_INLINE
)
1146 TRACE("run inline object %p, len %u\n", cur
->u
.object
.object
, cur
->u
.object
.length
);
1148 TRACE("run [%u,%u], len %u, bidilevel %u\n", cur
->u
.regular
.descr
.textPosition
, cur
->u
.regular
.descr
.textPosition
+
1149 cur
->u
.regular
.descr
.stringLength
-1, cur
->u
.regular
.descr
.stringLength
, cur
->u
.regular
.run
.bidiLevel
);
1153 layout
->recompute
&= ~RECOMPUTE_CLUSTERS
;
1157 static inline FLOAT
get_cluster_range_width(struct dwrite_textlayout
*layout
, UINT32 start
, UINT32 end
)
1160 for (; start
< end
; start
++)
1161 width
+= layout
->clustermetrics
[start
].width
;
1165 static struct layout_range_header
*get_layout_range_header_by_pos(struct list
*ranges
, UINT32 pos
)
1167 struct layout_range_header
*cur
;
1169 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
1170 DWRITE_TEXT_RANGE
*r
= &cur
->range
;
1171 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
1178 static inline IUnknown
*layout_get_effect_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1180 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->effects
, pos
);
1181 return ((struct layout_range_iface
*)h
)->iface
;
1184 static inline BOOL
layout_is_erun_rtl(const struct layout_effective_run
*erun
)
1186 return erun
->run
->u
.regular
.run
.bidiLevel
& 1;
1189 /* A set of parameters that additionally splits resulting runs. It happens after shaping and all text processing,
1190 no glyph changes are possible. It's understandable for drawing effects, because DrawGlyphRun() reports them as
1191 one of the arguments, but it also happens for decorations, so every effective run has uniform
1192 underline/strikethough/effect tuple. */
1193 struct layout_final_splitting_params
{
1199 static inline BOOL
layout_get_strikethrough_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1201 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->strike_ranges
, pos
);
1202 return ((struct layout_range_bool
*)h
)->value
;
1205 static inline BOOL
layout_get_underline_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
1207 struct layout_range_header
*h
= get_layout_range_header_by_pos(&layout
->underline_ranges
, pos
);
1208 return ((struct layout_range_bool
*)h
)->value
;
1211 static void layout_splitting_params_from_pos(struct dwrite_textlayout
*layout
, UINT32 pos
,
1212 struct layout_final_splitting_params
*params
)
1214 params
->strikethrough
= layout_get_strikethrough_from_pos(layout
, pos
);
1215 params
->underline
= layout_get_underline_from_pos(layout
, pos
);
1216 params
->effect
= layout_get_effect_from_pos(layout
, pos
);
1219 static BOOL
is_same_splitting_params(const struct layout_final_splitting_params
*left
,
1220 const struct layout_final_splitting_params
*right
)
1222 return left
->strikethrough
== right
->strikethrough
&&
1223 left
->underline
== right
->underline
&&
1224 left
->effect
== right
->effect
;
1227 static void layout_get_erun_font_metrics(struct dwrite_textlayout
*layout
, struct layout_effective_run
*erun
,
1228 DWRITE_FONT_METRICS
*metrics
)
1230 memset(metrics
, 0, sizeof(*metrics
));
1231 if (is_layout_gdi_compatible(layout
)) {
1232 HRESULT hr
= IDWriteFontFace_GetGdiCompatibleMetrics(
1233 erun
->run
->u
.regular
.run
.fontFace
,
1234 erun
->run
->u
.regular
.run
.fontEmSize
,
1239 WARN("failed to get font metrics, 0x%08x\n", hr
);
1242 IDWriteFontFace_GetMetrics(erun
->run
->u
.regular
.run
.fontFace
, metrics
);
1245 /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
1246 'cluster_count' indicates how many clusters to add, including first one. */
1247 static HRESULT
layout_add_effective_run(struct dwrite_textlayout
*layout
, const struct layout_run
*r
, UINT32 first_cluster
,
1248 UINT32 cluster_count
, UINT32 line
, FLOAT origin_x
, struct layout_final_splitting_params
*params
)
1250 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1251 UINT32 i
, start
, length
, last_cluster
;
1252 struct layout_effective_run
*run
;
1254 if (r
->kind
== LAYOUT_RUN_INLINE
) {
1255 struct layout_effective_inline
*inlineobject
;
1257 inlineobject
= heap_alloc(sizeof(*inlineobject
));
1259 return E_OUTOFMEMORY
;
1261 inlineobject
->object
= r
->u
.object
.object
;
1262 inlineobject
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1263 inlineobject
->origin
.x
= is_rtl
? origin_x
- inlineobject
->width
: origin_x
;
1264 inlineobject
->origin
.y
= 0.0f
; /* set after line is built */
1265 inlineobject
->align_dx
= 0.0f
;
1266 inlineobject
->baseline
= r
->baseline
;
1268 /* It's not clear how these two are set, possibly directionality
1269 is derived from surrounding text (replaced text could have
1270 different ranges which differ in reading direction). */
1271 inlineobject
->is_sideways
= FALSE
;
1272 inlineobject
->is_rtl
= FALSE
;
1273 inlineobject
->line
= line
;
1275 /* effect assigned from start position and on is used for inline objects */
1276 inlineobject
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[first_cluster
].position
+
1277 layout
->clusters
[first_cluster
].run
->start_position
);
1279 list_add_tail(&layout
->inlineobjects
, &inlineobject
->entry
);
1283 run
= heap_alloc(sizeof(*run
));
1285 return E_OUTOFMEMORY
;
1287 /* No need to iterate for that, use simple fact that:
1288 <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */
1289 last_cluster
= first_cluster
+ cluster_count
- 1;
1290 length
= layout
->clusters
[last_cluster
].position
- layout
->clusters
[first_cluster
].position
+
1291 layout
->clustermetrics
[last_cluster
].length
;
1293 run
->clustermap
= heap_alloc(sizeof(UINT16
)*length
);
1294 if (!run
->clustermap
) {
1296 return E_OUTOFMEMORY
;
1300 run
->start
= start
= layout
->clusters
[first_cluster
].position
;
1301 run
->length
= length
;
1302 run
->width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1303 memset(&run
->bbox
, 0, sizeof(run
->bbox
));
1305 /* Check if run direction matches paragraph direction, if it doesn't adjust by
1307 if (layout_is_erun_rtl(run
) ^ is_rtl
)
1308 run
->origin
.x
= is_rtl
? origin_x
- run
->width
: origin_x
+ run
->width
;
1310 run
->origin
.x
= origin_x
;
1312 run
->origin
.y
= 0.0f
; /* set after line is built */
1313 run
->align_dx
= 0.0f
;
1316 if (r
->u
.regular
.run
.glyphCount
) {
1317 /* Trim leading and trailing clusters. */
1318 run
->glyphcount
= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
];
1319 if (start
+ length
< r
->u
.regular
.descr
.stringLength
)
1320 run
->glyphcount
-= r
->u
.regular
.run
.glyphCount
- r
->u
.regular
.clustermap
[start
+ length
];
1323 run
->glyphcount
= 0;
1325 /* cluster map needs to be shifted */
1326 for (i
= 0; i
< length
; i
++)
1327 run
->clustermap
[i
] = r
->u
.regular
.clustermap
[start
+ i
] - r
->u
.regular
.clustermap
[start
];
1329 run
->effect
= params
->effect
;
1330 run
->underlined
= params
->underline
;
1331 list_add_tail(&layout
->eruns
, &run
->entry
);
1333 /* Strikethrough style is guaranteed to be consistent within effective run,
1334 its width equals to run width, thickness and offset are derived from
1335 font metrics, rest of the values are from layout or run itself */
1336 if (params
->strikethrough
) {
1337 struct layout_strikethrough
*s
;
1338 DWRITE_FONT_METRICS metrics
;
1340 s
= heap_alloc(sizeof(*s
));
1342 return E_OUTOFMEMORY
;
1344 layout_get_erun_font_metrics(layout
, run
, &metrics
);
1345 s
->s
.width
= get_cluster_range_width(layout
, first_cluster
, first_cluster
+ cluster_count
);
1346 s
->s
.thickness
= SCALE_FONT_METRIC(metrics
.strikethroughThickness
, r
->u
.regular
.run
.fontEmSize
, &metrics
);
1347 /* Negative offset moves it above baseline as Y coordinate grows downward. */
1348 s
->s
.offset
= -SCALE_FONT_METRIC(metrics
.strikethroughPosition
, r
->u
.regular
.run
.fontEmSize
, &metrics
);
1349 s
->s
.readingDirection
= layout
->format
.readingdir
;
1350 s
->s
.flowDirection
= layout
->format
.flow
;
1351 s
->s
.localeName
= r
->u
.regular
.descr
.localeName
;
1352 s
->s
.measuringMode
= layout
->measuringmode
;
1355 list_add_tail(&layout
->strikethrough
, &s
->entry
);
1361 static void layout_apply_line_spacing(struct dwrite_textlayout
*layout
, UINT32 line
)
1363 switch (layout
->format
.spacing
.method
)
1365 case DWRITE_LINE_SPACING_METHOD_DEFAULT
:
1366 layout
->linemetrics
[line
].height
= layout
->lines
[line
].height
;
1367 layout
->linemetrics
[line
].baseline
= layout
->lines
[line
].baseline
;
1369 case DWRITE_LINE_SPACING_METHOD_UNIFORM
:
1370 layout
->linemetrics
[line
].height
= layout
->format
.spacing
.height
;
1371 layout
->linemetrics
[line
].baseline
= layout
->format
.spacing
.baseline
;
1373 case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL
:
1374 layout
->linemetrics
[line
].height
= layout
->lines
[line
].height
* layout
->format
.spacing
.height
;
1375 layout
->linemetrics
[line
].baseline
= layout
->lines
[line
].baseline
* layout
->format
.spacing
.baseline
;
1378 ERR("Unknown spacing method %u\n", layout
->format
.spacing
.method
);
1382 static HRESULT
layout_set_line_metrics(struct dwrite_textlayout
*layout
, DWRITE_LINE_METRICS1
*metrics
)
1384 UINT32 i
= layout
->metrics
.lineCount
;
1386 if (!layout
->line_alloc
) {
1387 layout
->line_alloc
= 5;
1388 layout
->linemetrics
= heap_alloc(layout
->line_alloc
* sizeof(*layout
->linemetrics
));
1389 layout
->lines
= heap_alloc(layout
->line_alloc
* sizeof(*layout
->lines
));
1390 if (!layout
->linemetrics
|| !layout
->lines
) {
1391 heap_free(layout
->linemetrics
);
1392 heap_free(layout
->lines
);
1393 layout
->linemetrics
= NULL
;
1394 layout
->lines
= NULL
;
1395 return E_OUTOFMEMORY
;
1399 if (layout
->metrics
.lineCount
== layout
->line_alloc
) {
1400 DWRITE_LINE_METRICS1
*metrics
;
1401 struct layout_line
*lines
;
1403 if ((metrics
= heap_realloc(layout
->linemetrics
, layout
->line_alloc
* 2 * sizeof(*layout
->linemetrics
))))
1404 layout
->linemetrics
= metrics
;
1405 if ((lines
= heap_realloc(layout
->lines
, layout
->line_alloc
* 2 * sizeof(*layout
->lines
))))
1406 layout
->lines
= lines
;
1408 if (!metrics
|| !lines
)
1409 return E_OUTOFMEMORY
;
1411 layout
->line_alloc
*= 2;
1414 layout
->linemetrics
[i
] = *metrics
;
1415 layout
->lines
[i
].height
= metrics
->height
;
1416 layout
->lines
[i
].baseline
= metrics
->baseline
;
1418 if (layout
->format
.spacing
.method
!= DWRITE_LINE_SPACING_METHOD_DEFAULT
)
1419 layout_apply_line_spacing(layout
, i
);
1421 layout
->metrics
.lineCount
++;
1425 static inline struct layout_effective_run
*layout_get_next_erun(struct dwrite_textlayout
*layout
,
1426 const struct layout_effective_run
*cur
)
1431 e
= list_head(&layout
->eruns
);
1433 e
= list_next(&layout
->eruns
, &cur
->entry
);
1436 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1439 static inline struct layout_effective_run
*layout_get_prev_erun(struct dwrite_textlayout
*layout
,
1440 const struct layout_effective_run
*cur
)
1445 e
= list_tail(&layout
->eruns
);
1447 e
= list_prev(&layout
->eruns
, &cur
->entry
);
1450 return LIST_ENTRY(e
, struct layout_effective_run
, entry
);
1453 static inline struct layout_effective_inline
*layout_get_next_inline_run(struct dwrite_textlayout
*layout
,
1454 const struct layout_effective_inline
*cur
)
1459 e
= list_head(&layout
->inlineobjects
);
1461 e
= list_next(&layout
->inlineobjects
, &cur
->entry
);
1464 return LIST_ENTRY(e
, struct layout_effective_inline
, entry
);
1467 static FLOAT
layout_get_line_width(struct dwrite_textlayout
*layout
,
1468 struct layout_effective_run
*erun
, struct layout_effective_inline
*inrun
, UINT32 line
)
1472 while (erun
&& erun
->line
== line
) {
1473 width
+= erun
->width
;
1474 erun
= layout_get_next_erun(layout
, erun
);
1479 while (inrun
&& inrun
->line
== line
) {
1480 width
+= inrun
->width
;
1481 inrun
= layout_get_next_inline_run(layout
, inrun
);
1489 static inline BOOL
should_skip_transform(const DWRITE_MATRIX
*m
, FLOAT
*det
)
1491 *det
= m
->m11
* m
->m22
- m
->m12
* m
->m21
;
1492 /* on certain conditions we can skip transform */
1493 return (!memcmp(m
, &identity
, sizeof(*m
)) || fabsf(*det
) <= 1e-10f
);
1496 static inline void layout_apply_snapping(D2D1_POINT_2F
*vec
, BOOL skiptransform
, FLOAT ppdip
,
1497 const DWRITE_MATRIX
*m
, FLOAT det
)
1499 if (!skiptransform
) {
1502 /* apply transform */
1506 vec2
.x
= m
->m11
* vec
->x
+ m
->m21
* vec
->y
+ m
->dx
;
1507 vec2
.y
= m
->m12
* vec
->x
+ m
->m22
* vec
->y
+ m
->dy
;
1510 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
1511 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
1513 /* apply inverted transform, we don't care about X component at this point */
1514 vec
->x
= (m
->m22
* vec2
.x
- m
->m21
* vec2
.y
+ m
->m21
* m
->dy
- m
->m22
* m
->dx
) / det
;
1517 vec
->y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
1521 vec
->x
= floorf(vec
->x
* ppdip
+ 0.5f
) / ppdip
;
1522 vec
->y
= floorf(vec
->y
* ppdip
+ 0.5f
) / ppdip
;
1526 static void layout_apply_leading_alignment(struct dwrite_textlayout
*layout
)
1528 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1529 struct layout_effective_inline
*inrun
;
1530 struct layout_effective_run
*erun
;
1532 erun
= layout_get_next_erun(layout
, NULL
);
1533 inrun
= layout_get_next_inline_run(layout
, NULL
);
1536 erun
->align_dx
= 0.0f
;
1537 erun
= layout_get_next_erun(layout
, erun
);
1541 inrun
->align_dx
= 0.0f
;
1542 inrun
= layout_get_next_inline_run(layout
, inrun
);
1545 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
1548 static void layout_apply_trailing_alignment(struct dwrite_textlayout
*layout
)
1550 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1551 struct layout_effective_inline
*inrun
;
1552 struct layout_effective_run
*erun
;
1555 erun
= layout_get_next_erun(layout
, NULL
);
1556 inrun
= layout_get_next_inline_run(layout
, NULL
);
1558 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1559 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1560 FLOAT shift
= layout
->metrics
.layoutWidth
- width
;
1565 while (erun
&& erun
->line
== line
) {
1566 erun
->align_dx
= shift
;
1567 erun
= layout_get_next_erun(layout
, erun
);
1570 while (inrun
&& inrun
->line
== line
) {
1571 inrun
->align_dx
= shift
;
1572 inrun
= layout_get_next_inline_run(layout
, inrun
);
1576 layout
->metrics
.left
= is_rtl
? 0.0f
: layout
->metrics
.layoutWidth
- layout
->metrics
.width
;
1579 static inline FLOAT
layout_get_centered_shift(struct dwrite_textlayout
*layout
, BOOL skiptransform
,
1580 FLOAT width
, FLOAT det
)
1582 if (is_layout_gdi_compatible(layout
)) {
1583 D2D1_POINT_2F vec
= { layout
->metrics
.layoutWidth
- width
, 0.0f
};
1584 layout_apply_snapping(&vec
, skiptransform
, layout
->ppdip
, &layout
->transform
, det
);
1585 return floorf(vec
.x
/ 2.0f
);
1588 return (layout
->metrics
.layoutWidth
- width
) / 2.0f
;
1591 static void layout_apply_centered_alignment(struct dwrite_textlayout
*layout
)
1593 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1594 struct layout_effective_inline
*inrun
;
1595 struct layout_effective_run
*erun
;
1600 erun
= layout_get_next_erun(layout
, NULL
);
1601 inrun
= layout_get_next_inline_run(layout
, NULL
);
1603 skiptransform
= should_skip_transform(&layout
->transform
, &det
);
1605 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1606 FLOAT width
= layout_get_line_width(layout
, erun
, inrun
, line
);
1607 FLOAT shift
= layout_get_centered_shift(layout
, skiptransform
, width
, det
);
1612 while (erun
&& erun
->line
== line
) {
1613 erun
->align_dx
= shift
;
1614 erun
= layout_get_next_erun(layout
, erun
);
1617 while (inrun
&& inrun
->line
== line
) {
1618 inrun
->align_dx
= shift
;
1619 inrun
= layout_get_next_inline_run(layout
, inrun
);
1623 layout
->metrics
.left
= (layout
->metrics
.layoutWidth
- layout
->metrics
.width
) / 2.0f
;
1626 static void layout_apply_text_alignment(struct dwrite_textlayout
*layout
)
1628 switch (layout
->format
.textalignment
)
1630 case DWRITE_TEXT_ALIGNMENT_LEADING
:
1631 layout_apply_leading_alignment(layout
);
1633 case DWRITE_TEXT_ALIGNMENT_TRAILING
:
1634 layout_apply_trailing_alignment(layout
);
1636 case DWRITE_TEXT_ALIGNMENT_CENTER
:
1637 layout_apply_centered_alignment(layout
);
1639 case DWRITE_TEXT_ALIGNMENT_JUSTIFIED
:
1640 FIXME("alignment %d not implemented\n", layout
->format
.textalignment
);
1647 static void layout_apply_par_alignment(struct dwrite_textlayout
*layout
)
1649 struct layout_effective_inline
*inrun
;
1650 struct layout_effective_run
*erun
;
1651 FLOAT origin_y
= 0.0f
;
1654 /* alignment mode defines origin, after that all run origins are updated
1657 switch (layout
->format
.paralign
)
1659 case DWRITE_PARAGRAPH_ALIGNMENT_NEAR
:
1662 case DWRITE_PARAGRAPH_ALIGNMENT_FAR
:
1663 origin_y
= layout
->metrics
.layoutHeight
- layout
->metrics
.height
;
1665 case DWRITE_PARAGRAPH_ALIGNMENT_CENTER
:
1666 origin_y
= (layout
->metrics
.layoutHeight
- layout
->metrics
.height
) / 2.0f
;
1672 layout
->metrics
.top
= origin_y
;
1674 erun
= layout_get_next_erun(layout
, NULL
);
1675 inrun
= layout_get_next_inline_run(layout
, NULL
);
1676 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
1677 FLOAT pos_y
= origin_y
+ layout
->linemetrics
[line
].baseline
;
1679 while (erun
&& erun
->line
== line
) {
1680 erun
->origin
.y
= pos_y
;
1681 erun
= layout_get_next_erun(layout
, erun
);
1684 while (inrun
&& inrun
->line
== line
) {
1685 inrun
->origin
.y
= pos_y
- inrun
->baseline
;
1686 inrun
= layout_get_next_inline_run(layout
, inrun
);
1689 origin_y
+= layout
->linemetrics
[line
].height
;
1693 struct layout_underline_splitting_params
{
1694 const WCHAR
*locale
; /* points to range data, no additional allocation */
1695 IUnknown
*effect
; /* does not hold another reference */
1698 static void init_u_splitting_params_from_erun(struct layout_effective_run
*erun
,
1699 struct layout_underline_splitting_params
*params
)
1701 params
->locale
= erun
->run
->u
.regular
.descr
.localeName
;
1702 params
->effect
= erun
->effect
;
1705 static BOOL
is_same_u_splitting(struct layout_underline_splitting_params
*left
,
1706 struct layout_underline_splitting_params
*right
)
1708 return left
->effect
== right
->effect
&& !strcmpiW(left
->locale
, right
->locale
);
1711 static HRESULT
layout_add_underline(struct dwrite_textlayout
*layout
, struct layout_effective_run
*first
,
1712 struct layout_effective_run
*last
)
1714 FLOAT thickness
, offset
, runheight
;
1715 struct layout_effective_run
*cur
;
1716 DWRITE_FONT_METRICS metrics
;
1718 if (first
== layout_get_prev_erun(layout
, last
)) {
1719 layout_get_erun_font_metrics(layout
, first
, &metrics
);
1720 thickness
= SCALE_FONT_METRIC(metrics
.underlineThickness
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1721 offset
= SCALE_FONT_METRIC(metrics
.underlinePosition
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1722 runheight
= SCALE_FONT_METRIC(metrics
.capHeight
, first
->run
->u
.regular
.run
.fontEmSize
, &metrics
);
1727 /* Single underline is added for consecutive underlined runs. In this case underline parameters are
1728 calculated as weighted average, where run width acts as a weight. */
1729 thickness
= offset
= runheight
= 0.0f
;
1732 layout_get_erun_font_metrics(layout
, cur
, &metrics
);
1734 thickness
+= SCALE_FONT_METRIC(metrics
.underlineThickness
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
1735 offset
+= SCALE_FONT_METRIC(metrics
.underlinePosition
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
) * cur
->width
;
1736 runheight
= max(SCALE_FONT_METRIC(metrics
.capHeight
, cur
->run
->u
.regular
.run
.fontEmSize
, &metrics
), runheight
);
1737 width
+= cur
->width
;
1739 cur
= layout_get_next_erun(layout
, cur
);
1740 } while (cur
!= last
);
1748 struct layout_underline_splitting_params params
, prev_params
;
1749 struct layout_effective_run
*next
, *w
;
1750 struct layout_underline
*u
;
1752 init_u_splitting_params_from_erun(cur
, &prev_params
);
1753 while ((next
= layout_get_next_erun(layout
, cur
)) != last
) {
1754 init_u_splitting_params_from_erun(next
, ¶ms
);
1755 if (!is_same_u_splitting(&prev_params
, ¶ms
))
1760 u
= heap_alloc(sizeof(*u
));
1762 return E_OUTOFMEMORY
;
1767 u
->u
.width
+= w
->width
;
1768 w
= layout_get_next_erun(layout
, w
);
1771 u
->u
.thickness
= thickness
;
1772 /* Font metrics convention is to have it negative when below baseline, for rendering
1773 however Y grows from baseline down for horizontal baseline. */
1774 u
->u
.offset
= -offset
;
1775 u
->u
.runHeight
= runheight
;
1776 u
->u
.readingDirection
= is_run_rtl(cur
) ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
:
1777 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
1778 u
->u
.flowDirection
= layout
->format
.flow
;
1779 u
->u
.localeName
= cur
->run
->u
.regular
.descr
.localeName
;
1780 u
->u
.measuringMode
= layout
->measuringmode
;
1782 list_add_tail(&layout
->underlines
, &u
->entry
);
1785 } while (cur
!= last
);
1790 /* Adds zero width line, metrics are derived from font at specified text position. */
1791 static HRESULT
layout_set_dummy_line_metrics(struct dwrite_textlayout
*layout
, UINT32 pos
)
1793 DWRITE_LINE_METRICS1 metrics
= { 0 };
1794 DWRITE_FONT_METRICS fontmetrics
;
1795 struct layout_range
*range
;
1796 IDWriteFontFace
*fontface
;
1800 range
= get_layout_range_by_pos(layout
, pos
);
1801 hr
= create_matching_font(range
->collection
,
1809 hr
= IDWriteFont_CreateFontFace(font
, &fontface
);
1810 IDWriteFont_Release(font
);
1814 layout_get_font_metrics(layout
, fontface
, range
->fontsize
, &fontmetrics
);
1815 layout_get_font_height(range
->fontsize
, &fontmetrics
, &metrics
.baseline
, &metrics
.height
);
1816 IDWriteFontFace_Release(fontface
);
1818 return layout_set_line_metrics(layout
, &metrics
);
1821 static void layout_add_line(struct dwrite_textlayout
*layout
, UINT32 first_cluster
, UINT32 last_cluster
,
1824 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
1825 struct layout_final_splitting_params params
, prev_params
;
1826 DWRITE_INLINE_OBJECT_METRICS sign_metrics
= { 0 };
1827 UINT32 line
= layout
->metrics
.lineCount
, i
;
1828 DWRITE_LINE_METRICS1 metrics
= { 0 };
1829 UINT32 index
, start
, pos
= *textpos
;
1830 FLOAT descent
, trailingspacewidth
;
1831 BOOL append_trimming_run
= FALSE
;
1832 const struct layout_run
*run
;
1833 FLOAT width
, origin_x
;
1836 /* Take a look at clusters we got for this line in reverse order to set trailing properties for current line */
1837 for (index
= last_cluster
, trailingspacewidth
= 0.0f
; index
>= first_cluster
; index
--) {
1838 DWRITE_CLUSTER_METRICS
*cluster
= &layout
->clustermetrics
[index
];
1839 struct layout_cluster
*lc
= &layout
->clusters
[index
];
1842 /* This also filters out clusters added from inline objects, those are never
1843 treated as a white space. */
1844 if (!cluster
->isWhitespace
)
1847 /* Every isNewline cluster is also isWhitespace, but not every
1848 newline character cluster has isNewline set, so go back to original string. */
1849 ch
= lc
->run
->u
.regular
.descr
.string
[lc
->position
];
1850 if (cluster
->length
== 1 && lb_is_newline_char(ch
))
1851 metrics
.newlineLength
+= cluster
->length
;
1853 metrics
.trailingWhitespaceLength
+= cluster
->length
;
1854 trailingspacewidth
+= cluster
->width
;
1857 /* Line metrics length includes trailing whitespace length too */
1858 for (i
= first_cluster
; i
<= last_cluster
; i
++)
1859 metrics
.length
+= layout
->clustermetrics
[i
].length
;
1861 /* Ignore trailing whitespaces */
1862 while (last_cluster
> first_cluster
) {
1863 if (!layout
->clustermetrics
[last_cluster
].isWhitespace
)
1869 /* Does not include trailing space width */
1870 width
= get_cluster_range_width(layout
, first_cluster
, last_cluster
+ 1);
1872 /* Append trimming run if necessary */
1873 if (width
> layout
->metrics
.layoutWidth
&& layout
->format
.trimmingsign
!= NULL
&&
1874 layout
->format
.trimming
.granularity
!= DWRITE_TRIMMING_GRANULARITY_NONE
) {
1875 FLOAT trimmed_width
= width
;
1877 hr
= IDWriteInlineObject_GetMetrics(layout
->format
.trimmingsign
, &sign_metrics
);
1878 if (SUCCEEDED(hr
)) {
1879 while (last_cluster
> first_cluster
) {
1880 if (trimmed_width
+ sign_metrics
.width
<= layout
->metrics
.layoutWidth
)
1882 if (layout
->format
.trimming
.granularity
== DWRITE_TRIMMING_GRANULARITY_CHARACTER
)
1883 trimmed_width
-= layout
->clustermetrics
[last_cluster
--].width
;
1885 while (last_cluster
> first_cluster
) {
1886 trimmed_width
-= layout
->clustermetrics
[last_cluster
].width
;
1887 if (layout
->clustermetrics
[last_cluster
--].canWrapLineAfter
)
1892 append_trimming_run
= TRUE
;
1895 WARN("Failed to get trimming sign metrics, lines won't be trimmed, hr %#x.\n", hr
);
1897 width
= trimmed_width
+ sign_metrics
.width
;
1900 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
1901 prev_params
= params
;
1902 run
= layout
->clusters
[first_cluster
].run
;
1904 /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */
1905 origin_x
= is_rtl
? layout
->metrics
.layoutWidth
: 0.0f
;
1906 for (start
= first_cluster
, i
= first_cluster
; i
<= last_cluster
; i
++) {
1907 layout_splitting_params_from_pos(layout
, pos
, ¶ms
);
1909 if (run
!= layout
->clusters
[i
].run
|| !is_same_splitting_params(&prev_params
, ¶ms
)) {
1910 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
1914 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) :
1915 get_cluster_range_width(layout
, start
, i
);
1916 run
= layout
->clusters
[i
].run
;
1920 prev_params
= params
;
1921 pos
+= layout
->clustermetrics
[i
].length
;
1924 /* Final run from what's left from cluster range */
1925 hr
= layout_add_effective_run(layout
, run
, start
, i
- start
, line
, origin_x
, &prev_params
);
1929 if (append_trimming_run
) {
1930 struct layout_effective_inline
*trimming_sign
;
1932 trimming_sign
= heap_alloc(sizeof(*trimming_sign
));
1936 trimming_sign
->object
= layout
->format
.trimmingsign
;
1937 trimming_sign
->width
= sign_metrics
.width
;
1938 origin_x
+= is_rtl
? -get_cluster_range_width(layout
, start
, i
) : get_cluster_range_width(layout
, start
, i
);
1939 trimming_sign
->origin
.x
= is_rtl
? origin_x
- trimming_sign
->width
: origin_x
;
1940 trimming_sign
->origin
.y
= 0.0f
; /* set after line is built */
1941 trimming_sign
->align_dx
= 0.0f
;
1942 trimming_sign
->baseline
= sign_metrics
.baseline
;
1944 trimming_sign
->is_sideways
= FALSE
;
1945 trimming_sign
->is_rtl
= FALSE
;
1946 trimming_sign
->line
= line
;
1948 trimming_sign
->effect
= layout_get_effect_from_pos(layout
, layout
->clusters
[i
].position
+
1949 layout
->clusters
[i
].run
->start_position
);
1951 list_add_tail(&layout
->inlineobjects
, &trimming_sign
->entry
);
1954 /* Look for max baseline and descent for this line */
1955 for (index
= first_cluster
, metrics
.baseline
= 0.0f
, descent
= 0.0f
; index
<= last_cluster
; index
++) {
1956 const struct layout_run
*cur
= layout
->clusters
[index
].run
;
1957 FLOAT cur_descent
= cur
->height
- cur
->baseline
;
1959 if (cur
->baseline
> metrics
.baseline
)
1960 metrics
.baseline
= cur
->baseline
;
1961 if (cur_descent
> descent
)
1962 descent
= cur_descent
;
1965 layout
->metrics
.width
= max(width
, layout
->metrics
.width
);
1966 layout
->metrics
.widthIncludingTrailingWhitespace
= max(width
+ trailingspacewidth
,
1967 layout
->metrics
.widthIncludingTrailingWhitespace
);
1969 metrics
.height
= descent
+ metrics
.baseline
;
1970 metrics
.isTrimmed
= append_trimming_run
|| width
> layout
->metrics
.layoutWidth
;
1971 layout_set_line_metrics(layout
, &metrics
);
1973 *textpos
+= metrics
.length
;
1976 static void layout_set_line_positions(struct dwrite_textlayout
*layout
)
1978 struct layout_effective_inline
*inrun
;
1979 struct layout_effective_run
*erun
;
1983 /* Now all line info is here, update effective runs positions in flow direction */
1984 erun
= layout_get_next_erun(layout
, NULL
);
1985 inrun
= layout_get_next_inline_run(layout
, NULL
);
1987 for (line
= 0, origin_y
= 0.0f
; line
< layout
->metrics
.lineCount
; line
++) {
1988 FLOAT pos_y
= origin_y
+ layout
->linemetrics
[line
].baseline
;
1990 /* For all runs on this line */
1991 while (erun
&& erun
->line
== line
) {
1992 erun
->origin
.y
= pos_y
;
1993 erun
= layout_get_next_erun(layout
, erun
);
1996 /* Same for inline runs */
1997 while (inrun
&& inrun
->line
== line
) {
1998 inrun
->origin
.y
= pos_y
- inrun
->baseline
;
1999 inrun
= layout_get_next_inline_run(layout
, inrun
);
2002 origin_y
+= layout
->linemetrics
[line
].height
;
2005 layout
->metrics
.height
= origin_y
;
2007 /* Initial paragraph alignment is always near */
2008 if (layout
->format
.paralign
!= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
)
2009 layout_apply_par_alignment(layout
);
2012 static BOOL
layout_can_wrap_after(const struct dwrite_textlayout
*layout
, UINT32 cluster
)
2014 if (layout
->format
.wrapping
== DWRITE_WORD_WRAPPING_CHARACTER
)
2017 return layout
->clustermetrics
[cluster
].canWrapLineAfter
;
2020 static HRESULT
layout_compute_effective_runs(struct dwrite_textlayout
*layout
)
2022 BOOL is_rtl
= layout
->format
.readingdir
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
;
2023 struct layout_effective_run
*erun
, *first_underlined
;
2024 UINT32 i
, start
, textpos
, last_breaking_point
;
2025 DWRITE_LINE_METRICS1 metrics
;
2030 if (!(layout
->recompute
& RECOMPUTE_LINES
))
2033 free_layout_eruns(layout
);
2035 hr
= layout_compute(layout
);
2039 layout
->metrics
.lineCount
= 0;
2040 memset(&metrics
, 0, sizeof(metrics
));
2042 layout
->metrics
.height
= 0.0f
;
2043 layout
->metrics
.width
= 0.0f
;
2044 layout
->metrics
.widthIncludingTrailingWhitespace
= 0.0f
;
2046 last_breaking_point
= ~0u;
2048 for (i
= 0, start
= 0, width
= 0.0f
, textpos
= 0; i
< layout
->cluster_count
; i
++) {
2049 BOOL overflow
= FALSE
;
2051 while (i
< layout
->cluster_count
&& !layout
->clustermetrics
[i
].isNewline
) {
2052 /* Check for overflow */
2053 overflow
= ((width
+ layout
->clustermetrics
[i
].width
> layout
->metrics
.layoutWidth
) &&
2054 (layout
->format
.wrapping
!= DWRITE_WORD_WRAPPING_NO_WRAP
));
2058 if (layout_can_wrap_after(layout
, i
))
2059 last_breaking_point
= i
;
2060 width
+= layout
->clustermetrics
[i
].width
;
2063 i
= min(i
, layout
->cluster_count
- 1);
2065 /* Ignore if overflown on whitespace */
2066 if (overflow
&& !(layout
->clustermetrics
[i
].isWhitespace
&& layout_can_wrap_after(layout
, i
))) {
2067 /* Use most recently found breaking point */
2068 if (last_breaking_point
!= ~0u) {
2069 i
= last_breaking_point
;
2070 last_breaking_point
= ~0u;
2073 /* Otherwise proceed forward to next newline or breaking point */
2074 for (; i
< layout
->cluster_count
; i
++)
2075 if (layout_can_wrap_after(layout
, i
) || layout
->clustermetrics
[i
].isNewline
)
2079 i
= min(i
, layout
->cluster_count
- 1);
2081 layout_add_line(layout
, start
, i
, &textpos
);
2086 /* Add dummy line if:
2087 - there's no text, metrics come from first range in this case;
2088 - last ended with a mandatory break, metrics come from last text position.
2090 if (layout
->len
== 0)
2091 hr
= layout_set_dummy_line_metrics(layout
, 0);
2092 else if (layout
->cluster_count
&& layout
->clustermetrics
[layout
->cluster_count
- 1].isNewline
)
2093 hr
= layout_set_dummy_line_metrics(layout
, layout
->len
- 1);
2097 layout
->metrics
.left
= is_rtl
? layout
->metrics
.layoutWidth
- layout
->metrics
.width
: 0.0f
;
2098 layout
->metrics
.top
= 0.0f
;
2099 layout
->metrics
.maxBidiReorderingDepth
= 1; /* FIXME */
2101 /* Add explicit underlined runs */
2102 erun
= layout_get_next_erun(layout
, NULL
);
2103 first_underlined
= erun
&& erun
->underlined
? erun
: NULL
;
2104 for (line
= 0; line
< layout
->metrics
.lineCount
; line
++) {
2105 while (erun
&& erun
->line
== line
) {
2106 erun
= layout_get_next_erun(layout
, erun
);
2108 if (first_underlined
&& (!erun
|| !erun
->underlined
)) {
2109 layout_add_underline(layout
, first_underlined
, erun
);
2110 first_underlined
= NULL
;
2112 else if (!first_underlined
&& erun
&& erun
->underlined
)
2113 first_underlined
= erun
;
2117 /* Position runs in flow direction */
2118 layout_set_line_positions(layout
);
2120 /* Initial alignment is always leading */
2121 if (layout
->format
.textalignment
!= DWRITE_TEXT_ALIGNMENT_LEADING
)
2122 layout_apply_text_alignment(layout
);
2124 layout
->recompute
&= ~RECOMPUTE_LINES
;
2128 static BOOL
is_same_layout_attrvalue(struct layout_range_header
const *h
, enum layout_range_attr_kind attr
,
2129 struct layout_range_attr_value
*value
)
2131 struct layout_range_spacing
const *range_spacing
= (struct layout_range_spacing
*)h
;
2132 struct layout_range_iface
const *range_iface
= (struct layout_range_iface
*)h
;
2133 struct layout_range_bool
const *range_bool
= (struct layout_range_bool
*)h
;
2134 struct layout_range
const *range
= (struct layout_range
*)h
;
2137 case LAYOUT_RANGE_ATTR_WEIGHT
:
2138 return range
->weight
== value
->u
.weight
;
2139 case LAYOUT_RANGE_ATTR_STYLE
:
2140 return range
->style
== value
->u
.style
;
2141 case LAYOUT_RANGE_ATTR_STRETCH
:
2142 return range
->stretch
== value
->u
.stretch
;
2143 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2144 return range
->fontsize
== value
->u
.fontsize
;
2145 case LAYOUT_RANGE_ATTR_INLINE
:
2146 return range
->object
== value
->u
.object
;
2147 case LAYOUT_RANGE_ATTR_EFFECT
:
2148 return range_iface
->iface
== value
->u
.effect
;
2149 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2150 return range_bool
->value
== value
->u
.underline
;
2151 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2152 return range_bool
->value
== value
->u
.strikethrough
;
2153 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2154 return range
->pair_kerning
== value
->u
.pair_kerning
;
2155 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2156 return range
->collection
== value
->u
.collection
;
2157 case LAYOUT_RANGE_ATTR_LOCALE
:
2158 return strcmpiW(range
->locale
, value
->u
.locale
) == 0;
2159 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2160 return strcmpW(range
->fontfamily
, value
->u
.fontfamily
) == 0;
2161 case LAYOUT_RANGE_ATTR_SPACING
:
2162 return range_spacing
->leading
== value
->u
.spacing
.leading
&&
2163 range_spacing
->trailing
== value
->u
.spacing
.trailing
&&
2164 range_spacing
->min_advance
== value
->u
.spacing
.min_advance
;
2165 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2166 return range_iface
->iface
== (IUnknown
*)value
->u
.typography
;
2174 static inline BOOL
is_same_layout_attributes(struct layout_range_header
const *hleft
, struct layout_range_header
const *hright
)
2176 switch (hleft
->kind
)
2178 case LAYOUT_RANGE_REGULAR
:
2180 struct layout_range
const *left
= (struct layout_range
const*)hleft
;
2181 struct layout_range
const *right
= (struct layout_range
const*)hright
;
2182 return left
->weight
== right
->weight
&&
2183 left
->style
== right
->style
&&
2184 left
->stretch
== right
->stretch
&&
2185 left
->fontsize
== right
->fontsize
&&
2186 left
->object
== right
->object
&&
2187 left
->pair_kerning
== right
->pair_kerning
&&
2188 left
->collection
== right
->collection
&&
2189 !strcmpiW(left
->locale
, right
->locale
) &&
2190 !strcmpW(left
->fontfamily
, right
->fontfamily
);
2192 case LAYOUT_RANGE_UNDERLINE
:
2193 case LAYOUT_RANGE_STRIKETHROUGH
:
2195 struct layout_range_bool
const *left
= (struct layout_range_bool
const*)hleft
;
2196 struct layout_range_bool
const *right
= (struct layout_range_bool
const*)hright
;
2197 return left
->value
== right
->value
;
2199 case LAYOUT_RANGE_EFFECT
:
2200 case LAYOUT_RANGE_TYPOGRAPHY
:
2202 struct layout_range_iface
const *left
= (struct layout_range_iface
const*)hleft
;
2203 struct layout_range_iface
const *right
= (struct layout_range_iface
const*)hright
;
2204 return left
->iface
== right
->iface
;
2206 case LAYOUT_RANGE_SPACING
:
2208 struct layout_range_spacing
const *left
= (struct layout_range_spacing
const*)hleft
;
2209 struct layout_range_spacing
const *right
= (struct layout_range_spacing
const*)hright
;
2210 return left
->leading
== right
->leading
&&
2211 left
->trailing
== right
->trailing
&&
2212 left
->min_advance
== right
->min_advance
;
2215 FIXME("unknown range kind %d\n", hleft
->kind
);
2220 static inline BOOL
is_same_text_range(const DWRITE_TEXT_RANGE
*left
, const DWRITE_TEXT_RANGE
*right
)
2222 return left
->startPosition
== right
->startPosition
&& left
->length
== right
->length
;
2225 /* Allocates range and inits it with default values from text format. */
2226 static struct layout_range_header
*alloc_layout_range(struct dwrite_textlayout
*layout
, const DWRITE_TEXT_RANGE
*r
,
2227 enum layout_range_kind kind
)
2229 struct layout_range_header
*h
;
2233 case LAYOUT_RANGE_REGULAR
:
2235 struct layout_range
*range
;
2237 range
= heap_alloc(sizeof(*range
));
2238 if (!range
) return NULL
;
2240 range
->weight
= layout
->format
.weight
;
2241 range
->style
= layout
->format
.style
;
2242 range
->stretch
= layout
->format
.stretch
;
2243 range
->fontsize
= layout
->format
.fontsize
;
2244 range
->object
= NULL
;
2245 range
->pair_kerning
= FALSE
;
2247 range
->fontfamily
= heap_strdupW(layout
->format
.family_name
);
2248 if (!range
->fontfamily
) {
2253 range
->collection
= layout
->format
.collection
;
2254 if (range
->collection
)
2255 IDWriteFontCollection_AddRef(range
->collection
);
2256 strcpyW(range
->locale
, layout
->format
.locale
);
2261 case LAYOUT_RANGE_UNDERLINE
:
2262 case LAYOUT_RANGE_STRIKETHROUGH
:
2264 struct layout_range_bool
*range
;
2266 range
= heap_alloc(sizeof(*range
));
2267 if (!range
) return NULL
;
2269 range
->value
= FALSE
;
2273 case LAYOUT_RANGE_EFFECT
:
2274 case LAYOUT_RANGE_TYPOGRAPHY
:
2276 struct layout_range_iface
*range
;
2278 range
= heap_alloc(sizeof(*range
));
2279 if (!range
) return NULL
;
2281 range
->iface
= NULL
;
2285 case LAYOUT_RANGE_SPACING
:
2287 struct layout_range_spacing
*range
;
2289 range
= heap_alloc(sizeof(*range
));
2290 if (!range
) return NULL
;
2292 range
->leading
= 0.0f
;
2293 range
->trailing
= 0.0f
;
2294 range
->min_advance
= 0.0f
;
2299 FIXME("unknown range kind %d\n", kind
);
2308 static struct layout_range_header
*alloc_layout_range_from(struct layout_range_header
*h
, const DWRITE_TEXT_RANGE
*r
)
2310 struct layout_range_header
*ret
;
2314 case LAYOUT_RANGE_REGULAR
:
2316 struct layout_range
*from
= (struct layout_range
*)h
;
2318 struct layout_range
*range
= heap_alloc(sizeof(*range
));
2319 if (!range
) return NULL
;
2322 range
->fontfamily
= heap_strdupW(from
->fontfamily
);
2323 if (!range
->fontfamily
) {
2328 /* update refcounts */
2330 IDWriteInlineObject_AddRef(range
->object
);
2331 if (range
->collection
)
2332 IDWriteFontCollection_AddRef(range
->collection
);
2336 case LAYOUT_RANGE_UNDERLINE
:
2337 case LAYOUT_RANGE_STRIKETHROUGH
:
2339 struct layout_range_bool
*strike
= heap_alloc(sizeof(*strike
));
2340 if (!strike
) return NULL
;
2342 *strike
= *(struct layout_range_bool
*)h
;
2346 case LAYOUT_RANGE_EFFECT
:
2347 case LAYOUT_RANGE_TYPOGRAPHY
:
2349 struct layout_range_iface
*effect
= heap_alloc(sizeof(*effect
));
2350 if (!effect
) return NULL
;
2352 *effect
= *(struct layout_range_iface
*)h
;
2354 IUnknown_AddRef(effect
->iface
);
2358 case LAYOUT_RANGE_SPACING
:
2360 struct layout_range_spacing
*spacing
= heap_alloc(sizeof(*spacing
));
2361 if (!spacing
) return NULL
;
2363 *spacing
= *(struct layout_range_spacing
*)h
;
2368 FIXME("unknown range kind %d\n", h
->kind
);
2376 static void free_layout_range(struct layout_range_header
*h
)
2383 case LAYOUT_RANGE_REGULAR
:
2385 struct layout_range
*range
= (struct layout_range
*)h
;
2388 IDWriteInlineObject_Release(range
->object
);
2389 if (range
->collection
)
2390 IDWriteFontCollection_Release(range
->collection
);
2391 heap_free(range
->fontfamily
);
2394 case LAYOUT_RANGE_EFFECT
:
2395 case LAYOUT_RANGE_TYPOGRAPHY
:
2397 struct layout_range_iface
*range
= (struct layout_range_iface
*)h
;
2399 IUnknown_Release(range
->iface
);
2409 static void free_layout_ranges_list(struct dwrite_textlayout
*layout
)
2411 struct layout_range_header
*cur
, *cur2
;
2413 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->ranges
, struct layout_range_header
, entry
) {
2414 list_remove(&cur
->entry
);
2415 free_layout_range(cur
);
2418 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->underline_ranges
, struct layout_range_header
, entry
) {
2419 list_remove(&cur
->entry
);
2420 free_layout_range(cur
);
2423 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->strike_ranges
, struct layout_range_header
, entry
) {
2424 list_remove(&cur
->entry
);
2425 free_layout_range(cur
);
2428 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->effects
, struct layout_range_header
, entry
) {
2429 list_remove(&cur
->entry
);
2430 free_layout_range(cur
);
2433 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->spacing
, struct layout_range_header
, entry
) {
2434 list_remove(&cur
->entry
);
2435 free_layout_range(cur
);
2438 LIST_FOR_EACH_ENTRY_SAFE(cur
, cur2
, &layout
->typographies
, struct layout_range_header
, entry
) {
2439 list_remove(&cur
->entry
);
2440 free_layout_range(cur
);
2444 static struct layout_range_header
*find_outer_range(struct list
*ranges
, const DWRITE_TEXT_RANGE
*range
)
2446 struct layout_range_header
*cur
;
2448 LIST_FOR_EACH_ENTRY(cur
, ranges
, struct layout_range_header
, entry
) {
2450 if (cur
->range
.startPosition
> range
->startPosition
)
2453 if ((cur
->range
.startPosition
+ cur
->range
.length
< range
->startPosition
+ range
->length
) &&
2454 (range
->startPosition
< cur
->range
.startPosition
+ cur
->range
.length
))
2456 if (cur
->range
.startPosition
+ cur
->range
.length
>= range
->startPosition
+ range
->length
)
2463 static struct layout_range
*get_layout_range_by_pos(struct dwrite_textlayout
*layout
, UINT32 pos
)
2465 struct layout_range
*cur
;
2467 LIST_FOR_EACH_ENTRY(cur
, &layout
->ranges
, struct layout_range
, h
.entry
) {
2468 DWRITE_TEXT_RANGE
*r
= &cur
->h
.range
;
2469 if (r
->startPosition
<= pos
&& pos
< r
->startPosition
+ r
->length
)
2476 static inline BOOL
set_layout_range_iface_attr(IUnknown
**dest
, IUnknown
*value
)
2478 if (*dest
== value
) return FALSE
;
2481 IUnknown_Release(*dest
);
2484 IUnknown_AddRef(*dest
);
2489 static BOOL
set_layout_range_attrval(struct layout_range_header
*h
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2491 struct layout_range_spacing
*dest_spacing
= (struct layout_range_spacing
*)h
;
2492 struct layout_range_iface
*dest_iface
= (struct layout_range_iface
*)h
;
2493 struct layout_range_bool
*dest_bool
= (struct layout_range_bool
*)h
;
2494 struct layout_range
*dest
= (struct layout_range
*)h
;
2496 BOOL changed
= FALSE
;
2499 case LAYOUT_RANGE_ATTR_WEIGHT
:
2500 changed
= dest
->weight
!= value
->u
.weight
;
2501 dest
->weight
= value
->u
.weight
;
2503 case LAYOUT_RANGE_ATTR_STYLE
:
2504 changed
= dest
->style
!= value
->u
.style
;
2505 dest
->style
= value
->u
.style
;
2507 case LAYOUT_RANGE_ATTR_STRETCH
:
2508 changed
= dest
->stretch
!= value
->u
.stretch
;
2509 dest
->stretch
= value
->u
.stretch
;
2511 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2512 changed
= dest
->fontsize
!= value
->u
.fontsize
;
2513 dest
->fontsize
= value
->u
.fontsize
;
2515 case LAYOUT_RANGE_ATTR_INLINE
:
2516 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->object
, (IUnknown
*)value
->u
.object
);
2518 case LAYOUT_RANGE_ATTR_EFFECT
:
2519 changed
= set_layout_range_iface_attr((IUnknown
**)&dest_iface
->iface
, (IUnknown
*)value
->u
.effect
);
2521 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2522 changed
= dest_bool
->value
!= value
->u
.underline
;
2523 dest_bool
->value
= value
->u
.underline
;
2525 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2526 changed
= dest_bool
->value
!= value
->u
.strikethrough
;
2527 dest_bool
->value
= value
->u
.strikethrough
;
2529 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2530 changed
= dest
->pair_kerning
!= value
->u
.pair_kerning
;
2531 dest
->pair_kerning
= value
->u
.pair_kerning
;
2533 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2534 changed
= set_layout_range_iface_attr((IUnknown
**)&dest
->collection
, (IUnknown
*)value
->u
.collection
);
2536 case LAYOUT_RANGE_ATTR_LOCALE
:
2537 changed
= strcmpiW(dest
->locale
, value
->u
.locale
) != 0;
2539 strcpyW(dest
->locale
, value
->u
.locale
);
2540 strlwrW(dest
->locale
);
2543 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2544 changed
= strcmpW(dest
->fontfamily
, value
->u
.fontfamily
) != 0;
2546 heap_free(dest
->fontfamily
);
2547 dest
->fontfamily
= heap_strdupW(value
->u
.fontfamily
);
2550 case LAYOUT_RANGE_ATTR_SPACING
:
2551 changed
= dest_spacing
->leading
!= value
->u
.spacing
.leading
||
2552 dest_spacing
->trailing
!= value
->u
.spacing
.trailing
||
2553 dest_spacing
->min_advance
!= value
->u
.spacing
.min_advance
;
2554 dest_spacing
->leading
= value
->u
.spacing
.leading
;
2555 dest_spacing
->trailing
= value
->u
.spacing
.trailing
;
2556 dest_spacing
->min_advance
= value
->u
.spacing
.min_advance
;
2558 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2559 changed
= set_layout_range_iface_attr((IUnknown
**)&dest_iface
->iface
, (IUnknown
*)value
->u
.typography
);
2568 static inline BOOL
is_in_layout_range(const DWRITE_TEXT_RANGE
*outer
, const DWRITE_TEXT_RANGE
*inner
)
2570 return (inner
->startPosition
>= outer
->startPosition
) &&
2571 (inner
->startPosition
+ inner
->length
<= outer
->startPosition
+ outer
->length
);
2574 static inline HRESULT
return_range(const struct layout_range_header
*h
, DWRITE_TEXT_RANGE
*r
)
2576 if (r
) *r
= h
->range
;
2580 /* Sets attribute value for given range, does all needed splitting/merging of existing ranges. */
2581 static HRESULT
set_layout_range_attr(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind attr
, struct layout_range_attr_value
*value
)
2583 struct layout_range_header
*cur
, *right
, *left
, *outer
;
2584 BOOL changed
= FALSE
;
2585 struct list
*ranges
;
2586 DWRITE_TEXT_RANGE r
;
2588 /* ignore zero length ranges */
2589 if (value
->range
.length
== 0)
2592 /* select from ranges lists */
2595 case LAYOUT_RANGE_ATTR_WEIGHT
:
2596 case LAYOUT_RANGE_ATTR_STYLE
:
2597 case LAYOUT_RANGE_ATTR_STRETCH
:
2598 case LAYOUT_RANGE_ATTR_FONTSIZE
:
2599 case LAYOUT_RANGE_ATTR_INLINE
:
2600 case LAYOUT_RANGE_ATTR_PAIR_KERNING
:
2601 case LAYOUT_RANGE_ATTR_FONTCOLL
:
2602 case LAYOUT_RANGE_ATTR_LOCALE
:
2603 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2604 ranges
= &layout
->ranges
;
2606 case LAYOUT_RANGE_ATTR_UNDERLINE
:
2607 ranges
= &layout
->underline_ranges
;
2609 case LAYOUT_RANGE_ATTR_STRIKETHROUGH
:
2610 ranges
= &layout
->strike_ranges
;
2612 case LAYOUT_RANGE_ATTR_EFFECT
:
2613 ranges
= &layout
->effects
;
2615 case LAYOUT_RANGE_ATTR_SPACING
:
2616 ranges
= &layout
->spacing
;
2618 case LAYOUT_RANGE_ATTR_TYPOGRAPHY
:
2619 ranges
= &layout
->typographies
;
2622 FIXME("unknown attr kind %d\n", attr
);
2626 /* If new range is completely within existing range, split existing range in two */
2627 if ((outer
= find_outer_range(ranges
, &value
->range
))) {
2629 /* no need to add same range */
2630 if (is_same_layout_attrvalue(outer
, attr
, value
))
2633 /* for matching range bounds just replace data */
2634 if (is_same_text_range(&outer
->range
, &value
->range
)) {
2635 changed
= set_layout_range_attrval(outer
, attr
, value
);
2639 /* add new range to the left */
2640 if (value
->range
.startPosition
== outer
->range
.startPosition
) {
2641 left
= alloc_layout_range_from(outer
, &value
->range
);
2642 if (!left
) return E_OUTOFMEMORY
;
2644 changed
= set_layout_range_attrval(left
, attr
, value
);
2645 list_add_before(&outer
->entry
, &left
->entry
);
2646 outer
->range
.startPosition
+= value
->range
.length
;
2647 outer
->range
.length
-= value
->range
.length
;
2651 /* add new range to the right */
2652 if (value
->range
.startPosition
+ value
->range
.length
== outer
->range
.startPosition
+ outer
->range
.length
) {
2653 right
= alloc_layout_range_from(outer
, &value
->range
);
2654 if (!right
) return E_OUTOFMEMORY
;
2656 changed
= set_layout_range_attrval(right
, attr
, value
);
2657 list_add_after(&outer
->entry
, &right
->entry
);
2658 outer
->range
.length
-= value
->range
.length
;
2662 r
.startPosition
= value
->range
.startPosition
+ value
->range
.length
;
2663 r
.length
= outer
->range
.length
+ outer
->range
.startPosition
- r
.startPosition
;
2666 right
= alloc_layout_range_from(outer
, &r
);
2667 /* new range in the middle */
2668 cur
= alloc_layout_range_from(outer
, &value
->range
);
2669 if (!right
|| !cur
) {
2670 free_layout_range(right
);
2671 free_layout_range(cur
);
2672 return E_OUTOFMEMORY
;
2675 /* reuse container range as a left part */
2676 outer
->range
.length
= value
->range
.startPosition
- outer
->range
.startPosition
;
2679 set_layout_range_attrval(cur
, attr
, value
);
2681 list_add_after(&outer
->entry
, &cur
->entry
);
2682 list_add_after(&cur
->entry
, &right
->entry
);
2684 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2688 /* Now it's only possible that given range contains some existing ranges, fully or partially.
2689 Update all of them. */
2690 left
= get_layout_range_header_by_pos(ranges
, value
->range
.startPosition
);
2691 if (left
->range
.startPosition
== value
->range
.startPosition
)
2692 changed
= set_layout_range_attrval(left
, attr
, value
);
2693 else /* need to split */ {
2694 r
.startPosition
= value
->range
.startPosition
;
2695 r
.length
= left
->range
.length
- value
->range
.startPosition
+ left
->range
.startPosition
;
2696 left
->range
.length
-= r
.length
;
2697 cur
= alloc_layout_range_from(left
, &r
);
2698 changed
= set_layout_range_attrval(cur
, attr
, value
);
2699 list_add_after(&left
->entry
, &cur
->entry
);
2701 cur
= LIST_ENTRY(list_next(ranges
, &left
->entry
), struct layout_range_header
, entry
);
2703 /* for all existing ranges covered by new one update value */
2704 while (cur
&& is_in_layout_range(&value
->range
, &cur
->range
)) {
2705 changed
|= set_layout_range_attrval(cur
, attr
, value
);
2706 cur
= LIST_ENTRY(list_next(ranges
, &cur
->entry
), struct layout_range_header
, entry
);
2709 /* it's possible rightmost range intersects */
2710 if (cur
&& (cur
->range
.startPosition
< value
->range
.startPosition
+ value
->range
.length
)) {
2711 r
.startPosition
= cur
->range
.startPosition
;
2712 r
.length
= value
->range
.startPosition
+ value
->range
.length
- cur
->range
.startPosition
;
2713 left
= alloc_layout_range_from(cur
, &r
);
2714 changed
|= set_layout_range_attrval(left
, attr
, value
);
2715 cur
->range
.startPosition
+= left
->range
.length
;
2716 cur
->range
.length
-= left
->range
.length
;
2717 list_add_before(&cur
->entry
, &left
->entry
);
2722 struct list
*next
, *i
;
2724 layout
->recompute
= RECOMPUTE_EVERYTHING
;
2725 i
= list_head(ranges
);
2726 while ((next
= list_next(ranges
, i
))) {
2727 struct layout_range_header
*next_range
= LIST_ENTRY(next
, struct layout_range_header
, entry
);
2729 cur
= LIST_ENTRY(i
, struct layout_range_header
, entry
);
2730 if (is_same_layout_attributes(cur
, next_range
)) {
2731 /* remove similar range */
2732 cur
->range
.length
+= next_range
->range
.length
;
2734 free_layout_range(next_range
);
2737 i
= list_next(ranges
, i
);
2744 static inline const WCHAR
*get_string_attribute_ptr(struct layout_range
*range
, enum layout_range_attr_kind kind
)
2749 case LAYOUT_RANGE_ATTR_LOCALE
:
2750 str
= range
->locale
;
2752 case LAYOUT_RANGE_ATTR_FONTFAMILY
:
2753 str
= range
->fontfamily
;
2762 static HRESULT
get_string_attribute_length(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2763 UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
2765 struct layout_range
*range
;
2768 range
= get_layout_range_by_pos(layout
, position
);
2774 str
= get_string_attribute_ptr(range
, kind
);
2775 *length
= strlenW(str
);
2776 return return_range(&range
->h
, r
);
2779 static HRESULT
get_string_attribute_value(struct dwrite_textlayout
*layout
, enum layout_range_attr_kind kind
, UINT32 position
,
2780 WCHAR
*ret
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
2782 struct layout_range
*range
;
2786 return E_INVALIDARG
;
2789 range
= get_layout_range_by_pos(layout
, position
);
2791 return E_INVALIDARG
;
2793 str
= get_string_attribute_ptr(range
, kind
);
2794 if (length
< strlenW(str
) + 1)
2795 return E_NOT_SUFFICIENT_BUFFER
;
2798 return return_range(&range
->h
, r
);
2801 static HRESULT WINAPI
dwritetextlayout_QueryInterface(IDWriteTextLayout3
*iface
, REFIID riid
, void **obj
)
2803 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2805 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
2809 if (IsEqualIID(riid
, &IID_IDWriteTextLayout3
) ||
2810 IsEqualIID(riid
, &IID_IDWriteTextLayout2
) ||
2811 IsEqualIID(riid
, &IID_IDWriteTextLayout1
) ||
2812 IsEqualIID(riid
, &IID_IDWriteTextLayout
) ||
2813 IsEqualIID(riid
, &IID_IUnknown
))
2817 else if (IsEqualIID(riid
, &IID_IDWriteTextFormat2
) ||
2818 IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
2819 IsEqualIID(riid
, &IID_IDWriteTextFormat
))
2820 *obj
= &This
->IDWriteTextFormat2_iface
;
2823 IDWriteTextLayout3_AddRef(iface
);
2827 WARN("%s not implemented.\n", debugstr_guid(riid
));
2829 return E_NOINTERFACE
;
2832 static ULONG WINAPI
dwritetextlayout_AddRef(IDWriteTextLayout3
*iface
)
2834 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2835 ULONG ref
= InterlockedIncrement(&This
->ref
);
2836 TRACE("(%p)->(%d)\n", This
, ref
);
2840 static ULONG WINAPI
dwritetextlayout_Release(IDWriteTextLayout3
*iface
)
2842 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2843 ULONG ref
= InterlockedDecrement(&This
->ref
);
2845 TRACE("(%p)->(%d)\n", This
, ref
);
2848 IDWriteFactory5_Release(This
->factory
);
2849 free_layout_ranges_list(This
);
2850 free_layout_eruns(This
);
2851 free_layout_runs(This
);
2852 release_format_data(&This
->format
);
2853 heap_free(This
->nominal_breakpoints
);
2854 heap_free(This
->actual_breakpoints
);
2855 heap_free(This
->clustermetrics
);
2856 heap_free(This
->clusters
);
2857 heap_free(This
->linemetrics
);
2858 heap_free(This
->lines
);
2859 heap_free(This
->str
);
2866 static HRESULT WINAPI
dwritetextlayout_SetTextAlignment(IDWriteTextLayout3
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
2868 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2869 return IDWriteTextFormat2_SetTextAlignment(&This
->IDWriteTextFormat2_iface
, alignment
);
2872 static HRESULT WINAPI
dwritetextlayout_SetParagraphAlignment(IDWriteTextLayout3
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
2874 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2875 return IDWriteTextFormat2_SetParagraphAlignment(&This
->IDWriteTextFormat2_iface
, alignment
);
2878 static HRESULT WINAPI
dwritetextlayout_SetWordWrapping(IDWriteTextLayout3
*iface
, DWRITE_WORD_WRAPPING wrapping
)
2880 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2881 return IDWriteTextFormat2_SetWordWrapping(&This
->IDWriteTextFormat2_iface
, wrapping
);
2884 static HRESULT WINAPI
dwritetextlayout_SetReadingDirection(IDWriteTextLayout3
*iface
, DWRITE_READING_DIRECTION direction
)
2886 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2887 return IDWriteTextFormat2_SetReadingDirection(&This
->IDWriteTextFormat2_iface
, direction
);
2890 static HRESULT WINAPI
dwritetextlayout_SetFlowDirection(IDWriteTextLayout3
*iface
, DWRITE_FLOW_DIRECTION direction
)
2892 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2893 TRACE("(%p)->(%d)\n", This
, direction
);
2894 return IDWriteTextFormat2_SetFlowDirection(&This
->IDWriteTextFormat2_iface
, direction
);
2897 static HRESULT WINAPI
dwritetextlayout_SetIncrementalTabStop(IDWriteTextLayout3
*iface
, FLOAT tabstop
)
2899 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2900 TRACE("(%p)->(%.2f)\n", This
, tabstop
);
2901 return IDWriteTextFormat2_SetIncrementalTabStop(&This
->IDWriteTextFormat2_iface
, tabstop
);
2904 static HRESULT WINAPI
dwritetextlayout_SetTrimming(IDWriteTextLayout3
*iface
, DWRITE_TRIMMING
const *trimming
,
2905 IDWriteInlineObject
*trimming_sign
)
2907 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2908 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
2909 return IDWriteTextFormat2_SetTrimming(&This
->IDWriteTextFormat2_iface
, trimming
, trimming_sign
);
2912 static HRESULT WINAPI
dwritetextlayout_SetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING_METHOD spacing
,
2913 FLOAT line_spacing
, FLOAT baseline
)
2915 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2916 TRACE("(%p)->(%d %.2f %.2f)\n", This
, spacing
, line_spacing
, baseline
);
2917 return IDWriteTextFormat1_SetLineSpacing((IDWriteTextFormat1
*)&This
->IDWriteTextFormat2_iface
, spacing
,
2918 line_spacing
, baseline
);
2921 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextlayout_GetTextAlignment(IDWriteTextLayout3
*iface
)
2923 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2924 return IDWriteTextFormat2_GetTextAlignment(&This
->IDWriteTextFormat2_iface
);
2927 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextlayout_GetParagraphAlignment(IDWriteTextLayout3
*iface
)
2929 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2930 return IDWriteTextFormat2_GetParagraphAlignment(&This
->IDWriteTextFormat2_iface
);
2933 static DWRITE_WORD_WRAPPING WINAPI
dwritetextlayout_GetWordWrapping(IDWriteTextLayout3
*iface
)
2935 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2936 return IDWriteTextFormat2_GetWordWrapping(&This
->IDWriteTextFormat2_iface
);
2939 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_GetReadingDirection(IDWriteTextLayout3
*iface
)
2941 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2942 return IDWriteTextFormat2_GetReadingDirection(&This
->IDWriteTextFormat2_iface
);
2945 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextlayout_GetFlowDirection(IDWriteTextLayout3
*iface
)
2947 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2948 return IDWriteTextFormat2_GetFlowDirection(&This
->IDWriteTextFormat2_iface
);
2951 static FLOAT WINAPI
dwritetextlayout_GetIncrementalTabStop(IDWriteTextLayout3
*iface
)
2953 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2954 return IDWriteTextFormat2_GetIncrementalTabStop(&This
->IDWriteTextFormat2_iface
);
2957 static HRESULT WINAPI
dwritetextlayout_GetTrimming(IDWriteTextLayout3
*iface
, DWRITE_TRIMMING
*options
,
2958 IDWriteInlineObject
**trimming_sign
)
2960 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2961 return IDWriteTextFormat2_GetTrimming(&This
->IDWriteTextFormat2_iface
, options
, trimming_sign
);
2964 static HRESULT WINAPI
dwritetextlayout_GetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
2965 FLOAT
*spacing
, FLOAT
*baseline
)
2967 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2968 return IDWriteTextFormat_GetLineSpacing((IDWriteTextFormat
*)&This
->IDWriteTextFormat2_iface
, method
,
2972 static HRESULT WINAPI
dwritetextlayout_GetFontCollection(IDWriteTextLayout3
*iface
, IDWriteFontCollection
**collection
)
2974 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2975 return IDWriteTextFormat2_GetFontCollection(&This
->IDWriteTextFormat2_iface
, collection
);
2978 static UINT32 WINAPI
dwritetextlayout_GetFontFamilyNameLength(IDWriteTextLayout3
*iface
)
2980 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2981 return IDWriteTextFormat2_GetFontFamilyNameLength(&This
->IDWriteTextFormat2_iface
);
2984 static HRESULT WINAPI
dwritetextlayout_GetFontFamilyName(IDWriteTextLayout3
*iface
, WCHAR
*name
, UINT32 size
)
2986 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2987 return IDWriteTextFormat2_GetFontFamilyName(&This
->IDWriteTextFormat2_iface
, name
, size
);
2990 static DWRITE_FONT_WEIGHT WINAPI
dwritetextlayout_GetFontWeight(IDWriteTextLayout3
*iface
)
2992 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2993 return IDWriteTextFormat2_GetFontWeight(&This
->IDWriteTextFormat2_iface
);
2996 static DWRITE_FONT_STYLE WINAPI
dwritetextlayout_GetFontStyle(IDWriteTextLayout3
*iface
)
2998 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
2999 return IDWriteTextFormat2_GetFontStyle(&This
->IDWriteTextFormat2_iface
);
3002 static DWRITE_FONT_STRETCH WINAPI
dwritetextlayout_GetFontStretch(IDWriteTextLayout3
*iface
)
3004 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3005 return IDWriteTextFormat2_GetFontStretch(&This
->IDWriteTextFormat2_iface
);
3008 static FLOAT WINAPI
dwritetextlayout_GetFontSize(IDWriteTextLayout3
*iface
)
3010 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3011 return IDWriteTextFormat2_GetFontSize(&This
->IDWriteTextFormat2_iface
);
3014 static UINT32 WINAPI
dwritetextlayout_GetLocaleNameLength(IDWriteTextLayout3
*iface
)
3016 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3017 return IDWriteTextFormat2_GetLocaleNameLength(&This
->IDWriteTextFormat2_iface
);
3020 static HRESULT WINAPI
dwritetextlayout_GetLocaleName(IDWriteTextLayout3
*iface
, WCHAR
*name
, UINT32 size
)
3022 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3023 return IDWriteTextFormat2_GetLocaleName(&This
->IDWriteTextFormat2_iface
, name
, size
);
3026 static HRESULT WINAPI
dwritetextlayout_SetMaxWidth(IDWriteTextLayout3
*iface
, FLOAT maxWidth
)
3028 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3031 TRACE("(%p)->(%.2f)\n", This
, maxWidth
);
3033 if (maxWidth
< 0.0f
)
3034 return E_INVALIDARG
;
3036 changed
= This
->metrics
.layoutWidth
!= maxWidth
;
3037 This
->metrics
.layoutWidth
= maxWidth
;
3040 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3044 static HRESULT WINAPI
dwritetextlayout_SetMaxHeight(IDWriteTextLayout3
*iface
, FLOAT maxHeight
)
3046 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3049 TRACE("(%p)->(%.2f)\n", This
, maxHeight
);
3051 if (maxHeight
< 0.0f
)
3052 return E_INVALIDARG
;
3054 changed
= This
->metrics
.layoutHeight
!= maxHeight
;
3055 This
->metrics
.layoutHeight
= maxHeight
;
3058 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
3062 static HRESULT WINAPI
dwritetextlayout_SetFontCollection(IDWriteTextLayout3
*iface
, IDWriteFontCollection
* collection
, DWRITE_TEXT_RANGE range
)
3064 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3065 struct layout_range_attr_value value
;
3067 TRACE("(%p)->(%p %s)\n", This
, collection
, debugstr_range(&range
));
3069 value
.range
= range
;
3070 value
.u
.collection
= collection
;
3071 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTCOLL
, &value
);
3074 static HRESULT WINAPI
dwritetextlayout_SetFontFamilyName(IDWriteTextLayout3
*iface
, WCHAR
const *name
, DWRITE_TEXT_RANGE range
)
3076 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3077 struct layout_range_attr_value value
;
3079 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(name
), debugstr_range(&range
));
3082 return E_INVALIDARG
;
3084 value
.range
= range
;
3085 value
.u
.fontfamily
= name
;
3086 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, &value
);
3089 static HRESULT WINAPI
dwritetextlayout_SetFontWeight(IDWriteTextLayout3
*iface
, DWRITE_FONT_WEIGHT weight
, DWRITE_TEXT_RANGE range
)
3091 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3092 struct layout_range_attr_value value
;
3094 TRACE("(%p)->(%d %s)\n", This
, weight
, debugstr_range(&range
));
3096 if ((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
)
3097 return E_INVALIDARG
;
3099 value
.range
= range
;
3100 value
.u
.weight
= weight
;
3101 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_WEIGHT
, &value
);
3104 static HRESULT WINAPI
dwritetextlayout_SetFontStyle(IDWriteTextLayout3
*iface
, DWRITE_FONT_STYLE style
, DWRITE_TEXT_RANGE range
)
3106 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3107 struct layout_range_attr_value value
;
3109 TRACE("(%p)->(%d %s)\n", This
, style
, debugstr_range(&range
));
3111 if ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
)
3112 return E_INVALIDARG
;
3114 value
.range
= range
;
3115 value
.u
.style
= style
;
3116 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STYLE
, &value
);
3119 static HRESULT WINAPI
dwritetextlayout_SetFontStretch(IDWriteTextLayout3
*iface
, DWRITE_FONT_STRETCH stretch
, DWRITE_TEXT_RANGE range
)
3121 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3122 struct layout_range_attr_value value
;
3124 TRACE("(%p)->(%d %s)\n", This
, stretch
, debugstr_range(&range
));
3126 if (stretch
== DWRITE_FONT_STRETCH_UNDEFINED
|| (UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
)
3127 return E_INVALIDARG
;
3129 value
.range
= range
;
3130 value
.u
.stretch
= stretch
;
3131 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRETCH
, &value
);
3134 static HRESULT WINAPI
dwritetextlayout_SetFontSize(IDWriteTextLayout3
*iface
, FLOAT size
, DWRITE_TEXT_RANGE range
)
3136 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3137 struct layout_range_attr_value value
;
3139 TRACE("(%p)->(%.2f %s)\n", This
, size
, debugstr_range(&range
));
3142 return E_INVALIDARG
;
3144 value
.range
= range
;
3145 value
.u
.fontsize
= size
;
3146 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_FONTSIZE
, &value
);
3149 static HRESULT WINAPI
dwritetextlayout_SetUnderline(IDWriteTextLayout3
*iface
, BOOL underline
, DWRITE_TEXT_RANGE range
)
3151 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3152 struct layout_range_attr_value value
;
3154 TRACE("(%p)->(%d %s)\n", This
, underline
, debugstr_range(&range
));
3156 value
.range
= range
;
3157 value
.u
.underline
= underline
;
3158 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_UNDERLINE
, &value
);
3161 static HRESULT WINAPI
dwritetextlayout_SetStrikethrough(IDWriteTextLayout3
*iface
, BOOL strikethrough
, DWRITE_TEXT_RANGE range
)
3163 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3164 struct layout_range_attr_value value
;
3166 TRACE("(%p)->(%d %s)\n", This
, strikethrough
, debugstr_range(&range
));
3168 value
.range
= range
;
3169 value
.u
.strikethrough
= strikethrough
;
3170 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_STRIKETHROUGH
, &value
);
3173 static HRESULT WINAPI
dwritetextlayout_SetDrawingEffect(IDWriteTextLayout3
*iface
, IUnknown
* effect
, DWRITE_TEXT_RANGE range
)
3175 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3176 struct layout_range_attr_value value
;
3178 TRACE("(%p)->(%p %s)\n", This
, effect
, debugstr_range(&range
));
3180 value
.range
= range
;
3181 value
.u
.effect
= effect
;
3182 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_EFFECT
, &value
);
3185 static HRESULT WINAPI
dwritetextlayout_SetInlineObject(IDWriteTextLayout3
*iface
, IDWriteInlineObject
*object
, DWRITE_TEXT_RANGE range
)
3187 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3188 struct layout_range_attr_value value
;
3190 TRACE("(%p)->(%p %s)\n", This
, object
, debugstr_range(&range
));
3192 value
.range
= range
;
3193 value
.u
.object
= object
;
3194 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_INLINE
, &value
);
3197 static HRESULT WINAPI
dwritetextlayout_SetTypography(IDWriteTextLayout3
*iface
, IDWriteTypography
* typography
, DWRITE_TEXT_RANGE range
)
3199 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3200 struct layout_range_attr_value value
;
3202 TRACE("(%p)->(%p %s)\n", This
, typography
, debugstr_range(&range
));
3204 value
.range
= range
;
3205 value
.u
.typography
= typography
;
3206 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_TYPOGRAPHY
, &value
);
3209 static HRESULT WINAPI
dwritetextlayout_SetLocaleName(IDWriteTextLayout3
*iface
, WCHAR
const* locale
, DWRITE_TEXT_RANGE range
)
3211 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3212 struct layout_range_attr_value value
;
3214 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(locale
), debugstr_range(&range
));
3216 if (!locale
|| strlenW(locale
) > LOCALE_NAME_MAX_LENGTH
-1)
3217 return E_INVALIDARG
;
3219 value
.range
= range
;
3220 value
.u
.locale
= locale
;
3221 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_LOCALE
, &value
);
3224 static FLOAT WINAPI
dwritetextlayout_GetMaxWidth(IDWriteTextLayout3
*iface
)
3226 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3227 TRACE("(%p)\n", This
);
3228 return This
->metrics
.layoutWidth
;
3231 static FLOAT WINAPI
dwritetextlayout_GetMaxHeight(IDWriteTextLayout3
*iface
)
3233 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3234 TRACE("(%p)\n", This
);
3235 return This
->metrics
.layoutHeight
;
3238 static HRESULT WINAPI
dwritetextlayout_layout_GetFontCollection(IDWriteTextLayout3
*iface
, UINT32 position
,
3239 IDWriteFontCollection
** collection
, DWRITE_TEXT_RANGE
*r
)
3241 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3242 struct layout_range
*range
;
3244 TRACE("(%p)->(%u %p %p)\n", This
, position
, collection
, r
);
3246 if (position
>= This
->len
)
3249 range
= get_layout_range_by_pos(This
, position
);
3250 *collection
= range
->collection
;
3252 IDWriteFontCollection_AddRef(*collection
);
3254 return return_range(&range
->h
, r
);
3257 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyNameLength(IDWriteTextLayout3
*iface
,
3258 UINT32 position
, UINT32
*length
, DWRITE_TEXT_RANGE
*r
)
3260 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3261 TRACE("(%p)->(%d %p %p)\n", This
, position
, length
, r
);
3262 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, length
, r
);
3265 static HRESULT WINAPI
dwritetextlayout_layout_GetFontFamilyName(IDWriteTextLayout3
*iface
,
3266 UINT32 position
, WCHAR
*name
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3268 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3269 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, name
, length
, r
);
3270 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_FONTFAMILY
, position
, name
, length
, r
);
3273 static HRESULT WINAPI
dwritetextlayout_layout_GetFontWeight(IDWriteTextLayout3
*iface
,
3274 UINT32 position
, DWRITE_FONT_WEIGHT
*weight
, DWRITE_TEXT_RANGE
*r
)
3276 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3277 struct layout_range
*range
;
3279 TRACE("(%p)->(%u %p %p)\n", This
, position
, weight
, r
);
3281 if (position
>= This
->len
)
3284 range
= get_layout_range_by_pos(This
, position
);
3285 *weight
= range
->weight
;
3287 return return_range(&range
->h
, r
);
3290 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStyle(IDWriteTextLayout3
*iface
,
3291 UINT32 position
, DWRITE_FONT_STYLE
*style
, DWRITE_TEXT_RANGE
*r
)
3293 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3294 struct layout_range
*range
;
3296 TRACE("(%p)->(%u %p %p)\n", This
, position
, style
, r
);
3298 range
= get_layout_range_by_pos(This
, position
);
3299 *style
= range
->style
;
3300 return return_range(&range
->h
, r
);
3303 static HRESULT WINAPI
dwritetextlayout_layout_GetFontStretch(IDWriteTextLayout3
*iface
,
3304 UINT32 position
, DWRITE_FONT_STRETCH
*stretch
, DWRITE_TEXT_RANGE
*r
)
3306 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3307 struct layout_range
*range
;
3309 TRACE("(%p)->(%u %p %p)\n", This
, position
, stretch
, r
);
3311 range
= get_layout_range_by_pos(This
, position
);
3312 *stretch
= range
->stretch
;
3313 return return_range(&range
->h
, r
);
3316 static HRESULT WINAPI
dwritetextlayout_layout_GetFontSize(IDWriteTextLayout3
*iface
,
3317 UINT32 position
, FLOAT
*size
, DWRITE_TEXT_RANGE
*r
)
3319 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3320 struct layout_range
*range
;
3322 TRACE("(%p)->(%u %p %p)\n", This
, position
, size
, r
);
3324 range
= get_layout_range_by_pos(This
, position
);
3325 *size
= range
->fontsize
;
3326 return return_range(&range
->h
, r
);
3329 static HRESULT WINAPI
dwritetextlayout_GetUnderline(IDWriteTextLayout3
*iface
,
3330 UINT32 position
, BOOL
*underline
, DWRITE_TEXT_RANGE
*r
)
3332 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3333 struct layout_range_bool
*range
;
3335 TRACE("(%p)->(%u %p %p)\n", This
, position
, underline
, r
);
3337 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->underline_ranges
, position
);
3338 *underline
= range
->value
;
3340 return return_range(&range
->h
, r
);
3343 static HRESULT WINAPI
dwritetextlayout_GetStrikethrough(IDWriteTextLayout3
*iface
,
3344 UINT32 position
, BOOL
*strikethrough
, DWRITE_TEXT_RANGE
*r
)
3346 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3347 struct layout_range_bool
*range
;
3349 TRACE("(%p)->(%u %p %p)\n", This
, position
, strikethrough
, r
);
3351 range
= (struct layout_range_bool
*)get_layout_range_header_by_pos(&This
->strike_ranges
, position
);
3352 *strikethrough
= range
->value
;
3354 return return_range(&range
->h
, r
);
3357 static HRESULT WINAPI
dwritetextlayout_GetDrawingEffect(IDWriteTextLayout3
*iface
,
3358 UINT32 position
, IUnknown
**effect
, DWRITE_TEXT_RANGE
*r
)
3360 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3361 struct layout_range_iface
*range
;
3363 TRACE("(%p)->(%u %p %p)\n", This
, position
, effect
, r
);
3365 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&This
->effects
, position
);
3366 *effect
= range
->iface
;
3368 IUnknown_AddRef(*effect
);
3370 return return_range(&range
->h
, r
);
3373 static HRESULT WINAPI
dwritetextlayout_GetInlineObject(IDWriteTextLayout3
*iface
,
3374 UINT32 position
, IDWriteInlineObject
**object
, DWRITE_TEXT_RANGE
*r
)
3376 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3377 struct layout_range
*range
;
3379 TRACE("(%p)->(%u %p %p)\n", This
, position
, object
, r
);
3381 if (position
>= This
->len
)
3384 range
= get_layout_range_by_pos(This
, position
);
3385 *object
= range
->object
;
3387 IDWriteInlineObject_AddRef(*object
);
3389 return return_range(&range
->h
, r
);
3392 static HRESULT WINAPI
dwritetextlayout_GetTypography(IDWriteTextLayout3
*iface
,
3393 UINT32 position
, IDWriteTypography
** typography
, DWRITE_TEXT_RANGE
*r
)
3395 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3396 struct layout_range_iface
*range
;
3398 TRACE("(%p)->(%u %p %p)\n", This
, position
, typography
, r
);
3400 range
= (struct layout_range_iface
*)get_layout_range_header_by_pos(&This
->typographies
, position
);
3401 *typography
= (IDWriteTypography
*)range
->iface
;
3403 IDWriteTypography_AddRef(*typography
);
3405 return return_range(&range
->h
, r
);
3408 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleNameLength(IDWriteTextLayout3
*iface
,
3409 UINT32 position
, UINT32
* length
, DWRITE_TEXT_RANGE
*r
)
3411 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3412 TRACE("(%p)->(%u %p %p)\n", This
, position
, length
, r
);
3413 return get_string_attribute_length(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, length
, r
);
3416 static HRESULT WINAPI
dwritetextlayout_layout_GetLocaleName(IDWriteTextLayout3
*iface
,
3417 UINT32 position
, WCHAR
* locale
, UINT32 length
, DWRITE_TEXT_RANGE
*r
)
3419 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3420 TRACE("(%p)->(%u %p %u %p)\n", This
, position
, locale
, length
, r
);
3421 return get_string_attribute_value(This
, LAYOUT_RANGE_ATTR_LOCALE
, position
, locale
, length
, r
);
3424 static inline FLOAT
renderer_apply_snapping(FLOAT coord
, BOOL skiptransform
, FLOAT ppdip
, FLOAT det
,
3425 const DWRITE_MATRIX
*m
)
3427 D2D1_POINT_2F vec
, vec2
;
3429 if (!skiptransform
) {
3430 /* apply transform */
3432 vec
.y
= coord
* ppdip
;
3434 vec2
.x
= m
->m11
* vec
.x
+ m
->m21
* vec
.y
+ m
->dx
;
3435 vec2
.y
= m
->m12
* vec
.x
+ m
->m22
* vec
.y
+ m
->dy
;
3438 vec2
.x
= floorf(vec2
.x
+ 0.5f
);
3439 vec2
.y
= floorf(vec2
.y
+ 0.5f
);
3441 /* apply inverted transform, we don't care about X component at this point */
3442 vec
.y
= (-m
->m12
* vec2
.x
+ m
->m11
* vec2
.y
- (m
->m11
* m
->dy
- m
->m12
* m
->dx
)) / det
;
3446 vec
.y
= floorf(coord
* ppdip
+ 0.5f
) / ppdip
;
3451 static HRESULT WINAPI
dwritetextlayout_Draw(IDWriteTextLayout3
*iface
,
3452 void *context
, IDWriteTextRenderer
* renderer
, FLOAT origin_x
, FLOAT origin_y
)
3454 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3455 BOOL disabled
= FALSE
, skiptransform
= FALSE
;
3456 struct layout_effective_inline
*inlineobject
;
3457 struct layout_effective_run
*run
;
3458 struct layout_strikethrough
*s
;
3459 struct layout_underline
*u
;
3460 FLOAT det
= 0.0f
, ppdip
= 0.0f
;
3461 DWRITE_MATRIX m
= { 0 };
3464 TRACE("(%p)->(%p %p %.2f %.2f)\n", This
, context
, renderer
, origin_x
, origin_y
);
3466 hr
= layout_compute_effective_runs(This
);
3470 hr
= IDWriteTextRenderer_IsPixelSnappingDisabled(renderer
, context
, &disabled
);
3475 hr
= IDWriteTextRenderer_GetPixelsPerDip(renderer
, context
, &ppdip
);
3479 hr
= IDWriteTextRenderer_GetCurrentTransform(renderer
, context
, &m
);
3483 /* it's only allowed to have a diagonal/antidiagonal transform matrix */
3484 if (ppdip
<= 0.0f
||
3485 (m
.m11
* m
.m22
!= 0.0f
&& (m
.m12
!= 0.0f
|| m
.m21
!= 0.0f
)) ||
3486 (m
.m12
* m
.m21
!= 0.0f
&& (m
.m11
!= 0.0f
|| m
.m22
!= 0.0f
)))
3489 skiptransform
= should_skip_transform(&m
, &det
);
3492 #define SNAP_COORD(x) (disabled ? (x) : renderer_apply_snapping((x), skiptransform, ppdip, det, &m))
3493 /* 1. Regular runs */
3494 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
3495 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3496 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3497 DWRITE_GLYPH_RUN_DESCRIPTION descr
;
3498 DWRITE_GLYPH_RUN glyph_run
;
3500 /* Everything but cluster map will be reused from nominal run, as we only need
3501 to adjust some pointers. Cluster map however is rebuilt when effective run is added,
3502 it can't be reused because it has to start with 0 index for each reported run. */
3503 glyph_run
= regular
->run
;
3504 glyph_run
.glyphCount
= run
->glyphcount
;
3506 /* fixup glyph data arrays */
3507 glyph_run
.glyphIndices
+= start_glyph
;
3508 glyph_run
.glyphAdvances
+= start_glyph
;
3509 glyph_run
.glyphOffsets
+= start_glyph
;
3512 descr
= regular
->descr
;
3513 descr
.stringLength
= run
->length
;
3514 descr
.string
+= run
->start
;
3515 descr
.clusterMap
= run
->clustermap
;
3516 descr
.textPosition
+= run
->start
;
3518 /* return value is ignored */
3519 IDWriteTextRenderer_DrawGlyphRun(renderer
,
3521 run
->origin
.x
+ run
->align_dx
+ origin_x
,
3522 SNAP_COORD(run
->origin
.y
+ origin_y
),
3523 This
->measuringmode
,
3529 /* 2. Inline objects */
3530 LIST_FOR_EACH_ENTRY(inlineobject
, &This
->inlineobjects
, struct layout_effective_inline
, entry
) {
3531 IDWriteTextRenderer_DrawInlineObject(renderer
,
3533 inlineobject
->origin
.x
+ inlineobject
->align_dx
+ origin_x
,
3534 SNAP_COORD(inlineobject
->origin
.y
+ origin_y
),
3535 inlineobject
->object
,
3536 inlineobject
->is_sideways
,
3537 inlineobject
->is_rtl
,
3538 inlineobject
->effect
);
3542 LIST_FOR_EACH_ENTRY(u
, &This
->underlines
, struct layout_underline
, entry
) {
3543 IDWriteTextRenderer_DrawUnderline(renderer
,
3545 /* horizontal underline always grows from left to right, width is always added to origin regardless of run direction */
3546 (is_run_rtl(u
->run
) ? u
->run
->origin
.x
- u
->run
->width
: u
->run
->origin
.x
) + u
->run
->align_dx
+ origin_x
,
3547 SNAP_COORD(u
->run
->origin
.y
+ origin_y
),
3552 /* 4. Strikethrough */
3553 LIST_FOR_EACH_ENTRY(s
, &This
->strikethrough
, struct layout_strikethrough
, entry
) {
3554 IDWriteTextRenderer_DrawStrikethrough(renderer
,
3556 s
->run
->origin
.x
+ s
->run
->align_dx
+ origin_x
,
3557 SNAP_COORD(s
->run
->origin
.y
+ origin_y
),
3566 static HRESULT WINAPI
dwritetextlayout_GetLineMetrics(IDWriteTextLayout3
*iface
,
3567 DWRITE_LINE_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3569 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3572 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
3574 hr
= layout_compute_effective_runs(This
);
3579 UINT32 i
, c
= min(max_count
, This
->metrics
.lineCount
);
3580 for (i
= 0; i
< c
; i
++)
3581 memcpy(metrics
+ i
, This
->linemetrics
+ i
, sizeof(*metrics
));
3584 *count
= This
->metrics
.lineCount
;
3585 return max_count
>= This
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3588 static HRESULT WINAPI
dwritetextlayout_GetMetrics(IDWriteTextLayout3
*iface
, DWRITE_TEXT_METRICS
*metrics
)
3590 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3591 DWRITE_TEXT_METRICS1 metrics1
;
3594 TRACE("(%p)->(%p)\n", This
, metrics
);
3596 hr
= IDWriteTextLayout3_GetMetrics(iface
, &metrics1
);
3598 memcpy(metrics
, &metrics1
, sizeof(*metrics
));
3603 static void scale_glyph_bbox(RECT
*bbox
, FLOAT emSize
, UINT16 units_per_em
, D2D1_RECT_F
*ret
)
3605 #define SCALE(x) ((FLOAT)x * emSize / (FLOAT)units_per_em)
3606 ret
->left
= SCALE(bbox
->left
);
3607 ret
->right
= SCALE(bbox
->right
);
3608 ret
->top
= SCALE(bbox
->top
);
3609 ret
->bottom
= SCALE(bbox
->bottom
);
3613 static void d2d_rect_offset(D2D1_RECT_F
*rect
, FLOAT x
, FLOAT y
)
3621 static BOOL
d2d_rect_is_empty(const D2D1_RECT_F
*rect
)
3623 return ((rect
->left
>= rect
->right
) || (rect
->top
>= rect
->bottom
));
3626 static void d2d_rect_union(D2D1_RECT_F
*dst
, const D2D1_RECT_F
*src
)
3628 if (d2d_rect_is_empty(dst
)) {
3629 if (d2d_rect_is_empty(src
)) {
3630 dst
->left
= dst
->right
= dst
->top
= dst
->bottom
= 0.0f
;
3637 if (!d2d_rect_is_empty(src
)) {
3638 dst
->left
= min(dst
->left
, src
->left
);
3639 dst
->right
= max(dst
->right
, src
->right
);
3640 dst
->top
= min(dst
->top
, src
->top
);
3641 dst
->bottom
= max(dst
->bottom
, src
->bottom
);
3646 static void layout_get_erun_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_run
*run
, D2D1_RECT_F
*bbox
)
3648 const struct regular_layout_run
*regular
= &run
->run
->u
.regular
;
3649 UINT32 start_glyph
= regular
->clustermap
[run
->start
];
3650 const DWRITE_GLYPH_RUN
*glyph_run
= ®ular
->run
;
3651 DWRITE_FONT_METRICS font_metrics
;
3652 D2D1_POINT_2F origin
= { 0 };
3655 if (run
->bbox
.top
== run
->bbox
.bottom
) {
3656 IDWriteFontFace_GetMetrics(glyph_run
->fontFace
, &font_metrics
);
3658 for (i
= 0; i
< run
->glyphcount
; i
++) {
3659 D2D1_RECT_F glyph_bbox
;
3662 freetype_get_design_glyph_bbox((IDWriteFontFace4
*)glyph_run
->fontFace
, font_metrics
.designUnitsPerEm
,
3663 glyph_run
->glyphIndices
[i
+ start_glyph
], &design_bbox
);
3665 scale_glyph_bbox(&design_bbox
, glyph_run
->fontEmSize
, font_metrics
.designUnitsPerEm
, &glyph_bbox
);
3666 d2d_rect_offset(&glyph_bbox
, origin
.x
+ glyph_run
->glyphOffsets
[i
+ start_glyph
].advanceOffset
,
3667 origin
.y
+ glyph_run
->glyphOffsets
[i
+ start_glyph
].ascenderOffset
);
3668 d2d_rect_union(&run
->bbox
, &glyph_bbox
);
3670 /* FIXME: take care of vertical/rtl */
3671 origin
.x
+= glyph_run
->glyphAdvances
[i
+ start_glyph
];
3676 d2d_rect_offset(bbox
, run
->origin
.x
+ run
->align_dx
, run
->origin
.y
);
3679 static void layout_get_inlineobj_bbox(struct dwrite_textlayout
*layout
, struct layout_effective_inline
*run
,
3682 DWRITE_OVERHANG_METRICS overhang_metrics
= { 0 };
3683 DWRITE_INLINE_OBJECT_METRICS metrics
= { 0 };
3686 if (FAILED(hr
= IDWriteInlineObject_GetMetrics(run
->object
, &metrics
))) {
3687 WARN("Failed to get inline object metrics, hr %#x.\n", hr
);
3688 memset(bbox
, 0, sizeof(*bbox
));
3692 bbox
->left
= run
->origin
.x
+ run
->align_dx
;
3693 bbox
->right
= bbox
->left
+ metrics
.width
;
3694 bbox
->top
= run
->origin
.y
;
3695 bbox
->bottom
= bbox
->top
+ metrics
.height
;
3697 IDWriteInlineObject_GetOverhangMetrics(run
->object
, &overhang_metrics
);
3699 bbox
->left
-= overhang_metrics
.left
;
3700 bbox
->right
+= overhang_metrics
.right
;
3701 bbox
->top
-= overhang_metrics
.top
;
3702 bbox
->bottom
+= overhang_metrics
.bottom
;
3705 static HRESULT WINAPI
dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3
*iface
,
3706 DWRITE_OVERHANG_METRICS
*overhangs
)
3708 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3709 struct layout_effective_inline
*inline_run
;
3710 struct layout_effective_run
*run
;
3711 D2D1_RECT_F bbox
= { 0 };
3714 TRACE("(%p)->(%p)\n", This
, overhangs
);
3716 memset(overhangs
, 0, sizeof(*overhangs
));
3718 if (!(This
->recompute
& RECOMPUTE_OVERHANGS
)) {
3719 *overhangs
= This
->overhangs
;
3723 hr
= layout_compute_effective_runs(This
);
3727 LIST_FOR_EACH_ENTRY(run
, &This
->eruns
, struct layout_effective_run
, entry
) {
3728 D2D1_RECT_F run_bbox
;
3730 layout_get_erun_bbox(This
, run
, &run_bbox
);
3731 d2d_rect_union(&bbox
, &run_bbox
);
3734 LIST_FOR_EACH_ENTRY(inline_run
, &This
->inlineobjects
, struct layout_effective_inline
, entry
) {
3735 D2D1_RECT_F object_bbox
;
3737 layout_get_inlineobj_bbox(This
, inline_run
, &object_bbox
);
3738 d2d_rect_union(&bbox
, &object_bbox
);
3741 /* Deltas from layout box. */
3742 This
->overhangs
.left
= -bbox
.left
;
3743 This
->overhangs
.top
= -bbox
.top
;
3744 This
->overhangs
.right
= bbox
.right
- This
->metrics
.layoutWidth
;
3745 This
->overhangs
.bottom
= bbox
.bottom
- This
->metrics
.layoutHeight
;
3746 This
->recompute
&= ~RECOMPUTE_OVERHANGS
;
3748 *overhangs
= This
->overhangs
;
3753 static HRESULT WINAPI
dwritetextlayout_GetClusterMetrics(IDWriteTextLayout3
*iface
,
3754 DWRITE_CLUSTER_METRICS
*metrics
, UINT32 max_count
, UINT32
*count
)
3756 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3759 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
3761 hr
= layout_compute(This
);
3766 memcpy(metrics
, This
->clustermetrics
, sizeof(DWRITE_CLUSTER_METRICS
)*min(max_count
, This
->cluster_count
));
3768 *count
= This
->cluster_count
;
3769 return max_count
>= This
->cluster_count
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
3772 static HRESULT WINAPI
dwritetextlayout_DetermineMinWidth(IDWriteTextLayout3
*iface
, FLOAT
* min_width
)
3774 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3779 TRACE("(%p)->(%p)\n", This
, min_width
);
3782 return E_INVALIDARG
;
3784 if (!(This
->recompute
& RECOMPUTE_MINIMAL_WIDTH
))
3788 hr
= layout_compute(This
);
3792 /* Find widest word without emergency breaking between clusters, trailing whitespaces
3793 preceding breaking point do not contribute to word width. */
3794 for (start
= 0; start
< This
->cluster_count
;) {
3795 UINT32 end
= start
, j
, next
;
3797 /* Last cluster always could be wrapped after. */
3798 while (!This
->clustermetrics
[end
].canWrapLineAfter
)
3800 /* make is so current cluster range that we can wrap after is [start,end) */
3805 /* Ignore trailing whitespace clusters, in case of single space range will
3806 be reduced to empty range, or [start,start+1). */
3807 while (end
> start
&& This
->clustermetrics
[end
-1].isWhitespace
)
3810 /* check if cluster range exceeds last minimal width */
3812 for (j
= start
; j
< end
; j
++)
3813 width
+= This
->clustermetrics
[j
].width
;
3817 if (width
> This
->minwidth
)
3818 This
->minwidth
= width
;
3820 This
->recompute
&= ~RECOMPUTE_MINIMAL_WIDTH
;
3823 *min_width
= This
->minwidth
;
3827 static HRESULT WINAPI
dwritetextlayout_HitTestPoint(IDWriteTextLayout3
*iface
,
3828 FLOAT pointX
, FLOAT pointY
, BOOL
* is_trailinghit
, BOOL
* is_inside
, DWRITE_HIT_TEST_METRICS
*metrics
)
3830 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3831 FIXME("(%p)->(%f %f %p %p %p): stub\n", This
, pointX
, pointY
, is_trailinghit
, is_inside
, metrics
);
3835 static HRESULT WINAPI
dwritetextlayout_HitTestTextPosition(IDWriteTextLayout3
*iface
,
3836 UINT32 textPosition
, BOOL is_trailinghit
, FLOAT
* pointX
, FLOAT
* pointY
, DWRITE_HIT_TEST_METRICS
*metrics
)
3838 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3839 FIXME("(%p)->(%u %d %p %p %p): stub\n", This
, textPosition
, is_trailinghit
, pointX
, pointY
, metrics
);
3843 static HRESULT WINAPI
dwritetextlayout_HitTestTextRange(IDWriteTextLayout3
*iface
,
3844 UINT32 textPosition
, UINT32 textLength
, FLOAT originX
, FLOAT originY
,
3845 DWRITE_HIT_TEST_METRICS
*metrics
, UINT32 max_metricscount
, UINT32
* actual_metricscount
)
3847 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3848 FIXME("(%p)->(%u %u %f %f %p %u %p): stub\n", This
, textPosition
, textLength
, originX
, originY
, metrics
,
3849 max_metricscount
, actual_metricscount
);
3853 static HRESULT WINAPI
dwritetextlayout1_SetPairKerning(IDWriteTextLayout3
*iface
, BOOL is_pairkerning_enabled
,
3854 DWRITE_TEXT_RANGE range
)
3856 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3857 struct layout_range_attr_value value
;
3859 TRACE("(%p)->(%d %s)\n", This
, is_pairkerning_enabled
, debugstr_range(&range
));
3861 value
.range
= range
;
3862 value
.u
.pair_kerning
= !!is_pairkerning_enabled
;
3863 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_PAIR_KERNING
, &value
);
3866 static HRESULT WINAPI
dwritetextlayout1_GetPairKerning(IDWriteTextLayout3
*iface
, UINT32 position
, BOOL
*is_pairkerning_enabled
,
3867 DWRITE_TEXT_RANGE
*r
)
3869 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3870 struct layout_range
*range
;
3872 TRACE("(%p)->(%u %p %p)\n", This
, position
, is_pairkerning_enabled
, r
);
3874 if (position
>= This
->len
)
3877 range
= get_layout_range_by_pos(This
, position
);
3878 *is_pairkerning_enabled
= range
->pair_kerning
;
3880 return return_range(&range
->h
, r
);
3883 static HRESULT WINAPI
dwritetextlayout1_SetCharacterSpacing(IDWriteTextLayout3
*iface
, FLOAT leading
, FLOAT trailing
,
3884 FLOAT min_advance
, DWRITE_TEXT_RANGE range
)
3886 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3887 struct layout_range_attr_value value
;
3889 TRACE("(%p)->(%.2f %.2f %.2f %s)\n", This
, leading
, trailing
, min_advance
, debugstr_range(&range
));
3891 if (min_advance
< 0.0f
)
3892 return E_INVALIDARG
;
3894 value
.range
= range
;
3895 value
.u
.spacing
.leading
= leading
;
3896 value
.u
.spacing
.trailing
= trailing
;
3897 value
.u
.spacing
.min_advance
= min_advance
;
3898 return set_layout_range_attr(This
, LAYOUT_RANGE_ATTR_SPACING
, &value
);
3901 static HRESULT WINAPI
dwritetextlayout1_GetCharacterSpacing(IDWriteTextLayout3
*iface
, UINT32 position
, FLOAT
*leading
,
3902 FLOAT
*trailing
, FLOAT
*min_advance
, DWRITE_TEXT_RANGE
*r
)
3904 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3905 struct layout_range_spacing
*range
;
3907 TRACE("(%p)->(%u %p %p %p %p)\n", This
, position
, leading
, trailing
, min_advance
, r
);
3909 range
= (struct layout_range_spacing
*)get_layout_range_header_by_pos(&This
->spacing
, position
);
3910 *leading
= range
->leading
;
3911 *trailing
= range
->trailing
;
3912 *min_advance
= range
->min_advance
;
3914 return return_range(&range
->h
, r
);
3917 static HRESULT WINAPI
dwritetextlayout2_GetMetrics(IDWriteTextLayout3
*iface
, DWRITE_TEXT_METRICS1
*metrics
)
3919 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3922 TRACE("(%p)->(%p)\n", This
, metrics
);
3924 hr
= layout_compute_effective_runs(This
);
3928 *metrics
= This
->metrics
;
3932 static HRESULT WINAPI
dwritetextlayout2_SetVerticalGlyphOrientation(IDWriteTextLayout3
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
3934 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3936 TRACE("(%p)->(%d)\n", This
, orientation
);
3938 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
3939 return E_INVALIDARG
;
3941 This
->format
.vertical_orientation
= orientation
;
3945 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextlayout2_GetVerticalGlyphOrientation(IDWriteTextLayout3
*iface
)
3947 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3948 TRACE("(%p)\n", This
);
3949 return This
->format
.vertical_orientation
;
3952 static HRESULT WINAPI
dwritetextlayout2_SetLastLineWrapping(IDWriteTextLayout3
*iface
, BOOL lastline_wrapping_enabled
)
3954 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3955 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
3956 return IDWriteTextFormat2_SetLastLineWrapping(&This
->IDWriteTextFormat2_iface
, lastline_wrapping_enabled
);
3959 static BOOL WINAPI
dwritetextlayout2_GetLastLineWrapping(IDWriteTextLayout3
*iface
)
3961 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3962 TRACE("(%p)\n", This
);
3963 return IDWriteTextFormat2_GetLastLineWrapping(&This
->IDWriteTextFormat2_iface
);
3966 static HRESULT WINAPI
dwritetextlayout2_SetOpticalAlignment(IDWriteTextLayout3
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
3968 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3969 TRACE("(%p)->(%d)\n", This
, alignment
);
3970 return IDWriteTextFormat2_SetOpticalAlignment(&This
->IDWriteTextFormat2_iface
, alignment
);
3973 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextlayout2_GetOpticalAlignment(IDWriteTextLayout3
*iface
)
3975 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3976 TRACE("(%p)\n", This
);
3977 return IDWriteTextFormat2_GetOpticalAlignment(&This
->IDWriteTextFormat2_iface
);
3980 static HRESULT WINAPI
dwritetextlayout2_SetFontFallback(IDWriteTextLayout3
*iface
, IDWriteFontFallback
*fallback
)
3982 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3983 TRACE("(%p)->(%p)\n", This
, fallback
);
3984 return set_fontfallback_for_format(&This
->format
, fallback
);
3987 static HRESULT WINAPI
dwritetextlayout2_GetFontFallback(IDWriteTextLayout3
*iface
, IDWriteFontFallback
**fallback
)
3989 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3990 TRACE("(%p)->(%p)\n", This
, fallback
);
3991 return get_fontfallback_from_format(&This
->format
, fallback
);
3994 static HRESULT WINAPI
dwritetextlayout3_InvalidateLayout(IDWriteTextLayout3
*iface
)
3996 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
3998 TRACE("(%p)\n", This
);
4000 This
->recompute
= RECOMPUTE_EVERYTHING
;
4004 static HRESULT WINAPI
dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING
const *spacing
)
4006 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
4010 TRACE("(%p)->(%p)\n", This
, spacing
);
4012 hr
= format_set_linespacing(&This
->format
, spacing
, &changed
);
4017 if (!(This
->recompute
& RECOMPUTE_LINES
)) {
4020 for (line
= 0; line
< This
->metrics
.lineCount
; line
++)
4021 layout_apply_line_spacing(This
, line
);
4023 layout_set_line_positions(This
);
4026 This
->recompute
|= RECOMPUTE_OVERHANGS
;
4032 static HRESULT WINAPI
dwritetextlayout3_GetLineSpacing(IDWriteTextLayout3
*iface
, DWRITE_LINE_SPACING
*spacing
)
4034 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
4036 TRACE("(%p)->(%p)\n", This
, spacing
);
4038 *spacing
= This
->format
.spacing
;
4042 static HRESULT WINAPI
dwritetextlayout3_GetLineMetrics(IDWriteTextLayout3
*iface
, DWRITE_LINE_METRICS1
*metrics
,
4043 UINT32 max_count
, UINT32
*count
)
4045 struct dwrite_textlayout
*This
= impl_from_IDWriteTextLayout3(iface
);
4048 TRACE("(%p)->(%p %u %p)\n", This
, metrics
, max_count
, count
);
4050 hr
= layout_compute_effective_runs(This
);
4055 memcpy(metrics
, This
->linemetrics
, sizeof(*metrics
) * min(max_count
, This
->metrics
.lineCount
));
4057 *count
= This
->metrics
.lineCount
;
4058 return max_count
>= This
->metrics
.lineCount
? S_OK
: E_NOT_SUFFICIENT_BUFFER
;
4061 static const IDWriteTextLayout3Vtbl dwritetextlayoutvtbl
= {
4062 dwritetextlayout_QueryInterface
,
4063 dwritetextlayout_AddRef
,
4064 dwritetextlayout_Release
,
4065 dwritetextlayout_SetTextAlignment
,
4066 dwritetextlayout_SetParagraphAlignment
,
4067 dwritetextlayout_SetWordWrapping
,
4068 dwritetextlayout_SetReadingDirection
,
4069 dwritetextlayout_SetFlowDirection
,
4070 dwritetextlayout_SetIncrementalTabStop
,
4071 dwritetextlayout_SetTrimming
,
4072 dwritetextlayout_SetLineSpacing
,
4073 dwritetextlayout_GetTextAlignment
,
4074 dwritetextlayout_GetParagraphAlignment
,
4075 dwritetextlayout_GetWordWrapping
,
4076 dwritetextlayout_GetReadingDirection
,
4077 dwritetextlayout_GetFlowDirection
,
4078 dwritetextlayout_GetIncrementalTabStop
,
4079 dwritetextlayout_GetTrimming
,
4080 dwritetextlayout_GetLineSpacing
,
4081 dwritetextlayout_GetFontCollection
,
4082 dwritetextlayout_GetFontFamilyNameLength
,
4083 dwritetextlayout_GetFontFamilyName
,
4084 dwritetextlayout_GetFontWeight
,
4085 dwritetextlayout_GetFontStyle
,
4086 dwritetextlayout_GetFontStretch
,
4087 dwritetextlayout_GetFontSize
,
4088 dwritetextlayout_GetLocaleNameLength
,
4089 dwritetextlayout_GetLocaleName
,
4090 dwritetextlayout_SetMaxWidth
,
4091 dwritetextlayout_SetMaxHeight
,
4092 dwritetextlayout_SetFontCollection
,
4093 dwritetextlayout_SetFontFamilyName
,
4094 dwritetextlayout_SetFontWeight
,
4095 dwritetextlayout_SetFontStyle
,
4096 dwritetextlayout_SetFontStretch
,
4097 dwritetextlayout_SetFontSize
,
4098 dwritetextlayout_SetUnderline
,
4099 dwritetextlayout_SetStrikethrough
,
4100 dwritetextlayout_SetDrawingEffect
,
4101 dwritetextlayout_SetInlineObject
,
4102 dwritetextlayout_SetTypography
,
4103 dwritetextlayout_SetLocaleName
,
4104 dwritetextlayout_GetMaxWidth
,
4105 dwritetextlayout_GetMaxHeight
,
4106 dwritetextlayout_layout_GetFontCollection
,
4107 dwritetextlayout_layout_GetFontFamilyNameLength
,
4108 dwritetextlayout_layout_GetFontFamilyName
,
4109 dwritetextlayout_layout_GetFontWeight
,
4110 dwritetextlayout_layout_GetFontStyle
,
4111 dwritetextlayout_layout_GetFontStretch
,
4112 dwritetextlayout_layout_GetFontSize
,
4113 dwritetextlayout_GetUnderline
,
4114 dwritetextlayout_GetStrikethrough
,
4115 dwritetextlayout_GetDrawingEffect
,
4116 dwritetextlayout_GetInlineObject
,
4117 dwritetextlayout_GetTypography
,
4118 dwritetextlayout_layout_GetLocaleNameLength
,
4119 dwritetextlayout_layout_GetLocaleName
,
4120 dwritetextlayout_Draw
,
4121 dwritetextlayout_GetLineMetrics
,
4122 dwritetextlayout_GetMetrics
,
4123 dwritetextlayout_GetOverhangMetrics
,
4124 dwritetextlayout_GetClusterMetrics
,
4125 dwritetextlayout_DetermineMinWidth
,
4126 dwritetextlayout_HitTestPoint
,
4127 dwritetextlayout_HitTestTextPosition
,
4128 dwritetextlayout_HitTestTextRange
,
4129 dwritetextlayout1_SetPairKerning
,
4130 dwritetextlayout1_GetPairKerning
,
4131 dwritetextlayout1_SetCharacterSpacing
,
4132 dwritetextlayout1_GetCharacterSpacing
,
4133 dwritetextlayout2_GetMetrics
,
4134 dwritetextlayout2_SetVerticalGlyphOrientation
,
4135 dwritetextlayout2_GetVerticalGlyphOrientation
,
4136 dwritetextlayout2_SetLastLineWrapping
,
4137 dwritetextlayout2_GetLastLineWrapping
,
4138 dwritetextlayout2_SetOpticalAlignment
,
4139 dwritetextlayout2_GetOpticalAlignment
,
4140 dwritetextlayout2_SetFontFallback
,
4141 dwritetextlayout2_GetFontFallback
,
4142 dwritetextlayout3_InvalidateLayout
,
4143 dwritetextlayout3_SetLineSpacing
,
4144 dwritetextlayout3_GetLineSpacing
,
4145 dwritetextlayout3_GetLineMetrics
4148 static HRESULT WINAPI
dwritetextformat_layout_QueryInterface(IDWriteTextFormat2
*iface
, REFIID riid
, void **obj
)
4150 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4151 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
4152 return IDWriteTextLayout3_QueryInterface(&This
->IDWriteTextLayout3_iface
, riid
, obj
);
4155 static ULONG WINAPI
dwritetextformat_layout_AddRef(IDWriteTextFormat2
*iface
)
4157 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4158 return IDWriteTextLayout3_AddRef(&This
->IDWriteTextLayout3_iface
);
4161 static ULONG WINAPI
dwritetextformat_layout_Release(IDWriteTextFormat2
*iface
)
4163 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4164 return IDWriteTextLayout3_Release(&This
->IDWriteTextLayout3_iface
);
4167 static HRESULT WINAPI
dwritetextformat_layout_SetTextAlignment(IDWriteTextFormat2
*iface
,
4168 DWRITE_TEXT_ALIGNMENT alignment
)
4170 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4174 TRACE("(%p)->(%d)\n", This
, alignment
);
4176 hr
= format_set_textalignment(&This
->format
, alignment
, &changed
);
4181 /* if layout is not ready there's nothing to align */
4182 if (!(This
->recompute
& RECOMPUTE_LINES
))
4183 layout_apply_text_alignment(This
);
4184 This
->recompute
|= RECOMPUTE_OVERHANGS
;
4190 static HRESULT WINAPI
dwritetextformat_layout_SetParagraphAlignment(IDWriteTextFormat2
*iface
,
4191 DWRITE_PARAGRAPH_ALIGNMENT alignment
)
4193 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4197 TRACE("(%p)->(%d)\n", This
, alignment
);
4199 hr
= format_set_paralignment(&This
->format
, alignment
, &changed
);
4204 /* if layout is not ready there's nothing to align */
4205 if (!(This
->recompute
& RECOMPUTE_LINES
))
4206 layout_apply_par_alignment(This
);
4207 This
->recompute
|= RECOMPUTE_OVERHANGS
;
4213 static HRESULT WINAPI
dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat2
*iface
, DWRITE_WORD_WRAPPING wrapping
)
4215 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4219 TRACE("(%p)->(%d)\n", This
, wrapping
);
4221 hr
= format_set_wordwrapping(&This
->format
, wrapping
, &changed
);
4226 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4231 static HRESULT WINAPI
dwritetextformat_layout_SetReadingDirection(IDWriteTextFormat2
*iface
,
4232 DWRITE_READING_DIRECTION direction
)
4234 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4238 TRACE("(%p)->(%d)\n", This
, direction
);
4240 hr
= format_set_readingdirection(&This
->format
, direction
, &changed
);
4245 This
->recompute
= RECOMPUTE_EVERYTHING
;
4250 static HRESULT WINAPI
dwritetextformat_layout_SetFlowDirection(IDWriteTextFormat2
*iface
,
4251 DWRITE_FLOW_DIRECTION direction
)
4253 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4257 TRACE("(%p)->(%d)\n", This
, direction
);
4259 hr
= format_set_flowdirection(&This
->format
, direction
, &changed
);
4264 This
->recompute
= RECOMPUTE_EVERYTHING
;
4269 static HRESULT WINAPI
dwritetextformat_layout_SetIncrementalTabStop(IDWriteTextFormat2
*iface
, FLOAT tabstop
)
4271 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4272 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
4276 static HRESULT WINAPI
dwritetextformat_layout_SetTrimming(IDWriteTextFormat2
*iface
, DWRITE_TRIMMING
const *trimming
,
4277 IDWriteInlineObject
*trimming_sign
)
4279 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4283 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
4285 hr
= format_set_trimming(&This
->format
, trimming
, trimming_sign
, &changed
);
4288 This
->recompute
|= RECOMPUTE_LINES_AND_OVERHANGS
;
4293 static HRESULT WINAPI
dwritetextformat_layout_SetLineSpacing(IDWriteTextFormat2
*iface
,
4294 DWRITE_LINE_SPACING_METHOD method
, FLOAT height
, FLOAT baseline
)
4296 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4297 DWRITE_LINE_SPACING spacing
;
4299 TRACE("(%p)->(%d %f %f)\n", This
, method
, height
, baseline
);
4301 spacing
= This
->format
.spacing
;
4302 spacing
.method
= method
;
4303 spacing
.height
= height
;
4304 spacing
.baseline
= baseline
;
4305 return IDWriteTextLayout3_SetLineSpacing(&This
->IDWriteTextLayout3_iface
, &spacing
);
4308 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_layout_GetTextAlignment(IDWriteTextFormat2
*iface
)
4310 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4311 TRACE("(%p)\n", This
);
4312 return This
->format
.textalignment
;
4315 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_layout_GetParagraphAlignment(IDWriteTextFormat2
*iface
)
4317 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4318 TRACE("(%p)\n", This
);
4319 return This
->format
.paralign
;
4322 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_layout_GetWordWrapping(IDWriteTextFormat2
*iface
)
4324 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4325 TRACE("(%p)\n", This
);
4326 return This
->format
.wrapping
;
4329 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_layout_GetReadingDirection(IDWriteTextFormat2
*iface
)
4331 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4332 TRACE("(%p)\n", This
);
4333 return This
->format
.readingdir
;
4336 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_layout_GetFlowDirection(IDWriteTextFormat2
*iface
)
4338 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4339 TRACE("(%p)\n", This
);
4340 return This
->format
.flow
;
4343 static FLOAT WINAPI
dwritetextformat_layout_GetIncrementalTabStop(IDWriteTextFormat2
*iface
)
4345 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4346 FIXME("(%p): stub\n", This
);
4350 static HRESULT WINAPI
dwritetextformat_layout_GetTrimming(IDWriteTextFormat2
*iface
, DWRITE_TRIMMING
*options
,
4351 IDWriteInlineObject
**trimming_sign
)
4353 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4355 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
4357 *options
= This
->format
.trimming
;
4358 *trimming_sign
= This
->format
.trimmingsign
;
4360 IDWriteInlineObject_AddRef(*trimming_sign
);
4364 static HRESULT WINAPI
dwritetextformat_layout_GetLineSpacing(IDWriteTextFormat2
*iface
,
4365 DWRITE_LINE_SPACING_METHOD
*method
, FLOAT
*spacing
, FLOAT
*baseline
)
4367 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4369 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
4371 *method
= This
->format
.spacing
.method
;
4372 *spacing
= This
->format
.spacing
.height
;
4373 *baseline
= This
->format
.spacing
.baseline
;
4377 static HRESULT WINAPI
dwritetextformat_layout_GetFontCollection(IDWriteTextFormat2
*iface
,
4378 IDWriteFontCollection
**collection
)
4380 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4382 TRACE("(%p)->(%p)\n", This
, collection
);
4384 *collection
= This
->format
.collection
;
4386 IDWriteFontCollection_AddRef(*collection
);
4390 static UINT32 WINAPI
dwritetextformat_layout_GetFontFamilyNameLength(IDWriteTextFormat2
*iface
)
4392 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4393 TRACE("(%p)\n", This
);
4394 return This
->format
.family_len
;
4397 static HRESULT WINAPI
dwritetextformat_layout_GetFontFamilyName(IDWriteTextFormat2
*iface
, WCHAR
*name
, UINT32 size
)
4399 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4401 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4403 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
4404 strcpyW(name
, This
->format
.family_name
);
4408 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_layout_GetFontWeight(IDWriteTextFormat2
*iface
)
4410 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4411 TRACE("(%p)\n", This
);
4412 return This
->format
.weight
;
4415 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_layout_GetFontStyle(IDWriteTextFormat2
*iface
)
4417 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4418 TRACE("(%p)\n", This
);
4419 return This
->format
.style
;
4422 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_layout_GetFontStretch(IDWriteTextFormat2
*iface
)
4424 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4425 TRACE("(%p)\n", This
);
4426 return This
->format
.stretch
;
4429 static FLOAT WINAPI
dwritetextformat_layout_GetFontSize(IDWriteTextFormat2
*iface
)
4431 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4432 TRACE("(%p)\n", This
);
4433 return This
->format
.fontsize
;
4436 static UINT32 WINAPI
dwritetextformat_layout_GetLocaleNameLength(IDWriteTextFormat2
*iface
)
4438 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4439 TRACE("(%p)\n", This
);
4440 return This
->format
.locale_len
;
4443 static HRESULT WINAPI
dwritetextformat_layout_GetLocaleName(IDWriteTextFormat2
*iface
, WCHAR
*name
, UINT32 size
)
4445 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4447 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
4449 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
4450 strcpyW(name
, This
->format
.locale
);
4454 static HRESULT WINAPI
dwritetextformat1_layout_SetVerticalGlyphOrientation(IDWriteTextFormat2
*iface
,
4455 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
4457 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4458 FIXME("(%p)->(%d): stub\n", This
, orientation
);
4462 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_layout_GetVerticalGlyphOrientation(IDWriteTextFormat2
*iface
)
4464 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4465 FIXME("(%p): stub\n", This
);
4466 return DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
4469 static HRESULT WINAPI
dwritetextformat1_layout_SetLastLineWrapping(IDWriteTextFormat2
*iface
,
4470 BOOL lastline_wrapping_enabled
)
4472 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4474 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
4476 This
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
4480 static BOOL WINAPI
dwritetextformat1_layout_GetLastLineWrapping(IDWriteTextFormat2
*iface
)
4482 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4483 TRACE("(%p)\n", This
);
4484 return This
->format
.last_line_wrapping
;
4487 static HRESULT WINAPI
dwritetextformat1_layout_SetOpticalAlignment(IDWriteTextFormat2
*iface
,
4488 DWRITE_OPTICAL_ALIGNMENT alignment
)
4490 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4491 TRACE("(%p)->(%d)\n", This
, alignment
);
4492 return format_set_optical_alignment(&This
->format
, alignment
);
4495 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_layout_GetOpticalAlignment(IDWriteTextFormat2
*iface
)
4497 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4498 TRACE("(%p)\n", This
);
4499 return This
->format
.optical_alignment
;
4502 static HRESULT WINAPI
dwritetextformat1_layout_SetFontFallback(IDWriteTextFormat2
*iface
,
4503 IDWriteFontFallback
*fallback
)
4505 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4506 TRACE("(%p)->(%p)\n", This
, fallback
);
4507 return IDWriteTextLayout3_SetFontFallback(&This
->IDWriteTextLayout3_iface
, fallback
);
4510 static HRESULT WINAPI
dwritetextformat1_layout_GetFontFallback(IDWriteTextFormat2
*iface
,
4511 IDWriteFontFallback
**fallback
)
4513 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4514 TRACE("(%p)->(%p)\n", This
, fallback
);
4515 return IDWriteTextLayout3_GetFontFallback(&This
->IDWriteTextLayout3_iface
, fallback
);
4518 static HRESULT WINAPI
dwritetextformat2_layout_SetLineSpacing(IDWriteTextFormat2
*iface
,
4519 DWRITE_LINE_SPACING
const *spacing
)
4521 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4522 return IDWriteTextLayout3_SetLineSpacing(&This
->IDWriteTextLayout3_iface
, spacing
);
4525 static HRESULT WINAPI
dwritetextformat2_layout_GetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING
*spacing
)
4527 struct dwrite_textlayout
*This
= impl_layout_from_IDWriteTextFormat2(iface
);
4528 return IDWriteTextLayout3_GetLineSpacing(&This
->IDWriteTextLayout3_iface
, spacing
);
4531 static const IDWriteTextFormat2Vtbl dwritetextformat2_layout_vtbl
= {
4532 dwritetextformat_layout_QueryInterface
,
4533 dwritetextformat_layout_AddRef
,
4534 dwritetextformat_layout_Release
,
4535 dwritetextformat_layout_SetTextAlignment
,
4536 dwritetextformat_layout_SetParagraphAlignment
,
4537 dwritetextformat_layout_SetWordWrapping
,
4538 dwritetextformat_layout_SetReadingDirection
,
4539 dwritetextformat_layout_SetFlowDirection
,
4540 dwritetextformat_layout_SetIncrementalTabStop
,
4541 dwritetextformat_layout_SetTrimming
,
4542 dwritetextformat_layout_SetLineSpacing
,
4543 dwritetextformat_layout_GetTextAlignment
,
4544 dwritetextformat_layout_GetParagraphAlignment
,
4545 dwritetextformat_layout_GetWordWrapping
,
4546 dwritetextformat_layout_GetReadingDirection
,
4547 dwritetextformat_layout_GetFlowDirection
,
4548 dwritetextformat_layout_GetIncrementalTabStop
,
4549 dwritetextformat_layout_GetTrimming
,
4550 dwritetextformat_layout_GetLineSpacing
,
4551 dwritetextformat_layout_GetFontCollection
,
4552 dwritetextformat_layout_GetFontFamilyNameLength
,
4553 dwritetextformat_layout_GetFontFamilyName
,
4554 dwritetextformat_layout_GetFontWeight
,
4555 dwritetextformat_layout_GetFontStyle
,
4556 dwritetextformat_layout_GetFontStretch
,
4557 dwritetextformat_layout_GetFontSize
,
4558 dwritetextformat_layout_GetLocaleNameLength
,
4559 dwritetextformat_layout_GetLocaleName
,
4560 dwritetextformat1_layout_SetVerticalGlyphOrientation
,
4561 dwritetextformat1_layout_GetVerticalGlyphOrientation
,
4562 dwritetextformat1_layout_SetLastLineWrapping
,
4563 dwritetextformat1_layout_GetLastLineWrapping
,
4564 dwritetextformat1_layout_SetOpticalAlignment
,
4565 dwritetextformat1_layout_GetOpticalAlignment
,
4566 dwritetextformat1_layout_SetFontFallback
,
4567 dwritetextformat1_layout_GetFontFallback
,
4568 dwritetextformat2_layout_SetLineSpacing
,
4569 dwritetextformat2_layout_GetLineSpacing
,
4572 static HRESULT WINAPI
dwritetextlayout_sink_QueryInterface(IDWriteTextAnalysisSink1
*iface
,
4573 REFIID riid
, void **obj
)
4575 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink1
) ||
4576 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSink
) ||
4577 IsEqualIID(riid
, &IID_IUnknown
))
4580 IDWriteTextAnalysisSink1_AddRef(iface
);
4584 WARN("%s not implemented.\n", debugstr_guid(riid
));
4587 return E_NOINTERFACE
;
4590 static ULONG WINAPI
dwritetextlayout_sink_AddRef(IDWriteTextAnalysisSink1
*iface
)
4592 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4593 return IDWriteTextLayout3_AddRef(&layout
->IDWriteTextLayout3_iface
);
4596 static ULONG WINAPI
dwritetextlayout_sink_Release(IDWriteTextAnalysisSink1
*iface
)
4598 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4599 return IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
4602 static HRESULT WINAPI
dwritetextlayout_sink_SetScriptAnalysis(IDWriteTextAnalysisSink1
*iface
,
4603 UINT32 position
, UINT32 length
, DWRITE_SCRIPT_ANALYSIS
const* sa
)
4605 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4606 struct layout_run
*run
;
4608 TRACE("[%u,%u) script=%u:%s\n", position
, position
+ length
, sa
->script
, debugstr_sa_script(sa
->script
));
4610 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
);
4612 return E_OUTOFMEMORY
;
4614 run
->u
.regular
.descr
.string
= &layout
->str
[position
];
4615 run
->u
.regular
.descr
.stringLength
= length
;
4616 run
->u
.regular
.descr
.textPosition
= position
;
4617 run
->u
.regular
.sa
= *sa
;
4618 list_add_tail(&layout
->runs
, &run
->entry
);
4622 static HRESULT WINAPI
dwritetextlayout_sink_SetLineBreakpoints(IDWriteTextAnalysisSink1
*iface
,
4623 UINT32 position
, UINT32 length
, DWRITE_LINE_BREAKPOINT
const* breakpoints
)
4625 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4627 if (position
+ length
> layout
->len
)
4630 memcpy(&layout
->nominal_breakpoints
[position
], breakpoints
, length
*sizeof(DWRITE_LINE_BREAKPOINT
));
4634 static HRESULT WINAPI
dwritetextlayout_sink_SetBidiLevel(IDWriteTextAnalysisSink1
*iface
, UINT32 position
,
4635 UINT32 length
, UINT8 explicitLevel
, UINT8 resolvedLevel
)
4637 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSink1(iface
);
4638 struct layout_run
*cur_run
;
4640 TRACE("[%u,%u) %u %u\n", position
, position
+ length
, explicitLevel
, resolvedLevel
);
4642 LIST_FOR_EACH_ENTRY(cur_run
, &layout
->runs
, struct layout_run
, entry
) {
4643 struct regular_layout_run
*cur
= &cur_run
->u
.regular
;
4644 struct layout_run
*run
;
4646 if (cur_run
->kind
== LAYOUT_RUN_INLINE
)
4649 /* FIXME: levels are reported in a natural forward direction, so start loop from a run we ended on */
4650 if (position
< cur
->descr
.textPosition
|| position
>= cur
->descr
.textPosition
+ cur
->descr
.stringLength
)
4653 /* full hit - just set run level */
4654 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
== length
) {
4655 cur
->run
.bidiLevel
= resolvedLevel
;
4659 /* current run is fully covered, move to next one */
4660 if (cur
->descr
.textPosition
== position
&& cur
->descr
.stringLength
< length
) {
4661 cur
->run
.bidiLevel
= resolvedLevel
;
4662 position
+= cur
->descr
.stringLength
;
4663 length
-= cur
->descr
.stringLength
;
4667 /* all fully covered runs are processed at this point, reuse existing run for remaining
4668 reported bidi range and add another run for the rest of original one */
4670 run
= alloc_layout_run(LAYOUT_RUN_REGULAR
, position
+ length
);
4672 return E_OUTOFMEMORY
;
4675 run
->u
.regular
.descr
.textPosition
= position
+ length
;
4676 run
->u
.regular
.descr
.stringLength
= cur
->descr
.stringLength
- length
;
4677 run
->u
.regular
.descr
.string
= &layout
->str
[position
+ length
];
4679 /* reduce existing run */
4680 cur
->run
.bidiLevel
= resolvedLevel
;
4681 cur
->descr
.stringLength
= length
;
4683 list_add_after(&cur_run
->entry
, &run
->entry
);
4690 static HRESULT WINAPI
dwritetextlayout_sink_SetNumberSubstitution(IDWriteTextAnalysisSink1
*iface
,
4691 UINT32 position
, UINT32 length
, IDWriteNumberSubstitution
* substitution
)
4696 static HRESULT WINAPI
dwritetextlayout_sink_SetGlyphOrientation(IDWriteTextAnalysisSink1
*iface
,
4697 UINT32 position
, UINT32 length
, DWRITE_GLYPH_ORIENTATION_ANGLE angle
, UINT8 adjusted_bidi_level
,
4698 BOOL is_sideways
, BOOL is_rtl
)
4703 static const IDWriteTextAnalysisSink1Vtbl dwritetextlayoutsinkvtbl
= {
4704 dwritetextlayout_sink_QueryInterface
,
4705 dwritetextlayout_sink_AddRef
,
4706 dwritetextlayout_sink_Release
,
4707 dwritetextlayout_sink_SetScriptAnalysis
,
4708 dwritetextlayout_sink_SetLineBreakpoints
,
4709 dwritetextlayout_sink_SetBidiLevel
,
4710 dwritetextlayout_sink_SetNumberSubstitution
,
4711 dwritetextlayout_sink_SetGlyphOrientation
4714 static HRESULT WINAPI
dwritetextlayout_source_QueryInterface(IDWriteTextAnalysisSource1
*iface
,
4715 REFIID riid
, void **obj
)
4717 if (IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource1
) ||
4718 IsEqualIID(riid
, &IID_IDWriteTextAnalysisSource
) ||
4719 IsEqualIID(riid
, &IID_IUnknown
))
4722 IDWriteTextAnalysisSource1_AddRef(iface
);
4726 WARN("%s not implemented.\n", debugstr_guid(riid
));
4729 return E_NOINTERFACE
;
4732 static ULONG WINAPI
dwritetextlayout_source_AddRef(IDWriteTextAnalysisSource1
*iface
)
4734 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4735 return IDWriteTextLayout3_AddRef(&layout
->IDWriteTextLayout3_iface
);
4738 static ULONG WINAPI
dwritetextlayout_source_Release(IDWriteTextAnalysisSource1
*iface
)
4740 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4741 return IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
4744 static HRESULT WINAPI
dwritetextlayout_source_GetTextAtPosition(IDWriteTextAnalysisSource1
*iface
,
4745 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
4747 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4749 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
4751 if (position
< layout
->len
) {
4752 *text
= &layout
->str
[position
];
4753 *text_len
= layout
->len
- position
;
4763 static HRESULT WINAPI
dwritetextlayout_source_GetTextBeforePosition(IDWriteTextAnalysisSource1
*iface
,
4764 UINT32 position
, WCHAR
const** text
, UINT32
* text_len
)
4766 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4768 TRACE("(%p)->(%u %p %p)\n", layout
, position
, text
, text_len
);
4770 if (position
> 0 && position
< layout
->len
) {
4771 *text
= layout
->str
;
4772 *text_len
= position
;
4782 static DWRITE_READING_DIRECTION WINAPI
dwritetextlayout_source_GetParagraphReadingDirection(IDWriteTextAnalysisSource1
*iface
)
4784 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4785 return IDWriteTextLayout3_GetReadingDirection(&layout
->IDWriteTextLayout3_iface
);
4788 static HRESULT WINAPI
dwritetextlayout_source_GetLocaleName(IDWriteTextAnalysisSource1
*iface
,
4789 UINT32 position
, UINT32
* text_len
, WCHAR
const** locale
)
4791 struct dwrite_textlayout
*layout
= impl_from_IDWriteTextAnalysisSource1(iface
);
4792 struct layout_range
*range
= get_layout_range_by_pos(layout
, position
);
4794 if (position
< layout
->len
) {
4795 struct layout_range
*next
;
4797 *locale
= range
->locale
;
4798 *text_len
= range
->h
.range
.length
- position
;
4800 next
= LIST_ENTRY(list_next(&layout
->ranges
, &range
->h
.entry
), struct layout_range
, h
.entry
);
4801 while (next
&& next
->h
.range
.startPosition
< layout
->len
&& !strcmpW(range
->locale
, next
->locale
)) {
4802 *text_len
+= next
->h
.range
.length
;
4803 next
= LIST_ENTRY(list_next(&layout
->ranges
, &next
->h
.entry
), struct layout_range
, h
.entry
);
4806 *text_len
= min(*text_len
, layout
->len
- position
);
4816 static HRESULT WINAPI
dwritetextlayout_source_GetNumberSubstitution(IDWriteTextAnalysisSource1
*iface
,
4817 UINT32 position
, UINT32
* text_len
, IDWriteNumberSubstitution
**substitution
)
4819 FIXME("%u %p %p: stub\n", position
, text_len
, substitution
);
4823 static HRESULT WINAPI
dwritetextlayout_source_GetVerticalGlyphOrientation(IDWriteTextAnalysisSource1
*iface
,
4824 UINT32 position
, UINT32
*length
, DWRITE_VERTICAL_GLYPH_ORIENTATION
*orientation
, UINT8
*bidi_level
)
4826 FIXME("%u %p %p %p: stub\n", position
, length
, orientation
, bidi_level
);
4830 static const IDWriteTextAnalysisSource1Vtbl dwritetextlayoutsourcevtbl
= {
4831 dwritetextlayout_source_QueryInterface
,
4832 dwritetextlayout_source_AddRef
,
4833 dwritetextlayout_source_Release
,
4834 dwritetextlayout_source_GetTextAtPosition
,
4835 dwritetextlayout_source_GetTextBeforePosition
,
4836 dwritetextlayout_source_GetParagraphReadingDirection
,
4837 dwritetextlayout_source_GetLocaleName
,
4838 dwritetextlayout_source_GetNumberSubstitution
,
4839 dwritetextlayout_source_GetVerticalGlyphOrientation
4842 static HRESULT
layout_format_from_textformat(struct dwrite_textlayout
*layout
, IDWriteTextFormat
*format
)
4844 struct dwrite_textformat
*textformat
;
4845 IDWriteTextFormat1
*format1
;
4849 if ((textformat
= unsafe_impl_from_IDWriteTextFormat(format
))) {
4850 layout
->format
= textformat
->format
;
4852 layout
->format
.locale
= heap_strdupW(textformat
->format
.locale
);
4853 layout
->format
.family_name
= heap_strdupW(textformat
->format
.family_name
);
4854 if (!layout
->format
.locale
|| !layout
->format
.family_name
)
4856 heap_free(layout
->format
.locale
);
4857 heap_free(layout
->format
.family_name
);
4858 return E_OUTOFMEMORY
;
4861 if (layout
->format
.trimmingsign
)
4862 IDWriteInlineObject_AddRef(layout
->format
.trimmingsign
);
4863 if (layout
->format
.collection
)
4864 IDWriteFontCollection_AddRef(layout
->format
.collection
);
4865 if (layout
->format
.fallback
)
4866 IDWriteFontFallback_AddRef(layout
->format
.fallback
);
4871 layout
->format
.weight
= IDWriteTextFormat_GetFontWeight(format
);
4872 layout
->format
.style
= IDWriteTextFormat_GetFontStyle(format
);
4873 layout
->format
.stretch
= IDWriteTextFormat_GetFontStretch(format
);
4874 layout
->format
.fontsize
= IDWriteTextFormat_GetFontSize(format
);
4875 layout
->format
.textalignment
= IDWriteTextFormat_GetTextAlignment(format
);
4876 layout
->format
.paralign
= IDWriteTextFormat_GetParagraphAlignment(format
);
4877 layout
->format
.wrapping
= IDWriteTextFormat_GetWordWrapping(format
);
4878 layout
->format
.readingdir
= IDWriteTextFormat_GetReadingDirection(format
);
4879 layout
->format
.flow
= IDWriteTextFormat_GetFlowDirection(format
);
4880 layout
->format
.fallback
= NULL
;
4881 layout
->format
.spacing
.leadingBefore
= 0.0f
;
4882 layout
->format
.spacing
.fontLineGapUsage
= DWRITE_FONT_LINE_GAP_USAGE_DEFAULT
;
4883 hr
= IDWriteTextFormat_GetLineSpacing(format
, &layout
->format
.spacing
.method
,
4884 &layout
->format
.spacing
.height
, &layout
->format
.spacing
.baseline
);
4888 hr
= IDWriteTextFormat_GetTrimming(format
, &layout
->format
.trimming
, &layout
->format
.trimmingsign
);
4892 /* locale name and length */
4893 len
= IDWriteTextFormat_GetLocaleNameLength(format
);
4894 layout
->format
.locale
= heap_alloc((len
+1)*sizeof(WCHAR
));
4895 if (!layout
->format
.locale
)
4896 return E_OUTOFMEMORY
;
4898 hr
= IDWriteTextFormat_GetLocaleName(format
, layout
->format
.locale
, len
+1);
4901 layout
->format
.locale_len
= len
;
4903 /* font family name and length */
4904 len
= IDWriteTextFormat_GetFontFamilyNameLength(format
);
4905 layout
->format
.family_name
= heap_alloc((len
+1)*sizeof(WCHAR
));
4906 if (!layout
->format
.family_name
)
4907 return E_OUTOFMEMORY
;
4909 hr
= IDWriteTextFormat_GetFontFamilyName(format
, layout
->format
.family_name
, len
+1);
4912 layout
->format
.family_len
= len
;
4914 hr
= IDWriteTextFormat_QueryInterface(format
, &IID_IDWriteTextFormat1
, (void**)&format1
);
4916 IDWriteTextFormat2
*format2
;
4918 layout
->format
.vertical_orientation
= IDWriteTextFormat1_GetVerticalGlyphOrientation(format1
);
4919 layout
->format
.optical_alignment
= IDWriteTextFormat1_GetOpticalAlignment(format1
);
4920 IDWriteTextFormat1_GetFontFallback(format1
, &layout
->format
.fallback
);
4922 if (IDWriteTextFormat1_QueryInterface(format1
, &IID_IDWriteTextFormat2
, (void**)&format2
) == S_OK
) {
4923 IDWriteTextFormat2_GetLineSpacing(format2
, &layout
->format
.spacing
);
4924 IDWriteTextFormat2_Release(format2
);
4927 IDWriteTextFormat1_Release(format1
);
4930 layout
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
4931 layout
->format
.optical_alignment
= DWRITE_OPTICAL_ALIGNMENT_NONE
;
4934 return IDWriteTextFormat_GetFontCollection(format
, &layout
->format
.collection
);
4937 static HRESULT
init_textlayout(const struct textlayout_desc
*desc
, struct dwrite_textlayout
*layout
)
4939 struct layout_range_header
*range
, *strike
, *underline
, *effect
, *spacing
, *typography
;
4940 static const DWRITE_TEXT_RANGE r
= { 0, ~0u };
4943 layout
->IDWriteTextLayout3_iface
.lpVtbl
= &dwritetextlayoutvtbl
;
4944 layout
->IDWriteTextFormat2_iface
.lpVtbl
= &dwritetextformat2_layout_vtbl
;
4945 layout
->IDWriteTextAnalysisSink1_iface
.lpVtbl
= &dwritetextlayoutsinkvtbl
;
4946 layout
->IDWriteTextAnalysisSource1_iface
.lpVtbl
= &dwritetextlayoutsourcevtbl
;
4948 layout
->len
= desc
->length
;
4949 layout
->recompute
= RECOMPUTE_EVERYTHING
;
4950 layout
->nominal_breakpoints
= NULL
;
4951 layout
->actual_breakpoints
= NULL
;
4952 layout
->cluster_count
= 0;
4953 layout
->clustermetrics
= NULL
;
4954 layout
->clusters
= NULL
;
4955 layout
->linemetrics
= NULL
;
4956 layout
->lines
= NULL
;
4957 layout
->line_alloc
= 0;
4958 layout
->minwidth
= 0.0f
;
4959 list_init(&layout
->eruns
);
4960 list_init(&layout
->inlineobjects
);
4961 list_init(&layout
->underlines
);
4962 list_init(&layout
->strikethrough
);
4963 list_init(&layout
->runs
);
4964 list_init(&layout
->ranges
);
4965 list_init(&layout
->strike_ranges
);
4966 list_init(&layout
->underline_ranges
);
4967 list_init(&layout
->effects
);
4968 list_init(&layout
->spacing
);
4969 list_init(&layout
->typographies
);
4970 memset(&layout
->format
, 0, sizeof(layout
->format
));
4971 memset(&layout
->metrics
, 0, sizeof(layout
->metrics
));
4972 layout
->metrics
.layoutWidth
= desc
->max_width
;
4973 layout
->metrics
.layoutHeight
= desc
->max_height
;
4974 layout
->measuringmode
= DWRITE_MEASURING_MODE_NATURAL
;
4976 layout
->ppdip
= 0.0f
;
4977 memset(&layout
->transform
, 0, sizeof(layout
->transform
));
4979 layout
->str
= heap_strdupnW(desc
->string
, desc
->length
);
4980 if (desc
->length
&& !layout
->str
) {
4985 hr
= layout_format_from_textformat(layout
, desc
->format
);
4989 range
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_REGULAR
);
4990 strike
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_STRIKETHROUGH
);
4991 underline
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_UNDERLINE
);
4992 effect
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_EFFECT
);
4993 spacing
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_SPACING
);
4994 typography
= alloc_layout_range(layout
, &r
, LAYOUT_RANGE_TYPOGRAPHY
);
4995 if (!range
|| !strike
|| !effect
|| !spacing
|| !typography
|| !underline
) {
4996 free_layout_range(range
);
4997 free_layout_range(strike
);
4998 free_layout_range(underline
);
4999 free_layout_range(effect
);
5000 free_layout_range(spacing
);
5001 free_layout_range(typography
);
5006 if (desc
->is_gdi_compatible
)
5007 layout
->measuringmode
= desc
->use_gdi_natural
? DWRITE_MEASURING_MODE_GDI_NATURAL
: DWRITE_MEASURING_MODE_GDI_CLASSIC
;
5009 layout
->measuringmode
= DWRITE_MEASURING_MODE_NATURAL
;
5010 layout
->ppdip
= desc
->ppdip
;
5011 layout
->transform
= desc
->transform
? *desc
->transform
: identity
;
5013 layout
->factory
= desc
->factory
;
5014 IDWriteFactory5_AddRef(layout
->factory
);
5015 list_add_head(&layout
->ranges
, &range
->entry
);
5016 list_add_head(&layout
->strike_ranges
, &strike
->entry
);
5017 list_add_head(&layout
->underline_ranges
, &underline
->entry
);
5018 list_add_head(&layout
->effects
, &effect
->entry
);
5019 list_add_head(&layout
->spacing
, &spacing
->entry
);
5020 list_add_head(&layout
->typographies
, &typography
->entry
);
5024 IDWriteTextLayout3_Release(&layout
->IDWriteTextLayout3_iface
);
5028 HRESULT
create_textlayout(const struct textlayout_desc
*desc
, IDWriteTextLayout
**ret
)
5030 struct dwrite_textlayout
*layout
;
5035 if (!desc
->format
|| !desc
->string
)
5036 return E_INVALIDARG
;
5038 layout
= heap_alloc(sizeof(struct dwrite_textlayout
));
5039 if (!layout
) return E_OUTOFMEMORY
;
5041 hr
= init_textlayout(desc
, layout
);
5043 *ret
= (IDWriteTextLayout
*)&layout
->IDWriteTextLayout3_iface
;
5048 static HRESULT WINAPI
dwritetrimmingsign_QueryInterface(IDWriteInlineObject
*iface
, REFIID riid
, void **obj
)
5050 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5052 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
5054 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteInlineObject
)) {
5056 IDWriteInlineObject_AddRef(iface
);
5060 WARN("%s not implemented.\n", debugstr_guid(riid
));
5063 return E_NOINTERFACE
;
5066 static ULONG WINAPI
dwritetrimmingsign_AddRef(IDWriteInlineObject
*iface
)
5068 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5069 ULONG ref
= InterlockedIncrement(&This
->ref
);
5070 TRACE("(%p)->(%d)\n", This
, ref
);
5074 static ULONG WINAPI
dwritetrimmingsign_Release(IDWriteInlineObject
*iface
)
5076 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5077 ULONG ref
= InterlockedDecrement(&This
->ref
);
5079 TRACE("(%p)->(%d)\n", This
, ref
);
5082 IDWriteTextLayout_Release(This
->layout
);
5089 static HRESULT WINAPI
dwritetrimmingsign_Draw(IDWriteInlineObject
*iface
, void *context
, IDWriteTextRenderer
*renderer
,
5090 FLOAT originX
, FLOAT originY
, BOOL is_sideways
, BOOL is_rtl
, IUnknown
*effect
)
5092 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5093 DWRITE_LINE_METRICS line
;
5096 TRACE("(%p)->(%p %p %.2f %.2f %d %d %p)\n", This
, context
, renderer
, originX
, originY
,
5097 is_sideways
, is_rtl
, effect
);
5099 IDWriteTextLayout_GetLineMetrics(This
->layout
, &line
, 1, &line_count
);
5100 return IDWriteTextLayout_Draw(This
->layout
, context
, renderer
, originX
, originY
- line
.baseline
);
5103 static HRESULT WINAPI
dwritetrimmingsign_GetMetrics(IDWriteInlineObject
*iface
, DWRITE_INLINE_OBJECT_METRICS
*ret
)
5105 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5106 DWRITE_TEXT_METRICS metrics
;
5109 TRACE("(%p)->(%p)\n", This
, ret
);
5111 hr
= IDWriteTextLayout_GetMetrics(This
->layout
, &metrics
);
5113 memset(ret
, 0, sizeof(*ret
));
5117 ret
->width
= metrics
.width
;
5119 ret
->baseline
= 0.0f
;
5120 ret
->supportsSideways
= FALSE
;
5124 static HRESULT WINAPI
dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject
*iface
, DWRITE_OVERHANG_METRICS
*overhangs
)
5126 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5127 TRACE("(%p)->(%p)\n", This
, overhangs
);
5128 return IDWriteTextLayout_GetOverhangMetrics(This
->layout
, overhangs
);
5131 static HRESULT WINAPI
dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject
*iface
, DWRITE_BREAK_CONDITION
*before
,
5132 DWRITE_BREAK_CONDITION
*after
)
5134 struct dwrite_trimmingsign
*This
= impl_from_IDWriteInlineObject(iface
);
5136 TRACE("(%p)->(%p %p)\n", This
, before
, after
);
5138 *before
= *after
= DWRITE_BREAK_CONDITION_NEUTRAL
;
5142 static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl
= {
5143 dwritetrimmingsign_QueryInterface
,
5144 dwritetrimmingsign_AddRef
,
5145 dwritetrimmingsign_Release
,
5146 dwritetrimmingsign_Draw
,
5147 dwritetrimmingsign_GetMetrics
,
5148 dwritetrimmingsign_GetOverhangMetrics
,
5149 dwritetrimmingsign_GetBreakConditions
5152 static inline BOOL
is_reading_direction_horz(DWRITE_READING_DIRECTION direction
)
5154 return (direction
== DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
) ||
5155 (direction
== DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
);
5158 static inline BOOL
is_reading_direction_vert(DWRITE_READING_DIRECTION direction
)
5160 return (direction
== DWRITE_READING_DIRECTION_TOP_TO_BOTTOM
) ||
5161 (direction
== DWRITE_READING_DIRECTION_BOTTOM_TO_TOP
);
5164 static inline BOOL
is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction
)
5166 return (direction
== DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
) ||
5167 (direction
== DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT
);
5170 static inline BOOL
is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction
)
5172 return (direction
== DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
) ||
5173 (direction
== DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP
);
5176 HRESULT
create_trimmingsign(IDWriteFactory5
*factory
, IDWriteTextFormat
*format
, IDWriteInlineObject
**sign
)
5178 static const WCHAR ellipsisW
= 0x2026;
5179 struct dwrite_trimmingsign
*This
;
5180 DWRITE_READING_DIRECTION reading
;
5181 DWRITE_FLOW_DIRECTION flow
;
5186 /* Validate reading/flow direction here, layout creation won't complain about
5187 invalid combinations. */
5188 reading
= IDWriteTextFormat_GetReadingDirection(format
);
5189 flow
= IDWriteTextFormat_GetFlowDirection(format
);
5191 if ((is_reading_direction_horz(reading
) && is_flow_direction_horz(flow
)) ||
5192 (is_reading_direction_vert(reading
) && is_flow_direction_vert(flow
)))
5193 return DWRITE_E_FLOWDIRECTIONCONFLICTS
;
5195 This
= heap_alloc(sizeof(*This
));
5197 return E_OUTOFMEMORY
;
5199 This
->IDWriteInlineObject_iface
.lpVtbl
= &dwritetrimmingsignvtbl
;
5202 hr
= IDWriteFactory5_CreateTextLayout(factory
, &ellipsisW
, 1, format
, 0.0f
, 0.0f
, &This
->layout
);
5208 IDWriteTextLayout_SetWordWrapping(This
->layout
, DWRITE_WORD_WRAPPING_NO_WRAP
);
5209 IDWriteTextLayout_SetParagraphAlignment(This
->layout
, DWRITE_PARAGRAPH_ALIGNMENT_NEAR
);
5210 IDWriteTextLayout_SetTextAlignment(This
->layout
, DWRITE_TEXT_ALIGNMENT_LEADING
);
5212 *sign
= &This
->IDWriteInlineObject_iface
;
5217 static HRESULT WINAPI
dwritetextformat_QueryInterface(IDWriteTextFormat2
*iface
, REFIID riid
, void **obj
)
5219 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5221 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
5223 if (IsEqualIID(riid
, &IID_IDWriteTextFormat2
) ||
5224 IsEqualIID(riid
, &IID_IDWriteTextFormat1
) ||
5225 IsEqualIID(riid
, &IID_IDWriteTextFormat
) ||
5226 IsEqualIID(riid
, &IID_IUnknown
))
5229 IDWriteTextFormat2_AddRef(iface
);
5233 WARN("%s not implemented.\n", debugstr_guid(riid
));
5237 return E_NOINTERFACE
;
5240 static ULONG WINAPI
dwritetextformat_AddRef(IDWriteTextFormat2
*iface
)
5242 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5243 ULONG ref
= InterlockedIncrement(&This
->ref
);
5244 TRACE("(%p)->(%d)\n", This
, ref
);
5248 static ULONG WINAPI
dwritetextformat_Release(IDWriteTextFormat2
*iface
)
5250 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5251 ULONG ref
= InterlockedDecrement(&This
->ref
);
5253 TRACE("(%p)->(%d)\n", This
, ref
);
5257 release_format_data(&This
->format
);
5264 static HRESULT WINAPI
dwritetextformat_SetTextAlignment(IDWriteTextFormat2
*iface
, DWRITE_TEXT_ALIGNMENT alignment
)
5266 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5267 TRACE("(%p)->(%d)\n", This
, alignment
);
5268 return format_set_textalignment(&This
->format
, alignment
, NULL
);
5271 static HRESULT WINAPI
dwritetextformat_SetParagraphAlignment(IDWriteTextFormat2
*iface
, DWRITE_PARAGRAPH_ALIGNMENT alignment
)
5273 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5274 TRACE("(%p)->(%d)\n", This
, alignment
);
5275 return format_set_paralignment(&This
->format
, alignment
, NULL
);
5278 static HRESULT WINAPI
dwritetextformat_SetWordWrapping(IDWriteTextFormat2
*iface
, DWRITE_WORD_WRAPPING wrapping
)
5280 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5281 TRACE("(%p)->(%d)\n", This
, wrapping
);
5282 return format_set_wordwrapping(&This
->format
, wrapping
, NULL
);
5285 static HRESULT WINAPI
dwritetextformat_SetReadingDirection(IDWriteTextFormat2
*iface
, DWRITE_READING_DIRECTION direction
)
5287 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5288 TRACE("(%p)->(%d)\n", This
, direction
);
5289 return format_set_readingdirection(&This
->format
, direction
, NULL
);
5292 static HRESULT WINAPI
dwritetextformat_SetFlowDirection(IDWriteTextFormat2
*iface
, DWRITE_FLOW_DIRECTION direction
)
5294 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5295 TRACE("(%p)->(%d)\n", This
, direction
);
5296 return format_set_flowdirection(&This
->format
, direction
, NULL
);
5299 static HRESULT WINAPI
dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat2
*iface
, FLOAT tabstop
)
5301 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5302 FIXME("(%p)->(%f): stub\n", This
, tabstop
);
5306 static HRESULT WINAPI
dwritetextformat_SetTrimming(IDWriteTextFormat2
*iface
, DWRITE_TRIMMING
const *trimming
,
5307 IDWriteInlineObject
*trimming_sign
)
5309 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5310 TRACE("(%p)->(%p %p)\n", This
, trimming
, trimming_sign
);
5311 return format_set_trimming(&This
->format
, trimming
, trimming_sign
, NULL
);
5314 static HRESULT WINAPI
dwritetextformat_SetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING_METHOD method
,
5315 FLOAT height
, FLOAT baseline
)
5317 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5318 DWRITE_LINE_SPACING spacing
;
5320 TRACE("(%p)->(%d %f %f)\n", This
, method
, height
, baseline
);
5322 spacing
= This
->format
.spacing
;
5323 spacing
.method
= method
;
5324 spacing
.height
= height
;
5325 spacing
.baseline
= baseline
;
5327 return format_set_linespacing(&This
->format
, &spacing
, NULL
);
5330 static DWRITE_TEXT_ALIGNMENT WINAPI
dwritetextformat_GetTextAlignment(IDWriteTextFormat2
*iface
)
5332 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5333 TRACE("(%p)\n", This
);
5334 return This
->format
.textalignment
;
5337 static DWRITE_PARAGRAPH_ALIGNMENT WINAPI
dwritetextformat_GetParagraphAlignment(IDWriteTextFormat2
*iface
)
5339 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5340 TRACE("(%p)\n", This
);
5341 return This
->format
.paralign
;
5344 static DWRITE_WORD_WRAPPING WINAPI
dwritetextformat_GetWordWrapping(IDWriteTextFormat2
*iface
)
5346 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5347 TRACE("(%p)\n", This
);
5348 return This
->format
.wrapping
;
5351 static DWRITE_READING_DIRECTION WINAPI
dwritetextformat_GetReadingDirection(IDWriteTextFormat2
*iface
)
5353 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5354 TRACE("(%p)\n", This
);
5355 return This
->format
.readingdir
;
5358 static DWRITE_FLOW_DIRECTION WINAPI
dwritetextformat_GetFlowDirection(IDWriteTextFormat2
*iface
)
5360 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5361 TRACE("(%p)\n", This
);
5362 return This
->format
.flow
;
5365 static FLOAT WINAPI
dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat2
*iface
)
5367 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5368 FIXME("(%p): stub\n", This
);
5372 static HRESULT WINAPI
dwritetextformat_GetTrimming(IDWriteTextFormat2
*iface
, DWRITE_TRIMMING
*options
,
5373 IDWriteInlineObject
**trimming_sign
)
5375 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5376 TRACE("(%p)->(%p %p)\n", This
, options
, trimming_sign
);
5378 *options
= This
->format
.trimming
;
5379 if ((*trimming_sign
= This
->format
.trimmingsign
))
5380 IDWriteInlineObject_AddRef(*trimming_sign
);
5385 static HRESULT WINAPI
dwritetextformat_GetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING_METHOD
*method
,
5386 FLOAT
*spacing
, FLOAT
*baseline
)
5388 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5389 TRACE("(%p)->(%p %p %p)\n", This
, method
, spacing
, baseline
);
5391 *method
= This
->format
.spacing
.method
;
5392 *spacing
= This
->format
.spacing
.height
;
5393 *baseline
= This
->format
.spacing
.baseline
;
5397 static HRESULT WINAPI
dwritetextformat_GetFontCollection(IDWriteTextFormat2
*iface
, IDWriteFontCollection
**collection
)
5399 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5401 TRACE("(%p)->(%p)\n", This
, collection
);
5403 *collection
= This
->format
.collection
;
5404 IDWriteFontCollection_AddRef(*collection
);
5409 static UINT32 WINAPI
dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat2
*iface
)
5411 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5412 TRACE("(%p)\n", This
);
5413 return This
->format
.family_len
;
5416 static HRESULT WINAPI
dwritetextformat_GetFontFamilyName(IDWriteTextFormat2
*iface
, WCHAR
*name
, UINT32 size
)
5418 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5420 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
5422 if (size
<= This
->format
.family_len
) return E_NOT_SUFFICIENT_BUFFER
;
5423 strcpyW(name
, This
->format
.family_name
);
5427 static DWRITE_FONT_WEIGHT WINAPI
dwritetextformat_GetFontWeight(IDWriteTextFormat2
*iface
)
5429 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5430 TRACE("(%p)\n", This
);
5431 return This
->format
.weight
;
5434 static DWRITE_FONT_STYLE WINAPI
dwritetextformat_GetFontStyle(IDWriteTextFormat2
*iface
)
5436 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5437 TRACE("(%p)\n", This
);
5438 return This
->format
.style
;
5441 static DWRITE_FONT_STRETCH WINAPI
dwritetextformat_GetFontStretch(IDWriteTextFormat2
*iface
)
5443 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5444 TRACE("(%p)\n", This
);
5445 return This
->format
.stretch
;
5448 static FLOAT WINAPI
dwritetextformat_GetFontSize(IDWriteTextFormat2
*iface
)
5450 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5451 TRACE("(%p)\n", This
);
5452 return This
->format
.fontsize
;
5455 static UINT32 WINAPI
dwritetextformat_GetLocaleNameLength(IDWriteTextFormat2
*iface
)
5457 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5458 TRACE("(%p)\n", This
);
5459 return This
->format
.locale_len
;
5462 static HRESULT WINAPI
dwritetextformat_GetLocaleName(IDWriteTextFormat2
*iface
, WCHAR
*name
, UINT32 size
)
5464 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5466 TRACE("(%p)->(%p %u)\n", This
, name
, size
);
5468 if (size
<= This
->format
.locale_len
) return E_NOT_SUFFICIENT_BUFFER
;
5469 strcpyW(name
, This
->format
.locale
);
5473 static HRESULT WINAPI
dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat2
*iface
, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation
)
5475 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5477 TRACE("(%p)->(%d)\n", This
, orientation
);
5479 if ((UINT32
)orientation
> DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED
)
5480 return E_INVALIDARG
;
5482 This
->format
.vertical_orientation
= orientation
;
5486 static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI
dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat2
*iface
)
5488 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5489 TRACE("(%p)\n", This
);
5490 return This
->format
.vertical_orientation
;
5493 static HRESULT WINAPI
dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat2
*iface
, BOOL lastline_wrapping_enabled
)
5495 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5497 TRACE("(%p)->(%d)\n", This
, lastline_wrapping_enabled
);
5499 This
->format
.last_line_wrapping
= !!lastline_wrapping_enabled
;
5503 static BOOL WINAPI
dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat2
*iface
)
5505 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5506 TRACE("(%p)\n", This
);
5507 return This
->format
.last_line_wrapping
;
5510 static HRESULT WINAPI
dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat2
*iface
, DWRITE_OPTICAL_ALIGNMENT alignment
)
5512 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5513 TRACE("(%p)->(%d)\n", This
, alignment
);
5514 return format_set_optical_alignment(&This
->format
, alignment
);
5517 static DWRITE_OPTICAL_ALIGNMENT WINAPI
dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat2
*iface
)
5519 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5520 TRACE("(%p)\n", This
);
5521 return This
->format
.optical_alignment
;
5524 static HRESULT WINAPI
dwritetextformat1_SetFontFallback(IDWriteTextFormat2
*iface
, IDWriteFontFallback
*fallback
)
5526 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5527 TRACE("(%p)->(%p)\n", This
, fallback
);
5528 return set_fontfallback_for_format(&This
->format
, fallback
);
5531 static HRESULT WINAPI
dwritetextformat1_GetFontFallback(IDWriteTextFormat2
*iface
, IDWriteFontFallback
**fallback
)
5533 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5534 TRACE("(%p)->(%p)\n", This
, fallback
);
5535 return get_fontfallback_from_format(&This
->format
, fallback
);
5538 static HRESULT WINAPI
dwritetextformat2_SetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING
const *spacing
)
5540 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5541 TRACE("(%p)->(%p)\n", This
, spacing
);
5542 return format_set_linespacing(&This
->format
, spacing
, NULL
);
5545 static HRESULT WINAPI
dwritetextformat2_GetLineSpacing(IDWriteTextFormat2
*iface
, DWRITE_LINE_SPACING
*spacing
)
5547 struct dwrite_textformat
*This
= impl_from_IDWriteTextFormat2(iface
);
5549 TRACE("(%p)->(%p)\n", This
, spacing
);
5551 *spacing
= This
->format
.spacing
;
5555 static const IDWriteTextFormat2Vtbl dwritetextformatvtbl
= {
5556 dwritetextformat_QueryInterface
,
5557 dwritetextformat_AddRef
,
5558 dwritetextformat_Release
,
5559 dwritetextformat_SetTextAlignment
,
5560 dwritetextformat_SetParagraphAlignment
,
5561 dwritetextformat_SetWordWrapping
,
5562 dwritetextformat_SetReadingDirection
,
5563 dwritetextformat_SetFlowDirection
,
5564 dwritetextformat_SetIncrementalTabStop
,
5565 dwritetextformat_SetTrimming
,
5566 dwritetextformat_SetLineSpacing
,
5567 dwritetextformat_GetTextAlignment
,
5568 dwritetextformat_GetParagraphAlignment
,
5569 dwritetextformat_GetWordWrapping
,
5570 dwritetextformat_GetReadingDirection
,
5571 dwritetextformat_GetFlowDirection
,
5572 dwritetextformat_GetIncrementalTabStop
,
5573 dwritetextformat_GetTrimming
,
5574 dwritetextformat_GetLineSpacing
,
5575 dwritetextformat_GetFontCollection
,
5576 dwritetextformat_GetFontFamilyNameLength
,
5577 dwritetextformat_GetFontFamilyName
,
5578 dwritetextformat_GetFontWeight
,
5579 dwritetextformat_GetFontStyle
,
5580 dwritetextformat_GetFontStretch
,
5581 dwritetextformat_GetFontSize
,
5582 dwritetextformat_GetLocaleNameLength
,
5583 dwritetextformat_GetLocaleName
,
5584 dwritetextformat1_SetVerticalGlyphOrientation
,
5585 dwritetextformat1_GetVerticalGlyphOrientation
,
5586 dwritetextformat1_SetLastLineWrapping
,
5587 dwritetextformat1_GetLastLineWrapping
,
5588 dwritetextformat1_SetOpticalAlignment
,
5589 dwritetextformat1_GetOpticalAlignment
,
5590 dwritetextformat1_SetFontFallback
,
5591 dwritetextformat1_GetFontFallback
,
5592 dwritetextformat2_SetLineSpacing
,
5593 dwritetextformat2_GetLineSpacing
5596 static struct dwrite_textformat
*unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat
*iface
)
5598 return (iface
->lpVtbl
== (IDWriteTextFormatVtbl
*)&dwritetextformatvtbl
) ?
5599 CONTAINING_RECORD(iface
, struct dwrite_textformat
, IDWriteTextFormat2_iface
) : NULL
;
5602 HRESULT
create_textformat(const WCHAR
*family_name
, IDWriteFontCollection
*collection
, DWRITE_FONT_WEIGHT weight
, DWRITE_FONT_STYLE style
,
5603 DWRITE_FONT_STRETCH stretch
, FLOAT size
, const WCHAR
*locale
, IDWriteTextFormat
**format
)
5605 struct dwrite_textformat
*This
;
5610 return E_INVALIDARG
;
5612 if (((UINT32
)weight
> DWRITE_FONT_WEIGHT_ULTRA_BLACK
) ||
5613 ((UINT32
)stretch
> DWRITE_FONT_STRETCH_ULTRA_EXPANDED
) ||
5614 ((UINT32
)style
> DWRITE_FONT_STYLE_ITALIC
))
5615 return E_INVALIDARG
;
5617 This
= heap_alloc(sizeof(struct dwrite_textformat
));
5618 if (!This
) return E_OUTOFMEMORY
;
5620 This
->IDWriteTextFormat2_iface
.lpVtbl
= &dwritetextformatvtbl
;
5622 This
->format
.family_name
= heap_strdupW(family_name
);
5623 This
->format
.family_len
= strlenW(family_name
);
5624 This
->format
.locale
= heap_strdupW(locale
);
5625 This
->format
.locale_len
= strlenW(locale
);
5626 /* force locale name to lower case, layout will inherit this modified value */
5627 strlwrW(This
->format
.locale
);
5628 This
->format
.weight
= weight
;
5629 This
->format
.style
= style
;
5630 This
->format
.fontsize
= size
;
5631 This
->format
.stretch
= stretch
;
5632 This
->format
.textalignment
= DWRITE_TEXT_ALIGNMENT_LEADING
;
5633 This
->format
.optical_alignment
= DWRITE_OPTICAL_ALIGNMENT_NONE
;
5634 This
->format
.paralign
= DWRITE_PARAGRAPH_ALIGNMENT_NEAR
;
5635 This
->format
.wrapping
= DWRITE_WORD_WRAPPING_WRAP
;
5636 This
->format
.last_line_wrapping
= TRUE
;
5637 This
->format
.readingdir
= DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
;
5638 This
->format
.flow
= DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM
;
5639 This
->format
.spacing
.method
= DWRITE_LINE_SPACING_METHOD_DEFAULT
;
5640 This
->format
.spacing
.height
= 0.0f
;
5641 This
->format
.spacing
.baseline
= 0.0f
;
5642 This
->format
.spacing
.leadingBefore
= 0.0f
;
5643 This
->format
.spacing
.fontLineGapUsage
= DWRITE_FONT_LINE_GAP_USAGE_DEFAULT
;
5644 This
->format
.vertical_orientation
= DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT
;
5645 This
->format
.trimming
.granularity
= DWRITE_TRIMMING_GRANULARITY_NONE
;
5646 This
->format
.trimming
.delimiter
= 0;
5647 This
->format
.trimming
.delimiterCount
= 0;
5648 This
->format
.trimmingsign
= NULL
;
5649 This
->format
.collection
= collection
;
5650 This
->format
.fallback
= NULL
;
5651 IDWriteFontCollection_AddRef(collection
);
5653 *format
= (IDWriteTextFormat
*)&This
->IDWriteTextFormat2_iface
;
5658 static HRESULT WINAPI
dwritetypography_QueryInterface(IDWriteTypography
*iface
, REFIID riid
, void **obj
)
5660 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5662 TRACE("(%p)->(%s %p)\n", typography
, debugstr_guid(riid
), obj
);
5664 if (IsEqualIID(riid
, &IID_IDWriteTypography
) || IsEqualIID(riid
, &IID_IUnknown
)) {
5666 IDWriteTypography_AddRef(iface
);
5670 WARN("%s not implemented.\n", debugstr_guid(riid
));
5674 return E_NOINTERFACE
;
5677 static ULONG WINAPI
dwritetypography_AddRef(IDWriteTypography
*iface
)
5679 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5680 ULONG ref
= InterlockedIncrement(&typography
->ref
);
5681 TRACE("(%p)->(%d)\n", typography
, ref
);
5685 static ULONG WINAPI
dwritetypography_Release(IDWriteTypography
*iface
)
5687 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5688 ULONG ref
= InterlockedDecrement(&typography
->ref
);
5690 TRACE("(%p)->(%d)\n", typography
, ref
);
5693 heap_free(typography
->features
);
5694 heap_free(typography
);
5700 static HRESULT WINAPI
dwritetypography_AddFontFeature(IDWriteTypography
*iface
, DWRITE_FONT_FEATURE feature
)
5702 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5704 TRACE("(%p)->(%x %u)\n", typography
, feature
.nameTag
, feature
.parameter
);
5706 if (typography
->count
== typography
->allocated
) {
5707 DWRITE_FONT_FEATURE
*ptr
= heap_realloc(typography
->features
, 2*typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
5709 return E_OUTOFMEMORY
;
5711 typography
->features
= ptr
;
5712 typography
->allocated
*= 2;
5715 typography
->features
[typography
->count
++] = feature
;
5719 static UINT32 WINAPI
dwritetypography_GetFontFeatureCount(IDWriteTypography
*iface
)
5721 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5722 TRACE("(%p)\n", typography
);
5723 return typography
->count
;
5726 static HRESULT WINAPI
dwritetypography_GetFontFeature(IDWriteTypography
*iface
, UINT32 index
, DWRITE_FONT_FEATURE
*feature
)
5728 struct dwrite_typography
*typography
= impl_from_IDWriteTypography(iface
);
5730 TRACE("(%p)->(%u %p)\n", typography
, index
, feature
);
5732 if (index
>= typography
->count
)
5733 return E_INVALIDARG
;
5735 *feature
= typography
->features
[index
];
5739 static const IDWriteTypographyVtbl dwritetypographyvtbl
= {
5740 dwritetypography_QueryInterface
,
5741 dwritetypography_AddRef
,
5742 dwritetypography_Release
,
5743 dwritetypography_AddFontFeature
,
5744 dwritetypography_GetFontFeatureCount
,
5745 dwritetypography_GetFontFeature
5748 HRESULT
create_typography(IDWriteTypography
**ret
)
5750 struct dwrite_typography
*typography
;
5754 typography
= heap_alloc(sizeof(*typography
));
5756 return E_OUTOFMEMORY
;
5758 typography
->IDWriteTypography_iface
.lpVtbl
= &dwritetypographyvtbl
;
5759 typography
->ref
= 1;
5760 typography
->allocated
= 2;
5761 typography
->count
= 0;
5763 typography
->features
= heap_alloc(typography
->allocated
*sizeof(DWRITE_FONT_FEATURE
));
5764 if (!typography
->features
) {
5765 heap_free(typography
);
5766 return E_OUTOFMEMORY
;
5769 *ret
= &typography
->IDWriteTypography_iface
;